diff --git a/CHANGES.txt b/CHANGES.txt index f0aa69b..1fa8a06 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,6 @@ [2.0.3] - + * Added map view. [2.0.2] diff --git a/Gruntfile.js b/Gruntfile.js index 0aaa1dc..ceecba9 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -32,6 +32,7 @@ module.exports = function(grunt) { 'cubesviewer/views/cube/chart/chart-radar.js', 'cubesviewer/views/cube/chart/chart-sunburst.js', 'cubesviewer/views/cube/chart/map/chart-map.js', + 'cubesviewer/views/cube/chart/map/chart-map-layers.js', //'cubesviewer/cubesviewer.views.cube.rangefilter.js', 'cubesviewer/views/cube/export.js', 'cubesviewer/views/undo.js', diff --git a/cubesviewer/cubes/cubes-cvextensions.js b/cubesviewer/cubes/cubes-cvextensions.js index 1d07fde..85ca0fc 100644 --- a/cubesviewer/cubes/cubes-cvextensions.js +++ b/cubesviewer/cubes/cubes-cvextensions.js @@ -24,6 +24,8 @@ "use strict"; /* Extensions to cubesviewer client lib */ + + cubes.Dimension.prototype.hierarchies_count = function() { var count = 0; @@ -39,18 +41,18 @@ cubes.Dimension.prototype.default_hierarchy = function() { return this.hierarchies[this.default_hierarchy_name]; }; -/* +/** * Extend model prototype to support datefilter dimensions. + * Inform if a dimension is a date dimension and can be used as a date + * filter (i.e. with date selection tool). + * @returns Whether the dimension is a date dimension. */ cubes.Dimension.prototype.isDateDimension = function() { - - // Inform if a dimension is a date dimension and can be used as a date - // filter (i.e. with date selection tool). return ((this.role == "time") && ((! ("cv-datefilter" in this.info)) || (this.info["cv-datefilter"] == true)) ); - }; + /** * List date dimensions. * @@ -66,6 +68,33 @@ cubes.Cube.prototype.dateDimensions = function() { }; +/** + * Extend model prototype to support geographic dimensions. + * @returns Whether the dimension level is a geographic dimension. + */ +cubes.Level.prototype.isGeoLevel = function() { + return ((this.role == "geo") || ("cv-geo-source" in this.info)); +}; + + +/** + * List date dimensions. + * + * @returns An array with the dimensions that are date dimensions (role: time). + */ +cubes.Cube.prototype.geoLevels = function() { + var result = []; + for (var index in this.dimensions) { + var dimension = this.dimensions[index]; + for (var indexL in dimension.levels) { + var level = dimension.levels[indexL]; + if (level.isGeoLevel()) result.push(level); + } + } + return result; +}; + + cubes.Cube.prototype.cvdim_dim = function(dimensionString) { // Get a dimension by name. Accepts dimension hierarchy and level in the input string. var dimname = dimensionString; diff --git a/cubesviewer/views/cube/chart/chart-bars-horizontal.js b/cubesviewer/views/cube/chart/chart-bars-horizontal.js index d161e73..10e019e 100644 --- a/cubesviewer/views/cube/chart/chart-bars-horizontal.js +++ b/cubesviewer/views/cube/chart/chart-bars-horizontal.js @@ -52,7 +52,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartBarsHorizon var columnDefs = view.grid.columnDefs; var container = $($element).find("svg").get(0); - var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : "None") + var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : ""); var d = []; @@ -61,7 +61,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartBarsHorizon $(dataRows).each(function(idx, e) { var serie = []; for (var i = 1; i < columnDefs.length; i++) { - var value = e[columnDefs[i].name]; + var value = e[columnDefs[i].field]; // If second serie is reversed if (dataRows.length == 2 && serieCount == 1 && view.params.chartoptions.mirrorSerie2) value = (value != undefined) ? -value : 0; diff --git a/cubesviewer/views/cube/chart/chart-bars-vertical.js b/cubesviewer/views/cube/chart/chart-bars-vertical.js index 5195d60..b3cb9b6 100644 --- a/cubesviewer/views/cube/chart/chart-bars-vertical.js +++ b/cubesviewer/views/cube/chart/chart-bars-vertical.js @@ -53,7 +53,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartBarsVertica var columnDefs = view.grid.columnDefs; var container = $($element).find("svg").get(0); - var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : "None") + var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : ""); var d = []; @@ -62,7 +62,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartBarsVertica $(dataRows).each(function(idx, e) { var serie = []; for (var i = 1; i < columnDefs.length; i++) { - var value = e[columnDefs[i].name]; + var value = e[columnDefs[i].field]; serie.push( { "x": columnDefs[i].name, "y": (value != undefined) ? value : 0 } ); } var series = { "values": serie, "key": e["key"] != "" ? e["key"] : view.params.yaxis }; diff --git a/cubesviewer/views/cube/chart/chart-lines.js b/cubesviewer/views/cube/chart/chart-lines.js index a9ea13e..ec53f91 100644 --- a/cubesviewer/views/cube/chart/chart-lines.js +++ b/cubesviewer/views/cube/chart/chart-lines.js @@ -58,7 +58,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartLinesContro var container = $($element).find("svg").get(0); - var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : "None") + var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : ""); // TODO: Check there's only one value column @@ -196,7 +196,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartLinesContro this.drawChartLinesCumulative = function (view, colNames, dataRows, dataTotals) { var container = $('#seriesChart-' + view.id).find("svg").get(0); - var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.getDimensionParts(view.params.xaxis).label : "None") + var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.getDimensionParts(view.params.xaxis).label : ""); var d = []; diff --git a/cubesviewer/views/cube/chart/chart-pie.js b/cubesviewer/views/cube/chart/chart-pie.js index 89d8d0a..1f933db 100644 --- a/cubesviewer/views/cube/chart/chart-pie.js +++ b/cubesviewer/views/cube/chart/chart-pie.js @@ -64,7 +64,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartPieControll var value = e[columnDefs[1].field]; if ((value != undefined) && (value > 0)) { - var series = { "y": value, "key": e["key"] != "" ? e["key"] : columnDefs[0].name }; + var series = { "y": value, "key": e["key"] != "" ? e["key"] : columnDefs[0].field }; if (view.params["chart-disabledseries"]) { if (view.params["chart-disabledseries"]["key"] == (view.params.drilldown.join(","))) { series.disabled = !! view.params["chart-disabledseries"]["disabled"][series.key]; diff --git a/cubesviewer/views/cube/chart/chart-sunburst.js b/cubesviewer/views/cube/chart/chart-sunburst.js index 1e5af22..cb639dc 100644 --- a/cubesviewer/views/cube/chart/chart-sunburst.js +++ b/cubesviewer/views/cube/chart/chart-sunburst.js @@ -86,6 +86,8 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartSunburstCon */ $scope.prepareDrilldownTree = function (data) { + // FIXME: This representation is using cells directly, instead of data from series. + var view = $scope.view; var json = [{ diff --git a/cubesviewer/views/cube/chart/chart.html b/cubesviewer/views/cube/chart/chart.html index eaa0565..1ba5253 100644 --- a/cubesviewer/views/cube/chart/chart.html +++ b/cubesviewer/views/cube/chart/chart.html @@ -85,7 +85,12 @@

Chart
-

Map chart

+

Map chart + +

+
+ +
diff --git a/cubesviewer/views/cube/chart/chart.js b/cubesviewer/views/cube/chart/chart.js index 5196626..4555ddc 100644 --- a/cubesviewer/views/cube/chart/chart.js +++ b/cubesviewer/views/cube/chart/chart.js @@ -115,8 +115,14 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartController" $(rows).each(function(idx, e) { var jointkey = []; + var jointlabel = []; for (var i = 0; i < view.params.drilldown.length; i++) jointkey.push(e["key" + i]); - e["key"] = jointkey.join(" / "); + for (var i = 0; i < view.params.drilldown.length; i++) jointlabel.push(e["label" + i]); + e["key"] = jointkey.join("_"); + e["label"] = jointlabel.join(" / "); + + // FIXME: Using label as key for charts, but we should properly use keys/labels for charts and column definitions in general + e["key"] = e["label"]; }); } diff --git a/cubesviewer/views/cube/chart/map/chart-map-layers.js b/cubesviewer/views/cube/chart/map/chart-map-layers.js new file mode 100644 index 0000000..5dfc549 --- /dev/null +++ b/cubesviewer/views/cube/chart/map/chart-map-layers.js @@ -0,0 +1,189 @@ +/* + * CubesViewer + * Copyright (c) 2012-2016 Jose Juan Montes, see AUTHORS for more details + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +"use strict"; + + +var defineMapControllerLayerMethods = function($scope) { + + /** + * Creates a Tile XYZ layer. + * @param mapLayer + * @returns The created layer. + */ + $scope.createLayerXYZ = function (mapLayer) { + + var sourceParams = {}; + angular.extend(sourceParams, mapLayer.params); + if (mapLayer.attribution) sourceParams['attributions'] = [ new ol.Attribution({ 'html': "" + mapLayer.attribution }) ]; + + var layer = new ol.layer.Tile({ + source: new ol.source.XYZ(sourceParams), + opacity: mapLayer.opacity ? mapLayer.opacity : 1.0, + visible: false + }); + + return layer; + }; + + /** + * Creates a WMTS layer. This provides a set of default parameters. + * @returns The created layer. + */ + $scope.createLayerWMTS = function (mapLayer) { + + // Generate resolutions and matrixIds arrays for this WMTS (having seen capabilities) + // Note: Grid may be built also by: ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(matrixSet, opt_extent) + var projection = ol.proj.get('EPSG:3857'); + var projectionExtent = projection.getExtent(); + var size = ol.extent.getWidth(projectionExtent) / 256; + var resolutions = new Array(20); + var matrixIds = new Array(20); + for (var z = 0; z < 20; ++z) { + resolutions[z] = size / Math.pow(2, z); + matrixIds[z] = z; + } + + var sourceParamsBase = { + //url: 'http://www.ign.es/wmts/pnoa-ma?service=WMTS', + //layer: 'OI.OrthoimageCoverage', + matrixSet: 'GoogleMapsCompatible', // 'EPSG:3857', + format: 'image/png', + projection: projection, + tileGrid: new ol.tilegrid.WMTS({ + origin: ol.extent.getTopLeft(projectionExtent), + resolutions: resolutions, + matrixIds: matrixIds + }), + style: 'default' + }; + + var sourceParams = {}; + angular.extend(sourceParams, sourceParamsBase); + angular.extend(sourceParams, mapLayer.params); + if (mapLayer.attribution) sourceParams['attributions'] = [ new ol.Attribution({ 'html': "" + mapLayer.attribution }) ]; + + var layer = new ol.layer.Tile({ + source: new ol.source.WMTS(sourceParams), + opacity: mapLayer.opacity ? mapLayer.opacity : 1.0, + visible: false + //extent: projectionExtent, + }) + + return layer; + }; + + /** + * Creates a KML layer. + * @returns The created layer. + */ + $scope.createLayerKML = function (mapLayer) { + + var sourceParams = {}; + angular.extend(sourceParams, { format: new ol.format.KML() }); + angular.extend(sourceParams, mapLayer.params); + if (mapLayer.attribution) sourceParams['attributions'] = [ new ol.Attribution({ 'html': "" + mapLayer.attribution }) ]; + + var layer = new ol.layer.Vector({ + source: new ol.source.Vector(sourceParams) + }); + + return layer; + }; + + /** + * Creates a GeoJSON layer. + * @returns The created layer. + */ + $scope.createLayerGeoJSON = function (mapLayer) { + + var sourceParams = {}; + angular.extend(sourceParams, { format: new ol.format.GeoJSON() }); + angular.extend(sourceParams, mapLayer.params); + + var cityNamesStyle = function(feature, resolution) { + var fontSize = 1.5 - 0.5 * feature.get("scalerank") / 10; + return [ new ol.style.Style({ + text: new ol.style.Text({ + text: resolution < 3600 || (resolution < 14400 && feature.get("scalerank") < 4) ? feature.get("name") : "", + font: 'bold ' + (fontSize * 10) + 'px Calibri,sans-serif', + fill: new ol.style.Fill({color: "#ffffff"}), + stroke: new ol.style.Stroke({color: "#000000", width: 3}), + }) + }) ] + }; + + // Populated places GeoJSON + var layer = new ol.layer.Vector({ + title: mapLayer.label, + source: new ol.source.Vector(sourceParams), + visible: false, + + // TODO: Layer styles shall be optional and chosen from several possibilities (if applied) + style: cityNamesStyle + }); + + return layer; + }; + + + /** + * Creates various types of map layers based on settings. + */ + $scope.createLayers = function(mapLayers) { + + var layers = {}; + layers['_order'] = []; + angular.forEach(mapLayers, function(mapLayer) { + + var layer = null; + + if (mapLayer.params.url && (mapLayer.params.url.search('{}') >= 0)) { + mapLayer.params.url = mapLayer.params.url.replace('{}', $location.host()); + } + + if (mapLayer.source == 'wmts') { + layer = $scope.createLayerWMTS(mapLayer); + } else if (mapLayer.source == 'xyz') { + layer = $scope.createLayerXYZ(mapLayer); + } else if (mapLayer.source == 'geojson') { + layer = $scope.createLayerGeoJSON(mapLayer); + } else if (mapLayer.source == 'kml') { + layer = $scope.createLayerKML(mapLayer); + } else { + console.error('Wrong map settings. Could not create map layer of source type: ' + mapLayer.source); + return; + } + + layers[mapLayer.name] = layer; + layers['_order'].push(layer); + + + }); + }; + +}; + + + + diff --git a/cubesviewer/views/cube/chart/map/chart-map.js b/cubesviewer/views/cube/chart/map/chart-map.js index d42c45e..0d0e7c1 100644 --- a/cubesviewer/views/cube/chart/map/chart-map.js +++ b/cubesviewer/views/cube/chart/map/chart-map.js @@ -35,6 +35,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartMapControll $scope.map = null; + $scope.initialize = function() { // Add chart view parameters to view definition }; @@ -57,11 +58,31 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartMapControll var container = $($element).find(".cv-map-container").get(0); $(container).empty(); - var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : "None") + var xAxisLabel = ( (view.params.xaxis != null) ? view.cube.dimensionParts(view.params.xaxis).label : "None"); var projection = ol.proj.get('EPSG:3857'); - var raster = new ol.layer.Tile({ + // Select column + var geoLevels = $.grep(view.params.drilldown, function(e) { + var dimParts = view.cube.dimensionParts(e); + return dimParts.level.isGeoLevel(); + }); + + // Get geo info from model + $scope.geoLevel = null; + if (geoLevels.length > 0) { + $scope.geoLevel = geoLevels[0]; + console.debug($scope.geoLevel); + } else { + return; + } + + // Create layers + var mapLayers = $scope.geoLevel.info['cv-geo-map-layers']; + $scope.mapLayers = $scope.createLayers(mapLayers); + + /* + var raster = new ol.layer.Tile({ source: new ol.source.XYZ({ url: 'http://tile.openstreetmap.org/{z}/{x}/{y}.png' }) @@ -76,9 +97,10 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartMapControll }), projection: projection }); + */ $scope.map = new ol.Map({ - layers: [raster, vector], // raster + layers: $scope.mapLayers['_order'], target: container, view: new ol.View({ center: [876970.8463461736, 5859807.853963373], @@ -109,7 +131,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartMapControll font: '10px Verdana', text: text, // getText(feature), fill: new ol.style.Fill({color: 'black'}), - stroke: new ol.style.Stroke({color: 'white', width: 0.0}) + stroke: new ol.style.Stroke({color: 'white', width: 2.0}) }); }; @@ -139,7 +161,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartMapControll feature.setStyle( new ol.style.Style({ fill: new ol.style.Fill({color: color, opacity: 0.7}), // colorArr[colorindex] - stroke: new ol.style.Stroke({color: "#ffffff", width: 2,opacity: 0.7} ), + stroke: new ol.style.Stroke({color: color, width: 0.0, opacity: 0.7} ), // "#ffffff" text: createTextStyle(feature, label + "\n" + valueFormatted) }) ); @@ -195,6 +217,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeChartMapControll }; + defineMapControllerLayerMethods($scope); $scope.initialize(); }]); diff --git a/cubesviewer/views/cube/cube.js b/cubesviewer/views/cube/cube.js index efbfdc3..cb5f367 100644 --- a/cubesviewer/views/cube/cube.js +++ b/cubesviewer/views/cube/cube.js @@ -111,7 +111,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeController", ['$ }; $scope.setViewMode = function(mode) { - console.debug("Remove setViewMode call on the controller?") + // TODO: Remove setViewMode call on the controller $scope.view.setViewMode(mode); }; diff --git a/cubesviewer/views/cube/facts/facts.js b/cubesviewer/views/cube/facts/facts.js index 5a3ab82..89ece8d 100644 --- a/cubesviewer/views/cube/facts/facts.js +++ b/cubesviewer/views/cube/facts/facts.js @@ -107,7 +107,7 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeFactsController" }); view.grid.columnDefs.push({ - name: "id", + name: "Id", field: "id", index: "id", enableHiding: false, @@ -271,7 +271,9 @@ angular.module('cv.views.cube').controller("CubesViewerViewsCubeFactsController" // Set key row["id"] = counter++; + if ("id" in e) row["id"] = e["id"]; + if ("__fact_key__" in e) row["id"] = e["__fact_key__"]; row["key"] = row["id"]; row["_cell"] = e; diff --git a/cubesviewer/views/cube/series/series.js b/cubesviewer/views/cube/series/series.js index c8b7ee3..5e81162 100644 --- a/cubesviewer/views/cube/series/series.js +++ b/cubesviewer/views/cube/series/series.js @@ -179,6 +179,7 @@ cubesviewer._seriesAddRows = function($scope, data) { // Copy drilldown as we'll modify it var drilldown = view.params.drilldown.slice(0); + var ag = $.grep(view.cube.aggregates, function(ag) { return ag.ref == view.params.yaxis; })[0]; // Include X Axis if necessary if (view.params.xaxis != null) { @@ -189,8 +190,8 @@ cubesviewer._seriesAddRows = function($scope, data) { var addedCols = []; $(data.cells).each(function (idx, e) { - var row = []; var key = []; + var label = []; // For the drilldown level, if present for (var i = 0; i < drilldown.length; i++) { @@ -200,22 +201,24 @@ cubesviewer._seriesAddRows = function($scope, data) { var infos = parts.hierarchy.readCell(e, parts.level); // Values and Labels - var drilldownLevelValues = []; + var drilldownLevelKeys = []; var drilldownLevelLabels = []; $(infos).each(function(idx, info) { - drilldownLevelValues.push(info.key); + drilldownLevelKeys.push(info.key); drilldownLevelLabels.push(info.label); }); - key.push (drilldownLevelLabels.join(" / ")); + label.push(drilldownLevelLabels.join(" / ")); + key.push(drilldownLevelKeys.join("_")); } // Set key - var colKey = (view.params.xaxis == null) ? view.params.yaxis : key[0]; + var colKey = (view.params.xaxis == null) ? view.params.yaxis : key[0]; // key[0] because that's the horizontal dimension key + var colLabel = (view.params.xaxis == null) ? ag.label : label[0]; + var rowKey = (view.params.xaxis == null) ? key.join (' / ') : key.slice(1).join(' / '); var value = (e[view.params.yaxis]); - var rowKey = (view.params.xaxis == null) ? key.join (' / ') : key.slice(1).join (' / '); // Search or introduce var row = $.grep(rows, function(ed) { return ed["key"] == rowKey; }); @@ -229,6 +232,7 @@ cubesviewer._seriesAddRows = function($scope, data) { for (var i = baseidx ; i < key.length; i++) { newrow["key" + (i - baseidx)] = key[i]; + newrow["label" + (i - baseidx)] = label[i]; } newrow["_cell"] = e; @@ -240,12 +244,11 @@ cubesviewer._seriesAddRows = function($scope, data) { if (addedCols.indexOf(colKey) < 0) { addedCols.push(colKey); - var ag = $.grep(view.cube.aggregates, function(ag) { return ag.ref == view.params.yaxis })[0]; var col = { - name: colKey, + name: colLabel, field: colKey, - index : colKey, + index: colKey, cellClass : "text-right", //sorttype : "number", cellTemplate: '
{{ col.colDef.formatter(COL_FIELD, row, col) }}
', @@ -263,10 +266,10 @@ cubesviewer._seriesAddRows = function($scope, data) { }); //var label = []; - $(view.params.drilldown).each (function (idx, e) { + $(view.params.drilldown).each(function (idx, e) { var col = { name: view.cube.cvdim_dim(e).label, - field: "key" + idx, + field: "label" + idx, index : "key" + idx, headerCellClass: "cv-grid-header-dimension", enableHiding: false, @@ -286,7 +289,8 @@ cubesviewer._seriesAddRows = function($scope, data) { }); if (view.params.drilldown.length == 0 && rows.length > 0) { - rows[0]["key0"] = view.cube.aggregateFromName(view.params.yaxis).label; + rows[0]["key0"] = view.cube.aggregateFromName(view.params.yaxis).name; + rows[0]["label0"] = view.cube.aggregateFromName(view.params.yaxis).label; var col = { name: "Measure", diff --git a/doc/guide/cubesviewer-maps.md b/doc/guide/cubesviewer-maps.md index 9313bf8..3d2fec1 100644 --- a/doc/guide/cubesviewer-maps.md +++ b/doc/guide/cubesviewer-maps.md @@ -4,20 +4,22 @@ CubesViewer Map Charts Features -------- -- Geographic data on dimension attributes and fact details -- Features: points, lines, polygons -- Sources: latitude/longitude (x/y), WKG, GeoJSON, reference to Layer/Feature -- Support for multiple layers (basemap) +- Support geographic data in dimension attributes and fact details +- Geographic feature types: points, lines, polygons +- Sources: latitude/longitude (x/y), WKT, GeoJSON, reference to layer feature +- Multiple layers - Layer types: GeoJson, WMTS +- Selectable CRS + - Configurable view: - Automatic bounding box, fixed bounding box, free view - Configurable min/max zoom level - Representation: -` - cloropleth: applies to all possible, info on hover - - points: info on hover - - circles (measure in radius), info on hover - - legends +` - Cloropleth: applies to all possible, info on hover + - Points: info on hover + - Circles (measure in radius), info on hover + - Legends Model configuration ------------------- @@ -25,23 +27,43 @@ Model configuration ``` "dimensions": [ { - "name": "date_created", - "label": "Date Created", - "role": "time", - "info": { - "cv-datefilter-hierarchy": "weekly" - }, + "label": "Country", "levels": [ - { - "name":"year", - "label":"Year", - "role": "year" - }, - { - "name":"quarter", - "label":"Quarter", - "role": "quarter" - }, + { + "attributes": [ + "country_code", + "country_label", + "country_iso3", + ], + "key": "country_code", + "label": "Country", + "label_attribute": "geo_label", + "info": { + "cv-geo-source": "ref", + "cv-geo-ref-layer": "countries", + "cv-geo-ref-attribute": "country_iso3", + "cv-geo-map-layers": [ { + "name": "osm-standard", + "type": "xyz", + "attribution": "© Dataset owner", + "params": { + "url": "http://tile.openstreetmap.org/{z}/{x}/{y}.png" + } + }, { + "name": "countries", + "type": "geojson", + "attribution": "© Dataset owner", + "params": { + "url": "maps/ne_110m_admin_0_countries.geo.json" + } + } ] + }, + "name": "country", + "role": "geo" + } + ], + "name": "country" + }, ```