fix(cockpit): a ship's double-click memory belongs to that ship

The first press's picture of the ship survived a change of followed
subject: following an aircraft (or another ship) within 700 ms let a
double-click on the old ship's spot enter the new subject. The memory now
carries the ship's MMSI and is used only while that ship is still the one
followed.
This commit is contained in:
Sameh Khamis committed 2026-11-08 14:09:17 -08:00
1 parent f96a89a9ef
commit 5c937e67e1
2 files changed
+28 -1

No files matched your search

+22
View File
@@ -1435,6 +1435,28 @@ test('a followed aircraft keeps its own double-click hit area', async (t) => {
assert.equal(cockpit.active, false);
});
test("a ship's double-click memory does not carry over to an aircraft followed since", async (t) => {
const aircraftInfo = {
icao24: 'abc123',
callsign: 'TEST1',
latitude: 54.5,
longitude: 10.2,
altitudeM: 3000,
velocityMps: 200,
track: 45,
onGround: false,
};
const { cockpit, viewer, aircraft } = fixture(t, { aircraftInfo });
heightSensitiveProjection(viewer);
// The press finds the ship at (400, 300).
cockpit.onScenePointerDown(1000);
// Within the memory, an aircraft is followed, drawn elsewhere.
viewer.trackedEntity = aircraft;
heightSensitiveProjection(viewer, { x: 900 });
assert.equal(cockpit.onSceneDoubleClick({ x: 400, y: 300 }, 1250), false);
assert.equal(cockpit.active, false);
});
test("a double-click's second press keeps the first press's picture of the ship", async (t) => {
const { cockpit, viewer, store } = fixture(t);
heightSensitiveProjection(viewer);
+6 -1
View File
@@ -81,7 +81,8 @@ export function onScenePointerDown(nowMs = performance.now()) {
return;
}
const at = subjectCanvasPosition.call(this);
this.doubleClickStart = at ? { x: at.x, y: at.y, atMs: nowMs } : null;
const mmsi = this.readVesselInfo()?.mmsi ?? null;
this.doubleClickStart = at ? { x: at.x, y: at.y, atMs: nowMs, mmsi } : null;
}
/**
@@ -105,6 +106,10 @@ export function onSceneDoubleClick(position, nowMs = performance.now()) {
doubleClickHitsSubject(position, subjectCanvasPosition.call(this)) ||
(Boolean(start) &&
nowMs - start.atMs <= DOUBLE_CLICK_MEMORY_MS &&
// The memory is the ship's it was taken for: one followed since (an
// aircraft, another ship) is hit only where it is drawn.
this.resolveEntryKind() === 'vessel' &&
start.mmsi === (this.readVesselInfo()?.mmsi ?? null) &&
doubleClickHitsSubject(position, start));
if (!hit) return false;
this.enter();