Commit 9b4e34e5 authored by S Anand's avatar S Anand

ENH: mapviewer addNote, add/remove layer, show mismatches

Fixes #112
Fixes #118
By @bharat.r
parent f36ecaa0
Pipeline #72945 passed with stage
in 2 minutes and 18 seconds
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -18,5 +18,17 @@
{
"score": 20.940920,
"name": "Odisha"
},
{
"score": 20.940920,
"name": "Odisa"
},
{
"score": 20.940920,
"name": "Karnatak"
},
{
"score": 20.940920,
"name": "Andra Pradesh"
}
]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>MapViewer</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="tape.js"></script>
<link rel="stylesheet" href="../node_modules/leaflet/dist/leaflet.css">
<style>
.error-pane {
height: 200px;
overflow-y: scroll;
width: 200px;
}
.map {
position: absolute;
height: 300px;
}
</style>
</head>
<body>
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
<script src="../node_modules/leaflet/dist/leaflet.js"></script>
<script src="../node_modules/d3/build/d3.js"></script>
<script src="../node_modules/d3-scale-chromatic/dist/d3-scale-chromatic.min.js"></script>
<script src="../dist/mapviewer.min.js"></script>
<div class="error-pane"></div>
<div id="geojson-map-1" style="height:300px"></div>
<div id="geojson-map-2" style="height:300px"></div>
<script>
var map_config = {
options: {
style: {
fillColor: '#ccc',
fillOpacity: 0.9
}
},
attrs: {
fillColor: {
metric: 'score', // same as function(d) { return d.age }
scale: 'linear',
domain: [10, 15, 30],
range: ['red', 'yellow', 'green'],
}
}
}
tape.onFinish(function () {
window.renderComplete = true
})
</script>
<script>
var mismatch_array = []
var state_scores = ''
var geojson_map_1, geojson_map_2
$.get("state_score.json", function (resp) {
state_scores = resp
tape("g1.mapviewer data mismatch", function (test) {
geojson_map_1 = g1.mapviewer({
id: 'geojson-map-1',
layers: {
indiaGeojson: {
type: 'geojson',
url: 'india-states.geojson',
link: {
url: state_scores,
dataKey: 'name',
mapKey: 'ST_NM'
// mismatch: false // can be a function that accepts array of objects (each object cnotains status, feature properties)
},
options: map_config.options,
attrs: map_config.attrs
}
}
})
geojson_map_2 = g1.mapviewer({
id: 'geojson-map-2',
layers: {
indiaGeojson: {
type: 'geojson',
url: 'india-states.geojson',
link: {
url: state_scores,
dataKey: 'name',
mapKey: 'ST_NM',
mismatch: function (ary) { // can be true or a function that accepts array of objects (each object contains status, feature properties)
mismatch_array = ary
// console.log("Mismatch fields.. ", ary)
var custom_message = `<h2>List of Data Mismatches</h2>`
custom_message += `<table>`
mismatch_array.forEach(function(obj){
custom_message += `<tr><td>${obj.feature.properties.ST_NM}</td></tr>`
})
custom_message += `</table>`
$('.error-pane')
.html(custom_message)
test.equals(mismatch_array.length, 30)
test.end()
}
},
options: map_config.options,
attrs: map_config.attrs
}
}
})
geojson_map_1.on('indiaGeojsonloaded', function () {
var mismatch_fields = []
mismatch_array.forEach(function (f) {
mismatch_fields.push(f.feature.properties.ST_NM.toLowerCase())
})
test.notEquals(document.querySelector('.mismatch-log'), null)
test.equals(document.querySelector('.mismatch-log').innerHTML, '30 Mismatches found!')
})
})
})
</script>
</body>
</html>
......@@ -55,7 +55,7 @@
scheme: 'Viridis'
},
tooltip: function (properties) {
return properties['ST_NM']
return properties['ST_NM']
}
}
},
......@@ -64,9 +64,9 @@
rootLayer: 'indiaGeojson',
levels: [
{
layerName: function(props) { return props['ST_NM'].toLowerCase() + '-layer'},
layerName: function (props) { return props['ST_NM'].toLowerCase() + '-layer' },
layerOptions: {
url: function(props) { return props['ST_NM'].toLowerCase() + '-census.json'},
url: function (props) { return props['ST_NM'].toLowerCase() + '-census.json' },
type: 'geojson',
attrs: {
fillColor: {
......@@ -112,13 +112,13 @@
kerala_layer.fireEvent('click')
// once again the 'layersload' event is fired and map should drilldown
drilldown_map.on('kerala-layer'+'loaded', function () {
drilldown_map.on('kerala-layer' + 'loaded', function () {
kerala_drill_bounds = drilldown_map.map.getBounds()
drillleveltwo()
test.ok(Object.keys(drilldown_map.gLayers).indexOf('kerala-layer') > -1)
}, {
once: true
})
once: true
})
}
function drillleveltwo() {
......@@ -128,14 +128,14 @@
ernakulam_layer = sublayer
}
})
drilldown_map.on('ernakulam-layer'+'loaded', function () {
drilldown_map.on('ernakulam-layer' + 'loaded', function () {
test.ok(Object.keys(drilldown_map.gLayers).indexOf('ernakulam-layer') > -1)
drilldown_map.drillup()
test.deepEquals(drilldown_map.map.getBounds(), kerala_drill_bounds)
test.end()
})
ernakulam_layer.fireEvent('click')
ernakulam_layer.fireEvent('click')
}
drilllevelone()
})
......@@ -150,4 +150,143 @@
})
</script>
<div id="drilldown-map-2" style="height:400px"></div>
<script>
var drilldown_map_2
tape("g1.mapviewer Drilldown for 5 levels - test if drilldown zoom for last level", function (test) {
drilldown_map_2 = g1.mapviewer({
id: 'drilldown-map-2',
fitbounds: {
animate: false
},
layers: {
world_layer: {
type: 'geojson',
url: 'world.geo.json'
}
},
drilldown: {
rootLayer: 'world_layer',
levels: [
{
layerName: "asia_layer",
layerOptions: {
type: 'geojson',
url: 'asia.geo.json'
}
},
{
layerName: "india_layer",
layerOptions: {
type: 'geojson',
url: 'india-states.geojson',
link: {
url: 'state_score.json',
dataKey: 'name',
mapKey: 'ST_NM'
},
attrs: {
fillColor: {
metric: 'TOT_P',
scheme: 'Viridis'
},
tooltip: function (properties) {
return properties['ST_NM']
}
}
}
},
{
layerName: function (props) { return props['ST_NM'].toLowerCase() + '_layer' },
layerOptions: {
url: function (props) { return props['ST_NM'].toLowerCase() + '-census.json' },
type: 'geojson',
attrs: {
fillColor: {
metric: 'DT_CEN_CD',
scheme: 'Viridis'
},
tooltip: function (properties) {
return 'DISTRICT: ' + properties['DISTRICT']
}
}
}
},
{
layerName: 'ernakulam_layer',
layerOptions: {
url: 'ernakulam-census.json',
type: 'geojson',
attrs: {
fillColor: {
metric: 'TOT_P',
scheme: 'Viridis'
},
tooltip: function (properties) {
return '<h5 style="background-color: yellow;"> VILLAGE: ' + properties['NAME'] + '</h5>'
}
}
}
}
]
}
})
var kerala_drill_bounds
drilldown_map_2.on('layersloaded', function cb(event) {
let seq = 0
event.currentTarget.removeEventListener(event.type, cb)
var drill_layers = [
{ current_layer: "world_layer", field: "CONTINENT", value: "Asia", next_layer: "asia_layer" },
{ current_layer: "asia_layer", field: "geounit", value: "India", next_layer: "india_layer" },
{ current_layer: "india_layer", field: "ST_NM", value: "Kerala", next_layer: "kerala_layer" },
{ current_layer: "kerala_layer", field: "DISTRICT", value: "Ernakulam", next_layer: "ernakulam_layer" },
{ current_layer: "ernakulam_layer" }
]
var findLayer = (root_layer, prop, key) => {
let target_layer
drilldown_map_2.gLayers[root_layer].eachLayer(function (sublayer) {
if (sublayer.feature.properties[prop].toLowerCase() == key.toLowerCase())
target_layer = sublayer
})
return target_layer
}
function drilldown() {
let level = drill_layers[seq++]
drilldown_map_2.on(level.current_layer + "loaded", function () {
kerala_drill_bounds = drilldown_map_2.map.getBounds()
test.ok(Object.keys(drilldown_map_2.gLayers).indexOf(level.current_layer) > -1)
test.deepEquals(drilldown_map_2.map.getBounds(), kerala_drill_bounds)
if (seq < 5) {
let temp_layer = findLayer(level.current_layer, level.field, level.value)
temp_layer.fireEvent('click')
drilldown()
} else
test.end()
})
}
drilldown()
})
$("#drilldown-map-2 .leaflet-control-zoom-in").removeAttr('href').addClass('cursor-pointer')
$("#drilldown-map-2 .leaflet-control-zoom-out").removeAttr('href').addClass('cursor-pointer')
$("#drilldown-map-2 .leaflet-control-zoom").append('<a class="leaflet-control-zoom-reset" href="#" title="Zoom reset" role="button" aria-label="Zoom out"><i class="fa fa-undo fa-lg"></i></a>')
$("#drilldown-map-2 .leaflet-control-zoom-reset").on("click", function (evt) {
evt.preventDefault()
drilldown_map_2.drillup()
})
})
</script>
</body>
</html>
......@@ -67,6 +67,9 @@
tape("g1.mapviewer test if tooltip is added to the circle marker", function (test) {
var tooltip_map = g1.mapviewer({
id: 'tooltip-map',
map: {
zoomAnimation: true
},
layers: {
// worldMap: { type: 'tile', url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' },
cityMarkers: {
......@@ -74,11 +77,6 @@
url: 'cities.json',
latitude: 'lat',
longitude: 'long',
options: {
icon: L.divIcon({
className: 'anything'
})
},
tooltip: function (d) {
return d.name
......@@ -88,7 +86,7 @@
return args.centerPoint[1] > args.tooltipPoint.x[1] ? 'top' : 'bottom'
},
permanent: true
}
},
},
indiaGeojson: {
......@@ -99,6 +97,8 @@
dataKey: 'name',
mapKey: 'ST_NM'
},
attrs: {
fillColor: {
metric: 'score',
......@@ -109,8 +109,7 @@
}
})
tooltip_map.zoomHandler('cityMarkers', 5)
tooltip_map.on('mapviewerloaded', function () {
tooltip_map.on('layersloaded', function () {
tooltip_map.gLayers['cityMarkers'].eachLayer(function (sublayer) {
test.ok(tooltip_map.map.hasLayer(sublayer._tooltip))
})
......@@ -126,6 +125,9 @@
var tooltipFunction_map = g1.mapviewer({
id: 'tooltipFunction-map',
map: {
zoomAnimation: false
},
layers: {
worldMap: { type: 'tile', url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' },
indiaGeojson: {
......@@ -182,7 +184,7 @@
}
})
tooltipFunction_map.on('mapviewerloaded', function () {
tooltipFunction_map.on('layersloaded', function () {
tooltipFunction_map.gLayers['cityMarkers'].eachLayer(function (sublayer) {
test.notOk(tooltipFunction_map.map.hasLayer(sublayer._tooltip))
})
......@@ -201,10 +203,10 @@
// // 'screenY': 588
// }))
tooltipFunction_map.gLayers['cityMarkers'].eachLayer(function (sublayer) {
test.ok(tooltipFunction_map.map.hasLayer(sublayer._tooltip))
test.ok(tooltipFunction_map.map.hasLayer(sublayer._tooltip)) // "cityMarkers 5 hasLayer"
})
tooltipFunction_map.gLayers['cityCircleMarkers'].eachLayer(function (sublayer) {
test.ok(tooltipFunction_map.map.hasLayer(sublayer._tooltip))
test.ok(tooltipFunction_map.map.hasLayer(sublayer._tooltip)) // "cityCircleMarkers 5 hasLayer"
})
// $('.leaflet-interactive', $('#tooltipFunction-map')).dispatch('mouseout')
......
......@@ -60,7 +60,8 @@
test.end()
})
</script>
<br>
<hr><br>
<div id="marker-map" style="height:300px"></div>
<script>
// TODO: write test case to see if properties are merged for choropleth?
......@@ -81,7 +82,7 @@
}
})
// document.getElementById('marker-map').addEventListener('loadmarker-map', function() {
marker_map.on('mapviewerloaded', function() {
marker_map.on('mapviewerloaded', function () {
tape("g1.mapviewer test if markers are plotted on map", function (test) {
test.equals($("#marker-map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-marker-pane").children().length, 5)
......@@ -105,7 +106,7 @@
})
tape("g1.mapviewer test if markers are positioned as per lat lng even when map pane is moved", function (test) {
marker_map.map.setView([29.23, 76.4], 3)
marker_map.map.on('zoomend', function() {
marker_map.map.on('zoomend', function () {
test.equals(Object.values(marker_map.gLayers.cityMarkers._layers)[0]._latlng.lat, 29.238478434343)
test.equals(Object.values(marker_map.gLayers.cityMarkers._layers)[0]._latlng.lng, 76.431885)
// reset map zoom and center
......@@ -193,20 +194,20 @@
}
})
tape("g1.mapviewer geojson layers", function(t) {
tape("g1.mapviewer geojson layers", function (t) {
// geojson_map.on("loadgeojson-map", function () {
document.getElementById("geojson-map").addEventListener("loadgeojson-map", function () {
tape("g1.mapviewer geojson is parsed and loaded", function(test) {
test.equals($("#geojson-map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > svg > g").children().length, 34)
test.end()
})
tape("g1.mapviewer geojson is parsed and loaded", function (test) {
test.equals($("#geojson-map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > svg > g").children().length, 34)
test.end()
})
// To merge data and load choropleth
tape("g1.mapviewer linked dataset properties are added to geojson layer properties", function (test) {
setTimeout(() => {
var odisha_properties
geojson_map.gLayers.indiaGeojson.eachLayer(function(sublayer) {
if(sublayer.feature.properties.ST_NM === "Odisha") {
geojson_map.gLayers.indiaGeojson.eachLayer(function (sublayer) {
if (sublayer.feature.properties.ST_NM === "Odisha") {
odisha_properties = sublayer.feature.properties
}
})
......@@ -221,7 +222,7 @@
// TODO: if metric is not found in properties all states are of default color
</script>
</script>
<div class="map" id="mapid"></div>
<script type="text/javascript">
......@@ -356,7 +357,7 @@
// mapviewer2.cacheData('testLayerName2', tiny_geojson).then(function(response) {
// test.ok(JSON.stringify(response).hashCode() in mapviewer2.gData, "passing dataset in cache data")
// })
merged_geojson = mapviewer2.mergeData(tiny_geojson, tiny_data, 'mKey', 'dKey')
merged_geojson = mapviewer2.mergeData(tiny_geojson, tiny_data, { mapKey: 'mKey', dataKey: 'dKey' })
test.equals(merged_geojson.features[0].properties.score, 33)
test.equals(merged_geojson.features[0].properties.dKey, tiny_geojson.features[0].properties.mKey)
test.equals(merged_geojson.features[1].properties.score, undefined)
......@@ -380,6 +381,75 @@
// tape("g1.mapviewer test if cacheData hashcode works when data object is given", function (test) {
// test.end()
// })
</script>
<div id="popup-map" style="height:300px"></div>
<script>
var popup_map
var newLayer = {
type: 'marker',
url: 'cities.json',
latitude: 'lat',
longitude: 'long',
popup: function (d) {
return d.name
},
popupOptions: {
closeButton: false
}
}
tape("g1.mapviewer test removeLayer & addLayer", function (test) {
popup_map = g1.mapviewer({
id: 'popup-map',
layers: {
cityMarkers: {
type: 'marker',
url: 'cities.json',
latitude: 'lat',
longitude: 'long',
popup: function (d) {
return d.name
},
popupOptions: {
closeButton: false
}
},
indiaGeojson: {
type: 'geojson',
url: 'india-states.geojson',
link: {
url: 'state_score.json',
dataKey: 'name',
mapKey: 'ST_NM'
},
attrs: {
fillColor: {
metric: 'score',
scheme: 'Viridis'
}
}
}
}
})
popup_map.on('cityMarkersloaded', function () {
popup_map.removeLayer('cityMarkers')
test.equals($("#popup-map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-marker-pane").children().length, 0)
popup_map.addLayer('cityMarkers')
test.ok($("#popup-map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-marker-pane").children().length > 0)
popup_map.addLayer('cityMarkers2', newLayer)
popup_map.on('cityMarkers2loaded', function(){
test.ok($("#popup-map > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-marker-pane").children().length === 10)
test.ok(popup_map.gLayers.cityMarkers2)
test.end()
})
})
})
</script>
<script>
tape.onFinish(function () { window.renderComplete = true })
</script>
</body>
......
This diff is collapsed.
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