UNPKG

leaflet.vectorgrid

Version:

Display gridded vector data (sliced GeoJSON or protobuf vector tiles) in Leaflet 1.0

160 lines (135 loc) 4.84 kB
import Pbf from 'pbf'; import {VectorTile} from 'vector-tile'; /* * 🍂class VectorGrid.Protobuf * 🍂extends VectorGrid * * A `VectorGrid` for vector tiles fetched from the internet. * Tiles are supposed to be protobufs (AKA "protobuffer" or "Protocol Buffers"), * containing data which complies with the * [MapBox Vector Tile Specification](https://github.com/mapbox/vector-tile-spec/tree/master/2.1). * * This is the format used by: * - Mapbox Vector Tiles * - Mapzen Vector Tiles * - ESRI Vector Tiles * - [OpenMapTiles hosted Vector Tiles](https://openmaptiles.com/hosting/) * * 🍂example * * You must initialize a `VectorGrid.Protobuf` with a URL template, just like in * `L.TileLayer`s. The difference is that the template must point to vector tiles * (usually `.pbf` or `.mvt`) instead of raster (`.png` or `.jpg`) tiles, and that * you should define the styling for all the features. * * <br><br> * * For OpenMapTiles, with a key from [https://openmaptiles.org/docs/host/use-cdn/](https://openmaptiles.org/docs/host/use-cdn/), * initialization looks like this: * * ``` * L.vectorGrid.protobuf("https://free-{s}.tilehosting.com/data/v3/{z}/{x}/{y}.pbf.pict?key={key}", { * vectorTileLayerStyles: { ... }, * subdomains: "0123", * key: 'abcdefghi01234567890', * maxNativeZoom: 14 * }).addTo(map); * ``` * * And for Mapbox vector tiles, it looks like this: * * ``` * L.vectorGrid.protobuf("https://{s}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/{z}/{x}/{y}.vector.pbf?access_token={token}", { * vectorTileLayerStyles: { ... }, * subdomains: "abcd", * token: "pk.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTS.TUVWXTZ0123456789abcde" * }).addTo(map); * ``` */ L.VectorGrid.Protobuf = L.VectorGrid.extend({ options: { // 🍂section // As with `L.TileLayer`, the URL template might contain a reference to // any option (see the example above and note the `{key}` or `token` in the URL // template, and the corresponding option). // // 🍂option subdomains: String = 'abc' // Akin to the `subdomains` option for `L.TileLayer`. subdomains: 'abc', // Like L.TileLayer // // 🍂option fetchOptions: Object = {} // options passed to `fetch`, e.g. {credentials: 'same-origin'} to send cookie for the current domain fetchOptions: {} }, initialize: function(url, options) { // Inherits options from geojson-vt! // this._slicer = geojsonvt(geojson, options); this._url = url; L.VectorGrid.prototype.initialize.call(this, options); }, // 🍂method setUrl(url: String, noRedraw?: Boolean): this // Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`). setUrl: function(url, noRedraw) { this._url = url; if (!noRedraw) { this.redraw(); } return this; }, _getSubdomain: L.TileLayer.prototype._getSubdomain, _getVectorTilePromise: function(coords) { var data = { s: this._getSubdomain(coords), x: coords.x, y: coords.y, z: coords.z // z: this._getZoomForUrl() /// TODO: Maybe replicate TileLayer's maxNativeZoom }; if (this._map && !this._map.options.crs.infinite) { var invertedY = this._globalTileRange.max.y - coords.y; if (this.options.tms) { // Should this option be available in Leaflet.VectorGrid? data['y'] = invertedY; } data['-y'] = invertedY; } var tileUrl = L.Util.template(this._url, L.extend(data, this.options)); return fetch(tileUrl, this.options.fetchOptions).then(function(response){ if (!response.ok) { return {layers:[]}; } return response.blob().then( function (blob) { // console.log(blob); var reader = new FileReader(); return new Promise(function(resolve){ reader.addEventListener("loadend", function() { // reader.result contains the contents of blob as a typed array // blob.type === 'application/x-protobuf' var pbf = new Pbf( reader.result ); // console.log(pbf); return resolve(new VectorTile( pbf )); }); reader.readAsArrayBuffer(blob); }); }); }).then(function(json){ // console.log('Vector tile:', json.layers); // console.log('Vector tile water:', json.layers.water); // Instance of VectorTileLayer // Normalize feature getters into actual instanced features for (var layerName in json.layers) { var feats = []; for (var i=0; i<json.layers[layerName].length; i++) { var feat = json.layers[layerName].feature(i); feat.geometry = feat.loadGeometry(); feats.push(feat); } json.layers[layerName].features = feats; } return json; }); } }); // 🍂factory L.vectorGrid.protobuf(url: String, options) // Instantiates a new protobuf VectorGrid with the given URL template and options L.vectorGrid.protobuf = function (url, options) { return new L.VectorGrid.Protobuf(url, options); };