Leaflet / Leaflet.VectorGrid

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

Nothing rendering with `_getVectorTilePromise` custom implementation #278

Closed slutske22 closed 1 year ago

slutske22 commented 1 year ago

I am trying to implement a custom vectorgrid to work with my application's api. I am struggling to get anything rendering on the map using this method though. The docs state that

Classes inheriting from VectorGrid must define the _getVectorTilePromise private method.

And that _getVectorTilePromise is a function that takes in a TileCoord, and returns a promise that resolves to a vector tile. This is my implementation:

export const StationGridLayer = L.VectorGrid.extend({
  _getVectorTilePromise: async function (coords: TileCoord) {
    console.log(coords);
    // Fancy logic to retrieve data from our api based on a tile coordinate
    const response = await fetchTile(tilecoordToBounds(tilename(coords)));

    // Transform data into geojson
    const geojson = podsToGeoJson(response.result.data.data);

    // Create geojsonvt from the geojson
    const vt = geojsonvt(geojson, this.options);

    // resolve the geojson vt
    return vt;
  }
});

L.StationGridLayer = StationGridLayer;
L.stationGridLayer = (options?: L.VectorGridOptions) =>
  new L.StationGridLayer(options);

When I create a StationGridLayer, nothing renders on the map:

const stations = L.stationGridLayer({
  interactive: true,
  debug: 1
}).addTo(map);

Though looking at the debug logs, it seems like everything is working properly under the hood:

Screen Shot 2022-12-28 at 1 41 38 PM

The number of features and points is always consistent with what I would expect from my dataset based on the zoom level (lower zoom means higher number of points), and I see that some of the debug logs show tiles generated: 1 {"z0":1}, though some of them also show tiles generated: 0 {}, so I'm not sure what's going on there.

What am I doing wrong here? Why are my debug logs showing real data come through, and tiles being generated, but nothing rendered to the screen? In an alternate scenario where I grab the data from the API, and feed it to VectorGrid.Slicer, it renders as expected.

Sandbox demonstrating the issue

Sandbox where VectorGrid.Slicer works nicely with the api

IvanSanchez commented 1 year ago

The code expects that promise to resolve to a vector tile, and not to the geojsonvt instance (which holds multiple tiles, at least in the general case). Leverage .getTile() on the geojsonvt instance.

slutske22 commented 1 year ago

@IvanSanchez sorry to bother on what is more of a question than an issue, but I don't see how this is supposed to work exactly. I try something like

return vt.getTile(z, y, x) // where z, y, x comes from the coord argument

I get the error Cannot read properties of null (reading 'layers'). I dug into some of the source code and examples, and I see that _getVectorTilePromise is sometimes written to return an object with a .layers and .coords property. So I tried this:

return { layers: vt.getTile(z, x, y), coords }

But that gives the error Cannot read properties of undefined (reading 'length'). That appears to be erroring on the .features property from within the vectorgrid source code. When I check the GeoJSON being fed to geojsonvt, it seems to be a correct .features array:

Screen Shot 2022-12-30 at 8 41 47 AM

Apparently sometimes the getTile function returns null. I fixed that with a check:

// With check to make sure function returns a non-null value
 return (
      vt.getTile(z, x, y)?.features ?? {
        features: [],
        numFeatures: 0,
        numPoints: 0,
        numSimplified: 0,
        source: [],
        transformed: true,
        ...coords
      }
    );

Which supresses the errors. But still, nothing renders here.

What am I doing wrong in this case? (Sandbox is updated to show the new code)

IvanSanchez commented 1 year ago

Read https://github.com/Leaflet/Leaflet.VectorGrid/blob/master/src/slicerWebWorker.js (or an old workerless version of the Slicer). Debug and compare how the slicer works versus how your code works.