Leaflet: "move" event has oldLatLng in Marker but not in Circle Marker

Created on 27 Jul 2018  Â·  8Comments  Â·  Source: Leaflet/Leaflet

  • [X] I'm reporting a bug, not asking for help; support questions like "How can I do X with Leaflet?" will be closed (use Stack Overflow or gis.stackexchange.com for questions)
  • [X] I've looked at the documentation to make sure the behaviour is documented and expected
  • [X] I'm sure this is a Leaflet code issue, not an issue with my own code nor with the framework I'm using (Cordova, Ionic, Angular, React…)**
  • [X] I've searched through the issues to make sure it's not yet reported

**The error is a result of a combination of react and leaflet and leaflet-markercluster, but the original source of the error is leaflet
UPDATE: it's reproducible with just leaflet

How to reproduce

  • Leaflet version I'm using: 1.3.1
  • Browser (with version) I'm using: Chrome 67.0.3396.99
  • OS/Platform (with version) I'm using: macOS 10.12.6

What behaviour I'm expecting and which behaviour I'm seeing

Expect: setLatLng should work for CircleMarkers like it does for Markers
Reality: setLatLng leads to undefined errors

I originally experienced the error using the marker cluster plugin, but it's reproducible without it.
Related issue: https://github.com/YUzhva/react-leaflet-markercluster/issues/31

Error stack trace in leaflet-markercluster:

leaflet-src.js:1658 Uncaught TypeError: Cannot read property 'lat' of undefined
    at Object.project (leaflet-src.js:1658)
    at Object.latLngToPoint (leaflet-src.js:1497)
    at NewClass.project (leaflet-src.js:3931)
    at NewClass._removeFromGridUnclustered (leaflet.markercluster-src.js:690)
    at NewClass._removeLayer (leaflet.markercluster-src.js:738)
    at NewClass.removeLayer (leaflet.markercluster-src.js:181)
    at NewClass._moveChild (leaflet.markercluster-src.js:713)
    at NewClass._childMarkerMoved (leaflet.markercluster-src.js:703)
    at NewClass.fire (leaflet-src.js:592)
    at NewClass.setLatLng (leaflet-src.js:7843)

The problem is that e.oldLatLng is undefined here in leaflet-markercluster:

_childMarkerMoved: function (e) {
        if (!this._ignoreMove && !e.target.__dragStart) {
            var isPopupOpen = e.target._popup && e.target._popup.isOpen();

            this._moveChild(e.target, e.oldLatLng, e.latlng);

            if (isPopupOpen) {
                e.target.openPopup();
            }
        }
    },

How is this a leaflet issue? When you fire a move end it seems to expect both a 'from' (oldLatLng) and a 'to' (latlng).

This is what setLatLng looks like for vanilla Markers:

setLatLng: function (latlng) {
        var oldLatLng = this._latlng;
        this._latlng = toLatLng(latlng);
        this.update();
        return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
    }

and this is what it looks like for CircleMarkers:

setLatLng: function (latlng) {
        this._latlng = toLatLng(latlng);
        this.redraw();
        return this.fire('move', {latlng: this._latlng});
    },

It doesn't set oldLatLng, so it's undefined when the move event fires.

Changing CircleMarker's setLatLng to this fixes the issue:

setLatLng: function (latlng) {
        var oldLatLng = this._latlng;
        this._latlng = toLatLng(latlng);
        this._update();
        return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
    },

Minimal example reproducing the issue

  • [X] this example is as simple as possible
  • [X] this example does not rely on any third party code

https://codepen.io/mmacquarrie/pen/VBMRva~~
UPDATE: https://codepen.io/mmacquarrie/pen/ajqKZW

  1. Open the browser console
  2. Click on the marker
  3. View error in browser console.

Most helpful comment

This is still an ongoing problem. I faced the same issue when using CircleMarker with react-leaflet-markercluster. I fixed this creating a custom wrapper and overriding setLatLng of L.CircleMarker. Here is the code if anyone wants to check it.

