Skip to content

Commit

Permalink
Merge pull request antvis#4960 from antvis/v5-scroll-opt
Browse files Browse the repository at this point in the history
feat: scroll-canvas support tile updating
  • Loading branch information
Yanyan-Wang authored Sep 19, 2023
2 parents 0b60397 + c6fb527 commit affd3c5
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 76 deletions.
88 changes: 53 additions & 35 deletions packages/g6/src/runtime/graph.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import EventEmitter from '@antv/event-emitter';
import { AABB, Canvas, DataURLType, DisplayObject, PointLike, Rect } from '@antv/g';
import {
AABB,
Canvas,
DataURLType,
DisplayObject,
PointLike,
Rect,
} from '@antv/g';
import { GraphChange, ID } from '@antv/graphlib';
import {
clone,
Expand Down Expand Up @@ -2074,8 +2081,8 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>

const pixelRatio =
typeof window !== 'undefined' ? window.devicePixelRatio : 1;
let width = this.getSize()[0];
let height = this.getSize()[1];
const width = this.getSize()[0];
const height = this.getSize()[1];

const vContainerDOM: HTMLDivElement = createDom(
'<div id="virtual-image"></div>',
Expand Down Expand Up @@ -2105,9 +2112,9 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
});
vCanvas.appendChild(bgRect);
}
let backgroundClonedGroup = backgroundCanvas.getRoot().cloneNode(true);
let clonedGroup = canvas.getRoot().cloneNode(true);
let transientClonedGroup = transientCanvas.getRoot().cloneNode(true);
const backgroundClonedGroup = backgroundCanvas.getRoot().cloneNode(true);
const clonedGroup = canvas.getRoot().cloneNode(true);
const transientClonedGroup = transientCanvas.getRoot().cloneNode(true);
vCanvas.appendChild(backgroundClonedGroup);
vCanvas.appendChild(clonedGroup);
vCanvas.appendChild(transientClonedGroup);
Expand Down Expand Up @@ -2151,33 +2158,36 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
padding = [padding, padding, padding, padding];
}

const left = (transientBBox.left
? backgroundBBox.left
? Math.min(backgroundBBox.left, BBox.left, transientBBox.left)
: Math.min(BBox.left, transientBBox.left)
: BBox.left)-padding[3];
const right = (transientBBox.right
? backgroundBBox.right
? Math.max(backgroundBBox.right, BBox.right, transientBBox.right)
: Math.max(BBox.right, transientBBox.right)
: BBox.right)+padding[1];
const top = (transientBBox.top
? backgroundBBox.top
? Math.min(backgroundBBox.top, BBox.top, transientBBox.top)
: Math.min(BBox.top, transientBBox.top)
: BBox.top)-padding[0];
const bottom = (transientBBox.bottom
? backgroundBBox.bottom
? Math.max(backgroundBBox.bottom, BBox.bottom, transientBBox.bottom)
: Math.max(BBox.bottom, transientBBox.bottom)
: BBox.bottom)+padding[2];
const left =
(transientBBox.left
? backgroundBBox.left
? Math.min(backgroundBBox.left, BBox.left, transientBBox.left)
: Math.min(BBox.left, transientBBox.left)
: BBox.left) - padding[3];
const right =
(transientBBox.right
? backgroundBBox.right
? Math.max(backgroundBBox.right, BBox.right, transientBBox.right)
: Math.max(BBox.right, transientBBox.right)
: BBox.right) + padding[1];
const top =
(transientBBox.top
? backgroundBBox.top
? Math.min(backgroundBBox.top, BBox.top, transientBBox.top)
: Math.min(BBox.top, transientBBox.top)
: BBox.top) - padding[0];
const bottom =
(transientBBox.bottom
? backgroundBBox.bottom
? Math.max(backgroundBBox.bottom, BBox.bottom, transientBBox.bottom)
: Math.max(BBox.bottom, transientBBox.bottom)
: BBox.bottom) + padding[2];

const graphCenterX = (left + right) / 2;
const graphCenterY = (top + bottom) / 2;
const halfX = (right - left) / 2;
const halfY = (bottom - top) / 2;


