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()
}
});
}
Related
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.
Alright, I don't really know where the issue in my code lies, but maybe it will be obvious to some of you.
I have an html form that includes names of all US states that correspond to numerical values in a geoJSON of all US counties. I use jquery function to get the user selected value, and JS to filter by state and only add those counties to my choropleth map.
// get value from form
var value;
$('select').on('click', function() {
value = this.value;
return value;
})
//filter by state value
var filtered = L.geoJson(counties, {
filter: function (features, layer) {
return features.properties.STATE == value
}
});
I then assign those counties a color based on the Count field (which is default gray) from the geoJSON and have listeners that highlight the county and update an info div on mouseover.
// create gradient
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';
}
// determine fill
function style(feature) {
if (feature.properties.Count >= 1 && feature.properties.STATE == value) {
return {
fillColor: getColor(feature.properties.Count),
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
} else if (feature.properties.value != value && feature.properties.Count >= 1) {
return {
fillColor: '#DDD',
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
}
} else {
return {
fillColor: '#DDD',
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
}
}
}
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);
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
info.update();
}
var geojson;
// listeners
geojson = filtered;
function zoomToFeature(e) {
map.fitBounds(e.target.getBounds());
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
geojson = L.geoJson(counties, {
style: style,
onEachFeature: onEachFeature
}).addTo(mymap);
var info = L.control();
info.onAdd = function (mymap) {
this._div = L.DomUtil.create('div', 'info'); // create info div
this.update();
return this._div;
};
// update info on hover
info.update = function (props) {
this._div.innerHTML = '<h4>2020 Sales</h4>' + (props ?
props.NAME + ' county: '
+ props.Count + ' sales / county' :
'Hover over a state/county');
};
info.addTo(mymap);
</script>
My problem is it only updates the filtered county fill color on mouseover of the county when a state is selected from the form, whereas I want to update the entirety of the filtered county's fill color on the state select. I have a bit more code I can include on request (css and some map setup js), but I think included the pertinent stuff.
Also, this is based on the leaflet choropleth example.
EDIT
Here is the google drive link: https://drive.google.com/drive/folders/1YMQZWgQb1UJga0SnXkYT50067KSz5il3?usp=sharing , let me know if there is an issue.
The code is too large to host live. Select a state from the list on the bottom left of the page, e.i. California, and you will see my problem
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
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.
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