diff --git a/src/lib/FastImageSequence.ts b/src/lib/FastImageSequence.ts index 1c3ad7d..0239228 100644 --- a/src/lib/FastImageSequence.ts +++ b/src/lib/FastImageSequence.ts @@ -146,9 +146,9 @@ export class FastImageSequence { this.mutationObserver.observe(container, {childList: true}); this.inViewportObserver = new IntersectionObserver((entries) => { - entries.forEach(entry => { + for (const entry of entries) { this.inViewport = entry.isIntersecting; - }); + } }); this.inViewportObserver.observe(this.canvas); @@ -230,6 +230,36 @@ export class FastImageSequence { return this.sources[0] as ImageSource; } + /** + * Set number of frames in the image sequence. + */ + public set frameCount(value: number) { + for (const frame of this.frames) { + frame.reset(); + } + this.clearCanvas = true; + + const count = Math.max(1, value | 0); + this.options.frames = count; + + if (count < this.frames.length) { + this.frames = Array.from({length: count}, (_, index) => new Frame(index)); + } else if (count > this.frames.length) { + this.frames = this.frames.concat(Array.from({length: count - this.frames.length}, (_, index) => new Frame(index + this.frames.length))); + } + for (const source of this.sources) { + source.initFrames(); + source.checkImageAvailability(); + } + } + + /** + * Get number of frames in the image sequence. + */ + public get frameCount(): number { + return this.options.frames; + } + private get index(): number { return this.wrapIndex(this.frame); } @@ -352,12 +382,12 @@ export class FastImageSequence { private setLoadingPriority() { const priorityIndex = this.index;// this.wrapIndex(Math.min(this.spread / 2 - 2, (this.frame - this.prevFrame) * (dt * 60)) + this.frame); - this.frames.forEach((image) => { - image.priority = Math.abs(image.index + 0.25 - priorityIndex); + for (const frame of this.frames) { + frame.priority = Math.abs(frame.index + 0.25 - priorityIndex); if (this.options.loop) { - image.priority = Math.min(image.priority, this.options.frames - image.priority); + frame.priority = Math.min(frame.priority, this.options.frames - frame.priority); } - }); + } } private async loadResources() { @@ -405,12 +435,11 @@ export class FastImageSequence { this.frame += this.speed * dt; this.frame = this.wrapFrame(this.frame); - if (this.inViewport) { const index = this.index; // find the best matching loaded frame, based on current index and direction // first set some sort of priority - this.frames.forEach((frame) => { + for (const frame of this.frames) { frame.priority = Math.abs(frame.index - index); let direction = Math.sign(this.frame - this.prevFrame); if (this.options.loop) { @@ -421,7 +450,7 @@ export class FastImageSequence { } } frame.priority += this.direction * direction === -1 ? this.frames.length : 0; - }); + } this.frames.sort((a, b) => b.priority - a.priority); // best loaded image @@ -447,7 +476,7 @@ export class FastImageSequence { private drawFrame(frame: Frame) { const image = frame.image; - if (!image) { + if (!image || frame.index >= this.options.frames) { return; } @@ -473,8 +502,8 @@ export class FastImageSequence { const canvasWidth = (containerAspect > imageAspect ? this.height * containerAspect : this.width) | 0; const canvasHeight = (containerAspect > imageAspect ? this.height : this.width / containerAspect) | 0; - if (this.canvas.width < canvasWidth || this.canvas.height < this.height || this.canvas.width/this.canvas.height !== canvasWidth/canvasHeight) { - // if (this.canvas.width !== canvasWidth || this.canvas.height !== canvasHeight) { + if (this.canvas.width < canvasWidth || this.canvas.height < this.height || this.canvas.width / this.canvas.height !== canvasWidth / canvasHeight) { + // if (this.canvas.width !== canvasWidth || this.canvas.height !== canvasHeight) { this.canvas.width = canvasWidth; this.canvas.height = canvasHeight; } @@ -483,8 +512,8 @@ export class FastImageSequence { const canvasWidth = (containerAspect > imageAspect ? this.width : this.height * containerAspect) | 0; const canvasHeight = (containerAspect > imageAspect ? this.width / containerAspect : this.height) | 0; - if (this.canvas.width < canvasWidth || this.canvas.height < this.height || this.canvas.width/this.canvas.height !== canvasWidth/canvasHeight) { - // if (this.canvas.width !== canvasWidth || this.canvas.height !== canvasHeight) { + if (this.canvas.width < canvasWidth || this.canvas.height < this.height || this.canvas.width / this.canvas.height !== canvasWidth / canvasHeight) { + // if (this.canvas.width !== canvasWidth || this.canvas.height !== canvasHeight) { this.canvas.width = canvasWidth; this.canvas.height = canvasHeight; } diff --git a/src/lib/Frame.ts b/src/lib/Frame.ts index b273c08..195b3f9 100644 --- a/src/lib/Frame.ts +++ b/src/lib/Frame.ts @@ -35,4 +35,8 @@ export default class Frame { public releaseImage() { this.images.forEach(image => image.releaseImage()); } + + public reset() { + this.images.forEach(image => image.reset()); + } } \ No newline at end of file diff --git a/src/lib/ImageSource.ts b/src/lib/ImageSource.ts index 5af6117..ef985d8 100644 --- a/src/lib/ImageSource.ts +++ b/src/lib/ImageSource.ts @@ -55,7 +55,11 @@ export default class ImageSource { this.index = index; this.options = {...ImageSource.defaultOptions, ...options}; - this.context.frames.forEach(frame => frame.images[index] = new ImageElement(this, frame)); + this.initFrames(); + } + + public initFrames() { + this.context.frames.forEach(frame => frame.images[this.index] ||= new ImageElement(this, frame)); } public get type() { @@ -85,14 +89,17 @@ export default class ImageSource { return undefined; } - public async loadResources() { + public checkImageAvailability() { for (const image of this.images) { image.available = this.available(image, image.available); } if (!this.images[0]?.available) { throw new Error(`No image available for index 0 in ImageSource${this.index} (${this.images[0]?.imageURL})`); } + } + public async loadResources() { + this.checkImageAvailability(); this.initialized = true; } diff --git a/src/lib/ImageSourceFetch.ts b/src/lib/ImageSourceFetch.ts index 32a6a1e..49d4a84 100644 --- a/src/lib/ImageSourceFetch.ts +++ b/src/lib/ImageSourceFetch.ts @@ -28,7 +28,7 @@ export default class ImageSourceFetch extends ImageSource { }).catch(e => reject(e)); } } else { - reject('Image url not set or image allready loading'); + reject('Image url not set or image already loading'); } }); }