const pixelRatio =
typeof window !== 'undefined' ? window.devicePixelRatio : 1;
const vWidth = halfX * 2;
Expand Down Expand Up @@ -2209,10 +2219,10 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
});
vCanvas.appendChild(bgRect);
}
let backgroundClonedGroup = backgroundRoot.cloneNode(true);
let clonedGroup = root.cloneNode(true);
let transientClonedGroup = transientRoot.cloneNode(true);
let transPosition: [number, number] = [
const backgroundClonedGroup = backgroundRoot.cloneNode(true);
const clonedGroup = root.cloneNode(true);
const transientClonedGroup = transientRoot.cloneNode(true);
const transPosition: [number, number] = [
-graphCenterX + halfX,
-graphCenterY + halfY,
];
Expand Down Expand Up @@ -2316,9 +2326,13 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
* @param type The type of the image to download (optional, defaults to 'image/png').
* @param imageConfig Configuration options for the image (optional).
*/
public downloadFullImage(name?: string, type?: DataURLType, imageConfig?: { padding?: number | number[] }): void {
public downloadFullImage(
name?: string,
type?: DataURLType,
imageConfig?: { padding?: number | number[] },
): void {
const self = this;

const rendererType = this.rendererType;
if (!type) type = 'image/png';
const fileName: string =
Expand Down Expand Up @@ -2352,13 +2366,17 @@ export default class Graph<B extends BehaviorRegistry, T extends ThemeRegistry>
}

/**
* Asynchronously converts the entire canvas content to a Data URL of the specified type
* Asynchronously converts the entire canvas content to a Data URL of the specified type
* with optional padding, and invokes the provided callback.
* @param type The type of the Data URL (optional, defaults to 'image/png').
* @param imageConfig Configuration options for the image (optional).
* @param callback A callback function to handle the Data URL (optional).
*/
protected asyncToFullDataUrl(type?: DataURLType, imageConfig?: { padding?: number | number[] }, callback?: Function): void {
protected asyncToFullDataUrl(
type?: DataURLType,
imageConfig?: { padding?: number | number[] },
callback?: Function,
): void {
let dataURL = '';
if (!type) type = 'image/png';

Expand Down
12 changes: 6 additions & 6 deletions packages/g6/src/stdlib/behavior/drag-canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,12 @@ export class DragCanvas extends Behavior {
return;
}
const section = sections.shift();
graph.hideItem(section, false, true);
graph.executeWithNoStack(() => {
graph.hideItem(section, false, true);
});
requestId = requestAnimationFrame(update);
};
graph.executeWithNoStack(() => {
requestId = requestAnimationFrame(update);
});
requestId = requestAnimationFrame(update);
}
}

Expand Down Expand Up @@ -285,12 +285,12 @@ export class DragCanvas extends Behavior {
cancelAnimationFrame(requestId);
return;
}
graph.startHistoryBatch();
graph.showItem(sections.shift(), false);
graph.stopHistoryBatch();
requestId = requestAnimationFrame(update);
};
graph.startHistoryBatch();
requestId = requestAnimationFrame(update);
graph.stopHistoryBatch();
}
}
}
Expand Down
94 changes: 65 additions & 29 deletions packages/g6/src/stdlib/behavior/scroll-canvas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isBoolean, isObject } from '@antv/util';
import { isBoolean, isNumber, isObject } from '@antv/util';
import { Behavior } from '../../types/behavior';
import { ID, IG6GraphEvent } from '../../types';

Expand Down Expand Up @@ -51,16 +51,11 @@ const DEFAULT_OPTIONS: ScrollCanvasOptions = {
direction: 'both',
enableOptimize: false,
zoomKey: 'ctrl',
// scroll-canvas 可滚动的扩展范围,默认为 0,即最多可以滚动一屏的位置
// 当设置的值大于 0 时,即滚动可以超过一屏
// 当设置的值小于 0 时,相当于缩小了可滚动范围
// 具体实例可参考:https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*IFfoS67_HssAAAAAAAAAAAAAARQnAQ
scalableRange: 0,
allowDragOnItem: true,
zoomRatio: 0.05,
};


export class ScrollCanvas extends Behavior {
private hiddenEdgeIds: ID[];
private hiddenNodeIds: ID[];
Expand All @@ -81,19 +76,22 @@ export class ScrollCanvas extends Behavior {
};
};

