Restore BIM pointer pivot navigation

This commit is contained in:
CODEX 2026-06-23 20:55:53 +03:00
parent 63b72d0e36
commit b90142a6c8
1 changed files with 54 additions and 5 deletions

View File

@ -302,6 +302,7 @@ let modelVersionHistory = null;
let modelVersionHistoryLoading = false;
let modelVersionUploading = false;
let versionHistoryModal = null;
let emptyWheelNavigationRestoreTimer = null;
const GUEST_TOOLBAR_ACTIONS = new Set(["measure", "section", "projection"]);
const memoryStore = new Map(); // url -> ArrayBuffer
const blobUrls = [];
@ -377,8 +378,8 @@ const treeModelIds = new Set();
const CAMERA_CONTROL_SETTINGS = {
keyboardDollyRate: 45,
dollyInertia: 0,
dollyMinSpeed: 0.008,
dollyProximityThreshold: 90,
dollyMinSpeed: 0.04,
dollyProximityThreshold: 30,
};
const ZOOM_SPEED_PERCENT_MIN = 5;
@ -460,10 +461,9 @@ const configureCameraControl = () => {
if (!control) return;
activeZoomSpeed = normalizeZoomSpeed(activeZoomSpeed);
configureCameraPanMap(control);
// Keep wheel dolly speed independent from whether the pointer is over model geometry.
control.followPointer = false;
control.followPointer = true;
control.doublePickFlyTo = false;
control.smartPivot = false;
control.smartPivot = true;
control.zoomOnMouseWheel = true;
control.keyboardDollyRate = CAMERA_CONTROL_SETTINGS.keyboardDollyRate;
control.mouseWheelDollyRate = getZoomDollyRate(activeZoomSpeed);
@ -1341,6 +1341,53 @@ const getCanvasPointFromEvent = (event) => {
};
};
const restorePointerNavigation = () => {
if (emptyWheelNavigationRestoreTimer) {
window.clearTimeout(emptyWheelNavigationRestoreTimer);
emptyWheelNavigationRestoreTimer = null;
}
const control = viewer?.cameraControl;
if (!control) return;
control.followPointer = true;
control.smartPivot = true;
};
const schedulePointerNavigationRestore = () => {
if (emptyWheelNavigationRestoreTimer) {
window.clearTimeout(emptyWheelNavigationRestoreTimer);
}
emptyWheelNavigationRestoreTimer = window.setTimeout(() => {
emptyWheelNavigationRestoreTimer = null;
restorePointerNavigation();
}, 80);
};
const hasWheelSurfaceHit = (event) => {
if (!activeModels.length || !viewer?.scene?.pick) return true;
const point = getCanvasPointFromEvent(event);
if (!point) return true;
try {
const hit = viewer.scene.pick({
canvasPos: point.canvasPos,
pickSurface: true,
});
return Boolean(hit?.entity || hit?.worldPos);
} catch (_) {
return true;
}
};
const guardEmptyWheelNavigation = (event) => {
const control = viewer?.cameraControl;
if (!control) return;
if (hasWheelSurfaceHit(event)) {
restorePointerNavigation();
return;
}
control.followPointer = false;
schedulePointerNavigationRestore();
};
const getWorldPosFromPick = (hit) => {
const direct = hit?.worldPos || hit?.worldPosition || hit?.position || hit?.origin;
if (direct && direct.length >= 3) {
@ -5705,6 +5752,8 @@ const initViewer = async () => {
const opened = openCommentContextMenuFromEvent(event);
if (!opened) event.preventDefault();
});
canvasEl.addEventListener("pointerdown", restorePointerNavigation, { capture: true });
canvasEl.addEventListener("wheel", guardEmptyWheelNavigation, { capture: true, passive: true });
canvasEl.addEventListener("pointerdown", (event) => {
if (measureActive) {
downPos = null;