# G6
G6 是一个图可视化引擎。
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.4.7/dist/g6.min.js"></script>
<script>
console.log(G6.Global.version);//查看版本
</script>
# G6基本创建
- 创建容器
在 HTML 中创建一个用于容纳 G6 绘制的图的容器。G6 在绘制时会在该容器下追加 canvas 标签,然后将图绘制在其中。
<div id="mountNode"></div>
- 数据
引入 G6 的数据源为 JSON 格式的对象。该对象中需要有节点(nodes)和边(edges)字段
<script>
const initData = {
// 点集
nodes: [
{
id: 'node1', // 节点的唯一标识
x: 100, // 节点横坐标
y: 200, // 节点纵坐标
label: '起始点', // 节点文本
},
{
id: 'node2',
x: 300,
y: 200,
label: '目标点',
},
],
// 边集
edges: [
// 表示一条从 node1 节点连接到 node2 节点的边
{
source: 'node1', // 起始点 id
target: 'node2', // 目标点 id
label: '我是连线', // 边的文本
},
],
};
</script>
注意
- nodes 数组中包含节点对象,唯一的 id 是每个节点对象中必要的属性,x、 y 用于定位;
- edges 数组中包含边对象,source 和 target 是每条边的必要属性,分别代表了该边的起始点 id 与 目标点 id。
- 图实例化
图实例化时,至少需要为图设置容器、宽、高
const graph = new G6.Graph({
container: 'mountNode', // 指定挂载容器
width: 800, // 图的宽度
height: 500, // 图的高度
});
还可以设置其他配置: fitView:Boolean ,适配画布,默认false;fitViewPadding画布周围留白,默认无,Number/Array(20/[20,40,10,30])
- 图的渲染
graph.data(initData); // 加载数据
graph.render(); // 渲染
# G6元素及其配置
图的元素特指图上的节点 Node 和边 Edge 。
不论是节点还是边,它们的属性分为两种:
- 样式属性 style:对应 Canvas 中的各种样式,在元素状态 State 发生变化时,可以被改变;
- 其他属性:例如图形类型( type)、id(id )一类在元素状态 State 发生变化时不能被改变的属性。
例如,G6 设定 hover 或 click 节点,造成节点状态的改变,只能自动改变节点的样式属性(如 fill、stroke 等),其他属性(如 type 等)不能被改变。如果需要改变其他属性,要通过 graph.updateItem 手动配置。样式属性是一个名为 style 的对象, style 字段与其他属性并行。
//以节点元素为例 ,
//边元素的属性数据结构与节点元素相似,只是其他属性中多了 source 和 target 字段,代表起始和终止节点的 id。
{
id: 'node0', // 元素的 id
shape: 'circle', // 元素的图形
size: 40, // 元素的大小
label: 'node0' // 标签文字
labelCfg: { // 标签配置属性
positions: 'center',// 标签的属性,标签在元素中的位置
style: { // 包裹标签样式属性的字段 style 与标签其他属性在数据结构上并行
fontSize: 12, // 标签的样式属性,文字字体大小
// ... // 标签的其他样式属性
}
}
// ..., // 其他属性
style: { // 包裹样式属性的字段 style 与其他属性在数据结构上并行
fill: '#000', // 样式属性,元素的填充色
stroke: '#888', // 样式属性,元素的描边色
// ... // 其他样式属性
}
}
如果所有节点统一的属性配置,所有边统一的属性配置,可以使用defaultNode和defaultEdge来配置(不包括某些个性化设置)
defaultNode:节点在默认状态下的样式属性(style)和其他属性;defaultEdge:边在默认状态下的样式属性(style)和其他属性。
const graph = new G6.Graph({
// ... // 图的其他配置
// 节点在默认状态下的样式配置(style)和其他配置
defaultNode: {
size: 30, // 节点大小
// ... // 节点的其他配置
// 节点样式配置
style: {
fill: 'steelblue', // 节点填充色
stroke: '#666', // 节点描边色
lineWidth: 1, // 节点描边粗细
},
// 节点上的标签文本配置
labelCfg: {
// 节点上的标签文本样式配置
style: {
fill: '#fff', // 节点标签文字颜色
},
},
},
// 边在默认状态下的样式配置(style)和其他配置
defaultEdge: {
// ... // 边的其他配置
// 边样式配置
style: {
opacity: 0.6, // 边透明度
stroke: 'grey', // 边描边颜色
},
// 边上的标签文本配置
labelCfg: {
autoRotate: true, // 边上的标签文本根据边的方向旋转
},
},
});
可以通过设置获取个性化设置
const nodes = remoteData.nodes;
nodes.forEach(node => {
if (!node.style) {
node.style = {};
}
switch (
node.class // 根据节点数据中的 class 属性配置图形
) {
case 'c0': {
node.shape = 'circle'; // class = 'c0' 时节点图形为 circle
break;
}
case 'c1': {
node.shape = 'rect'; // class = 'c1' 时节点图形为 rect
node.size = [35, 20]; // class = 'c1' 时节点大小
break;
}
case 'c2': {
node.shape = 'ellipse'; // class = 'c2' 时节点图形为 ellipse
node.size = [35, 20]; // class = 'c2' 时节点大小
break;
}
}
});
// 遍历边数据
const edges = remoteData.edges;
edges.forEach(edge => {
if (!edge.style) {
edge.style = {};
}
edge.style.lineWidth = edge.weight; // 边的粗细映射边数据中的 weight 属性数值
});
graph.data(remoteData);
{
"nodes": [
{"id": "0", "label": "n0", "class": "c0","x": 1000, "y": -100 },
{"id": "1", "label": "n1", "class": "c0","x": 300, "y": -10 }
],
"edges": [
{"source": "0", "target": "1", "label": "e0-1", "weight": 1 },
{"source": "0", "target": "2", "label": "e0-2", "weight": 2 }
]
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tutorial Demo</title>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.1.0/build/g6.js"></script>
<script>
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
fitView: true,
fitViewPadding: [20, 40, 50, 20],
defaultNode: {
size: 30,
labelCfg: {
style: {
fill: '#fff',
},
},
},
defaultEdge: {
labelCfg: {
autoRotate: true,
},
},
});
const main = async () => {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
);
const remoteData = await response.json();
const nodes = remoteData.nodes;
const edges = remoteData.edges;
nodes.forEach(node => {
if (!node.style) {
node.style = {};
}
node.style.lineWidth = 1;
node.style.stroke = '#666';
node.style.fill = 'steelblue';
switch (node.class) {
case 'c1': {
node.shape = 'rect';
node.size = [35, 20];
break;
}
case 'c2': {
node.shape = 'ellipse';
node.size = [35, 20];
break;
}
}
});
edges.forEach(edge => {
if (!edge.style) {
edge.style = {};
}
edge.style.lineWidth = edge.weight;
edge.style.opacity = 0.6;
edge.style.stroke = 'grey';
});
graph.data(remoteData);
graph.render();
};
main();
</script>
</body>
</html>
# G6布局layout
G6 提供了 9 种一般图的布局和 4 种树图的布局:
一般图:
- Random Layout:随机布局;
- Force Layout:经典力导向布局:
Circular Layout:环形布局;
Radial Layout:辐射状布局;
MDS Layout:高维数据降维算法布局;
Fruchterman Layout:Fruchterman 布局,一种力导布局;
Dagre Layout:层次布局。
树图布局:
- Dendrogram Layout:树状布局(叶子节点布局对齐到同一层);
- CompactBox Layout:紧凑树布局;
- Mindmap Layout:脑图布局;
- Intended Layout:缩进布局.
复杂的布局系统会打破适配规则,最好关闭fitView
const graph = new G6.Graph({
// ... // 其他配置项
layout: { // Object,可选,布局的方法及其配置项,默认为 random 布局。
type: 'force', // 指定为力导向布局
preventOverlap: true, // 防止节点重叠
// nodeSize: 30 // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
}
});
# G6交互行为
# 拖拽、缩放——内置的交互行为
const graph = new G6.Graph({
// ... // 其他配置项
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node'], // 允许拖拽画布、放缩画布、拖拽节点
},
});
modes 定义了 G6 的模式,default 是默认的模式,还可以允许有其他的模式,比如:编辑模式 edit 等。不同的模式,用户能进行的行为可以不同,比如默认模式能拖拽画布,编辑模式不允许拖拽画布
在实例化图时,通过 nodeStateStyles 和 edgeStateStyles 两个配置项可以配置元素在不同状态下的样式。
const graph = new G6.Graph({
// ... // 其他配置项
// 节点不同状态下的样式集合
nodeStateStyles: {
// 鼠标 hover 上节点,即 hover 状态为 true 时的样式
hover: {
fill: 'lightsteelblue',
},
// 鼠标点击节点,即 click 状态为 true 时的样式
click: {
stroke: '#000',
lineWidth: 3,
},
},
// 边不同状态下的样式集合
edgeStateStyles: {
// 鼠标点击边,即 click 状态为 true 时的样式
click: {
stroke: 'steelblue',
},
},
});
# 监听事件并切换元素状态
G6 中所有元素监听都挂载在图实例上,如下代码中的 graph 对象是 G6.Graph 的实例,graph.on() 函数监听了某元素类型(node / edge)的某种事件(click / mouseenter / mouseleave / ... )。
// 在图实例 graph 上监听
graph.on('元素类型:事件名', e => {
// do something
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tutorial Demo</title>
<style type="text/css">
#mountNode{
border: 1px solid red;
}
</style>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.1.0/build/g6.js"></script>
<script>
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
// 节点默认配置
defaultNode: {
labelCfg: {
style: {
fill: '#fff',
},
},
},
// 边默认配置
defaultEdge: {
labelCfg: {
autoRotate: true,
},
},
// 节点在各状态下的样式
nodeStateStyles: {
// hover 状态为 true 时的样式
hover: {
fill: 'lightsteelblue',
},
// click 状态为 true 时的样式
click: {
stroke: '#000',
lineWidth: 3,
},
},
// 边在各状态下的样式
edgeStateStyles: {
// click 状态为 true 时的样式
click: {
stroke: 'steelblue',
},
},
// 布局
layout: {
type: 'force',
linkDistance: 100,
preventOverlap: true,
nodeStrength: -30,
edgeStrength: 0.1,
},
// 内置交互
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node'],
},
});
const main = async () => {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
);
const remoteData = await response.json();
const nodes = remoteData.nodes;
const edges = remoteData.edges;
nodes.forEach(node => {
if (!node.style) {
node.style = {};
}
node.style.lineWidth = 1;
node.style.stroke = '#666';
node.style.fill = 'steelblue';
switch (node.class) {
case 'c0': {
node.shape = 'circle';
node.size = 30;
break;
}
case 'c1': {
node.shape = 'rect';
node.size = [35, 20];
break;
}
case 'c2': {
node.shape = 'ellipse';
node.size = [35, 20];
break;
}
}
});
edges.forEach(edge => {
if (!edge.style) {
edge.style = {};
}
edge.style.lineWidth = edge.weight;
edge.style.opacity = 0.6;
edge.style.stroke = 'grey';
});
graph.data(remoteData);
graph.render();
// 监听鼠标进入节点
graph.on('node:mouseenter', e => {
const nodeItem = e.item;
// 设置目标节点的 hover 状态 为 true
graph.setItemState(nodeItem, 'hover', true);
});
// 监听鼠标离开节点
graph.on('node:mouseleave', e => {
const nodeItem = e.item;
// 设置目标节点的 hover 状态 false
graph.setItemState(nodeItem, 'hover', false);
});
// 监听鼠标点击节点
graph.on('node:click', e => {
// 先将所有当前有 click 状态的节点的 click 状态置为 false
const clickNodes = graph.findAllByState('node', 'click');
clickNodes.forEach(cn => {
graph.setItemState(cn, 'click', false);
});
const nodeItem = e.item;
// 设置目标节点的 click 状态 为 true
graph.setItemState(nodeItem, 'click', true);
});
// 监听鼠标点击节点
graph.on('edge:click', e => {
// 先将所有当前有 click 状态的边的 click 状态置为 false
const clickEdges = graph.findAllByState('edge', 'click');
clickEdges.forEach(ce => {
graph.setItemState(ce, 'click', false);
});
const edgeItem = e.item;
// 设置目标边的 click 状态 为 true
graph.setItemState(edgeItem, 'click', true);
});
};
main();
</script>
</body>
</html>
# G6插件和交互工具
# 插件
- Step 1: 引入插件;
- Step 2: 实例化插件;
- Step 3: 在实例化图时将插件的实例配置到图上。
# 缩略图 (Minimap) 栅格grid
// 实例化插件
const minimap = new G6.Minimap({
size: [100, 100],
className: 'minimap',
type: 'delegate',
});
const grid = new G6.Grid();
// 实例化图
const graph = new G6.Graph({
// ... // 其他配置项
plugins: [minimap, grid], // 将实例配置到图上
});
# 交互工具
- Step 1: 在实例化图时配置 modes;
- Step 2: 为交互工具定义样式。
# tooltip 节点提示框
const graph = new G6.Graph({
modes: {
default: [
// ...
{
type: 'tooltip', // 提示框
formatText(model) {
// 提示框文本内容
const text = 'label: ' + model.label + '<br/> class: ' + model.class;
return text;
},
},
],
},
});
tooltip 实际上是一个悬浮的 <div> 标签,因此可在 HTML 的 <style> 标签或 CSS 中设置样式。下面展示在 HTML 中设置样式:
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
# edge-tooltip 边提示框
const graph = new G6.Graph({
modes: {
default: [
// ...
{
type: 'tooltip', // 节点提示框
// ...
},
{
type: 'edge-tooltip', // 边提示框
formatText(model) {
// 边提示框文本内容
const text =
'source: ' +
model.source +
'<br/> target: ' +
model.target +
'<br/> weight: ' +
model.weight;
return text;
},
},
],
},
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tutorial Demo</title>
<style type="text/css">
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.4.7/dist/g6.min.js"></script>
<script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
// 实例化 Minimap 插件
const minimap = new G6.Minimap({
size: [ 100, 100 ],
className: "minimap",
type: 'delegate'
});
// 实例化 Grid 插件
const grid = new G6.Grid();
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
defaultNode: {
labelCfg: {
style: {
fill: '#fff'
}
}
},
defaultEdge: {
labelCfg: {
autoRotate: true
}
},
nodeStateStyles: {
hover: {
fill: 'lightsteelblue'
},
click: {
stroke: '#000',
lineWidth: 3
}
},
edgeStateStyles: {
click: {
stroke: 'steelblue'
}
},
layout: {
type: 'force',
linkDistance: 100,
preventOverlap: true,
nodeStrength: -30,
edgeStrength: 0.1
},
modes: {
default: [ 'drag-node', 'drag-canvas', 'zoom-canvas',
// 点提示框交互工具的配置
{
type: 'tooltip',
formatText(model) {
const text = 'label: ' + model.label
+ '<br/> class: ' + model.class;
return text;
},
shouldUpdate: e => {
return true;
}
},
// 边提示框交互工具的配置
{
type: 'edge-tooltip',
formatText(model) {
const text = 'source: ' + model.source
+ '<br/> target: ' + model.target
+ '<br/> weight: ' + model.weight;
return text;
},
shouldUpdate: e => {
return true;
}
}
]
},
plugins: [ minimap, grid ] // 将 Minimap 和 Grid 插件的实例配置到图上
});
//$.getJSON('https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json', data => {
const main = async () => {
const response = await fetch('https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json');
const data = await response.json();
console.log(data);
const nodes = data.nodes;
const edges = data.edges;
nodes.forEach(node => {
if (!node.style) {
node.style = {};
}
node.style.lineWidth = 1;
node.style.stroke = '#666';
node.style.fill = 'steelblue';
switch (node.class) {
case 'c0': {
node.shape = 'circle';
node.size = 30;
break;
}
case 'c1': {
node.shape = 'rect';
node.size = [ 35, 20 ];
break;
}
case 'c2': {
node.shape = 'ellipse';
node.size = [ 35, 20 ];
break;
}
}
});
edges.forEach(edge => {
if (!edge.style) {
edge.style = {};
}
edge.style.lineWidth = edge.weight;
edge.style.opacity = 0.6;
edge.style.stroke = 'grey';
});
graph.data(data);
graph.render();
graph.on('node:mouseenter', e => {
const nodeItem = e.item;
graph.setItemState(nodeItem, 'hover', true);
});
graph.on('node:mouseleave', e => {
const nodeItem = e.item;
graph.setItemState(nodeItem, 'hover', false);
});
graph.on('node:click', e => {
const clickNodes = graph.findAllByState('node', 'click');
clickNodes.forEach(cn => {
graph.setItemState(cn, 'click', false);
});
const nodeItem = e.item;
graph.setItemState(nodeItem, 'click', true);
});
graph.on('edge:click', e => {
const clickEdges = graph.findAllByState('edge', 'click');
clickEdges.forEach(ce => {
graph.setItemState(ce, 'click', false);
});
const edgeItem = e.item;
graph.setItemState(edgeItem, 'click', true);
});
};
main();
</script>
</body>
</html>
antv G6 关于元素类型,shape 字段即将被废弃,请使用 type 代替
# G6扩展
G6 的内置节点包括 circle,rect,ellipse,diamond,triangle,star,image,modelRect。
circle的size是直径,rect的size是数组[100,50]等等
内置的节点支持的通用属性
| 名称 | 是否必须 | 类型 | 备注 |
|---|---|---|---|
| id | true | String | 节点编号 |
| x | false | Number | x 坐标 |
| y | false | Number | y 坐标 |
| type(shape会被废弃) | false | String | 节点图形,默认为 'circle' |
| size | false | Number / Array | 节点的大小 |
| anchorPoints | false | Array | 指定边连入节点的连接点的位置(相对于该节点而言),可以为空。例如: [0, 0],代表节点左上角的锚点,[1, 1],代表节点右下角的锚点 |
| style | false | Object | 节点的样式属性。 |
| label | false | String | 文本文字 |
| labelCfg | false | Object | 文本配置项 |
样式属性 style Object 类型。通过 style 配置来修改节点的填充色、边框颜色、阴影等属性。
| 名称 | 类型 | 备注 |
|---|---|---|
| fill | String | 节点填充色 |
| stroke | String | 节点的描边颜色 |
| lineWidth | Number | 描边宽度 |
| lineDash | Number[] | 描边虚线,数组代表实、虚长度 |
| shadowColor | String | 阴影颜色 |
| shadowBlur | Number | 阴影范围 |
| shadowOffsetX | Number | 阴影 x 方向偏移量 |
| shadowOffsetY | Number | 阴影 y 方向偏移量 |
| opacity | Number | 设置绘图的当前 alpha 或透明值 |
| fillOpacity | Number | 设置填充的 alpha 或透明值 |
| cursor | String | 鼠标在该节点上时的鼠标样式,CSS 的 cursor 选项都支持 |
labelCfg Object 类型。配置标签文本
| 名称 | 类型 | 备注 |
|---|---|---|
| position | String | 文本相对于节点的位置,目前支持的位置有: 'center','top','left','right','bottom'。默认为 'center' |
| offset | Number | 文本的偏移,position 为 'bottom' 时,文本的上方偏移量;position 为 'left' 时,文本的右方偏移量;以此类推在其他 position 时的情况。 |
| style | Object | 标签的样式属性。 |
# 节点的配置方法
实例化图时全局配置,在数据中动态配置,使用 graph.node(nodeFn) 函数配置 使用 graph.node(nodeFn) 配置 > 数据中动态配置 > 实例化图时全局配置
# graph.node()
该方法可以为不同节点进行不同的配置。
- 该方法必须在 render 之前调用,否则不起作用;
- 由于该方法优先级最高,将覆盖其他地方对节点的配置,这可能将造成一些其他配置不生效的疑惑;
- 该方法在增加元素、更新元素时会被调用,如果数据量大、每个节点上需要更新的内容多时,可能会有性能问题。
// const data = ...
// const graph = ...
graph.node(node => {
return {
id: node.id,
shape: 'rect',
style: {
fill: 'blue',
},
};
});
graph.data(data);
graph.render();
# circle
linkPoints Object 类型。可以指定节点周围「上、下、左、右」四个方向上的四个小圆点
区分于 anchorPoints: anchorPoints 是真正用于指定该节点相关边的连入位置的「数组」,见 anchorPoints;而 linkPoints 仅是指定是否「绘制」出四个圆点,不起实际的连接相关边的作用。二者常常配合使用。
const data = {
// ... data 内容
};
const graph = new G6.Graph({
// ... 图的其他属性
defaultNode: {
// ... 其他属性
linkPoints: {
top: true,
bottom: true,
left: true,
right: true,
fill: '#fff',
size: 5,
},
},
});
还可以设置图标icon
| 名称 | 含义 | 类型 | 备注 |
|---|---|---|---|
| show | 是否显示 icon | Boolean | 默认为 false,不显示 |
| width | icon 的宽度 | Number | 默认为 16 |
| height | icon 的高度 | Number | 默认为 16 |
| img | icon 的地址 | String | - |
const data = {
// ... data 内容
};
const graph = new G6.Graph({
// ... 图的其他属性
defaultNode: {
// ... 其他属性
icon: {
show: true,
//img: '...', 可更换为其他图片地址
width: 25,
height: 25,
},
},
});
// ...
# ellipse
size 为 Number 时,效果为一个圆形。为 Array 时,size[0] 为椭圆长轴长度,size[1] 为椭圆短轴长度
# Triangle
- size 三角形的边长 Number Array
- direction 三角形的方向 String 可取值:'up','down','left','right'。默认为 'up'
# image
可根据需要裁剪
# ModelRect
| 名称 | 含义 | 类型 | 备注 |
|---|---|---|---|
| preRect | 左侧的小矩形 | Object | modelRect 节点特有 |
| logoIcon | 左侧的 logo 图标 | Object | modelRect 节点特有 |
| stateIcon | 右侧的状态图标 | Object | modelRect 节点特有 |
| description | 节点主要文本下方的描述文本 | String | modelRect 节点特有 |
// 节点中 icon 配置
logoIcon: {
// 是否显示 icon,值为 false 则不渲染 icon
show: true,
x: 0,
y: 0,
// icon 的地址,字符串类型
img: 'https://gw.alipayobjects.com/zos/basement_prod/4f81893c-1806-4de4-aff3-9a6b266bc8a2.svg',
width: 16,
height: 16,
// 用于调整图标的左右位置
offset: 0
},
// 节点中表示状态的 icon 配置
stateIcon: {
// 是否显示 icon,值为 false 则不渲染 icon
show: true,
x: 0,
y: 0,
// icon 的地址,字符串类型
img: 'https://gw.alipayobjects.com/zos/basement_prod/300a2523-67e0-4cbf-9d4a-67c077b40395.svg',
width: 16,
height: 16,
// 用于调整图标的左右位置
offset: -5
}
# G6边
- line:直线,不支持控制点;
- polyline:折线,支持多个控制点;
- arc:圆弧线;
- quadratic:二阶贝塞尔曲线;
- cubic:三阶贝塞尔曲线;
- cubic-vertical:垂直方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
- cubic-horizontal:水平方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
- loop:自环。
const data = {
nodes: [
{ id: '1', x: 50, y: 50, size: 20 },
{ id: '2', x: 150, y: 50, size: 20 },
],
edges: [
{ source: '1', target: '2', shape: 'line', label: 'line' },
{ source: '3', target: '4', shape: 'polyline', label: 'polyline',style:{
stroke:"green",
cursor:`pointer`,
lineAppendWidth:10//不好点击边进行操作的时候可适当增大点击范围
} },
],
};
const graph = new G6.Graph({
container: 'mountNode',
width: 1500,
height: 300,
linkCenter: true, // 使边连入节点的中心
});
graph.data(data);
graph.render();
# line
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
defaultEdge: {
type: 'line',
// 其他配置
},
});
还可以单独配置line的color,不放在style里(style里用stroke,优先color配色)
# polyline
color: '#87e8de',
style: {
offset: 20, // 拐弯处距离节点最小距离
radius: 10, // 拐弯处的圆角弧度,若不设置则为直角
lineWidth: 2,
stroke: '#87e8de'
},
label: '边的标签文字',
labelCfg: {
refX: 10, // 文本在 x 方向偏移量
refY: 10, // 文本在 y 方向偏移量
style: {
fill: '#595959'
}
}
# quadratic
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tutorial Demo</title>
<style type="text/css">
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.4.7/dist/g6.min.js"></script>
<script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
const data = {
nodes: [
{
id: 'node0',
x: 100,
y: 100,
size: 20,
},
{
id: 'node1',
x: 200,
y: 100,
size: 20,
},
],
edges: [
{
source: 'node0',
target: 'node1',
type: 'quadratic',
label: 'quadratic',
},
],
};
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
defaultEdge: {
// type: 'quadratic', // 在数据中已经指定 type,这里无需再次指定
style: {
stroke: '#088',
endArrow: true,
lineWidth: 3,
},
},
});
graph.data(data);
graph.render();
</script>
</body>
</html>
# 节点与边的层级
groupByTypes 是图的一个配置项,当其为默认值 true 时,所有节点在一个名为 nodeGroup 的分组,所有边在另一个名为 edgeGroup 的分组,且 nodeGroup 在 edgeGroup 上层。将其设置为 false 后,将不存在 nodeGroup 和 edgeGroup,所有节点和边在同一个分组,它们的层级根据生成的顺序决定。
const graph = new G6.Graph({
// ... // 其他配置
groupByTypes: false,
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tutorial Demo</title>
<style type="text/css">
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.4.7/dist/g6.min.js"></script>
<script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
// 数据源
const data = {
nodes: [
{
id: 'node0',
x: 100,
y: 100,
size: 20,
},
{
id: 'node1',
x: 200,
y: 200,
size: 20,
},
{
id: 'node2',
x: 150,
y: 150,
size: 20,
},
{
id: 'node3',
x: 150,
y: 250,
size: 20,
},
{
id: 'node4',
x: 150,
y: 200,
size: 20,
},
],
edges: [
{
id: 'edge0',
source: 'node0',
target: 'node1',
},
{
id: 'edge1',
source: 'node2',
target: 'node3',
},
],
};
// 实例化图
const graph = new G6.Graph({
container: 'mountNode',
groupByTypes: false,
width: 800,
height: 600,
// 为方便演示,加粗边
defaultEdge: {
style: {
lineWidth: 2,
},
},
});
// 读取数据
graph.data(data);
// 渲染图
graph.render();
// const nodes = graph.getNodes();
// // 遍历节点实例,将所有节点提前。
// nodes.forEach(node => {
// node.toFront();
// });
// // 更改层级后需要重新绘制图
// graph.paint();
// 鼠标进入节点事件
graph.on('edge:mouseenter', ev => {
// 获得鼠标当前目标边
const edge = ev.item;
// 该边的起始点
const source = edge.getSource();
// 该边的结束点
const target = edge.getTarget();
// 先将边提前,再将端点提前。这样该边两个端点还是在该边上层,较符合常规。
edge.toFront();
source.toFront();
target.toFront();
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
graph.on('edge:mouseleave', ev => {
// 获得图上所有边实例
const edges = graph.getEdges();
// 遍历边,将所有边的层级放置在后方,以恢复原样
edges.forEach(edge => {
edge.toBack();
});
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
graph.on('node:mouseenter', ev => {
// 获得鼠标当前目标节点
const node = ev.item;
// 获取该节点的所有相关边
const edges = node.getEdges();
// 遍历相关边,将所有相关边提前,再将相关边的两个端点提前,以保证相关边的端点在边的上方常规效果
edges.forEach(edge => {
edge.toFront();
edge.getSource().toFront();
edge.getTarget().toFront();
});
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
graph.on('node:mouseleave', ev => {
// 获得图上所有边实例
const edges = graph.getEdges();
// 遍历边,将所有边的层级放置在后方,以恢复原样
edges.forEach(edge => {
edge.toBack();
});
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
</script>
</body>
</html>
# 显示隐藏
// 显示节点实例 nodeItem,该节点的 visible 属性值在该方法调用后被置为 true
nodeItem.show();
// 隐藏节点实例 nodeItem,该节点的 visible 属性值在该方法调用后被置为 false
nodeItem.hide();
// 显示边实例 edgeItem,该边的 visible 属性值在该方法调用后被置为 true
edgeItem.show();
// 隐藏边实例 edgeItem,该边的 visible 属性值在该方法调用后被置为 false
edgeItem.hide();
// 鼠标点击节点,隐藏该节点
graph.on('node:click', ev => {
const node = ev.item;
console.log('before hide(), the nodevisible = ', node.get('visible'));
node.hide();
graph.paint();
console.log('after hide(), the node visible = ', node.get('visible'));
});
// 鼠标点击边,隐藏该边
graph.on('edge:click', ev => {
const edge = ev.item;
console.log('before hide(), the edge visible = ', edge.get('visible'));
edge.hide();
graph.paint();
console.log('after hide(), the edge visible = ', edge.get('visible'));
});
// 鼠标点击画布,显示所有节点和边
graph.on('canvas:click', ev => {
const nodes = graph.getNodes();
const edges = graph.getEdges();
nodes.forEach(node => {
node.show();
});
edges.forEach(edge => {
edge.show();
});
graph.paint();
});
# shape 和 keyShape
每一种节点和边都有一个唯一的关键图形 keyShape。keyShape 是在节点的 draw() 方法中返回的图形对象
内置节点/边配置项中的 style 属性将只体现在它的 keyShape 上。且内置节点/边的状态样式 (图实例的 nodeStateStyles / edgeStateStyles 或元素自身的 stateStyles) 也仅体现在它的 keyShape 上。
# anchorPoints
结合sourceAnchor targetAnchor更好配置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tutorial Demo</title>
<style type="text/css">
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.4.7/dist/g6.min.js"></script>
<script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
// 数据源
const data = {
nodes: [
{
id: 'node1',
label: 'node1',
x: 100,
y: 200,
// 该节点可选的连接点集合,该点有两个可选的连接点
anchorPoints: [
[0, 1],
[0.5, 1],
],
type: 'rect',
},
{
id: 'node2',
label: 'node2',
x: 300,
y: 400,
// 该节点可选的连接点集合,该点有两个可选的连接点
anchorPoints: [
[0.5, 0],
[1, 0.5],
],
type: 'rect',
},
],
edges: [
{
source: 'node1',
target: 'node2',
// 该边连入 source 点的第 0 个 anchorPoint,
sourceAnchor: 0,
// 该边连入 target 点的第 0 个 anchorPoint,
targetAnchor: 0,
style: {
endArrow: true,
},
},
{
source: 'node2',
target: 'node1',
// 该边连入 source 点的第 1 个 anchorPoint,
sourceAnchor: 1,
// 该边连入 source 点的第 1 个 anchorPoint,
targetAnchor: 1,
style: {
endArrow: true,
},
},
],
};
// 实例化图
const graph = new G6.Graph({
container: 'mountNode',
groupByTypes: false,
width: 800,
height: 600,
// 为方便演示,加粗边
defaultEdge: {
style: {
lineWidth: 2,
},
},
});
// 读取数据
graph.data(data);
// 渲染图
graph.render();
// const nodes = graph.getNodes();
// // 遍历节点实例,将所有节点提前。
// nodes.forEach(node => {
// node.toFront();
// });
// // 更改层级后需要重新绘制图
// graph.paint();
// 鼠标进入节点事件
graph.on('edge:mouseenter', ev => {
// 获得鼠标当前目标边
const edge = ev.item;
// 该边的起始点
const source = edge.getSource();
// 该边的结束点
const target = edge.getTarget();
// 先将边提前,再将端点提前。这样该边两个端点还是在该边上层,较符合常规。
edge.toFront();
source.toFront();
target.toFront();
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
graph.on('edge:mouseleave', ev => {
// 获得图上所有边实例
const edges = graph.getEdges();
// 遍历边,将所有边的层级放置在后方,以恢复原样
edges.forEach(edge => {
edge.toBack();
});
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
graph.on('node:mouseenter', ev => {
// 获得鼠标当前目标节点
const node = ev.item;
// 获取该节点的所有相关边
const edges = node.getEdges();
// 遍历相关边,将所有相关边提前,再将相关边的两个端点提前,以保证相关边的端点在边的上方常规效果
edges.forEach(edge => {
edge.toFront();
edge.getSource().toFront();
edge.getTarget().toFront();
});
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
graph.on('node:mouseleave', ev => {
// 获得图上所有边实例
const edges = graph.getEdges();
// 遍历边,将所有边的层级放置在后方,以恢复原样
edges.forEach(edge => {
edge.toBack();
});
// 注意:必须调用以根据新的层级顺序重绘
graph.paint();
});
</script>
</body>
</html>
# vue中体验G6
<template>
<div class="hello" ref="hello">
<div id="left">1</div>
<div id="canvas"></div>
<div id="right">3</div>
</div>
</template>
<script>
import G6 from"@antv/G6"
export default {
name: 'HelloWorld',
data(){
return{
graph:null,
data:null,
}
},
mounted(){
const width = this.$refs.hello.clientWidth ;
const height = this.$refs.hello.clientHeight;
console.log(width)
console.log("-----")
this.data= {
// 点集
nodes: [
{
id: 'node1', // String,该节点存在则必须,节点的唯一标识
x: 100, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
},
{
id: 'node2', // String,该节点存在则必须,节点的唯一标识
x: 300, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
},
],
// 边集
edges: [
{
source: 'node1', // String,必须,起始点 id
target: 'node2', // String,必须,目标点 id
},
]
}
const minimap = new G6.Minimap({
size: [100, 100],
className: 'minimap',
});
const grid = new G6.Grid();
this.graph=new G6.Graph({
container:"canvas",
width:width-400,
height:height,
plugins: [minimap,grid],
// 节点默认配置
defaultNode: {
labelCfg: {
style: {
fill: '#fff',
},
},
},
// 边默认配置
defaultEdge: {
labelCfg: {
autoRotate: true,
},
},
// 节点在各状态下的样式
nodeStateStyles: {
// hover 状态为 true 时的样式
hover: {
fill: 'lightsteelblue',
},
// click 状态为 true 时的样式
click: {
stroke: '#000',
lineWidth: 3,
},
},
// 边在各状态下的样式
edgeStateStyles: {
// click 状态为 true 时的样式
click: {
stroke: 'steelblue',
},
},
// 布局
layout: {
type: 'force',
linkDistance: 100,
preventOverlap: true,
nodeStrength: -30,
edgeStrength: 0.1,
},
// 内置交互
modes: {
default: [
'drag-canvas',
'zoom-canvas',
'drag-node',
{
type: 'tooltip', // 提示框
formatText(model) {
// 提示框文本内容
const text = 'label: ' + model.label + '<br/> class: ' + model.class;
return text;
}
}
],
},
})
let remoteData = null;
const response = fetch(
'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
).then(res=>{
return res.json()
}).then((res)=>{
remoteData=res;
console.log(res)
const nodes = remoteData.nodes;
const edges = remoteData.edges;
nodes.forEach(node => {
if (!node.style) {
node.style = {};
}
node.style.lineWidth = 1;
node.style.stroke = '#666';
node.style.fill = 'steelblue';
switch (node.class) {
case 'c0': {
node.shape = 'circle';
node.size = 30;
break;
}
case 'c1': {
node.shape = 'rect';
node.size = [35, 20];
break;
}
case 'c2': {
node.shape = 'ellipse';
node.size = [35, 20];
break;
}
}
});
edges.forEach(edge => {
if (!edge.style) {
edge.style = {};
}
edge.style.lineWidth = edge.weight;
edge.style.opacity = 0.6;
edge.style.stroke = 'grey';
});
this.graph.data(remoteData)
this.graph.render()
// 监听鼠标进入节点
this.graph.on('node:mouseenter', e => {
const nodeItem = e.item;
// 设置目标节点的 hover 状态 为 true
this.graph.setItemState(nodeItem, 'hover', true);
});
// 监听鼠标离开节点
this.graph.on('node:mouseleave', e => {
const nodeItem = e.item;
// 设置目标节点的 hover 状态 false
this.graph.setItemState(nodeItem, 'hover', false);
});
// 监听鼠标点击节点
this.graph.on('node:click', e => {
// 先将所有当前有 click 状态的节点的 click 状态置为 false
const clickNodes = this.graph.findAllByState('node', 'click');
clickNodes.forEach(cn => {
this.graph.setItemState(cn, 'click', false);
});
const nodeItem = e.item;
// 设置目标节点的 click 状态 为 true
this.graph.setItemState(nodeItem, 'click', true);
});
// 监听鼠标点击节点
this.graph.on('edge:click', e => {
// 先将所有当前有 click 状态的边的 click 状态置为 false
const clickEdges = this.graph.findAllByState('edge', 'click');
clickEdges.forEach(ce => {
this.graph.setItemState(ce, 'click', false);
});
const edgeItem = e.item;
// 设置目标边的 click 状态 为 true
this.graph.setItemState(edgeItem, 'click', true);
});
})
console.log(this.graph)
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus">
.hello
display flex
height 100%
font-size 0
// overflow-y hidden
#left
width 200px
border-right 1px solid #F2F2F2
height 100%
font-size 12px
#right
width 200px
border-left 1px solid #F2F2F2
height 100%
font-size 12px
#canvas
flex:1
height 100%
position relative
</style>
<style>
.minimap{
position:fixed;
top:0;
left:200px;
}
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
警告
- shape会被废弃,以后版本需要改成type
- 配置minimap时写在stylus里不生效,只好写在style里
- 给容器加了个定位relative,否则位置有问题
更多参见官方文档官网地址 (opens new window)
← echarts组件化 arcgis →