mirror of
https://gitee.com/antv/g6.git
synced 2024-11-30 18:58:34 +08:00
Merge pull request #4989 from ColinChen2/feature/edge-filter-lens
Feature/edge filter lens
This commit is contained in:
commit
20bb27cffa
@ -46,7 +46,7 @@
|
||||
"fix": "eslint ./src ./tests --fix && prettier ./src ./tests --write ",
|
||||
"test": "jest",
|
||||
"test:integration": "node --expose-gc --max-old-space-size=4096 --unhandled-rejections=strict node_modules/jest/bin/jest tests/integration/ --config jest.node.config.js --coverage -i --logHeapUsage --detectOpenHandles",
|
||||
"test:integration_one": "node --expose-gc --max-old-space-size=4096 --unhandled-rejections=strict node_modules/jest/bin/jest tests/integration/items-edge-loop.spec.ts --config jest.node.config.js --coverage -i --logHeapUsage --detectOpenHandles",
|
||||
"test:integration_one": "node --expose-gc --max-old-space-size=4096 --unhandled-rejections=strict node_modules/jest/bin/jest tests/integration/plugins-edgeFilterLens.spec.ts --config jest.node.config.js --coverage -i --logHeapUsage --detectOpenHandles",
|
||||
"size": "limit-size",
|
||||
"test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/item-animate-spec.ts",
|
||||
"test-behavior": "DEBUG_MODE=1 jest --watch ./tests/unit/item-3d-spec.ts"
|
||||
|
@ -77,6 +77,7 @@ const {
|
||||
Toolbar,
|
||||
Timebar,
|
||||
Snapline,
|
||||
EdgeFilterLens,
|
||||
} = Plugins;
|
||||
|
||||
const {
|
||||
@ -292,6 +293,7 @@ const Extensions = {
|
||||
Timebar,
|
||||
Hull,
|
||||
Snapline,
|
||||
EdgeFilterLens,
|
||||
WaterMarker
|
||||
};
|
||||
|
||||
|
380
packages/g6/src/stdlib/plugin/edgeFilterLens/index.ts
Normal file
380
packages/g6/src/stdlib/plugin/edgeFilterLens/index.ts
Normal file
@ -0,0 +1,380 @@
|
||||
import { DisplayObject } from '@antv/g';
|
||||
import { clone } from '@antv/util';
|
||||
import { Plugin as Base, IPluginBaseConfig } from '../../../types/plugin';
|
||||
import { IGraph } from '../../../types';
|
||||
import { IG6GraphEvent } from '../../../types/event';
|
||||
import { ShapeStyle } from '../../../types/item';
|
||||
import { distance } from '../../../util/point';
|
||||
|
||||
const DELTA = 0.01;
|
||||
interface EdgeFilterLensConfig extends IPluginBaseConfig {
|
||||
trigger?: 'mousemove' | 'click' | 'drag';
|
||||
r?: number;
|
||||
delegateStyle?: ShapeStyle;
|
||||
showLabel?: 'node' | 'edge' | 'both' | undefined;
|
||||
scaleRBy?: 'wheel' | undefined;
|
||||
maxR?: number;
|
||||
minR?: number;
|
||||
showType?: 'one' | 'both' | 'only-source' | 'only-target'; // 更名,原名与plugin的type冲突
|
||||
shouldShow?: (d?: unknown) => boolean;
|
||||
}
|
||||
|
||||
const lensDelegateStyle = {
|
||||
stroke: '#000',
|
||||
strokeOpacity: 0.8,
|
||||
lineWidth: 2,
|
||||
fillOpacity: 0.1,
|
||||
fill: '#fff',
|
||||
};
|
||||
|
||||
export class EdgeFilterLens extends Base {
|
||||
private showNodeLabel: boolean;
|
||||
private showEdgeLabel: boolean;
|
||||
private delegate: DisplayObject;
|
||||
private cachedTransientNodes: Set<string | number>;
|
||||
private cachedTransientEdges: Set<string | number>;
|
||||
private dragging: boolean;
|
||||
private delegateCenterDiff: { x: number; y: number };
|
||||
|
||||
constructor(config?: EdgeFilterLensConfig) {
|
||||
super(config);
|
||||
this.cachedTransientNodes = new Set();
|
||||
this.cachedTransientEdges = new Set();
|
||||
}
|
||||
|
||||
public getDefaultCfgs(): EdgeFilterLensConfig {
|
||||
return {
|
||||
showType: 'both',
|
||||
trigger: 'mousemove',
|
||||
r: 60,
|
||||
delegateStyle: clone(lensDelegateStyle),
|
||||
showLabel: 'edge',
|
||||
scaleRBy: 'wheel',
|
||||
};
|
||||
}
|
||||
|
||||
public getEvents() {
|
||||
let events = {
|
||||
pointerdown: this.onPointerDown,
|
||||
pointerup: this.onPointerUp,
|
||||
wheel: this.onWheel,
|
||||
} as {
|
||||
[key: string]: any;
|
||||
};
|
||||
switch (this.options.trigger) {
|
||||
case 'click':
|
||||
events = {
|
||||
...events,
|
||||
click: this.filter,
|
||||
};
|
||||
break;
|
||||
case 'drag':
|
||||
events = {
|
||||
...events,
|
||||
pointermove: this.onPointerMove,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
events = {
|
||||
...events,
|
||||
pointermove: this.filter,
|
||||
};
|
||||
break;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
public init(graph: IGraph) {
|
||||
super.init(graph);
|
||||
const showLabel = this.options.showLabel;
|
||||
const showNodeLabel = showLabel === 'node' || showLabel === 'both';
|
||||
const showEdgeLabel = showLabel === 'edge' || showLabel === 'both';
|
||||
this.showNodeLabel = showNodeLabel;
|
||||
this.showEdgeLabel = showEdgeLabel;
|
||||
const shouldShow = this.options.shouldShow;
|
||||
if (!shouldShow) this.options.shouldShow = () => true;
|
||||
}
|
||||
|
||||
protected onPointerUp(e: IG6GraphEvent) {
|
||||
this.dragging = false;
|
||||
}
|
||||
|
||||
protected onPointerMove(e: IG6GraphEvent) {
|
||||
if (!this.dragging) return;
|
||||
this.moveDelegate(e);
|
||||
}
|
||||
|
||||
protected onPointerDown(e: IG6GraphEvent) {
|
||||
const { delegate: lensDelegate } = this;
|
||||
let cacheCenter;
|
||||
if (!lensDelegate || lensDelegate.destroyed) {
|
||||
cacheCenter = { x: e.canvas.x, y: e.canvas.y };
|
||||
this.filter(e);
|
||||
} else {
|
||||
cacheCenter = {
|
||||
x: lensDelegate.style.cx,
|
||||
y: lensDelegate.style.cy,
|
||||
};
|
||||
}
|
||||
this.delegateCenterDiff = {
|
||||
x: e.canvas.x - cacheCenter.x,
|
||||
y: e.canvas.y - cacheCenter.y,
|
||||
};
|
||||
this.dragging = true;
|
||||
}
|
||||
|
||||
// Determine whether it is dragged in the delegate
|
||||
protected isInLensDelegate(lensDelegate, pointer): boolean {
|
||||
const { cx: lensX, cy: lensY, r: lensR } = lensDelegate.style;
|
||||
if (
|
||||
pointer.x >= lensX - lensR &&
|
||||
pointer.x <= lensX + lensR &&
|
||||
pointer.y >= lensY - lensR &&
|
||||
pointer.y <= lensY + lensR
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected moveDelegate(e) {
|
||||
if (
|
||||
this.isInLensDelegate(this.delegate, { x: e.canvas.x, y: e.canvas.y })
|
||||
) {
|
||||
const center = {
|
||||
x: e.canvas.x - this.delegateCenterDiff.x,
|
||||
y: e.canvas.y - this.delegateCenterDiff.y,
|
||||
};
|
||||
this.filter(e, center);
|
||||
}
|
||||
}
|
||||
|
||||
protected onWheel(e: IG6GraphEvent) {
|
||||
const { delegate: lensDelegate, options } = this;
|
||||
const { scaleRBy } = options;
|
||||
if (!lensDelegate || lensDelegate.destroyed) return;
|
||||
if (scaleRBy !== 'wheel') return;
|
||||
if (this.isInLensDelegate(lensDelegate, { x: e.canvas.x, y: e.canvas.y })) {
|
||||
if (scaleRBy === 'wheel') {
|
||||
this.scaleRByWheel(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the range by wheel
|
||||
* @param e mouse wheel event
|
||||
*/
|
||||
protected scaleRByWheel(e: IG6GraphEvent) {
|
||||
if (!e || !e.originalEvent) return;
|
||||
if (e.preventDefault) e.preventDefault();
|
||||
const { graph, options } = this;
|
||||
const graphCanvasEl = graph.canvas.context.config.canvas;
|
||||
const graphHeight = graphCanvasEl?.height || 500;
|
||||
const maxR = options.maxR
|
||||
? Math.min(options.maxR, graphHeight)
|
||||
: graphHeight;
|
||||
const minR = options.minR
|
||||
? Math.max(options.minR, graphHeight * DELTA)
|
||||
: graphHeight * DELTA;
|
||||
|
||||
const scale = 1 + (e.originalEvent as any).deltaY * -1 * DELTA;
|
||||
let r = options.r * scale;
|
||||
r = Math.min(r, maxR);
|
||||
r = Math.max(r, minR);
|
||||
options.r = r;
|
||||
this.delegate.style.r = r;
|
||||
this.filter(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Response function for mousemove, click, or drag to filter out the edges
|
||||
* @param e mouse event
|
||||
*/
|
||||
protected filter(e: IG6GraphEvent, mousePos?) {
|
||||
const {
|
||||
graph,
|
||||
options,
|
||||
showNodeLabel,
|
||||
showEdgeLabel,
|
||||
cachedTransientNodes,
|
||||
cachedTransientEdges,
|
||||
} = this;
|
||||
const r = options.r;
|
||||
const showType = options.showType;
|
||||
const shouldShow = options.shouldShow;
|
||||
const fCenter = mousePos || { x: e.canvas.x, y: e.canvas.y };
|
||||
this.updateDelegate(fCenter, r);
|
||||
|
||||
const nodes = graph.getAllNodesData();
|
||||
const hitNodesMap = {};
|
||||
nodes.forEach((node) => {
|
||||
const { data, id } = node;
|
||||
if (distance({ x: data.x, y: data.y }, fCenter) < r) {
|
||||
hitNodesMap[id] = node;
|
||||
}
|
||||
});
|
||||
|
||||
const edges = graph.getAllEdgesData();
|
||||
const hitEdges = [];
|
||||
edges.forEach((edge) => {
|
||||
const sourceId = edge.source;
|
||||
const targetId = edge.target;
|
||||
if (shouldShow(edge)) {
|
||||
if (showType === 'only-source' || showType === 'one') {
|
||||
if (hitNodesMap[sourceId] && !hitNodesMap[targetId])
|
||||
hitEdges.push(edge);
|
||||
} else if (showType === 'only-target' || showType === 'one') {
|
||||
if (hitNodesMap[targetId] && !hitNodesMap[sourceId])
|
||||
hitEdges.push(edge);
|
||||
} else if (
|
||||
showType === 'both' &&
|
||||
hitNodesMap[sourceId] &&
|
||||
hitNodesMap[targetId]
|
||||
) {
|
||||
hitEdges.push(edge);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const currentTransientNodes = new Set<string | number>();
|
||||
const currentTransientEdges = new Set<string | number>();
|
||||
|
||||
if (showNodeLabel) {
|
||||
Object.keys(hitNodesMap).forEach((key) => {
|
||||
const node = hitNodesMap[key];
|
||||
currentTransientNodes.add(node.id);
|
||||
|
||||
if (cachedTransientNodes.has(node.id)) {
|
||||
cachedTransientNodes.delete(node.id);
|
||||
} else {
|
||||
graph.drawTransient('node', node.id, { shapeIds: ['labelShape'] });
|
||||
}
|
||||
});
|
||||
|
||||
cachedTransientNodes.forEach((id) => {
|
||||
graph.drawTransient('node', id, { action: 'remove' });
|
||||
});
|
||||
}
|
||||
|
||||
if (showEdgeLabel) {
|
||||
hitEdges.forEach((edge) => {
|
||||
currentTransientEdges.add(edge.id);
|
||||
|
||||
if (cachedTransientEdges.has(edge.id)) {
|
||||
cachedTransientEdges.delete(edge.id);
|
||||
} else {
|
||||
graph.drawTransient('edge', edge.id, {
|
||||
shapeIds: ['labelShape'],
|
||||
drawSource: false,
|
||||
drawTarget: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
cachedTransientEdges.forEach((id) => {
|
||||
graph.drawTransient('edge', id, { action: 'remove' });
|
||||
});
|
||||
}
|
||||
|
||||
this.cachedTransientNodes = currentTransientNodes;
|
||||
this.cachedTransientEdges = currentTransientEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust part of the parameters, including trigger, showType, r, maxR, minR, shouldShow, showLabel, and scaleRBy
|
||||
* @param {EdgeFilterLensConfig} cfg
|
||||
*/
|
||||
public updateParams(cfg: EdgeFilterLensConfig) {
|
||||
const self = this;
|
||||
const { r, trigger, minR, maxR, scaleRBy, showLabel, shouldShow } = cfg;
|
||||
if (!isNaN(cfg.r)) {
|
||||
self.options.r = r;
|
||||
}
|
||||
if (!isNaN(maxR)) {
|
||||
self.options.maxR = maxR;
|
||||
}
|
||||
if (!isNaN(minR)) {
|
||||
self.options.minR = minR;
|
||||
}
|
||||
if (trigger === 'mousemove' || trigger === 'click' || trigger === 'drag') {
|
||||
self.options.trigger = trigger;
|
||||
}
|
||||
if (scaleRBy === 'wheel' || scaleRBy === 'unset') {
|
||||
self.options.scaleRBy = scaleRBy;
|
||||
self.delegate.remove();
|
||||
self.delegate.destroy();
|
||||
}
|
||||
if (showLabel === 'node' || showLabel === 'both') {
|
||||
self.showNodeLabel = true;
|
||||
}
|
||||
if (showLabel === 'edge' || showLabel === 'both') {
|
||||
self.showEdgeLabel = true;
|
||||
}
|
||||
if (shouldShow) {
|
||||
self.options.shouldShow = shouldShow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the delegate shape of the lens
|
||||
* @param {Point} mCenter the center of the shape
|
||||
* @param {number} r the radius of the shape
|
||||
*/
|
||||
private updateDelegate(mCenter, r) {
|
||||
const { graph, options, delegate } = this;
|
||||
let lensDelegate = delegate;
|
||||
if (!lensDelegate || lensDelegate.destroyed) {
|
||||
// 拖动多个
|
||||
const attrs = options.delegateStyle || lensDelegateStyle;
|
||||
|
||||
// model上的x, y是相对于图形中心的,delegateShape是g实例,x,y是绝对坐标
|
||||
lensDelegate = graph.drawTransient('circle', 'lens-shape', {
|
||||
style: {
|
||||
r,
|
||||
cx: mCenter.x,
|
||||
cy: mCenter.y,
|
||||
...attrs,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
lensDelegate.style.cx = mCenter.x;
|
||||
lensDelegate.style.cy = mCenter.y;
|
||||
lensDelegate.style.r = mCenter.r;
|
||||
}
|
||||
|
||||
this.delegate = lensDelegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the filtering
|
||||
*/
|
||||
public clear() {
|
||||
const {
|
||||
graph,
|
||||
delegate: lensDelegate,
|
||||
cachedTransientNodes,
|
||||
cachedTransientEdges,
|
||||
} = this;
|
||||
|
||||
if (lensDelegate && !lensDelegate.destroyed) {
|
||||
graph.drawTransient('circle', 'lens-shape', { action: 'remove' });
|
||||
}
|
||||
cachedTransientNodes.forEach((id) => {
|
||||
graph.drawTransient('node', id, { action: 'remove' });
|
||||
});
|
||||
cachedTransientEdges.forEach((id) => {
|
||||
graph.drawTransient('edge', id, { action: 'remove' });
|
||||
});
|
||||
|
||||
cachedTransientNodes.clear();
|
||||
cachedTransientEdges.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the component
|
||||
*/
|
||||
public destroy() {
|
||||
this.clear();
|
||||
}
|
||||
}
|
@ -8,3 +8,4 @@ export * from './toolbar';
|
||||
export * from './tooltip';
|
||||
export * from './timebar';
|
||||
export * from './snapline';
|
||||
export * from './edgeFilterLens';
|
||||
|
@ -8,3 +8,4 @@ export type { ToolbarConfig } from './toolbar';
|
||||
export type { TooltipConfig } from './tooltip';
|
||||
export type { TimebarConfig } from './timebar';
|
||||
export type { SnapLineConfig } from './snapline';
|
||||
export type { EdgeFilterLens } from './edgeFilterLens';
|
||||
|
@ -64,6 +64,7 @@ import legend from './plugins/legend';
|
||||
import snapline from './plugins/snapline';
|
||||
import mapper from './visual/mapper';
|
||||
import minimap from './plugins/minimap';
|
||||
import edgeFilterLens from './plugins/edgeFilterLens';
|
||||
import watermarker from './plugins/watermarker';
|
||||
import cube from './item/node/cube';
|
||||
import graphCore from './data/graphCore';
|
||||
@ -138,7 +139,8 @@ export {
|
||||
hull,
|
||||
legend,
|
||||
snapline,
|
||||
watermarker
|
||||
edgeFilterLens,
|
||||
watermarker,
|
||||
cube,
|
||||
graphCore,
|
||||
dagreUpdate,
|
||||
|
195
packages/g6/tests/demo/plugins/edgeFilterLens.ts
Normal file
195
packages/g6/tests/demo/plugins/edgeFilterLens.ts
Normal file
@ -0,0 +1,195 @@
|
||||
import { Graph, Extensions, extend } from '../../../src/index';
|
||||
import { TestCaseContext } from '../interface';
|
||||
import data from '../../datasets/force-data.json';
|
||||
import { clone } from '@antv/util';
|
||||
|
||||
export default (context: TestCaseContext, options = {}) => {
|
||||
const trigger = 'mousemove';
|
||||
let filterLens = {
|
||||
type: 'filterLens',
|
||||
key: 'filterLens1',
|
||||
trigger,
|
||||
showLabel: 'edge',
|
||||
r: 140,
|
||||
...options,
|
||||
};
|
||||
|
||||
// ================= The DOMs for configurations =============== //
|
||||
const graphDiv = document.getElementById('container');
|
||||
|
||||
const buttonContainer = document.createElement('div');
|
||||
buttonContainer.style.display = 'inline-block';
|
||||
buttonContainer.style.height = '35px';
|
||||
buttonContainer.style.width = '100%';
|
||||
buttonContainer.style.textAlign = 'center';
|
||||
|
||||
// tip
|
||||
const tip = document.createElement('span');
|
||||
tip.innerHTML =
|
||||
'点击画布任意位置开始探索。过滤镜中显示两端节点均在过滤镜中的边。';
|
||||
buttonContainer.appendChild(tip);
|
||||
|
||||
buttonContainer.appendChild(document.createElement('br'));
|
||||
|
||||
// tip english
|
||||
const tipEn = document.createElement('span');
|
||||
tipEn.innerHTML =
|
||||
'Click the canvas to begin. Show the edge whose both end nodes are inside the lens.';
|
||||
buttonContainer.appendChild(tipEn);
|
||||
|
||||
buttonContainer.appendChild(document.createElement('br'));
|
||||
|
||||
// enable/disable the fisheye lens button
|
||||
const swithButton = document.createElement('input');
|
||||
swithButton.type = 'button';
|
||||
swithButton.value = 'Disable';
|
||||
swithButton.style.height = '25px';
|
||||
swithButton.style.width = '60px';
|
||||
swithButton.style.marginLeft = '16px';
|
||||
buttonContainer.appendChild(swithButton);
|
||||
|
||||
// list for changing trigger
|
||||
const triggerTag = document.createElement('span');
|
||||
triggerTag.innerHTML = 'Trigger:';
|
||||
triggerTag.style.marginLeft = '16px';
|
||||
buttonContainer.appendChild(triggerTag);
|
||||
const configTrigger = document.createElement('select');
|
||||
configTrigger.value = 'mousemove';
|
||||
configTrigger.style.height = '25px';
|
||||
configTrigger.style.width = '100px';
|
||||
configTrigger.style.marginLeft = '8px';
|
||||
const mousemoveTrigger = document.createElement('option');
|
||||
mousemoveTrigger.value = 'mousemove';
|
||||
mousemoveTrigger.innerHTML = 'mousemove';
|
||||
configTrigger.appendChild(mousemoveTrigger);
|
||||
const dragTrigger = document.createElement('option');
|
||||
dragTrigger.value = 'drag';
|
||||
dragTrigger.innerHTML = 'drag';
|
||||
configTrigger.appendChild(dragTrigger);
|
||||
const clickTrigger = document.createElement('option');
|
||||
clickTrigger.value = 'click';
|
||||
clickTrigger.innerHTML = 'click';
|
||||
configTrigger.appendChild(clickTrigger);
|
||||
buttonContainer.appendChild(configTrigger);
|
||||
|
||||
// list for changing scaleRBy
|
||||
const scaleR = document.createElement('span');
|
||||
scaleR.innerHTML = 'Scale r by:';
|
||||
scaleR.style.marginLeft = '16px';
|
||||
buttonContainer.appendChild(scaleR);
|
||||
const configScaleRBy = document.createElement('select');
|
||||
configScaleRBy.value = 'wheel';
|
||||
configScaleRBy.style.height = '25px';
|
||||
configScaleRBy.style.width = '100px';
|
||||
configScaleRBy.style.marginLeft = '8px';
|
||||
const scaleRByWheel = document.createElement('option');
|
||||
scaleRByWheel.value = 'wheel';
|
||||
scaleRByWheel.innerHTML = 'wheel';
|
||||
configScaleRBy.appendChild(scaleRByWheel);
|
||||
const scaleRByUnset = document.createElement('option');
|
||||
scaleRByUnset.value = 'unset';
|
||||
scaleRByUnset.innerHTML = 'unset';
|
||||
configScaleRBy.appendChild(scaleRByUnset);
|
||||
buttonContainer.appendChild(configScaleRBy);
|
||||
|
||||
graphDiv.parentNode.appendChild(buttonContainer);
|
||||
|
||||
// ========================================================= //
|
||||
|
||||
const ExtGraph = extend(Graph, {
|
||||
plugins: {
|
||||
filterLens: Extensions.EdgeFilterLens,
|
||||
},
|
||||
});
|
||||
const graph = new ExtGraph({
|
||||
...context,
|
||||
layout: {
|
||||
type: 'grid',
|
||||
begin: [0, 0],
|
||||
},
|
||||
plugins: [filterLens],
|
||||
node: (innerModel) => {
|
||||
return {
|
||||
...innerModel,
|
||||
data: {
|
||||
...innerModel.data,
|
||||
lodStrategy: {
|
||||
levels: [
|
||||
{ zoomRange: [0, 0.9] }, // -1
|
||||
{ zoomRange: [0.9, 1], primary: true }, // 0
|
||||
{ zoomRange: [1, 1.2] }, // 1
|
||||
{ zoomRange: [1.2, 1.5] }, // 2
|
||||
{ zoomRange: [1.5, Infinity] }, // 3
|
||||
],
|
||||
animateCfg: {
|
||||
duration: 500,
|
||||
},
|
||||
},
|
||||
labelShape: {
|
||||
text: innerModel.data.label,
|
||||
lod: 1, // 图的缩放大于 levels 第一层定义的 zoomRange[0] 时展示,小于时隐藏
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
edge: (innerModel) => {
|
||||
return {
|
||||
...innerModel,
|
||||
data: {
|
||||
...innerModel.data,
|
||||
lodStrategy: {
|
||||
levels: [
|
||||
{ zoomRange: [0, 0.9] }, // -1
|
||||
{ zoomRange: [0.9, 1], primary: true }, // 0
|
||||
{ zoomRange: [1, 1.2] }, // 1
|
||||
{ zoomRange: [1.2, 1.5] }, // 2
|
||||
{ zoomRange: [1.5, Infinity] }, // 3
|
||||
],
|
||||
animateCfg: {
|
||||
duration: 500,
|
||||
},
|
||||
},
|
||||
labelShape: {
|
||||
text: innerModel.data.label,
|
||||
maxWidth: '100%',
|
||||
lod: 1, // 图的缩放大于 levels 第一层定义的 zoomRange[0] 时展示,小于时隐藏
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
modes: {
|
||||
// default: ['drag-canvas',],
|
||||
},
|
||||
});
|
||||
|
||||
swithButton.addEventListener('click', (e) => {
|
||||
if (swithButton.value === 'Disable') {
|
||||
swithButton.value = 'Enable';
|
||||
graph.removePlugins(['filterLens1']);
|
||||
} else {
|
||||
swithButton.value = 'Disable';
|
||||
graph.addPlugins([filterLens]);
|
||||
}
|
||||
});
|
||||
configScaleRBy.addEventListener('change', (e) => {
|
||||
filterLens = {
|
||||
...filterLens,
|
||||
scaleRBy: e.target.value,
|
||||
};
|
||||
graph.updatePlugin(filterLens);
|
||||
});
|
||||
configTrigger.addEventListener('change', (e) => {
|
||||
filterLens = {
|
||||
...filterLens,
|
||||
trigger: e.target.value,
|
||||
};
|
||||
graph.updatePlugin(filterLens);
|
||||
});
|
||||
|
||||
const cloneData = clone(data);
|
||||
cloneData.edges.forEach((edge) => (edge.data = { label: edge.id }));
|
||||
graph.read(cloneData);
|
||||
graph.zoom(0.6);
|
||||
|
||||
return graph;
|
||||
};
|
42
packages/g6/tests/integration/plugins-edgeFilterLens.spec.ts
Normal file
42
packages/g6/tests/integration/plugins-edgeFilterLens.spec.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { resetEntityCounter } from '@antv/g';
|
||||
import EdgeFilterLens from '../demo/plugins/edgeFilterLens';
|
||||
import { createContext, sleep } from './utils';
|
||||
import { triggerEvent } from './utils/event';
|
||||
import './utils/useSnapshotMatchers';
|
||||
|
||||
describe('Default EdgeFilterLens', () => {
|
||||
beforeEach(() => {
|
||||
resetEntityCounter();
|
||||
});
|
||||
|
||||
it('should be rendered correctly with fitler lens with mousemove', async () => {
|
||||
const dir = `${__dirname}/snapshots/canvas/plugins/edgeFilterLens`;
|
||||
const { backgroundCanvas, canvas, transientCanvas, container } =
|
||||
createContext('canvas', 500, 500);
|
||||
const graph = EdgeFilterLens({
|
||||
backgroundCanvas,
|
||||
canvas,
|
||||
transientCanvas,
|
||||
width: 500,
|
||||
height: 500,
|
||||
container,
|
||||
});
|
||||
console.log('graph', graph);
|
||||
|
||||
const process = new Promise((reslove) => {
|
||||
graph.on('afterlayout', () => {
|
||||
console.log('afterlayout');
|
||||
reslove();
|
||||
});
|
||||
});
|
||||
|
||||
await process;
|
||||
await sleep(300);
|
||||
triggerEvent(graph, 'mousedown', 200, 200);
|
||||
await expect(transientCanvas).toMatchCanvasSnapshot(
|
||||
dir,
|
||||
'plugins-edge-filter-lens-transients',
|
||||
);
|
||||
graph.destroy();
|
||||
});
|
||||
});
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Loading…
Reference in New Issue
Block a user