Tune BIM zoom and modal layering
This commit is contained in:
parent
249d46c7c7
commit
63b72d0e36
|
|
@ -214,7 +214,7 @@ header {
|
||||||
#navCube {
|
#navCube {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 64px;
|
top: 64px;
|
||||||
right: 12px;
|
right: 64px;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
|
@ -1664,7 +1664,8 @@ header {
|
||||||
|
|
||||||
#saveProjectBackdrop,
|
#saveProjectBackdrop,
|
||||||
#deleteProjectBackdrop,
|
#deleteProjectBackdrop,
|
||||||
#shareModalBackdrop {
|
#shareModalBackdrop,
|
||||||
|
.version-history-backdrop {
|
||||||
z-index: var(--z-critical-backdrop);
|
z-index: var(--z-critical-backdrop);
|
||||||
background: rgba(10, 12, 16, 0.38);
|
background: rgba(10, 12, 16, 0.38);
|
||||||
backdrop-filter: blur(18px) saturate(1.18) brightness(0.82);
|
backdrop-filter: blur(18px) saturate(1.18) brightness(0.82);
|
||||||
|
|
@ -2784,6 +2785,7 @@ header {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 4px 6px 4px 6px;
|
padding: 4px 6px 4px 6px;
|
||||||
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-panel .env-range-control.slider-row {
|
.settings-panel .env-range-control.slider-row {
|
||||||
|
|
@ -3245,17 +3247,14 @@ html[data-share-startup="pending"] #loader.hidden {
|
||||||
.version-history-backdrop {
|
.version-history-backdrop {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
z-index: var(--z-modal, 10000);
|
z-index: var(--z-critical-backdrop);
|
||||||
background: rgba(0, 0, 0, 0.58);
|
|
||||||
backdrop-filter: blur(18px);
|
|
||||||
-webkit-backdrop-filter: blur(18px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.version-history-modal {
|
.version-history-modal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
z-index: calc(var(--z-modal, 10000) + 1);
|
z-index: var(--z-critical-modal);
|
||||||
display: flex;
|
display: flex;
|
||||||
width: min(96vw, 1280px);
|
width: min(96vw, 1280px);
|
||||||
max-height: min(76vh, 720px);
|
max-height: min(76vh, 720px);
|
||||||
|
|
|
||||||
|
|
@ -381,10 +381,23 @@ const CAMERA_CONTROL_SETTINGS = {
|
||||||
dollyProximityThreshold: 90,
|
dollyProximityThreshold: 90,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ZOOM_SPEED_PERCENT_MIN = 5;
|
||||||
|
const ZOOM_SPEED_PERCENT_MAX = 100;
|
||||||
|
const ZOOM_DOLLY_RATE_MIN = 1;
|
||||||
|
const ZOOM_DOLLY_RATE_MAX = 100;
|
||||||
|
const ZOOM_DOLLY_RESPONSE_EXPONENT = 1.45;
|
||||||
|
|
||||||
const normalizeZoomSpeed = (value) => {
|
const normalizeZoomSpeed = (value) => {
|
||||||
const numeric = Number(value);
|
const numeric = Number(value);
|
||||||
if (!Number.isFinite(numeric)) return 20;
|
if (!Number.isFinite(numeric)) return 20;
|
||||||
return Math.min(100, Math.max(5, Math.round(numeric)));
|
return Math.min(ZOOM_SPEED_PERCENT_MAX, Math.max(ZOOM_SPEED_PERCENT_MIN, Math.round(numeric)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getZoomDollyRate = (value) => {
|
||||||
|
const normalized = normalizeZoomSpeed(value);
|
||||||
|
const range = ZOOM_SPEED_PERCENT_MAX - ZOOM_SPEED_PERCENT_MIN;
|
||||||
|
const t = range > 0 ? (normalized - ZOOM_SPEED_PERCENT_MIN) / range : 0;
|
||||||
|
return ZOOM_DOLLY_RATE_MIN + (Math.pow(t, ZOOM_DOLLY_RESPONSE_EXPONENT) * (ZOOM_DOLLY_RATE_MAX - ZOOM_DOLLY_RATE_MIN));
|
||||||
};
|
};
|
||||||
|
|
||||||
const isHexColor = (value) => /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(String(value || "").trim());
|
const isHexColor = (value) => /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(String(value || "").trim());
|
||||||
|
|
@ -453,7 +466,7 @@ const configureCameraControl = () => {
|
||||||
control.smartPivot = false;
|
control.smartPivot = false;
|
||||||
control.zoomOnMouseWheel = true;
|
control.zoomOnMouseWheel = true;
|
||||||
control.keyboardDollyRate = CAMERA_CONTROL_SETTINGS.keyboardDollyRate;
|
control.keyboardDollyRate = CAMERA_CONTROL_SETTINGS.keyboardDollyRate;
|
||||||
control.mouseWheelDollyRate = activeZoomSpeed;
|
control.mouseWheelDollyRate = getZoomDollyRate(activeZoomSpeed);
|
||||||
control.dollyInertia = CAMERA_CONTROL_SETTINGS.dollyInertia;
|
control.dollyInertia = CAMERA_CONTROL_SETTINGS.dollyInertia;
|
||||||
control.dollyMinSpeed = CAMERA_CONTROL_SETTINGS.dollyMinSpeed;
|
control.dollyMinSpeed = CAMERA_CONTROL_SETTINGS.dollyMinSpeed;
|
||||||
control.dollyProximityThreshold = CAMERA_CONTROL_SETTINGS.dollyProximityThreshold;
|
control.dollyProximityThreshold = CAMERA_CONTROL_SETTINGS.dollyProximityThreshold;
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,57 @@ export function createSliderControl({
|
||||||
onChange?.(v);
|
onChange?.(v);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const clampValue = (next) => Math.min(Number(input.max), Math.max(Number(input.min), next));
|
||||||
|
|
||||||
|
const valueFromClientX = (clientX) => {
|
||||||
|
const rect = input.getBoundingClientRect();
|
||||||
|
const minValue = Number(input.min);
|
||||||
|
const maxValue = Number(input.max);
|
||||||
|
const range = maxValue - minValue;
|
||||||
|
if (!rect.width || !range) return Number(input.value);
|
||||||
|
const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
||||||
|
const raw = minValue + (ratio * range);
|
||||||
|
if (input.step === "any") return clampValue(raw);
|
||||||
|
const stepValue = Number(input.step) || 1;
|
||||||
|
return clampValue(minValue + (Math.round((raw - minValue) / stepValue) * stepValue));
|
||||||
|
};
|
||||||
|
|
||||||
|
const commitValue = (nextValue) => {
|
||||||
|
input.value = nextValue;
|
||||||
|
updateFill();
|
||||||
|
onChange?.(Number(input.value));
|
||||||
|
};
|
||||||
|
|
||||||
|
let activeTouchPointerId = null;
|
||||||
|
|
||||||
|
const isTouchLikePointer = (event) => event.pointerType === "touch" || event.pointerType === "pen";
|
||||||
|
|
||||||
|
row.addEventListener("pointerdown", (event) => {
|
||||||
|
if (!isTouchLikePointer(event) || (event.button !== undefined && event.button !== 0)) return;
|
||||||
|
activeTouchPointerId = event.pointerId;
|
||||||
|
event.preventDefault();
|
||||||
|
row.setPointerCapture?.(event.pointerId);
|
||||||
|
input.focus?.({ preventScroll: true });
|
||||||
|
commitValue(valueFromClientX(event.clientX));
|
||||||
|
});
|
||||||
|
|
||||||
|
row.addEventListener("pointermove", (event) => {
|
||||||
|
if (activeTouchPointerId !== event.pointerId) return;
|
||||||
|
event.preventDefault();
|
||||||
|
commitValue(valueFromClientX(event.clientX));
|
||||||
|
});
|
||||||
|
|
||||||
|
const finishTouchPointer = (event) => {
|
||||||
|
if (activeTouchPointerId !== event.pointerId) return;
|
||||||
|
activeTouchPointerId = null;
|
||||||
|
if (row.hasPointerCapture?.(event.pointerId)) {
|
||||||
|
row.releasePointerCapture?.(event.pointerId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
row.addEventListener("pointerup", finishTouchPointer);
|
||||||
|
row.addEventListener("pointercancel", finishTouchPointer);
|
||||||
|
|
||||||
updateFill();
|
updateFill();
|
||||||
|
|
||||||
row.appendChild(lbl);
|
row.appendChild(lbl);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue