mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
fix(camera): hold the globe recovery while a pointer is down
Holding a drag still for half a second on a view that already showed no surface looked like a camera at rest, so the recovery turned the view down under the user's hand. The recovery now defers while a pointer pressed on the canvas is held, and runs once it is released, as for a flight or a playing scene.
This commit is contained in:
1 parent
a20076fc5e
commit
44106b2bfb
3 files changed
+61
-8
No files matched your search
@@ -103,8 +103,9 @@ zoom-out guard above keeps wheel and pinch zoom-outs in view; this catches the
|
|||||||
other ways a move can end looking away, such as a saved or shared view that did.
|
other ways a move can end looking away, such as a saved or shared view that did.
|
||||||
Views with more surface than that, such as the oblique orbital Director shots,
|
Views with more surface than that, such as the oblique orbital Director shots,
|
||||||
are left as they are, and so are tracked or locked cameras, a camera flight in
|
are left as they are, and so are tracked or locked cameras, a camera flight in
|
||||||
progress, a Director scene while it plays (holds included) and the 2D and
|
progress, a Director scene while it plays (holds included), a pointer held
|
||||||
Columbus modes; a check a flight or scene defers runs once it ends. A Director
|
down on the globe (a drag held still) and the 2D and Columbus modes; a check a
|
||||||
|
flight, scene or held pointer defers runs once it ends. A Director
|
||||||
shot loaded or replayed outside a run is not a playing scene. A view that loses
|
shot loaded or replayed outside a run is not a playing scene. A view that loses
|
||||||
its surface without a camera move (a resize, or turning the scope on) is left as
|
its surface without a camera move (a resize, or turning the scope on) is left as
|
||||||
it is until the next move. A voice turn requested while the camera is tracked is
|
it is until the next move. A voice turn requested while the camera is tracked is
|
||||||
|
|||||||
@@ -778,6 +778,39 @@ test('a check a scene or flight defers runs once it ends', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Holding a drag still for half a second on a view that already showed no
|
||||||
|
// surface looked like a settled camera, and the view was turned down under
|
||||||
|
// the user's hand.
|
||||||
|
test('the recovery waits while a pointer is held on the globe', () => {
|
||||||
|
const timers = fakeTimers();
|
||||||
|
const { camera, scene, viewer } = realCamera({ width: 1225, height: 923 });
|
||||||
|
const document = new EventTarget();
|
||||||
|
scene.canvas = Object.assign(new EventTarget(), {
|
||||||
|
clientWidth: 1225,
|
||||||
|
clientHeight: 923,
|
||||||
|
ownerDocument: document,
|
||||||
|
});
|
||||||
|
const dispose = installGlobeInViewRecovery(viewer, timers);
|
||||||
|
aim(camera, reportedStuckView);
|
||||||
|
scene.canvas.dispatchEvent(new Event('pointerdown'));
|
||||||
|
camera.moveStart.raiseEvent();
|
||||||
|
for (let i = 0; i < 8; i += 1) timers.tick();
|
||||||
|
camera.moveEnd.raiseEvent();
|
||||||
|
for (let i = 0; i < 8; i += 1) timers.tick();
|
||||||
|
assert.equal(globeOutOfFrame(camera), true, 'left alone while held');
|
||||||
|
document.dispatchEvent(new Event('pointerup'));
|
||||||
|
for (let i = 0; i < 3; i += 1) timers.tick();
|
||||||
|
assert.ok(
|
||||||
|
Cesium.Math.equalsEpsilon(camera.pitch, -Math.PI / 2, 1e-6),
|
||||||
|
'recovered once the pointer is released',
|
||||||
|
);
|
||||||
|
dispose();
|
||||||
|
aim(camera, reportedStuckView);
|
||||||
|
scene.canvas.dispatchEvent(new Event('pointerdown'));
|
||||||
|
document.dispatchEvent(new Event('pointerup'));
|
||||||
|
assert.equal(timers.pending(), 0, 'disposed recovery holds no listeners');
|
||||||
|
});
|
||||||
|
|
||||||
function fakeTimers() {
|
function fakeTimers() {
|
||||||
let next = 1;
|
let next = 1;
|
||||||
const pending = new Map();
|
const pending = new Map();
|
||||||
|
|||||||
+25
-6
@@ -172,9 +172,10 @@ const SETTLE_GIVE_UP_MS = 5 * 60_000;
|
|||||||
* catches a saved or shared view that looked away, or any other move that ends
|
* catches a saved or shared view that looked away, or any other move that ends
|
||||||
* looking away from the planet.
|
* looking away from the planet.
|
||||||
* Heading and position are kept. Tracked cameras, locked ones (non-identity
|
* Heading and position are kept. Tracked cameras, locked ones (non-identity
|
||||||
* transform), a camera flight in progress, the 2D and Columbus modes, and any
|
* transform), a camera flight in progress, a pointer held down on the canvas
|
||||||
* time `paused` returns true (an authored scene playing) are left alone; a
|
* (a drag held still), the 2D and Columbus modes, and any time `paused`
|
||||||
* check they defer runs once they end, however long they last.
|
* returns true (an authored scene playing) are left alone; a check they defer
|
||||||
|
* runs once they end, however long they last.
|
||||||
* `keyholeRadius`
|
* `keyholeRadius`
|
||||||
* returns the radius of the visible circle when a scope mask hides the rest of
|
* returns the radius of the visible circle when a scope mask hides the rest of
|
||||||
* the frame (see `globeFrameShare`), or 0; it is read at every check.
|
* the frame (see `globeFrameShare`), or 0; it is read at every check.
|
||||||
@@ -205,12 +206,27 @@ export function installGlobeInViewRecovery(
|
|||||||
if (!scene || !camera?.moveEnd || !camera?.moveStart)
|
if (!scene || !camera?.moveEnd || !camera?.moveStart)
|
||||||
throw new TypeError('A complete Cesium viewer is required');
|
throw new TypeError('A complete Cesium viewer is required');
|
||||||
|
|
||||||
// Returns false while a flight or a paused scene defers the check, so the
|
// A pointer held on the globe is a gesture in progress, even when it holds
|
||||||
// caller can try again once it ends.
|
// still for half a second: the check waits for its release.
|
||||||
|
const canvas = scene.canvas;
|
||||||
|
const releaseTarget = canvas?.ownerDocument ?? canvas;
|
||||||
|
let pointerHeld = false;
|
||||||
|
const onPointerDown = () => {
|
||||||
|
pointerHeld = true;
|
||||||
|
};
|
||||||
|
const onPointerUp = () => {
|
||||||
|
pointerHeld = false;
|
||||||
|
};
|
||||||
|
canvas?.addEventListener?.('pointerdown', onPointerDown);
|
||||||
|
releaseTarget?.addEventListener?.('pointerup', onPointerUp);
|
||||||
|
releaseTarget?.addEventListener?.('pointercancel', onPointerUp);
|
||||||
|
|
||||||
|
// Returns false while a flight, a paused scene or a held pointer defers the
|
||||||
|
// check, so the caller can try again once it ends.
|
||||||
const recover = () => {
|
const recover = () => {
|
||||||
if (!isFreeGlobeCamera(viewer)) return true;
|
if (!isFreeGlobeCamera(viewer)) return true;
|
||||||
// Cesium has no public running-flight flag.
|
// Cesium has no public running-flight flag.
|
||||||
if (camera._currentFlight || paused()) return false;
|
if (camera._currentFlight || paused() || pointerHeld) return false;
|
||||||
const height = camera.positionCartographic?.height;
|
const height = camera.positionCartographic?.height;
|
||||||
if (
|
if (
|
||||||
!(height > minHeight) ||
|
!(height > minHeight) ||
|
||||||
@@ -294,6 +310,9 @@ export function installGlobeInViewRecovery(
|
|||||||
stopSettling();
|
stopSettling();
|
||||||
removeMoveEnd();
|
removeMoveEnd();
|
||||||
removeMoveStart();
|
removeMoveStart();
|
||||||
|
canvas?.removeEventListener?.('pointerdown', onPointerDown);
|
||||||
|
releaseTarget?.removeEventListener?.('pointerup', onPointerUp);
|
||||||
|
releaseTarget?.removeEventListener?.('pointercancel', onPointerUp);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user