Skip to content

Commit

Permalink
don't use requestAnimationFrame in Canvg.render(); instead render as …
Browse files Browse the repository at this point in the history
…soon as all images and fonts are loaded (#146)
  • Loading branch information
HackbrettXXX authored Sep 24, 2024
1 parent a22564c commit 1b7296f
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 15 deletions.
18 changes: 9 additions & 9 deletions src/Canvg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,17 @@ export default class Canvg {
* Render only first frame, ignoring animations and mouse.
* @param options - Rendering options.
*/
async render(options: IScreenStartOptions = {}) {
this.start({
enableRedraw: true,
ignoreAnimation: true,
ignoreMouse: true,
render(options: Omit<IScreenStartOptions, 'enableRedraw' | 'ignoreMouse' | 'ignoreAnimation'> = {}) {
const {
documentElement,
screen,
options: baseOptions
} = this;

return screen.render(documentElement, {
...baseOptions,
...options
});

await this.ready();

this.stop();
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/Document/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ export default class Document {

this.screen.wait(this.isImagesLoaded.bind(this));
this.screen.wait(this.isFontsLoaded.bind(this));
this.screen.waitPromise(this.loadImages.bind(this));
this.screen.waitPromise(this.loadFonts.bind(this));
}

private bindCreateImage(createImage: CreateImage, anonymousCrossOrigin?: boolean) {
Expand Down Expand Up @@ -178,6 +180,14 @@ export default class Document {
return this.fonts.every(_ => _.loaded);
}

async loadImages(): Promise<void> {
await Promise.all(this.images.map(_ => _.loadingPromise));
}

async loadFonts(): Promise<void> {
await Promise.all(this.fonts.map(_ => _.loadingPromise));
}

createDocumentElement(document: DOMDocument) {
const documentElement = this.createElement<SVGElement>(document.documentElement);

Expand Down
5 changes: 3 additions & 2 deletions src/Document/ImageElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const dataUriRegex = /^\s*data:(([^/,;]+\/[^/,;]+)(?:;([^,;=]+=[^,;=]+))?)?(?:;(
export default class ImageElement extends RenderedElement {
type = 'image';
loaded = false;
loadingPromise: Promise<void>;
protected readonly isSvg: boolean;
protected image: CanvasImageSource | string;

Expand All @@ -32,9 +33,9 @@ export default class ImageElement extends RenderedElement {
document.images.push(this);

if (!isSvg) {
void this.loadImage(href);
this.loadingPromise = this.loadImage(href);
} else {
void this.loadSvg(href);
this.loadingPromise = this.loadSvg(href);
}

this.isSvg = isSvg;
Expand Down
8 changes: 7 additions & 1 deletion src/SVGFontLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ import Document from './Document';

export default class SVGFontLoader {
loaded = false;
loadingPromise: Promise<void>;

constructor(
private readonly document: Document
) {
document.fonts.push(this);
}

async load(fontFamily: string, url: string) {
load(fontFamily: string, url: string) {
this.loadingPromise = this.loadCore(url, fontFamily);
return this.loadingPromise;
}

private async loadCore(fontFamily: string, url: string) {
try {
const {
document
Expand Down
31 changes: 28 additions & 3 deletions src/Screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export default class Screen {
private readyPromise: Promise<void>;
private resolveReady: () => void;
private waits: (() => boolean)[] = [];
private loadingPromises: (() => Promise<void>)[] = [];
private frameDuration = 0;
private isReadyLock = false;
private isFirstRender = true;
Expand All @@ -128,6 +129,10 @@ export default class Screen {
this.waits.push(checker);
}

waitPromise(promise: () => Promise<void>) {
this.loadingPromises.push(promise);
}

ready() {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
if (!this.readyPromise) {
Expand Down Expand Up @@ -157,6 +162,11 @@ export default class Screen {
return isReadyLock;
}

private async finishLoading(): Promise<void> {
await Promise.all(this.loadingPromises.map(_ => _()));
this.loadingPromises = [];
}

setDefaults(ctx: RenderingContext2D) {
// initial values and defaults
ctx.strokeStyle = 'rgba(0,0,0,0)';
Expand Down Expand Up @@ -283,6 +293,21 @@ export default class Screen {
ctx.translate(-minX, -minY);
}

async render(
element: Element,
{
ignoreDimensions = false,
ignoreClear = false,
scaleWidth,
scaleHeight,
offsetX,
offsetY
}: IScreenStartOptions = {}
) {
await this.finishLoading();
this.renderFrame(element, ignoreDimensions, ignoreClear, scaleWidth, scaleHeight, offsetX, offsetY);
}

start(
element: Element,
{
Expand Down Expand Up @@ -310,7 +335,7 @@ export default class Screen {
});

if (this.isReady()) {
this.render(
this.renderFrame(
element,
ignoreDimensions,
ignoreClear,
Expand Down Expand Up @@ -339,7 +364,7 @@ export default class Screen {
ignoreAnimation,
forceRedraw
)) {
this.render(
this.renderFrame(
element,
ignoreDimensions,
ignoreClear,
Expand Down Expand Up @@ -407,7 +432,7 @@ export default class Screen {
return false;
}

private render(
private renderFrame(
element: Element,
ignoreDimensions: boolean,
ignoreClear: boolean,
Expand Down

0 comments on commit 1b7296f

Please sign in to comment.