Tuesday 29 January 2019

markers - GeoJSON, circlemarkers using Leaflet OverlappingMarkerSpiderfier plugin?


I am wondering if I can use the Leaflet OverlappingMarkerSpiderfier plugin with my circlemarkers.


I've loaded a GeoJSON file and added circlemarkers using;


var gj = L.geoJson(route, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, geojsonMarkerOptions);
},
onEachFeature: onEachFeature,
}).addTo(map);


I followed the OverlappingMarkerSpiderfier example but I cannot understand how to combine my circlemarkers with the plugin.


I am guessing that changing;


  pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, geojsonMarkerOptions);

}

to something like


oms.addMarker(marker);


(Leaflet OverlappingMarkerSpiderfier is a port of the original library for the Google Maps API)



Answer



OverlappingMarkerSpiderfier is a plugin designed for the L.Marker class in Leaflet. Thus, it only accepts an L.Marker object and can't handle L.circleMarker properly, since it's based on the L.Circle objects which is based on L.Path. Credit for pointing this out goes to @FranceImage.


You can't use the L.circleMarker layer with the spiderfier plugin, it will be glitchy (http://jsfiddle.net/GFarkas/qzdr2w73/). However, you can convert your GeoJSON data to traditional markers with the L.Marker object. You can customize your marker icon to resemble to the circleMarker object (http://jsfiddle.net/GFarkas/qzdr2w73/4/).


To do this easily, Leaflet offers a L.DivIcon style which can be customized with pure CSS, you won't need an image. To make orange circles with solid border in CSS, the code will look like the following:


.mydivicon{
width: 12px
height: 12px;
border-radius: 10px;

background: #ff7800;
border: 1px solid #000;
opacity: 0.85
}

The most important part is the border-radius property. It will round your shape at the corners. To create a regular circle with it, you have to calculate the radius with the border. The formula is width / 2 + border * 4 if width = height. After you created the CSS, you have to make a L.DivIcon object to be used with L.Marker:


var icon = new L.divIcon({className: 'mydivicon'});

When rendering the GeoJSON data to the map object, use L.Marker instead of L.circleMarker with the previously created icon:


pointToLayer: function (feature, latlng) {

return L.marker(latlng, {
icon: icon});

Now to use OverlappingMarkerSpiderfier properly: you have to create an OMS instance before adding the GeoJSON data:


var oms = new OverlappingMarkerSpiderfier(map);

After, you have to add each marker to the OMS object, so the built-in renderer can use them. To do this, use the onEachFeature method of L.geoJson:


onEachFeature: function (feature, latlng) {
oms.addMarker(latlng);
}


Finally, create an event associated with the OMS object and the markers it contains and add popup content to the markers. Note: if you don't add some markers to the OMS object, it won't apply the spiderfy effect on them. Also, the popup content in my case is in the GeoJSON data (properties -> popupContent).


var popup = new L.Popup();
oms.addListener('click', function(marker) {
popup.setContent(marker.feature.properties.popupContent);
popup.setLatLng(marker.getLatLng());
map.openPopup(popup);
});

Final note: markers created with L.DivIcon will be rendered as individual div objects instead of canvas or SVG. If you use a lot of points (around thousand or more) the rendering process will be painfully slow if the browser doesn't crash. To avoid it at masses of points like that, use OMS with other strategies (clusters, bounding box, etc.).



No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...