Vue3使用G6基础
需要用到思维导图,找到蚂蚁金服的G6可以满足需求,不得不说阿里巴巴yyds,这一套图标全家桶可太棒了,熟悉了下基本用法,记录下来,官网讲的就很好了,建议去认真读读手册就会用了,这里总结的更精简和直观,需要的小伙伴可以看看,目前还是一些比较基础的操作,后面用的深入了还会更新
·
Vue3使用G6笔记(
需要用到思维导图,找到蚂蚁金服的G6可以满足需求,不得不说阿里巴巴yyds,这一套图标全家桶可太棒了
- 熟悉了下基本用法,记录下来
- 官网讲的就很好了,建议去认真读读手册就会用了
- 这里总结的更精简和直观,需要的小伙伴可以看看
- 目前还是一些比较基础的操作,后面用的深入了还会更新
一. 安装和引入
- npm安装
npm install --save @antv/g6
- 项目中引入
import G6 from '@antv/g6';
二. 第一个小demo
通过一个小demo了解基础的创建方式
步骤
- 首先需要一个标记了id的div
<template>
<div>
<div id="mountNode"></div>
</div>
</template>
- 之后需要初始化G6的Graph实例,这一步需要放在onMounted生命周期中,不然加载不出来
const graph = new G6.Graph({
container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
width: 800, // Number,必须,图的宽度
height: 500, // Number,必须,图的高度
});
- 之后需要定义一些节点数据
const data = {
// 点集
nodes: [
{
id: 'node1', // String,该节点存在则必须,节点的唯一标识
x: 100, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
label: 'start'
},
{
id: 'node2', // String,该节点存在则必须,节点的唯一标识
x: 300, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
label: 'end'
},
],
// 边集
edges: [
{
source: 'node1', // String,必须,起始点 id
target: 'node2', // String,必须,目标点 id
label: '我是连线'
},
],
};
- 还是在onMounted中加载数据,并且渲染
graph.data(remoteData); // 加载远程数据
graph.render(); // 渲染
- 完整代码
<template>
<div>
<div id="mountNode"></div>
</div>
</template>
<script>
import G6 from '@antv/g6';
import {onMounted} from "vue";
export default {
name: "Test02",
setup(){
const data = {
// 点集
nodes: [
{
id: 'node1', // String,该节点存在则必须,节点的唯一标识
x: 100, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
label: 'start'
},
{
id: 'node2', // String,该节点存在则必须,节点的唯一标识
x: 300, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
label: 'end'
},
],
// 边集
edges: [
{
source: 'node1', // String,必须,起始点 id
target: 'node2', // String,必须,目标点 id
label: '我是连线'
},
],
};
onMounted(()=>{
// 实例化graph对象
const graph = new G6.Graph({
container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
width: 800, // Number,必须,图的宽度
height: 500, // Number,必须,图的高度
});
graph.data(remoteData); // 加载远程数据
graph.render(); // 渲染
};
main()
})
}
}
</script>
<style scoped>
</style>
之后就是详细各部分的教程
三. 点和边的参数设置
1. 基本配置
点和线的样式和设置都是包裹在nodes对象数组中的,在对象中填入下面的配置即可配置点和边的样式
{
id: 'node0', // 元素的 id
type: 'circle', // 元素的图形
size: 40, // 元素的大小
label: 'node0' // 标签文字
visible: true, // 控制初次渲染显示与隐藏,若为 false,代表隐藏。默认不隐藏
labelCfg: { // 标签配置属性
positions: 'center',// 标签的属性,标签在元素中的位置
style: { // 包裹标签样式属性的字段 style 与标签其他属性在数据结构上并行
fontSize: 12 // 标签的样式属性,文字字体大小
// ... // 标签的其他样式属性
}
}
// ..., // 其他属性
style: { // 包裹样式属性的字段 style 与其他属性在数据结构上并行
fill: '#000', // 样式属性,元素的填充色
stroke: '#888', // 样式属性,元素的描边色
// ... // 其他样式属性
}
}
2. 通过遍历节点来设置样式
既可以在节点数据就写好样式,但更多的我们是拿到后端传来的很标准的json数据(只有数据),这个时候可以通过遍历节点来设置各个节点的样式
要注意的是动态配置的样式会覆盖掉在graph初始化时配置的默认样式
const nodes = remoteData.nodes; //这里是拿到的节点数据
nodes.forEach((node) => { //遍历节点数据
if (!node.style) {
node.style = {};
}
switch (
node.class // 根据节点数据中的 class 属性配置图形
) {
case 'c0': {
node.type = 'circle'; // class = 'c0' 时节点图形为 circle
break;
}
case 'c1': {
node.type = 'rect'; // class = 'c1' 时节点图形为 rect
node.size = [35, 20]; // class = 'c1' 时节点大小
break;
}
case 'c2': {
node.type = 'ellipse'; // class = 'c2' 时节点图形为 ellipse
node.size = [35, 20]; // class = 'c2' 时节点大小
break;
}
}
});
graph.data(remoteData);
四. 初始化实例时的参数设置
1. 让画布适应图像
由于点和变数据在设置的时候可以指定位置,而如果画布不够大的话是会超出画布大小,显示不完整的
- 这一点可以在初始化的时候解决
const graph = new G6.Graph({
container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
width: 800, // Number,必须,图的宽度
height: 500, // Number,必须,图的高度
fitView: true, // 让图片适应当前的画布大小
fitViewPadding: [20,40,50,20] // 适应之后加入边框
});
2. 给点和边指定默认样式
需要点和边有统一的样式的时候,可以在graph初始化的时候指定默认样式
const graph = new G6.Graph({
container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
width: 800, // Number,必须,图的宽度
height: 500, // Number,必须,图的高度
fitView: true, // 让图片适应当前的画布大小
fitViewPadding: [20,40,50,20], // 适应之后加入边框
// 从这开始指定默认节点样式
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, // 边上的标签文本根据边的方向旋转
},
},
});
3. 添加图布局Layout
const graph = new G6.Graph({
// ... // 其他配置项
layout: {
// Object,可选,布局的方法及其配置项,默认为 random 布局。
type: 'force',
linkDistance: 100, // 指定边距离为100
preventOverlap: true, // 防止节点重叠
// nodeSize: 30 // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
},
});
4. 添加交互模式
下文会说
5. 添加提示框
下文会说
五. 图布局Layout
当数据中没有节点位置信息,或者数据中的位置信息不满足需求时,需要借助一些布局算法对图进行布局
一般图布局
- Random Layout:随机布局;
- Force Layout:经典力导向布局:
力导向布局:一个布局网络中,粒子与粒子之间具有引力和斥力,从初始的随机无序的布局不断演变,逐渐趋于平衡稳定的布局方式称之为力导向布局。适用于描述事物间关系,比如人物关系、计算机网络关系等。
- Circular Layout:环形布局;
- Radial Layout:辐射状布局;
- MDS Layout:高维数据降维算法布局;
- Fruchterman Layout:Fruchterman 布局,一种力导布局;
- Dagre Layout:层次布局;
- Concentric Layout:同心圆布局,将重要(默认以度数为度量)的节点放置在布局中心;
- Grid Layout:格子布局,将节点有序(默认是数据顺序)排列在格子上
树图布局
- Dendrogram Layout:树状布局(叶子节点布局对齐到同一层);
- CompactBox Layout:紧凑树布局;
- Mindmap Layout:脑图布局;
- Indented Layout:缩进布局。
默认情况
- 默认情况下,如果节点数据中有坐标信息,就用坐标信息
- 没有坐标信息,就用 Random Layout 布局
const graph = new G6.Graph({
// 。。。。。其他配置省略
// 图布局Layout
layout: {
// Object,可选,布局的方法及其配置项,默认为 random 布局。
type: 'force',
linkDistance: 100, // 指定边距离为100
preventOverlap: true, // 防止节点重叠
// nodeSize: 30 // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
},
)}
六. 图的交互
给图添加简单的交互,比如:hover 节点、点击节点、点击边、放缩画布、拖拽画布
1. 拖拽,放大,缩小
直接在graph初始化的时候写上mode就行,
const graph = new G6.graph({
// 交互模式
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node'], // 允许拖拽画布、放缩画布、拖拽节点
},
})
2. 提示框
- hover的时候出现提示框,在mode的数组中加入tooltip类型或edge-tooltip类型
- 实际上就是将这个节点上的一些数据输出出来,需要手动写一个html的字符串
const graph = new G6.Graph({
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node', // 允许拖拽画布、放缩画布、拖拽节点
{
type: 'tooltip', // 提示框
formatText(model) {
// 提示框文本内容,实际上就是放了个div进去
const text = 'label: ' + model.label + '<br/> class: ' + model.class;
return text;
}
},
{
type: 'edge-tooltip', // 边提示框
formatText(model) {
// 边提示框文本内容
const text =
'source: ' +
model.source +
'<br/> target: ' +
model.target +
'<br/> weight: ' +
model.weight;
return text;
}
},
],
)}
3. 状态式交互
比如点击,hover触发的事件和样式的改变等等
(a) 交互状态
- 交互状态就是这个节点是否处于被hover,或者是否被点击等等事件触发的状态
- 比如这个节点被点击了,那这个节点的click状态就是true
- 而节点处于激活状态时候的样式,是需要在初始化的时候就进行配置的
- 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',
},
},
});
(2) 绑定事件
- 绑定事件和交互状态需要联合起来用,经过绑定的事件并触发后,才会显示初始化中定义的处于true状态时候的样式
- 思路就是:拿到点击的节点/边,然后设置这个节点的状态
//graph事件监听
// 鼠标进入节点
graph.on('node:mouseenter', (e) => {
const nodeItem = e.item; // 获取鼠标进入的节点元素对象
graph.setItemState(nodeItem, 'hover', true); // 设置当前节点的 hover 状态为 true
});
// 鼠标离开节点
graph.on('node:mouseleave', (e) => {
const nodeItem = e.item; // 获取鼠标离开的节点元素对象
graph.setItemState(nodeItem, 'hover', false); // 设置当前节点的 hover 状态为 false
});
// 点击节点
graph.on('node:click', (e) => {
// 先将所有当前是 click 状态的节点置为非 click 状态
const clickNodes = graph.findAllByState('node', 'click');
clickNodes.forEach((cn) => {
graph.setItemState(cn, 'click', false);
});
const nodeItem = e.item; // 获取被点击的节点元素对象
graph.setItemState(nodeItem, 'click', true); // 设置当前节点的 click 状态为 true
});
// 点击边
graph.on('edge:click', (e) => {
// 先将所有当前是 click 状态的边置为非 click 状态
const clickEdges = graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) => {
graph.setItemState(ce, 'click', false);
});
const edgeItem = e.item; // 获取被点击的边元素对象
graph.setItemState(edgeItem, 'click', true); // 设置当前边的 click 状态为 true
});
七. 插件的使用
步骤:
- 实例化插件
- 在初始化graph的时候在plugins中加入
- 实例化两个插件,一个是缩略图,一个是网格
// 实例化minimap插件对象
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],
)}
整个案例
整个组件的案例代码在这,里面包含了上面说的所有部分
<template>
<div>
<div id="mountNode"></div>
</div>
</template>
<script>
import request from "../utils/request";
import G6 from '@antv/g6';
import {onMounted} from "vue";
export default {
name: "Test02",
setup(){
// 实例化minimap插件对象
const minimap = new G6.Minimap({
size: [100, 100],
className: 'minimap',
type: 'delegate',
})
// 实例化网格插件对象
const grid = new G6.Grid()
const data = {
// 点集
nodes: [
{
id: 'node1', // String,该节点存在则必须,节点的唯一标识
x: 100, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
label: 'start'
},
{
id: 'node2', // String,该节点存在则必须,节点的唯一标识
x: 300, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
label: 'end'
},
],
// 边集
edges: [
{
source: 'node1', // String,必须,起始点 id
target: 'node2', // String,必须,目标点 id
label: '我是连线'
},
],
};
onMounted(()=>{
const graph = new G6.Graph({
container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
width: 800, // Number,必须,图的宽度
height: 500, // Number,必须,图的高度
fitView: true, // 让图片适应当前的画布大小
fitViewPadding: [20,40,50,20], // 适应之后加入边框
plugins:[minimap, grid],
// 图布局Layout
layout: {
// Object,可选,布局的方法及其配置项,默认为 random 布局。
type: 'force',
linkDistance: 100, // 指定边距离为100
preventOverlap: true, // 防止节点重叠
// nodeSize: 30 // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
},
// 交互模式
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node', // 允许拖拽画布、放缩画布、拖拽节点
{
type: 'tooltip', // 提示框
formatText(model) {
// 提示框文本内容,实际上就是放了个div进去
const text = 'label: ' + model.label + '<br/> class: ' + model.class;
return text;
}
},
{
type: 'edge-tooltip', // 边提示框
formatText(model) {
// 边提示框文本内容
const text =
'source: ' +
model.source +
'<br/> target: ' +
model.target +
'<br/> weight: ' +
model.weight;
return text;
}
},
],
},
// 交互式状态,hover和click时候的样式改变
nodeStateStyles: {
// 鼠标 hover 上节点,即 hover 状态为 true 时的样式
hover: {
fill: 'lightsteelblue',
},
// 鼠标点击节点,即 click 状态为 true 时的样式
click: {
stroke: '#000',
lineWidth: 3,
},
},
// 边不同状态下的样式集合
edgeStateStyles: {
// 鼠标点击边,即 click 状态为 true 时的样式
click: {
stroke: 'steelblue',
},
},
// 节点的默认样式
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, // 边上的标签文本根据边的方向旋转
},
},
});
//graph事件监听
// 鼠标进入节点
graph.on('node:mouseenter', (e) => {
const nodeItem = e.item; // 获取鼠标进入的节点元素对象
graph.setItemState(nodeItem, 'hover', true); // 设置当前节点的 hover 状态为 true
});
// 鼠标离开节点
graph.on('node:mouseleave', (e) => {
const nodeItem = e.item; // 获取鼠标离开的节点元素对象
graph.setItemState(nodeItem, 'hover', false); // 设置当前节点的 hover 状态为 false
});
// 点击节点
graph.on('node:click', (e) => {
// 先将所有当前是 click 状态的节点置为非 click 状态
const clickNodes = graph.findAllByState('node', 'click');
clickNodes.forEach((cn) => {
graph.setItemState(cn, 'click', false);
});
const nodeItem = e.item; // 获取被点击的节点元素对象
graph.setItemState(nodeItem, 'click', true); // 设置当前节点的 click 状态为 true
});
// 点击边
graph.on('edge:click', (e) => {
// 先将所有当前是 click 状态的边置为非 click 状态
const clickEdges = graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) => {
graph.setItemState(ce, 'click', false);
});
const edgeItem = e.item; // 获取被点击的边元素对象
graph.setItemState(edgeItem, 'click', true); // 设置当前边的 click 状态为 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();
// ...
graph.data(remoteData); // 加载远程数据
graph.render(); // 渲染
};
main()
})
}
}
</script>
<style scoped>
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(117, 77, 77, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
更多推荐
已为社区贡献1条内容
所有评论(0)