fix touch actions
This commit is contained in:
@@ -190,6 +190,7 @@ mc-diorama {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
touch-action: none;
|
||||
|
||||
& .track-inner {
|
||||
position: relative;
|
||||
|
||||
@@ -230,6 +230,107 @@ export class SpacetimeController {
|
||||
this.syncUI();
|
||||
}
|
||||
});
|
||||
|
||||
// --- MOBILE TOUCH LOGIC ("Wait and See" Scroll vs Camera) ---
|
||||
|
||||
this.touchEngaged = false;
|
||||
this.touchTimer = null;
|
||||
this.touchStartPos = new Map();
|
||||
this.lastTouchPos = new Map();
|
||||
|
||||
this.canvas.addEventListener('touchstart', (e) => {
|
||||
if (!this.hasSpatial) return;
|
||||
// DO NOT call e.preventDefault() here, or the page will never scroll!
|
||||
|
||||
for (let i = 0; i < e.changedTouches.length; i++) {
|
||||
const t = e.changedTouches[i];
|
||||
this.touchStartPos.set(t.identifier, {x: t.clientX, y: t.clientY});
|
||||
this.lastTouchPos.set(t.identifier, {x: t.clientX, y: t.clientY});
|
||||
}
|
||||
|
||||
// A new finger restarts the timeout
|
||||
clearTimeout(this.touchTimer);
|
||||
this.touchEngaged = false;
|
||||
|
||||
this.touchTimer = setTimeout(() => {
|
||||
this.touchEngaged = true;
|
||||
// Once engaged, disable click propagation so it doesn't toggle play/pause
|
||||
this.hasDragged = true;
|
||||
}, 200);
|
||||
}, {passive: false});
|
||||
|
||||
this.canvas.addEventListener('touchmove', (e) => {
|
||||
if (!this.hasSpatial) return;
|
||||
|
||||
if (!this.touchEngaged) {
|
||||
// Check if they are swiping quickly before the timer completes.
|
||||
let maxDist = 0;
|
||||
for (let i = 0; i < e.touches.length; i++) {
|
||||
const t = e.touches[i];
|
||||
const start = this.touchStartPos.get(t.identifier);
|
||||
if (start) {
|
||||
maxDist = Math.max(maxDist, Math.hypot(t.clientX - start.x, t.clientY - start.y));
|
||||
}
|
||||
}
|
||||
// If they drag more than 10px before the 200ms timer, assume page scroll intent
|
||||
if (maxDist > 10) clearTimeout(this.touchTimer);
|
||||
return; // Let the browser scroll the page
|
||||
}
|
||||
|
||||
// --- CAMERA IS ENGAGED ---
|
||||
e.preventDefault(); // Stop the page from scrolling
|
||||
this.hasDragged = true;
|
||||
|
||||
if (e.touches.length === 1) {
|
||||
// 1 Finger: Orbit
|
||||
const t = e.touches[0];
|
||||
const last = this.lastTouchPos.get(t.identifier);
|
||||
if (last) {
|
||||
this.orbit(t.clientX - last.x, t.clientY - last.y);
|
||||
notifyCameraChange();
|
||||
}
|
||||
this.lastTouchPos.set(t.identifier, {x: t.clientX, y: t.clientY});
|
||||
} else if (e.touches.length === 2) {
|
||||
// 2 Fingers: Pan and Zoom
|
||||
const t1 = e.touches[0];
|
||||
const t2 = e.touches[1];
|
||||
const l1 = this.lastTouchPos.get(t1.identifier);
|
||||
const l2 = this.lastTouchPos.get(t2.identifier);
|
||||
|
||||
if (l1 && l2) {
|
||||
// Zoom (Pinch distance delta)
|
||||
const lastDist = Math.hypot(l1.x - l2.x, l1.y - l2.y);
|
||||
const currentDist = Math.hypot(t1.clientX - t2.clientX, t1.clientY - t2.clientY);
|
||||
this.zoomLinear((lastDist - currentDist) * 1.5); // inverted for pinch-to-zoom
|
||||
|
||||
// Pan (Center point delta)
|
||||
const lastCx = (l1.x + l2.x) / 2;
|
||||
const lastCy = (l1.y + l2.y) / 2;
|
||||
const cx = (t1.clientX + t2.clientX) / 2;
|
||||
const cy = (t1.clientY + t2.clientY) / 2;
|
||||
this.pan(cx - lastCx, cy - lastCy);
|
||||
|
||||
notifyCameraChange();
|
||||
}
|
||||
this.lastTouchPos.set(t1.identifier, {x: t1.clientX, y: t1.clientY});
|
||||
this.lastTouchPos.set(t2.identifier, {x: t2.clientX, y: t2.clientY});
|
||||
}
|
||||
}, {passive: false});
|
||||
|
||||
const handleTouchEnd = (e) => {
|
||||
for (let i = 0; i < e.changedTouches.length; i++) {
|
||||
const t = e.changedTouches[i];
|
||||
this.touchStartPos.delete(t.identifier);
|
||||
this.lastTouchPos.delete(t.identifier);
|
||||
}
|
||||
if (e.touches.length === 0) {
|
||||
clearTimeout(this.touchTimer);
|
||||
this.touchEngaged = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.canvas.addEventListener('touchend', handleTouchEnd);
|
||||
this.canvas.addEventListener('touchcancel', handleTouchEnd);
|
||||
}
|
||||
|
||||
// --- TEMPORAL CONTROL ---
|
||||
@@ -273,19 +374,26 @@ export class SpacetimeController {
|
||||
onDrag(pct);
|
||||
};
|
||||
|
||||
wrapper.addEventListener('mousedown', (e) => {
|
||||
wrapper.addEventListener('pointerdown', (e) => {
|
||||
wrapper.setPointerCapture(e.pointerId);
|
||||
isTrackDragging = true;
|
||||
this.playMode = 'paused';
|
||||
update(e);
|
||||
});
|
||||
|
||||
window.addEventListener('mousemove', (e) => {
|
||||
wrapper.addEventListener('pointermove', (e) => {
|
||||
if (isTrackDragging) update(e);
|
||||
});
|
||||
|
||||
window.addEventListener('mouseup', () => {
|
||||
isTrackDragging = false;
|
||||
});
|
||||
const stopDrag = (e) => {
|
||||
if (isTrackDragging) {
|
||||
isTrackDragging = false;
|
||||
wrapper.releasePointerCapture(e.pointerId);
|
||||
}
|
||||
};
|
||||
|
||||
wrapper.addEventListener('pointerup', stopDrag);
|
||||
wrapper.addEventListener('pointercancel', stopDrag);
|
||||
}
|
||||
|
||||
bindTimelineEvents() {
|
||||
|
||||
Reference in New Issue
Block a user