[Feature] Promise based camera movement and concurrent calls handling

#17 · closed · 1 comments

View on GitHub ↗

xwkya

**Is your feature request related to a problem? Please describe.** I recently started using it to showcase a network, and certain buttons trigger an animation. If we need to perform actions on Animation end, it's unreliable to start timeout with durationMs delay as the `cameraPosition()` call can get overridden by another call (user pressing another button). Hence we would be performing the promise resolution of the first `cameraPosition()` call without it being resolved in the end. **Describe the solution you'd like** I have fixed this locally by wrapping camera position inside a Promise based framework with a token generated for each call. - When call occurs to `cameraMovementWrapper`, a token is generated and stored in a state and a `cameraPosition` call occurs. We create a promise, store its reference in the component and return it. - A recursive resolution is called with a loop on animation frames inside the Promise body. If the camera is close to its final position , transition period expired or the associated token does not match the stored token inside the component, the Promise is resolved. We resolve with success if the token matches at Resolution time and reject if token does not match. - From the user perspective, we get a promise resolution and can call subsequent actions or the promise chain is broken and error can be caught. **Note** Let me know if you're interested and accepting contributions. I can submit a PR with the solution you prefer. **Describe alternatives you've considered** Modifying this library, we can use a resolution on the Tween completion, and maybe use a token based approach to camera movement requests and break the promise if another request is performed. **Additional context** Sample code (I work with force-graph-3d) ``` function moveCameraWithPromise(graph, pos, lookAt, transitionMs, token, tolerance = 2) { graph.cameraPosition(pos, lookAt, transitionMs); const startTime = performance.now(); return new Promise((resolve, reject) => { const check = () => { // Invalidate if a new camera action has been requested. if (token !== cameraAnimationTokenRef.current) { reject(new Error('Cancelled')); return; } const elapsed = performance.now() - startTime; const camPos = graph.camera().position; const dx = camPos.x - pos.x; const dy = camPos.y - pos.y; const dz = camPos.z - pos.z; const distance = Math.sqrt(dx * dx + dy * dy + dz * dz); if (distance < tolerance || elapsed >= transitionMs) { resolve(); } else { requestAnimationFrame(check); } }; requestAnimationFrame(check); }); } ```

Comments

vasturiano

@xwkya thanks for reaching out. In order to avoid adding too much complexity in this module, I would suggest that you can achieve the same thing on your app side. You don't need to call `cameraPosition` with a timed animation. You can run your own tween and have this promise system all in your app side. At every tick of the tween you simply invoke `cameraPosition` with `0` transition time (the default), which effectively disables the animation and moves the camera immediately to the final position.