-
Notifications
You must be signed in to change notification settings - Fork 364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interactive vector tile layers #1213
Interactive vector tile layers #1213
Conversation
@martinRenou could you please suggest someone for review? |
Thanks! I'll have a look |
layer_styles: dict | ||
Style to apply to the feature | ||
""" | ||
self.send({"msg": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if this could be a traitlets property instead of a custom comm message?
Something like
feature_styles = Dict().tag(sync=True)
feature_styles
being the {id: layerStyle} dictionary?
Custom comm messages are transient and will not be saved in your widget model, resulting in many issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would that work in VectorTileLayer.ts
so that the this.obj.setFeatureStyle
is called when the python method is called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You would need to set a new value for feature_styles
Python side:
def set_feature_style(self, id:Int, layer_style:Dict):
self.feature_styles = {**feature_styles, id: layer_style}
Then you would listen for changes in the JavaScript side:
this.model.on("change:feature_styles", () => {
const feature_styles = this.model.get("feature_styles");
// You may need to reset all previous features styles here
// [...]
for (const id of Object.keys(feature_styles)) {
this.obj.setFeatureStyle(id, feature_styles[id]);
}
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll give it a try and make a new commit.
FYI I am also testing another commit with changes to how rendererFactory
, getFeatureId
, and vectorTileLayerStyles
are exposed in python, because I encountered an issue as follows:
- Create a vector tile layer with
renderer_factory='svg'
, which is a string. - In javascript, the
rendererFactory
is set to a functionL.svg.tile
. - Change the opacity in python.
- Move the map
- Error in javascript -- because renderer_factory is in sync with
rendererFactory
, it's now set to the stringsvg
, and it throws a javascript error that therendererFactory
is not a function.
The new change to avoid this issue is that in python, instead of rendererFactory
I will have a separate option called renderer
, which is used in javascript to create rendererFactory
. A similar strategy can be used for getFeatureId
and vectorTileLayerStyles
because they are constructed in javascript as functions, they shouldn't be in 'sync' with python.
I will aim to commit this change soon as well.
@lopezvoliver I was curious to run this example, but it seems I'm getting 404s on this https://planetarycomputer.microsoft.com url when LeafletJS tries to download the tiles. Is there anything particular to do to allow this example to work? |
I just checked and it should work as is. Are you able to access the following tile directly? This layer is only available until z=13, so the |
Here's a description of the recent five commits:
3, 4, and 5: Each of these commits is a decision to rename I will update the original PR comment to reflect these changes where needed. |
Ah right I was not using the main branch! Thanks for the clarification.
Is it ready for another review? Happy to make a release of your recent PRs after this one is merged |
Yes, it's ready for review. (Edit: I just pushed one last commit -- I figured out a way to keep
That would be great, thanks! |
|
||
def __init__(self, **kwargs): | ||
super(VectorTileLayer, self).__init__(**kwargs) | ||
# Backwards compatibility: allow vector_tile_layer_styles as input: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be backward compatible only at the layer creation.
I see three options here:
- should we really rename this property? If not we can keep
vector_tile_layer_styles
?
If yes: - we remain backward compatible and we'd need a Python setter too
@vector_tile_layer_styles.setter def set_vector_tile_layer_styles
- we remove backward compatibility and go with 0.20.0
I'd prefer one of the two first options
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went ahead with option 2: vector_tile_layer_styles
is backwards compatible, and it uses a setter that updates layer_styles
.
Regarding the ability to update styles after initialization -- this wasn't contemplated in #1206, so I also fixed this by adding a listener to layer_styles
.
Here's a demo of the new capabilities:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
The CI would deserve some love, let's do that separately |
Renderer factory
Vector tile layers can be rendered using either
L.canvas.tile
orL.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
option was added toVectorTileLayer
, which can be eithersvg
orcanvas
, with the new default beingsvg
.Here's an example using the
ms-buildings
from Microsoft Planetary Computer, with the new default (svg):And here's how it renders using
renderer='canvas'
:Interactivity
A new
interactive
option was added withFalse
as default, which enables the user to add listeners to the layer, which include information about the feature. Note that the defaultrenderer='svg'
option should be used for interactivity. For example: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
andreset_feature_style
methods. The javascript function is of the form:where
feat
is the feature, andidVar
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 originalgetFeatureId
documentation here).Updating styles
Two new methods for
VectorTileLayer
were added:set_feature_style
andreset_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.