UNPKG

kinetic-slider

Version:

A WebGL-powered kinetic slider component using PIXI.js

293 lines (288 loc) 8.82 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var UpdateTypes = require('./UpdateTypes.cjs'); var FrameThrottler = require('./FrameThrottler.cjs'); var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); const _RenderScheduler = class _RenderScheduler { /** * Private constructor for singleton pattern. * @private */ constructor() { /** Map of task IDs to pending update tasks */ __publicField(this, "updateQueue", /* @__PURE__ */ new Map()); /** Whether the processing loop is active */ __publicField(this, "isProcessing", false); /** Current requestAnimationFrame ID or null if not active */ __publicField(this, "rafId", null); /** Timestamp of the last frame execution */ __publicField(this, "lastFrameTime", 0); /** Minimum time between frames in milliseconds (~60fps default) */ __publicField(this, "frameThrottle", 16); /** Frame throttler for advanced timing control */ __publicField(this, "frameThrottler"); this.lastFrameTime = performance.now(); this.frameThrottler = new FrameThrottler.FrameThrottler({ targetFps: 60, strategy: FrameThrottler.ThrottleStrategy.PRIORITY, enableMonitoring: true }); } /** * Get the singleton instance of the RenderScheduler. * @returns {RenderScheduler} The singleton instance */ static getInstance() { if (!_RenderScheduler.instance) { _RenderScheduler.instance = new _RenderScheduler(); } return _RenderScheduler.instance; } /** * Schedule a task for execution. * If a task with the same ID already exists, it will be replaced. * * @param {string} id - Unique identifier for the task * @param {() => void} callback - Function to execute * @param {UpdatePriority} [priority=UpdatePriority.NORMAL] - Priority level * @returns {RenderScheduler} The scheduler instance for chaining * * @example * ```typescript * scheduler.scheduleUpdate('update-text', () => { * element.textContent = 'Updated text'; * }, UpdatePriority.NORMAL); * ``` */ scheduleUpdate(id, callback, priority = 1 /* NORMAL */) { this.updateQueue.set(id, { id, callback, priority, timestamp: performance.now() }); this.startProcessing(); return this; } /** * Schedule an update using a standard update type. * This provides a more semantic API for scheduling updates. * * @param {string} componentId - ID of the component requesting the update * @param {UpdateType} updateType - Type of update * @param {() => void} callback - Function to execute * @param {string} [suffix] - Optional suffix for the update ID * @returns {RenderScheduler} The scheduler instance for chaining * * @example * ```typescript * scheduler.scheduleTypedUpdate( * 'slider', * UpdateType.SLIDE_TRANSFORM, * () => updateSlidePosition() * ); * ``` */ scheduleTypedUpdate(componentId, updateType, callback, suffix) { const id = UpdateTypes.createUpdateId(componentId, updateType, suffix); const priority = UpdateTypes.getPriorityForUpdateType(updateType); return this.scheduleUpdate(id, callback, priority); } /** * Cancel a scheduled update. * * @param {string} id - ID of the task to cancel * @returns {boolean} True if a task was found and removed * * @example * ```typescript * const wasRemoved = scheduler.cancelUpdate('update-text'); * console.log(`Update was ${wasRemoved ? 'successfully' : 'not'} canceled`); * ``` */ cancelUpdate(id) { return this.updateQueue.delete(id); } /** * Cancel an update that was scheduled with a standard update type. * * @param {string} componentId - ID of the component that scheduled the update * @param {UpdateType} updateType - Type of update to cancel * @param {string} [suffix] - Optional suffix from the update ID * @returns {boolean} True if a task was found and removed * * @example * ```typescript * scheduler.cancelTypedUpdate('slider', UpdateType.SLIDE_TRANSFORM); * ``` */ cancelTypedUpdate(componentId, updateType, suffix) { const id = UpdateTypes.createUpdateId(componentId, updateType, suffix); return this.cancelUpdate(id); } /** * Immediately execute a task with CRITICAL priority. * Bypasses the queue but still respects frame throttling. * * @param {() => void} callback - Function to execute immediately * * @example * ```typescript * scheduler.executeImmediate(() => { * // Handle urgent user input * processCriticalUserAction(); * }); * ``` */ executeImmediate(callback) { const id = `immediate-${performance.now()}`; this.scheduleUpdate(id, callback, 3 /* CRITICAL */); this.processQueue(); } /** * Start the processing loop if not already running. * @private */ startProcessing() { if (this.isProcessing || this.updateQueue.size === 0) return; this.isProcessing = true; this.processQueue(); } /** * Process the queue using requestAnimationFrame for timing. * @private */ processQueue() { if (this.rafId !== null) { cancelAnimationFrame(this.rafId); this.rafId = null; } this.rafId = requestAnimationFrame(() => { const now = performance.now(); let highestPriority = 0; this.updateQueue.forEach((task) => { if (task.priority > highestPriority) { highestPriority = task.priority; } }); if (this.frameThrottler.shouldProcessFrame(highestPriority)) { this.executeQueuedTasks(); this.frameThrottler.frameProcessed(); this.lastFrameTime = now; } if (this.updateQueue.size > 0) { this.processQueue(); } else { this.isProcessing = false; this.rafId = null; } }); } /** * Execute all queued tasks in priority order. * @private */ executeQueuedTasks() { if (this.updateQueue.size === 0) return; const tasks = Array.from(this.updateQueue.values()).sort((a, b) => { if (a.priority !== b.priority) { return b.priority - a.priority; } return a.timestamp - b.timestamp; }); this.updateQueue.clear(); tasks.forEach((task) => { try { task.callback(); } catch (error) { console.error(`Error executing task ${task.id}:`, error); } }); } /** * Set the frame throttle rate. * * @param {number} milliseconds - Minimum time between frames * * @example * ```typescript * // Set to 30fps (33.33ms between frames) * scheduler.setFrameThrottle(33.33); * ``` */ setFrameThrottle(milliseconds) { this.frameThrottle = Math.max(0, milliseconds); } /** * Get current queue size for debugging. * * @returns {number} Number of tasks currently in the queue * * @example * ```typescript * const queueSize = scheduler.getQueueSize(); * console.log(`Current queue size: ${queueSize}`); * ``` */ getQueueSize() { return this.updateQueue.size; } /** * Clear all pending updates. * * @example * ```typescript * // Cancel all pending updates (e.g., when component unmounts) * scheduler.clearQueue(); * ``` */ clearQueue() { this.updateQueue.clear(); } /** * Configure frame throttling behavior. * * @param {ThrottlerConfig} config - Throttling configuration options * * @example * ```typescript * scheduler.configureThrottling({ * targetFps: 30, * strategy: ThrottleStrategy.ADAPTIVE * }); * ``` */ configureThrottling(config) { if (config.strategy !== void 0) { this.frameThrottler.setStrategy(config.strategy); } if (config.targetFps !== void 0) { this.frameThrottler.setTargetFps(config.targetFps); } } /** * Get current performance metrics. * * @returns {Object} Performance metrics including queue size and frame rate * * @example * ```typescript * const metrics = scheduler.getPerformanceMetrics(); * console.log(`Current FPS: ${metrics.currentFps}`); * ``` */ getPerformanceMetrics() { return { queueSize: this.getQueueSize(), ...this.frameThrottler.getPerformanceMetrics() }; } }; /** Singleton instance of the scheduler */ __publicField(_RenderScheduler, "instance"); let RenderScheduler = _RenderScheduler; exports.RenderScheduler = RenderScheduler; exports.default = RenderScheduler; //# sourceMappingURL=RenderScheduler.cjs.map