feat: fisheye plugin, support clear, update, show labels.

This commit is contained in:
Yanyan-Wang 2020-07-24 20:01:35 +08:00 committed by Yanyan Wang
parent 41abeae5a2
commit 7936523d67
5 changed files with 113 additions and 13 deletions

View File

@ -1,5 +1,8 @@
# ChangeLog
#### 3.5
- feat: fisheye lens plugin.
#### 3.5.12
- fix: node:click is triggered twice while clicking a node;
- fix: update combo edge when drag node out of it problem;

View File

@ -1,6 +1,6 @@
{
"name": "@antv/g6",
"version": "3.5.12",
"version": "3.6.0",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",

View File

@ -1,5 +1,5 @@
export default {
version: '3.5.12',
version: '3.6.0',
rootContainerClassName: 'root-container',
nodeContainerClassName: 'node-container',
edgeContainerClassName: 'edge-container',

View File

@ -1,6 +1,6 @@
import createDOM from '@antv/dom-util/lib/create-dom';
import modifyCSS from '@antv/dom-util/lib/modify-css';
import { IG6GraphEvent } from '../../types';
import { IG6GraphEvent, ShapeStyle } from '../../types';
import { IGraph } from '../../interface/graph';
import Graph from '../../graph/graph';
import Base from '../base';
@ -8,7 +8,17 @@ import Base from '../base';
interface FisheyeConfig {
trigger?: 'mousemove' | 'click',
d?: number,
r?: number
r?: number,
delegateStyle?: ShapeStyle,
showLabel?: boolean
}
const lensDelegateStyle = {
stroke: '#000',
strokeOpacity: 0.8,
lineWidth: 2,
fillOpacity: 0.1,
fill: '#ccc'
}
export default class Fisheye extends Base {
constructor(cfg?: FisheyeConfig) {
@ -18,7 +28,9 @@ export default class Fisheye extends Base {
return {
trigger: 'mousemove',
d: 1.5,
r: 100
r: 300,
delegateStyle: lensDelegateStyle,
showLabel: false
};
}
@ -53,12 +65,14 @@ export default class Fisheye extends Base {
const graph: Graph = self.get('graph');
const cachedMagnifiedModels = self.get('cachedMagnifiedModels');
const cachedOriginPositions = self.get('cachedOriginPositions');
const showLabel = self.get('showLabel');
const r = self.get('r');
const r2 = self.get('r2');
const d = self.get('d');
const nodes = graph.getNodes();
const nodeLength = nodes.length;
const mCenter = { x: e.x, y: e.y };
self.updateDelegate(mCenter, r);
for (let i = 0; i < nodeLength; i++) {
const model = nodes[i].getModel();
const { x, y } = model;
@ -73,9 +87,26 @@ export default class Fisheye extends Base {
model.x = cos * magnifiedDist + mCenter.x;
model.y = sin * magnifiedDist + mCenter.y;
if (!cachedOriginPositions[model.id]) {
cachedOriginPositions[model.id] = { x, y };
cachedOriginPositions[model.id] = { x, y, texts: [] };
}
cachedMagnifiedModels.push(model);
if (showLabel && 2 * dist < r) {
const node = nodes[i];
const nodeGroup = node.getContainer();
const shapes = nodeGroup.getChildren();
const shapeLength = shapes.length;
for (let j = 0; j < shapeLength; j++) {
const shape = shapes[j];
if (shape.get('type') === 'text') {
cachedOriginPositions[model.id].texts.push({
visible: shape.get('visible'),
shape
});
shape.set('visible', true);
}
}
}
}
}
graph.refreshPositions();
@ -92,8 +123,12 @@ export default class Fisheye extends Base {
for (let i = 0; i < cacheLength; i++) {
const node = cachedMagnifiedModels[i];
const id = node.id;
node.x = cachedOriginPositions[id].x;
node.y = cachedOriginPositions[id].y;
const ori = cachedOriginPositions[id];
node.x = ori.x;
node.y = ori.y;
ori.texts.forEach(text => {
text.shape.set('visible', text.visible);
});
}
self.set('cachedMagnifiedModels', []);
self.set('cachedOriginPositions', {});
@ -114,10 +149,47 @@ export default class Fisheye extends Base {
}
}
/**
*
* @param {Point} mCenter
* @param {number} r
*/
private updateDelegate(mCenter, r) {
const self = this;
const graph = self.get('graph');
let lensDelegate = self.get('delegate');
if (!lensDelegate || lensDelegate.destroyed) {
// 拖动多个
const parent = graph.get('group');
const attrs = self.get('delegateStyle') || lensDelegateStyle;
// model上的x, y是相对于图形中心的delegateShape是g实例x,y是绝对坐标
lensDelegate = parent.addShape('circle', {
attrs: {
r: r / 1.5,
x: mCenter.x,
y: mCenter.y,
...attrs,
},
name: 'lens-delegate-shape',
});
lensDelegate.set('capture', false);
} else {
lensDelegate.attr({
x: mCenter.x,
y: mCenter.y,
});
}
self.set('delegate', lensDelegate);
}
public clear() {
const graph = this.get('graph');
this.restoreCache();
graph.refreshPositions();
let lensDelegate = this.get('delegate');
lensDelegate.destroy();
}
}

View File

@ -7,20 +7,34 @@ let graph: IGraph = null;
const FishEye = () => {
const container = React.useRef();
const fisheye = new G6.Fisheye({
r: 100
r: 200,
showLabel: true,
});
const colors = [
'#8FE9FF',
'#87EAEF',
'#FFC9E3',
'#A7C2FF',
'#FFA1E3',
'#FFE269',
'#BFCFEE',
'#FFA0C5',
'#D5FF86',
]
useEffect(() => {
if (!graph) {
graph = new G6.Graph({
container: container.current as string | HTMLElement,
width: 500,
height: 500,
width: 1000,
height: 700,
plugins: [fisheye],
layout: {
type: 'force'
type: 'force',
preventOverlap: true
},
modes: {
default: ['drag-canvas']
default: ['drag-canvas', 'zoom-canvas']
}
});
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/relations.json')
@ -28,9 +42,20 @@ const FishEye = () => {
.then(data => {
data.nodes.forEach(node => {
node.label = node.id;
node.size = Math.random() * 40 + 20;
node.style = {
fill: colors[Math.floor(Math.random() * 9)],
lineWidth: 0
}
console.log(node)
});
graph.data(data);
graph.render();
graph.getNodes().forEach(node => {
node.getContainer().getChildren().forEach(shape => {
if (shape.get('type') === 'text') shape.set('visible', false);
});
});
});
}
});