How to add multiple layers in leaflet and update them dynamically - javascript

I am using leaflet to draw a layer and show the Line String data in the map.But since I have a lot of LineString (40000) data it takes a lot of time to render in one layer.So I decided to split the data into seperate layers and then update the layers one by one So each layer will have less amount of data to render.
var map = L.map('map').setView([36.447488,102.463303], 12);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=token', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(map);
var options = {
position: 'topleft',
title: 'Search',
placeholder: 'enter id ',
maxResultLength: 15,
threshold: 0.5,
showInvisibleFeatures: true,
showResultFct: function(feature,container) {
props = feature.properties;
var name = L.DomUtil.create('b', null, container);
name.innerHTML = props.id;
container.appendChild(L.DomUtil.create('br', null, container));
var cat = props.id
info = '' + cat + ', ' + 'th id';
container.appendChild(document.createTextNode(info));
}
};
var searchCtrl = L.control.fuseSearch(options);
searchCtrl.addTo(map);
var geojson;
function getColor(d) {
if(d==10 || d==9 || d==8){
return '#ff0000';
}
else {
return '#00ff65';
}
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: getColor(feature.properties.points),
fillOpacity: 0.7,
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 2,
color:'#007d80',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
map.doubleClickZoom.disable();
}
var info = L.control();
info.update = function (props) {
this._div.innerHTML = '<h4><b>Link: <b></h4>' + (props ?
'<b>LineString ' + props.id + '</b><br />'
: 'Hover over a LineSting');
};
function onEachFeature(feature, layer) {
feature.layer = layer;
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
});
var popupContent =
'<b>Link ' + feature.properties.id + '</b>';
layer.bindPopup(popupContent);
feature.layer = layer;
}
function mapupdatecolor(){
$.ajax({
type: "GET",
async : false,
url: 'http:dataurl',
success: function(data) {
console.log("sucess");
for (i = 0; i<40000; i++) {
links['features'][i]['properties']['points']=data[i].points;
}
if (geojson) {
geojson.remove();
console.log("removed");
}
function picnicFilter(feature) {
if (feature.properties.points >= 9) return true
}
geojson = L.geoJson(lines, {
filter: picnicFilter,
style: style,
onEachFeature: onEachFeature
}).addTo(map);
console.log("update done");
},
error: function (xhr, ajaxOptions, thrownError) {
alert(thrownError);
},
complete: function() {
setTimeout(mapupdatecolor, 5000);
}
});
// schedule the first invocation:
}
geojson = L.geoJson(lines, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this.update();
return this._div;
};
searchCtrl.indexFeatures(links.features, ['id']);
info.addTo(map);
setTimeout( mapupdatecolor, 5000);
So the above code is to render all the LineString initially and then after the update of the points just display the LineStrings which have points >=9.But now I would like to draw multiple layers(say 10) and then draw the whole LineStrings(40000) in those 10 layers.(400 LineStrings per layer). Will increase the speed of rendering the map?
Update:
So I tried with Leaflet.VectorGrid and it is plotting the map a bit fast but when i zoom in all the lines get invisible .
var map = L.map('map');
var canvasRenderer = L.canvas();
var cartodbAttribution = '© OpenStreetMap contributors, © CartoDB';
var positron =L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=token', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(map);
function getColor(d) {
if(d==10 || d==9 || d==8){
return '#ff0000';
}
else {
return '#00ff65';
}
}
var highlight;
var clearHighlight = function() {
if (highlight) {
vectorGrid.resetFeatureStyle(highlight);
}
highlight = null;
};
var vectorGrid = L.vectorGrid.slicer(lines, {
rendererFactory: L.svg.tile,
vectorTileLayerStyles: {
sliced: function(properties, zoom) {
return {
weight: 2,
opacity: 1,
color: getColor(properties.points),
fillOpacity: 0.7
}
}
},
interactive: true,
getFeatureId: function(f) {
return f.properties.id;
}
})
.on('mouseover', function(e) {
var properties = e.layer.properties;
L.popup()
.setContent(properties.id)
.setLatLng(e.latlng)
.openOn(map);
clearHighlight();
highlight = properties.id;
var p = properties.points;
var style = {
fillColor: p === 0 ? '#800026' :
p === 1 ? '#E31A1C' :
p === 2 ? '#FEB24C' :
p === 3 ? '#B2FE4C' : '#FFEDA0',
fillOpacity: 0.5,
fillOpacity: 1,
stroke: true,
fill: true,
color: 'red',
opacity: 1,
weight: 2,
};
vectorGrid.setFeatureStyle(properties.points, style);
})
.addTo(map);
map.on('click', clearHighlight);
map.setView({ lat: 36.447488, lng: 102.463303}, 12);
Any help is appreciated

Related

