I want to draw a map with few routes drawn on it.
I want to have a dropbox with numbers 1,..,n
when an item in the dropbox is chosen, the corresponding route is highlighted on the map.
I have started using "leaflet".
why doesn't my resetStyle() return the lines to their original style?
here is my code:
document.onload = loadMap();
function loadMap() {
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors,CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiZW==========yJ9.3HqHQ4BMRvSPaYe8ToA7YQ'
}).addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(map);
var myLines = [{
"type": "LineString",
"properties": {
"id": "1"
}
"coordinates": [
[-100, 40],
[-105, 45],
[-110, 55]
]
}, {
"type": "LineString",
"properties": {
"id": "2"
}
"coordinates": [
[-105, 40],
[-110, 45],
[-115, 55]
]
}];
var myLayer = L.geoJson().addTo(map);
myLayer.addData(myLines);
geojson = L.geoJson(myLines, {
onEachFeature: onEachFeature
}).addTo(map);
}
function highlightFeature(e) {
var layer = e.target;
layer
layer.setStyle({
weight: 25,
color: '#ff3300',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
layer.setStyle({
weight: 5,
color: '#0000ff',
dashArray: '',
fillOpacity: 0.7
});
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
// click: zoomToFeature
});
}
$('select[name="dropdown"]').change(function() {
var item = $(this).val();
alert("call the do something function on option " + item);
//how to make the chosen line highlighted ??
});
The resetStyle method of L.GeoJSON reset the given layer's style back to the style defined when initializing the L.GeoJSON layer:
Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
http://leafletjs.com/reference.html#geojson-resetstyle
Code example:
var geojsonLayer = new L.GeoJSON(geojson, {
style: function () {
return {
color: 'red'
}
},
onEachFeature: function (feature, layer) {
layer.on('mouseover', function () {
this.setStyle({
color: 'green'
});
});
layer.on('mouseout', function () {
geojsonLayer.resetStyle(this);
});
}
}).addTo(map);
Working example on Plunker: http://plnkr.co/edit/iriGMBYiFRizeXizMF06?p=preview
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.
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)
});
}
I tried to render the polygon-shaped surfaces on the map whenever user clicks on polygon shape layer A popup
with polygon details is displayed and the layer can be edited.In the popup, there is option to delete the polygon. After Clicking on Delete on popup I tried reinitialize the map with new surfaces i.e(polygons) data but still, the selected surface is appearing.
componentDidUpdate(prevProps, prevState) {
const { user, surfaces } = this.props;
const { allLayers } = this.state;
const that = this;
let selectedSurface = null;
if (!prevProps.user.id && user.id) {
this.initializeMap();
}
if (this.props.deleteAction.success !== prevProps.deleteAction.success) {
this.props.actionFetch();
map.remove();
this.initializeMap();
}
if ((allLayers.length === 1 && surfaces.length) || (surfaces.length !==
prevProps.surfaces.length)) {
let allLayers = [{ key: -1, name: this.props.intl.formatMessage({ id:
'surface.allsurfaces' }), color: '#CCCCCC' }];
surfaces.forEach((o) => {
let l = L.geoJSON(o.geometry)._layers;
[l] = Object.keys(l).map(ob => l[ob]);
const customlayer = this.addPopupToLayer(o, l);
map.addLayer(drawnItems[o.surface_type.id].addLayer(customlayer));
l.on('click', (e) => {
if (selectedSurface) {
selectedSurface.editing.disable();
}
selectedSurface = e.target;
e.target.editing.enable();
that.setState({
popup: true,
detail: true,
surfaceDetail: o,
typeSelected: o.surface_type,
editSurface: selectedSurface
});
});
allLayers.push({
key: o.surface_type.id,
name: o.surface_type.name,
color: o.surface_type.color
});
});
allLayers = allLayers.filter(
(l, index, self) => self.findIndex(
t => t.key === l.key
) === index
);
this.setState({
allLayers,
counter: surfaces.length
});
}
}
initializeMap() {
const { user, actionFetch, actionFetchTypes } = this.props;
actionFetch();
actionFetchTypes();
map = L.map('map', {
center: [...user.airport.location.coordinates].reverse(),
zoom: 15,
editable: true,
});
L.gridLayer.googleMutant({ type: 'satellite', maxZoom: 20 }).addTo(map);
const that = this;
map.on(L.Draw.Event.CREATED, (e) => {
drawnItems[that.state.typeSelected.key].addLayer(e.layer);
utils.toggleZooming(map, 'disable');
that.setState({ popup: true, layer: e.layer });
});
map.on('draw:deleted', (e) => {
that.setState({ popup: false });
});
}
.In the popup, there is option to delete the polygon.
Please check below example.
// initialize the map
var map = L.map('map', {
center: [0.4, 102],
zoom: 7
});
// add map layer (OpenStreetMap)
L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap, Tiles courtesy of Humanitarian OpenStreetMap Team'
}).addTo(map);
// load example GEOJSON (from Wikipedia)
var geojsonFeature = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [102.0, 0.5]
},
"properties": {
"prop0": "A"
}
},{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
]
},
"properties": {
"prop0": "B",
"prop1": 0.0
}
},{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
]
},
"properties": {
"prop0": "C",
"prop1": {"this": "that"}
}
}
]
};
// load GEOJSON object/array to map
L.geoJSON(geojsonFeature, {
// style features based on properties
style: function(feature) {
switch(feature.properties.prop0){
case 'B': return { color: "red" }
case 'C': return { color: "green" }
}
},
// replace default maker with circle for point feature
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng, {
radius: 14,
fillColor: "orange",
color: "orange",
weight: 2,
opacity: 1,
fillOpacity: 0.5
});
},
// bind tooltip to each feature
onEachFeature: function(feature, layer) {
var popupContent = "<button onclick='removeSelectedLayer(\""+feature.properties.prop0+"\")'>Click here to remove this polygon</button><p>";
if (feature.properties.prop0) {
popupContent += feature.properties.prop0;
}
layer.bindPopup(popupContent);
layer.myTag = feature.properties.prop0
}
}).addTo(map);
function removeSelectedLayer(layerName) {
map.eachLayer( function(layer) {
console.log(layer.myTag)
if ( layer.myTag && layer.myTag === layerName) {
map.removeLayer(layer)
}
});
}
#map {
height: 500px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.6.0/dist/leaflet.css" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.6.0/dist/leaflet.js"crossorigin=""></script>
<div id="map"></div>
Hope this will helps you
This is my json response from URL:
{
"geometry": {
"type": "Point",
"coordinates": [
-1.480921,
52.979698
],
"Timestamp": "2017-07-09T09:21:30",
"GatewayID": 193,
"Speed": 94.9,
"Heading": 157
},
"type": "Feature",
"properties": {}
}
This is my js file:
var map = L.map('map', {
'center': [0, 0],
'zoom': 0,
'layers': [
L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
'attribution': 'Map data © OpenStreetMap contributors'
})
]
});
var geojsonMarkerOptions = {
radius: 18,
fillColor: "#ff7800",
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
};
var realtime = L.realtime({
url: 'http://127.0.0.1:8000/mongo/getgpsdata/',
crossOrigin: true,
type: 'json'
}, {
interval: 3 * 1000,
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng)
}
}).addTo(map);
realtime.on('layeradd', function(e) {
var coordPart = function(v, dirs) {
return dirs.charAt(v >= 0 ? 0 : 1) +
(Math.round(Math.abs(v) * 100) / 100).toString();
},
popupContent = function(fId) {
var feature = e.features[fId],
c1 = feature.geometry.Speed
c2=feature.geometry.Timestamp
c = feature.geometry.coordinates;
return '<b>coord: </b>' +c + '<br><b>Speed:</b> '+c1 + '<br><b>Time: </b>' + c2;
},
bindFeaturePopup = function(fId) {
realtime.getLayer(fId).bindPopup(popupContent(fId));
},
updateFeaturePopup = function(fId) {
realtime.getLayer(fId).getPopup().setContent(popupContent(fId));
};
map.fitBounds(realtime.getBounds(), {maxZoom: 30});
Object.keys(e.enter).forEach(bindFeaturePopup);
Object.keys(e.update).forEach(updateFeaturePopup);
});
It works perfectly fine but it wont show the popups, but if i give 'update' in place of 'layeradd' then it gives me the popups but the historical data is lost as it gets updated every time.
Any help would be great, Thanks!
Add bindPopup while returning the Marker, this worked for me.
return L.circleMarker(latlng).bindPopup("your content")
I want to draw a map with few routes drawn on it.
I want to have a dropbox with numbers 1,..,n
when an item in the dropbox is chosen, the corresponding route is highlighted on the map.
I have started using "leaflet".
how do I highlight a line? I have used "weight" but it's more a border to a line. I would like to see the line is getting bolder.
here is my code:
document.onload = loadMap();
function loadMap() {
var map = L.map('map').setView([37.8, -96], 4);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors,CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiZW======V6ZTdlb2V5cyJ9.3HqHQ4BMRvSPaYe8ToA7YQ'
}).addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(map);
var myLines = [{
"type": "LineString",
"properties": {
"id": "1"
}
"coordinates": [
[-100, 40],
[-105, 45],
[-110, 55]
]
}, {
"type": "LineString",
"properties": {
"id": "2"
}
"coordinates": [
[-105, 40],
[-110, 45],
[-115, 55]
]
}];
var myLayer = L.geoJson().addTo(map);
myLayer.addData(myLines);
geojson = L.geoJson(myLines, {
onEachFeature: onEachFeature
}).addTo(map);
}
function highlightFeature(e) {
var layer = e.target;
layer
layer.setStyle({
weight: 25,
color: '#ff3300',
dashArray: '',
fillOpacity: 0.7
});
if (!L.Browser.ie && !L.Browser.opera) {
layer.bringToFront();
}
}
function resetHighlight(e) {
geojson.resetStyle(e.target);
layer.setStyle({
weight: 5,
color: '#0000ff',
dashArray: '',
fillOpacity: 0.7
});
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
// click: zoomToFeature
});
}
$('select[name="dropdown"]').change(function() {
var item = $(this).val();
alert("call the do something function on option " + item);
//how to make the chosen line highlighted ??
});
weight property is not changing line border, it changes stroke width in pixels. You get border effect because you are adding lines twice. Here:
myLayer.addData(myLines);
And here:
geojson = L.geoJson(myLines, {
onEachFeature: onEachFeature
}).addTo(map);
When a polyline is hovered, top layer's style is changed, but because you are adding polylines twice, there still remains a polyline from the lower layer. As it is described here, default stroke opacity is 0.5 (setting fillOpacity is redundant for the polyline by the way, for changing stroke-opacity opacity property is used). Polyline from the top layer becomes semi-transparent, and that makes the illusion of the border effect.
So, you can just remove this line myLayer.addData(myLines); and get the expected result.
I've made a fiddle, where your example is corrected.