mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
fix(awareness): keep a long drag or touch counting as camera input
Only canvas events refreshed the 1.5 s input window, and a touch only on touchstart. Cesium follows a drag that leaves the canvas at document level (in Firefox, and wherever there are no pointer events), so a long gesture kept moving the camera after the window closed, and the pulses rested mid-gesture. From a pointer or touch start on the canvas until its end or cancel, moves at document level now count too; the listeners go when the gesture ends or the layer detaches.
This commit is contained in:
1 parent
56a7cacbec
commit
de634952ec
3 files changed
+71
-1
No files matched your search
@@ -23,6 +23,36 @@ export function createLifecycle({
|
||||
if (event?.type === 'pointermove' && !event.buttons) return;
|
||||
if (!cameraInputsEnabled()) return;
|
||||
layerState.lastCameraInputMs = Date.now();
|
||||
if (event?.type === 'pointerdown' || event?.type === 'touchstart')
|
||||
followGesture(true);
|
||||
}
|
||||
|
||||
// A drag can leave the canvas, and Cesium follows it at document level
|
||||
// (in Firefox, and wherever there are no pointer events). So does this,
|
||||
// from a gesture's start on the canvas to its end, so a long gesture keeps
|
||||
// the input window open the whole way.
|
||||
const GESTURE_MOVE_EVENTS = ['pointermove', 'touchmove'];
|
||||
const GESTURE_END_EVENTS = [
|
||||
'pointerup',
|
||||
'pointercancel',
|
||||
'touchend',
|
||||
'touchcancel',
|
||||
];
|
||||
let followingGesture = false;
|
||||
|
||||
function followGesture(on) {
|
||||
if (followingGesture === on) return;
|
||||
followingGesture = on;
|
||||
const listen = on ? 'addEventListener' : 'removeEventListener';
|
||||
for (const type of GESTURE_MOVE_EVENTS)
|
||||
globalThis.document?.[listen]?.(type, noteCameraInput, { passive: true });
|
||||
for (const type of GESTURE_END_EVENTS)
|
||||
globalThis.document?.[listen]?.(type, endGesture, { passive: true });
|
||||
}
|
||||
|
||||
function endGesture(event) {
|
||||
noteCameraInput(event);
|
||||
followGesture(false);
|
||||
}
|
||||
|
||||
function cameraInputsEnabled() {
|
||||
@@ -160,6 +190,7 @@ export function createLifecycle({
|
||||
noteCameraInput,
|
||||
);
|
||||
layerState.cameraInputTarget = null;
|
||||
followGesture(false);
|
||||
}
|
||||
layerState.preRenderRemover?.();
|
||||
layerState.preRenderRemover = null;
|
||||
|
||||
@@ -667,6 +667,45 @@ test('input the camera controller ignores, as in the cockpit, does not wake the
|
||||
assert.equal(pulsing(), true, 'a drag after the cockpit');
|
||||
});
|
||||
|
||||
test('a long drag or touch keeps the pulses awake after it leaves the canvas', (t) => {
|
||||
const ring = ringRendering(t);
|
||||
const { inputWakeMs } = AWARENESS_RANGE_PULSE;
|
||||
const { dispatch, pan, pulsing, loop, lifecycle } = inputLifecycle(t, ring);
|
||||
const onDocument = (type, init = {}) =>
|
||||
document.dispatchEvent(Object.assign(new Event(type), init));
|
||||
// The gesture starts on the canvas and carries on past `inputWakeMs`
|
||||
// outside it, where Cesium still follows it at document level.
|
||||
const longGesture = (start, move, init) => {
|
||||
dispatch(start, init);
|
||||
for (let ms = 0; ms < inputWakeMs + 1000; ms += 250) {
|
||||
loop.advance(250);
|
||||
onDocument(move, init);
|
||||
}
|
||||
};
|
||||
for (const [start, move, end, init] of [
|
||||
['pointerdown', 'pointermove', 'pointerup', { buttons: 1 }],
|
||||
['touchstart', 'touchmove', 'touchend', {}],
|
||||
['touchstart', 'touchmove', 'touchcancel', {}],
|
||||
]) {
|
||||
longGesture(start, move, init);
|
||||
pan();
|
||||
assert.equal(pulsing(), true, `${move} outside the canvas`);
|
||||
// Once it ends, moves elsewhere are not handling the map.
|
||||
onDocument(end);
|
||||
loop.advance(inputWakeMs + 100);
|
||||
onDocument(move, init);
|
||||
pan();
|
||||
assert.equal(pulsing(), false, `${move} after ${end}`);
|
||||
}
|
||||
// Detaching mid-gesture drops the document listeners too.
|
||||
dispatch('pointerdown');
|
||||
lifecycle.detachRuntimeListeners();
|
||||
loop.advance(inputWakeMs + 100);
|
||||
const noted = ring.state.lastCameraInputMs;
|
||||
onDocument('pointermove', { buttons: 1 });
|
||||
assert.equal(ring.state.lastCameraInputMs, noted);
|
||||
});
|
||||
|
||||
test('disabling the layer tears the pulses down completely', (t) => {
|
||||
const ring = ringRendering(t);
|
||||
const { state, scene, rendering, motion, pulseFrames } = ring;
|
||||
|
||||
Reference in new issue
Block a user