ipyleaflet
ipyleaflet copied to clipboard
Interactive vector tile layers
Renderer factory
Vector tile layers can be rendered using either L.canvas.tile or L.svg.tile. Currently, only the canvas option is implemented in ipyleaflet and it's not doing a great job at higher levels of zoom, see for example #1095.
Here a new renderer_factory option was added to VectorTileLayer, which can be either svg or canvas, with the new default being svg.
Here's an example using the ms-buildings from Microsoft Planetary Computer, with the new default (svg):
import ipyleaflet
m = ipyleaflet.Map(center=(41.91867,-88.10602), zoom=15)
url = 'https://planetarycomputer.microsoft.com/api/data/v1/vector/collections/ms-buildings/tilesets/global-footprints/tiles/{z}/{x}/{y}'
layer = ipyleaflet.VectorTileLayer(
url=url,
attribution='Microsoft',
max_native_zoom=13,
max_zoom=20,
vector_tile_layer_styles={"bingmlbuildings":{
"fill":True,
"weight":0.5
}},
)
m.add(layer)
m
And here's how it renders using renderer_factory='canvas':
Interactivity
A new interactive option was added with False as default, which enables the user to add listeners to the layer, which include information about the feature. Note that the default renderer_factory='svg' option should be used for interactivity. For example:
m = ipyleaflet.Map()
layer = ipyleaflet.VectorTileLayer(
url=url_data, # My vector tile layer
interactive=True, # New interactive option
max_native_zoom=13,
max_zoom=20,
renderer_factory='svg', # New renderer_factory option. Defaults to 'svg'
vector_tile_layer_styles=jStyles, # javascript function given as a string
get_feature_id = 'label', # New get_feature_id option. Here, 'label' is the name of the (numeric)
# attribute in my layer that uniquely identifies each feature (see below for more information)
)
m.add(layer)
def handle_click(**kwargs):
if ("properties" in kwargs):
properties = kwargs["properties"]
options = kwargs["options"]
print(properties)
print(options)
layer.on_click(handle_click)
m
get_feature_id
This is an optional attribute that is used to construct a simple javascript function to uniquely identify a feature. This is required if you will be updating feature styles through the new set_feature_style and reset_feature_style methods. The javascript function is of the form:
function (feat: any) {return feat.properties[idVar];}
where feat is the feature, and idVar is the name of the (numeric) attribute in the layer to identify a feature. Note that features with the same id will be treated as one when changing style (see the original getFeatureId documentation here).
Updating styles
Two new methods for VectorTileLayer were added: set_feature_style and reset_feature_style. The first one is used to update the style for an individual feature, which is useful for highlighting a feature (e.g., on click or mouseover), while the second one is useful for resetting the style to the default (e.g. to clear the highlight).
Example
Here's a motivating example that demonstrates all of the new features.
m = ipyleaflet.Map()
layer = ipyleaflet.VectorTileLayer(
url=url_data, # My vector tile layer
interactive=True, # New interactive option
max_native_zoom=13,
max_zoom=20,
renderer_factory='svg', # New renderer_factory option. Defaults to 'svg'
vector_tile_layer_styles=jStyles, # javascript function given as a string
get_feature_id = 'label', # New get_feature_id option. Here, 'label' is the name of the (numeric)
# attribute in my layer that uniquely identifies each feature.
)
m.add(layer)
layer._selected = None
info_title = "<h4>Field info</h4>"
info_default_value = "Hover over a field"
info_widget = widgets.HTML(value=info_title + info_default_value)
highlight_style = {
"weight": 5,
"color": '#666',
"dashArray": '',
"fillOpacity": 0.7,
"fill": True
}
def highlight_feature(**kwargs):
if ("properties" in kwargs):
properties = kwargs["properties"]
options = kwargs["options"]
feature_id = properties["label"]
fill_color = options["fillColor"]
highlight_style["fillColor"] = fill_color
layer._selected = feature_id
layer.set_feature_style(
id=feature_id,
layer_style=highlight_style,
)
info_html = info_title
for k,v in properties.items():
info_html += "<b>"+ k + "</b>" + ": " + str(v) + "<br />"
info_widget.value = info_html
def clear_highlight(**kwargs):
if layer._selected:
layer.reset_feature_style(layer._selected)
info_widget.value = info_title + info_default_value
layer.on_mouseover(highlight_feature)
layer.on_mouseout(clear_highlight)
widget_control = ipyleaflet.WidgetControl(widget=info_widget, position='topright')
m.add(widget_control)
m