leaflet-vector-tile-layer
Version:
Leaflet layer for vector tiles
330 lines (254 loc) • 12.4 kB
Markdown
Leaflet.VectorTileLayer
=======================
This module provides a [Leaflet][L] layer that displays [vector tiles][VT].
It is very similar to [`Leaflet.VectorGrid`][LVG].
The biggest difference to `VectorGrid` is the [styling](#style-options).
`VectorTileLayer` also supports two options `min/maxDetailZoom` which are
subtly different from `VectorGrid`'s `min/maxNativeZoom`. Both provide the
possibility to specify a range of zoom levels that offer an optimal
trade-off between detail and size. When using the `native` variants, tiles
above or below the zoom range are scaled, changing the stroke weight. The
`detail` settings offer the same trade-off while still rendering the tiles
at the correct zoom levels, meaning stroke weight is visually consistent
across all zoom levels.
Furthermore, `VectorTileLayer` gives clients full control over the SVG DOM
created for vector tile features. The layer option `featureToLayer` accepts
a function that can return any graphics for visualising a given feature
while making it easy to fall back to the default implementation.
In contrast to `VectorGrid`, this class has been designed as much as
possible in terms of Leaflet's public API. This makes it more likely to
continue working with future versions of Leaflet.
Use
---
Loads vector tiles from a URL template like
https://{s}.example.com/tiles/{z}/{x}/{y}.pbf
The URL template also supports the undocumented `{-y}` option for
»[inverted Y][Y]« if the map's [coordinate reference system][CRS] is finite
(the default).
This pacakge can be used as an ES6 module.
```js
import vectorTileLayer from 'leaflet-vector-tile-layer';
const tileLayer = vectorTileLayer(url, options);
```
The AMD build comes with all dependencies included. If imported as an ES6
module, the dependencies need to be made available to the build system, for
example:
```sh
$ npm install /vector-tile pbf
```
See this package's development dependencies for version information.
Layer options
-------------
The main difference to `VectorGrid` is that `VectorTileLayer` takes a
different approach to styling. Whereas `VectorGrid` only supports styling a
previously known set of vector-tile layer names, this class allows
specifying a single style for all layers irrespective of their names. When
specifying a function, it is called with the vector-tile feature, the layer
name and the current zoom level, enabling clients can handle layer names
dynamically or ignore them altogether.
Another feature not supported by `VectorGrid` is a `setStyle()` call which
allows changing the style of the entire layer.
For compatibility, support for the `vectorTileLayerStyles` option and
`set/resetFeatureStyle()` method is also provided.
`VectorTileLayer` also supports ordering the layers based on their names
using an option like `layers: ["a", "b", "c"]`.
Another added feature of `VectorTileLayer` is a `getBounds()` function.
After the `load` event, it returns the bounds occupied by the features on
all currently loaded tiles.
`VectorTileLayer` allows clients to create their own DOM representation for
any given layer. A function provided to the `featureToLayer` option takes a
vector-tile feature, the layer name, the number of SVG coordinate units per
vector-tile unit and the feature's style object. It should return an object
that eventually delegates to [`Leaflet.Layer`][LYR] and provides the
following:
- a `bbox()` function that returns the feature's bounding box in SVG
coordinate units.
- a `graphics` property that holds the top-level SVG DOM element.
- a `setStyle(style)` function that takes a style object and applies it
to the generated SVG elements.
`VectorTileLayer` supports all options provided by [`GridLayer`][GL].
Additionally, the following options are provided:
```js
const url = 'https://{s}.example.com/tiles/{z}/{x}/{y}.pbf';
const options = {
// A function that will be passed a vector-tile feature, the layer
// name, the number of SVG coordinate units per vector-tile unit
// and the feature's style object to create each feature layer.
featureToLayer, // default undefined
// Options passed to the `fetch` function when fetching a tile.
fetchOptions, // default undefined
// A function that will be used to decide whether to include a
// feature or not. If specified, it will be passed the vector-tile
// feature, the layer name and the zoom level. The default is to
// include all features.
filter, // default undefined
// A function that receives a list of vector-tile layer names and
// the zoom level and returns the names in the order in which they
// should be rendered, from bottom to top. The default is to render
// all layers as they appear in the tile.
layerOrder, // default undefined
// An array of vector-tile layer names from bottom to top. Layers
// that are missing from this list will not be rendered. The
// default is to render all layers as they appear in the tile.
layers, // default undefined
// Specify zoom range in which tiles are loaded. Tiles will be
// rendered from the same data for Zoom levels outside the range.
minDetailZoom, // default undefined
maxDetailZoom, // default undefined
// Either a single style object for all features on all layers or a
// function that receives the vector-tile feature, the layer name
// and the zoom level and returns the appropriate style options.
style, // default undefined
// This works like the same option for `Leaflet.VectorGrid`.
// Ignored if style is specified.
vectorTileLayerStyles, // default undefined
};
const layer = vectorTileLayer(url, options);
```
The style can be updated at any time using the `setStyle()` method.
```js
layer.setStyle({ weight: 3 });
```
All omitted options will be substituted by the default options for
[`L.CircleMarker`][CM], [`L.Polyline`][PL] or [`L.Polygon`][PG], as
appropriate.
Style options
-------------
Style options are interpreted by the individual feature layers. For points,
these are `L.CircleMarker` options, or the `icon` property supplies an
`L.Icon` to determine the appearance. For polylines or polygons, these are
`L.Path` options. If the `options.style` property is a function, it will be
passed the vector-tile feature, the layer name and the zoom level as
parameters.
If the style option `interactive` is `true`, the created SVG elements will
listen to mouse events.
The style option `hidden` permits any feature to be hidden. It operates by
setting the SVG attribute `visibility` to `hidden`.
Feature layer helpers
---------------------
A few functions are made available to simplify creating custom layers for
individual features:
- `defaultFeatureLayer(feature, layerName, pxPerExtent, options)`. This
function is used if the `featureToLayer` option is unset. It takes the
vector-tile feature, the layer name, the number of SVG coordinate units
per vector-tile unit and a style object and returns an appropriate layer
object to visualise it.
- `featureCircleLayer(feature, layerName, pxPerExtent, options)` returns a
layer object that visualises a vector-tile point feature.
- `featureIconLayer(feature, layerName, pxPerExtent, options)` returns a
layer object that visualises a vector-tile point feature using the
[`Leaflet.Icon`][ICO] specified by `options.icon`.
- `featurePathLayer(feature, layerName, pxPerExtent, options)` returns a
layer object to visualise a vector-tile line or polygon feature.
- `featureLayerBase(feature, layerName, pxPerExtent, options)` can be used
to create a layer object for a vector-tile feature. It returns an object
that eventually delegates to a [`Leaflet.Layer`][LYR] instantiated with
the given options. The delegating object must provide:
- a `graphics` property that holds the top-level SVG DOM element.
- a `setStyle(style)` method that applies the given style to the
layer's DOM after enhancing it with the feature layer's default
options.
Objects created by this function provide the following:
- An `applyOptions(style)` function that should be called by a
delegating object once the `graphics` property is initialised. It
applies the `style.className` option to it and then invokes
`setStyle({})` to allow the delegating object to apply its default
style.
- A `bbox()` function that returns the feature's bounding box in SVG
coordinate units and is used by `VectorTileLayer.getBounds()`.
- A `scalePoint(point)` function converts from vector-tile coordinates
to SVG coordinates.
A few functions are provided to simplify the implementation of
`setStyle(style)` functions:
- `applyBasicStyle(element, style)` applies the `style.interactive` and
`style.hidden` options to the given SVG DOM element.
- `applyImageStyle(element, style)` applies the `height`, `width` and
`href` proprties from the [`Leaflet.Icon`][ICO] object in `style.icon`
to the SVG `<image>` element.
- `applyPathStyle(element, style)` applies [`Leaflet.Path`][PT] style
properties to the SVG `<path>` element.
Feature layer example
---------------------
The `featureToLayer` option on `VectorTileLayer` accepts a function that
can render custom SVG elements depending on feature properties, options,
layer names and zoom level.
Example drawing a thickened transparent overlay for polyline interaction:
```js
import {SVG} from "leaflet";
import {defaultFeatureLayer, featureLayerBase} from "leaflet-vector-tile-layer";
function interactiveLinesLayer(feature, layerName, pxPerExtent, options) {
// Construct a base feature layer.
const self = featureLayerBase(feature, layerName, pxPerExtent, options);
// Compose this feature layer of two sub-layers, one for the visible
// line controlled by `options` and a second controlled by the path
// options contained in `options.interaction`. Both will share the same
// path geometry.
self.visibleLine = defaultFeatureLayer(
feature,
layerName,
pxPerExtent,
options
);
self.interactionLine = defaultFeatureLayer(
feature,
layerName,
pxPerExtent,
options.interaction
);
// Place the two layers in an SVG group.
const group = SVG.create("g");
group.appendChild(self.visibleLine.graphics);
group.appendChild(self.interactionLine.graphics);
self.graphics = group;
// Setting of style is delegated to the sub layers.
self.setStyle = function setStyle(style) {
self.visibleLine.setStyle(style);
self.interactionLine.setStyle(style.interaction);
};
// Initial setup of this feature layer.
self.applyOptions(options);
return self;
}
// Example options for the above custom renderer:
const interactiveLineOptions = {
color: "red",
weight: 2,
interaction: {
opacity: 0.0,
weight: 10
}
};
```
Events
------
Events attached to this layer provide access to the vector-tile `feature`
and the `layerName` through their `layer` attribute. For compatibility with
`VectorGrid`, the feature's `properties` are also made directly available.
Installing and building
-----------------------
You can install this package using
```sh
$ npm install leaflet-vector-tile-layer
```
It can be built by
```sh
$ npm run build
```
Limitations
-----------
At this time, only SVG rendering and vector tiles in [`protobuf`][PBF]
format are supported, but support for other renderers or formats may be
added through options in the future.
[CM]: https://leafletjs.com/reference.html#circlemarker
[CRS]: https://leafletjs.com/reference#crs
[ICO]: https://leafletjs.com/reference.html#icon
[GL]: https://leafletjs.com/reference.html#gridlayer
[LVG]: https://github.com/Leaflet/Leaflet.VectorGrid
[LYR]: https://leafletjs.com/reference.html#layer
[L]: http://leafletjs.com/
[PBF]: https://developers.google.com/protocol-buffers/
[PG]: https://leafletjs.com/reference.html#polygon
[PL]: https://leafletjs.com/reference.html#polyline
[PT]: https://leafletjs.com/reference.html#path
[VT]: https://github.com/mapbox/vector-tile-spec
[Y]: https://github.com/Leaflet/Leaflet/issues/4284