onWheel(ev: IG6GraphEvent & { deltaX?: number; deltaY?: number; }) {
onWheel(ev: IG6GraphEvent & { deltaX?: number; deltaY?: number }) {
if (!this.allowDrag(ev)) return;
const graph = this.graph;
const { zoomKey, zoomRatio, scalableRange, direction, enableOptimize } = this.options;
const { zoomKey, zoomRatio, scalableRange, direction, enableOptimize } =
this.options;
const zoomKeys = Array.isArray(zoomKey) ? [].concat(zoomKey) : [zoomKey];
if (zoomKeys.includes('control')) zoomKeys.push('ctrl');
const keyDown = zoomKeys.some((ele) => ev[`${ele}Key`]);

const nativeEvent = ev.nativeEvent as WheelEvent & { wheelDelta: number } | undefined;
const nativeEvent = ev.nativeEvent as
| (WheelEvent & { wheelDelta: number })
| undefined;

if (keyDown) {
const canvas = graph.canvas;
const point = canvas.client2Viewport({ x: ev.client.x, y: ev.client.y});
const point = canvas.client2Viewport({ x: ev.client.x, y: ev.client.y });
let ratio = graph.getZoom();
if (nativeEvent && nativeEvent.wheelDelta > 0) {
ratio = ratio + ratio * zoomRatio;
Expand Down Expand Up @@ -221,8 +219,14 @@ export class ScrollCanvas extends Behavior {

private hideShapes() {
const { graph, options } = this;
const { tileBehavior: graphBehaviorOptimize, tileBehaviorSize = 1000 } =
graph.getSpecification().optimize || {};
const { optimizeZoom } = options;
if (this.options.enableOptimize) {
const optimize = this.options.enableOptimize || graphBehaviorOptimize;
const shouldOptimzie = isNumber(optimize)
? graph.getAllNodesData().length > optimize
: optimize;
if (shouldOptimzie) {
const currentZoom = graph.getZoom();
const newHiddenEdgeIds = graph
.getAllEdgesData()
Expand All @@ -240,14 +244,27 @@ export class ScrollCanvas extends Behavior {
.getAllNodesData()
.map((node) => node.id)
.filter((id) => graph.getItemVisible(id));
// draw node's keyShapes on transient, and then hidden the real nodes;
newHiddenNodeIds.forEach((id) => {
graph.drawTransient('node', id, {
onlyDrawKeyShape: true,
upsertAncestors: false,
});
});
graph.hideItem(newHiddenNodeIds, true);

let requestId;
const sectionNum = Math.ceil(newHiddenNodeIds.length / tileBehaviorSize);
const sections = Array.from({ length: sectionNum }, (v, i) =>
newHiddenNodeIds.slice(
i * tileBehaviorSize,
i * tileBehaviorSize + tileBehaviorSize,
),
);
const update = () => {
if (!sections.length) {
cancelAnimationFrame(requestId);
return;
}
const section = sections.shift();
graph.startHistoryBatch();
graph.hideItem(section, false, true);
graph.stopHistoryBatch();
requestId = requestAnimationFrame(update);
};
requestId = requestAnimationFrame(update);

if (currentZoom < optimizeZoom) {
this.hiddenNodeIds.push(...newHiddenNodeIds);
Expand All @@ -267,20 +284,39 @@ export class ScrollCanvas extends Behavior {
return;
}

this.hiddenEdgeIds = this.hiddenNodeIds = [];
if (!this.options.enableOptimize) {
const { tileBehavior: graphBehaviorOptimize, tileBehaviorSize = 1000 } =
graph.getSpecification().optimize || {};
const optimize = this.options.enableOptimize || graphBehaviorOptimize;
const shouldOptimzie = isNumber(optimize)
? graph.getAllNodesData().length > optimize
: optimize;
if (!shouldOptimzie) {
this.hiddenEdgeIds = this.hiddenNodeIds = [];
return;
}

if (hiddenEdgeIds) {
graph.showItem(hiddenEdgeIds, true);
}
if (hiddenNodeIds) {
hiddenNodeIds.forEach((id) => {
this.graph.drawTransient('node', id, { action: 'remove' });
let requestId;
const hiddenIds = [...hiddenNodeIds, ...hiddenEdgeIds];
const sectionNum = Math.ceil(hiddenIds.length / tileBehaviorSize);
const sections = Array.from({ length: sectionNum }, (v, i) =>
hiddenIds.slice(
i * tileBehaviorSize,
i * tileBehaviorSize + tileBehaviorSize,
),
);
const update = () => {
if (!sections.length) {
cancelAnimationFrame(requestId);
return;
}
graph.executeWithNoStack(() => {
graph.showItem(sections.shift(), false);
});
graph.showItem(hiddenNodeIds, true);
}
requestId = requestAnimationFrame(update);
};
requestId = requestAnimationFrame(update);

this.hiddenEdgeIds = this.hiddenNodeIds = [];
}
}

Expand Down
12 changes: 6 additions & 6 deletions packages/g6/src/stdlib/behavior/zoom-canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,12 @@ export class ZoomCanvas extends Behavior {
return;
}
const section = sections.shift();
graph.startHistoryBatch();
graph.hideItem(section, false, true);
graph.stopHistoryBatch();
requestId = requestAnimationFrame(update);
};
graph.startHistoryBatch();
requestId = requestAnimationFrame(update);
graph.stopHistoryBatch();
}
}

Expand Down Expand Up @@ -180,12 +180,12 @@ export class ZoomCanvas extends Behavior {
cancelAnimationFrame(requestId);
return;
}
graph.showItem(sections.shift(), false);
graph.executeWithNoStack(() => {
graph.showItem(sections.shift(), false);
});
requestId = requestAnimationFrame(update);
};
graph.executeWithNoStack(() => {
requestId = requestAnimationFrame(update);
});
requestId = requestAnimationFrame(update);
}
}
this.hiddenEdgeIds = [];
Expand Down

0 comments on commit affd3c5

Please sign in to comment.