francoisromain / leaflet-markers-canvas

A Leaflet plugin to render many markers in a canvas instead of the DOM
GNU Affero General Public License v3.0
42 stars 15 forks source link

Able to stack multiple layers, but mousepointer seems to only work with the top layer #9

Open Michael-372 opened 2 years ago

Michael-372 commented 2 years ago

Mouse and click events fire regardless of layer, but the mouse does not change to "pointer" for markers that aren't in the top most L.MarkersCanvas().

const layers = {
    bottom: new L.MarkersCanvas(),
    middle: new L.MarkersCanvas(),
    top: new L.MarkersCanvas(),
}

Only "top" layer has mouse pointer on hover.

francoisromain commented 2 years ago

Hello Michael, The canvas on top prevents clicking on anything below. I don't know how to do something about this issue. Why don't you put all your markers in the same canvas instead?

Michael-372 commented 2 years ago

I can move to a single layer by drawing the markers I want on top at the end of the loop, however, when I pan around the map the redraw doesnt seem to preserve the original order in which I drew the markers. Certain markers NEED to be on top in my application as they are more important than others.

Creating different layers allowed me to guarantee the important markers stay on top. But it removed my ability to have mouse over pointer. I'm open to ideas on how to move forward.

Michael-372 commented 2 years ago

@francoisromain

I was looking at the code and I think this issue can be resolved by making the following change:

Original Code:

      } else {
        this._map._container.style.cursor = "";
        if (event.type === "mousemove" && this._mouseOverMarker) {
          if (this._mouseOverMarker.listens("mouseout")) {
            this._mouseOverMarker.fire("mouseout");
          }

          delete this._mouseOverMarker;
        }
      }

Proposed change:

      } else {
        if (event.type === "mousemove" && this._mouseOverMarker) {
          // Relocated to inside the event.type.
          // Basically only change the cursor to default, if we are leaving a marker
         // --------------------------------------------------------
          this._map._container.style.cursor = ""; 
         // --------------------------------------------------------
          if (this._mouseOverMarker.listens("mouseout")) {
            this._mouseOverMarker.fire("mouseout");
          }

          delete this._mouseOverMarker;
        }
      }

Manually making this change in a local branch allows me to have multiple layers with multiple mouse over events and correctly functioning pointers.

Would you like me to make a PR for the change?

francoisromain commented 2 years ago

I gave a try with example below. The pointer changes on mouseover on both layers A and B.

Please make a repro to show your problem.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>leaflet-markers-canvas example</title>
    <link
      rel="stylesheet"
      href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
    />
    <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
    <script src="https://unpkg.com/rbush@3.0.1/rbush.js"></script>
    <script src="https://unpkg.com/leaflet-markers-canvas@0.2.2/dist/leaflet-markers-canvas.min.js"></script>
    <style>
      body {
        font-family: Arial, Helvetica, sans-serif;
      }
      .container {
        margin: 0 auto;
        max-width: 1200px;
      }
      .map {
        width: 100%;
        height: 600px;
      }
      .header {
        padding-top: 50px;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <div class="header">
        <h1>leaflet-markers-canvas</h1>
        <p>
          A Leaflet plugin to render many markers in a canvas instead of the
          DOM.
        </p>

        <p>
          <a href="https://github.com/francoisromain/leaflet-markers-canvas"
            >https://github.com/francoisromain/leaflet-markers-canvas</a
          >
        </p>
      </div>
      <div class="map" id="map"></div>
    </div>
    <script>
      var map = L.map("map").setView([59.9578, 30.2987], 10);
      var tiles = L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
        attribution:
          '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a>',
        preferCanvas: true,
      }).addTo(map);

      var markersCanvasA = new L.MarkersCanvas();
      map.addLayer(markersCanvasA);
      var icon = L.icon({
        iconUrl: "marker.png",
        iconSize: [20, 32],
        iconAnchor: [10, 0],
      });

      var markersA = [];

      for (var i = 0; i < 100; i++) {
        var marker = L.marker(
          [58.5578 + Math.random() * 1.8, 29.0087 + Math.random() * 3.6],
          { icon }
        )
          .bindPopup("A" + i)
          .on({
            mouseover(e) {
              this.openPopup();
            },
            mouseout(e) {
              this.closePopup();
            },
          });

        markersA.push(marker);
      }

      markersCanvasA.addMarkers(markersA);

      var markersCanvasB = new L.MarkersCanvas();
      map.addLayer(markersCanvasB);
      var icon = L.icon({
        iconUrl: "marker.png",
        iconSize: [20, 32],
        iconAnchor: [10, 0],
      });

      var markersB = [];

      for (var i = 0; i < 100; i++) {
        var marker = L.marker(
          [58.5578 + Math.random() * 1.8, 29.0087 + Math.random() * 3.6],
          { icon }
        )
          .bindPopup("B" + i)
          .on({
            mouseover(e) {
              this.openPopup();
            },
            mouseout(e) {
              this.closePopup();
            },
          });

        markersB.push(marker);
      }

      markersCanvasB.addMarkers(markersB);
    </script>
  </body>
</html>
samwillis commented 2 years ago

I had the same issue, some markers on a "markers-canvas" and others on a native leaflet canvas, the "markers-canvas" was blocking pointer events from making it though to the native leaflet canvas. This css solves it:

    canvas.leaflet-markers-canvas-layer {
      pointer-events: none;
    }

Should also add thanks for the plugin!!

chrysllercs commented 2 years ago

I'm having the same problem I can't click on bottom layers

albertoamohp commented 1 year ago

you can do this: ciLayer._container.style.pointerEvents = 'none';

but you will loose al the pointer events in the top canvas