diff --git a/docs/demo-labels.html b/docs/demo-labels.html
new file mode 100644
index 0000000..d901825
--- /dev/null
+++ b/docs/demo-labels.html
@@ -0,0 +1,86 @@
+
+
+
+ Leaflet Map Panes Example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
index cd82d81..f961d1b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@geoblink/leaflet.vectorgrid",
- "version": "1.4.1",
+ "version": "1.5.0",
"description": "Display gridded vector data (sliced GeoJSON or protobuf vector tiles) in Leaflet 1.0",
"main": "dist/Leaflet.VectorGrid.bundled.min.js",
"scripts": {
diff --git a/src/Leaflet.VectorGrid.js b/src/Leaflet.VectorGrid.js
index b804758..2c10f84 100644
--- a/src/Leaflet.VectorGrid.js
+++ b/src/Leaflet.VectorGrid.js
@@ -25,6 +25,9 @@ L.VectorGrid = L.GridLayer.extend({
// A data structure holding initial symbolizer definitions for the vector features.
vectorTileLayerStyles: {},
+ // Function that will execute per feature
+ onEachFeature: null,
+
// 🍂option interactive: Boolean = false
// Whether this `VectorGrid` fires `Interactive Layer` events.
interactive: false,
@@ -41,27 +44,22 @@ L.VectorGrid = L.GridLayer.extend({
if (this.options.getFeatureId) {
this._vectorTiles = {};
this._overriddenStyles = {};
- this.on('tileunload', function(e) {
- var key = this._tileCoordsToKey(e.coords),
- tile = this._vectorTiles[key];
-
- if (tile && this._map) {
- tile.removeFrom(this._map);
- }
- delete this._vectorTiles[key];
- }, this);
}
this._dataLayerNames = {};
+ this._userLayers = {};
+ this.on('tileunload', function(e) {
+ this._tileUnload(e);
+ }, this);
},
createTile: function(coords, done) {
-
var storeFeatures = this.options.getFeatureId;
+ var onEachFeature = this.options.onEachFeature;
var tileSize = this.getTileSize();
var renderer = this.options.rendererFactory(coords, tileSize, this.options);
- var tileBounds = this._tileCoordsToBounds(coords);
+ var tileBounds = this._tileCoordsToBounds(coords);
var vectorTilePromise = this._getVectorTilePromise(coords, tileBounds);
@@ -77,16 +75,16 @@ L.VectorGrid = L.GridLayer.extend({
for (var layerName in vectorTile.layers) {
this._dataLayerNames[layerName] = true;
var layer = vectorTile.layers[layerName];
-
+
var pxPerExtent = this.getTileSize().divideBy(layer.extent);
-
+
var layerStyle = this.options.vectorTileLayerStyles[ layerName ] ||
L.Path.prototype.options;
-
+
for (var i = 0; i < layer.features.length; i++) {
var feat = layer.features[i];
var id;
-
+
var styleOptions = layerStyle;
if (storeFeatures) {
id = this.options.getFeatureId(feat);
@@ -99,31 +97,37 @@ L.VectorGrid = L.GridLayer.extend({
}
}
}
-
+
if (styleOptions instanceof Function) {
styleOptions = styleOptions(feat.properties, coords.z);
}
-
+
if (!(styleOptions instanceof Array)) {
styleOptions = [styleOptions];
}
-
+
if (!styleOptions.length) {
+ if (onEachFeature) {
+ onEachFeature.call(this, feat, null, layer, coords);
+ }
continue;
}
-
+
var featureLayer = this._createLayer(feat, pxPerExtent);
-
+ if (onEachFeature) {
+ onEachFeature.call(this, feat, null, layer, coords);
+ }
+
for (var j = 0; j < styleOptions.length; j++) {
var style = L.extend({}, L.Path.prototype.options, styleOptions[j]);
featureLayer.render(renderer, style);
renderer._addPath(featureLayer);
}
-
+
if (this.options.interactive) {
featureLayer.makeInteractive();
}
-
+
if (storeFeatures) {
renderer._features[id] = {
layerName: layerName,
@@ -131,15 +135,15 @@ L.VectorGrid = L.GridLayer.extend({
};
}
}
-
+
}
-
+
}
-
+
if (this._map != null) {
renderer.addTo(this._map);
}
-
+
L.Util.requestAnimFrame(done.bind(coords, null, null));
}.bind(this), function (err) {
@@ -205,6 +209,47 @@ L.VectorGrid = L.GridLayer.extend({
return Object.keys(this._dataLayerNames);
},
+ vtGeometryToPoint: function(geometry, vtLayer, tileCoords) {
+ var pxPerExtent = this.getTileSize().x / vtLayer.extent;
+ var tileSize = this.getTileSize();
+ var offset = tileCoords.scaleBy(tileSize);
+ var point;
+ if (typeof geometry[0] === 'object' && 'x' in geometry[0]) {
+ // Protobuf vector tiles return [{x: , y:}]
+ point = L.point(offset.x + (geometry[0].x * pxPerExtent), offset.y + (geometry[0].y * pxPerExtent));
+ } else {
+ // Geojson-vt returns [,]
+ point = L.point(offset.x + (geometry[0] * pxPerExtent), offset.y + (geometry[1] * pxPerExtent));
+ }
+ return point;
+ },
+
+ vtGeometryToLatLng: function(geometry, vtLayer, tileCoords) {
+ return this._map.unproject(this.vtGeometryToPoint(geometry, vtLayer, tileCoords), tileCoords.z);
+ },
+
+ addUserLayer: function(userLayer, tileCoords) {
+ var tileKey = this._tileCoordsToKey(tileCoords);
+ this._userLayers[tileKey] = this._userLayers[tileKey] || [];
+ this._userLayers[tileKey].push(userLayer);
+ this._map.addLayer(userLayer);
+ },
+
+ _tileUnload: function(e) {
+ var tileKey = this._tileCoordsToKey(e.coords);
+ if (this._vectorTiles) {
+ delete this._vectorTiles[tileKey];
+ }
+ var userLayers = this._userLayers[tileKey];
+ if (!userLayers) {
+ return;
+ }
+ for(var i = 0; i < userLayers.length; i++) {
+ this._map.removeLayer(userLayers[i]);
+ }
+ delete this._userLayers[tileKey];
+ },
+
_updateStyles: function(feat, renderer, styleOptions) {
styleOptions = (styleOptions instanceof Function) ?
styleOptions(feat.properties, renderer.getCoord().z) :