Skip to content
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

Merged
merged 18 commits into from
Sep 23, 2016
Merged

Add event propagation system to Evented #3244

merged 18 commits into from
Sep 23, 2016

Conversation

lucaswoj
Copy link
Contributor

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...

  • adds a Evented#setEventedParent method which propagates events
  • uses Evented#setEventedParent to eliminate repetitive binding / unbinding of _forward*Event methods
  • uses Evented#setEventedParent allow event names to remain constant from Evented#fire to Map listeners, making it easier to add new events and follow the path of existing events
  • improves test coverage of Evented
  • eliminates the ability to call Evented#off with less than two arguments, removing all listeners (this could break GL JS core)
  • eliminates lines of code

I'm still not 💯 on the name Evented#setEventedParent. Any other ideas?

cc @jfirebaugh @mourner @mollymerp @lbud @mapsam

Launch Checklist

  • briefly describe the changes in this PR
  • write tests for all new functionality
  • document any changes to public APIs
  • post benchmark scores
  • manually test the debug page

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

@jfirebaugh
Copy link
Contributor

This looks great. We can apply these ideas to mapbox/mapbox-gl-native#6383 as well.

I'm still not 💯 on the name Evented#setEventedParent. Any other ideas?

I think it's fine, but if you are looking for something more descriptive, I'd suggest setParentForEventBubbling.

@@ -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'));
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Member

@mourner mourner left a 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}});
Copy link
Member

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: ...}?

Copy link
Contributor Author

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 StyeLayers 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);
Copy link
Member

@mourner mourner Sep 23, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intentionally remove binds 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.

Copy link
Contributor Author

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.

@lucaswoj
Copy link
Contributor Author

Glad to hear this is in line with what we've done in other projects! Excited to 🚢 and keep digging on #1715

@lucaswoj lucaswoj merged commit 24f2135 into master Sep 23, 2016
@lucaswoj lucaswoj deleted the datastart branch September 23, 2016 16:27
captainbarbosa pushed a commit that referenced this pull request Oct 3, 2016
* 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants