libpag
Version:
Portable Animated Graphics
172 lines (164 loc) • 5.02 kB
text/typescript
import { WorkerMessageType } from './events';
import { postMessage } from './utils';
import { calculateDisplaySize } from '../utils/canvas';
import { destroyVerify } from '../utils/decorators';
import type { WorkerPAGFile } from './pag-file';
import type { PAGViewOptions } from '../pag-view';
import type { DebugData, PAGScaleMode } from '../types';
export class WorkerPAGView {
/**
* Create pag view.
* @param file pag file.
* @param canvas target render canvas.
* @param initOptions pag view options
* @returns
*/
public static init(file: WorkerPAGFile, canvas: HTMLCanvasElement, initOptions?: PAGViewOptions) {
const options = {
...{
useScale: true,
useCanvas2D: false,
firstFrame: true,
},
...initOptions,
};
if (options.useScale) {
resizeCanvas(canvas);
}
const offscreen = canvas.transferControlToOffscreen();
return postMessage(
file.worker,
{ name: WorkerMessageType.PAGView_init, args: [file.key, offscreen, initOptions] },
(key: number) => new WorkerPAGView(file.worker, key),
[offscreen],
);
}
public key: number;
public worker: Worker;
public isDestroyed = false;
public constructor(worker: Worker, key: number) {
this.worker = worker;
this.key = key;
}
/**
* The duration of current composition in microseconds.
*/
public duration() {
return postMessage(
this.worker,
{ name: WorkerMessageType.PAGView_duration, args: [this.key] },
(res: number) => res,
);
}
/**
* Start the animation.
*/
public play() {
return postMessage(this.worker, { name: WorkerMessageType.PAGView_play, args: [this.key] }, () => undefined);
}
/**
* Pause the animation.
*/
public pause(): Promise<void> {
return postMessage(this.worker, { name: WorkerMessageType.PAGView_pause, args: [this.key] }, () => undefined);
}
/**
* Stop the animation.
*/
public stop(): Promise<void> {
return postMessage(this.worker, { name: WorkerMessageType.PAGView_stop, args: [this.key] }, () => undefined);
}
/**
* Set the number of times the animation will repeat. The default is 1, which means the animation
* will play only once. 0 means the animation will play infinity times.
*/
public setRepeatCount(repeatCount: number): Promise<void> {
return postMessage(
this.worker,
{ name: WorkerMessageType.PAGView_setRepeatCount, args: [this.key, repeatCount] },
() => undefined,
);
}
/**
* Returns the current progress of play position, the value is from 0.0 to 1.0. It is applied only
* when the composition is not null.
*/
public getProgress() {
return postMessage(
this.worker,
{ name: WorkerMessageType.PAGView_getProgress, args: [this.key] },
(res: number) => res,
);
}
/**
* Returns the current frame.
*/
public currentFrame() {
return postMessage(
this.worker,
{ name: WorkerMessageType.PAGView_currentFrame, args: [this.key] },
(res: number) => res,
);
}
/**
* Set the progress of play position, the value is from 0.0 to 1.0.
*/
public setProgress(progress: number) {
return postMessage(
this.worker,
{
name: WorkerMessageType.PAGView_setProgress,
args: [this.key, progress],
},
() => undefined,
);
}
/**
* Returns the current scale mode.
*/
public scaleMode() {
return postMessage(
this.worker,
{ name: WorkerMessageType.PAGView_scaleMode, args: [this.key] },
(res: number) => res,
);
}
/**
* Specifies the rule of how to scale the pag content to fit the surface size. The matrix
* changes when this method is called.
*/
public setScaleMode(value: PAGScaleMode): Promise<void> {
return postMessage(
this.worker,
{ name: WorkerMessageType.PAGView_setScaleMode, args: [this.key, value] },
() => undefined,
);
}
/**
* Call this method to render current position immediately. If the play() method is already
* called, there is no need to call it. Returns true if the content has changed.
*/
public flush() {
return postMessage(this.worker, { name: WorkerMessageType.PAGView_flush, args: [this.key] }, (res: boolean) => res);
}
public getDebugData() {
return postMessage(
this.worker,
{ name: WorkerMessageType.PAGView_getDebugData, args: [this.key] },
(res: DebugData) => res,
);
}
public destroy() {
postMessage(this.worker, { name: WorkerMessageType.PAGView_destroy, args: [this.key] }, () => {
this.isDestroyed = true;
});
}
}
const resizeCanvas = (canvas: HTMLCanvasElement) => {
const displaySize = calculateDisplaySize(canvas);
canvas.style.width = `${displaySize.width}px`;
canvas.style.height = `${displaySize.height}px`;
canvas.width = displaySize.width * globalThis.devicePixelRatio;
canvas.height = displaySize.height * globalThis.devicePixelRatio;
};