Markers in the same position don't work properly with Vue3 + Leaflet Markercluster - leaflet

The problem is that the leaflet map inside the vue3 App loads perfectly and looks great. Also, when you click on a location with two icons in the same position, they open perfectly, but when you click on the same place again, the icons disappear and the "spider" remains visible (see picture).
spider remains
The methods in the Vue3 App are:
methods:{
setupMarkers(){
this.markers.clearLayers();
this.cursesData.forEach(cursa =>this.ficaMarkers(cursa));
this.map.addLayer(this.markers);
},
setupLeafletMap(){
this.map=L.map("mapContainer").setView(this.center,6);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",{
attribution:'OpenStreetMap',
}).addTo(this.map);
this.markers= L.markerClusterGroup({
//spiderfyOnMaxZoom: true,
});
},
ficaMarkers(cursa){
this.markers.addLayer(L.marker([cursa.coordenades[0],cursa.coordenades[1]],{title:cursa.nom})
.bindPopup(cursa.distancies)
)
},
},
If someone could help me, I would be very grateful.
Thanks.

It is a similar issue as in Uncaught TypeError: this._map is null (Vue.js 3, Leaflet) :
What seems to be the culprit is the proxying of this.map by Vue, which seems to interfere with Leaflet events (un)binding. It looks like Vue 3 now automatically performs deep proxying, whereas Vue 2 was shallow.
In your case, the same thing happens for this.markers (which is the Leaflet MarkerClusterGroup).
A solution consists in "unwrapping" / un-proxying the map and the mcg whenever you use them, e.g. with Vue3's toRaw:
toRaw(this.map).addLayer(toRaw(this.markers));
Then we retrieve the normal MCG behaviour, i.e. if you click on the cluster while it is already spiderfied, nothing happens (whereas initially the Markers were collapsing, but the spider legs were remaining indefinitely)
Fixed CodeSandbox: https://codesandbox.io/s/markers-hide-spiders-stay-forked-l2ruqh?file=/src/App.vue

Related

How fix error when using Leaflet's TileLayer.NoGap and styled WMS layers from GeoServer?

A governmental agency has a WMS layer and I want to display it on my leaflet canvas.
I add this code:
var wmslayer = L.tileLayer.wms('http://localhost:8080/geoserver/depo/wms',{
layers:'nep'
}).addTo(mymap);
This works fine. The layer is displayed. Now, the layer comes with two styles: "brightbackground" and "darkbackground". When I open the layer in QGIS I can select and add any of the styled layer. But when I add styles : 'darkbackground' to the code, like this:
var wmslayer = L.tileLayer.wms('http://localhost:8080/geoserver/depo/wms',{
layers:'nep',
styles:'darkbackground'
}).addTo(mymap);
I get an error saying:
L.TileLayer.NoGap.js:224 Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
If I comment out the plugin "NoGap" I don't get any errors, but also not getting any wms-layer, unless I remove styles : 'darkbackground'. Then layer returns.
Any ideas how to use the style that comes with the WMS-layer? Is there anything I can do in Geoserver? Or can I serve it from any other place? Or are there any plugin that might help?
I'm out of ideas.

Leaflet labels when upgrading to 1.0.3

I try to use leaflet labels and on several pages it is successful. I wanted to use the same approach to display labels on another page and it responded with an obscure technical message which I did not understand:
Uncaught TypeError: Cannot read property 'call' of undefined
at e.whenReady (leaflet.js:6)
at e.addLayer (leaflet.js:6)
at e.showLabel (leaflet.label-src.js:538)
at e.showLabel (leaflet.label-src.js:287)
at e._onMarkerAdd (leaflet.label-src.js:383)
at e.fire (leaflet.js:5)
at e._layerAdd (leaflet.js:6)
at e.whenReady (leaflet.js:6)
at e.addLayer (leaflet.js:6)
at e.onAdd (leaflet.js:7)
After a lot of researching I found out that leaflet.label is deprecated for Leaflet 1.0.3, which makes sense, since we are using older leaflet version in other pages where the labels appear correctly, but on the newer leaflet versions it crashes the map. The docs say that I should use bindTooltip instead of bindLabel, but I do not know how. I have tried to call it with some content on a marker but it did not appear on the map and I did not find it in the generated structure.
So, my question is as follows: How can I use labels with Leaflet 1.0.3, which will be bound to a marker and will adjust in case of translation/zoom?
The Tooltip is indeed now directly part of Leaflet main library.
Note that it appears only on mouseover by default, but you can use the permanent option to have it remain always visible.
marker.bindTooltip("Some tooltip content", {
permanent: true
});
Example: http://playground-leaflet.rhcloud.com/tiqo/1/edit?html,output

Change 'prefer canvas' setting per leaflet map

