Leaflet: how to add an attribution on a GeoJSON Layer? - leaflet

I need to use a GeoJSON Layer on my Leaflet map. Here is a sample of my code:
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
myGeoJsonLayer = L.geoJson(data, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, geojsonMarkerOptions);
},
onEachFeature: onEachFeature
});
myGeoJsonLayer.addTo(map);
TOC.addOverlay(myGeoJsonLayer, "My GeoJSON Layer");
All is working.
Now I'd like to add an attribution on my layer but how?
Any suggestions are appreciated.

By default this isn't supported, but you can tack a getAttribution() method on an instance like so: http://bl.ocks.org/tmcw/05c7d1164a9e62e67e6d

Related

Changing leaflet markers to circleMarkers

I'm trying to Change Leaflet markers to circleMarker on data coming from geoJSON file.
Until now her is how I display data on map:
const geodesic = new L.Geodesic().addTo(map); /* Affiche les ligne géodésiques*/
geodesic.fromGeoJson(waypoints);
function pointFilter(feature) {
if (feature.geometry.type === "Point") return true
}
var points = new L.geoJson(waypoints, {filter: pointFilter}).addTo(map);
My geoJSON file contains LineStrings and Points.
The geodesic lines and standard icon markers are displayed, but I would change them by circleMarker between each lines.
Hope I'm clear enough.
Thanks
Pierre
This is what the code may look like, change it as you see fit.
Here'a a whole example - autocomplete-with-geojson
const geojsonlayer = L.geoJSON(object, {
style: function (feature) {
return {
color: feature.properties.color || "red",
weight: 7,
opacity: 1,
fillOpacity: 0.7,
};
},
pointToLayer: (feature, latlng) => {
if (feature.properties.type === "Point") {
return new L.circleMarker(latlng, {
radius: 20,
});
}
},
onEachFeature: function (feature, layer) {},
});

How to return multiple layers from pointToLayer leaflet geojson

I want to add a marker icon and a boundary box to the map from a single data item. This is because I need to show both the location and rough size of a work site.
I can add a maker like this
pointToLayer: function (feature, latlng)
{
return L.marker(latlng);
}
And I can add a rectangle like this
pointToLayer: function (feature, latlng)
{
return L.rectangle(feature.properties.rect);
}
How can I add both at once?
The solution is to use a layer group. pointToLayer expects a return type of ILayer.
pointToLayer: function (feature, latlng)
{
let oMyMarker = L.marker(latlng);
let oMyRect = L.rectangle(feature.properties.rect);
return L.layerGroup([oMyMarker, oMyRect]);
}
However I found that sometimes this was causing Leaflet to throw exceptions because it was trying to use getLatLng() and setLatLng(latlng) on the returned layer group.
I found this hack works around that exception, for my purposes I never update existing layers therfore I do not care if setLatLng(latlng) does anything or not.
pointToLayer: function (feature, latlng)
{
let oMyMarker = L.marker(latlng);
let oMyRect = L.rectangle(feature.properties.rect);
let oLayer = L.layerGroup([oMyMarker, oMyRect]);
if (typeof oLayer.getLatLng === 'undefined')
{
if (typeof oLayer._latlng === 'undefined') oLayer._latlng = latlng;
oLayer.getLatLng = function () { return this._latlng; };
if (typeof oLayer.setLatLng === 'undefined')
{
oLayer.setLatLng = function (val_latlng) { this._latlng = val_latlng; return; };
}
}
return oLayer;
}
If you need methods getLatLng() and setLatLng(latlng) to work correctly on the layer group I suggest you make the methods we add there do a loop over the collection of child layers it contains to call the methods on all of them.

Leaflet Markercluster - tooltip on hover issue

I'm a newbie of javascript, trying to build an interactive map online, where some events should be triggered by clicking on markers and some just by hovering them.
Managed to have the click part working, but, because of Markercluster plugin, I'm not sure where to use onEachFeature function for having the tooltip opened by hover a single marker.
Anyone please can tell me what I'm doing wrong?
var geoJsonFeature = {
type: 'FeatureCollection',
features:
[
{
type: 'Feature',
properties: {
title: 'Title',
page: 'some.html',
'marker-color': '#000000',
zoom: 7
},
geometry: {
type: 'Point',
coordinates: [12.583745,55.6750803]
}
},
...
};
// access to mapbox api
L.mapbox.accessToken ='...';
var map = L.mapbox.map('map', 'example1234').setView([34, -37], 3);
function getTitle(marker) {
return marker.feature.properties.title;
};
function getPage(marker) {
return marker.feature.properties.page;
};
var markerGroup = new L.MarkerClusterGroup({showCoverageOnHover:false});
var geoJsonLayer = L.geoJson(geoJsonFeature, {
onEachFeature: function (feature, layer) {
var popupContent = getTitle(marker);
layer.bindPopup(popupContent);
}
});
markerGroup.addLayer(geoJsonLayer);
map.addLayer(markerGroup);
markerGroup.on('click', function(ev) {
var marker = ev.layer;
marker.on('click', function(ev) {
if(map.getZoom() > marker.feature.properties.zoom) {
map.setView(ev.latlng, map.getZoom());
}
else {
map.setView(ev.latlng, marker.feature.properties.zoom);
}
});
});
});
geoJsonLayer.on('mouseover', function(e) {
e.layer.openPopup();
});
geoJsonLayer.on('mouseout', function(e) {
e.layer.closePopup();
});
You need to use the onEachFeature option to get the individual markers and bind handlers to the mouseover and mouseout events:
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.title);
layer.on("mouseover", function () {
layer.openPopup();
});
layer.on("mouseout", function () {
layer.closePopup();
});
}
Here's a working example on Plunker: http://plnkr.co/edit/hfjOWv3uCBFawDGqR3Ue?p=preview
Note: i'm not using ClusterMarker in this example but it should work just fine when using ClusterMarker

