kinetic-slider
Version:
A WebGL-powered kinetic slider component using PIXI.js
217 lines (215 loc) • 7.2 kB
JavaScript
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);
var ThrottleStrategy = /* @__PURE__ */ ((ThrottleStrategy2) => {
ThrottleStrategy2["FIXED_FPS"] = "fixed_fps";
ThrottleStrategy2["ADAPTIVE"] = "adaptive";
ThrottleStrategy2["PRIORITY"] = "priority";
ThrottleStrategy2["NONE"] = "none";
return ThrottleStrategy2;
})(ThrottleStrategy || {});
const DEFAULT_CONFIG = {
targetFps: 60,
minFps: 30,
maxFps: 120,
strategy: "fixed_fps" /* FIXED_FPS */,
enableMonitoring: true
};
class FrameThrottler {
/**
* Create a new FrameThrottler with the specified configuration.
*
* @param {ThrottlerConfig} [config] - Configuration options for the throttler
*
* @example
* // Create a throttler with default settings (60fps, FIXED_FPS strategy)
* const throttler = new FrameThrottler();
*
* @example
* // Create a throttler with custom settings
* const throttler = new FrameThrottler({
* targetFps: 30,
* strategy: ThrottleStrategy.ADAPTIVE,
* minFps: 15,
* maxFps: 60
* });
*/
constructor(config) {
/** Active configuration */
__publicField(this, "config");
/** Performance monitoring data */
__publicField(this, "performance");
/** Timestamp of the last processed frame */
__publicField(this, "lastFrameTime", 0);
this.config = { ...DEFAULT_CONFIG, ...config };
this.performance = {
frameTimes: [],
currentFps: this.config.targetFps,
frameCount: 0,
lastAdjustment: performance.now(),
currentInterval: this.calculateInterval(this.config.targetFps)
};
this.lastFrameTime = performance.now();
}
/**
* Calculate the frame interval in milliseconds from FPS.
*
* @param {number} fps - Frames per second
* @returns {number} Interval in milliseconds between frames
* @private
*/
calculateInterval(fps) {
return 1e3 / fps;
}
/**
* Check if enough time has passed to process the next frame.
*
* @param {number} [priority] - Optional priority level to consider (higher values bypass more throttling)
* @returns {boolean} True if the frame should be processed, false if it should be skipped
*
* @example
* // Basic usage in animation loop
* if (throttler.shouldProcessFrame()) {
* // Process frame
* render();
* throttler.frameProcessed();
* }
*
* @example
* // Usage with priority (3 is highest priority)
* if (throttler.shouldProcessFrame(2)) {
* // Process high-priority frame
* renderImportantElements();
* throttler.frameProcessed();
* }
*/
shouldProcessFrame(priority) {
const now = performance.now();
const elapsed = now - this.lastFrameTime;
switch (this.config.strategy) {
case "none" /* NONE */:
return true;
case "priority" /* PRIORITY */:
if (priority !== void 0 && priority >= 2) {
return true;
}
return elapsed >= this.performance.currentInterval;
case "adaptive" /* ADAPTIVE */:
this.updateAdaptivePerformance(now);
return elapsed >= this.performance.currentInterval;
case "fixed_fps" /* FIXED_FPS */:
default:
return elapsed >= this.performance.currentInterval;
}
}
/**
* Mark the current frame as processed and update timing metrics.
* Should be called after processing a frame that passed the shouldProcessFrame check.
*
* @example
* if (throttler.shouldProcessFrame()) {
* // Process frame
* render();
* throttler.frameProcessed();
* }
*/
frameProcessed() {
const now = performance.now();
const frameDuration = now - this.lastFrameTime;
this.lastFrameTime = now;
if (this.config.enableMonitoring) {
this.updatePerformanceMetrics(frameDuration);
}
}
/**
* Update performance metrics with the latest frame duration.
*
* @param {number} frameDuration - Duration of the last frame in milliseconds
* @private
*/
updatePerformanceMetrics(frameDuration) {
this.performance.frameTimes.push(frameDuration);
if (this.performance.frameTimes.length > 60) {
this.performance.frameTimes.shift();
}
const avgFrameDuration = this.performance.frameTimes.reduce((sum, time) => sum + time, 0) / this.performance.frameTimes.length;
this.performance.currentFps = 1e3 / avgFrameDuration;
this.performance.frameCount++;
}
/**
* Update adaptive performance settings based on recent metrics.
* This method adjusts the frame rate based on the device's capabilities.
*
* @param {number} now - Current timestamp in milliseconds
* @private
*/
updateAdaptivePerformance(now) {
if (now - this.performance.lastAdjustment < 1e3 || this.performance.frameTimes.length < 10) {
return;
}
const avgFps = this.performance.currentFps;
let targetFps = this.config.targetFps;
if (avgFps < this.config.minFps) {
targetFps = Math.max(this.config.minFps, targetFps * 0.8);
} else if (avgFps > this.config.maxFps) {
targetFps = Math.min(this.config.maxFps, targetFps * 1.2);
} else if (avgFps > targetFps * 1.2) {
targetFps = Math.min(this.config.maxFps, targetFps * 1.1);
}
this.performance.currentInterval = this.calculateInterval(targetFps);
this.performance.lastAdjustment = now;
}
/**
* Set a specific throttling strategy.
*
* @param {ThrottleStrategy} strategy - The throttling strategy to use
*
* @example
* // Switch to adaptive strategy based on device capability
* if (isLowEndDevice) {
* throttler.setStrategy(ThrottleStrategy.ADAPTIVE);
* }
*/
setStrategy(strategy) {
this.config.strategy = strategy;
}
/**
* Set a specific target FPS.
*
* @param {number} fps - Target frames per second (must be > 0)
*
* @example
* // Reduce target FPS to save battery
* if (isBatteryLow) {
* throttler.setTargetFps(30);
* } else {
* throttler.setTargetFps(60);
* }
*/
setTargetFps(fps) {
this.config.targetFps = Math.max(1, fps);
if (this.config.strategy === "fixed_fps" /* FIXED_FPS */) {
this.performance.currentInterval = this.calculateInterval(this.config.targetFps);
}
}
/**
* Get current performance metrics for monitoring and debugging.
*
* @returns {Object} Performance information including current FPS, interval, frame count, and strategy
*
* @example
* // Log performance metrics
* console.log(throttler.getPerformanceMetrics());
* // Example output: { currentFps: 58.2, targetInterval: 16.67, frameCount: 1242, strategy: 'fixed_fps' }
*/
getPerformanceMetrics() {
return {
currentFps: this.performance.currentFps,
targetInterval: this.performance.currentInterval,
frameCount: this.performance.frameCount,
strategy: this.config.strategy
};
}
}
export { FrameThrottler, ThrottleStrategy };
//# sourceMappingURL=FrameThrottler.js.map