Leaflet.VectorGrid icon indicating copy to clipboard operation
Leaflet.VectorGrid copied to clipboard

Rework maxNativeZoom

Open IvanSanchez opened this issue 8 years ago • 11 comments

As @jkuebart pointed out:

It's interesting to note that by using maxNativeZoom as implemented by GridLayer, vector tiles will not be re-rendered at higher zoom levels. Consequently, the stroke width is scaled up along with the tile, while with the previous solution given above the stroke width remained constant.

If maxNativeZoom is only used because there is sufficient detail at a particular zoom level, this might not be the intended effect. If the stroke width should remain visually constant across all zoom levels, a vector tile layer might still need to reimplement getTileSize() and createTile() accordingly.

I think this is a valid concern, and deserves its own issue.

A tentative approach would be to:

  • Override L.GridLayer._clampZoom and replace it with an identity function
  • Calculate the "data tile" to be fetched for a given "display tile"
  • Multiply pxPerExtent by (2 to the power of the zoom delta)
  • Calculate some pxOffset for when the "data tile" and "display tile" are not aligned at their top left corners
  • Use that pxOffset in all coordinate calculations in PointLayer, PolylineLayer and PolygonLayer

Another approach would be:

  • Keep the current _clampZoom logic
  • On a zoomend event, iterate through all the tiled renderers (there's a reference in this._vectorTiles) and
    • Reset the size of the containers of the tiled renderers by a factor of (2 to the power of zoom delta)
    • Trigger an update of the tiled renderers

First approach doesn't sound too easy, and might need re-requesting tiles. Second approach sounds simpler, almost too simple.

IvanSanchez avatar Feb 13 '17 14:02 IvanSanchez

Do I understand correctly that for your second solution step 2.2 the tiles would need to keep hold of the feature geometries in order to update the path coordinates for the new dimensions? I.e. for the case of SVG, 2.1 would update the viewBox and step 2.2 would recalculate the d attributes for the paths?

jkuebart avatar Feb 15 '17 08:02 jkuebart

The fact is that the tiled renderers already keep an internal copy of the feature geometries (i.e. see the references to this._layers in the /src/layer/vector/SVG.js file).

So step 2.1 would be setting the viewBox as in the constructor of SVG.Tile.js, and hopefully step 2.2 would be a simple renderer._update().

Please keep in mind that this is a conjecture right now, I haven't spent the time to make an actual prototype and see if the methods would work.

IvanSanchez avatar Feb 15 '17 08:02 IvanSanchez

You're right, the renderers have references to the layers (i.e. PolylineLayer and siblings). However, renderer._update() isn't currently called for tile renderers, and I think it would be problematic because it attempts to translate its contents according to the visible area of the map, which is definitely not what we need tiles to do.

Firing an 'update' event at the tile renderer should have the effect of running _updatePaths() which will in turn _update() all the contained PolylineLayers and siblings. But this would be equally problematic since it performs clipping and _simplifyPoints() which might not be desirable for tile features.

I do like the basic idea of adjusting the tiles' viewport and then rescaling the feature coordinates, and I think the first solution would be troublesome not least because extra clipping would be needed on the »sub-tiles«.

I think what basically needs to be done is that the FeatureLayer constructor stores the vector-tile's extent and the feature geometry unmodified (currently it is adjusted to the tile size using pxPerExtent) and the scaling is done before rendering, perhaps re-purposing _project() which serves a similar purpose for latLngs. If this sounds sane, I can start taking a look at implementing this.

jkuebart avatar Feb 15 '17 12:02 jkuebart

I'm not 100% sure, but maybe we can refactor pxPerExtent away? It looks like it should become a property of each tile (i.e. of each tiled renderer), maybe it stays constant through all the tiles (but this is not guaranteed).

Maybe the tiled renderers can just scale everything with a CanvasRenderingContext2D.currentTransform or SVG transform? I wonder if that will resize the line widths and so on as expected.

If this sounds sane, I can start taking a look at implementing this.

For me, every last bit of this sounds completely crazy :rofl: :rofl: :rofl:

IvanSanchez avatar Feb 15 '17 12:02 IvanSanchez

I think the vector-tile extent need not be constant within one tile, since each vector-tile layer seems to have its own extent – but I don't know enough about vector-tiles to be sure.

jkuebart avatar Feb 15 '17 13:02 jkuebart

https://github.com/mapbox/vector-tile-spec/tree/master/2.1

A layer MUST contain an extent that describes the width and height of the tile in integer coordinates.

No wording about extents being identical for every layer in a vector-tile.

jkuebart avatar Feb 15 '17 14:02 jkuebart

@IvanSanchez @jkuebart is anybody here?

egemon avatar Sep 04 '18 23:09 egemon

@egemon Yes, there's somebody here. What's not here is spare time to work on this.

IvanSanchez avatar Sep 05 '18 08:09 IvanSanchez

@egemon I've switched to https://gitlab.com/jkuebart/Leaflet.VectorTileLayer, the readme details differences to Leaflet.VectorGrid.

jkuebart avatar Sep 05 '18 12:09 jkuebart

@jkuebart I don't see that listed in https://leafletjs.com/plugins#vector-tiles - Could you consider adding it to the plugins list?

IvanSanchez avatar Sep 05 '18 12:09 IvanSanchez

@IvanSanchez done, although I haven't done any development on it recently either. I am however using it successfully in one project.

jkuebart avatar Sep 05 '18 12:09 jkuebart