antv/G6使用记录,vue组件实现节点、边的动态增减、右键事件等功能
antv/G6是蚂蚁金服数据可视化团队出品的一个功能完备的图可视化引擎。 介于业务需要,最近在学习G6,特此记录下~~ 简单展示:功能点:连接关系图表鼠标控制缩放节点拖动事件画布拖动事件边的状态切换节点层级展示边的动态增加还原视图特性: 状态:G6中提供了状态管理,指的是节点或边的状态,包括交互状态和业务状态。 动画:动画是可视化中非常重要的内容,本例中涉及到边的动画效果 字体图标:本例中使用
·
基本展示
antv/G6是蚂蚁金服数据可视化团队出品的一个功能完备的图可视化引擎。
介于业务需要,最近在学习G6,特此记录下~~
简单展示:
功能点:
- 连接关系图表
- 鼠标控制缩放
- 节点拖动事件
- 画布拖动事件
- 边的状态切换
- 节点层级展示
- 边的动态增加
- 还原视图
特性:
状态:G6中提供了状态管理,指的是节点或边的状态,包括交互状态和业务状态。
动画:动画是可视化中非常重要的内容,本例中涉及到边的动画效果
字体图标:本例中使用iconfont,具体实现参照G6官方文档,比较的详细
布局:G6提供了一些布局的方法,只需要在实例化G6时进行配置就好,但是本例没有使用布局,而是指定了节点额度坐标
话不多说,上代码,使用vue写的组件,代码写的比较low~~~
完整代码
<template>
<div class="main-content-box">
<div class="demoDiv">
<div class="toolDiv">
<div class="zoom zoomOut" title="放大" @click="getZoomOut">
<i class="iconfont"></i>
</div>
<div class="zoom zoomIn" title="缩小" @click="getZoomIn">
<i class="iconfont"></i>
</div>
<div class="zoom subNodes" title="二级" @click="showSubNodes">
<i class="iconfont"></i>
</div>
<div class="zoom allViews" title="全部线路" @click="showAllViews">
<i class="iconfont"></i>
</div>
<div class="zoom refreshViews" title="刷新拓扑图" @click="refreshViews">
<i class="iconfont"></i>
</div>
<div class="zoom thirdNodes" title="还原" @click="reFreshNodeOrg">
<i class="iconfont"></i>
</div>
</div>
<div id="container"></div>
<div class="showDetails" v-if="isShowDetails">
<p class="details-title">详细信息</p>
<span class="closeDetail" @click="closeDetail">
<i class="iconfont"></i>
</span>
<div class="details-info">
<div class="details-info-items">
<h4 class="info-items-label">名称:</h4>
<h4 class="info-items">{{ showNodeDetailsObj.label }}</h4>
</div>
<div class="details-info-items">
<h4 class="info-items-label">Id:</h4>
<h4 class="info-items">{{ showNodeDetailsObj.id }}</h4>
</div>
<div class="details-info-items">
<h4 class="info-items-label">状态:</h4>
<h4 class="info-items"></h4>
</div>
<div class="details-info-items">
<h4 class="info-items-label">描述信息:</h4>
<p class="info-items-description">此处是对节点的一些介绍描述信息</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import G6 from "@antv/g6";
import Util from "@antv/g6/lib/util";
import { getForce } from "../../nodeApi/api/getData.js"
export default {
name: "g6demo13",
data () {
return {
currentGraph: {},
lineEdge: [],
lineEdgeArrOne: [],
lineEdgeArrTwo: [],
clickNum: 0,
showNodeDetailsObj: {},
showEdgeDetailsObj: {},
isShowDetails: false,
drawData: {},
tempData: {
nodes: [],
edges: [],
},
isClickNodes: false,
isClickRefresh: false,
ForceData: {}
};
},
created () {
},
mounted () {
this.$loading({
lock: true,
text: '数据加载中~~~',
spinner: 'el-icon-loading',
background: 'rgba(232, 240, 230, 0.85)'
});
/**
* 模拟后台请求数据(全量获取)
*/
getForce().then(res => {
if (res.status === 1) {
this.drawData = res.data
setTimeout(() => {
this.getFirstNodes();
this.initGrahp();
}, 10)
}
})
setTimeout(() => {
this.$loading().close()
}, 1000)
},
methods: {
initGrahp () {
/**
* 需要保存vue的this实例,否则直接调用this时,this的指向会发生变化
*/
let _that = this; //保存vue实例
/**
* 临时变量,用于存储需要显示的节点信息
*/
let tempObj = {};
/**
* 使用iconfont
*/
G6.registerNode("iconfont", {
draw (cfg, group) {
const {
backgroundConfig: backgroundStyle,
style,
labelCfg: labelStyle,
} = cfg;
if (backgroundStyle) {
group.addShape("circle", {
attrs: {
x: 0,
y: 0,
r: cfg.size * 0.5, //背景节点的大小
...backgroundStyle,
},
name: "circle-shape",
});
}
const keyShape = group.addShape("text", {
attrs: {
x: 0,
y: 0,
fontFamily: "iconfont", // 对应css里面的font-family: "iconfont";
textAlign: "center",
textBaseline: "middle",
text: cfg.text,
fontSize: cfg.size,
// lineHeight: 44,
...style,
},
name: "text-shape1",
});
/**
* 节点label的y轴偏移量
* 原值为 labelY = backgroundStyle ? cfg.size *2 : cfg.size;
*/
const labelY = backgroundStyle ? cfg.size : cfg.size;
group.addShape("text", {
attrs: {
x: 0,
y: labelY,
textAlign: "center",
textBaseline: "middle",
text: cfg.label,
fontSize: labelStyle.fontSize, //此属性可生效,配置labelCfg中的fontSize字段,即可实现设置
...labelStyle.style,
},
name: "text-shape1",
});
return keyShape;
},
});
/**
* 添加右键点击节点的菜单及事件
*/
const conextMenuContainer = document.createElement("ul");
conextMenuContainer.id = "contextMenu";
// create li
const firstLi = document.createElement("li");
firstLi.innerHTML = `查看层级`;
firstLi.style.display = "block";
firstLi.addEventListener("click", function (ev) {
/**
* 此处增加对点击边时隐藏的默认显示边的显示
* 即在查看节点时,显示默认边
*/
const edges = graph.getEdges();
edges.forEach(edge => {
edge.show();
});
/**
* 显示当前节点下的子节点的方法
*/
graph.changeData(_that.tempData);
});
conextMenuContainer.appendChild(firstLi);
const lastLi = document.createElement("li");
lastLi.innerText = "节点详情";
lastLi.style.display = "block";
lastLi.addEventListener("click", function (ev) {
_that.isShowDetails = true; //显示详情框
_that.showNodeDetailsObj = tempObj;
});
conextMenuContainer.appendChild(lastLi);
document.getElementById("container").appendChild(conextMenuContainer);
const width = document.getElementById("container").scrollWidth;
const height = document.getElementById("container").scrollHeight || 600;
console.log(height)
const graph = new G6.Graph({
container: "container",
width,
height,
// renderer: 'canvas',
linkCenter: true,
modes: {
default: [
"drag-canvas",
"zoom-canvas",
{
type: "edge-tooltip", // 边提示框
formatText (model) {
// 边提示框文本内容
// console.log(model)
const text = model.lineNum
? "端口连接数: " + model.lineNum
: null;
return text;
},
offset: -20,
},
],
},
layout: {
type: "force",
preventOverlap: true,
/**
* 边长。可以使用回调函数的形式对不同对边定义不同边长
*/
linkDistance: (d) => {
console.log(d)
if (d.source.id === "node0") {
return 180;
}
if (d.source.siteFlag === 'firstNodes') {
return 120;
}
if (d.source.siteFlag === 'subNodes') {
return 100;
}
if (d.source.siteFlag === 'subNodes' && d.target.siteFlag === 'thirdNodes') {
return 80;
}
return 30;
},
/**
* 节点作用力,正数代表节点之间的引力作用,负数代表节点之间的斥力作用。
* 可以使用回调函数的形式对不同对节点定义不同节点作用力
*/
nodeStrength: (d) => {
if (d.isLeaf) {
return -150;
}
return -50;
},
/**
* 边的作用力,默认根据节点的出入度自适应。可以使用回调函数的形式对不同对节点定义不同边作用力
*/
edgeStrength: (d) => {
if (
d.source.id === "node1" ||
d.source.id === "node2" ||
d.source.id === "node3"
) {
return 5;
}
return 1;
},
/**
* preventOverlap 为 true 时生效,防止重叠时节点边缘间距的最小值。
* 可以是回调函数,为不同节点设置不同的最小间距,
*/
nodeSpacing: (d) => {
// d 是一个节点
if (
d.id === "node1" ||
d.id === "node2" ||
d.id === "node3" ||
d.id === "node4" ||
d.id === "node5"
) {
return 50;
}
return 10;
},
/**
* 是否启用 web-worker 以防布局计算时间过长阻塞页面交互,默认false
*/
workerEnabled: false,
},
defaultNode: {
backgroundConfig: {
backgroundType: "circle",
fill: "#40a9ff",
//stroke: 'LightSkyBlue',
},
size: 36,
color: "#5B8FF9",
type: "iconfont",
style: {
lineWidth: 2,
fill: "#C6E5FF",
},
labelCfg: {
autoRotate: true,
offset: [60, 10, 10, 10],
style: {
fontSize: 14,
},
},
},
defaultEdge: {
size: 1,
color: "#e2e2e2",
style: {
lineWidth: 1,
stroke: "#b5b5b5",
lineAppendWidth: 10,
},
},
});
graph.data(_that.tempData);
graph.render();
/**
* 当节点开始被拖拽的时候触发的事件,此事件作用在被拖曳节点上
*/
graph.on("node:dragstart", function (e) {
graph.layout();
refreshDragedNodePosition(e);
});
/**
* 当节点在拖动过程中时触发的事件,此事件作用于被拖拽节点上
*/
graph.on("node:drag", function (e) {
refreshDragedNodePosition(e);
});
/**
* 当拖拽完成后触发的事件,此事件作用在被拖曳节点上
*/
graph.on("node:dragend", function (e) {
e.item.get("model").fx = null;
e.item.get("model").fy = null;
});
function refreshDragedNodePosition (e) {
const model = e.item.get("model");
model.fx = e.x;
model.fy = e.y;
}
/**
* 将实例化的G6,赋给data中的currentGraph
*/
_that.currentGraph = graph;
/**
* 右键点击事件
*/
// let temporaryData = Object.assign({}, this.drawData); //保存一份所有的原始数据信息
let temporaryData = JSON.parse(JSON.stringify(this.drawData))
graph.on("node:contextmenu", (evt) => {
// console.log(evt)
evt.preventDefault();
evt.stopPropagation();
/**
* 右键点击时需要将右键菜单区域显示
* 由于部分节点不需要显示子级节点信息,处理是需要将将查看层级li隐藏掉
* 右键时使其默认显示,再根据节点信息判断是否显示
*/
conextMenuContainer.style.left = `${evt.canvasX + 36}px`; //使菜单出现在节点的右侧
conextMenuContainer.style.top = `${evt.canvasY}px`;
firstLi.style.display = "block";
/**
* 拿到于此节点相关的边的信息,再根据边查找到节点信息,然后添加边、节点
*/
// console.log(temporaryData)
let showRelationId = evt.item._cfg.id;
// console.log(showRelationId)
let edgeTemp = [];
temporaryData.edges.forEach((item) => {
if (item.source === showRelationId) {
edgeTemp.push(item);
}
});
console.log(edgeTemp);
let nodeTemp = [];
temporaryData.nodes.forEach((item) => {
edgeTemp.forEach((i) => {
if (i.target === item.id) {
nodeTemp.push(item);
}
});
});
console.log(nodeTemp);
tempObj = evt.item._cfg.model;
if (edgeTemp.length === 0 && nodeTemp.length === 0) {
firstLi.style.display = "none";
_that.$notify.warning({
title: "提示",
message: "此节点无子节点信息",
duration: 3000,
});
return;
}
/**
* 右键事件 尝试方法2
* new 新增判断节点层级字段 siteFlag
*/
// let hasClickCenter = evt.item._cfg.model.isCenter;
let isCenterNodes = evt.item._cfg.model.siteFlag;
let isClickTag = evt.item._cfg.model.isClick;
if (isCenterNodes === 'center') {
firstLi.style.display = "none";
return;
}
/**
* 防止多次点击造成重复数据过多,显示出现问题
* 将当前节点的后拿到的节点及边数据拼接到源数据中
*/
if (!isClickTag) {
_that.tempData.nodes = _that.tempData.nodes.concat(nodeTemp);
_that.tempData.edges = _that.tempData.edges.concat(edgeTemp);
evt.item._cfg.model.isClick = true;
}
console.log(_that.tempData);
});
/**
* 鼠标离开节点区域,取消右键菜单的显示(位置还原)
*/
graph.on("node:mouseleave", () => {
conextMenuContainer.style.left = "-300px";
});
/**
* 边的点击事件,点击边动态增加边
*/
graph.on("edge:dblclick", (ev) => {
// console.log(ev);
/**
* 双击时隐藏默认显示的边
*/
let hiddenOrgEdge = ev.item
hiddenOrgEdge.hide()
let edgeNum = ev.item._cfg.model.lineNum;
let edgeSource = ev.item._cfg.model.source;
let edgeTarget = ev.item._cfg.model.target;
/**
* 此处考虑,是否在显示多条边时,将原本的那条线隐藏掉(删除掉数据)
* 或者新增边时,使数目 -1(循环从1开始)
* new 将默认显示边隐藏后,不需要-1 操作
*/
for (let i = 0; i < edgeNum; i++) {
let moduleEdges = {
source: edgeSource,
target: edgeTarget,
type: "arc",
curveOffset: 10,
};
if (i % 2 === 0) {
moduleEdges.curveOffset = moduleEdges.curveOffset * (i + 1) * 1;
} else {
moduleEdges.curveOffset = moduleEdges.curveOffset * i * -1;
}
graph.addItem("edge", moduleEdges);
}
});
/**
* 点击画布 隐藏详细信息
*/
graph.on('canvas:click', () => {
_that.isShowDetails = false
})
},
getZoomOut () {
let currentZoom = this.currentGraph.getZoom();
this.currentGraph.zoomTo(currentZoom + 0.1, this.getViewCenter());
},
getZoomIn () {
const currentZoom = this.currentGraph.getZoom();
this.currentGraph.zoomTo(currentZoom - 0.1, this.getViewCenter());
},
showSubNodes () {
// console.log("显示二级节点");
this.currentGraph.destroy();
this.drawData.nodes.filter((item, index, arr) => {
if (item.isSubNodes) {
this.tempData.nodes.push(item);
}
});
/**
* 利用对象访问属性的方法,判断对象中是否存在某个key。
* 从而达到去重的目的
*/
let result = [];
let tempObj = {};
for (let i = 0; i < this.tempData.nodes.length; i++) {
if (!tempObj[this.tempData.nodes[i].id]) {
result.push(this.tempData.nodes[i]);
tempObj[this.tempData.nodes[i].id] = true;
}
}
/**
* 此处为for循环中数组splice方法调用次数有误的解决方法
* 由于splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。
* 此方法会改变原数组,意味着原数组的下标会发生变化
*/
let deleteNum = 1;
let loop = result.length;
for (let j = 0; j < loop; j++) {
if (result[j].isThirdNodes) {
result.splice(j, deleteNum);
j--; //改变下标
loop = loop - deleteNum; // 改变循环长度
}
}
this.tempData.nodes = result;
this.tempData.edges = this.drawData.edges.slice(
0,
this.tempData.nodes.length - 1
);
console.log(this.tempData);
this.initGrahp();
},
reFreshNodeOrg () {
console.log("还原节点");
/**
* 还原初始化显示节点信息,需要将此对象置为空
*/
this.tempData = {
nodes: [],
edges: [],
};
/**
* 点击还原节点是,需要将源数据中所以的节点点击标识置为false
* 否则会出现,点击显示节点后,还原节点后,原节点不显示展开的节点
*/
this.drawData.nodes.forEach((item) => {
item.isClick = false;
});
setTimeout(() => {
this.currentGraph.destroy();
this.getFirstNodes();
this.initGrahp();
}, 10);
},
showAllViews () {
this.currentGraph.clear();
this.currentGraph.destroy();
this.tempData.nodes = this.drawData.nodes;
let result = [];
let tempObj = {};
for (let k = 0; k < this.tempData.nodes.length; k++) {
if (!tempObj[this.tempData.nodes[k].id]) {
result.push(this.tempData.nodes[k]);
tempObj[this.tempData.nodes[k].id] = true;
}
}
this.tempData.nodes = result;
this.tempData.edges = this.drawData.edges;
this.initGrahp();
},
getFirstNodes () {
/**
* 先将中心节点push进tempData中
*/
this.drawData.nodes.forEach((item) => {
if (item.isCenter) {
this.tempData.nodes.push(item);
}
if (item.isFisrtNodes) {
this.tempData.nodes.push(item);
}
});
/**
* 以中心节点为source的,都是默认显示的意见节点
*/
this.drawData.edges.forEach(item => {
if (item.source === 'node0') {
this.tempData.edges.push(item)
}
})
console.log(this.tempData);
},
refreshViews () {
/**
* 将graph实例销毁时,需要销毁画布
* 否则会造成画布重复渲染,但画布元素未显示的问题
*/
this.currentGraph.destroy();
console.log("刷新视图");
setTimeout(() => {
this.initGrahp();
}, 10);
// this.currentGraph.changeData()
},
/**
* 计算画布的padding值
*/
getFormatPadding () {
return Util.formatPadding(this.currentGraph.get("fitViewPadding"));
},
/**
* 画布中心位置
*/
getViewCenter () {
const padding = this.getFormatPadding();
// console.log(padding)
const graph = this.currentGraph;
const width = this.currentGraph.get("width");
const height = graph.get("height");
return {
x: (width - padding[2] - padding[3]) / 2 + padding[3],
y: (height - padding[0] - padding[2]) / 2 + padding[0],
};
},
noRepeatArr (arr) {
let result = [];
let tempObj = {};
for (let i = 0; i < arr.length; i++) {
if (!tempObj[arr[i].id]) {
result.push(arr[i]);
tempObj[arr[i].id] = true;
}
}
return result;
},
closeDetail () {
this.isShowDetails = false;
this.showNodeDetailsObj = {};
},
},
};
</script>
<style scoped>
.main-content-box {
width: 95%;
margin: 5px 20px;
}
.demoDiv {
position: relative;
padding: 20px;
border: 1px solid skyblue;
}
.toolDiv {
width: 50px;
border: 1px solid #f5f5f5;
position: absolute;
z-index: 100;
}
.zoom {
cursor: pointer;
border: 1px solid #f5f5f5;
font-size: 26px;
background-color: #ffffff;
}
/* 右键菜单及显示详情区域,宽度为屏幕窗口的12%,高度为屏幕窗口的40% */
.showDetails {
width: 12vw;
height: 40vh;
border: 1px solid #f5f5f5;
box-shadow: -5px 5px 5px #aaaaaa;
position: absolute;
top: 0;
right: 0;
border-radius: 4px;
background-color: #ffffff;
padding: 5px;
overflow-y: auto;
font-size: 12px;
}
.details-title {
text-align: left;
}
.closeDetail {
position: absolute;
right: 8px;
top: 18px;
cursor: pointer;
}
.closeDetail:hover {
color: #e27e7e;
}
.details-info {
margin: 0 10px;
background-color: aquamarine;
}
.details-info-items {
background-color: #ffffff;
display: flex;
}
.details-info-items:last-child {
background-color: #ffffff;
display: flex;
flex-direction: column;
align-items: baseline;
}
.info-items {
font-size: 12px;
color: #545454;
text-align: left;
}
.info-items-label {
color: #000000;
text-align: left;
width: 65px;
}
.info-items-description {
height: 100px;
width: 100%;
border: 1px solid #d2bebe;
margin-top: 0px;
line-height: 24px;
}
/* 右键菜单 */
.demoDiv >>> #contextMenu {
position: absolute;
list-style-type: none;
padding: 10px 8px;
left: -300px;
background-color: rgba(255, 255, 255, 0.9);
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 14px;
color: #545454;
z-index: 2;
}
.demoDiv >>> #contextMenu li {
cursor: pointer;
list-style-type: none;
list-style: none;
margin-left: 0px;
margin-top: 5px;
}
.demoDiv >>> #contextMenu li:hover {
color: #aaa;
}
.title_for_layout {
position: absolute;
top: 0;
left: 100px;
color: crimson;
}
.demoDiv >>> .g6-edge-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>
示例数据
{
"message": "这是mock数据",
"status": 1,
"data": {
"nodes": [
{
"id": "node0",
"size": 80,
"label": "xxx 交换机 \n xxx-1.0.1 bate",
"text": "\ue6ec",
"isCenter": true,
"siteFlag": "center",
"isClick": false,
"style": {
"fill": "red",
"opacity": 1,
"fillOpacity": 1,
"cursor": "auto"
},
"labelCfg": {
"style": {
"fill": "red",
"fontSize": 24
},
"position": "bottom",
"offset": [
110,
10,
10,
10
]
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node1",
"size": 50,
"label": "node1",
"isCenter": false,
"siteFlag": "firstNodes",
"isClick": false,
"text": "\ue68c",
"isFisrtNodes": true,
"style": {
"fill": "skyblue",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node2",
"size": 50,
"label": "node2",
"isCenter": false,
"siteFlag": "firstNodes",
"isClick": false,
"text": "\ue68c",
"isFisrtNodes": true,
"style": {
"fill": "skyblue",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node3",
"size": 50,
"label": "node3",
"isCenter": false,
"siteFlag": "firstNodes",
"isClick": false,
"text": "\ue68c",
"isFisrtNodes": true,
"style": {
"fill": "skyblue",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node4",
"size": 50,
"label": "node4",
"isCenter": false,
"siteFlag": "firstNodes",
"isClick": false,
"isLeaf": true,
"text": "\ue78a",
"isFisrtNodes": true,
"style": {
"fill": "skyblue",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node5",
"size": 50,
"label": "node5",
"isCenter": false,
"siteFlag": "firstNodes",
"isClick": false,
"isLeaf": true,
"text": "\ue78a",
"isFisrtNodes": true,
"style": {
"fill": "skyblue",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node6",
"size": 30,
"label": "node6",
"isCenter": false,
"isClick": false,
"siteFlag": "subNodes",
"isLeaf": true,
"text": "\ue78a",
"isSubNodes": true,
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node7",
"size": 30,
"label": "node7",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"text": "\ue78a",
"isSubNodes": true,
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node8",
"size": 30,
"label": "node8",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node9",
"size": 30,
"label": "node9",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node10",
"size": 30,
"label": "node10",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node11",
"size": 30,
"label": "node11",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node12",
"size": 30,
"label": "node12",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node13",
"size": 30,
"label": "node13",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node14",
"size": 30,
"label": "node14",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node15",
"size": 30,
"label": "node15",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node16",
"size": 30,
"label": "node16",
"isCenter": false,
"siteFlag": "subNodes",
"isClick": false,
"isLeaf": true,
"isSubNodes": true,
"text": "\ue78a",
"style": {
"fill": "green",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "skyblue"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node17",
"size": 15,
"label": "node17",
"isCenter": false,
"siteFlag": "thirdNodes",
"isClick": false,
"isLeaf": true,
"isThirdNodes": true,
"text": "\ue679",
"style": {
"fill": "red",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "orange"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
},
{
"id": "node18",
"size": 15,
"label": "node18",
"isCenter": false,
"siteFlag": "thirdNodes",
"isClick": false,
"isLeaf": true,
"isThirdNodes": true,
"text": "\ue743",
"style": {
"fill": "black",
"cursor": "pointer"
},
"labelCfg": {
"style": {
"fill": "purple"
}
},
"backgroundConfig": {
"fill": "white",
"padding": [
2,
2,
2,
2
],
"radius": 2
}
}
],
"edges": [
{
"source": "node0",
"target": "node1",
"type": "line",
"label": "node-edge1",
"lineNum": 3
},
{
"source": "node0",
"target": "node2",
"type": "line",
"label": "node-edge2",
"lineNum": 2
},
{
"source": "node0",
"target": "node3",
"type": "line",
"label": "node-edge3",
"lineNum": 4
},
{
"source": "node0",
"target": "node4",
"type": "line",
"label": "node-edge4",
"lineNum": 5
},
{
"source": "node0",
"target": "node5",
"type": "line",
"label": "node-edge5",
"lineNum": 2
},
{
"source": "node1",
"target": "node6",
"type": "line",
"label": "node-edge6",
"lineNum": 2
},
{
"source": "node1",
"target": "node7",
"type": "line",
"label": "node-edge7",
"lineNum": 2
},
{
"source": "node2",
"target": "node8",
"type": "line",
"label": "node-edge8",
"lineNum": 2
},
{
"source": "node2",
"target": "node9",
"type": "line",
"label": "node-edge9",
"lineNum": 2
},
{
"source": "node2",
"target": "node10",
"type": "line",
"label": "node-edge10",
"lineNum": 2
},
{
"source": "node2",
"target": "node11",
"type": "line",
"label": "node-edge11",
"lineNum": 2
},
{
"source": "node2",
"target": "node12",
"type": "line",
"label": "node-edge12",
"lineNum": 2
},
{
"source": "node2",
"target": "node13",
"type": "line",
"label": "node-edge13",
"lineNum": 2
},
{
"source": "node3",
"target": "node14",
"type": "line",
"label": "node-edge14",
"lineNum": 2
},
{
"source": "node3",
"target": "node15",
"type": "line",
"label": "node-edge15",
"lineNum": 2
},
{
"source": "node3",
"target": "node16",
"type": "line",
"label": "node-edge16",
"lineNum": 2
},
{
"source": "node16",
"target": "node17",
"type": "line",
"label": "node-edge17",
"lineNum": 2
},
{
"source": "node16",
"target": "node18",
"type": "line",
"label": "node-edge18",
"lineNum": 2
}
]
}
}
补充说明:
本例使用的G6版本为3.5.0版本,上述代码为图例实际使用代码(代码low,勿喷)。使用G6时建议阅读官方文档、查看官方示例。
以上就是示例的完整代码,使用vue完成,G6在不断地更新,学习也在不断地进行。
Tips:
如果本文章对您有帮助,欢迎评论告知!
更多推荐
已为社区贡献4条内容
所有评论(0)