mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-10 21:32:23 +00:00
fix(cockpit): keep the orbital view on a double-click at a ground point
In the orbital view a double-click on a mapped ground point went on to Cesium's own double-click, which tracks the picked entity and so ended the view. The Cockpit's double-click routing now takes it in orbit: it keeps or starts the focus on that point (a point beyond the reach is left unfocused but still not tracked). A double-click anywhere else, one a tool owns, and every one outside orbit go on to Cesium's as before, and stopping the Cockpit still hands Cesium's handler back.
This commit is contained in:
1 parent
dd063b0e83
commit
b18336d3d4
5 files changed
+116
-9
No files matched your search
@@ -1723,7 +1723,10 @@ in a polite live region (`FOCUS · Camp Alpha`), and the swath reads
|
|||||||
approximate as for a tilt, scaled by the tilt onto the point. Clicks still
|
approximate as for a tilt, scaled by the tilt onto the point. Clicks still
|
||||||
reach Cesium's own handler and never untrack the satellite; a click a tool
|
reach Cesium's own handler and never untrack the satellite; a click a tool
|
||||||
owns (drawing) is ignored, and the draw tool still borrows the click while
|
owns (drawing) is ignored, and the draw tool still borrows the click while
|
||||||
it draws. Under the readout, IN REACH · *n* (a disclosure) lists the mapped
|
it draws. A double-click on a mapped ground point keeps or starts the focus
|
||||||
|
on it and never reaches Cesium's double-click, which would track the point
|
||||||
|
and end the view (the Cockpit's double-click routing in
|
||||||
|
`src/ui/cockpitInput.js`); any other double-click goes on as before. Under the readout, IN REACH · *n* (a disclosure) lists the mapped
|
||||||
points facing the satellite that are within the reach or in the frame now,
|
points facing the satellite that are within the reach or in the frame now,
|
||||||
nearest to nadir first, at most 12 (with NEAREST 12 OF *n* beyond that),
|
nearest to nadir first, at most 12 (with NEAREST 12 OF *n* beyond that),
|
||||||
rebuilt once a second. A row opens the point's details: position, source and
|
rebuilt once a second. A row opens the point's details: position, source and
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
} from './cockpitOrbitalView.js';
|
} from './cockpitOrbitalView.js';
|
||||||
import {
|
import {
|
||||||
onOrbitalClick,
|
onOrbitalClick,
|
||||||
|
onOrbitalDoubleClick,
|
||||||
routeSceneClick,
|
routeSceneClick,
|
||||||
toggleOrbitalFocus,
|
toggleOrbitalFocus,
|
||||||
} from './cockpitOrbitalFocus.js';
|
} from './cockpitOrbitalFocus.js';
|
||||||
@@ -445,6 +446,15 @@ export class CockpitViewController {
|
|||||||
onOrbitalClick(position) {
|
onOrbitalClick(position) {
|
||||||
return onOrbitalClick.call(this, position);
|
return onOrbitalClick.call(this, position);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* A double-click on the orbital picture: on a mapped ground point it keeps
|
||||||
|
* or starts the focus there instead of letting Cesium track the point.
|
||||||
|
* @param {{x: number, y: number}|null|undefined} position
|
||||||
|
* @returns {boolean} True when it was taken.
|
||||||
|
*/
|
||||||
|
onOrbitalDoubleClick(position) {
|
||||||
|
return onOrbitalDoubleClick.call(this, position);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* FOCUS on the reach list: focus that point, switch to it, or end the
|
* FOCUS on the reach list: focus that point, switch to it, or end the
|
||||||
* focus held on it.
|
* focus held on it.
|
||||||
|
|||||||
@@ -123,7 +123,8 @@ export function onSceneDoubleClick(position, nowMs = performance.now()) {
|
|||||||
* installs its own (pickAndTrackObject), which untracks whenever the pick is
|
* installs its own (pickAndTrackObject), which untracks whenever the pick is
|
||||||
* not an Entity: on a followed aircraft's model, a primitive, it would drop
|
* not an Entity: on a followed aircraft's model, a primitive, it would drop
|
||||||
* the very track the double-click means to ride. A double-click on the
|
* the very track the double-click means to ride. A double-click on the
|
||||||
* followed track is the Cockpit's; any other goes on to Cesium's.
|
* followed track is the Cockpit's, as is one on a mapped ground point in
|
||||||
|
* orbit (a focus); any other goes on to Cesium's.
|
||||||
* @returns {() => void} Puts Cesium's handler back, unless another owner
|
* @returns {() => void} Puts Cesium's handler back, unless another owner
|
||||||
* (the draw tool borrows it) has replaced ours since.
|
* (the draw tool borrows it) has replaced ours since.
|
||||||
*/
|
*/
|
||||||
@@ -134,6 +135,9 @@ export function routeSceneDoubleClick() {
|
|||||||
const stock = handler.getInputAction?.(type) ?? null;
|
const stock = handler.getInputAction?.(type) ?? null;
|
||||||
const routed = (event) => {
|
const routed = (event) => {
|
||||||
if (this.onSceneDoubleClick(event?.position)) return;
|
if (this.onSceneDoubleClick(event?.position)) return;
|
||||||
|
// In orbit, a double-click on a mapped ground point is a focus, never a
|
||||||
|
// retarget that would end the view.
|
||||||
|
if (this.onOrbitalDoubleClick?.(event?.position)) return;
|
||||||
stock?.(event);
|
stock?.(event);
|
||||||
};
|
};
|
||||||
handler.setInputAction(routed, type);
|
handler.setInputAction(routed, type);
|
||||||
|
|||||||
@@ -168,6 +168,37 @@ export function toggleOrbitalFocus(key) {
|
|||||||
return record ? startFocus.call(this, record) : false;
|
return record ? startFocus.call(this, record) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The mapped ground point drawn at a canvas position, or null. */
|
||||||
|
function groundRecordAt(controller, position) {
|
||||||
|
let picked = null;
|
||||||
|
try {
|
||||||
|
picked = controller.viewer.scene?.pick?.(position) ?? null;
|
||||||
|
} catch {
|
||||||
|
picked = null;
|
||||||
|
}
|
||||||
|
return pickedGroundRecord(controller, picked);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A double-click on the orbital picture. On a mapped ground point it keeps
|
||||||
|
* or starts the focus on it (as a single click does) and is taken: Cesium's
|
||||||
|
* own double-click would track that point, which ends the view. Any other
|
||||||
|
* double-click, one a tool owns, and every one outside orbit go on.
|
||||||
|
* @param {{x: number, y: number}|null|undefined} position Canvas position.
|
||||||
|
* @returns {boolean} True when it landed on a ground point and was taken.
|
||||||
|
*/
|
||||||
|
export function onOrbitalDoubleClick(position) {
|
||||||
|
if (!inOrbit(this) || !isPointerFree()) return false;
|
||||||
|
if (!Number.isFinite(position?.x) || !Number.isFinite(position?.y))
|
||||||
|
return false;
|
||||||
|
const record = groundRecordAt(this, position);
|
||||||
|
if (!record) return false;
|
||||||
|
// A point beyond the reach is not focused, but still never tracked.
|
||||||
|
if (this.orbital.focus?.key !== String(record.id))
|
||||||
|
startFocus.call(this, record);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A click on the orbital picture. One on a mapped ground point in reach
|
* A click on the orbital picture. One on a mapped ground point in reach
|
||||||
* focuses it; any other click ends a focus. A click a tool owns (drawing)
|
* focuses it; any other click ends a focus. A click a tool owns (drawing)
|
||||||
@@ -179,13 +210,7 @@ export function onOrbitalClick(position) {
|
|||||||
if (!inOrbit(this) || !isPointerFree()) return false;
|
if (!inOrbit(this) || !isPointerFree()) return false;
|
||||||
if (!Number.isFinite(position?.x) || !Number.isFinite(position?.y))
|
if (!Number.isFinite(position?.x) || !Number.isFinite(position?.y))
|
||||||
return false;
|
return false;
|
||||||
let picked = null;
|
const record = groundRecordAt(this, position);
|
||||||
try {
|
|
||||||
picked = this.viewer.scene?.pick?.(position) ?? null;
|
|
||||||
} catch {
|
|
||||||
picked = null;
|
|
||||||
}
|
|
||||||
const record = pickedGroundRecord(this, picked);
|
|
||||||
const state = this.orbital;
|
const state = this.orbital;
|
||||||
if (record) {
|
if (record) {
|
||||||
if (state.focus?.key === String(record.id)) return true;
|
if (state.focus?.key === String(record.id)) return true;
|
||||||
|
|||||||
@@ -109,6 +109,18 @@ function fixture(t, { reducedMotion = false } = {}) {
|
|||||||
};
|
};
|
||||||
handler.stock = stockClick;
|
handler.stock = stockClick;
|
||||||
actions.set(Cesium.ScreenSpaceEventType.LEFT_CLICK, stockClick);
|
actions.set(Cesium.ScreenSpaceEventType.LEFT_CLICK, stockClick);
|
||||||
|
// Its double-click tracks what it picks (pickAndTrackObject): a mapped
|
||||||
|
// point, tracked, would end the orbital view.
|
||||||
|
handler.stockDoubleClicks = 0;
|
||||||
|
const stockDoubleClick = ({ position }) => {
|
||||||
|
handler.stockDoubleClicks += 1;
|
||||||
|
const picked = viewer.scene.pick(position);
|
||||||
|
viewer.trackedEntity = picked?.id
|
||||||
|
? { ...picked.id, position: { getValue: () => null } }
|
||||||
|
: undefined;
|
||||||
|
};
|
||||||
|
handler.stockDouble = stockDoubleClick;
|
||||||
|
actions.set(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK, stockDoubleClick);
|
||||||
viewer.screenSpaceEventHandler = handler;
|
viewer.screenSpaceEventHandler = handler;
|
||||||
|
|
||||||
let subject = { ...ISS };
|
let subject = { ...ISS };
|
||||||
@@ -229,6 +241,12 @@ function fixture(t, { reducedMotion = false } = {}) {
|
|||||||
frame,
|
frame,
|
||||||
click: (position) =>
|
click: (position) =>
|
||||||
actions.get(Cesium.ScreenSpaceEventType.LEFT_CLICK)?.({ position }),
|
actions.get(Cesium.ScreenSpaceEventType.LEFT_CLICK)?.({ position }),
|
||||||
|
/** A double-click as Cesium fires it: two clicks, then the double. */
|
||||||
|
doubleClick(position) {
|
||||||
|
actions.get(Cesium.ScreenSpaceEventType.LEFT_CLICK)?.({ position });
|
||||||
|
actions.get(Cesium.ScreenSpaceEventType.LEFT_CLICK)?.({ position });
|
||||||
|
actions.get(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)?.({ position });
|
||||||
|
},
|
||||||
/** Move the satellite along its track by `deg` of latitude and longitude. */
|
/** Move the satellite along its track by `deg` of latitude and longitude. */
|
||||||
move(dLat, dLon) {
|
move(dLat, dLon) {
|
||||||
subject = {
|
subject = {
|
||||||
@@ -642,3 +660,50 @@ test('stopping the Cockpit hands the single click back to Cesium', async (t) =>
|
|||||||
assert.equal(scene.handler.stockClicks, 1);
|
assert.equal(scene.handler.stockClicks, 1);
|
||||||
assert.equal(scene.cockpit.orbital, null);
|
assert.equal(scene.cockpit.orbital, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a double-click on a mapped point focuses it and keeps the orbital view', async (t) => {
|
||||||
|
const scene = await inOrbit(t);
|
||||||
|
const { cockpit, viewer, handler } = scene;
|
||||||
|
scene.doubleClick(SITES.alpha.at);
|
||||||
|
assert.equal(handler.stockDoubleClicks, 0, 'Cesium does not track the point');
|
||||||
|
assert.equal(viewer.trackedEntity, undefined);
|
||||||
|
scene.frame();
|
||||||
|
assert.equal(cockpit.active, true, 'still in orbit');
|
||||||
|
assert.equal(cockpit.orbital.focus.key, 'site-alpha');
|
||||||
|
run(scene, LAND_FRAMES);
|
||||||
|
assert.ok(missDeg(scene.shots.at(-1), 'alpha') < 1e-5);
|
||||||
|
|
||||||
|
// On the focused point it keeps the focus; on another it switches.
|
||||||
|
scene.doubleClick(SITES.alpha.at);
|
||||||
|
assert.equal(cockpit.orbital.focus.key, 'site-alpha');
|
||||||
|
scene.doubleClick(SITES.bravo.at);
|
||||||
|
assert.equal(cockpit.orbital.focus.key, 'site-bravo');
|
||||||
|
// A mapped point beyond the reach is not focused, but not tracked either.
|
||||||
|
scene.doubleClick(SITES.far.at);
|
||||||
|
assert.equal(handler.stockDoubleClicks, 0);
|
||||||
|
scene.frame();
|
||||||
|
assert.equal(cockpit.active, true);
|
||||||
|
|
||||||
|
// Anywhere else the double-click goes on to Cesium's, as before.
|
||||||
|
scene.doubleClick(EMPTY_GROUND);
|
||||||
|
assert.equal(handler.stockDoubleClicks, 1);
|
||||||
|
assert.equal(cockpit.orbital.focus, null, 'the clicks ended the focus');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a double-click a tool owns, or one outside orbit, goes on to Cesium', async (t) => {
|
||||||
|
const scene = fixture(t);
|
||||||
|
const type = Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK;
|
||||||
|
scene.doubleClick(SITES.alpha.at);
|
||||||
|
assert.equal(scene.handler.stockDoubleClicks, 1, 'outside orbit');
|
||||||
|
scene.viewer.trackedEntity = undefined;
|
||||||
|
assert.equal(scene.cockpit.enter(), true);
|
||||||
|
await settle();
|
||||||
|
scene.frame();
|
||||||
|
const lease = claimPointer('draw');
|
||||||
|
t.after(() => releasePointer(lease));
|
||||||
|
scene.doubleClick(SITES.alpha.at);
|
||||||
|
assert.equal(scene.handler.stockDoubleClicks, 2, 'a tool owns it');
|
||||||
|
releasePointer(lease);
|
||||||
|
scene.cockpit.stop();
|
||||||
|
assert.equal(scene.handler.getInputAction(type), scene.handler.stockDouble);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user