diff --git a/packages/g-plugin-annotation/src/rendering/rect-render.ts b/packages/g-plugin-annotation/src/rendering/rect-render.ts index 6ff82cf7b..0e013c442 100644 --- a/packages/g-plugin-annotation/src/rendering/rect-render.ts +++ b/packages/g-plugin-annotation/src/rendering/rect-render.ts @@ -5,6 +5,7 @@ import { DASH_LINE_STYLE, DEFAULT_STYLE } from '../constants/style'; import type { DrawerState } from '../interface/drawer'; function getWidthFromBbox(path: PointLike[]) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [tl, tr, br, bl] = path; const dy = tr.y - tl.y; const dx = tr.x - tl.x; @@ -12,12 +13,14 @@ function getWidthFromBbox(path: PointLike[]) { } function getHeightFromBbox(path: PointLike[]) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [tl, tr, br, bl] = path; const dy = br.y - tr.y; const dx = br.x - tr.x; return Math.sqrt(dy * dy + dx * dx); } function getRotationFromBbox(path: PointLike[]) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [tl, tr, br, bl] = path; const dy = tr.y - tl.y; const dx = tr.x - tl.x; diff --git a/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts b/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts index d7c8190db..ad1e83257 100644 --- a/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts +++ b/packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts @@ -175,15 +175,17 @@ export class CanvasRendererPlugin implements RenderingPlugin { if (object.isVisible() && !object.isCulled()) { this.renderDisplayObject(object, renderingService); // if we did a full screen rendering last frame + // setTimeout(() => { this.saveDirtyAABB(object); + // }); } + const sorted = object.sortable.sorted || object.childNodes; + // should account for z-index - if (object.sortable.sorted && object.sortable.sorted.length) { - object.sortable.sorted.forEach((child: DisplayObject) => { - renderByZIndex(child); - }); - } + sorted.forEach((child: DisplayObject) => { + renderByZIndex(child); + }); }; // render at the end of frame diff --git a/packages/g-plugin-canvaskit-renderer/src/CanvaskitRendererPlugin.ts b/packages/g-plugin-canvaskit-renderer/src/CanvaskitRendererPlugin.ts index e89ee994a..370c76951 100644 --- a/packages/g-plugin-canvaskit-renderer/src/CanvaskitRendererPlugin.ts +++ b/packages/g-plugin-canvaskit-renderer/src/CanvaskitRendererPlugin.ts @@ -267,13 +267,12 @@ export class CanvaskitRendererPlugin implements RenderingPlugin { private drawWithSurface(canvas: Canvas, object: DisplayObject) { this.renderDisplayObject(object, canvas); + const sorted = object.sortable.sorted || object.childNodes; // should account for z-index - if (object.sortable.sorted && object.sortable.sorted.length) { - object.sortable.sorted.forEach((child: DisplayObject) => { - this.drawWithSurface(canvas, child); - }); - } + sorted.forEach((child: DisplayObject) => { + this.drawWithSurface(canvas, child); + }); } private generatePattern(object: DisplayObject, pattern: Pattern) { diff --git a/packages/g-plugin-html-renderer/src/HTMLRenderingPlugin.ts b/packages/g-plugin-html-renderer/src/HTMLRenderingPlugin.ts index 0f010a40c..263fc2b6a 100644 --- a/packages/g-plugin-html-renderer/src/HTMLRenderingPlugin.ts +++ b/packages/g-plugin-html-renderer/src/HTMLRenderingPlugin.ts @@ -250,7 +250,7 @@ export class HTMLRenderingPlugin implements RenderingPlugin { $el.style['border-style'] = 'dashed'; break; case 'filter': - const { filter } = object.parsedStyle; + const { filter } = object.style; $el.style.filter = filter; break; } diff --git a/packages/g/src/plugins/PrepareRendererPlugin.ts b/packages/g/src/plugins/PrepareRendererPlugin.ts index e0e941281..fdf0ce78e 100644 --- a/packages/g/src/plugins/PrepareRendererPlugin.ts +++ b/packages/g/src/plugins/PrepareRendererPlugin.ts @@ -38,6 +38,8 @@ export class PrepareRendererPlugin implements RenderingPlugin { }); } + // private isFirstTimeRendering = true; + apply(renderingService: RenderingService) { const handleAttributeChanged = (e: FederatedEvent) => { const object = e.target as DisplayObject; @@ -109,6 +111,14 @@ export class PrepareRendererPlugin implements RenderingPlugin { }); renderingService.hooks.endFrame.tap(PrepareRendererPlugin.tag, () => { + // if (this.isFirstTimeRendering) { + // // @see https://github.com/antvis/G/issues/1117 + // setTimeout(() => this.syncRTree()); + // this.isFirstTimeRendering = false; + // } else { + // this.syncRTree(); + // } + this.syncRTree(); }); } diff --git a/packages/g/src/services/SceneGraphService.ts b/packages/g/src/services/SceneGraphService.ts index 6e7f2f556..d92ca1317 100644 --- a/packages/g/src/services/SceneGraphService.ts +++ b/packages/g/src/services/SceneGraphService.ts @@ -125,7 +125,9 @@ export class DefaultSceneGraphService implements SceneGraphService { // parent needs re-sort const sortable = (parent as unknown as Element).sortable; - if (sortable) { + if (sortable?.sorted?.length && (child as unknown as Element).style?.zIndex) { + // if (sortable) { + // only child has z-Index sortable.dirty = true; } @@ -154,7 +156,8 @@ export class DefaultSceneGraphService implements SceneGraphService { // parent needs re-sort const sortable = (child.parentNode as Element).sortable; - if (sortable) { + // if (sortable) { + if (sortable?.sorted?.length && (child as unknown as Element).style?.zIndex) { sortable.dirty = true; } diff --git a/packages/site/examples/perf/demo/animation.js b/packages/site/examples/perf/demo/animation.js new file mode 100644 index 000000000..7f659b84c --- /dev/null +++ b/packages/site/examples/perf/demo/animation.js @@ -0,0 +1,93 @@ +import { Canvas, CanvasEvent, Circle } from '@antv/g'; +import { Renderer as CanvasRenderer } from '@antv/g-canvas'; +import { Renderer as CanvaskitRenderer } from '@antv/g-canvaskit'; +import { Renderer as SVGRenderer } from '@antv/g-svg'; +import { Renderer as WebGLRenderer } from '@antv/g-webgl'; +import * as lil from 'lil-gui'; +import Stats from 'stats.js'; + +/** + * G4.0 @see https://codesandbox.io/s/g-4-0-perf-k2tm35?file=/src/index.tsx + * G5.0 @see https://codesandbox.io/s/g-5-0-perf-forked-jvcidq?file=/index.js + */ + +// create a renderer +const canvasRenderer = new CanvasRenderer(); +const webglRenderer = new WebGLRenderer(); +const svgRenderer = new SVGRenderer(); +const canvaskitRenderer = new CanvaskitRenderer({ + wasmDir: '/', +}); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: canvasRenderer, +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + for (let i = 0; i < 5000; i++) { + const circle = new Circle({ + style: { + cx: Math.random() * 600, + cy: Math.random() * 500, + r: 10 + Math.random() * 5, + fill: '#1890FF', + stroke: '#F04864', + lineWidth: 4, + }, + }); + + canvas.appendChild(circle); + + circle.animate([{ opacity: 1 }, { opacity: 0 }], { + duration: 1000, + delay: 1000, + fill: 'both', + iterations: Infinity, + }); + } +}); + +// stats +const stats = new Stats(); +stats.showPanel(0); +const $stats = stats.dom; +$stats.style.position = 'absolute'; +$stats.style.left = '0px'; +$stats.style.top = '0px'; +const $wrapper = document.getElementById('container'); +$wrapper.appendChild($stats); +canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => { + if (stats) { + stats.update(); + } +}); + +// GUI +let currentRenderer = canvasRenderer; +const gui = new lil.GUI({ autoPlace: false }); +$wrapper.appendChild(gui.domElement); +const rendererFolder = gui.addFolder('renderer'); +const rendererConfig = { + renderer: 'canvas', +}; + +rendererFolder + .add(rendererConfig, 'renderer', ['canvas', 'svg', 'webgl', 'webgpu', 'canvaskit']) + .onChange((rendererName) => { + let renderer; + if (rendererName === 'canvas') { + renderer = canvasRenderer; + } else if (rendererName === 'svg') { + renderer = svgRenderer; + } else if (rendererName === 'webgl') { + renderer = webglRenderer; + } else if (rendererName === 'canvaskit') { + renderer = canvaskitRenderer; + } + canvas.setRenderer(renderer); + }); +rendererFolder.open(); diff --git a/packages/site/examples/perf/demo/fcp.js b/packages/site/examples/perf/demo/fcp.js new file mode 100644 index 000000000..e5a25553d --- /dev/null +++ b/packages/site/examples/perf/demo/fcp.js @@ -0,0 +1,67 @@ +import { Canvas, CanvasEvent, Path } from '@antv/g'; +import { Renderer as CanvasRenderer } from '@antv/g-canvas'; +import Stats from 'stats.js'; + +const canvasRenderer = new CanvasRenderer(); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: canvasRenderer, +}); + +function draw(nodesNum) { + function inner() { + for (let i = 0; i < nodesNum; i++) { + const x = Math.random() * 600; + const y = Math.random() * 500; + const path = canvas.appendChild( + new Path({ + attrs: { + fill: '#C6E5FF', + stroke: '#5B8FF9', + path: ` + M${54.4462133232839 + x},${-6.41757177038063 + y} + L${61.3765714868427 + x},${6.41757177038063 + y} + + M${61.3765714868427 + x},${6.41757177038063 + y} + L${61.54285370420826 + x},${0.5852759906612777 + y} + + M${61.3765714868427 + x},${6.41757177038063 + y} + L${56.4087962879037 + x},${3.3574192560847824 + y} + `, + }, + }), + ); + // path.animate([{ fillOpacity: 0 }, { fillOpacity: 1 }]); + } + } + + inner(); + inner(); + inner(); + inner(); + inner(); +} + +canvas.addEventListener(CanvasEvent.READY, () => { + let nodesNum = 10000; + draw(nodesNum); +}); + +// stats +const stats = new Stats(); +stats.showPanel(0); +const $stats = stats.dom; +$stats.style.position = 'absolute'; +$stats.style.left = '0px'; +$stats.style.top = '0px'; +const $wrapper = document.getElementById('container'); +$wrapper.appendChild($stats); +canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => { + if (stats) { + stats.update(); + } +});