kinetic-slider
Version:
A WebGL-powered kinetic slider component using PIXI.js
270 lines (268 loc) • 9.01 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);
class SlidingWindowManager {
/**
* Creates a new SlidingWindowManager
*
* @param options - Configuration options
* @param resourceManager - Optional ResourceManager for resource tracking
*/
constructor(options, resourceManager) {
/** Current active slide index */
__publicField(this, "activeIndex");
/** Size of the window on each side of the active slide */
__publicField(this, "windowSize");
/** Total number of slides */
__publicField(this, "totalSlides");
/** Information about each slide */
__publicField(this, "slides");
/** Whether debug logging is enabled */
__publicField(this, "debug");
/** Resource manager for tracking resources */
__publicField(this, "resourceManager");
/** Direction of the last navigation (-1 for prev, 1 for next, 0 for initial) */
__publicField(this, "lastDirection", 0);
this.windowSize = options.windowSize ?? 2;
this.totalSlides = options.totalSlides;
this.activeIndex = options.initialIndex ?? 0;
this.debug = options.debug ?? false;
this.resourceManager = resourceManager;
this.slides = Array(this.totalSlides).fill(null).map((_, index) => ({
index,
state: "uninitialized" /* UNINITIALIZED */,
inWindow: this.isInWindow(index, this.activeIndex)
}));
this.log(`Initialized with ${this.totalSlides} slides, window size \xB1${this.windowSize}, active index ${this.activeIndex}`);
this.log(`Initial window: ${this.getWindowIndices().join(", ")}`);
}
/**
* Log a message if debug is enabled
*/
log(message, level = "info") {
if (!this.debug) return;
const prefix = `[SlidingWindowManager]`;
switch (level) {
case "info":
console.log(`${prefix} ${message}`);
break;
case "warn":
console.warn(`${prefix} ${message}`);
break;
case "error":
console.error(`${prefix} ${message}`);
break;
}
}
/**
* Check if a slide index is within the current window
*
* @param index - Slide index to check
* @param centerIndex - Center of the window (usually activeIndex)
* @returns Whether the index is within the window
*/
isInWindow(index, centerIndex) {
const distance = Math.abs(index - centerIndex);
return distance <= this.windowSize;
}
/**
* Get all slide indices that should be in the current window
*
* @returns Array of slide indices in the window
*/
getWindowIndices() {
const indices = [];
for (let i = Math.max(0, this.activeIndex - this.windowSize); i <= Math.min(this.totalSlides - 1, this.activeIndex + this.windowSize); i++) {
indices.push(i);
}
return indices;
}
/**
* Get all slide indices that should be in the extended window
* (includes prediction based on navigation direction)
*
* @returns Array of slide indices in the extended window
*/
getExtendedWindowIndices() {
const indices = this.getWindowIndices();
if (this.lastDirection !== 0) {
const extraIndex = this.lastDirection > 0 ? this.activeIndex + this.windowSize + 1 : this.activeIndex - this.windowSize - 1;
if (extraIndex >= 0 && extraIndex < this.totalSlides) {
indices.push(extraIndex);
}
}
return indices;
}
/**
* Update the active slide index and recalculate the window
*
* @param newIndex - New active slide index
* @returns Object containing arrays of indices that entered and left the window
*/
updateActiveIndex(newIndex) {
if (newIndex < 0 || newIndex >= this.totalSlides) {
this.log(`Invalid index: ${newIndex}`, "error");
return { entered: [], left: [] };
}
this.lastDirection = newIndex > this.activeIndex ? 1 : -1;
const oldWindowIndices = this.getWindowIndices();
const oldActiveIndex = this.activeIndex;
this.activeIndex = newIndex;
if (this.slides[newIndex]) {
this.slides[newIndex].state = "active" /* ACTIVE */;
this.slides[newIndex].lastActiveTime = Date.now();
}
if (this.slides[oldActiveIndex] && oldActiveIndex !== newIndex) {
if (this.slides[oldActiveIndex].state === "active" /* ACTIVE */) {
this.slides[oldActiveIndex].state = "loaded" /* LOADED */;
}
}
const newWindowIndices = this.getWindowIndices();
const entered = newWindowIndices.filter((index) => !oldWindowIndices.includes(index));
const left = oldWindowIndices.filter((index) => !newWindowIndices.includes(index));
this.slides.forEach((slide) => {
slide.inWindow = this.isInWindow(slide.index, this.activeIndex);
});
this.log(`Updated active index to ${newIndex}, direction: ${this.lastDirection}`);
this.log(`Window changed: +[${entered.join(", ")}] -[${left.join(", ")}]`);
return { entered, left };
}
/**
* Register a sprite for a slide
*
* @param index - Slide index
* @param sprite - Sprite instance
* @param state - Current state of the slide
*/
registerSlide(index, sprite, state = "loaded" /* LOADED */) {
if (index < 0 || index >= this.totalSlides) {
this.log(`Invalid index for registerSlide: ${index}`, "error");
return;
}
this.slides[index] = {
...this.slides[index],
sprite,
state: index === this.activeIndex ? "active" /* ACTIVE */ : state,
inWindow: this.isInWindow(index, this.activeIndex)
};
this.log(`Registered slide ${index} with state ${state}`);
}
/**
* Update the state of a slide
*
* @param index - Slide index
* @param state - New state
*/
updateSlideState(index, state) {
if (index < 0 || index >= this.totalSlides) {
this.log(`Invalid index for updateSlideState: ${index}`, "error");
return;
}
this.slides[index].state = state;
this.log(`Updated slide ${index} state to ${state}`);
}
/**
* Get information about a slide
*
* @param index - Slide index
* @returns Slide information or null if index is invalid
*/
getSlideInfo(index) {
if (index < 0 || index >= this.totalSlides) {
this.log(`Invalid index for getSlideInfo: ${index}`, "error");
return null;
}
return this.slides[index];
}
/**
* Get the current active index
*
* @returns Active slide index
*/
getActiveIndex() {
return this.activeIndex;
}
/**
* Get all slide information
*
* @returns Array of slide information
*/
getAllSlides() {
return [...this.slides];
}
/**
* Get slides that need to be initialized (converted from UNINITIALIZED to at least PLACEHOLDER)
*
* @returns Array of slide indices that need initialization
*/
getSlidesToInitialize() {
const windowIndices = this.getExtendedWindowIndices();
return windowIndices.filter(
(index) => this.slides[index].state === "uninitialized" /* UNINITIALIZED */
);
}
/**
* Get slides that need to be fully loaded (converted from PLACEHOLDER to LOADED)
*
* @returns Array of slide indices that need to be fully loaded
*/
getSlidesToLoad() {
const windowIndices = this.getWindowIndices();
return windowIndices.filter(
(index) => this.slides[index].state === "placeholder" /* PLACEHOLDER */
);
}
/**
* Get slides that can be unloaded (converted from LOADED to PLACEHOLDER)
*
* @returns Array of slide indices that can be unloaded
*/
getSlidesToUnload() {
return this.slides.filter(
(slide) => !slide.inWindow && (slide.state === "loaded" /* LOADED */ || slide.state === "active" /* ACTIVE */)
).map((slide) => slide.index);
}
/**
* Set the window size
*
* @param size - New window size
*/
setWindowSize(size) {
if (size < 1) {
this.log(`Invalid window size: ${size}, must be at least 1`, "error");
return;
}
this.windowSize = size;
this.slides.forEach((slide) => {
slide.inWindow = this.isInWindow(slide.index, this.activeIndex);
});
this.log(`Window size updated to \xB1${size}`);
}
/**
* Get the current window size
*
* @returns Current window size
*/
getWindowSize() {
return this.windowSize;
}
/**
* Get the last navigation direction
*
* @returns Last direction (-1 for prev, 1 for next, 0 for initial)
*/
getLastDirection() {
return this.lastDirection;
}
/**
* Alias for updateActiveIndex to maintain naming consistency
*
* @param newIndex - New current slide index
* @returns Object containing arrays of indices that entered and left the window
*/
updateCurrentIndex(newIndex) {
return this.updateActiveIndex(newIndex);
}
}
export { SlidingWindowManager as default };
//# sourceMappingURL=SlidingWindowManager.js.map