diff --git a/packages/g-canvas/src/plugins/canvas-renderer/CanvasRendererPlugin.ts b/packages/g-canvas/src/plugins/canvas-renderer/CanvasRendererPlugin.ts index 118431028b..16ef72fbf9 100644 --- a/packages/g-canvas/src/plugins/canvas-renderer/CanvasRendererPlugin.ts +++ b/packages/g-canvas/src/plugins/canvas-renderer/CanvasRendererPlugin.ts @@ -1,9 +1,6 @@ import type { DisplayObject, - FederatedEvent, - RBushNodeAABB, RenderingPlugin, - RBush, RenderingPluginContext, ContextService, CanvasContext, @@ -11,14 +8,7 @@ import type { ParsedBaseStyleProps, CSSRGB, } from '@antv/g-lite'; -import { - AABB, - CanvasEvent, - CustomEvent, - ElementEvent, - Shape, - Node, -} from '@antv/g-lite'; +import { AABB, CanvasEvent, CustomEvent, Shape, Node } from '@antv/g-lite'; import { mat4, vec3 } from 'gl-matrix'; import { isNil } from '@antv/util'; import type { CanvasRendererPluginOptions } from './interfaces'; @@ -49,17 +39,10 @@ export class CanvasRendererPlugin implements RenderingPlugin { private pathGeneratorFactory: Plugin['context']['pathGeneratorFactory']; - /** - * RBush used in dirty rectangle rendering - */ - private rBush: RBush; - constructor( private canvasRendererPluginOptions: CanvasRendererPluginOptions, // private styleRendererFactory: Record, ) {} - private removedRBushNodeAABBs: RBushNodeAABB[] = []; - private renderQueue: DisplayObject[] = []; #renderState: RenderState = { @@ -90,7 +73,6 @@ export class CanvasRendererPlugin implements RenderingPlugin { camera, renderingService, renderingContext, - rBushRoot, // @ts-ignore pathGeneratorFactory, } = this.context; @@ -100,7 +82,6 @@ export class CanvasRendererPlugin implements RenderingPlugin { config.renderer.getConfig().enableDirtyCheck = false; config.renderer.getConfig().enableDirtyRectangleRendering = false; - this.rBush = rBushRoot; this.pathGeneratorFactory = pathGeneratorFactory; const contextService = @@ -108,34 +89,7 @@ export class CanvasRendererPlugin implements RenderingPlugin { const canvas = renderingContext.root.ownerDocument.defaultView; - const handleUnmounted = (e: FederatedEvent) => { - const object = e.target as DisplayObject; - - // remove r-bush node - // @ts-ignore - const { rBushNode } = object; - - if (rBushNode?.aabb) { - // save removed aabbs for dirty-rectangle rendering later - this.removedRBushNodeAABBs.push(rBushNode.aabb); - } - }; - - const handleCulled = (e: FederatedEvent) => { - const object = e.target as DisplayObject; - // @ts-ignore - const { rBushNode } = object; - - if (rBushNode.aabb) { - // save removed aabbs for dirty-rectangle rendering later - this.removedRBushNodeAABBs.push(rBushNode.aabb); - } - }; - renderingService.hooks.init.tap(CanvasRendererPlugin.tag, () => { - canvas.addEventListener(ElementEvent.UNMOUNTED, handleUnmounted); - canvas.addEventListener(ElementEvent.CULLED, handleCulled); - // clear fullscreen const dpr = contextService.getDPR(); const { width, height } = config; @@ -151,10 +105,7 @@ export class CanvasRendererPlugin implements RenderingPlugin { }); renderingService.hooks.destroy.tap(CanvasRendererPlugin.tag, () => { - canvas.removeEventListener(ElementEvent.UNMOUNTED, handleUnmounted); - canvas.removeEventListener(ElementEvent.CULLED, handleCulled); this.renderQueue = []; - this.removedRBushNodeAABBs = []; this.#renderState = { restoreStack: [], prevObject: null, @@ -286,25 +237,12 @@ export class CanvasRendererPlugin implements RenderingPlugin { renderByZIndex(renderingContext.root, context); } // console.timeEnd('renderByZIndex'); - - this.removedRBushNodeAABBs = []; } else { // console.log('canvas renderer next...', this.renderQueue); // merge removed AABB const dirtyRenderBounds = this.safeMergeAABB( this.mergeDirtyAABBs(this.renderQueue), - ...this.removedRBushNodeAABBs.map(({ minX, minY, maxX, maxY }) => { - const aabb = new AABB(); - aabb.setMinMax( - // vec3.fromValues(minX, minY, 0), - // vec3.fromValues(maxX, maxY, 0), - [minX, minY, 0], - [maxX, maxY, 0], - ); - return aabb; - }), ); - this.removedRBushNodeAABBs = []; if (AABB.isEmpty(dirtyRenderBounds)) { this.renderQueue = []; @@ -374,7 +312,15 @@ export class CanvasRendererPlugin implements RenderingPlugin { } // search objects intersect with dirty rectangle - const dirtyObjects = this.searchDirtyObjects(dirtyRenderBounds); + const [minX, minY] = dirtyRenderBounds.getMin(); + const [maxX, maxY] = dirtyRenderBounds.getMax(); + const dirtyObjects = + renderingContext.root.ownerDocument.elementsFromBBox( + minX, + minY, + maxX, + maxY, + ); // do rendering dirtyObjects @@ -712,20 +658,6 @@ export class CanvasRendererPlugin implements RenderingPlugin { return aabb; } - private searchDirtyObjects(dirtyRectangle: AABB): DisplayObject[] { - // search in r-tree, get all affected nodes - const [minX, minY] = dirtyRectangle.getMin(); - const [maxX, maxY] = dirtyRectangle.getMax(); - const rBushNodes = this.rBush.search({ - minX, - minY, - maxX, - maxY, - }); - - return rBushNodes.map(({ displayObject }) => displayObject); - } - private saveDirtyAABB(object: DisplayObject) { const { renderable } = object; if (!renderable.dirtyRenderBounds) { diff --git a/packages/g-lite/src/components/RBushNode.ts b/packages/g-lite/src/components/RBushNode.ts deleted file mode 100644 index 19df94766f..0000000000 --- a/packages/g-lite/src/components/RBushNode.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DisplayObject } from '../display-objects'; - -/** - * Legacy interface for backward compatibility. - * Will be removed in future versions. - * @deprecated - */ -export interface RBushNodeAABB { - displayObject: DisplayObject; - minX: number; - minY: number; - maxX: number; - maxY: number; -} - -/** - * Legacy interface for backward compatibility. - * Will be removed in future versions. - * @deprecated - */ -export interface RBushNode { - aabb?: RBushNodeAABB; -} diff --git a/packages/g-lite/src/components/index.ts b/packages/g-lite/src/components/index.ts index 4f194ffb62..d8065e2500 100644 --- a/packages/g-lite/src/components/index.ts +++ b/packages/g-lite/src/components/index.ts @@ -1,6 +1,5 @@ export * from './Cullable'; export * from './Geometry'; -export * from './RBushNode'; export * from './Renderable'; export * from './Sortable'; export * from './Transform'; diff --git a/packages/g-lite/src/dom/Element.ts b/packages/g-lite/src/dom/Element.ts index 478639c5e7..928b817941 100644 --- a/packages/g-lite/src/dom/Element.ts +++ b/packages/g-lite/src/dom/Element.ts @@ -1,7 +1,6 @@ import type { Cullable, Geometry, - RBushNode, Renderable, Sortable, Transform, @@ -139,14 +138,6 @@ export class Element< dirtyReason: undefined, }; - /** - * @deprecated Legacy property for RBush spatial indexing. - * Will be removed in future versions. - */ - rBushNode: RBushNode = { - aabb: undefined, - }; - /** * used with `getElementById()` * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/id diff --git a/packages/g-plugin-annotation/src/SelectablePlugin.ts b/packages/g-plugin-annotation/src/SelectablePlugin.ts index 55676c65b1..a76fbdfbbc 100644 --- a/packages/g-plugin-annotation/src/SelectablePlugin.ts +++ b/packages/g-plugin-annotation/src/SelectablePlugin.ts @@ -320,7 +320,6 @@ export class SelectablePlugin implements RenderingPlugin { }; }; - // 基于 RBush 空间索引进行快速区域查询 const regionQuery = (region: { minX: number; minY: number; @@ -330,7 +329,11 @@ export class SelectablePlugin implements RenderingPlugin { return document .elementsFromBBox(region.minX, region.minY, region.maxX, region.maxY) .filter((intersection) => { - const { minX, minY, maxX, maxY } = intersection.rBushNode.aabb; + const { x, y, width, height } = intersection.getBBox(); + const minX = x; + const minY = y; + const maxX = x + width; + const maxY = y + height; // @see https://github.com/antvis/G/issues/1242 const isTotallyContains = minX < region.minX && diff --git a/site/docs/api/builtin-objects/document.en.md b/site/docs/api/builtin-objects/document.en.md index 087192dc9c..cd60bd17ff 100644 --- a/site/docs/api/builtin-objects/document.en.md +++ b/site/docs/api/builtin-objects/document.en.md @@ -190,7 +190,7 @@ Area queries, especially boundingbox-based detection, are particularly useful in - Dirty rectangle rendering for determining the affected area - Rectangle swiping for batch selection of graphics -This type of wraparound box-based detection does not need to be too precise, and is fast with spatial indexing like internal RBush. +This type of wraparound box-based detection does not need to be too precise, and is fast. This method is synchronous and accepts the enclosing box description `minX, minY, maxX, maxY` coordinates (under [Canvas coordinate system](/en/api/canvas/coordinates#canvas)). diff --git a/site/docs/api/builtin-objects/document.zh.md b/site/docs/api/builtin-objects/document.zh.md index de67831724..fe3c9fc4b0 100644 --- a/site/docs/api/builtin-objects/document.zh.md +++ b/site/docs/api/builtin-objects/document.zh.md @@ -190,7 +190,7 @@ const elements = await canvas.document.elementsFromPoint(150, 150); // [circle2, - 脏矩形渲染中用于确定受影响区域 - 矩形刷选批量选中图形 -此类基于包围盒的检测不需要太精确,配合内部 RBush 这样的空间索引,因此速度很快。 +此类基于包围盒的检测不需要太精确,因此速度很快。 该方法为同步方法,接受包围盒描述 `minX, minY, maxX, maxY` 坐标(在 [Canvas 坐标系](/api/canvas/coordinates#canvas)下): diff --git a/site/docs/api/renderer/canvas.en.md b/site/docs/api/renderer/canvas.en.md index e61ef8e59a..839a620156 100644 --- a/site/docs/api/renderer/canvas.en.md +++ b/site/docs/api/renderer/canvas.en.md @@ -67,7 +67,7 @@ The following diagram illustrates this idea. dirty rectangle rendering -In the above intersection and region query, we can reuse the optimizations in the culling scheme, such as the acceleration structure. In the implementation we use [RBush](https://github.com/mourner/rbush). +In the above intersection and region query, we can reuse the optimizations in the culling scheme, such as the acceleration structure. Obviously, when the number of dynamically changing objects is too large, this optimization becomes meaningless, as the "dirty rectangle" is almost equal to the whole canvas after some calculations, so it is better to just empty and redraw all objects. So 2D game rendering engines like Pixi.js, for example, are [not considered built-in](https://github.com/pixijs/pixi.js/issues/3503). diff --git a/site/docs/api/renderer/canvas.zh.md b/site/docs/api/renderer/canvas.zh.md index 5d93c9c6d7..e4935fc879 100644 --- a/site/docs/api/renderer/canvas.zh.md +++ b/site/docs/api/renderer/canvas.zh.md @@ -67,7 +67,7 @@ const renderer = new Renderer({ dirty rectangle rendering -在以上求交与区域查询的过程中,我们可以复用剔除方案中的优化手段,例如加速结构。在实现中我们使用了 [RBush](https://github.com/mourner/rbush)。 +在以上求交与区域查询的过程中,我们可以复用剔除方案中的优化手段,例如加速结构。 显然当动态变化的对象数目太多时,该优化手段就失去了意义,试想经过一番计算合并后的“脏矩形”几乎等于整个画布,那还不如直接清空重绘所有对象。因此例如 Pixi.js 这样的 2D 游戏渲染引擎就[不考虑内置](https://github.com/pixijs/pixi.js/issues/3503)。 diff --git a/site/docs/plugins/dev.zh.md b/site/docs/plugins/dev.zh.md index fa6e852ad2..1c825c622b 100644 --- a/site/docs/plugins/dev.zh.md +++ b/site/docs/plugins/dev.zh.md @@ -67,7 +67,7 @@ export class CanvasRendererPlugin implements RenderingPlugin { ```js apply(context: RenderingPluginContext) { - const { config, camera, renderingService, renderingContext, rBushRoot, pathGeneratorFactory } = + const { config, camera, renderingService, renderingContext, pathGeneratorFactory } = context; // 当渲染服务初始化时...