Add a WFS service in a Leaflet map and need to control the current scale

I need to load a WFS service (points) in my Leaflet map.
I know how to load a WFS service in my map but I've to check dinamically the map current scale / extent because I've to limit the number of features I've to request to the server and to render on my map.
My service has a lot of points and I'd like to limit the visualization of my layer only when we are al level=18 of my basemap (OpenStreetMap).
Is there any way to check dinamically the map current extent / scale and so decide if invoke or not my WFS Service?
Any example?
Thank you very much in advance, any suggestion is appreciate!!!!
Cesare
I solved in this manner
.....
.....
.....
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
};
myGeoJSONLayeraddressPCN3 = L.geoJson(myGeoJSON, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, geojsonMarkerOptions);
},
onEachFeature: onEachFeature
});
var baseLayers = {
"OSM": background
};
var overlays = {
"My GeoJSON Layer name": myGeoJSONLayer
};
map = new L.Map('map', {
center: [42, 12],
zoom: 6,
layers: [background]
});
// *** add base layers and overlay layers list to map ... ***
TOC = L.control.layers(baseLayers, overlays);
TOC.addTo(map);
map.on('overlayadd', function(e) {
map.removeLayer(myGeoJSONLayer);
TOC.removeLayer(myGeoJSONLayer);
if ((e.name == "My GeoJSON Layer name") && (map.getZoom() < 18)){
alert('To view the layer zoom at max details ...');
TOC.addOverlay(myGeoJSONLayer, "My GeoJSON Layer name");
isOnMap = 0;
}
if ((e.name == "My GeoJSON Layer name") && (map.getZoom() >= 18)){
var currentExtent = map.getBounds().toBBoxString();
invokeService(currentExtent);
}
});
map.on('overlayremove', function(e) {
if (e.name == "My GeoJSON Layer name"){
isOnMap = 0;
}
});
map.on('dragend', function(e) {
if ((map.getZoom() >= 18) && (isOnMap == 1)){
map.removeLayer(myGeoJSONLayer);
TOC.removeLayer(myGeoJSONLayer);
var currentExtent = map.getBounds().toBBoxString();
invokeService(currentExtent);
}
});
map.on('zoomend', function(e) {
if (map.getZoom() < 18) {
map.removeLayer(myGeoJSONLayer);
TOC.removeLayer(myGeoJSONLayer);
TOC.addOverlay(myGeoJSONLayer, "My GeoJSON Layer name");
}
});
and I've also a function invokeService() where I've ...
function invokeService (extent) {
.....
.....
.....
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
myGeoJSONLayeraddressPCN3 = L.geoJson(MyGeoJSON, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, geojsonMarkerOptions);
},
onEachFeature: onEachFeature
});
addressPCN3.addTo(map);
TOC.addOverlay(addressPCN3, "My GeoJSON Layer name");
isOnMap = 1;
}
.....
.....
.....
}
It's working now!

using Leaflet.Label with GeoJSON points

There are numerous references to leaflet.label working fine with GeoJSON points, but I've yet to find one example.
Here's what i've tried so far:
//Add labels layer
var labelStyle = {
color: '#CCC',
opacity: 1
};
var labelMarkerOptions = {
opacity: 0,
fillOpacity: 0
};
var labelLayer = L.geoJson(labels, {
pointToLayer: function (feature, latlng) {
return L.Marker(latlng, labelMarkerOptions);
},
onEachFeature: function (feature, layer) {
layer.bindLabel(feature.properties.Name, {noHide:true});
}
});
labelLayer.eachLayer(function(l) {l.showLabel();});
map.addLayer(labelLayer);
layerControl.addOverlay(labelLayer, 'Site Labels');
This adds a layer of my points, but with the default larkers, and no labels. Thanks for any help you can provide.
If you want to show only the label, return L.circleMarker instead of L.Marker:
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, labelMarkerOptions);
},
If you need L.Marker for some other reason, bind the label directly to marker:
pointToLayer: function (feature, latlng) {
return L.Marker(latlng, labelMarkerOptions).bindLabel(feature.properties.Name, {noHide:true});
},