-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Add event propagation system to Evented #3244
Conversation
This looks great. We can apply these ideas to mapbox/mapbox-gl-native#6383 as well.
I think it's fine, but if you are looking for something more descriptive, I'd suggest |
@@ -67,12 +62,12 @@ function Style(stylesheet, animationLoop, options) { | |||
|
|||
if (stylesheet.sprite) { | |||
this.sprite = new ImageSprite(stylesheet.sprite); | |||
this.sprite.on('load', this.fire.bind(this, 'change')); |
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.
Is there some other mechanism now for triggering a repaint when the sprite finishes loading?
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.
Yes. SpriteImage
fires a style.change
event which is propagated to Style
then Map
. The same flow occurs without this on
-> fire
interaction within Style.
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 looks great! I did the same thing in Leaflet some time ago, with addEventParent
and removeEventParent
methods, and it fit in really nicely. The only difference is that Leaflet needed the ability to have multiple event parents (hence add
instead of set
), and also ability to fire an event without propagation (so it's fire(type, data, propagate)
where propagate
can be false
), but these seem not to be necessary in GL JS. 👍
@@ -420,7 +399,7 @@ Style.prototype = util.inherit(Evented, { | |||
} | |||
this._validateLayer(layer); | |||
|
|||
layer.on('error', this._forwardLayerEvent); | |||
layer.setEventedParent(this, {layer: {id: layer.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.
Is it necessary to have nested {layer: {id: ...}
data for some compatibility reasons, or could we just have {layerId: ...}
?
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.
As this is a public event, I suspect that changing the structure would impact our users.
The intent behind this structure is to give us the flexibility to make StyeLayer
s part of the public API. Think of {id: ...}
as the public interface of StyleLayer
. 😅
I am working on adding custom layer types now, which bring these classes further into the public API.
this.on('move', this._update.bind(this, false)); | ||
this.on('zoom', this._update.bind(this, true)); | ||
this.on('move', this._update); | ||
this.on('zoom', this._update); |
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.
Did you intentionally remove bind
s here? They set the updateStyle
argument of _update
(e.g. so that move
doesn't trigger zoom recalc as far as I remember and zoom
does). Without bind
, updateStyle
will always be truthy because move
and zoom
pass event data to listeners.
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 was an oversight. I saw that _update
was bound to this
but did not appreciate the bound arguments. Reverting.
Glad to hear this is in line with what we've done in other projects! Excited to 🚢 and keep digging on #1715 |
* Minor refactoring of Evented * Refactor Evented tests * Add Evented#pipe * Fix flaky map test * Use Evented#pipe in SourceCache * Rename "Evented#pipe" to "Evented#forwardEvents" * Add "passes original 'target' to forwarded listeners" test * Use event forwarding for source -> style events * Use event forwarding for layer -> style events * Use event forwarding for sprite -> style events * Use event forwarding for all style -> map events * Get rid of typed error events * Replace "forwardEvents" with "setEventedParent" * Minor refactoring * Make Evented#setEventedParent private * Fix benchmarks * Eliminate remaining ImageSprite#load events * Fix removed bound arguments per PR comment #3244 (comment)
Adding a new
Map
event that needs to be fired from another class requires a lot of GL JS boilerplate. Before tackling #1715, I built an event propogation system that...Evented#setEventedParent
method which propagates eventsEvented#setEventedParent
to eliminate repetitive binding / unbinding of_forward*Event
methodsEvented#setEventedParent
allow event names to remain constant fromEvented#fire
toMap
listeners, making it easier to add new events and follow the path of existing eventsEvented
Evented#off
with less than two arguments, removing all listeners (this could break GL JS core)I'm still not 💯 on the name
Evented#setEventedParent
. Any other ideas?cc @jfirebaugh @mourner @mollymerp @lbud @mapsam
Launch Checklist
Benchmarks
map-load
master 594248c: 132 ms
datastart 102807b: 114 ms
style-load
master 594248c: 113 ms
datastart 102807b: 110 ms
buffer
master 594248c: 984 ms
datastart 102807b: 1,092 ms
fps
master 594248c: 60 fps
datastart 102807b: 60 fps
frame-duration
master 594248c: 8.1 ms, 1% > 16ms
datastart 102807b: 8 ms, 4% > 16ms
query-point
master 594248c: 1.15 ms
datastart 102807b: 1.23 ms
query-box
master 594248c: 92.81 ms
datastart 102807b: 92.15 ms
geojson-setdata-small
master 594248c: 15 ms
datastart 102807b: 13 ms
geojson-setdata-large
master 594248c: 131 ms
datastart 102807b: 133 ms