UNPKG

@evoke-ui/zsort3d

Version:

TypeScript z-plane rendering engine with 3D depth simulation using Canvas 2D and mouse-based navigation

310 lines 11.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.TouchManager = void 0; const ITouchConfig_1 = require("../interfaces/ITouchConfig"); let Hammer = null; const loadHammer = async () => { if (typeof window === 'undefined') { return null; } if (!Hammer) { Hammer = (await Promise.resolve().then(() => __importStar(require('hammerjs')))).default; } return Hammer; }; class TouchManager { constructor(element, config = {}) { this.hammer = null; this.eventHandlers = new Map(); this.isDestroyed = false; this.lastPanEvent = null; this.hammerLoaded = false; this.element = element; this.config = { ...ITouchConfig_1.DEFAULT_TOUCH_CONFIG, ...this.deepMergeConfig(ITouchConfig_1.DEFAULT_TOUCH_CONFIG, config) }; this.devicePixelRatio = typeof window !== 'undefined' ? (window.devicePixelRatio || 1) : 1; if (typeof window !== 'undefined') { this.init(); } } deepMergeConfig(defaultConfig, userConfig) { const merged = { ...defaultConfig }; if (userConfig.pan) { merged.pan = { ...defaultConfig.pan, ...userConfig.pan }; } if (userConfig.pinch) { merged.pinch = { ...defaultConfig.pinch, ...userConfig.pinch }; } if (userConfig.tap) { merged.tap = { ...defaultConfig.tap, ...userConfig.tap }; } if (userConfig.rotate) { merged.rotate = { ...defaultConfig.rotate, ...userConfig.rotate }; } if (userConfig.performance) { merged.performance = { ...defaultConfig.performance, ...userConfig.performance }; } if (userConfig.device) { merged.device = { ...defaultConfig.device, ...userConfig.device }; } return merged; } async init() { if (!this.config.enabled || this.isDestroyed || typeof window === 'undefined') { return; } const HammerClass = await loadHammer(); if (!HammerClass) { console.warn('TouchManager: Hammer.js could not be loaded'); return; } this.hammerLoaded = true; this.setupCSSTouchAction(); this.createHammerInstance(HammerClass); this.setupGestures(HammerClass); this.setupEventListeners(); this.setupOrientationHandler(); } setupCSSTouchAction() { if (this.config.performance.useCSSTouchAction) { this.element.style.touchAction = 'none'; this.element.style.userSelect = 'none'; this.element.style.webkitUserSelect = 'none'; } } createHammerInstance(HammerClass) { this.hammer = new HammerClass.Manager(this.element, { recognizers: [], inputClass: HammerClass.TouchInput, touchAction: 'none' }); } setupGestures(HammerClass) { if (!this.hammer) return; if (this.config.pan.enabled) { const pan = new HammerClass.Pan({ direction: HammerClass.DIRECTION_ALL, threshold: this.config.pan.threshold, pointers: this.config.pan.pointers }); this.hammer.add(pan); } if (this.config.pinch.enabled) { const pinch = new HammerClass.Pinch({ threshold: this.config.pinch.threshold }); this.hammer.add(pinch); } if (this.config.tap.enabled) { const tap = new HammerClass.Tap({ time: this.config.tap.time, threshold: this.config.tap.threshold, taps: this.config.tap.taps, pointers: this.config.tap.pointers }); this.hammer.add(tap); } if (this.config.rotate.enabled) { const rotate = new HammerClass.Rotate({ threshold: this.config.rotate.threshold }); this.hammer.add(rotate); if (this.config.pinch.enabled) { const pinchRecognizer = this.hammer.get('pinch'); if (pinchRecognizer) { rotate.recognizeWith(pinchRecognizer); } } } if (this.config.pan.enabled && this.config.pinch.enabled) { const panRecognizer = this.hammer.get('pan'); const pinchRecognizer = this.hammer.get('pinch'); if (panRecognizer && pinchRecognizer) { panRecognizer.recognizeWith(pinchRecognizer); } } } setupEventListeners() { if (!this.hammer) return; if (this.config.pan.enabled) { this.hammer.on('panstart panmove panend', this.handlePanEvent.bind(this)); } if (this.config.pinch.enabled) { this.hammer.on('pinchstart pinchmove pinchend', this.handlePinchEvent.bind(this)); } if (this.config.tap.enabled) { this.hammer.on('tap', this.handleTapEvent.bind(this)); } if (this.config.rotate.enabled) { this.hammer.on('rotatestart rotatemove rotateend', this.handleRotateEvent.bind(this)); } } setupOrientationHandler() { if (this.config.device.handleOrientationChange && typeof window !== 'undefined') { window.addEventListener('orientationchange', this.handleOrientationChange.bind(this)); window.addEventListener('resize', this.handleOrientationChange.bind(this)); } } handlePanEvent(e) { if (this.config.performance.preventDefault) { e.preventDefault(); } const now = Date.now(); const baseSensitivity = this.config.pan.sensitivity ?? 1.0; const sensitivity = this.config.device.adaptToPixelRatio ? baseSensitivity * this.devicePixelRatio : baseSensitivity; const throttleTime = this.config.performance.throttle ?? 16; if (this.lastPanEvent && (now - this.lastPanEvent.time) < throttleTime) { return; } const eventData = { type: 'pan', deltaX: e.deltaX * sensitivity, deltaY: e.deltaY * sensitivity, center: { x: e.center.x, y: e.center.y }, velocity: e.velocity, direction: e.direction, originalEvent: e }; this.lastPanEvent = { x: e.center.x, y: e.center.y, time: now }; this.emit('pan', eventData); } handlePinchEvent(e) { if (this.config.performance.preventDefault) { e.preventDefault(); } const baseSensitivity = this.config.pinch.sensitivity ?? 1.0; const sensitivity = this.config.device.adaptToPixelRatio ? baseSensitivity * this.devicePixelRatio : baseSensitivity; const eventData = { type: 'pinch', scale: e.scale * sensitivity, center: { x: e.center.x, y: e.center.y }, originalEvent: e }; this.emit('pinch', eventData); } handleTapEvent(e) { if (this.config.performance.preventDefault) { e.preventDefault(); } const eventData = { type: 'tap', center: { x: e.center.x, y: e.center.y }, originalEvent: e }; this.emit('tap', eventData); } handleRotateEvent(e) { if (this.config.performance.preventDefault) { e.preventDefault(); } const sensitivity = this.config.rotate.sensitivity ?? 1.0; const eventData = { type: 'rotate', rotation: e.rotation * sensitivity, center: { x: e.center.x, y: e.center.y }, originalEvent: e }; this.emit('rotate', eventData); } handleOrientationChange() { if (typeof window !== 'undefined') { setTimeout(() => { this.devicePixelRatio = window.devicePixelRatio || 1; }, 100); } } on(eventType, handler) { if (!this.eventHandlers.has(eventType)) { this.eventHandlers.set(eventType, []); } this.eventHandlers.get(eventType).push(handler); } off(eventType, handler) { const handlers = this.eventHandlers.get(eventType); if (handlers) { const index = handlers.indexOf(handler); if (index > -1) { handlers.splice(index, 1); } } } emit(eventType, data) { const handlers = this.eventHandlers.get(eventType); if (handlers) { handlers.forEach(handler => handler(data)); } } async updateConfig(newConfig) { this.config = { ...this.config, ...this.deepMergeConfig(this.config, newConfig) }; if (newConfig.enabled !== undefined) { this.destroy(); await this.init(); } } getConfig() { return { ...this.config }; } async setEnabled(enabled) { await this.updateConfig({ enabled }); } isEnabled() { return this.config.enabled && !this.isDestroyed && this.hammerLoaded; } destroy() { if (this.isDestroyed) return; this.isDestroyed = true; if (this.hammer) { this.hammer.destroy(); this.hammer = null; } this.eventHandlers.clear(); if (this.config.device.handleOrientationChange && typeof window !== 'undefined') { window.removeEventListener('orientationchange', this.handleOrientationChange.bind(this)); window.removeEventListener('resize', this.handleOrientationChange.bind(this)); } this.element.style.touchAction = ''; this.element.style.userSelect = ''; this.element.style.webkitUserSelect = ''; } } exports.TouchManager = TouchManager; //# sourceMappingURL=TouchManager.js.map