diff options
Diffstat (limited to 'public/app.js')
| -rw-r--r-- | public/app.js | 76 |
1 files changed, 63 insertions, 13 deletions
diff --git a/public/app.js b/public/app.js index 95f64d4..1c920ae 100644 --- a/public/app.js +++ b/public/app.js @@ -26,6 +26,8 @@ let scale = 1 let userZoomed = false let drag = null +const TOUCH = typeof window.matchMedia === "function" && window.matchMedia("(hover: none)").matches + function aspect(info) { return info.h > 0 ? info.w / info.h : 1 } @@ -197,19 +199,22 @@ function renderNav(id) { const exits = exitsCache.get(id) if (!exits) return const isCurrent = cur && cur.id === id + if (TOUCH && !isCurrent) return const nav = document.createElement("div") nav.className = "nav" for (const ex of exits) { const zone = document.createElement("div") zone.className = `nav-zone nav-zone-${ex.dir}` - zone.addEventListener("pointermove", () => { - if (adjacentTile(id, ex.dir)) return - cancelHideGhost() - showGhost(choosePlacement(id, ex.dir)) - }) - zone.addEventListener("pointerleave", () => { - scheduleHideGhost() - }) + if (!TOUCH) { + zone.addEventListener("pointermove", () => { + if (adjacentTile(id, ex.dir)) return + cancelHideGhost() + showGhost(choosePlacement(id, ex.dir)) + }) + zone.addEventListener("pointerleave", () => { + scheduleHideGhost() + }) + } zone.addEventListener("pointerdown", (e) => e.stopPropagation()) zone.addEventListener("click", (e) => { e.stopPropagation(); traverseFrom(id, ex.dir) }) if (!adjacentTile(id, ex.dir) && isCurrent) { @@ -389,6 +394,7 @@ function clearAllZones() { function renderTileZones(id) { clearTileZones(id) + if (TOUCH) return if (!tiles.has(id) || !exitsCache.has(id)) return const els = [] for (const dir of ["N", "E", "S", "W"]) { @@ -425,15 +431,37 @@ stage.addEventListener("pointerover", (e) => { if (tileEl) getExits(Number(tileEl.dataset.id)) }) +const pointers = new Map() +let pinchDist = 0 + stage.addEventListener("pointerdown", (e) => { if (e.target.closest(".nav-zone")) return + pointers.set(e.pointerId, { x: e.clientX, y: e.clientY }) + stage.setPointerCapture(e.pointerId) hideGhost() - drag = { x: e.clientX, y: e.clientY, px: panX, py: panY, moved: false, tile: e.target.closest(".tile") } world.style.transition = "none" - stage.setPointerCapture(e.pointerId) + if (pointers.size === 2) { + drag = null + const [a, b] = [...pointers.values()] + pinchDist = Math.hypot(b.x - a.x, b.y - a.y) + return + } + drag = { x: e.clientX, y: e.clientY, px: panX, py: panY, moved: false, tile: e.target.closest(".tile") } }) stage.addEventListener("pointermove", (e) => { + if (pointers.has(e.pointerId)) { + pointers.set(e.pointerId, { x: e.clientX, y: e.clientY }) + if (pointers.size === 2 && pinchDist > 0) { + const [a, b] = [...pointers.values()] + const d = Math.hypot(b.x - a.x, b.y - a.y) + if (d > 0) { + zoomAt((a.x + b.x) / 2, (a.y + b.y) / 2, d / pinchDist) + pinchDist = d + } + return + } + } if (!drag) return const dx = e.clientX - drag.x const dy = e.clientY - drag.y @@ -446,23 +474,45 @@ stage.addEventListener("pointermove", (e) => { }) stage.addEventListener("pointerup", (e) => { + const wasPinch = pointers.size >= 2 + pointers.delete(e.pointerId) + if (wasPinch && pointers.size === 1) { + const p = [...pointers.values()][0] + drag = { x: p.x, y: p.y, px: panX, py: panY, moved: true, tile: null } + } + pinchDist = 0 if (!drag) return const wasDrag = drag.moved const tile = drag.tile drag = null world.style.transition = "" - if (wasDrag || !tile) return + if (wasDrag || !tile) { + if (!wasDrag && !tile && e.pointerType === "touch") bgTap() + return + } const id = Number(tile.dataset.id) if (cur && cur.id === id) return setCurrent(id, tiles.get(id).rect) }) -stage.addEventListener("pointercancel", () => { - if (!drag) return +stage.addEventListener("pointercancel", (e) => { + pointers.delete(e.pointerId) + pinchDist = 0 drag = null world.style.transition = "" }) +let lastBgTap = -Infinity +function bgTap() { + const now = performance.now() + if (now - lastBgTap < 350) { + lastBgTap = 0 + resetZoom() + return + } + lastBgTap = now +} + let zoomTimer = 0 stage.addEventListener("wheel", (e) => { e.preventDefault() |
