Commit 1a892a7d authored by S Anand's avatar S Anand
Browse files

ENH: mapviewer: add scheme: option

parent 36adaa41
Pipeline #51902 passed with stage
in 3 minutes and 1 second
......@@ -1078,13 +1078,10 @@ You can apply styles based on any attribute or function.
url: 'cities.json',
latitude: 'lat',
longitude: 'long',
options: {
title: 'column-name' // TODO: implement as popup
},
attrs: {
fillColor: {
metric: 'pollution',
range: 'RdYlGn'
scheme: 'RdYlGn'
}
}
}
......@@ -1112,10 +1109,16 @@ attribute.
dataKey: 'name', // Join this column from the URL (data)
mapKey: 'ST_NM' // with this property in the GeoJSON
},
options: {
style: {
fillColor: '#a00',
fillOpacity: 1
}
},
attrs: {
fillColor: { // Fill the regions
metric: 'score', // with the "score" column state_score.json
range: 'RdYlGn' // using a RdYlGn gradient
metric: 'score', // with the "score" column from state_score.json
scheme: 'RdYlGn' // using a RdYlGn gradient
},
tooltip: function(prop) { // On hover, show this HTML tooltip
return prop.ST_NM + ': ' + prop.TOT_P
......@@ -1206,7 +1209,7 @@ Drilldown feature example:
- `url` is url (String) to fetch data
- `mapKey` is attribute name in geojson to match
- `dataKey` is column name in input dataset that matches with geojson `mapKey`
- `attrs` Data driven styles.
- `attrs` Data driven styles. same as `options`. (`attrs` take priority over `options`)
- For `color`, `weight`, `opacity`, `fillColor`, `fillOpacity` properties, the options are:.
- `metric` string / function
- If `metric`: is a string, can be any numeric property of geojson
......
......@@ -136,6 +136,7 @@ MapViewer.prototype.mergeData = function (mapJSON, dataTable, mapKey, dataKey) {
feature.properties[key] = row[key]
}
})
// returning mapJSON to write unit testcases for mergeData
return mapJSON
break
default:
......@@ -173,17 +174,21 @@ MapViewer.prototype.buildLayer = function (layerName, layerConfig) {
case 'topojson':
case 'geojson':
self.cacheData(layerName, layerConfig[dataOrURL(layerConfig)]).then(function (mapJSON) {
gLayer = new L.TopoJSON(mapJSON, layerConfig.options)
self.fitToLayer(gLayer)
self._saveLayer(layerName, gLayer)
if ('link' in layerConfig) {
self.cacheData(layerName, layerConfig.link[dataOrURL(layerConfig.link)]).then(function (tableData) {
self.mergeData(mapJSON, tableData, layerConfig.link.mapKey, layerConfig.link.dataKey)
if ('attrs' in layerConfig) self._choropleth(layerName, layerConfig)
self.fire(layerName+'loaded')
gLayer = new L.TopoJSON(mapJSON, layerConfig.options)
self._saveLayer(layerName, gLayer)
if ('attrs' in layerConfig) self._choropleth(layerName)
self.fitToLayer(layerName)
self.fire(layerName + 'loaded')
})
} else {
if ('attrs' in layerConfig) self._choropleth(layerName, layerConfig)
gLayer = new L.TopoJSON(mapJSON, layerConfig.options)
self._saveLayer(layerName, gLayer)
if ('attrs' in layerConfig) self._choropleth(layerName)
self.fitToLayer(layerName)
self.fire(layerName + 'loaded')
}
})
......@@ -208,23 +213,27 @@ MapViewer.prototype.buildLayer = function (layerName, layerConfig) {
var markerProxy = layerConfig.type.toLowerCase() === 'circle' ? L.circle : L.circleMarker
self.cacheData(layerName, layerConfig[dataOrURL(layerConfig)]).then(function (pointjson) {
var pointLayers = []
function create_layer() {
pointjson.forEach(function (d) {
var mark = markerProxy([d[layerConfig.latitude], d[layerConfig.longitude]], layerConfig.options)
mark.feature = {}
mark.feature.properties = d
pointLayers.push(mark)
})
self.fitToLayer(L.featureGroup(pointLayers))
self._saveLayer(layerName, L.featureGroup(pointLayers))
}
if ('link' in layerConfig) {
self.cacheData(layerName, layerConfig.link[dataOrURL(layerConfig.link)]).then(function (tableData) {
self.mergeData(pointjson, tableData, layerConfig.link.mapKey, layerConfig.link.dataKey)
if ('attrs' in layerConfig) self._choropleth(layerName, layerConfig)
self.fire(layerName + 'loaded')
create_layer()
if ('attrs' in layerConfig) self._choropleth(layerName)
self.fitToLayer(layerName)
})
} else {
if ('attrs' in layerConfig) self._choropleth(layerName, layerConfig)
self.fire(layerName + 'loaded')
create_layer()
if ('attrs' in layerConfig) self._choropleth(layerName)
self.fitToLayer(layerName)
}
})
break
......@@ -238,27 +247,36 @@ MapViewer.prototype._choropleth = function (layerName, layerConfig) {
layer.eachLayer(function (sublayer) {
var style = {}, prop, metricFormula, metric, domain
for (prop in layerConfig.attrs) {
if(prop.toLowerCase() == 'tooltip') continue
metric = layerConfig.attrs[prop].metric
for (prop in self.options.layers[layerName].attrs) {
if (prop.toLowerCase() == 'tooltip') continue
if (typeof (self.options.layers[layerName].attrs[prop]) != 'object') {
style[prop] = self.options.layers[layerName].attrs[prop]
continue
}
metric = self.options.layers[layerName].attrs[prop].metric
if (typeof (metric) === 'string')
metricFormula = (row) => row[metric]
else
metricFormula = metric
if (layerConfig.attrs[prop].domain)
domain = layerConfig.attrs[prop].domain
if (self.options.layers[layerName].attrs[prop].domain)
domain = self.options.layers[layerName].attrs[prop].domain
else
domain = self._calculateMinMax(layer, metricFormula)
// TODO: ENH: cache _calculateMinMax for each property bcz its same for each sublayer
if (prop === "fillColor" || prop === "color") {
// skip scale if sublayer.feature.properties do not have that metric, shows as per settings in `options: {style: ...}`
if (metricFormula(sublayer.feature.properties) !== undefined)
style[prop] = scale([], {
metric: metric,
domain: domain,
scheme: layerConfig.attrs[prop].range
scheme: self.options.layers[layerName].attrs[prop].scheme,
scale: self.options.layers[layerName].attrs[prop].scale,
range: self.options.layers[layerName].attrs[prop].range
})(sublayer.feature.properties)
}
}
sublayer.setStyle(style)
})
}
......
......@@ -51,7 +51,6 @@ function scale (data, config) {
}
var domain = config.domain || d3.extent(data, metricFormula)
if (color) {
result = d3['scale' + scale](d3[color])
.domain(domain)
......
......@@ -54,7 +54,7 @@
attrs: {
fillColor: {
metric: 'TOT_P',
range: 'RdYlGn'
scheme: 'Viridis'
},
tooltip: function (properties) {
return properties['ST_NM']
......@@ -73,7 +73,7 @@
attrs: {
fillColor: {
metric: 'DT_CEN_CD',
range: 'RdYlGn'
scheme: 'Viridis'
},
tooltip: function (properties) {
return 'DISTRICT: ' + properties['DISTRICT']
......@@ -89,7 +89,7 @@
attrs: {
fillColor: {
metric: 'TOT_P',
range: 'RdYlGn'
scheme: 'Viridis'
},
tooltip: function (properties) {
return '<h5 style="background-color: yellow;"> VILLAGE: ' + properties['NAME'] + '</h5>'
......
......@@ -48,7 +48,7 @@
attrs: {
fillColor: {
metric: function (row) { return row['pollution'] + row['crimes'] },
range: 'RdYlGn'
scheme: 'Viridis'
},
tooltip: 'just some tooltip text test'
}
......@@ -74,7 +74,7 @@
attrs: {
fillColor: {
metric: 'score',
range: 'RdYlGn'
scheme: 'Viridis'
},
tooltip: function (d) {
return d.ST_NM + ' : ' + d.score
......@@ -97,7 +97,7 @@
attrs: {
fillColor: {
metric: function (row) { return row['pollution'] + row['crimes'] },
range: 'RdYlGn'
scheme: 'Viridis'
},
tooltip: function (d) {
return 'just some tooltip text test' + d.name
......
......@@ -43,6 +43,8 @@
<div id="marker-map" style="height:300px"></div>
<script>
// TODO: write test case to see if properties are merged for choropleth?
// TODO: circle markers mergedata functions properly
var marker_map = g1.mapviewer({
id: 'marker-map',
layers: {
......@@ -105,13 +107,10 @@
url: 'cities.json',
latitude: 'lat',
longitude: 'long',
options: {
title: 'column-name' // TODO: implement as popup,
},
attrs: {
fillColor: {
metric: function (row) { return row['pollution'] + row['crimes'] },
range: 'RdYlGn'
scheme: 'Viridis'
}
}
}
......@@ -124,6 +123,7 @@
circle_svg.each(function () {
circle_fill.push($(this).attr('fill'))
})
console.log("check", circle_fill, new Set(circle_fill))
// tests if all colors are distinct
test.equals(circle_fill.length, (new Set(circle_fill)).size)
test.end()
......@@ -154,10 +154,18 @@
dataKey: 'name',
mapKey: 'ST_NM'
},
options: {
style: {
fillColor: '#ccc',
fillOpacity: 0.9
}
},
attrs: {
fillColor: {
metric: 'TOT_P',
range: 'RdYlGn'
metric: 'score', // same as function(d) { return d.age }
scale: 'linear',
domain: [10, 15, 30],
range: ['red', 'yellow', 'green'],
}
}
}
......@@ -230,7 +238,7 @@
attrs: {
fillColor: {
metric: 'TOT_P',
range: 'RdYlGn'
scheme: 'Viridis'
},
weight: {
metric: 'P_06',
......@@ -250,7 +258,7 @@
attrs: {
fillColor: {
metric: 'pollution',
range: 'RdYlGn',
scheme: 'Viridis',
domain: [0, 500]
},
weight: {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment