Skip to content

Commit

Permalink
Added a method to change frame count after initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
reindernijhoff committed Jan 6, 2025
1 parent 380c3a8 commit 167b62c
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 17 deletions.
57 changes: 43 additions & 14 deletions src/lib/FastImageSequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
4 changes: 4 additions & 0 deletions src/lib/Frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ export default class Frame {
public releaseImage() {
this.images.forEach(image => image.releaseImage());
}

public reset() {
this.images.forEach(image => image.reset());
}
}
11 changes: 9 additions & 2 deletions src/lib/ImageSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/ImageSourceFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
});
}
Expand Down

0 comments on commit 167b62c

Please sign in to comment.