I'm using Leaflet (v 0.7.7). It expects setting L_PREFER_CANVAS as a script tag, which is global. I wish to create 2 maps on same page, one with L_PREFER_CANVAS flag ON and once with OFF. How can I do that ?
1) I've tried setting window.L_PREFER_CANVAS before the map creation.
2) I've tried creating my layers with extended classes like this
var MyCircle = L.Circle.extend({
statics: {
CANVAS: true,
SVG: false
}
});
then using 'new MyCircle' instead of 'L.circle'.
Neither of the two methods have the desired effect, even though the map is rendered successfully
I'm looking into leaflet code but i'm not very comfortable with its inner workings yet, due to lack of js sorcery know-how i believe
Edit: A thing that partly works is cloning the entire leaflet source under a new object (M.* instead of L.), and keep my desired flag enabled for it. But its clumsy and breaks with plugins which add their functionality to L. classes. Thereby requiring more duplication to fix, which i'm trying to avoid
Would recommend you look into migrating onto Leaflet 1.0, where preferCanvas is now a traditional option inside the map constructor...Among many other significant improvements.
http://leafletjs.com/reference-1.0.0.html#map-prefercanvas

Multiple markers on the exact same position on a Leaflet map

We use leafletJS to show maps with round about 100 markers. Some of these markers are located on exact the same position. Marker2 is above Marker1 so Marker1 isn't visible. Is there a way to rotate Markers in a way that you can see there are more then one marker?
may be you should look at https://github.com/Leaflet/Leaflet.markercluster plugin
here demo - http://leaflet.github.io/Leaflet.markercluster/example/marker-clustering-realworld.388.html
The drawback with walla's answer is that Leaflet.markercluster requires clustering, which may not be an option depending on your requirements i.e. you need to always display individual markers.
OverlappingMarkerSpiderfier-Leaflet (a bit of a mouthful) works well in this case and it's fairly well documented. It displays a 'spider' of markers on click only if they overlap i.e. if the zoom level increases so markers don't overlap, then it won't 'spider' on click, which is quite nice. Demo.
It's available as a NPM package but it isn't a proper ES module, so usage is a bit trickier than usual if you're expecting an ES module:
// Need to specifically import the distributed JS file
import 'overlapping-marker-spiderfier-leaflet/dist/oms';
// Note access to constructor via window object
// map refers to your leaflet map object
const oms = new window.OverlappingMarkerSpiderfier(map);
oms.addListener('click', (marker) => {
// Your callback when marker is clicked
});
// Markers need to be added to OMS to spider overlapping markers
markers.forEach((marker) => {
oms.addMarker(marker);
});
// Conversely use oms.removeMarker(marker) if a marker is removed
Alternatively there is a forked version (confusingly) called OverlappingMarkerSpiderfier that is a proper ES module so you can do:
import OverlappingMarkerSpiderfier from 'overlapping-marker-spiderfier'
const oms = new OverlappingMarkerSpiderfier(map);
However as of 24 Jan 2020 there's a fair bit of divergence based on commits between the two so YMMV.
FWIW I'm using the original.
If anyone is looking working sample for Angular below are the steps,
Install it via npm: npm i --save overlapping-marker-spiderfier-leaflet
Then import it into the component where you need it: import 'overlapping-marker-spiderfier-leaflet/dist/oms';
Add this line on top of the file where you import it: const OverlappingMarkerSpiderfier = (<any>window).OverlappingMarkerSpiderfier;
Add the oms markup like that: this.oms = new OverlappingMarkerSpiderfier(this.map, { nearbyDistance: 20, keepSpiderfied: true });
Add the markers to oms at the same place where you add your markers to the map so oms can track them properly this.oms.addMarker(marker);
xlm is already gave a complete answer. Thanks to him for that answer. But this is a slightly changed answer that worked for me in angular.
we had the same problem, follows the jsFiddle with the solution we found http://jsfiddle.net/atma_tecnologia/mgkuq0gf/2/
var marker1 = new google.maps.Marker({
position: myLatLng,
map: map,
icon: {
url: image,
size: new google.maps.Size(134,130), //different sizes
},
zIndex: 2, //different overlays
title: '1ยบ marker',
});

How to trigger native popup on Leaflet polygon

How do you manually trigger the native popup on a Leaflet polygon?
I can bind the native popup to each layer like this:
geojsonLayer.on("featureparse", function (e){
// bind the native popup
var popupContent = "popup content goes here";
e.layer.bindPopup(popupContent);
});
And I have manually assigned an ID to each polygon so I can reference them later like this:
map._layers['poly0']
I've tried triggering the popup like this:
map._layers['poly0'].openPopup();
But that gives me an error like this:
map._layers['poly0'].openPopup is not a function
Any idea where I'm going wrong?
openPopup for vector layers only recently appeared in the latest version, it wasn't there before.
Also, check out the Leaflet 0.4 release announcement: http://leaflet.cloudmade.com/2012/07/30/leaflet-0-4-released.html (and note that GeoJSON API was changed and it's not backwards compatible, so you also have to update your code)