Make data layer disappear and different one appear on click in Leaflet

I'm mapping COVID vaccinations per state and per county in the MXN. I have state data as well as county data displaying properly.
I'm trying to make it so that when I click on a state it zooms in to the selected state, turns off the state data layer and turns on the county data layer. So basically it goes from showing state data to county data.
How do I do this? Would I need to add something to the zoomTofeature function?
var map = L.map("map", {
center: [24.0376106, -102.9590598],
zoom: 4.5,
});
// add basemap
var Stamen_TonerLite = L.tileLayer(
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
{
attribution:
'© OpenStreetMap'
maxZoom: 18,
minZoom: 3,
}
).addTo(map);
//zoom to a state, turn off state data, turn on county data
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
//zoom to county
function zoomToFeature1(e) {
map.fitBounds(e.target.getBounds());
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 4,
opacity: 1,
color: "#dbff4d",
});
layer.bringToFront();
}
function highlightFeature1(e) {
var layer = e.target;
layer.setStyle({
weight: 4,
opacity: 1,
color: "#dbff4d",
});
layer.bringToFront();
}
//reset the hightlighted states on mouseout
function resetHighlight(e) {
geojsonStates.resetStyle(e.target);
}
//reset the hightlighted counties on mouseout
function resetHighlight1(e) {
geojsonCounties.resetStyle(e.target);
}
//add these events to the layer object
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
click: zoomToFeature,
mouseout: resetHighlight,
});
}
//add these events to the layer object
function onEachFeature1(feature, layer) {
layer.on({
mouseover: highlightFeature1,
click: zoomToFeature1,
mouseout: resetHighlight1,
});
}
function getColor(d) {
return d > 70
? "#2c7bb6"
: d >= 60
? "#abd9e9"
: d >= 50
? "#fdae61"
: d < 50
? "#d7191c"
: "#5f5f5f";
}
function getColor1(d) {
return d >= 75
? "#1a9641"
: d >= 50
? "#a6d96a"
: d >= 25
? "#fdae61"
: d > 0
? "#d7191c"
: "#5f5f5f";
}
function states(feature) {
return {
weight: 3,
opacity: 1,
color: "whitesmoke",
fillOpacity: 0.8,
fillColor: getColor(feature.properties.vaxData_states_Series_Complete),
};
}
function counties(feature) {
return {
weight: 0.5,
opacity: 0.5,
color: "whitesmoke",
fillOpacity: 0.75,
fillColor: getColor1(feature.properties.vaxData_Series_Complete),
};
}
// add state borders
var geojsonStates = L.geoJson.ajax("data/us_states.geojson", {
style: states,
onEachFeature: onEachFeature,
});
geojsonStates.addTo(map);
//add county geojson
var geojsonCounties = L.geoJson.ajax("data/counties.geojson", {
style: counties,
onEachFeature: onEachFeature1,
});
geojsonCounties.addTo(map);
I hope you can help me and I have had this issue for more than a week and I don't know what the problem could be.

Leaflet: maps are not updated

I developed dynamic graphics with Leaflet.js in my project using my local machine. When applying some filters, the map must be updated. On the local machine it works perfectly. However, when uploading to my university's server, I ran into a problem: the maps are not being updated. I've tried using map.remove and map.off, but they're still the same. Looks like the map is still kept in some kind of cache. My application is being developed in PHP + Postgres + Apache. How can I solve?
My code:
function mapGenerator(zoom, coords, title, dataSource, yearCollection, typeTerritory, rangeLegend, user) {
if (user) {
mapUrl = "../assets/js/temp-geojson/" + user + "|geojson.js";
} else {
mapUrl = "../assets/js/temp-geojson/geojson.js";
}
if (map !== undefined && map !== null) {
map.off();
map.remove();
}
map = L.map('map').setView(coords, zoom);
map.spin(true);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
minZoom: 2,
maxZoom: 18,
attribution: '© OpenStreetMap contributors',
id: 'mapbox/light-v9',
tileSize: 512,
zoomOffset: -1
}).addTo(map);
// control that shows state info on hover
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h6><b>' + title + ' por ' + typeTerritory + '</b></h6>' + (props ?
'<b>' + props.localizacao + '</b>: ' +
'<br>' + props.valor.toLocaleString() + ' ha.'
: 'Passe o mouse sobre a localização desejada');
};
info.addTo(map);
// get color depending on population density value
function getColor(d) {
return d > rangeLegend[6] ? '#12500c' :
d > rangeLegend[5] ? '#36640f' :
d > rangeLegend[4] ? '#547915' :
d > rangeLegend[3] ? '#728f1f' :
d > rangeLegend[2] ? '#90a52d' :
d > rangeLegend[1] ? '#c8d029' :
d > rangeLegend[0] ? '#e5e738' :
'#ffff5b';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.valor)
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
var geojson;
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: function () {
layer.bindPopup('<b>' + feature.properties.localizacao + '</b>' +
'<br>' + feature.properties.valor.toLocaleString() + ' ha.').openPopup()
}
});
}