import { CircleMarker as LeafletCircleMarker } from 'leaflet'
import { withLeaflet, Path } from 'react-leaflet';

LeafletCircleMarker.include({
  setLatLng: function (latlng) {
    const oldLatLng = this._latlng;
    this._update();
    return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
  },
})

class CircleMarker extends Path {
  createLeafletElement({ position, leaflet, ...options }) {
    return new LeafletCircleMarker(position, options);
  }

  updateLeafletElement(fromProps, { position, radius }) {
    if (position !== fromProps.position) {
      this.leafletElement.setLatLng(position);
    }
    if (radius !== fromProps.radius) {
      this.leafletElement.setRadius(radius);
    }
  }
}

export default withLeaflet(CircleMarker);

All 8 comments

Hi,

Thank you for your report.

It seems to me that you essentially point out an inconsistency of the "move" event of Circle Markers compared to Markers.

The docs for the latter clearly mention the 2 properties indeed:

Old and new coordinates are included in event arguments as oldLatLng, latlng.

But there is no doc at all for the former.

Because both Circle Marker and Marker address a very similar usage, we could expect a similar API. Especially in this case where both provide a setLatLng method that does the same thing, except for the data associated to this "move" event.

If I understand correctly, that is what happened when you used Leaflet.markercluster plugin and filled it with Circle Markers.

While in your case you use React, you should have been able to build an example without it at all.
BTW, while the related issue you mention describes a similar error and also code with setLatLng (that is never executed), it seems to me that it describes a totally different situation.

Looking at the history behind oldLatLng in Marker "move" event, it was specifically introduced for Leaflet.markercluster plugin by PR https://github.com/Leaflet/Leaflet/pull/2412.

Since this plugin happily accepts Circle Markers, it is definitely an inconsistency not doing the same for Circle Marker "move" event.

Yes, my problem is the inconsistency between setLatLng for Markers and CircleMarkers, especially since the documentation says you can call setLatLng on the latter.

The related issue is the context in which I originally found the error. I wanted to make the codepen simpler, though, and just call the function that was causing the problem, so you're right that it seems like a totally different situation.

Here's a much simpler codepen that reproduces the issue with no third party code whatsoever:
https://codepen.io/mmacquarrie/pen/ajqKZW

And update on this? I'm also getting the error specifically with CircleMarkers.
If I switch to a regular marker, it works fine.

This is still an ongoing problem. I faced the same issue when using CircleMarker with react-leaflet-markercluster. I fixed this creating a custom wrapper and overriding setLatLng of L.CircleMarker. Here is the code if anyone wants to check it.

import { CircleMarker as LeafletCircleMarker } from 'leaflet'
import { withLeaflet, Path } from 'react-leaflet';

LeafletCircleMarker.include({
  setLatLng: function (latlng) {
    const oldLatLng = this._latlng;
    this._update();
    return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
  },
})

class CircleMarker extends Path {
  createLeafletElement({ position, leaflet, ...options }) {
    return new LeafletCircleMarker(position, options);
  }

  updateLeafletElement(fromProps, { position, radius }) {
    if (position !== fromProps.position) {
      this.leafletElement.setLatLng(position);
    }
    if (radius !== fromProps.radius) {
      this.leafletElement.setRadius(radius);
    }
  }
}

export default withLeaflet(CircleMarker);

@Nadhum thanks a lot for your solution. I was having the same: MarkerClusterGroup with CircleMarkers inside was throwing this error: https://github.com/YUzhva/react-leaflet-markercluster/issues/31.

This fixes it straight away if, when creating the CircleMarker, I pass not only the center, but also position prop

<CircleMarker
      center={latlng}
      position={latlng}
</CircleMarker>

Fixed by PR #6719

Fixed by PR #6719

Confirmed, upgrade to leaflet 1.6 fixes this issue for me.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

onethread picture onethread  Â·  3Comments

remilev picture remilev  Â·  4Comments

CallMarl picture CallMarl  Â·  3Comments

pgeyman picture pgeyman  Â·  3Comments

jcarenza picture jcarenza  Â·  3Comments