Leaflet - geoJSON multipolygon - bindPopup with bindTooltip - leaflet

I'm a complete beginner when it comes to leaflet but i'm slowly but surely learning the ropes after an introduction course. I've read over the Leaflet documentation but i'm still having trouble combining a permanent toolTip (label) with a bindPopup on click.
I can find success in doing one OR the other but not both. See below for my current code that labels each feature of my geoJSON multipolygon. I would now also like to display feature attribute information from the geoJSON in a popup when that feature polygon is clicked.
var lyrNeighbourhoods= new L.GeoJSON.AJAX("data/Neigh_Demo1.geojson",
{style: {weight:1, fillOpacity:0.1},
onEachFeature: function (feature, layer) {
layer.bindTooltip(feature.properties.Neigh_Name, {direction:"center",permanent:true,
className: 'labelstyle'});
}
}).addTo(mymap);
I've been racking my brain over this for too long. Any help is appreciated.

In your onEachFeature option function, there is nothing stopping you from also attaching a popup to your Layer:
function (feature, layer) {
layer.bindTooltip(feature.properties.Neigh_Name, {
direction: "center",
permanent: true,
className: 'labelstyle'
});
layer.bindPopup("My popup content");
}

Related

Leaflet - popups for polygons over each other

I place polygons in front of a map. Some smaller polygons are placed in front of a bigger polygon. I get the data from geojson file. I want to show the name-poperty as a popup. I use:
function onEachFeature(feature, layer) {
layer.bindPopup(layer.feature.properties.name);
};
Unfortunately only the name-property of the bigger ploygon is shown. How can i correct this? I tried an additionl geojson-property with:
function onEachFeature(feature, layer) {
if ((feature.properties.popupContent != "0"))
{layer.bindPopup(layer.feature.properties.name);
};
};
But this does not work too.
thanks, wonk
Leaflet provides a couple of functions to help access smaller markers that may be trapped under larger markers, those being the .bringToFront() and .bringToBack() methods provided by L.Path, L.featureGroup, and L.GridLayer and inherited by any descendants of those. I've set up a live, rudimentary example of using these to access trapped markers on StackBlitz.
Thank you for the example, I understand. I tried:
function onEachFeature(feature, layer) {
if ((feature.properties.popupContent != "0"))
{layer.bindPopup(layer.feature.properties.name);
layer.bringToFront();
};
}
But this only shows the first polygon (there are a lot of them). Maybe, I misunderstood the geojson-data. I thought, there is one layer for every polygon. But it seems, that all polygons of geojson-data-file are in ONE layer. In this case your proposal won't work, I think. I will have to find another solution. The data come from:
function show_geojson (overlay) {
$.ajax({url:overlay}).done(function(data) {
var data = JSON.parse(data);
L.geoJson(data,
{pointToLayer: MarkerStyle,
style: style,
onEachFeature: onEachFeature
});
geoJsonLayer = L.geoJson(data); //neu
});
}
Thank you!

Import Leaflet Markers from a external GeoJSON

I am starting with leaflet and wanted to display more information when clicking on a marker in a map using a sidebar.
I use the php call where the geoJeson called allande_geoJson is generated with all the information I need from my database:
In the example I'm using, a maker is generated so that when you click on it, the information is displayed in the sidebar:
var marker = L.marker([51.2, 7]).addTo(map).on('click', function () {
sidebar.toggle();
});
I wanted to enter the makers directly from my geoJeson and I am trying various ways with no success, such as:
var marker= L.marker(new L.GeoJSON(allande_geoJson)).addTo(map).on('click', function () {
sidebar.toggle();
});
any ideas?
The Markers are loaded automatically when you put the geojson data in the L.geoJSON() layer.
With onEachFeature you add the click event to each marker.
function onEachFeature(feature, layer) {
layer.on('click', function () {
sidebar.toggle();
});
}
L.geoJSON(allande_geoJson, {
onEachFeature: onEachFeature
}).addTo(map);

Edit leaflet draggable option after receiving a new GeoJson object

