Leaflet / Leaflet.VectorGrid

Display gridded vector data (sliced GeoJSON or protobuf vector tiles) in Leaflet 1.0.0
601 stars 193 forks source link

Problem with Leaflet >= 1.8 #274

Open SamG92 opened 2 years ago

SamG92 commented 2 years ago

Hi there,

I'm using VectorGrid and trying to catch the click event on one of my feature/vectorgrid using following code:

vectorGrid.on('click', function(e) { L.popup() .setContent("test") .setLatLng(e.latlng) .openOn(map); }

It works perfectly fine with Leaflet 1.7.1 but crashes with Leaflet 1.8+. I get the following error when the click happens:

Uncaught TypeError: L.DomEvent.fakeStop is not a function at NewClass._onClick (Leaflet.VectorGrid.bundled.min.js:2:15768) at HTMLCanvasElement.handler (DomEvent.js:108:13) Leaflet.VectorGrid.bundled.min.js:2

Strangely, the "mouseover" event is working fine.

Any idea on how to get it working?

Thanks a lot Sam

PalleZ commented 2 years ago

TL;DR: I solved this by changing to svg renderer instead of canvas renderer with rendererFactory option.

Issue is due to a change in Leaflet 1.8 due to this issue, https://github.com/Leaflet/Leaflet/issues/7431 Leaflet.Vectorgrid extends the Canvas renderer and its _onClick function and thus it has old Canvas code with fakeStop. But SVG renderer does not extend _onClick, instead it uses Leaflet native _onClick.

I think that this kind of issues is why the author of Leaflet.VectorTileLayer opted for another design. As he writes: "In contrast to VectorGrid, this class has been designed as much as possible in terms of Leaflet's public API."

dpakprajul commented 1 year ago

I have used: 1) <script src="https://unpkg.com/leaflet@1.9.2/dist/leaflet.js" integrity="sha256-o9N1jGDZrf5tS+Ft4gbIK7mYMipq9lqpVJ91xHSyKhg=" crossorigin=""> 2)

additional code: var vtLayer2 = L.vectorGrid .slicer(vt_layer, { rendererFactory: L.svg.tile, vectorTileLayerStyles: { sliced: function (properties, zoom) { var p = properties.D01; return {

        fillColor:
          p <= 3 ? "#ccffbb" :
            p <= 10 ? '#800026' :
              p <= 20 ? '#BD0026' :
                p <= 30 ? '#E31A1C' :
                  p <= 40 ? '#FC4E2A' :
                    p <= 50 ? '#FD8D3C' :
                      p <= 60 ? '#FEB24C' :
                        p <= 70 ? '#FED976' :
                          p <= 100 ? '#E31A1C' :
                            p <= 120 ? '#800026' :
                              p <= 150 ? '#FEB24C' :
                                p <= 300 ? '#B2FE4C' :
                                  p <= 500 ? '#B2FE4C' :
                                    p <= 1000 ? '#B2FE4C' :
                                      p <= 2000 ? '#B2FE4C' : '#FFEDA0',

        fillOpacity: 0.5,
        //fillOpacity: 1,
        stroke: true,
        fill: true,
        color: 'black',
        //opacity: 0.2,
        weight: 0,
      }
    },
  },
  interactive: true,
  getFeatureId: function (f) {
    return f.properties.NAMELSAD10;
  }
}).on('mouseover', function (e) {
  var properties = e.layer.properties;
  L.popup()
    .setContent("County: " + e.layer.properties.NAMELSAD10 + "<br>White Student: " + e.layer.properties.D01 + "<br>White Teacher: " + e.layer.properties.D02)
    .setLatLng(e.latlng)
    .openOn(map);

  clearHighlight();
  highlight = properties.NAMELSAD10;

  var p = properties.D01;;
  var style = {
    fillColor: p === 0 ? '#800026' :
      p <= 3 ? "#ccffbb" :
        p <= 10 ? '#800026' :
          p <= 20 ? '#BD0026' :
            p <= 30 ? '#E31A1C' :
              p <= 40 ? '#FC4E2A' :
                p <= 50 ? '#FD8D3C' :
                  p <= 60 ? '#FEB24C' :
                    p <= 70 ? '#FED976' :
                      p <= 100 ? '#E31A1C' :
                        p <= 120 ? '#800026' :
                          p <= 150 ? '#FEB24C' :
                            p <= 300 ? '#B2FE4C' :
                              p <= 500 ? '#B2FE4C' :
                                p <= 1000 ? '#B2FE4C' :
                                  p <= 2000 ? '#B2FE4C' : '#FFEDA0',
    fillOpacity: 0.5,
    fillOpacity: 1,
    stroke: true,
    fill: true,
    color: 'red',
    opacity: 1,
    weight: 2,
  };

  vtLayer2.setFeatureStyle(properties.NAMELSAD10, style);
})
.addTo(map);

vtLayer2.on('click', function(e) { var properties = e.layer.properties.NAMELSAD10;

        highlight = properties.NAMELSAD10;

        var p = properties.D01;
        var style = {
            fillColor: p === 0 ? '#800026' :
    p<=3?"#ccffbb":
    p <=10 ? '#800026' :
      p <= 20  ? '#BD0026' :
      p <= 30  ? '#E31A1C' :
      p <= 40  ? '#FC4E2A' :
      p <= 50   ? '#FD8D3C' :
      p <= 60   ? '#FEB24C' :
      p <= 70   ? '#FED976' :
        p <=100 ? '#E31A1C' :
        p<=120?'#800026':
        p <=150 ? '#FEB24C' :
        p <= 300 ? '#B2FE4C':
        p <= 500 ? '#B2FE4C': 
        p <= 1000 ? '#B2FE4C': 
        p <=2000 ? '#B2FE4C' : '#FFEDA0',
            fillOpacity: 0.5,
            fillOpacity: 1,
            stroke: true,
            fill: true,
            color: 'red',
            opacity: 1,
            weight: 2,
        };

        vtLayer2.setFeatureStyle(properties.NAMELSAD10, style);

});

image

slutske22 commented 1 year ago

I was able to solve this by including the following code before any use of L.VectorGrid code. This overwrites the place in the codebase where .fakeStop is used, and passes the event on to fire correctly without error

L.Canvas.Tile.include({
    _onClick: function (e) {
        var point = this._map.mouseEventToLayerPoint(e).subtract(this.getOffset());
        var layer: L.Layer;
        var clickedLayer: L.Layer;

        for (var id in this._layers) {
            layer = this._layers[id];
            if (
                layer.options.interactive &&
                layer._containsPoint(point) &&
                !this._map._draggableMoved(layer)
            ) {
                clickedLayer = layer;
            }
        }
        if (clickedLayer) {
                         // offending code used to be right here
            clickedLayer.fireEvent(e.type, undefined, true);
        }
    },
});