-
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
Synchronous redraw API #7893
Comments
does https://docs.mapbox.com/mapbox-gl-js/api/#map#triggerrepaint |
|
@Pessimistress would exposing the |
We need to both call |
@Pessimistress yeah, I updated the comment — should we add the logic of clearing the frame if there's no ongoing animation to (potentially renamed) |
Yeah that makes sense. Though I figure the naming of |
@Pessimistress yeah, maybe something like |
@Pessimistress would this be used for instantly jumping to a single new location or also animating a movement to a new location? Also, what would be deciding when frames are rendered? Would there be an animation loop outside of mapbox-gl that uses |
@ansis timing will be managed by React's component life cycle, on componentDidUpdate |
I'm not that familiar with React so please correct me if I'm getting something wrong. React's component life cycle appears to not to use Would it be an option to have all the components that need to be synced with the map live in a separate react tree and have updates to those components be set after the map renders a frame? I think just adding a synchronous render method wouldn't fix the underlying problem because you could still end up with multiple map renders for each browser repaint. |
The root issue is that both React and Mapbox's render cycles are asynchronous. If we update component states on a On a high level, when we are developing a React application, React is the source of truth for all app states, and the React clock should be driving all rerenders caused by app state change. In the context of mapbox, when the canvas is resized and/or the camera position is changed, the React root tells all child components when to update, not the other way around. In your proposal, imagine if more than one sub-component require to be informed of an update before everyone else. They can kick off an infinite update loop that never ends. With that said - It is only a description of why this API would solve our problem. I can understand your concern that such an API may get abused by the user and affect performance. |
Thanks for the explanation! I'm wondering if a render() {
return ReactDOM.createPortal(this.props.children, this.mapboxmarker.getElement());
} This example uses mapboxgl markers but something similar could be implemented for react so that it works without mapbox maps. The positioning of containers would happen synchronously with respect to the map. The rendering of the markers within the containers would happen synchronously with respect to react. This would allow the webgl rendering to be synced with browser repaints instead of react renders and could avoid unnecessary rendering. Side note: I looked into the spec and it looks like animation frames should always be run just before a repaint. This should mean that triggering a repaint would update the map before the dom element changes are visible. But I'm guessing browsers don't follow that exactly and maybe break that sometimes :( https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model |
Yes, portals might fix the rendering, though other issues would surface (e.g. React's event handling do not mix well with native event listeners). I've been working on the React wrapper for over two years now. Many of mapbox-gl's APIs are incompatible with the pure reactive pattern that we are after, as illustrated in this old issue. Being able to manage map states and control render cycles outside of the Map component is essential to a lot of our applications. Another example would be rendering two maps side by side and synchronize their cameras, which you cannot do with mapbox's native API. We have also built a lot more components than just marker, especially DeckGL. Admittedly some of the implementation decisions are legacy and could be revisited, but some are with good reason. I suspect either way there needs to be a lot of patching and hacking. |
@Pessimistress thanks for all the feedback and explanations! They were very helpful for me. We'll add a synchronous render method. |
This option allows the user to implement `requestAnimationFrame` and `cancelAnimationFrame` in order to synchronize map rendering with their external rendering. fix #7893
@Pessimistress I'm finally getting around to implementing this. An idea that popped up internally was to expose this functionality by letting users implement their own The main advantages of this approach seemed to be that:
It is more complicated that a Thanks! |
I prefer I observed something weird with the above hack. Although |
This uses an undocumented method to trigger a synchronous redraw instead of using the standard schedule from Mapbox. The CSS previously used to make the OL and MB views match is not necessary anymore. Reference: mapbox/mapbox-gl-js#7893 (comment)
This uses an undocumented method to trigger a synchronous redraw instead of using the standard schedule from Mapbox. The CSS previously used to make the OL and MB views match is not necessary anymore. Reference: mapbox/mapbox-gl-js#7893 (comment)
I believe we also require a synchronous solution to implement this feature https://stackoverflow.com/questions/60803985/how-to-synchronously-update-mapbox-gl-style The proposed implementation above did not work. |
Hi there, "icon-image": { "stops": [[4, "Capital"], [9, ""]] },
"text-font": [
"step",
["zoom"],
["literal", ["noto sans"]],
9,
["literal", ["noto sans bold"]]
],
"text-field": "{name}" Which make the map show both icon and text before zoom 9 for a specific poi. And start from zoom9 hide icon and show bold text. When current zoom is 8, we use jumpTo and _render to zoom 9, all these works., icon will disappear and text become bold. But when current zoom is 9, and use jumpTo and _render change to zoom 8, the map will not update, icon not appear and font weight still keep bold. And it need another trigger (like move or even call jumpTo with same properties again), map will change, icon will disappear and font weight become normal. |
Did this ever get implemented? Couldn't find any documentation for it, looks like others are finding this webpage in search of it |
Motivation
In react-map-gl, when the viewport updates, we call
Map.jumpTo()
insidecomponentDidUpdate()
, which schedules a Mapbox rerender in the next animation frame. This causes the canvas rerender to always occur one step behind the React updates.You can see this issue in visgl/react-map-gl#720 and visgl/deck.gl#2458.
Design
Provide a synchronous API e.g.
redraw()
that immediately flushes the dirty state.Implementation
Here's how we are currently forcing rerender:
Private methods and properties are manipulated here, which is not a reliable solution.
The text was updated successfully, but these errors were encountered: