Step 1: 使用命令行在项目目录下执行以下命令:
npm install --save @antv/g6
Step 2: 在需要用的 G6 的 JS 文件中导入:
import G6 from '@antv/g6';
Step 3你需要在template中写一个容器供g6进行绘制canvas
Step 4 准备数据 包含节点nodes和边edges
Step 5 给你的容器宽高
const graph = new G6.Graph({
width: 800, // Number,必须,图的宽度
height: 500, // Number,必须,图的高度
});
Step 6 开始绘制
graph.data(data); // 读取数据源到图上
graph.render(); // 渲染图
实际上深谙项目的我们是不会从零开始绘图的,我们直接在antvg6官网的案例中,找到合适的图例,然后开始魔改。
根据需求 我们本次使用决策树进行魔改
我们将官网上的代码 1部分加入style中,2部分的代码写入data()中,3部分的代码写入一个function里放在methods:中,例drawgraph(){}
;然后在mounted中调用;你以为这样的你会得到你的第一个图,然后并不是,在vue项目中,由于生命周期的关系,mounted阶段$el 尚未挂载dom 此时你的控制台会出现:
此时我们可以写一个尾调用将方法包裹:然后在mounted中调用
delaydrawgraph() {
if (document.getElementById('container') == null) {
this.delaydrawgraph()
}
this.drawgraph()
}
接下来我们就画好了这样一张图
const graph = new G6.Graph({
container: '',
width: 500, //画布宽
height: 500,// 画布高
modes: {
default: ['drag-canvas'],
},
layout: {
type: 'radial',
unitRadius: 50,
center: [500, 300],
},
});
默认包含可拖拽,缩放,当需要选中节点时可配置 使用edit。当我们想要取消默认行为时,
modes: {
default: ['drag-canvas', 'zoom-canvas'],
edit: ['click-select'],
},
当我们想要添加或取消默认行为时,我们可以在initGraph() 方法内 graph.render()之后进行如下操作:
// 向 default 模式中添加名为 drag-canvas 的行为,并使用行为的默认配置
graph.addBehaviors('drag-canvas', 'default');
// 从 default 模式中移除名为 drag-canvas 的行为
graph.removeBehaviors('drag-canvas', 'default');
使用 type 字段指定使用的布局方式,type 可取以下值:random, radial, mds, circular, fruchterman, force, gForce, forceAtlas2, dagre, concentric, grid。
另外树图(const treeGraph = new G6.TreeGraph({})
)配置还包含:dendrogram生态树、compactBox紧凑树、mindmap脑图树 和 indented缩进树
由于本次使用树图 以下属性基于树图的基础使用
fitView: false,
animate: true,
defaultNode: {
type: 'tree-node'
},
defaultEdge: {
// type: 'arc',
type: 'hvh',
style: {
stroke: '#987EFB',
lineWidth: 1
}
},
是否开启画布自适应。开启后图自动适配画布大小。
G6 的内置节点包括 circle,rect,ellipse,diamond,triangle,star,image,modelRect,donut(v4.2.5 起支持)
G6.registerNode()
以官网决策树部分代码为例进行分析
G6.registerNode(
'flow-rect',// 和defaultNode中的type需保持一致
{
shapeType: 'flow-rect',
draw(cfg, group) {
const {
label,
} = cfg;
// cfg拿到了整个实例,我们可以在上面找到数
//据、样式、属性等
// ##########################################
const nodeOrigin = {
x: -rectConfig.width / 2,
y: -rectConfig.height / 2,
};
const textConfig = {
textAlign: 'left',
textBaseline: 'bottom',
};
const rect = group.addShape('rect', {
attrs: {
x: nodeOrigin.x,
y: nodeOrigin.y,
...rectConfig,
},
});
// 这一部分我们可以提取公共配置
// ##########################################
this.drawLinkPoints(cfg, group);
return rect;
},
afterDraw(cfg, group) {},
/**
* 更新节点,包含文本
* @override
* @param {Object} cfg 节点的配置项
* @param {Node} node 节点
*/
update(cfg, node) {},
/**
* 更新节点后的操作,一般同 afterDraw 配合使用
* @override
* @param {Object} cfg 节点的配置项
* @param {Node} node 节点
*/
afterUpdate(cfg, node) {},
/**
* 响应节点的状态变化。
* 在需要使用动画来响应状态变化时需要被复写,其他样式的响应参见下文提及的 [配置状态样式] 文档
* @param {String} name 状态名称
* @param {Object} value 状态值
* @param {Node} node 节点
*/
setState(name, value, node) {},
// 这里是绘制的起点
getAnchorPoints() {
return [
[0, 0.5],
[1, 0.5],
];
},
},
'rect',
);
group.addShape('image',{})
图片源,G6 支持多种格式的图片:url,ImageData,Image,canvas
group.addShape('image', {
attrs: {
x: nodeOrigin.x - 1,
y: -6,
img: require('../images/rootcard.png'),
size: 1,
width: width * 0.15,
height: width * 0.15 * 0.68
}
})
当我们需要为不同场景下的节点定制化样式或覆盖原有样式时,我们可以const一个节点,然后利用.attr({})覆盖,此处可以用…运算符将通用config加入其中
eg.
const recticon = group.addShape('rect', {
attrs: {
x: 0,
y: -0
}
})
recticon.attr({
...iconconfig,
x: -width * 0.025 * 0.8,
y: width * 0.025 * 0.7,
fill: '#FFF0ED'
})
cfg.depth 为我们提供了层级的属性
我们借此可以利用const去定义一个渲染的图形,然后利用rectname.attr({})
覆盖重写节点的样式
eg.
if (cfg.depth === 4) {
group.addShape('rect', {
attrs: {
fill: '#987EFB'
},
name: 'left-border-shape'
})
}
这里的name其实可以在一些方法中用来获取绘制的东西
e.target.get('name')==='namexxx'
如使用tooltip时获取需要显示tooltip的节点
G6 提供了 9 种内置边:
具体形状通过style中控制:
endArrow: {
path: G6.Arrow.triangle(10, 20, 25), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)
d: 25
},
G6.registerEdge()
G6.registerEdge(
'flow-cubic',// 当你使用自定义边时与默认边type一致才能绘制
{
getControlPoints(cfg) {
let controlPoints = cfg.controlPoints;
// 指定controlPoints
if (!controlPoints || !controlPoints.length) {
const { startPoint, endPoint, sourceNode, targetNode } = cfg;
const { x: startX, y: startY, coefficientX, coefficientY } = sourceNode
? sourceNode.getModel()
: startPoint;
const { x: endX, y: endY } = targetNode ? targetNode.getModel() : endPoint;
let curveStart = (endX - startX) * coefficientX;
let curveEnd = (endY - startY) * coefficientY;
curveStart = curveStart > 40 ? 40 : curveStart;
curveEnd = curveEnd < -30 ? curveEnd : -30;
controlPoints = [
{ x: startPoint.x + curveStart, y: startPoint.y },
{ x: endPoint.x + curveEnd, y: endPoint.y },
];
}
return controlPoints;
},
getPath(points) {
const path = [];
path.push(['M', points[0].x, points[0].y]);
path.push([
'C',
points[1].x,
points[1].y,
points[2].x,
points[2].y,
points[3].x,
points[3].y,
]);
return path;
},
},
'single-line',
);
由于在绘制边时 我们拿到的cfg对象只包含数据中的id,而source、target、分别代表起始点的id,此时我们若想定制不同节点间边的样式,我们可以通过清洗数据,为数据id中拼接一个我们可以用来判断的字符串
if (cfg.source.includes('mystring')) {
shape.attr({
stroke: '#987EFB'
})
}
源代码抛出的边指令如下:M代表起始点,L是直线,Q指令可以为自定义折线添加拐点以及弧度(因为此时radius是失效的)
export declare type ElementFilterFn = (IElement: any) => boolean;
declare type A = ['a' | 'A', number, number, number, number, number, number, number];
declare type C = ['c' | 'C', number, number, number, number, number, number];
declare type O = ['o' | 'O', number, number];
declare type H = ['h' | 'H', number];
declare type L = ['l' | 'L', number, number];
declare type M = ['m' | 'M', number, number];
declare type R = ['r' | 'R', number, number, number, number];
declare type Q = ['q' | 'Q', number, number, number, number];
declare type S = ['s' | 'S', number, number, number, number, number, number, number];
declare type T = ['t' | 'T', number, number];
declare type V = ['v' | 'V', number];
declare type U = ['u' | 'U', number, number, number];
declare type Z = ['z' | 'Z'];
export declare type PathCommand = A | C | O | H | L | M | R | Q | S | T | V | U | Z;
eg.
path = [
['M', startPoint.x, startPoint.y],
['L', startPoint.x + 10, startPoint.y],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x - 15, startPoint.y],
['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y, endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y],
['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y, (endPoint.x / 3 + (2 / 3) * startPoint.x) + 13, endPoint.y],
['L', endPoint.x + (-15), endPoint.y],
['L', endPoint.x, endPoint.y]
]
在new G6.Graph
时加载插件
const graph = new G6.Graph({
//... 其他配置项
plugins: [tooltip], // 配置 Tooltip 插件
});
eg. DOM形式
const tooltip = new G6.Tooltip({
offsetX: 10,
offsetY: 20,
getContent(e) {
const outDiv = document.createElement('div');
outDiv.style.width = '180px';
outDiv.innerHTML = `
自定义tooltip
- Label:
${e.item.getModel().label || e.item.getModel().id}
`
return outDiv
},
// 允许出现 tooltip 的 item 类型
itemTypes: ['node', 'edge'],
});
String 形式
const tooltip = new G6.Tooltip({
getContent(e) {
return `
`;
},
});
当我们需要自定义tooltip样式时:
(注意:不要将此样式放在scoped中,此时会无法覆盖)
.g6-component-tooltip {
background: rgba(0,0,0,0.75) !important;
padding: 10px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
width: fit-content;
border-radius: 4px;
display:block;
color:#fff;
}
tooltip配置项:
g6还提供了如下插件:
绑定监听事件
graph.on('collapse-text:click', (e) => {
//collapse-text代表绘制的节点name。=,click为事件
})
事件包含:Canvas 交互事件、node交互事件、edge交互事件等等
常见如:click、mouseenter、mousemove、mouseover、drag、dragend、dragstart、keydown、keyup…
时机事件如:
复合交互事件:
BehaviorOption.getEvents()
BehaviorOption.onNodeClick(evt)
BehaviorOption.getDefaultCfg()
BehaviorOption.shouldBegin(evt)
BehaviorOption.shouldUpdate(evt)
BehaviorOption.shouldEnd(evt)
graph.data(data):初始化图数据
graph.save():获取图数据
graph.read(data):接收数据,并进行渲染,read 方法的功能相当于 data 和 render 方法的结合
graph.changeData(data, stack):更新数据源,根据新的数据重新渲染视图。
graph.render():根据提供的数据渲染视图。
graph.refresh():当源数据中现有节点/边/ Combo 的数据项发生配置的变更时,根据新数据刷新视图。
graph.paint():仅重新绘制画布。当设置了元素样式或状态后,通过调用 paint()
方法,让修改生效。
graph.setAutoPaint(auto):设置是否在更新/删除后自动重绘,一般搭配 paint()
方法使用。
1、当我获取后端数据时,应该重新绘制整张图,此时我可以先调用destroy()再重新绘制
// data中存放我的图
data() {
return {
mygraph:''
}
}
// 初始化时赋给我的图
graph = new G6.TreeGraph({
container: 'container',
...config,
})
this.mygraph = graph
// 数据更新时
changedata(){
this.mygraph.destroy()
this.drawgrapg()
}
2、更新某些数据时
graph.changeData(data, stack)
graph.getZoom():获取当前视口的缩放比例。
graph.zoom(ratio, center, animate, animateCfg):改变视口的缩放比例,在当前画布比例下缩放,是相对比例。
graph.zoomTo(toRatio, center, animate, animateCfg):缩放视窗窗口到一个固定比例。
graph.changeSize(width, height):改变画布大小。(canvas在当前画布大小中溢出)
graph.translate(dx, dy, animate, animateCfg):采用相对位移来平移画布。
graph.moveTo(x, y, animate, animateCfg):采用绝对位移将画布移动到指定坐标。(可相对于画布位置定位)
graph.fitView(padding, rules, animate, animateCfg):让画布内容适应视口。(拓展了fitView属性,rules可以是 { onlyOutOfViewPort?: boolean; direction?: 'x' / 'y' / 'both'; ratioRule?: 'max' / 'min}
此方法将会另你的图在画布中缩放
graph.fitCenter(animate, animateCfg):*v3.5.1 后支持。*平移图到中心将对齐到画布中心,但不缩放。优先级低于 fitView。
graph.focusItem(item, animate, animateCfg):移动图,使得 item 对齐到视口中心,该方法可用于做搜索后的缓动动画。