Our libraries react-map-gl and deck.gl both use Mapbox GL as a controlled React component. All viewport states are synced with a data store. Currently there is no event that is:
As a result, we have been implementing our own mouse/touch interaction in order to use Mapbox in a React/Redux paradigm. It would be nice if there is an event that we can subscribe to to dispatch requests for camera change.
We typically use the move event for things like this. Can you elaborate on why you need a similar event rendered before the map render?
@mourner I think I've heard mention of some cases in which the map moves but a move event isn't fired. These should be considered bugs and fixed. I believe this would eliminate the need for any new events.
Hopefully @Pessimistress can help us understand if my understanding is correct and what the situations are when we don't fire move.
@mourner @lucaswoj
My understanding is that move only gets fired when map center changes, not on zoom/rotate
More importantly: we use React/Redux to build applications on top of Mapbox. The Redux state container is the single source of truth for all app states, which we bind the Mapbox camera to. Otherwise we risk the map going out of sync with the overlays and other UI components. It means that the order of events is like:
move event firedBasically, I'm wishing for the ability to use a state manager that is external to Mapbox. This is critical to our tech stack as it allows us to manage the increasing complexity of our mapping applications.
The move event is fired for any camera mutation, not just when the map center changes.
There are a number of camera improvements coming in #2801 that will help your use case.
I think the key problem here is with syncing the render of two seperate components and most noticeable when the frame rate is low. If we just listen for "move" I think by that time, Mapbox has already done a render. I'll be digging into this more but if anyone else has any ideas, let me know!
I think the key here is react-map-gl was designed to be a Controlled Component, where React state holds the single source of truth. If we start subscribing to the move event after the change happens, then we are switching to an Uncontrolled Component, where Mapbox is the single source of truth.
The latter will likely break many of our use cases since you can no longer (reliably) control the viewport by updating the Redux store.
That's true but I don't think this is unique to react-map-gl. I would expect it to be a problem for any third party library wanting to stay in sync with mapboxGL
Maybe the best way forward would be suggest a couple of possible solutions @Pessimistress.
@lucaswoj there is no harm cleaning up the API, but I don't think it solves the issue presented by @Pessimistress. The reliability of move is a minor concern compared with the need to completely re-implement the user interaction logic when CameraOptions are externally controlled.
Before I go on, just to note that the 2 libraries in question have almost 5,000 stars combined. Sorry, not trying to be a pain, but just saying they represent a large user base. At the moment all user interaction for these libraries is left completely up to them (out of Mapbox's control).
__Solution 1__
Add a new event called beforeUserMove or even shouldUserMove that receives the translated CameraOptions object and accepts a return indicating if the library should execute the user input (i.e. update the matrix transforms). This would solve @Pessimistress's libraries major architectural issues and also provide more advanced maxBounds restrictions for other users. If that isn't possible due to issues with your eventing system, maybe solution 2...
__Solution 2__
Add an additional property to MapOptions that indicates if user actions should be executed, maybe interactiveExecuted. In this case the events described above would still be sent, but no action would be taken regardless of return.
Obviously in both cases, userland would then take the CameraOptions object and (in most cases) call your new setCamera function to update the camera.
Separating the command for camera movement from execution may require some dev/testing but it seems now is the time do it with all the other work going on in the camera class...
Thanks for articulating this pain point / use case. I definitely like the idea of decoupling the handling of user input from the consequent changes to the camera state. In terms of internal architecture, I think this is already very likely going to be a by-product of the refactor that @lucaswoj mentioned (#2801).
Once that work starts getting closer to complete, we'll be in a better position to design in detail the ideal API by which client code can subscribe to user actions that (attempt to) change the camera state.
If we just listen for "move" I think by that time, Mapbox has already done a render.
Noting here that this syncing issue should now be resolved via https://github.com/mapbox/mapbox-gl-js/pull/5743 and https://github.com/mapbox/mapbox-gl-js/pull/6005 (and some similar follow-ups).
The broader issue of decoupling interaction handling from state updates remains.
Most helpful comment
Thanks for articulating this pain point / use case. I definitely like the idea of decoupling the handling of user input from the consequent changes to the camera state. In terms of internal architecture, I think this is already very likely going to be a by-product of the refactor that @lucaswoj mentioned (#2801).
Once that work starts getting closer to complete, we'll be in a better position to design in detail the ideal API by which client code can subscribe to user actions that (attempt to) change the camera state.