zoooom 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/Zoooom-BypxEt9q.d.cts +128 -0
- package/dist/Zoooom-BypxEt9q.d.ts +128 -0
- package/dist/index.cjs +775 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +770 -0
- package/dist/index.js.map +1 -0
- package/dist/joystick.cjs +504 -0
- package/dist/joystick.cjs.map +1 -0
- package/dist/joystick.d.cts +31 -0
- package/dist/joystick.d.ts +31 -0
- package/dist/joystick.js +502 -0
- package/dist/joystick.js.map +1 -0
- package/dist/zoooom-full.iife.global.js +1272 -0
- package/dist/zoooom-full.iife.global.js.map +1 -0
- package/dist/zoooom.iife.global.js +773 -0
- package/dist/zoooom.iife.global.js.map +1 -0
- package/package.json +66 -0
- package/src/core/Zoooom.ts +294 -0
- package/src/core/constants.ts +29 -0
- package/src/core/loader.ts +129 -0
- package/src/core/transform.ts +146 -0
- package/src/full.ts +8 -0
- package/src/iife-entry.ts +2 -0
- package/src/iife-full-entry.ts +3 -0
- package/src/index.ts +11 -0
- package/src/input/gesture.ts +49 -0
- package/src/input/keyboard.ts +60 -0
- package/src/input/mouse.ts +54 -0
- package/src/input/touch.ts +111 -0
- package/src/input/wheel.ts +65 -0
- package/src/joystick/dom.ts +81 -0
- package/src/joystick/index.ts +2 -0
- package/src/joystick/joystick.ts +280 -0
- package/src/styles/core.ts +101 -0
- package/src/styles/joystick.ts +213 -0
- package/src/types.ts +118 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/constants.ts","../src/joystick/dom.ts","../src/styles/joystick.ts","../src/joystick/joystick.ts"],"names":[],"mappings":"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","file":"joystick.cjs","sourcesContent":["/** Default pan distance for keyboard arrows (px) */\nexport const PAN_STEP = 50;\n\n/** Zoom multiplier per discrete step (>1 zooms in) */\nexport const ZOOM_FACTOR = 1.5;\n\n/** Minimum zoom scale (allows slight zoom-out) */\nexport const MIN_SCALE = 0.8;\n\n/** Multiplier beyond native resolution for max zoom */\nexport const OVERSCALE_FACTOR = 2;\n\n/** Friction coefficient for momentum — velocity *= this each frame */\nexport const VELOCITY_DAMPING = 0.85;\n\n/** Sensitivity for trackpad continuous zoom */\nexport const TRACKPAD_SENSITIVITY = 0.002;\n\n/** Joystick panning zone radius (px) */\nexport const JOYSTICK_RADIUS = 60;\n\n/** Center deadzone as fraction of radius */\nexport const JOYSTICK_DEADZONE = 0.1;\n\n/** Maximum joystick panning speed (px/frame) */\nexport const MAX_JOYSTICK_SPEED = 10;\n\n/** Dwell timeout before joystick activates (ms) */\nexport const DWELL_TIMEOUT = 100;\n","/**\n * Create the joystick DOM structure.\n * Returns references to key elements for event binding.\n */\nexport interface JoystickDOM {\n wrap: HTMLElement;\n toggle: HTMLButtonElement;\n disc: HTMLElement;\n innerCircle: HTMLElement;\n zoomIn: HTMLElement;\n zoomOut: HTMLElement;\n}\n\nexport function createJoystickDOM(container: HTMLElement): JoystickDOM {\n // Toggle button (compass)\n const toggle = document.createElement('button');\n toggle.className = 'zoooom-joystick-toggle';\n toggle.setAttribute('aria-label', 'Toggle navigation joystick');\n toggle.setAttribute('aria-expanded', 'false');\n toggle.textContent = '\\u2316'; // ⌖ position indicator\n container.appendChild(toggle);\n\n // Joystick wrapper\n const wrap = document.createElement('div');\n wrap.className = 'zoooom-joystick-wrap';\n wrap.setAttribute('aria-hidden', 'true');\n\n // Disc (outer pan area)\n const disc = document.createElement('div');\n disc.className = 'zoooom-disc';\n disc.setAttribute('role', 'slider');\n disc.setAttribute('aria-label', 'Pan navigation control');\n disc.setAttribute('aria-valuenow', '0');\n disc.setAttribute('aria-valuemin', '0');\n disc.setAttribute('aria-valuemax', '1');\n disc.setAttribute('aria-valuetext', 'Center position — not moving');\n disc.setAttribute('tabindex', '0');\n\n // Inner circle (zoom)\n const innerCircle = document.createElement('div');\n innerCircle.className = 'zoooom-inner-circle';\n\n const zoomOut = document.createElement('div');\n zoomOut.className = 'zoooom-zoom-half zoooom-zoom-out';\n zoomOut.setAttribute('role', 'button');\n zoomOut.setAttribute('aria-label', 'Zoom out');\n zoomOut.setAttribute('tabindex', '0');\n zoomOut.textContent = '\\u2212'; // −\n\n const zoomIn = document.createElement('div');\n zoomIn.className = 'zoooom-zoom-half zoooom-zoom-in';\n zoomIn.setAttribute('role', 'button');\n zoomIn.setAttribute('aria-label', 'Zoom in');\n zoomIn.setAttribute('tabindex', '0');\n zoomIn.textContent = '+';\n\n innerCircle.appendChild(zoomOut);\n innerCircle.appendChild(zoomIn);\n\n // Direction arrows\n const arrows = document.createElement('div');\n arrows.className = 'zoooom-arrows';\n arrows.setAttribute('aria-hidden', 'true');\n for (const dir of ['n', 'e', 's', 'w']) {\n const arrow = document.createElement('div');\n arrow.className = `zoooom-arrow zoooom-arrow-${dir}`;\n arrows.appendChild(arrow);\n }\n\n disc.appendChild(innerCircle);\n disc.appendChild(arrows);\n wrap.appendChild(disc);\n container.appendChild(wrap);\n\n return { wrap, toggle, disc, innerCircle, zoomIn, zoomOut };\n}\n\nexport function destroyJoystickDOM(dom: JoystickDOM): void {\n dom.wrap.remove();\n dom.toggle.remove();\n}\n","export const JOYSTICK_CSS = `\n.zoooom-joystick-wrap {\n position: fixed;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 100;\n touch-action: none;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease-out, transform 0.3s ease-out;\n}\n\n.zoooom-joystick-wrap.visible {\n opacity: 1;\n pointer-events: auto;\n}\n\n.zoooom-joystick-toggle {\n position: fixed;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.5);\n border: 2px solid rgba(255, 255, 255, 0.6);\n cursor: pointer;\n z-index: 99;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #fff;\n font-size: 20px;\n font-weight: bold;\n backdrop-filter: blur(4px);\n transition: background 0.2s, box-shadow 0.2s;\n}\n\n.zoooom-joystick-toggle:hover {\n background: rgba(0, 0, 0, 0.7);\n box-shadow: 0 0 12px rgba(0, 0, 0, 0.4);\n}\n\n.zoooom-joystick-toggle:focus-visible {\n outline: 2px solid #2196f3;\n outline-offset: 2px;\n}\n\n.zoooom-disc {\n width: 200px;\n height: 200px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.4);\n border: 2px solid rgba(255, 255, 255, 0.6);\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n touch-action: none;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n}\n\n.zoooom-disc.active {\n border-color: rgba(255, 255, 255, 0.9);\n}\n\n.zoooom-inner-circle {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.5);\n display: flex;\n position: relative;\n z-index: 3;\n}\n\n.zoooom-zoom-half {\n width: 50%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-weight: bold;\n font-size: 22px;\n color: #fff;\n user-select: none;\n transition: background 0.15s;\n}\n\n.zoooom-zoom-half:hover {\n background: rgba(255, 255, 255, 0.25);\n}\n\n.zoooom-zoom-out {\n border-radius: 36px 0 0 36px;\n border-right: 1px solid rgba(255, 255, 255, 0.4);\n}\n\n.zoooom-zoom-in {\n border-radius: 0 36px 36px 0;\n}\n\n.zoooom-arrows {\n position: absolute;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n pointer-events: none;\n overflow: hidden;\n}\n\n.zoooom-arrow {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n transition: opacity 0.2s;\n}\n\n.zoooom-arrow-n {\n top: 14px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 10px solid transparent;\n border-right: 10px solid transparent;\n border-bottom: 14px solid rgba(255, 255, 255, 0.7);\n}\n\n.zoooom-arrow-e {\n top: 50%;\n right: 14px;\n transform: translateY(-50%);\n border-top: 10px solid transparent;\n border-bottom: 10px solid transparent;\n border-left: 14px solid rgba(255, 255, 255, 0.7);\n}\n\n.zoooom-arrow-s {\n bottom: 14px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 10px solid transparent;\n border-right: 10px solid transparent;\n border-top: 14px solid rgba(255, 255, 255, 0.7);\n}\n\n.zoooom-arrow-w {\n top: 50%;\n left: 14px;\n transform: translateY(-50%);\n border-top: 10px solid transparent;\n border-bottom: 10px solid transparent;\n border-right: 14px solid rgba(255, 255, 255, 0.7);\n}\n\n.zoooom-disc.north .zoooom-arrow-n,\n.zoooom-disc.south .zoooom-arrow-s,\n.zoooom-disc.east .zoooom-arrow-e,\n.zoooom-disc.west .zoooom-arrow-w,\n.zoooom-disc.north-east .zoooom-arrow-n,\n.zoooom-disc.north-east .zoooom-arrow-e,\n.zoooom-disc.south-east .zoooom-arrow-s,\n.zoooom-disc.south-east .zoooom-arrow-e,\n.zoooom-disc.south-west .zoooom-arrow-s,\n.zoooom-disc.south-west .zoooom-arrow-w,\n.zoooom-disc.north-west .zoooom-arrow-n,\n.zoooom-disc.north-west .zoooom-arrow-w {\n opacity: 1;\n}\n\n@media (max-width: 768px) {\n .zoooom-disc {\n width: 140px;\n height: 140px;\n }\n\n .zoooom-inner-circle {\n width: 56px;\n height: 56px;\n }\n\n .zoooom-joystick-toggle {\n width: 48px;\n height: 48px;\n font-size: 16px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .zoooom-joystick-wrap {\n transition: none;\n }\n\n .zoooom-arrow {\n transition: none;\n }\n}\n`;\n\nlet injected = false;\n\nexport function injectJoystickStyles(): void {\n if (injected || typeof document === 'undefined') return;\n const style = document.createElement('style');\n style.setAttribute('data-zoooom-joystick', '');\n style.textContent = JOYSTICK_CSS;\n document.head.appendChild(style);\n injected = true;\n}\n","import type { JoystickOptions } from '../types.js';\nimport { JOYSTICK_RADIUS, JOYSTICK_DEADZONE, MAX_JOYSTICK_SPEED, DWELL_TIMEOUT } from '../core/constants.js';\nimport type { Zoooom } from '../core/Zoooom.js';\nimport { createJoystickDOM, destroyJoystickDOM, type JoystickDOM } from './dom.js';\nimport { injectJoystickStyles } from '../styles/joystick.js';\n\nconst DIRECTIONS = [\n 'east', 'south-east', 'south', 'south-west',\n 'west', 'north-west', 'north', 'north-east',\n] as const;\n\nfunction angleToDirection(angle: number): string {\n if (angle >= -22.5 && angle < 22.5) return 'east';\n if (angle >= 22.5 && angle < 67.5) return 'south-east';\n if (angle >= 67.5 && angle < 112.5) return 'south';\n if (angle >= 112.5 && angle < 157.5) return 'south-west';\n if (angle >= 157.5 || angle < -157.5) return 'west';\n if (angle >= -157.5 && angle < -112.5) return 'north-west';\n if (angle >= -112.5 && angle < -67.5) return 'north';\n return 'north-east';\n}\n\nexport class ZoooomJoystick {\n private viewer: Zoooom;\n private dom: JoystickDOM;\n private options: Required<JoystickOptions>;\n private visible = false;\n private active = false;\n private animationId: number | null = null;\n private joystickX = 0;\n private joystickY = 0;\n private currentDirection = '';\n private dwellTimer: ReturnType<typeof setTimeout> | null = null;\n private isDwelling = false;\n private hideTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(viewer: Zoooom, options?: JoystickOptions) {\n this.viewer = viewer;\n this.options = {\n radius: options?.radius ?? JOYSTICK_RADIUS,\n deadzone: options?.deadzone ?? JOYSTICK_DEADZONE,\n maxSpeed: options?.maxSpeed ?? MAX_JOYSTICK_SPEED,\n position: options?.position ?? 'bottom-center',\n showToggle: options?.showToggle ?? true,\n dwellTimeout: options?.dwellTimeout ?? DWELL_TIMEOUT,\n };\n\n injectJoystickStyles();\n\n const elements = this.viewer.getElements();\n this.dom = createJoystickDOM(elements.container);\n this.bindEvents();\n }\n\n show(): void {\n this.visible = true;\n this.dom.wrap.classList.add('visible');\n this.dom.wrap.setAttribute('aria-hidden', 'false');\n this.dom.toggle.setAttribute('aria-expanded', 'true');\n if (this.hideTimer) clearTimeout(this.hideTimer);\n }\n\n hide(): void {\n this.visible = false;\n this.dom.wrap.classList.remove('visible');\n this.dom.wrap.setAttribute('aria-hidden', 'true');\n this.dom.toggle.setAttribute('aria-expanded', 'false');\n this.stopMovement();\n this.clearDirection();\n }\n\n destroy(): void {\n this.hide();\n this.stopMovement();\n if (this.dwellTimer) clearTimeout(this.dwellTimer);\n if (this.hideTimer) clearTimeout(this.hideTimer);\n destroyJoystickDOM(this.dom);\n }\n\n private bindEvents(): void {\n const { toggle, disc, zoomIn, zoomOut, innerCircle } = this.dom;\n\n // Toggle button\n toggle.addEventListener('click', () => {\n if (this.visible) this.hide();\n else this.show();\n });\n\n toggle.addEventListener('mouseenter', () => this.show());\n toggle.addEventListener('mouseleave', () => {\n this.hideTimer = setTimeout(() => this.hide(), 15000);\n });\n\n // Disc — panning\n disc.addEventListener('mousemove', (e) => {\n if (e.target !== disc) return;\n if (!this.isDwelling) {\n this.startDwell(e);\n } else {\n this.handleMove(e);\n }\n });\n\n disc.addEventListener('mousedown', (e) => {\n if (e.target !== disc) return;\n e.preventDefault();\n this.handleMove(e);\n\n const moveHandler = (me: MouseEvent) => this.handleMove(me);\n document.addEventListener('mousemove', moveHandler);\n document.addEventListener('mouseup', () => {\n document.removeEventListener('mousemove', moveHandler);\n this.stopDwell();\n this.resetJoystick();\n }, { once: true });\n });\n\n disc.addEventListener('mouseleave', () => {\n this.stopDwell();\n this.resetJoystick();\n });\n\n // Touch on disc\n disc.addEventListener('touchstart', (e) => {\n if (e.target !== disc) return;\n e.preventDefault();\n this.handleMove(e);\n\n const moveHandler = (te: TouchEvent) => this.handleMove(te);\n document.addEventListener('touchmove', moveHandler, { passive: false });\n document.addEventListener('touchend', () => {\n document.removeEventListener('touchmove', moveHandler);\n this.stopDwell();\n this.resetJoystick();\n }, { once: true });\n }, { passive: false });\n\n // Zoom buttons\n zoomIn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.viewer.zoomIn();\n });\n\n zoomOut.addEventListener('click', (e) => {\n e.stopPropagation();\n this.viewer.zoomOut();\n });\n\n // Stop panning when entering inner circle\n innerCircle.addEventListener('mouseenter', () => {\n this.stopDwell();\n this.resetJoystick();\n });\n\n innerCircle.addEventListener('mousedown', (e) => e.stopPropagation());\n innerCircle.addEventListener('touchstart', (e) => e.stopPropagation(), { passive: false });\n }\n\n private handleMove(event: MouseEvent | TouchEvent): void {\n if (!this.visible) return;\n\n const clientX = 'clientX' in event ? event.clientX : event.touches[0]?.clientX ?? 0;\n const clientY = 'clientY' in event ? event.clientY : event.touches[0]?.clientY ?? 0;\n\n const rect = this.dom.disc.getBoundingClientRect();\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n const distX = clientX - centerX;\n const distY = clientY - centerY;\n const distance = Math.sqrt(distX * distX + distY * distY);\n\n // Normalize to -1..1\n let normalizedX = distX / this.options.radius;\n let normalizedY = distY / this.options.radius;\n\n if (distance > this.options.radius) {\n normalizedX = normalizedX * (this.options.radius / distance);\n normalizedY = normalizedY * (this.options.radius / distance);\n }\n\n if (Math.abs(normalizedX) < this.options.deadzone) normalizedX = 0;\n if (Math.abs(normalizedY) < this.options.deadzone) normalizedY = 0;\n\n this.joystickX = normalizedX;\n this.joystickY = normalizedY;\n\n // Direction feedback\n if (distance > this.options.radius * this.options.deadzone) {\n const angle = Math.atan2(distY, distX) * 180 / Math.PI;\n const dir = angleToDirection(angle);\n if (dir !== this.currentDirection) {\n this.clearDirection();\n this.dom.disc.classList.add(dir);\n this.currentDirection = dir;\n }\n } else {\n this.clearDirection();\n }\n\n // Start movement if not already running\n if (!this.animationId && (Math.abs(normalizedX) > this.options.deadzone || Math.abs(normalizedY) > this.options.deadzone)) {\n this.active = true;\n this.dom.disc.classList.add('active');\n this.startMovement();\n this.updateAria(normalizedX, normalizedY);\n } else if (Math.abs(normalizedX) <= this.options.deadzone && Math.abs(normalizedY) <= this.options.deadzone) {\n this.active = false;\n this.dom.disc.classList.remove('active');\n this.stopMovement();\n this.dom.disc.setAttribute('aria-valuenow', '0');\n this.dom.disc.setAttribute('aria-valuetext', 'Center position — not moving');\n }\n }\n\n private startDwell(e: MouseEvent | TouchEvent): void {\n if (this.dwellTimer) clearTimeout(this.dwellTimer);\n this.dwellTimer = setTimeout(() => {\n this.isDwelling = true;\n this.handleMove(e);\n }, this.options.dwellTimeout);\n }\n\n private stopDwell(): void {\n if (this.dwellTimer) {\n clearTimeout(this.dwellTimer);\n this.dwellTimer = null;\n }\n this.isDwelling = false;\n }\n\n private startMovement(): void {\n if (this.animationId) return;\n const step = () => {\n if (!this.active) { this.stopMovement(); return; }\n const vx = -this.joystickX * this.options.maxSpeed;\n const vy = -this.joystickY * this.options.maxSpeed;\n this.viewer.applyVelocity(vx, vy);\n this.animationId = requestAnimationFrame(step);\n };\n this.animationId = requestAnimationFrame(step);\n }\n\n private stopMovement(): void {\n if (this.animationId) {\n cancelAnimationFrame(this.animationId);\n this.animationId = null;\n }\n }\n\n private resetJoystick(): void {\n this.joystickX = 0;\n this.joystickY = 0;\n this.active = false;\n this.stopMovement();\n this.clearDirection();\n this.dom.disc.classList.remove('active');\n }\n\n private clearDirection(): void {\n if (this.currentDirection) {\n this.dom.disc.classList.remove(this.currentDirection);\n this.currentDirection = '';\n }\n }\n\n private updateAria(x: number, y: number): void {\n const magnitude = Math.sqrt(x * x + y * y);\n this.dom.disc.setAttribute('aria-valuenow', magnitude.toFixed(2));\n\n let direction: string;\n if (Math.abs(x) > Math.abs(y)) {\n direction = x > 0 ? 'right' : 'left';\n } else {\n direction = y > 0 ? 'down' : 'up';\n }\n\n const intensity = magnitude > 0.7 ? 'fast' : magnitude > 0.3 ? 'medium' : 'slow';\n this.dom.disc.setAttribute('aria-valuetext', `Moving ${intensity} ${direction}`);\n }\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Z as Zoooom, J as JoystickOptions } from './Zoooom-BypxEt9q.cjs';
|
|
2
|
+
|
|
3
|
+
declare class ZoooomJoystick {
|
|
4
|
+
private viewer;
|
|
5
|
+
private dom;
|
|
6
|
+
private options;
|
|
7
|
+
private visible;
|
|
8
|
+
private active;
|
|
9
|
+
private animationId;
|
|
10
|
+
private joystickX;
|
|
11
|
+
private joystickY;
|
|
12
|
+
private currentDirection;
|
|
13
|
+
private dwellTimer;
|
|
14
|
+
private isDwelling;
|
|
15
|
+
private hideTimer;
|
|
16
|
+
constructor(viewer: Zoooom, options?: JoystickOptions);
|
|
17
|
+
show(): void;
|
|
18
|
+
hide(): void;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
private bindEvents;
|
|
21
|
+
private handleMove;
|
|
22
|
+
private startDwell;
|
|
23
|
+
private stopDwell;
|
|
24
|
+
private startMovement;
|
|
25
|
+
private stopMovement;
|
|
26
|
+
private resetJoystick;
|
|
27
|
+
private clearDirection;
|
|
28
|
+
private updateAria;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { JoystickOptions, ZoooomJoystick };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Z as Zoooom, J as JoystickOptions } from './Zoooom-BypxEt9q.js';
|
|
2
|
+
|
|
3
|
+
declare class ZoooomJoystick {
|
|
4
|
+
private viewer;
|
|
5
|
+
private dom;
|
|
6
|
+
private options;
|
|
7
|
+
private visible;
|
|
8
|
+
private active;
|
|
9
|
+
private animationId;
|
|
10
|
+
private joystickX;
|
|
11
|
+
private joystickY;
|
|
12
|
+
private currentDirection;
|
|
13
|
+
private dwellTimer;
|
|
14
|
+
private isDwelling;
|
|
15
|
+
private hideTimer;
|
|
16
|
+
constructor(viewer: Zoooom, options?: JoystickOptions);
|
|
17
|
+
show(): void;
|
|
18
|
+
hide(): void;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
private bindEvents;
|
|
21
|
+
private handleMove;
|
|
22
|
+
private startDwell;
|
|
23
|
+
private stopDwell;
|
|
24
|
+
private startMovement;
|
|
25
|
+
private stopMovement;
|
|
26
|
+
private resetJoystick;
|
|
27
|
+
private clearDirection;
|
|
28
|
+
private updateAria;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { JoystickOptions, ZoooomJoystick };
|
package/dist/joystick.js
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
// src/core/constants.ts
|
|
2
|
+
var JOYSTICK_RADIUS = 60;
|
|
3
|
+
var JOYSTICK_DEADZONE = 0.1;
|
|
4
|
+
var MAX_JOYSTICK_SPEED = 10;
|
|
5
|
+
var DWELL_TIMEOUT = 100;
|
|
6
|
+
|
|
7
|
+
// src/joystick/dom.ts
|
|
8
|
+
function createJoystickDOM(container) {
|
|
9
|
+
const toggle = document.createElement("button");
|
|
10
|
+
toggle.className = "zoooom-joystick-toggle";
|
|
11
|
+
toggle.setAttribute("aria-label", "Toggle navigation joystick");
|
|
12
|
+
toggle.setAttribute("aria-expanded", "false");
|
|
13
|
+
toggle.textContent = "\u2316";
|
|
14
|
+
container.appendChild(toggle);
|
|
15
|
+
const wrap = document.createElement("div");
|
|
16
|
+
wrap.className = "zoooom-joystick-wrap";
|
|
17
|
+
wrap.setAttribute("aria-hidden", "true");
|
|
18
|
+
const disc = document.createElement("div");
|
|
19
|
+
disc.className = "zoooom-disc";
|
|
20
|
+
disc.setAttribute("role", "slider");
|
|
21
|
+
disc.setAttribute("aria-label", "Pan navigation control");
|
|
22
|
+
disc.setAttribute("aria-valuenow", "0");
|
|
23
|
+
disc.setAttribute("aria-valuemin", "0");
|
|
24
|
+
disc.setAttribute("aria-valuemax", "1");
|
|
25
|
+
disc.setAttribute("aria-valuetext", "Center position \u2014 not moving");
|
|
26
|
+
disc.setAttribute("tabindex", "0");
|
|
27
|
+
const innerCircle = document.createElement("div");
|
|
28
|
+
innerCircle.className = "zoooom-inner-circle";
|
|
29
|
+
const zoomOut = document.createElement("div");
|
|
30
|
+
zoomOut.className = "zoooom-zoom-half zoooom-zoom-out";
|
|
31
|
+
zoomOut.setAttribute("role", "button");
|
|
32
|
+
zoomOut.setAttribute("aria-label", "Zoom out");
|
|
33
|
+
zoomOut.setAttribute("tabindex", "0");
|
|
34
|
+
zoomOut.textContent = "\u2212";
|
|
35
|
+
const zoomIn = document.createElement("div");
|
|
36
|
+
zoomIn.className = "zoooom-zoom-half zoooom-zoom-in";
|
|
37
|
+
zoomIn.setAttribute("role", "button");
|
|
38
|
+
zoomIn.setAttribute("aria-label", "Zoom in");
|
|
39
|
+
zoomIn.setAttribute("tabindex", "0");
|
|
40
|
+
zoomIn.textContent = "+";
|
|
41
|
+
innerCircle.appendChild(zoomOut);
|
|
42
|
+
innerCircle.appendChild(zoomIn);
|
|
43
|
+
const arrows = document.createElement("div");
|
|
44
|
+
arrows.className = "zoooom-arrows";
|
|
45
|
+
arrows.setAttribute("aria-hidden", "true");
|
|
46
|
+
for (const dir of ["n", "e", "s", "w"]) {
|
|
47
|
+
const arrow = document.createElement("div");
|
|
48
|
+
arrow.className = `zoooom-arrow zoooom-arrow-${dir}`;
|
|
49
|
+
arrows.appendChild(arrow);
|
|
50
|
+
}
|
|
51
|
+
disc.appendChild(innerCircle);
|
|
52
|
+
disc.appendChild(arrows);
|
|
53
|
+
wrap.appendChild(disc);
|
|
54
|
+
container.appendChild(wrap);
|
|
55
|
+
return { wrap, toggle, disc, innerCircle, zoomIn, zoomOut };
|
|
56
|
+
}
|
|
57
|
+
function destroyJoystickDOM(dom) {
|
|
58
|
+
dom.wrap.remove();
|
|
59
|
+
dom.toggle.remove();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/styles/joystick.ts
|
|
63
|
+
var JOYSTICK_CSS = `
|
|
64
|
+
.zoooom-joystick-wrap {
|
|
65
|
+
position: fixed;
|
|
66
|
+
bottom: 20px;
|
|
67
|
+
left: 50%;
|
|
68
|
+
transform: translateX(-50%);
|
|
69
|
+
z-index: 100;
|
|
70
|
+
touch-action: none;
|
|
71
|
+
opacity: 0;
|
|
72
|
+
pointer-events: none;
|
|
73
|
+
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.zoooom-joystick-wrap.visible {
|
|
77
|
+
opacity: 1;
|
|
78
|
+
pointer-events: auto;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.zoooom-joystick-toggle {
|
|
82
|
+
position: fixed;
|
|
83
|
+
bottom: 20px;
|
|
84
|
+
left: 50%;
|
|
85
|
+
transform: translateX(-50%);
|
|
86
|
+
width: 56px;
|
|
87
|
+
height: 56px;
|
|
88
|
+
border-radius: 50%;
|
|
89
|
+
background: rgba(0, 0, 0, 0.5);
|
|
90
|
+
border: 2px solid rgba(255, 255, 255, 0.6);
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
z-index: 99;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
color: #fff;
|
|
97
|
+
font-size: 20px;
|
|
98
|
+
font-weight: bold;
|
|
99
|
+
backdrop-filter: blur(4px);
|
|
100
|
+
transition: background 0.2s, box-shadow 0.2s;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.zoooom-joystick-toggle:hover {
|
|
104
|
+
background: rgba(0, 0, 0, 0.7);
|
|
105
|
+
box-shadow: 0 0 12px rgba(0, 0, 0, 0.4);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.zoooom-joystick-toggle:focus-visible {
|
|
109
|
+
outline: 2px solid #2196f3;
|
|
110
|
+
outline-offset: 2px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.zoooom-disc {
|
|
114
|
+
width: 200px;
|
|
115
|
+
height: 200px;
|
|
116
|
+
border-radius: 50%;
|
|
117
|
+
background: rgba(0, 0, 0, 0.4);
|
|
118
|
+
border: 2px solid rgba(255, 255, 255, 0.6);
|
|
119
|
+
position: relative;
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
touch-action: none;
|
|
124
|
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.zoooom-disc.active {
|
|
128
|
+
border-color: rgba(255, 255, 255, 0.9);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.zoooom-inner-circle {
|
|
132
|
+
width: 72px;
|
|
133
|
+
height: 72px;
|
|
134
|
+
border-radius: 50%;
|
|
135
|
+
background: rgba(255, 255, 255, 0.15);
|
|
136
|
+
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
137
|
+
display: flex;
|
|
138
|
+
position: relative;
|
|
139
|
+
z-index: 3;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.zoooom-zoom-half {
|
|
143
|
+
width: 50%;
|
|
144
|
+
height: 100%;
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
cursor: pointer;
|
|
149
|
+
font-weight: bold;
|
|
150
|
+
font-size: 22px;
|
|
151
|
+
color: #fff;
|
|
152
|
+
user-select: none;
|
|
153
|
+
transition: background 0.15s;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.zoooom-zoom-half:hover {
|
|
157
|
+
background: rgba(255, 255, 255, 0.25);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.zoooom-zoom-out {
|
|
161
|
+
border-radius: 36px 0 0 36px;
|
|
162
|
+
border-right: 1px solid rgba(255, 255, 255, 0.4);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.zoooom-zoom-in {
|
|
166
|
+
border-radius: 0 36px 36px 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.zoooom-arrows {
|
|
170
|
+
position: absolute;
|
|
171
|
+
width: 100%;
|
|
172
|
+
height: 100%;
|
|
173
|
+
border-radius: 50%;
|
|
174
|
+
pointer-events: none;
|
|
175
|
+
overflow: hidden;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.zoooom-arrow {
|
|
179
|
+
position: absolute;
|
|
180
|
+
width: 0;
|
|
181
|
+
height: 0;
|
|
182
|
+
opacity: 0;
|
|
183
|
+
transition: opacity 0.2s;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.zoooom-arrow-n {
|
|
187
|
+
top: 14px;
|
|
188
|
+
left: 50%;
|
|
189
|
+
transform: translateX(-50%);
|
|
190
|
+
border-left: 10px solid transparent;
|
|
191
|
+
border-right: 10px solid transparent;
|
|
192
|
+
border-bottom: 14px solid rgba(255, 255, 255, 0.7);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.zoooom-arrow-e {
|
|
196
|
+
top: 50%;
|
|
197
|
+
right: 14px;
|
|
198
|
+
transform: translateY(-50%);
|
|
199
|
+
border-top: 10px solid transparent;
|
|
200
|
+
border-bottom: 10px solid transparent;
|
|
201
|
+
border-left: 14px solid rgba(255, 255, 255, 0.7);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.zoooom-arrow-s {
|
|
205
|
+
bottom: 14px;
|
|
206
|
+
left: 50%;
|
|
207
|
+
transform: translateX(-50%);
|
|
208
|
+
border-left: 10px solid transparent;
|
|
209
|
+
border-right: 10px solid transparent;
|
|
210
|
+
border-top: 14px solid rgba(255, 255, 255, 0.7);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.zoooom-arrow-w {
|
|
214
|
+
top: 50%;
|
|
215
|
+
left: 14px;
|
|
216
|
+
transform: translateY(-50%);
|
|
217
|
+
border-top: 10px solid transparent;
|
|
218
|
+
border-bottom: 10px solid transparent;
|
|
219
|
+
border-right: 14px solid rgba(255, 255, 255, 0.7);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.zoooom-disc.north .zoooom-arrow-n,
|
|
223
|
+
.zoooom-disc.south .zoooom-arrow-s,
|
|
224
|
+
.zoooom-disc.east .zoooom-arrow-e,
|
|
225
|
+
.zoooom-disc.west .zoooom-arrow-w,
|
|
226
|
+
.zoooom-disc.north-east .zoooom-arrow-n,
|
|
227
|
+
.zoooom-disc.north-east .zoooom-arrow-e,
|
|
228
|
+
.zoooom-disc.south-east .zoooom-arrow-s,
|
|
229
|
+
.zoooom-disc.south-east .zoooom-arrow-e,
|
|
230
|
+
.zoooom-disc.south-west .zoooom-arrow-s,
|
|
231
|
+
.zoooom-disc.south-west .zoooom-arrow-w,
|
|
232
|
+
.zoooom-disc.north-west .zoooom-arrow-n,
|
|
233
|
+
.zoooom-disc.north-west .zoooom-arrow-w {
|
|
234
|
+
opacity: 1;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@media (max-width: 768px) {
|
|
238
|
+
.zoooom-disc {
|
|
239
|
+
width: 140px;
|
|
240
|
+
height: 140px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.zoooom-inner-circle {
|
|
244
|
+
width: 56px;
|
|
245
|
+
height: 56px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.zoooom-joystick-toggle {
|
|
249
|
+
width: 48px;
|
|
250
|
+
height: 48px;
|
|
251
|
+
font-size: 16px;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@media (prefers-reduced-motion: reduce) {
|
|
256
|
+
.zoooom-joystick-wrap {
|
|
257
|
+
transition: none;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.zoooom-arrow {
|
|
261
|
+
transition: none;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
`;
|
|
265
|
+
var injected = false;
|
|
266
|
+
function injectJoystickStyles() {
|
|
267
|
+
if (injected || typeof document === "undefined") return;
|
|
268
|
+
const style = document.createElement("style");
|
|
269
|
+
style.setAttribute("data-zoooom-joystick", "");
|
|
270
|
+
style.textContent = JOYSTICK_CSS;
|
|
271
|
+
document.head.appendChild(style);
|
|
272
|
+
injected = true;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/joystick/joystick.ts
|
|
276
|
+
function angleToDirection(angle) {
|
|
277
|
+
if (angle >= -22.5 && angle < 22.5) return "east";
|
|
278
|
+
if (angle >= 22.5 && angle < 67.5) return "south-east";
|
|
279
|
+
if (angle >= 67.5 && angle < 112.5) return "south";
|
|
280
|
+
if (angle >= 112.5 && angle < 157.5) return "south-west";
|
|
281
|
+
if (angle >= 157.5 || angle < -157.5) return "west";
|
|
282
|
+
if (angle >= -157.5 && angle < -112.5) return "north-west";
|
|
283
|
+
if (angle >= -112.5 && angle < -67.5) return "north";
|
|
284
|
+
return "north-east";
|
|
285
|
+
}
|
|
286
|
+
var ZoooomJoystick = class {
|
|
287
|
+
constructor(viewer, options) {
|
|
288
|
+
this.visible = false;
|
|
289
|
+
this.active = false;
|
|
290
|
+
this.animationId = null;
|
|
291
|
+
this.joystickX = 0;
|
|
292
|
+
this.joystickY = 0;
|
|
293
|
+
this.currentDirection = "";
|
|
294
|
+
this.dwellTimer = null;
|
|
295
|
+
this.isDwelling = false;
|
|
296
|
+
this.hideTimer = null;
|
|
297
|
+
this.viewer = viewer;
|
|
298
|
+
this.options = {
|
|
299
|
+
radius: options?.radius ?? JOYSTICK_RADIUS,
|
|
300
|
+
deadzone: options?.deadzone ?? JOYSTICK_DEADZONE,
|
|
301
|
+
maxSpeed: options?.maxSpeed ?? MAX_JOYSTICK_SPEED,
|
|
302
|
+
position: options?.position ?? "bottom-center",
|
|
303
|
+
showToggle: options?.showToggle ?? true,
|
|
304
|
+
dwellTimeout: options?.dwellTimeout ?? DWELL_TIMEOUT
|
|
305
|
+
};
|
|
306
|
+
injectJoystickStyles();
|
|
307
|
+
const elements = this.viewer.getElements();
|
|
308
|
+
this.dom = createJoystickDOM(elements.container);
|
|
309
|
+
this.bindEvents();
|
|
310
|
+
}
|
|
311
|
+
show() {
|
|
312
|
+
this.visible = true;
|
|
313
|
+
this.dom.wrap.classList.add("visible");
|
|
314
|
+
this.dom.wrap.setAttribute("aria-hidden", "false");
|
|
315
|
+
this.dom.toggle.setAttribute("aria-expanded", "true");
|
|
316
|
+
if (this.hideTimer) clearTimeout(this.hideTimer);
|
|
317
|
+
}
|
|
318
|
+
hide() {
|
|
319
|
+
this.visible = false;
|
|
320
|
+
this.dom.wrap.classList.remove("visible");
|
|
321
|
+
this.dom.wrap.setAttribute("aria-hidden", "true");
|
|
322
|
+
this.dom.toggle.setAttribute("aria-expanded", "false");
|
|
323
|
+
this.stopMovement();
|
|
324
|
+
this.clearDirection();
|
|
325
|
+
}
|
|
326
|
+
destroy() {
|
|
327
|
+
this.hide();
|
|
328
|
+
this.stopMovement();
|
|
329
|
+
if (this.dwellTimer) clearTimeout(this.dwellTimer);
|
|
330
|
+
if (this.hideTimer) clearTimeout(this.hideTimer);
|
|
331
|
+
destroyJoystickDOM(this.dom);
|
|
332
|
+
}
|
|
333
|
+
bindEvents() {
|
|
334
|
+
const { toggle, disc, zoomIn, zoomOut, innerCircle } = this.dom;
|
|
335
|
+
toggle.addEventListener("click", () => {
|
|
336
|
+
if (this.visible) this.hide();
|
|
337
|
+
else this.show();
|
|
338
|
+
});
|
|
339
|
+
toggle.addEventListener("mouseenter", () => this.show());
|
|
340
|
+
toggle.addEventListener("mouseleave", () => {
|
|
341
|
+
this.hideTimer = setTimeout(() => this.hide(), 15e3);
|
|
342
|
+
});
|
|
343
|
+
disc.addEventListener("mousemove", (e) => {
|
|
344
|
+
if (e.target !== disc) return;
|
|
345
|
+
if (!this.isDwelling) {
|
|
346
|
+
this.startDwell(e);
|
|
347
|
+
} else {
|
|
348
|
+
this.handleMove(e);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
disc.addEventListener("mousedown", (e) => {
|
|
352
|
+
if (e.target !== disc) return;
|
|
353
|
+
e.preventDefault();
|
|
354
|
+
this.handleMove(e);
|
|
355
|
+
const moveHandler = (me) => this.handleMove(me);
|
|
356
|
+
document.addEventListener("mousemove", moveHandler);
|
|
357
|
+
document.addEventListener("mouseup", () => {
|
|
358
|
+
document.removeEventListener("mousemove", moveHandler);
|
|
359
|
+
this.stopDwell();
|
|
360
|
+
this.resetJoystick();
|
|
361
|
+
}, { once: true });
|
|
362
|
+
});
|
|
363
|
+
disc.addEventListener("mouseleave", () => {
|
|
364
|
+
this.stopDwell();
|
|
365
|
+
this.resetJoystick();
|
|
366
|
+
});
|
|
367
|
+
disc.addEventListener("touchstart", (e) => {
|
|
368
|
+
if (e.target !== disc) return;
|
|
369
|
+
e.preventDefault();
|
|
370
|
+
this.handleMove(e);
|
|
371
|
+
const moveHandler = (te) => this.handleMove(te);
|
|
372
|
+
document.addEventListener("touchmove", moveHandler, { passive: false });
|
|
373
|
+
document.addEventListener("touchend", () => {
|
|
374
|
+
document.removeEventListener("touchmove", moveHandler);
|
|
375
|
+
this.stopDwell();
|
|
376
|
+
this.resetJoystick();
|
|
377
|
+
}, { once: true });
|
|
378
|
+
}, { passive: false });
|
|
379
|
+
zoomIn.addEventListener("click", (e) => {
|
|
380
|
+
e.stopPropagation();
|
|
381
|
+
this.viewer.zoomIn();
|
|
382
|
+
});
|
|
383
|
+
zoomOut.addEventListener("click", (e) => {
|
|
384
|
+
e.stopPropagation();
|
|
385
|
+
this.viewer.zoomOut();
|
|
386
|
+
});
|
|
387
|
+
innerCircle.addEventListener("mouseenter", () => {
|
|
388
|
+
this.stopDwell();
|
|
389
|
+
this.resetJoystick();
|
|
390
|
+
});
|
|
391
|
+
innerCircle.addEventListener("mousedown", (e) => e.stopPropagation());
|
|
392
|
+
innerCircle.addEventListener("touchstart", (e) => e.stopPropagation(), { passive: false });
|
|
393
|
+
}
|
|
394
|
+
handleMove(event) {
|
|
395
|
+
if (!this.visible) return;
|
|
396
|
+
const clientX = "clientX" in event ? event.clientX : event.touches[0]?.clientX ?? 0;
|
|
397
|
+
const clientY = "clientY" in event ? event.clientY : event.touches[0]?.clientY ?? 0;
|
|
398
|
+
const rect = this.dom.disc.getBoundingClientRect();
|
|
399
|
+
const centerX = rect.left + rect.width / 2;
|
|
400
|
+
const centerY = rect.top + rect.height / 2;
|
|
401
|
+
const distX = clientX - centerX;
|
|
402
|
+
const distY = clientY - centerY;
|
|
403
|
+
const distance = Math.sqrt(distX * distX + distY * distY);
|
|
404
|
+
let normalizedX = distX / this.options.radius;
|
|
405
|
+
let normalizedY = distY / this.options.radius;
|
|
406
|
+
if (distance > this.options.radius) {
|
|
407
|
+
normalizedX = normalizedX * (this.options.radius / distance);
|
|
408
|
+
normalizedY = normalizedY * (this.options.radius / distance);
|
|
409
|
+
}
|
|
410
|
+
if (Math.abs(normalizedX) < this.options.deadzone) normalizedX = 0;
|
|
411
|
+
if (Math.abs(normalizedY) < this.options.deadzone) normalizedY = 0;
|
|
412
|
+
this.joystickX = normalizedX;
|
|
413
|
+
this.joystickY = normalizedY;
|
|
414
|
+
if (distance > this.options.radius * this.options.deadzone) {
|
|
415
|
+
const angle = Math.atan2(distY, distX) * 180 / Math.PI;
|
|
416
|
+
const dir = angleToDirection(angle);
|
|
417
|
+
if (dir !== this.currentDirection) {
|
|
418
|
+
this.clearDirection();
|
|
419
|
+
this.dom.disc.classList.add(dir);
|
|
420
|
+
this.currentDirection = dir;
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
this.clearDirection();
|
|
424
|
+
}
|
|
425
|
+
if (!this.animationId && (Math.abs(normalizedX) > this.options.deadzone || Math.abs(normalizedY) > this.options.deadzone)) {
|
|
426
|
+
this.active = true;
|
|
427
|
+
this.dom.disc.classList.add("active");
|
|
428
|
+
this.startMovement();
|
|
429
|
+
this.updateAria(normalizedX, normalizedY);
|
|
430
|
+
} else if (Math.abs(normalizedX) <= this.options.deadzone && Math.abs(normalizedY) <= this.options.deadzone) {
|
|
431
|
+
this.active = false;
|
|
432
|
+
this.dom.disc.classList.remove("active");
|
|
433
|
+
this.stopMovement();
|
|
434
|
+
this.dom.disc.setAttribute("aria-valuenow", "0");
|
|
435
|
+
this.dom.disc.setAttribute("aria-valuetext", "Center position \u2014 not moving");
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
startDwell(e) {
|
|
439
|
+
if (this.dwellTimer) clearTimeout(this.dwellTimer);
|
|
440
|
+
this.dwellTimer = setTimeout(() => {
|
|
441
|
+
this.isDwelling = true;
|
|
442
|
+
this.handleMove(e);
|
|
443
|
+
}, this.options.dwellTimeout);
|
|
444
|
+
}
|
|
445
|
+
stopDwell() {
|
|
446
|
+
if (this.dwellTimer) {
|
|
447
|
+
clearTimeout(this.dwellTimer);
|
|
448
|
+
this.dwellTimer = null;
|
|
449
|
+
}
|
|
450
|
+
this.isDwelling = false;
|
|
451
|
+
}
|
|
452
|
+
startMovement() {
|
|
453
|
+
if (this.animationId) return;
|
|
454
|
+
const step = () => {
|
|
455
|
+
if (!this.active) {
|
|
456
|
+
this.stopMovement();
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const vx = -this.joystickX * this.options.maxSpeed;
|
|
460
|
+
const vy = -this.joystickY * this.options.maxSpeed;
|
|
461
|
+
this.viewer.applyVelocity(vx, vy);
|
|
462
|
+
this.animationId = requestAnimationFrame(step);
|
|
463
|
+
};
|
|
464
|
+
this.animationId = requestAnimationFrame(step);
|
|
465
|
+
}
|
|
466
|
+
stopMovement() {
|
|
467
|
+
if (this.animationId) {
|
|
468
|
+
cancelAnimationFrame(this.animationId);
|
|
469
|
+
this.animationId = null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
resetJoystick() {
|
|
473
|
+
this.joystickX = 0;
|
|
474
|
+
this.joystickY = 0;
|
|
475
|
+
this.active = false;
|
|
476
|
+
this.stopMovement();
|
|
477
|
+
this.clearDirection();
|
|
478
|
+
this.dom.disc.classList.remove("active");
|
|
479
|
+
}
|
|
480
|
+
clearDirection() {
|
|
481
|
+
if (this.currentDirection) {
|
|
482
|
+
this.dom.disc.classList.remove(this.currentDirection);
|
|
483
|
+
this.currentDirection = "";
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
updateAria(x, y) {
|
|
487
|
+
const magnitude = Math.sqrt(x * x + y * y);
|
|
488
|
+
this.dom.disc.setAttribute("aria-valuenow", magnitude.toFixed(2));
|
|
489
|
+
let direction;
|
|
490
|
+
if (Math.abs(x) > Math.abs(y)) {
|
|
491
|
+
direction = x > 0 ? "right" : "left";
|
|
492
|
+
} else {
|
|
493
|
+
direction = y > 0 ? "down" : "up";
|
|
494
|
+
}
|
|
495
|
+
const intensity = magnitude > 0.7 ? "fast" : magnitude > 0.3 ? "medium" : "slow";
|
|
496
|
+
this.dom.disc.setAttribute("aria-valuetext", `Moving ${intensity} ${direction}`);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
export { ZoooomJoystick };
|
|
501
|
+
//# sourceMappingURL=joystick.js.map
|
|
502
|
+
//# sourceMappingURL=joystick.js.map
|