Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import type {
DisplayObject,
FederatedEvent,
RBushNodeAABB,
RenderingPlugin,
RBush,
RenderingPluginContext,
ContextService,
CanvasContext,
GlobalRuntime,
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';
Expand Down Expand Up @@ -49,17 +39,10 @@ export class CanvasRendererPlugin implements RenderingPlugin {

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

/**
* RBush used in dirty rectangle rendering
*/
private rBush: RBush<RBushNodeAABB>;

constructor(
private canvasRendererPluginOptions: CanvasRendererPluginOptions, // private styleRendererFactory: Record<Shape, StyleRenderer>,
) {}

private removedRBushNodeAABBs: RBushNodeAABB[] = [];

private renderQueue: DisplayObject[] = [];

#renderState: RenderState = {
Expand Down Expand Up @@ -90,7 +73,6 @@ export class CanvasRendererPlugin implements RenderingPlugin {
camera,
renderingService,
renderingContext,
rBushRoot,
// @ts-ignore
pathGeneratorFactory,
} = this.context;
Expand All @@ -100,42 +82,14 @@ export class CanvasRendererPlugin implements RenderingPlugin {
config.renderer.getConfig().enableDirtyCheck = false;
config.renderer.getConfig().enableDirtyRectangleRendering = false;

this.rBush = rBushRoot;
this.pathGeneratorFactory = pathGeneratorFactory;

const contextService =
context.contextService as ContextService<CanvasRenderingContext2D>;

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;
Expand All @@ -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,
Expand Down Expand Up @@ -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 = [];
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
23 changes: 0 additions & 23 deletions packages/g-lite/src/components/RBushNode.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/g-lite/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from './Cullable';
export * from './Geometry';
export * from './RBushNode';
export * from './Renderable';
export * from './Sortable';
export * from './Transform';
9 changes: 0 additions & 9 deletions packages/g-lite/src/dom/Element.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type {
Cullable,
Geometry,
RBushNode,
Renderable,
Sortable,
Transform,
Expand Down Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions packages/g-plugin-annotation/src/SelectablePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,6 @@ export class SelectablePlugin implements RenderingPlugin {
};
};

// 基于 RBush 空间索引进行快速区域查询
const regionQuery = (region: {
minX: number;
minY: number;
Expand All @@ -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 &&
Expand Down
2 changes: 1 addition & 1 deletion site/docs/api/builtin-objects/document.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)).

Expand Down
2 changes: 1 addition & 1 deletion site/docs/api/builtin-objects/document.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ const elements = await canvas.document.elementsFromPoint(150, 150); // [circle2,
- 脏矩形渲染中用于确定受影响区域
- 矩形刷选批量选中图形

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

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

Expand Down
2 changes: 1 addition & 1 deletion site/docs/api/renderer/canvas.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ The following diagram illustrates this idea.

<img src="https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*6zyLTL-AIbQAAAAAAAAAAAAAARQnAQ" width="400" alt="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).

Expand Down
2 changes: 1 addition & 1 deletion site/docs/api/renderer/canvas.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const renderer = new Renderer({

<img src="https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*6zyLTL-AIbQAAAAAAAAAAAAAARQnAQ" width="400" alt="dirty rectangle rendering">

在以上求交与区域查询的过程中,我们可以复用剔除方案中的优化手段,例如加速结构。在实现中我们使用了 [RBush](https://github.com/mourner/rbush)。
在以上求交与区域查询的过程中,我们可以复用剔除方案中的优化手段,例如加速结构。

显然当动态变化的对象数目太多时,该优化手段就失去了意义,试想经过一番计算合并后的“脏矩形”几乎等于整个画布,那还不如直接清空重绘所有对象。因此例如 Pixi.js 这样的 2D 游戏渲染引擎就[不考虑内置](https://github.com/pixijs/pixi.js/issues/3503)。

Expand Down
2 changes: 1 addition & 1 deletion site/docs/plugins/dev.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;

// 当渲染服务初始化时...
Expand Down
Loading