I'm new on using leaflet and I'm wondering how do you edit a draggable option for object than has already been saved in GeoJson and that you display later on your map.
pldata[index] = new L.GeoJSON(plot[i],{
pointToLayer: function (feature, latlng){
return new L.circleMarker(larlng, geojsonAOs)
},
style: set_style
}).addTo(map)
pldata['aos'].eachLayer(function (layer){
layer.options.draggable: true;
});
I've tried also to put the draggable at true after style but nothing happen.
P.S : Am I obligated to add DrawItem for just drag options ?
P.S2 : All object have been transform in circleMarker or lines and development that has been done is quiet big so I'm trying to find a solution without break the all curent project.
Thanks for your answer.
Ok I've just update the all leaflet library and after I continue with a eachLayer
and on Layer
.on('mousedown', function(){
map.dragging.disable();
map.on('mousemove', function(e){
layer.setLatLng(e.latlng)
});
it's working well to make a circleMarker move.

Mapbox: Filtering out markers in a Leaflet Omnivore KML layer

I am exporting Google Directions routes as KML and displaying them on a Mapbox map by reading them with Omnivore and adding them to the map,
The Google KML stores each route as two Places (the start and end points) and one LineString (the route). In Mapbox I would like to show only the routes, that is to filter out the markers somehow. I'm displaying markers out of my own database and the Google markers clutter it up.
Here is my code. I change the styling of the LineStrings just to show that I can, but do not know what magic call(s) to make to not display the Points.
Thanks.
runLayer = omnivore.kml('data/xxxx.kml')
.on('ready', function() {
var llBnds = runLayer.getBounds();
map.fitBounds(llBnds);
this.eachLayer(function (layer) {
if (layer.feature.geometry.type == 'LineString') {
layer.setStyle({
color: '#4E3508',
weight: 4
});
}
if (layer.feature.geometry.type == 'Point') {
//
// Do something useful here to not display these items!!
//
}
});
})
.addTo(map);
Welcome to SO!
Many possible solutions:
Most straight forward from the code you provided, just use the removeLayer method on your runLayer Layer Group when you get a 'Point' feature.
Cleaner solution would be to filter out those features before they are even converted into Leaflet layers, through a custom GeoJSON Layer Group passed as 3rd argument of omnivore.kml, with a specified filter option:
var customLayer = L.geoJSON(null, {
filter: function(geoJsonFeature) {
// my custom filter function: do not display Point type features.
return geoJsonFeature.geometry.type !== 'Point';
}
}).addTo(map);
var runLayer = omnivore.kml('data/xxxx.kml', null, customLayer);
You can also use the style and/or onEachFeature options on customLayer to directly apply your desired style on your LineString.

Updating layers in Leaflet / Mapbox

I'm trying to make a mapping visualization in realtime, where I keep getting new points via websockets. The initial plotting these markers on the map seems simple, but I'm not sure what's the right way of updating a layer on Mapbox.
As of now, whenever I get a new point, I remove the old layer, create a new one and then add it on the map. The problem with this approach is that it is slow and for high number of points (>5000) it starts lagging.
// remove layer
if (this.pointsLayer != null) {
map.removeLayer(this.pointsLayer);
}
// build geoJSON
var geoJSON = { "type": "FeatureCollection", "features": [] };
geoJSON["features"] = tweets.map(function(tweet) {
return this.getGeoPoint(tweet);
}.bind(this));
// add geoJSON to layer
this.pointsLayer = L.mapbox.featureLayer(geoJSON, {
pointToLayer: function(feature, latlon) {
return L.circleMarker(latlon, {
fillColor: '#AA5042',
fillOpacity: 0.7,
radius: 3,
stroke: false
});
}
}).addTo(map);
Is there a better way?
You can create an empty GeoJSON layer by passing it a false instead of real data:
//create empty layer
this.pointsLayer = L.mapbox.featureLayer(false, {
pointToLayer: function(feature, latlon) {
return L.circleMarker(latlon, {
fillColor: '#AA5042',
fillOpacity: 0.7,
radius: 3,
stroke: false
});
}
}).addTo(map);
then use .addData to update it as new tweets come in. Something like:
// build geoJSON
var geoJSON = { "type": "FeatureCollection", "features": [] };
geoJSON["features"] = /**whatever function you use to build a single tweet's geoJSON**/
// add geoJSON to layer
this.pointsLayer.addData(geoJSON);
For a single tweet, I guess you could just create a Feature instead of a FeatureCollection, though I don't know whether that extra layer of abstraction would make any difference in terms of performance.
EDIT: Here is an example fiddle showing the .addData method at work:
http://jsfiddle.net/nathansnider/4mwrwo0t/
It does slow down noticeably if you add 10,000 points, and for 15,000 points, it's really sluggish, but I suspect that has less to do with how the points are added that the demands of rendering so many circleMarkers.
If you aren't already, you may want to try using the new Leaflet 1.0 beta, which redraws vector layers faster and is generally much more responsive with large datasets. Compare this 15,000-point example using Leaflet 0.7.5 to the same code using Leaflet 1.0.0b2. Not everything is fixed (popups take a long time to open in both), but the difference in lag time when trying to drag the map is pretty dramatic.
There's no reason to go through the intermediate step of construction a GeoJSON object just so you can add it to the map. Depending on your exact needs, you can do something like this:
tweets.forEach(function(t) {
L.marker(this.getGeoPoint(t)).addTo(map);
}, this);
You should manage the tweets object so it only contains points that are not already visible on the map, though. Deleting all the old markers, just so you can add them again, is of course going to be very slow.
I would take a look at Leaflet Realtime:
Put realtime data on a Leaflet map: live tracking GPS units, sensor data or just about anything.
https://github.com/perliedman/leaflet-realtime