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

Broken lines

Open zedsh opened this issue 6 years ago • 5 comments

I'm trying to map routes from GeoJson. Lines are displayed, but with a small increase they are broken. I suspect that somehow they are not redrawn. Help me please.

https://i.imgur.com/vzGIeHL.png https://i.imgur.com/VY37RL9.png

zedsh avatar May 30 '18 15:05 zedsh

In the first shot, it looks like an entire tile is missing. Notice how the lines are cut perfectly along the y and x axis at the same coordinates, like a square was cut out there.

Of course hard to tell what's going on without a bit more information about what you're doing.

perliedman avatar Jun 01 '18 06:06 perliedman

I've got similar thing happening here:

https://i.imgur.com/5AHlclA.jpg

The problem is that VectorGrid does not render multiple "named layers" in their order when grouped as one Leaflet gridLayer. For example you would have "landuse", "admin", "water" as "named layers," and "pbfLayer" as the Leaflet gridLayer.

So the tiles may or may not be consistent in their rendering order and, for example, you would have one tile that has "landuse" on top, while it's neighboring tile has "admin" on top.

Any workaround approach would be appreciated.

mngyng avatar Aug 01 '18 01:08 mngyng

Managed to have a workaround. The source of the problem is that the vector tile server serves those named layers of a tile without taking care of the order of rendering. I ended up assigning the rendering order in the styling options, and modified Leaflet.VectorGrid.bundle.js to make them render in order (somewhere from line 1997, for the latest version on Aug.3, 2018). Not a pretty code, though.

mngyng avatar Aug 03 '18 08:08 mngyng

mngyng, any chance of getting hold of your work around?

zawarski avatar Dec 29 '18 20:12 zawarski

@zawarski , I'm posting my entire createTile() here. You could probably do a diff among different versions of Leaflet.VectorGrid.bundle.js to find out what's changed. You'll now have to assign a non-negative integer zorder to indicate the rendering order of each layer in the composite layer in your styling options/function, e.g. admin:{weight: 1, fillColor: '#ffffff', fillOpacity: 1, fill: true, zorder:0}, landuse: {weight: 0, fillColor: '#9bc2c4', fillOpacity: 1, fill: true, zorder:1}. The layer that has a larger zorder is rendered later, i.e., rendered as the upper layer. The downside is the backward-compatibility for your old codes that doesn't have a zorder in the styling options.

Now the code:

	createTile: function(coords, done) {
		var storeFeatures = this.options.getFeatureId;

		var tileSize = this.getTileSize();
		var renderer = this.options.rendererFactory(coords, tileSize, this.options);

		var vectorTilePromise = this._getVectorTilePromise(coords);

		if (storeFeatures) {
			this._vectorTiles[this._tileCoordsToKey(coords)] = renderer;
			renderer._features = {};
		}

		vectorTilePromise.then( function renderTile(vectorTile) {
			var layerorder = new Array(Object.keys(vectorTile.layers).length);
			var cc=0;
			Array.prototype.clean = function(deleteValue) {
				for (var i = 0; i < this.length; i++) {
					if (this[i] == deleteValue) {         
						this.splice(i, 1);
						i--;
					}
				}
				return this;
			};
			for (var layerName0 in vectorTile.layers) {
				var layerStyle = this.options.vectorTileLayerStyles[ layerName0 ];
				if (layerStyle instanceof Function) {
					layerStyle = layerStyle(vectorTile.layers[layerName0].features[0].properties, coords.z);
				}
				layerorder[layerStyle.zorder]=layerName0;
				cc++;
				if (cc == Object.keys(vectorTile.layers).length){

					layerorder.clean(undefined);
					for (var ilayer = 0; ilayer < layerorder.length; ilayer++) {
						var layerName = layerorder[ilayer];
						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);
								var styleOverride = this._overriddenStyles[id];
								if (styleOverride) {
									if (styleOverride[layerName]) {
										styleOptions = styleOverride[layerName];
									} else {
										styleOptions = styleOverride;
									}
								}
							}
		
							if (styleOptions instanceof Function) {
								styleOptions = styleOptions(feat.properties, coords.z);
							}
		
							if (!(styleOptions instanceof Array)) {
								styleOptions = [styleOptions];
							}
		
							if (!styleOptions.length) {
								continue;
							}
		
							var featureLayer = this._createLayer(feat, pxPerExtent);
		
							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,
									feature: featureLayer
								};
							}
						}
		
					}

				}
			}
			if (this._map != null) {
				renderer.addTo(this._map);
			}
			L.Util.requestAnimFrame(done.bind(coords, null, null));
		}.bind(this));

		return renderer.getContainer();
	},

mngyng avatar Jan 03 '19 00:01 mngyng