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

Override vectorTileLayerStyles

Open torresomar opened this issue 8 years ago • 5 comments

First of all thanks for this implementation, I have to ask if it is possible to override the functions in charge of styles of the vector tiles dynamically. I tried checking the code in order to find the place where I could possibly achieve this but I couldn't find where. What I am trying to achieve is something like this:

var layer = L.vectorGrid.protobuf(url, vectorTileOptions);
....
document.getElementById('swap-styles').addEventListener('click', e => {
    layer.updateLayerStyle('the_layer_name', newColorFn);
    // the above would trigger a redraw for the viewport tiles
    // and the next tiles to be rendered would use the updated function
}

Thanks :)

torresomar avatar Dec 10 '16 01:12 torresomar

Hi there, you mean you want to update the style for all features in the layer?

There is currently no method for doing that. You could theoretically achieve this by using getFeatureId option, and then finding all features through the private member _vectorTiles and settings their style, but that would be a hack.

This seems like a useful feature, though, so I'll keep the issue open and think about if it could be implemented.

perliedman avatar Dec 13 '16 08:12 perliedman

duplicate/related to #50

abenrob avatar Jan 04 '17 13:01 abenrob

I have done what you describe: override/replace the vectorTileLayerStyles for a specific layer, then call its redraw() in order to apply the new style.

// the VectorGrid setup, with initial color schemes
mylayer = L.vectorGrid.protobuf(URL_HERE, {
	rendererFactory: L.canvas.tile,
	interactive: true,
	vectorTileLayerStyles: {
		easythings: {
			fill: true, fillColor: 'blue', fillOpacity: 1,
			color: 'rgb(0, 0, 0)', opacity: 1, weight: 0.5,
		},
		bigthings: {
			fill: true, fillColor: 'red', fillOpacity: 1,
			color: 'rgb(0, 0, 0)', opacity: 1, weight: 0.5,
		},
		otherthings: {
			fill: true, fillColor: 'yellow', fillOpacity: 1,
			color: 'rgb(0, 0, 0)', opacity: 1, weight: 0.5,
		}
	},
}).addTo(MAP);
// override the styles for one of those, to use a different fill color
// then redraw
mylayer.options.vectorTileLayerStyles.bigthings.fillColor = 'purple';
mylayer.redraw();
// override the styles for one of those, to use a callback for choosing colors
// before, it was just one solid color but now it chooses based on criteria
// then redraw
mylayer.options.vectorTileLayerStyles.easythings = function (properties, zoom) {
    var style = {
        fill: true, fillColor: 'white', fillOpacity: 1,
        color: 'rgb(0, 0, 0)', opacity: 1, weight: 0.5,
    };

    switch (properties.status) {
        case 'done':
            style.fillColor = 'orange';
            break;
        case 'happening':
            style.fillColor = 'silver';
            break;
        case 'pending':
            style.fillColor = 'blue';
            break;
        default:
            style.fillColor = 'green';
            break;
    }

    return style;
};
mylayer.redraw();

An improvement I would like to see, would be an alternative to redraw() to simply reapply the styles, without re-downloading the tiles. As it stands, the tiles are re-downloaded and this makes for a relatively slow visual experience as well as network usage and server hits. I think I'll open an Issue for that, and see about doing that...

gregallensworth avatar Apr 11 '18 18:04 gregallensworth

And should it be possible to achieve the same behavior with a L.vectorGrid.slicer layer? I tried the same approach you suggest, the layer only flashes but its style is not updated. Inspecting layer.options.vectorTileLayerStyles.sliced reveals that whatever style I am setting gets changed there, just not on the tiles.

tapiamcclung avatar Jun 13 '19 23:06 tapiamcclung

As an update to my previous post/question, I found that if I only set a property and redraw the layer, it doesn't work:

layer.options.vectorTileLayerStyles.sliced.fillColor = 'green';
layer.redraw();

whereas setting it to be a function and return the style, does:

layer.options.vectorTileLayerStyles.sliced = () => {
  return {
     fill: true,
     fillColor: 'green',
     fillOpacity: 0.25,
     stroke: true,
     color: 'green',
     weight: 1
  }
}
layer.redraw();

I had to include fill for fillColorto work... Not sure why, though.

tapiamcclung avatar Jun 18 '19 03:06 tapiamcclung