G6参考文档[https://g6.antv.vision/zh](https://g6.antv.vision/zh)
官方简介:G6是一个简单、易用、完备的图可视化引擎,它在高定制能力的基础上,提供了一系列设计优雅、便于使用的图可视化解决方案。能帮助开发者搭建属于自己的图可视化、图分析、或图编辑器应用。
初始化—>加载数据—>渲染—>更新—>销毁
G6.Graph、data(data)、render()、changeData(data)、clear()
初始化
- 页面mounted的,初始化G6实例,以及默认点、边属性
- 注册自定义边样式
- menu自定义
加载数据
graph.data(this.data)
渲染
graph.render()
更新
- 新增点
graph.addItem("node", {
label: e.name,
resource_id: e.resourceId,
resource_type: e.resourceType,
code: e.code,
x: e.x + 150 * (i + 1),
y: e.y + 100 * (i + 1),
img: imageName,
})
边的新增,可以在初始化G6的时候,在models的defaults中加入"create-edge"
2. 删除点、边
graph.removeItem(_cfg.id)
3. G6布局样式调整
graph.updateLayout({
type: "grid",
begin: [0, 0], // 可选,
preventOverlap: true, // 可选,必须配合 nodeSize
preventOverlapPadding: 40, // 可选
nodeSize: 60, // 可选
condense: false, // 可选
rows: 5, // 可选
cols: 5, // 可选
sortBy: "degree", // 可选
workerEnabled: true,
})
销毁
graph.clear()
- 附上项目部分代码
<template>
<div id="topo-container">
<div id="mountNode"></div>
<!-- 新增连线弹窗 -->
<el-dialog
title="关系选择"
:visible.sync="relationVisible"
width="350px">
<el-select v-model="relate" placeholder="请选择" value-key="id">
<el-option
v-for="item in relations"
:key="item.id"
:label="item.name"
:value="item">
</el-option>
</el-select>
<span slot="footer" class="dialog-footer">
<el-button @click="relationVisible = false">取 消</el-button>
<el-button type="primary" @click="handleSaveRelation">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import G6 from "@antv/g6";
import { getTopoValue, getMdRelation } from "@/api/resource/topology";
let graph = null;
// 初始化—>加载数据—>渲染—>更新—>销毁
// G6.Graph、data(data)、render()、changeData(data)、clear()
export default {
name: "topoContent",
props: ['defaultEdge', 'lineAllObj', 'currentId'],
data() {
return {
data: {
nodes: [],
edges: [],
},
lineList: [], // 边类型 4类
relationVisible: false, // 关系选择弹窗
relations: [],
relate: '', // 选中的关系
editEdge: {}, // 当前正在编辑的边
};
},
watch: {
defaultEdge: {
deep: true, // 深度监听
handler(newVal,oldVal) {
graph.cfg.defaultEdge.style = newVal.defaultEdgeStyle;
graph.cfg.defaultEdge.edgeType = newVal.edgeType;
}
},
currentId: {
deep: true, // 深度监听
handler(newVal,oldVal) {
this.getTopoValue (newVal)
}
},
},
mounted() {
let container = document.getElementById("mountNode");
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
G6.registerEdge(
"line-arrow",
{
getPath(points) {
const startPoint = points[0];
const endPoint = points[1];
return [
["M", startPoint.x, startPoint.y],
["L", endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y],
["L", endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y],
["L", endPoint.x, endPoint.y],
];
},
getShapeStyle(cfg) {
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const controlPoints = this.getControlPoints(cfg);
let points = [startPoint];
if (controlPoints) {
points = points.concat(controlPoints);
}
points.push(endPoint);
const path = this.getPath(points);
const style = Object.assign(
{},
G6.Global.defaultEdge.style,
{
stroke: "#BBB",
lineWidth: 1,
path,
},
cfg.style
);
return style;
},
},
"line"
);
let _this = this
const contextMenu = new G6.Menu({
getContent(evt) {
let item = evt.item._cfg
if (item.type == 'edge'){
let source_resource_type = item.sourceNode._cfg.model.resource_type || ''
let target_resource_type = item.targetNode._cfg.model.resource_type || ''
if (source_resource_type == '' || target_resource_type == '') { // 线上的点存在是拓扑树节点 此时没有关系选择
return `
<ul>
<li code='remove'>删除</li>
</ul>`;
} else {
_this.editEdge = {
resourceId: item.model.source,
resourceTypeId: source_resource_type,
targetId: item.model.target,
targetTypeId: target_resource_type
}
return `
<ul>
<li code='choose'>选择关系</li>
<li code='remove'>删除</li>
</ul>`;
}
} else {
return `
<ul>
<li code='edit'>编辑</li>
<li code='remove'>删除</li>
</ul>`;
}
},
handleMenuClick: (target, item) => {
let code = target.attributes.code? target.attributes.code.value : '';
if (code === "edit") {
this.$emit("isShowEdit", item, false);
} else if (code === "remove") {
graph.removeItem(item._cfg.id);
} else if (code === "choose") {
this.loadRelationList()
}
},
offsetX: -250,
offsetY: -120,
itemTypes: ["node", "edge"],
});
graph = new G6.Graph({
container: "mountNode",
width,
height,
plugins: [contextMenu],
// fitView:true,
// fitViewPadding: 40,
// layout: {
// type: 'dagre',
// rankdir: 'LR', // 可选,默认为图的中心
// align: 'DL', // 可选
// nodesep: 20, // 可选
// ranksep: 50, // 可选
// controlPoints: true, // 可选
// },
defaultNode: {
type: "image",
size: [40, 40],
img: '/3.png',
style: {
radius: 5,
stroke: "#69c0ff",
fill: "#ffffff",
lineWidth: 1,
fillOpacity: 1,
},
labelCfg: {
style: {
fill: "#595959",
fontSize: 12,
},
// offset: 20,
},
},
defaultEdge: {
type: "line-arrow",
style: {
stroke: "#0099CC",
// startArrow: {
// path: 'M 0,0 L 12,6 L 9,0 L 12,-6 Z',
// fill: '#0099CC',
// },
endArrow: {
path: "M 0,0 L 12,6 L 9,0 L 12,-6 Z",
fill: "#0099CC",
},
lineDash: [],
},
// style: {
// stroke: '#b5b5b5',
// lineAppendWidth: 2,
// endArrow: true,
// lineDash: []
// },
// labelCfg: {
// autoRotate: true,
// style: {
// stroke: 'white',
// lineWidth: 1,
// },
// },
},
modes: {
default: ["drag-canvas", "zoom-canvas", "drag-node", "create-edge"],
},
});
this.getTopoValue (this.currentId)
},
methods: {
// 查询拓扑图数据
getTopoValue (id) {
getTopoValue(id)
.then((res) => {
let { nodes, edges } = res.data.data;
nodes = this.initNodeData(nodes);
edges = this.initEdgeData(edges);
this.data = { nodes, edges };
this.loadGraph()
})
.catch((err) => {
console.log("获取拓扑数据失败", err);
});
},
initNodeData(nodes) {
nodes.forEach((o) => {
o.id = o.id.toString();
o.label = o.label.toString();
});
return nodes;
},
initEdgeData(edges) {
edges.forEach((o) => {
o.source = o.source.toString();
o.target = o.target.toString();
o.edgeType = o.edge_type;
o.style = this.lineAllObj[o.edge_type];
});
return edges;
},
// 加载拓扑图
loadGraph() {
let container = document.getElementById("mountNode");
graph.data(this.data);
graph.render();
this.$emit("graphGet", graph);
graph.on("aftercreateedge", (e) => {
const edges = graph.save().edges;
console.log(edges, "edges");
G6.Util.processParallelEdges(edges);
graph.getEdges().forEach((edge, i) => {
graph.updateItem(edge, {
curveOffset: edges[i].curveOffset,
curvePosition: edges[i].curvePosition,
});
});
});
if (typeof window !== "undefined")
window.onresize = () => {
if (!graph || graph.get("destroyed")) return;
if (!container || !container.scrollWidth || !container.scrollHeight)
return;
graph.changeSize(container.scrollWidth, container.scrollHeight);
};
},
// 加载关系list
loadRelationList () {
getMdRelation(this.editEdge).then(res => {
this.relationVisible = true
this.relations = res.data.data || []
}).catch(err => {
console.log('查询报错',err)
})
},
// 关系选择确认
handleSaveRelation () {
// 更改线的数据
// 通过 ID 查询节点实例
const item = graph.findById(this.editEdge.id);
graph.updateItem(item, {...this.editEdge, label: this.relate.name, relationType: this.relate.relationType});
this.relationVisible = false
},
handlerLayout() {
graph.updateLayout({
type: "grid",
begin: [0, 0], // 可选,
preventOverlap: true, // 可选,必须配合 nodeSize
preventOverlapPadding: 40, // 可选
nodeSize: 60, // 可选
condense: false, // 可选
rows: 5, // 可选
cols: 5, // 可选
sortBy: "degree", // 可选
workerEnabled: true,
});
},
handlerSave() {
let edgesAll = graph.getEdges(),
nodesAll = graph.getNodes();
let data = { edges: [], nodes: [] };
edgesAll.forEach((item) => {
data.edges.push(item._cfg.model);
});
nodesAll.forEach((item) => {
data.nodes.push(item._cfg.model);
});
console.log("保存的数据data:", data);
},
},
};
</script>
<style lang="scss">
#topo-container {
#mountNode {
position: relative;
overflow: hidden;
ul {
list-style-type: none;
left: -150px;
margin: 0;
padding: 10px;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 4px;
font-size: 12px;
color: #545454;
li {
cursor: pointer;
list-style-type: none;
list-style: none;
margin-left: 0px;
margin-bottom: 5px;
&:hover {
color: #aaa;
}
}
}
}
}
</style>