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.js","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"]}
|