mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
112 lines
3.9 KiB
JavaScript
112 lines
3.9 KiB
JavaScript
import * as Cesium from 'cesium';
|
|
import { isPointerFree } from './inputOwnership.js';
|
|
|
|
export const MAX_TRACKING_CLICK_TRAVEL_PX = 6;
|
|
export const MAX_TRACKING_CLICK_DURATION_MS = 400;
|
|
|
|
/**
|
|
* Decide whether a completed press stayed spatially click-like. Duration is
|
|
* deliberately ignored so a stationary long press may still select a contact;
|
|
* callers apply the full click classifier before destructive deselection.
|
|
* @param {{travelPx?: number}} gesture - Accumulated pointer path.
|
|
* @returns {boolean} True when travel stays within the click limit.
|
|
*/
|
|
export function isTrackingSelectionGesture(gesture = {}) {
|
|
const travelPx = Number.isFinite(gesture.travelPx)
|
|
? Math.max(0, gesture.travelPx)
|
|
: Number.POSITIVE_INFINITY;
|
|
return travelPx <= MAX_TRACKING_CLICK_TRAVEL_PX;
|
|
}
|
|
|
|
/**
|
|
* Decide whether a completed press is a clean click suitable for deselection
|
|
* or another action that requires both short duration and low travel.
|
|
* @param {{travelPx?: number, durationMs?: number}} gesture - Accumulated path and press time.
|
|
* @returns {boolean} True when the gesture stays within both click limits.
|
|
*/
|
|
export function isTrackingClickGesture(gesture = {}) {
|
|
const durationMs = Number.isFinite(gesture.durationMs)
|
|
? Math.max(0, gesture.durationMs)
|
|
: Number.POSITIVE_INFINITY;
|
|
return (
|
|
isTrackingSelectionGesture(gesture) &&
|
|
durationMs <= MAX_TRACKING_CLICK_DURATION_MS
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Bind LEFT_DOWN/MOUSE_MOVE/LEFT_UP accounting ahead of a scene click.
|
|
* Travel is accumulated segment-by-segment, so an orbit nudge that returns to
|
|
* its starting pixel cannot masquerade as a zero-distance click. Every scene
|
|
* click reaches `onClick` with its gesture metadata; the caller decides whether
|
|
* selection (travel-only) or deselection (travel + duration) is allowed.
|
|
* @param {Cesium.ScreenSpaceEventHandler|Object} handler - Input handler.
|
|
* @param {(click: Object, gesture: {travelPx: number, durationMs: number}) => void} onClick - Scene-click callback.
|
|
* @param {{now?: () => number, eventTypes?: Object, onMouseMove?: (event: Object) => void}} [options] - Test/interop seams.
|
|
* @returns {void}
|
|
*/
|
|
export function bindTrackingClickGesture(handler, onClick, options = {}) {
|
|
const now = options.now || (() => performance.now());
|
|
const eventTypes = options.eventTypes || Cesium.ScreenSpaceEventType;
|
|
let pressActive = false;
|
|
let pressStartedAt = 0;
|
|
let previousPosition = null;
|
|
let travelPx = 0;
|
|
let completedGesture = null;
|
|
|
|
const appendTravel = (position) => {
|
|
if (
|
|
!pressActive ||
|
|
!Number.isFinite(position?.x) ||
|
|
!Number.isFinite(position?.y)
|
|
)
|
|
return;
|
|
if (previousPosition) {
|
|
travelPx += Math.hypot(
|
|
position.x - previousPosition.x,
|
|
position.y - previousPosition.y,
|
|
);
|
|
}
|
|
previousPosition = { x: position.x, y: position.y };
|
|
};
|
|
|
|
const finishPress = (position) => {
|
|
if (!pressActive) return;
|
|
appendTravel(position);
|
|
completedGesture = {
|
|
travelPx,
|
|
durationMs: Math.max(0, now() - pressStartedAt),
|
|
};
|
|
pressActive = false;
|
|
previousPosition = null;
|
|
};
|
|
|
|
handler.setInputAction((event) => {
|
|
pressActive = true;
|
|
pressStartedAt = now();
|
|
previousPosition = null;
|
|
travelPx = 0;
|
|
completedGesture = null;
|
|
appendTravel(event?.position);
|
|
}, eventTypes.LEFT_DOWN);
|
|
|
|
handler.setInputAction((event) => {
|
|
appendTravel(event?.endPosition ?? event?.position);
|
|
options.onMouseMove?.(event);
|
|
}, eventTypes.MOUSE_MOVE);
|
|
|
|
handler.setInputAction((event) => {
|
|
finishPress(event?.position);
|
|
}, eventTypes.LEFT_UP);
|
|
|
|
handler.setInputAction((click) => {
|
|
if (pressActive) finishPress(click?.position);
|
|
const gesture = completedGesture || { travelPx: 0, durationMs: 0 };
|
|
completedGesture = null;
|
|
// A tool owns the pointer: a draw vertex placed over an aircraft is a
|
|
// vertex, not a track request (src/data/inputOwnership.js).
|
|
if (!isPointerFree()) return;
|
|
onClick(click, gesture);
|
|
}, eventTypes.LEFT_CLICK);
|
|
}
|