Skip to content

Commit 2a76f9a

Browse files
Remove rbush dependency (#2113)
* refactor: remove rbush dependency Removes the `rbush` dependency and all related logic from the codebase. This includes: - Deleting the `RBushNode` component. - Removing `rbush` logic from `CanvasRendererPlugin` and `SelectablePlugin`. - Updating documentation to remove mentions of `rbush`. * fix(lint): fix linting errors Removes unused imports from `CanvasRendererPlugin.ts` and fixes a Prettier error. * chore: fix lint error --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: wang1212 <mrwang1212@126.com>
1 parent fe1a550 commit 2a76f9a

10 files changed

Lines changed: 20 additions & 118 deletions

File tree

packages/g-canvas/src/plugins/canvas-renderer/CanvasRendererPlugin.ts

Lines changed: 10 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,14 @@
11
import type {
22
DisplayObject,
3-
FederatedEvent,
4-
RBushNodeAABB,
53
RenderingPlugin,
6-
RBush,
74
RenderingPluginContext,
85
ContextService,
96
CanvasContext,
107
GlobalRuntime,
118
ParsedBaseStyleProps,
129
CSSRGB,
1310
} from '@antv/g-lite';
14-
import {
15-
AABB,
16-
CanvasEvent,
17-
CustomEvent,
18-
ElementEvent,
19-
Shape,
20-
Node,
21-
} from '@antv/g-lite';
11+
import { AABB, CanvasEvent, CustomEvent, Shape, Node } from '@antv/g-lite';
2212
import { mat4, vec3 } from 'gl-matrix';
2313
import { isNil } from '@antv/util';
2414
import type { CanvasRendererPluginOptions } from './interfaces';
@@ -49,17 +39,10 @@ export class CanvasRendererPlugin implements RenderingPlugin {
4939

5040
private pathGeneratorFactory: Plugin['context']['pathGeneratorFactory'];
5141

52-
/**
53-
* RBush used in dirty rectangle rendering
54-
*/
55-
private rBush: RBush<RBushNodeAABB>;
56-
5742
constructor(
5843
private canvasRendererPluginOptions: CanvasRendererPluginOptions, // private styleRendererFactory: Record<Shape, StyleRenderer>,
5944
) {}
6045

61-
private removedRBushNodeAABBs: RBushNodeAABB[] = [];
62-
6346
private renderQueue: DisplayObject[] = [];
6447

6548
#renderState: RenderState = {
@@ -90,7 +73,6 @@ export class CanvasRendererPlugin implements RenderingPlugin {
9073
camera,
9174
renderingService,
9275
renderingContext,
93-
rBushRoot,
9476
// @ts-ignore
9577
pathGeneratorFactory,
9678
} = this.context;
@@ -100,42 +82,14 @@ export class CanvasRendererPlugin implements RenderingPlugin {
10082
config.renderer.getConfig().enableDirtyCheck = false;
10183
config.renderer.getConfig().enableDirtyRectangleRendering = false;
10284

103-
this.rBush = rBushRoot;
10485
this.pathGeneratorFactory = pathGeneratorFactory;
10586

10687
const contextService =
10788
context.contextService as ContextService<CanvasRenderingContext2D>;
10889

10990
const canvas = renderingContext.root.ownerDocument.defaultView;
11091

111-
const handleUnmounted = (e: FederatedEvent) => {
112-
const object = e.target as DisplayObject;
113-
114-
// remove r-bush node
115-
// @ts-ignore
116-
const { rBushNode } = object;
117-
118-
if (rBushNode?.aabb) {
119-
// save removed aabbs for dirty-rectangle rendering later
120-
this.removedRBushNodeAABBs.push(rBushNode.aabb);
121-
}
122-
};
123-
124-
const handleCulled = (e: FederatedEvent) => {
125-
const object = e.target as DisplayObject;
126-
// @ts-ignore
127-
const { rBushNode } = object;
128-
129-
if (rBushNode.aabb) {
130-
// save removed aabbs for dirty-rectangle rendering later
131-
this.removedRBushNodeAABBs.push(rBushNode.aabb);
132-
}
133-
};
134-
13592
renderingService.hooks.init.tap(CanvasRendererPlugin.tag, () => {
136-
canvas.addEventListener(ElementEvent.UNMOUNTED, handleUnmounted);
137-
canvas.addEventListener(ElementEvent.CULLED, handleCulled);
138-
13993
// clear fullscreen
14094
const dpr = contextService.getDPR();
14195
const { width, height } = config;
@@ -151,10 +105,7 @@ export class CanvasRendererPlugin implements RenderingPlugin {
151105
});
152106

153107
renderingService.hooks.destroy.tap(CanvasRendererPlugin.tag, () => {
154-
canvas.removeEventListener(ElementEvent.UNMOUNTED, handleUnmounted);
155-
canvas.removeEventListener(ElementEvent.CULLED, handleCulled);
156108
this.renderQueue = [];
157-
this.removedRBushNodeAABBs = [];
158109
this.#renderState = {
159110
restoreStack: [],
160111
prevObject: null,
@@ -286,25 +237,12 @@ export class CanvasRendererPlugin implements RenderingPlugin {
286237
renderByZIndex(renderingContext.root, context);
287238
}
288239
// console.timeEnd('renderByZIndex');
289-
290-
this.removedRBushNodeAABBs = [];
291240
} else {
292241
// console.log('canvas renderer next...', this.renderQueue);
293242
// merge removed AABB
294243
const dirtyRenderBounds = this.safeMergeAABB(
295244
this.mergeDirtyAABBs(this.renderQueue),
296-
...this.removedRBushNodeAABBs.map(({ minX, minY, maxX, maxY }) => {
297-
const aabb = new AABB();
298-
aabb.setMinMax(
299-
// vec3.fromValues(minX, minY, 0),
300-
// vec3.fromValues(maxX, maxY, 0),
301-
[minX, minY, 0],
302-
[maxX, maxY, 0],
303-
);
304-
return aabb;
305-
}),
306245
);
307-
this.removedRBushNodeAABBs = [];
308246

309247
if (AABB.isEmpty(dirtyRenderBounds)) {
310248
this.renderQueue = [];
@@ -374,7 +312,15 @@ export class CanvasRendererPlugin implements RenderingPlugin {
374312
}
375313

376314
// search objects intersect with dirty rectangle
377-
const dirtyObjects = this.searchDirtyObjects(dirtyRenderBounds);
315+
const [minX, minY] = dirtyRenderBounds.getMin();
316+
const [maxX, maxY] = dirtyRenderBounds.getMax();
317+
const dirtyObjects =
318+
renderingContext.root.ownerDocument.elementsFromBBox(
319+
minX,
320+
minY,
321+
maxX,
322+
maxY,
323+
);
378324

379325
// do rendering
380326
dirtyObjects
@@ -712,20 +658,6 @@ export class CanvasRendererPlugin implements RenderingPlugin {
712658
return aabb;
713659
}
714660

715-
private searchDirtyObjects(dirtyRectangle: AABB): DisplayObject[] {
716-
// search in r-tree, get all affected nodes
717-
const [minX, minY] = dirtyRectangle.getMin();
718-
const [maxX, maxY] = dirtyRectangle.getMax();
719-
const rBushNodes = this.rBush.search({
720-
minX,
721-
minY,
722-
maxX,
723-
maxY,
724-
});
725-
726-
return rBushNodes.map(({ displayObject }) => displayObject);
727-
}
728-
729661
private saveDirtyAABB(object: DisplayObject) {
730662
const { renderable } = object;
731663
if (!renderable.dirtyRenderBounds) {

packages/g-lite/src/components/RBushNode.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export * from './Cullable';
22
export * from './Geometry';
3-
export * from './RBushNode';
43
export * from './Renderable';
54
export * from './Sortable';
65
export * from './Transform';

packages/g-lite/src/dom/Element.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type {
22
Cullable,
33
Geometry,
4-
RBushNode,
54
Renderable,
65
Sortable,
76
Transform,
@@ -139,14 +138,6 @@ export class Element<
139138
dirtyReason: undefined,
140139
};
141140

142-
/**
143-
* @deprecated Legacy property for RBush spatial indexing.
144-
* Will be removed in future versions.
145-
*/
146-
rBushNode: RBushNode = {
147-
aabb: undefined,
148-
};
149-
150141
/**
151142
* used with `getElementById()`
152143
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/id

packages/g-plugin-annotation/src/SelectablePlugin.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,6 @@ export class SelectablePlugin implements RenderingPlugin {
320320
};
321321
};
322322

323-
// 基于 RBush 空间索引进行快速区域查询
324323
const regionQuery = (region: {
325324
minX: number;
326325
minY: number;
@@ -330,7 +329,11 @@ export class SelectablePlugin implements RenderingPlugin {
330329
return document
331330
.elementsFromBBox(region.minX, region.minY, region.maxX, region.maxY)
332331
.filter((intersection) => {
333-
const { minX, minY, maxX, maxY } = intersection.rBushNode.aabb;
332+
const { x, y, width, height } = intersection.getBBox();
333+
const minX = x;
334+
const minY = y;
335+
const maxX = x + width;
336+
const maxY = y + height;
334337
// @see https://github.com/antvis/G/issues/1242
335338
const isTotallyContains =
336339
minX < region.minX &&

site/docs/api/builtin-objects/document.en.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ Area queries, especially boundingbox-based detection, are particularly useful in
190190
- Dirty rectangle rendering for determining the affected area
191191
- Rectangle swiping for batch selection of graphics
192192

193-
This type of wraparound box-based detection does not need to be too precise, and is fast with spatial indexing like internal RBush.
193+
This type of wraparound box-based detection does not need to be too precise, and is fast.
194194

195195
This method is synchronous and accepts the enclosing box description `minX, minY, maxX, maxY` coordinates (under [Canvas coordinate system](/en/api/canvas/coordinates#canvas)).
196196

site/docs/api/builtin-objects/document.zh.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ const elements = await canvas.document.elementsFromPoint(150, 150); // [circle2,
190190
- 脏矩形渲染中用于确定受影响区域
191191
- 矩形刷选批量选中图形
192192

193-
此类基于包围盒的检测不需要太精确,配合内部 RBush 这样的空间索引,因此速度很快。
193+
此类基于包围盒的检测不需要太精确,因此速度很快。
194194

195195
该方法为同步方法,接受包围盒描述 `minX, minY, maxX, maxY` 坐标(在 [Canvas 坐标系](/api/canvas/coordinates#canvas)下):
196196

site/docs/api/renderer/canvas.en.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ The following diagram illustrates this idea.
6767
6868
<img src="https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*6zyLTL-AIbQAAAAAAAAAAAAAARQnAQ" width="400" alt="dirty rectangle rendering">
6969
70-
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).
70+
In the above intersection and region query, we can reuse the optimizations in the culling scheme, such as the acceleration structure.
7171
7272
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).
7373

site/docs/api/renderer/canvas.zh.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const renderer = new Renderer({
6767
6868
<img src="https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*6zyLTL-AIbQAAAAAAAAAAAAAARQnAQ" width="400" alt="dirty rectangle rendering">
6969
70-
在以上求交与区域查询的过程中,我们可以复用剔除方案中的优化手段,例如加速结构。在实现中我们使用了 [RBush](https://github.com/mourner/rbush)。
70+
在以上求交与区域查询的过程中,我们可以复用剔除方案中的优化手段,例如加速结构。
7171
7272
显然当动态变化的对象数目太多时,该优化手段就失去了意义,试想经过一番计算合并后的“脏矩形”几乎等于整个画布,那还不如直接清空重绘所有对象。因此例如 Pixi.js 这样的 2D 游戏渲染引擎就[不考虑内置](https://github.com/pixijs/pixi.js/issues/3503)。
7373

site/docs/plugins/dev.zh.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export class CanvasRendererPlugin implements RenderingPlugin {
6767

6868
```js
6969
apply(context: RenderingPluginContext) {
70-
const { config, camera, renderingService, renderingContext, rBushRoot, pathGeneratorFactory } =
70+
const { config, camera, renderingService, renderingContext, pathGeneratorFactory } =
7171
context;
7272

7373
// 当渲染服务初始化时...

0 commit comments

Comments
 (0)