leaflet geojsos, updating makers with Ajax, how to remove all markers before re adding?

Im using GeoJSON with leaflet to insert markers onto a map, I then have a Ajax request periodically update the icons every 60 seconds with their latest state (they go red or green if the location is up or down)
However it's been noted that the page looked like it had a memory leak, on further investigations we can see that additional markers are added on each refresh, so with 100 markers on the map after an hour we have 6000 markers. Can anyone help me on making the existing markers update based on the new data or remove and re add them?
current code below
Thanks
<script type="text/javascript">
var map = L.map('map').setView([54.0,-3.4], 7);
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox/dark-v10',
accessToken: 'pk.*****'
}).addTo(map);
$(function() {
function update_maps() {
// Update the pins in the amaps
$.get('/monitoring/data/status_map_geo_data/gb/', function(geo_data) {
L.geoJSON(geo_data, {
pointToLayer: function (feature, latlng) {
var zindex = feature.properties.z_index && feature.properties.z_index !== "null";
return L.marker(latlng, {
zIndexOffset: zindex ? 1000 : 0,
icon: L.AwesomeMarkers.icon(
{
icon: feature.properties.icon,
markerColor: feature.properties.color,
prefix: 'fa',
iconColor: 'white',
}
)
}
);
},
onEachFeature: function (feature, layer) {
var layer_text = '<h3>'+feature.properties.popupContent+'</h3>'
layer.bindPopup(layer_text)
}
}).addTo(map);
});
}
$(document).ready(function() {
// load icons on start
update_maps()
});
// refresh page
setInterval(function() {
update_maps()
}, 60 * 1000);
});
</script>
This is a simple solution, L.geoJSON returns a group with the markers, this group can be cleared with .clearLayers().
So change your code to:
var geoJsonGroup = null;
function update_maps() {
// Update the pins in the amaps
$.get('/monitoring/data/status_map_geo_data/gb/', function(geo_data) {
if(geoJsonGroup){
geoJsonGroup.clearLayers();
}
geoJsonGroup = L.geoJSON(geo_data, {
pointToLayer: function (feature, latlng) {
var zindex = feature.properties.z_index && feature.properties.z_index !== "null";
return L.marker(latlng, {
zIndexOffset: zindex ? 1000 : 0,
icon: L.AwesomeMarkers.icon(
{
icon: feature.properties.icon,
markerColor: feature.properties.color,
prefix: 'fa',
iconColor: 'white',
}
)
}
);
},
onEachFeature: function (feature, layer) {
var layer_text = '<h3>'+feature.properties.popupContent+'</h3>'
layer.bindPopup(layer_text)
}
}).addTo(map);
});
}
Alternatives (From #gyhbs) "Many roads lead to Rome":
Call geoJsonGroup.removeFrom(map) instead of geoJsonGroup.clearLayers();
Put the L.geoJSON outside and then call addData instead of creating a new group everytime:
var geoJsonGroup = L.geoJSON(null, {
pointToLayer: function(feature, latlng) {
var zindex = feature.properties.z_index && feature.properties.z_index !== "null";
return L.marker(latlng, {
zIndexOffset: zindex ? 1000 : 0,
icon: L.AwesomeMarkers.icon({
icon: feature.properties.icon,
markerColor: feature.properties.color,
prefix: 'fa',
iconColor: 'white',
})
});
},
onEachFeature: function(feature, layer) {
var layer_text = '<h3>' + feature.properties.popupContent + '</h3>'
layer.bindPopup(layer_text)
}
}).addTo(map);
function update_maps() {
// Update the pins in the amaps
$.get('/monitoring/data/status_map_geo_data/gb/', function(geo_data) {
if (geoJsonGroup) {
geoJsonGroup.clearLayers();
}
geoJsonGroup.addData(geo_data)
});
}

Color not changing after the change of geoJSON property

I am using mapbox and leaflet to plot lines in a map and below is my code:
var lines= {
"type":"FeatureCollection",
"features": [
{
"type": "Feature",
"geometry":{"type":"LineString",
"coordinates":[[103.85909,1.2941],[103.85895,1.2940450000000001],[103.85881,1.29399]]},
"properties": {"id":"01","score":10}
}
// totally having 100 elements in the array
]};
var map = L.map('map').setView([1.3096622448984000, 103.7689017333800], 12);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=token', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(map);
map.doubleClickZoom.disable();
var options = {
position: 'topleft',
title: 'Search',
placeholder: 'enter link id ',
maxResultLength: 15,
threshold: 0.5,
showInvisibleFeatures: true,
showResultFct: function(feature, container) {
props = feature.properties;
var name = L.DomUtil.create('b', null, container);
name.innerHTML = props.id;
container.appendChild(L.DomUtil.create('br', null, container));
var cat = props.id
info = '' + cat + ', ' + 'th link';
container.appendChild(document.createTextNode(info));
}
};
var searchCtrl = L.control.fuseSearch(options);
searchCtrl.addTo(map);
var geojson;
function getColor(d) {
if(d=10){
return '#ff0000';
}
else if(d<10){
return '#00FF00';
}
else{
return '#00FF00';
}
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: getColor(feature.properties.score),
fillOpacity: 0.7,
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 5,
color:'#0000FF',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
map.doubleClickZoom.disable();
}
var info = L.control();
info.update = function (props) {
this._div.innerHTML = '<h4><b>August 2016: <b></h4>' + (props ?
'<b>Link ' + props.id + '</b><br />'
: 'Hover over a link');
};
function onEachFeature(feature, layer) {
feature.layer = layer;
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
});
var popupContent =
'<b>Link ' + feature.properties.id + '</b>';
layer.bindPopup(popupContent);
feature.layer = layer;
}
function mapupdatecolor(){
$.ajax({
type: "GET",
url: 'http://'+backend+':8081/lines',
success: function(data) {
//data is 100 elements data array in the form of [{"street":1,"score":8},....
for (i = 0; i <100; i++) {
console.log("1 time score in console--"+zones['features'][i]['properties']['score']);
lines['features'][i]['properties']['score']=data[i].score;
console.log(data[i].score)
console.log("2 time score in console after change--"+lines['features'][i]['properties']['score']);
}
if (geojson) {
geojson.remove();
console.log("removed");
}
geojson = L.geoJson(lines, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
console.log("update done")
},
error: function (xhr, ajaxOptions, thrownError) {
alert(thrownError);
},
complete: function() {
setTimeout(mapupdatecolor, 1000);
}
});
}
geojson = L.geoJson(lines, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this.update();
return this._div;
};
searchCtrl.indexFeatures(lines.features, ['id']);
info.addTo(map);
setTimeout( mapupdatecolor, 1000);
So setTimeout( mapupdatecolor, 1000) lines calls the ajax call for every time period and then the score of the line is expected to be changed.For the first element initially score is 10 and after the first call it should change to 8 and the color also should change.When I run this it displays
1 time score in console--10
8
2 time score in console after change--8
in the console.But the color of line is not changing(it should change because in the getColor function d is 8 and not 10 so it should change to green instead of red ).Any help is appreciated.
Here is the problem :
if(d=10){
return '#ff0000';
}
The expression (d=10) is always true. Use (d === 10) instead.
IMHO you could have tested the behaviour of your getColor function before asking and showing such a big amount of code. The question seems to be related with Leaflet and in fact it is not.

Add external links to leaflet polygon

I use leaflet to display geographic zone with multiple polygons on a map and I want to link on click each layer to a webpage. For example the link (http://wikipedia.com) should be in replacement of "alert("You clicked the map at " + e.latlng);"
var map = L.map('map').setView([45.7676067, 4.8351733], 6);
var cloudmade = L.tileLayer('http://{s}.tile.cloudmade.com/{key}/{styleId}/256/{z}/{x}/{y}.png', {
attribution: 'Map data © 2011 OpenStreetMap, Imagery © 2012 CloudMade',
key: 'My Key',
styleId: 22677
}).addTo(map);
// control that shows state info on hover
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h4>Région</h4>' + (props ?
'<b>' + props.Name + '</b><br />'
: 'Survollez une région');
};
info.addTo(map);
// get color depending on population density value
function getColor(d) {
return d > 1000 ? '#800026' :
d > 500 ? '#BD0026' :
d > 200 ? '#E31A1C' :
d > 100 ? '#FC4E2A' :
d > 50 ? '#FD8D3C' :
d > 20 ? '#FEB24C' :
d > 10 ? '#FED976' :
'#FFEDA0';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor('10')
};
}
function highlightFeature(e) {
var layer = e.target;
layer.setStyle({
weight: 3,
color: '#666',
dashArray: '',
fillOpacity: 0.7,
fillColor: getColor('50')
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
info.update(layer.feature.properties);
}
var geojson;
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onMapClick(e) {
alert("You clicked the map at " + e.latlng);
}
map.on('click', onMapClick);
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
//click: zoomToFeature
click: onMapClick
});
}
geojson = L.geoJson(regions, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
</script>
Thanks for you help
You should be able to use a simple window redirect in the onMapClick function:
window.location = "http://www.google.com"
or to open in a new tab or window use window.open

Categories

Resources