Skip to content

Commit

Permalink
fix: change canvas' init hook frin async to sync #1117
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Jun 12, 2023
1 parent e8fe6ec commit 24352cd
Show file tree
Hide file tree
Showing 41 changed files with 455 additions and 310 deletions.
2 changes: 1 addition & 1 deletion packages/g-canvas/src/Canvas2DContextService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class Canvas2DContextService
this.canvasConfig = context.config;
}

async init() {
init() {
const { container, canvas } = this.canvasConfig;

if (canvas) {
Expand Down
36 changes: 25 additions & 11 deletions packages/g-canvaskit/src/CanvasKitContextService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ export interface ContextRegisterPluginOptions {
/**
* @see https://skia.org/docs/user/modules/quickstart/
*/
export class CanvasKitContextService implements ContextService<CanvasKitContext> {
export class CanvasKitContextService
implements ContextService<CanvasKitContext>
{
private $container: HTMLElement | null;
private $canvas: CanvasLike | null;
private dpr: number;
Expand All @@ -35,21 +37,26 @@ export class CanvasKitContextService implements ContextService<CanvasKitContext>
this.contextRegisterPluginOptions = context.contextRegisterPluginOptions;
}

async init() {
async initAsync() {
const { container, canvas, devicePixelRatio } = this.canvasConfig;

if (canvas) {
this.$canvas = canvas;

if (container && (canvas as HTMLCanvasElement).parentElement !== container) {
if (
container &&
(canvas as HTMLCanvasElement).parentElement !== container
) {
(container as HTMLElement).appendChild(canvas as HTMLCanvasElement);
}

this.$container = (canvas as HTMLCanvasElement).parentElement;
this.canvasConfig.container = this.$container;
} else if (container) {
// create container
this.$container = isString(container) ? document.getElementById(container) : container;
this.$container = isString(container)
? document.getElementById(container)
: container;
if (this.$container) {
// create canvas
const $canvas = document.createElement('canvas');
Expand All @@ -70,7 +77,9 @@ export class CanvasKitContextService implements ContextService<CanvasKitContext>

// making surface must after canvas init
const CanvasKit = await this.loadCanvaskit();
const surface = CanvasKit.MakeWebGLCanvasSurface(this.$canvas as HTMLCanvasElement);
const surface = CanvasKit.MakeWebGLCanvasSurface(
this.$canvas as HTMLCanvasElement,
);
this.context = {
surface,
CanvasKit,
Expand All @@ -96,11 +105,13 @@ export class CanvasKitContextService implements ContextService<CanvasKitContext>
}

destroy() {
// @ts-ignore
if (this.$container && this.$canvas && this.$canvas.parentNode) {
if (
this.$container &&
this.$canvas &&
(this.$canvas as HTMLCanvasElement).parentNode
) {
// destroy context
// @ts-ignore
this.$container.removeChild(this.$canvas);
this.$container.removeChild(this.$canvas as HTMLCanvasElement);
}
}

Expand All @@ -122,12 +133,15 @@ export class CanvasKitContextService implements ContextService<CanvasKitContext>
}

async toDataURL(options: Partial<DataURLOptions>) {
return this.contextRegisterPluginOptions.canvaskitRendererPlugin.toDataURL(options);
return this.contextRegisterPluginOptions.canvaskitRendererPlugin.toDataURL(
options,
);
}

private loadCanvaskit(): Promise<CanvasKit> {
return CanvasKitInit({
locateFile: (file: string) => this.contextRegisterPluginOptions.wasmDir + file,
locateFile: (file: string) =>
this.contextRegisterPluginOptions.wasmDir + file,
});
}
}
73 changes: 50 additions & 23 deletions packages/g-lite/src/Canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export enum CanvasEvent {
AFTER_DESTROY = 'afterdestroy',
RESIZE = 'resize',
DIRTY_RECTANGLE = 'dirtyrectangle',
RENDERER_CHANGED = 'rendererchanged',
}

const DEFAULT_CAMERA_Z = 500;
Expand Down Expand Up @@ -228,15 +229,7 @@ export class Canvas extends EventTarget implements ICanvas {

this.initDefaultCamera(canvasWidth, canvasHeight);

(async () => {
await this.initRenderer(renderer);

this.dispatchEvent(new CustomEvent(CanvasEvent.READY));

if (this.readyPromise) {
this.resolveReadyPromise();
}
})();
this.initRenderer(renderer, true);
}

private initRenderingContext(mergedConfig: CanvasConfig) {
Expand Down Expand Up @@ -473,12 +466,12 @@ export class Canvas extends EventTarget implements ICanvas {
private run() {
const tick = () => {
this.render();
this.frameId = requestAnimationFrame(tick);
this.frameId = this.requestAnimationFrame(tick);
};
tick();
}

private async initRenderer(renderer: IRenderer) {
private initRenderer(renderer: IRenderer, firstContentfullPaint = false) {
if (!renderer) {
throw new Error('Renderer is required.');
}
Expand Down Expand Up @@ -514,19 +507,53 @@ export class Canvas extends EventTarget implements ICanvas {
// init event service
this.context.eventService = new EventService(runtime, this.context);
this.context.eventService.init();
await this.context.contextService.init();
await this.context.renderingService.init();

if (this.context.contextService.init) {
this.context.contextService.init();
this.initRenderingService(renderer, firstContentfullPaint);
if (firstContentfullPaint) {
this.requestAnimationFrame(() => {
this.dispatchEvent(new CustomEvent(CanvasEvent.READY));
});
if (this.readyPromise) {
this.resolveReadyPromise();
}
} else {
this.dispatchEvent(new CustomEvent(CanvasEvent.RENDERER_CHANGED));
}
} else {
this.context.contextService.initAsync().then(() => {
this.initRenderingService(renderer, firstContentfullPaint);
if (firstContentfullPaint) {
this.dispatchEvent(new CustomEvent(CanvasEvent.READY));
if (this.readyPromise) {
this.resolveReadyPromise();
}
} else {
this.dispatchEvent(new CustomEvent(CanvasEvent.RENDERER_CHANGED));
}
});
}
}

private initRenderingService(
renderer: IRenderer,
firstContentfullPaint = false,
) {
this.context.renderingService.init();

this.inited = true;

this.getRoot().forEach((node) => {
const renderable = (node as Element).renderable;
if (renderable) {
renderable.renderBoundsDirty = true;
renderable.boundsDirty = true;
renderable.dirty = true;
}
});
if (!firstContentfullPaint) {
this.getRoot().forEach((node) => {
const renderable = (node as Element).renderable;
if (renderable) {
renderable.renderBoundsDirty = true;
renderable.boundsDirty = true;
renderable.dirty = true;
}
});
}

// keep current scenegraph unchanged, just trigger mounted event
this.mountChildren(this.getRoot());
Expand All @@ -545,7 +572,7 @@ export class Canvas extends EventTarget implements ICanvas {
});
}

async setRenderer(renderer: IRenderer) {
setRenderer(renderer: IRenderer) {
// update canvas' config
const canvasConfig = this.getConfig();
if (canvasConfig.renderer === renderer) {
Expand All @@ -563,7 +590,7 @@ export class Canvas extends EventTarget implements ICanvas {
plugin.destroy(runtime);
});

await this.initRenderer(renderer);
this.initRenderer(renderer);
}

setCursor(cursor: Cursor) {
Expand Down
24 changes: 9 additions & 15 deletions packages/g-lite/src/plugins/PrepareRendererPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,15 @@ export class PrepareRendererPlugin implements RenderingPlugin {
renderingService.dirtify();
};

renderingService.hooks.init.tapPromise(
PrepareRendererPlugin.tag,
async () => {
canvas.addEventListener(ElementEvent.MOUNTED, handleMounted);
canvas.addEventListener(ElementEvent.UNMOUNTED, handleUnmounted);
canvas.addEventListener(
ElementEvent.ATTR_MODIFIED,
handleAttributeChanged,
);
canvas.addEventListener(
ElementEvent.BOUNDS_CHANGED,
handleBoundsChanged,
);
},
);
renderingService.hooks.init.tap(PrepareRendererPlugin.tag, () => {
canvas.addEventListener(ElementEvent.MOUNTED, handleMounted);
canvas.addEventListener(ElementEvent.UNMOUNTED, handleUnmounted);
canvas.addEventListener(
ElementEvent.ATTR_MODIFIED,
handleAttributeChanged,
);
canvas.addEventListener(ElementEvent.BOUNDS_CHANGED, handleBoundsChanged);
});

renderingService.hooks.destroy.tap(PrepareRendererPlugin.tag, () => {
canvas.removeEventListener(ElementEvent.MOUNTED, handleMounted);
Expand Down
9 changes: 7 additions & 2 deletions packages/g-lite/src/services/ContextService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type { CanvasLike } from '../types';

export type DataURLType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/bmp';
export type DataURLType =
| 'image/png'
| 'image/jpeg'
| 'image/webp'
| 'image/bmp';
/**
* The created image data will have a resolution of 96dpi.
* @see https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL#%E5%8F%82%E6%95%B0
Expand All @@ -18,7 +22,8 @@ export interface DataURLOptions {

// 1 of 1 in each Canvas
export interface ContextService<Context> {
init: () => Promise<void>;
init?: () => void;
initAsync?: () => Promise<void>;
destroy: () => void;
getContext: () => Context | null;
getDomElement: () => CanvasLike | null;
Expand Down
8 changes: 3 additions & 5 deletions packages/g-lite/src/services/RenderingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type {
CanvasConfig,
} from '../types';
import {
AsyncParallelHook,
AsyncSeriesWaterfallHook,
sortByZIndex,
sortedIndex,
Expand Down Expand Up @@ -72,7 +71,7 @@ export class RenderingService {
/**
* called before any frame rendered
*/
init: new AsyncParallelHook<[]>(),
init: new SyncHook<[]>(),
/**
* only dirty object which has sth changed will be rendered
*/
Expand Down Expand Up @@ -121,15 +120,14 @@ export class RenderingService {
click: new SyncHook<[InteractivePointerEvent]>(),
};

async init() {
init() {
const context = { ...this.globalRuntime, ...this.context };

// register rendering plugins
this.context.renderingPlugins.forEach((plugin) => {
plugin.apply(context, runtime);
});
// await this.hooks.init.callPromise();
await this.hooks.init.promise();
this.hooks.init.call();
this.inited = true;
}

Expand Down
3 changes: 1 addition & 2 deletions packages/g-lite/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { vec2, vec3 } from 'gl-matrix';
import type { IEventTarget } from '.';
import type { IRenderer } from './AbstractRenderer';
import type {
CSSGlobalKeywords,
Expand Down Expand Up @@ -363,7 +362,7 @@ export interface RendererConfig {
/**
* eg. NodeCanvas, OffscreenCanvas, HTMLCanvasElement
*/
export interface CanvasLike extends IEventTarget {
export interface CanvasLike extends EventTarget {
width: number;
height: number;

Expand Down
22 changes: 17 additions & 5 deletions packages/g-plugin-a11y/src/A11yPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class A11yPlugin implements RenderingPlugin {
}
};

renderingService.hooks.init.tapPromise(A11yPlugin.tag, async () => {
renderingService.hooks.init.tap(A11yPlugin.tag, () => {
if (enableExtractingText && !this.isSVG()) {
this.textExtractor.activate();
}
Expand All @@ -93,7 +93,10 @@ export class A11yPlugin implements RenderingPlugin {

canvas.addEventListener(ElementEvent.MOUNTED, handleMounted);
canvas.addEventListener(ElementEvent.UNMOUNTED, handleUnmounted);
canvas.addEventListener(ElementEvent.ATTR_MODIFIED, handleAttributeChanged);
canvas.addEventListener(
ElementEvent.ATTR_MODIFIED,
handleAttributeChanged,
);
canvas.addEventListener(ElementEvent.BOUNDS_CHANGED, handleBoundsChanged);
});

Expand All @@ -108,12 +111,21 @@ export class A11yPlugin implements RenderingPlugin {

canvas.removeEventListener(ElementEvent.MOUNTED, handleMounted);
canvas.removeEventListener(ElementEvent.UNMOUNTED, handleUnmounted);
canvas.removeEventListener(ElementEvent.ATTR_MODIFIED, handleAttributeChanged);
canvas.removeEventListener(ElementEvent.BOUNDS_CHANGED, handleBoundsChanged);
canvas.removeEventListener(
ElementEvent.ATTR_MODIFIED,
handleAttributeChanged,
);
canvas.removeEventListener(
ElementEvent.BOUNDS_CHANGED,
handleBoundsChanged,
);
});
}

private isSVG() {
return isBrowser && this.context.contextService.getDomElement() instanceof SVGSVGElement;
return (
isBrowser &&
this.context.contextService.getDomElement() instanceof SVGSVGElement
);
}
}
2 changes: 1 addition & 1 deletion packages/g-plugin-annotation/src/AnnotationPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export class AnnotationPlugin implements RenderingPlugin {
this.hotkeyActive = false;
};

renderingService.hooks.init.tapPromise(AnnotationPlugin.tag, async () => {
renderingService.hooks.init.tap(AnnotationPlugin.tag, () => {
canvas.addEventListener('click', handleClick);
canvas.addEventListener('pointerdown', handleMouseDown);
canvas.addEventListener('pointermove', handleMouseMove);
Expand Down
2 changes: 1 addition & 1 deletion packages/g-plugin-annotation/src/SelectablePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ export class SelectablePlugin implements RenderingPlugin {
}
};

renderingService.hooks.init.tapPromise(SelectablePlugin.tag, async () => {
renderingService.hooks.init.tap(SelectablePlugin.tag, () => {
canvas.addEventListener('pointerdown', handleClick);
canvas.addEventListener('pointerdown', handleMouseDown);
canvas.addEventListener('pointermove', handleMouseMove);
Expand Down
Loading

0 comments on commit 24352cd

Please sign in to comment.