-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Move event management from deckgl.js React component into LayerManager. #708
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
Conversation
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 really like the direction this is taking.
Some comments mostly to make sure we have considered various design options.
Once this is done, I think it would be very easy to create a non-react based example using deck.gl, just using basic JavaScript setting up the LayerManager
and EventManager
and a luma.gl AnimationLoop
src/lib/layer-manager.js
Outdated
return this; | ||
} | ||
|
||
addEventListeners(eventNames) { |
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 am wondering if we should keep the event registration outside of the LayerManager
, so that the user could use some other event generation.
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.
Hm...so then EventManager
or an equivalent would be passed into LayerManager
? This feels a bit heavy, though I can see how it may improve extensibility for event handling. I wonder though how useful that flexibility is, given it would slightly increase complexity of the API.
We could make it an optional param and assume most people will use the default, which we would set to EventManager
. Is that what you're thinking?
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.
Hm...so then EventManager or an equivalent would be passed into LayerManager?
I had a different model in mind. The external event handling would be independent and just call layerManager.onClick
and layerManager.onPointerMove
when events occurred to get help with picking and delivering the resulting infos to the deck.gl callback system in the right way. Admittedly, I haven't thought it through completely.
src/lib/layer-manager.js
Outdated
* with any picking info generated by `pickLayer`. | ||
*/ | ||
_onClick(event) { | ||
const pos = getPos(event); |
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.
So the main thing the user needs to specify is how to extract the position from the event. The rest of the logic here is independent of event handling system, right?
So exploring the idea of keeping event registration separate, we could potentially move out the event registration, keep these functions in here (maybe removing the _
underscore prefixes) so that the can be called by the external event handlers, and add a getPositition
argument to the LayerManager
constructor ?
src/lib/layer-manager.js
Outdated
const radius = this.pickingRadius; | ||
const selectedInfos = this.pickLayer({x: pos.x, y: pos.y, radius, mode: 'click'}); | ||
if (selectedInfos.length) { | ||
const firstInfo = selectedInfos.find(info => info.index >= 0); |
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.
Should we just have a function pickTopLayer
so we can drop the find
here? @Pessimistress
src/lib/layer-manager.js
Outdated
/** | ||
* Get mouse position {x, y} relative to the container | ||
*/ | ||
function getPos(event) { |
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.
Abbreviated names are typically avoided in this code base: getPos
=> getPosition
src/lib/layer-manager.js
Outdated
return null; | ||
} | ||
|
||
const rect = rootElement.getBoundingClientRect(); |
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 am not an expert on these things, but folks who seem to be have advised me in the past to avoid calling getBoundingClientRect
on any regular basis, as it can trigger an expensive reflow in the browser.
My understanding was that events have offsetX
and offsetY
or similar parameters that contain relative coordinates so that this can be handled in a more lightweight fashion.
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 wrote a comment here earlier today and GH seems to have swallowed it.
IIRC I suggested we use rootElement.offsetLeft
/Top
instead of getBoundingClientRect()
to avoid reflows. @Pessimistress what's the use case here, was this logic added to handle the fact that touch events don't have clientX
/Y
or to handle situations in which the canvas
doesn't fill the viewport?
src/react/deckgl.js
Outdated
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
this._setLayerManagerProps(nextProps); |
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.
Feels a little misleading since LayerManager
is a traditional JS class and doesn't really have props. Just call it _updateLayerManager
?
src/lib/layer-manager.js
Outdated
// TODO | ||
} | ||
|
||
validateEventHandling() { |
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.
While I understand why you put this here, I'm a little torn about it. Can this be moved "deeper" into the layer manager life cycle?
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 -- after I wrote this I realized I needed to store onLayerClick
and onLayerHover
somewhere that LayerManager
could get at them. That means now that all this logic can live within LayerManager
instead of straddling across deckgl.js
as well.
src/react/deckgl.js
Outdated
|
||
// Note: avoid React setState due GL animation loop / setState timing issue | ||
this.layerManager = new LayerManager({gl}); | ||
this.layerManager = new LayerManager({gl, canvas}); |
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.
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.
There's no change here in the way we're using canvas
, just passing it along to LayerManager
for EventManager
event registration. Is there some caveat we're not covering here (hence the link)?
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.
The link was just to show that canvas
is already available as a member on the gl
context that we are already passing as a parameter, so it might be unnecessary to add the canvas
parameter.
But perhaps we want to handle the case where the event canvas is different from the canvas that the context was created on.
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 was thinking that the DOM element handling events should not be coupled with the gl context. If event handling exists in its own module, alongside LayerManager (instead of within it), this will be moot anyway (it will accept an arbitrary DOM element just like EventManager does).
Begin to remove drag event handling. Remove unused event handler props from webgl-renderer.js.
…ct deck.gl component and LayerManager. This enables a non-react app to opt into event handling. This commit is a quick pass for exposition and needs cleanup + tests.
5bc59c4
to
b177245
Compare
The diff is a little weird now due to @Pessimistress' PR and my rebasing onto it. |
src/lib/layer-event-manager.js
Outdated
// but do so in a way that doesn't cause reflow (e.g. `offsetWidth/Height`). | ||
// maybe the event object offers offsetCenter as a 0<>1 value as well? | ||
// since it's already doing size calculations... | ||
const {width, height} = this.layerManager.context.viewport; |
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.
Right or wrong, my expectation was that this file would contain code that was unique to doing event integration with the EventManager.
The code in _onPointerMode and _onClick (with the exception of the refernece to oevent.offsetCenter
) line like it would be identical for any event system integration, and so might be better to keep inside LayerManager.
Thus
_onPointerMove(event) {
this.layerManager.onPointerMode({event, pos: event.offsetCenter});
}
Doing it like this woud also mean that this class wouldn't need to rake for the LayerManager
s internal state like the context.viewport
.
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.
Makes sense, will do.
src/lib/layer-event-manager.js
Outdated
|
||
set(options = {}) { | ||
Object.keys(DEFAULT_OPTIONS).forEach(k => { | ||
this.options[k] = options[k] !== 'undefined' ? options[k] : DEFAULT_OPTIONS[k]; |
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.
undefined
?
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.
crap, good catch.
@ibgreen and I discussed where to draw the lines between modules here. Currently (before this PR):
A cleaner implementation of all of this would involve:
In this scenario, I'll rework this PR a bit further toward this goal, but will refrain from lifting per-layer callbacks out of |
Is the latest luma.gl still registering its own event handlers? If so, why are we not using those? |
luma.gl has a legacy system for registering event handlers, an optional Due to the complexity of the event handling topic and the fact that we already have two repos in play I have intentionally kept luma.gl event handling out of the discussions. A problem with the |
@Pessimistress we replaced a luma |
Adopt to new luma state management api.
Begin to remove drag event handling. Remove unused event handler props from webgl-renderer.js.
…ct deck.gl component and LayerManager. This enables a non-react app to opt into event handling. This commit is a quick pass for exposition and needs cleanup + tests.
…o events-in-layer-manager
Move all input event handling logic into LayerManager.
@ibgreen here's a diff for the state of this PR as of the latest push, rebased onto master. This commit does away with LayerEventManager and instead leaves layer event handling in control of LayerManager. In the interest of closing this PR, I stopped short of fixing the picking-on-every-event bug (#634), since it will require adding/removing handlers to/from EventManager every time new top-level handlers are passed to For the same reason, I'm also leaving for another PR the work to pull the per-layer handler calls out of |
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.
@ericsoco Great work for the PR.
Since this PR actually introduced some complicated merge actions between various branches, could you close this PR and open a new one? I have cherry-picked your commits to the new branch events-in-layer-manager2
based on latest master
.
Closing in favor of #738. |
*** * * DO NOT MERGE, WIP * * ***
This PR tackles the EventManager followup items in #656. Among its goals:
More to come.