133 lines
5.4 KiB
JavaScript
133 lines
5.4 KiB
JavaScript
"use strict";
|
|
|
|
(function (global) {
|
|
function bindTouchInput(ctx) {
|
|
if (!ctx?.canvas) return false;
|
|
const { canvas, world, uiCache } = ctx;
|
|
ctx.bindMobileModeControls();
|
|
|
|
canvas.addEventListener("touchstart", (e) => {
|
|
if (!e.touches?.length) return;
|
|
e.preventDefault();
|
|
uiCache.touchMoved = false;
|
|
const mode = ctx.mobileInputMode();
|
|
if ((mode === "camera" || mode === "family") && e.touches.length === 1) {
|
|
const t = e.touches[0];
|
|
uiCache.touchStartX = t.clientX;
|
|
uiCache.touchStartY = t.clientY;
|
|
uiCache.touchLastX = t.clientX;
|
|
uiCache.touchLastY = t.clientY;
|
|
uiCache.touchMode = "cameraPan";
|
|
return;
|
|
}
|
|
if (e.touches.length >= 2) {
|
|
const c = ctx.touchCenter(e.touches);
|
|
uiCache.touchMode = "pinchZoom";
|
|
uiCache.pinchStartDistance = Math.max(1, ctx.touchDistance(e.touches));
|
|
uiCache.pinchStartZoom = world.fieldZoom || 1;
|
|
uiCache.pinchLastCenterX = c?.clientX || 0;
|
|
uiCache.pinchLastCenterY = c?.clientY || 0;
|
|
return;
|
|
}
|
|
const t = e.touches[0];
|
|
const p = ctx.screenToWorldClient(t.clientX, t.clientY);
|
|
uiCache.touchStartX = t.clientX;
|
|
uiCache.touchStartY = t.clientY;
|
|
uiCache.touchLastX = t.clientX;
|
|
uiCache.touchLastY = t.clientY;
|
|
uiCache.touchLastWorldX = p.x;
|
|
uiCache.touchLastWorldY = p.y;
|
|
if (mode === "tool" && world.tool === "observe") {
|
|
uiCache.touchMode = "toolTapOnly";
|
|
return;
|
|
}
|
|
if (world.tool === "water_hose" && p.inside) {
|
|
ctx.beginHose(p, t.clientX, t.clientY, { touchMode: "hose" });
|
|
return;
|
|
}
|
|
if (world.tool === "pinch" && p.inside && ctx.beginGrab(p, t.clientX, t.clientY, { touchMode: "grab" })) return;
|
|
uiCache.touchMode = mode === "tool" ? "toolTapOnly" : "panOrTap";
|
|
}, { passive: false });
|
|
|
|
canvas.addEventListener("touchmove", (e) => {
|
|
if (!e.touches?.length || !uiCache.touchMode) return;
|
|
e.preventDefault();
|
|
if (uiCache.touchMode === "pinchZoom" && e.touches.length >= 2) {
|
|
const c = ctx.touchCenter(e.touches);
|
|
const distNow = Math.max(1, ctx.touchDistance(e.touches));
|
|
const ratio = distNow / Math.max(1, uiCache.pinchStartDistance || distNow);
|
|
ctx.setZoomAroundClientPoint(c.clientX, c.clientY, (uiCache.pinchStartZoom || 1) * ratio);
|
|
const dx = c.clientX - (uiCache.pinchLastCenterX || c.clientX);
|
|
const dy = c.clientY - (uiCache.pinchLastCenterY || c.clientY);
|
|
uiCache.pinchLastCenterX = c.clientX;
|
|
uiCache.pinchLastCenterY = c.clientY;
|
|
if (Math.hypot(dx, dy) > 0.1) world.panCamera?.(-dx, -dy);
|
|
uiCache.touchMoved = true;
|
|
render();
|
|
return;
|
|
}
|
|
const t = e.touches[0];
|
|
const p = ctx.screenToWorldClient(t.clientX, t.clientY);
|
|
const screenDx = t.clientX - (uiCache.touchLastX || t.clientX);
|
|
const screenDy = t.clientY - (uiCache.touchLastY || t.clientY);
|
|
const totalMove = Math.hypot(t.clientX - (uiCache.touchStartX || t.clientX), t.clientY - (uiCache.touchStartY || t.clientY));
|
|
uiCache.touchLastX = t.clientX;
|
|
uiCache.touchLastY = t.clientY;
|
|
if (uiCache.touchMode === "cameraPan") {
|
|
if (totalMove > 2) uiCache.touchMoved = true;
|
|
world.panCamera?.(-screenDx, -screenDy);
|
|
render();
|
|
return;
|
|
}
|
|
if (uiCache.touchMode === "toolTapOnly") {
|
|
if (totalMove > 8) uiCache.touchMoved = true;
|
|
return;
|
|
}
|
|
if (uiCache.touchMode === "hose" && uiCache.hosing) {
|
|
ctx.moveHose(p, t.clientX, t.clientY, { touch: true });
|
|
return;
|
|
}
|
|
if (uiCache.touchMode === "grab" && uiCache.grabbing) {
|
|
if (totalMove > 3) { uiCache.grabMoved = true; uiCache.touchMoved = true; }
|
|
ctx.moveGrab(p, t.clientX, t.clientY, { touch: true, renderFrame: true });
|
|
return;
|
|
}
|
|
if (uiCache.touchMode === "panOrTap") {
|
|
if (totalMove > 7) {
|
|
uiCache.touchMoved = true;
|
|
world.panCamera?.(-screenDx, -screenDy);
|
|
render();
|
|
}
|
|
}
|
|
}, { passive: false });
|
|
|
|
canvas.addEventListener("touchend", (e) => {
|
|
e.preventDefault();
|
|
if (uiCache.hosing) ctx.endHose();
|
|
if (uiCache.grabbing) {
|
|
ctx.endGrab(e.changedTouches?.[0]?.clientX || uiCache.touchLastX || 0, e.changedTouches?.[0]?.clientY || uiCache.touchLastY || 0);
|
|
} else if (uiCache.touchMode === "toolTapOnly" && !uiCache.touchMoved) {
|
|
const p = ctx.screenToWorldClient(uiCache.touchLastX || uiCache.touchStartX, uiCache.touchLastY || uiCache.touchStartY);
|
|
if (p.inside) {
|
|
window.TarinaiCommands?.dispatch?.(world, { type: "pointer.primary", x: p.x, y: p.y });
|
|
renderStats();
|
|
}
|
|
} else if (uiCache.touchMode === "panOrTap" && !uiCache.touchMoved) {
|
|
const p = ctx.screenToWorldClient(uiCache.touchLastX || uiCache.touchStartX, uiCache.touchLastY || uiCache.touchStartY);
|
|
if (p.inside) {
|
|
window.TarinaiCommands?.dispatch?.(world, { type: "pointer.primary", x: p.x, y: p.y });
|
|
renderStats();
|
|
}
|
|
}
|
|
if (!e.touches?.length) {
|
|
uiCache.touchMode = "";
|
|
uiCache.touchMoved = false;
|
|
}
|
|
}, { passive: false });
|
|
|
|
canvas.addEventListener("touchcancel", () => ctx.cancelPointerActions(), { passive: true });
|
|
return true;
|
|
}
|
|
|
|
global.TarinaiTouchInput = Object.freeze({ bindTouchInput });
|
|
})(window);
|