mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(awareness): follow a gesture to its last contact, and drop it on blur
Lifting one finger of a pinch removed the document listeners, so the remaining finger's drag, which Cesium carries on with, stopped counting. A gesture now ends only when its last pointer lifts or no touches are left. And a gesture whose end never reaches the page (the window loses focus mid-drag, or the page is hidden) left the listeners attached, so a later unrelated drag counted as camera input; a blur or hidden page now stops following it and drops its pending input.
This commit is contained in:
1 parent
de634952ec
commit
02a6739466
3 files changed
+105
-1
No files matched your search
@@ -706,6 +706,89 @@ test('a long drag or touch keeps the pulses awake after it leaves the canvas', (
|
||||
assert.equal(ring.state.lastCameraInputMs, noted);
|
||||
});
|
||||
|
||||
test('lifting one finger of a pinch leaves the other finger counting', (t) => {
|
||||
const ring = ringRendering(t);
|
||||
const { inputWakeMs } = AWARENESS_RANGE_PULSE;
|
||||
const { dispatch, pan, pulsing, loop } = inputLifecycle(t, ring);
|
||||
const onDocument = (type, init = {}) =>
|
||||
document.dispatchEvent(Object.assign(new Event(type), init));
|
||||
// Cesium carries on with a one-finger drag after the other lifts.
|
||||
const dragOn = (move, init) => {
|
||||
for (let ms = 0; ms < inputWakeMs + 1000; ms += 250) {
|
||||
loop.advance(250);
|
||||
onDocument(move, init);
|
||||
}
|
||||
pan();
|
||||
return pulsing();
|
||||
};
|
||||
// Without pointer events: the touch list says who is still down.
|
||||
dispatch('touchstart');
|
||||
onDocument('touchend', { touches: [{}] });
|
||||
assert.equal(dragOn('touchmove', {}), true, 'touch: one finger left');
|
||||
onDocument('touchend', { touches: [] });
|
||||
assert.equal(dragOn('touchmove', {}), false, 'touch: all lifted');
|
||||
// With pointer events: each contact has its own pointer id.
|
||||
dispatch('pointerdown', { pointerId: 1 });
|
||||
dispatch('pointerdown', { pointerId: 2 });
|
||||
onDocument('pointerup', { pointerId: 1 });
|
||||
const drag = { pointerId: 2, buttons: 1 };
|
||||
assert.equal(dragOn('pointermove', drag), true, 'pointer: one left');
|
||||
onDocument('pointercancel', { pointerId: 2 });
|
||||
assert.equal(dragOn('pointermove', drag), false, 'pointer: all lifted');
|
||||
});
|
||||
|
||||
test('a gesture lost to a window blur or a hidden page stops counting', (t) => {
|
||||
const ring = ringRendering(t);
|
||||
const { inputWakeMs } = AWARENESS_RANGE_PULSE;
|
||||
const { dispatch, pan, pulsing, loop } = inputLifecycle(t, ring);
|
||||
const visibility = Object.getOwnPropertyDescriptor(
|
||||
document,
|
||||
'visibilityState',
|
||||
);
|
||||
t.after(() => {
|
||||
if (visibility)
|
||||
Object.defineProperty(document, 'visibilityState', visibility);
|
||||
else delete document.visibilityState;
|
||||
});
|
||||
const setVisibility = (value) =>
|
||||
Object.defineProperty(document, 'visibilityState', {
|
||||
configurable: true,
|
||||
get: () => value,
|
||||
});
|
||||
for (const [name, lose] of [
|
||||
['blur', () => window.dispatchEvent(new Event('blur'))],
|
||||
[
|
||||
'hidden',
|
||||
() => {
|
||||
setVisibility('hidden');
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
setVisibility('visible');
|
||||
},
|
||||
],
|
||||
]) {
|
||||
// The release happens outside the window, so no end ever arrives.
|
||||
dispatch('pointerdown', { pointerId: 1 });
|
||||
lose();
|
||||
pan();
|
||||
assert.equal(pulsing(), false, `${name}: pending input dropped`);
|
||||
loop.advance(inputWakeMs + 100);
|
||||
const noted = ring.state.lastCameraInputMs;
|
||||
document.dispatchEvent(
|
||||
Object.assign(new Event('pointermove'), { pointerId: 1, buttons: 1 }),
|
||||
);
|
||||
assert.equal(ring.state.lastCameraInputMs, noted, `${name}: no follow`);
|
||||
}
|
||||
// A page coming back into view is no reason to drop a gesture.
|
||||
dispatch('pointerdown', { pointerId: 1 });
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
loop.advance(inputWakeMs + 100);
|
||||
document.dispatchEvent(
|
||||
Object.assign(new Event('pointermove'), { pointerId: 1, buttons: 1 }),
|
||||
);
|
||||
pan();
|
||||
assert.equal(pulsing(), true, 'visible: still following');
|
||||
});
|
||||
|
||||
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