vue + antv g6实现拓扑(用于数据亲属展示业务)
官方文档 官方文档链接(看了之后感觉懂了,但是没完全懂。) 具体用途 业务需求 制作数据亲缘关系大概类似于制作ER图。一开始想用ecarts的拓扑图,但是ecarts有个定位问题一直没搞懂,找不到解决办法。 ecarts的节点需要自定义定位,但是我们是动态数据,力导算法不符合业务需求,所以最终选择了antv g6。 主要问题 1\。需要自定义节点。 g6使用自定义的dom节点来满足修改需求。但是根
官方文档
官方文档链接(看了之后感觉懂了,但是没完全懂。)
具体用途
业务需求
- 制作数据亲缘关系大概类似于制作ER图。一开始想用ecarts的拓扑图,但是ecarts有个定位问题一直没搞懂,找不到解决办法。 ecarts的节点需要自定义定位,但是我们是动态数据,力导算法不符合业务需求,所以最终选择了antv g6。
主要问题
1\。需要自定义节点。 g6使用自定义的dom节点来满足修改需求。但是根据文档,dom节点不能使用g6提供的点击事件。
- 通过配置节点类型,使节点指向用户自定义的节点。
// 高亮当前节点并按类型匹配自定义节点
if (this.data.nodes[i].highLight u003du003d 1) {
this.data.nodes[i].type u003d 'center'
} 其他 {
this.data.nodes[i].type u003d 'dom-node'
}
- 自定义dom节点
G6.registerNode(
'dom 节点', {
绘制:(cfg,组)u003d> {
// console.log(cfg, group)
常量形状 u003d group.addShape('dom', {
属性:{
宽度:cfg.size[0],
高度:cfg.size[1],
// html 传入 DOM
html:`
<div onclicku003d"select(${cfg.name})" idu003d"${cfg.select}" classu003d"dom-node-style" styleu003d"cursor:pointer;border-radius: 5px;width: ${
cfg.size[0] - 5
}px;高度:${cfg.size[1] - 5}px;显示:弹性;">
<span styleu003d"margin:auto; padding:auto; color: #000">${cfg.id}</span>
</div> `,
},
可拖动:真,
});
返回形状;
},
},
'单节点',
);
// 当前表节点
G6.registerNode(
“中心”,{
绘制:(cfg,组)u003d> {
// 控制台.log(cfg)
常量形状 u003d group.addShape('dom', {
属性:{
宽度:cfg.size[0],
高度:cfg.size[1],
// HTML ${CFG.活跃? "class u003d'selected-style'": "class u003d'node-style'"} 传入 DOM“
html:`
<div onclicku003d"select(${cfg.name})" idu003d"${cfg.select}" classu003d"node-style" styleu003d"width: ${
cfg.size[0] - 5
}px;高度:${cfg.size[1] - 5}px;显示:弹性;边框半径:5px;光标:指针;">
<span styleu003d"margin:auto; padding:auto; color: #000">${cfg.id}</span>
</div> `,
},
可拖动:真,
});
返回形状;
},
},
'单节点',
);
2\。调整状态样式,单击节点或线时更改样式。
- 默认线路可以直接配置。详见文档
默认边缘:{
风格:{
endArrow:真,
线宽:2,
中风:'#CED4D9',
填写:“#CED4D9”,
},
},
边缘状态样式:{
点击:{
线宽:2,
中风:'#5394ef',
填充:“#5394ef”,
},
},
// 边缘点击事件
graph.on('edge:click', (e) u003d> {
// 首先,将当前处于点击状态的所有边设置为非点击状态
常量 clickEdges u003d graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) u003d> {
graph.setItemState(ce, 'click', false);
});
常量项 u003d e.item; // 获取鼠标输入的边缘元素对象
常量 jobId u003d item._cfg.model.jobId
graph.setItemState(item, 'click', true); // 设置当前边缘的点击状态为true
that.getLineInfo(jobId)
});
- 自定义dom节点需要动态改变class属性来改变样式。目前还没有找到更好的解决方案。欢迎交流!
// 节点点击事件
让那个 u003d 这个;
window.select u003d 函数(id){
常量 clickEdges u003d graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) u003d> {
graph.setItemState(ce, 'click', false);
});
that.getNodeInfo(id)
var divId u003d 'temp' + id
// 获取当前选中的div,点击这个div替换选中的样式,其他所有div恢复未选中的样式
var selectId u003d document.getElementById(divId)
for(让 i 在 that.data.nodes 中){
if (that.data.nodes[i].name u003du003d id) {
// if (that.data.nodes[i].isActive u003du003d false) {
selectId.setAttribute('class', 'selected-style')
that.data.nodes[i].isActive u003d true
// }
} 其他 {
让 tempId u003d document.getElementById('temp' + that.data.nodes[i].name)
if (that.data.nodes[i].type u003du003d 'dom-node') {
tempId.setAttribute('class', 'dom-node-style')
} 其他 {
tempId.setAttribute('class', 'node-style')
}
that.data.nodes[i].isActive u003d false
}
}
}
3\。如何销毁画布?
- 在每个数据请求之前进行判断。如果已经有数据,则销毁画布。
// 避免多次渲染数据并销毁画布
if (this.chart !u003du003d '') {
this.chart.destroy()
}
- 在渲染之前分配这个 g6 chart u003d graph
4\。使用交互模式。默认模式包括单击选定节点并拖动画布的行为。触发时会重新渲染画布,从而取消自定义dom节点设置的状态样式。 (自定义dom节点写在draw中,改变dom节点的状态样式,比如选择后改变颜色,是通过动态改变class属性来实现的)。这个问题目前还没有解决。
5\。对于布局问题,g6也是使用自定义节点位置,但是提供了dagre分层布局,可以满足需求。
布局:{
type: 'dagre', //分层布局
rankdir: 'LR', // 可选的。它默认位于图表的中心
align: 'DL', // 可选
nodeep: 25, // 可选
rankep: 25, // 可选
controlPoints: true, // 可选
},
完整代码
<脚本>
//引入g6
从“@antv/g6”导入 G6;
进口{
获取图形数据,
获取线路信息,
获取节点信息
} 来自'@/api/home/assetCatalogueDetail'
导出默认 {
数据() {
返回{
身份证:0,
type:0,//0-全是近亲,1-直系父子,2-全父表,3-全子表
activeName:'first',
图表:'',
可见:真实,
节点列表:[],
行列表:[],
数据:{
// 点集
节点:[],
// 边集
边缘:[],
}
}
},
方法:{
初始化(ID){
这个.id u003d id
this.getData()
},
获取数据() {
// 避免多次渲染数据并销毁画布
if (this.chart !u003du003d '') {
this.chart.destroy()
}
this.getNodeInfo(this.id)
getGraphData(对象。分配({
basicDataId:this.id,
关系类型:this.type
})).then(响应 u003d> {
this.data.nodes u003d response.data.data.node
this.data.edges u003d response.data.data.line
// console.log(this.data)
for(让 i 在 this.data.nodes 中){
// g6 id 代表节点名
让名称 u003d this.data.nodes[i].name
让 id u003d this.data.nodes[i].id
this.data.nodes[i].id u003d 名称
this.data.nodes[i].name u003d id
// 设置节点的连接点。 anchorPoint是指与节点相连的边的相对位置,即节点与其相关边的交点位置
this.data.nodes[in].anchor Points u003d [
[0.5, 0],
[1, 0.5],
[0, 0.5],
[0.5, 1],
]
this.data.nodes[i].select u003d 'temp' + id
this.data.nodes[i].isActive u003d false
this.data.nodes[i].size u003d [120, 40]
// 高亮当前节点并按类型匹配自定义节点
if (this.data.nodes[i].highLight u003du003d 1) {
this.data.nodes[i].type u003d 'center'
} 其他 {
this.data.nodes[i].type u003d 'dom-node'
}
}
this.renderView()
})
},
渲染视图() {
G6.registerNode(
'dom 节点', {
绘制:(cfg,组)u003d> {
// console.log(cfg, group)
常量形状 u003d group.addShape('dom', {
属性:{
宽度:cfg.size[0],
高度:cfg.size[1],
// html 传入 DOM
html:`
<div onclicku003d"select(${cfg.name})" idu003d"${cfg.select}" classu003d"dom-node-style" styleu003d"cursor:pointer;border-radius: 5px;width: ${
cfg.size[0] - 5
}px;高度:${cfg.size[1] - 5}px;显示:弹性;">
<span styleu003d"margin:auto; padding:auto; color: #000">${cfg.id}</span>
</div> `,
},
可拖动:真,
});
返回形状;
},
},
'单节点',
);
// 当前表节点
G6.registerNode(
“中心”,{
绘制:(cfg,组)u003d> {
// 控制台.log(cfg)
常量形状 u003d group.addShape('dom', {
属性:{
宽度:cfg.size[0],
高度:cfg.size[1],
// HTML ${CFG.活跃? "class u003d'selected-style'": "class u003d'node-style'"} 传入 DOM“
html:`
<div onclicku003d"select(${cfg.name})" idu003d"${cfg.select}" classu003d"node-style" styleu003d"width: ${
cfg.size[0] - 5
}px;高度:${cfg.size[1] - 5}px;显示:弹性;边框半径:5px;光标:指针;">
<span styleu003d"margin:auto; padding:auto; color: #000">${cfg.id}</span>
</div> `,
},
可拖动:真,
});
返回形状;
},
},
'单节点',
);
常量图 u003d 新 G6.Graph({
renderer: 'svg', //使用Dom节点时,需要使用svg来渲染情况
容器:'mountNode',
宽度:800,
高度:500,
布局:{
type: 'dagre', //分层布局
rankdir: 'LR', // 可选的。它默认位于图表的中心
align: 'DL', // 可选
nodeep: 25, // 可选
rankep: 25, // 可选
controlPoints: true, // 可选
},
默认边缘:{
风格:{
endArrow:真,
线宽:2,
中风:'#CED4D9',
填写:“#CED4D9”,
// 光标:'指针'
},
},
边缘状态样式:{
点击:{
线宽:2,
中风:'#5394ef',
填充:“#5394ef”,
},
},
模式:{
默认值:[
// 'drag canvas', // 拖动画布
// '缩放画布', // 缩放画布
]
},
fitCenter: true, //平移到中心对齐到画布的中心,但不缩放
});
// 节点点击事件
让那个 u003d 这个;
window.select u003d 函数(id){
常量 clickEdges u003d graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) u003d> {
graph.setItemState(ce, 'click', false);
});
that.getNodeInfo(id)
var divId u003d 'temp' + id
// 获取当前选中的div,点击这个div替换选中的样式,其他所有div恢复未选中的样式
var selectId u003d document.getElementById(divId)
for(让 i 在 that.data.nodes 中){
if (that.data.nodes[i].name u003du003d id) {
// if (that.data.nodes[i].isActive u003du003d false) {
selectId.setAttribute('class', 'selected-style')
that.data.nodes[i].isActive u003d true
// }
} 其他 {
让 tempId u003d document.getElementById('temp' + that.data.nodes[i].name)
if (that.data.nodes[i].type u003du003d 'dom-node') {
tempId.setAttribute('class', 'dom-node-style')
} 其他 {
tempId.setAttribute('class', 'node-style')
}
that.data.nodes[i].isActive u003d false
}
}
}
// 边缘点击事件
graph.on('edge:click', (e) u003d> {
// 首先,将当前处于点击状态的所有边设置为非点击状态
常量 clickEdges u003d graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) u003d> {
graph.setItemState(ce, 'click', false);
});
常量项 u003d e.item; // 获取鼠标输入的边缘元素对象
常量 jobId u003d item._cfg.model.jobId
graph.setItemState(item, 'click', true); // 设置当前边缘的点击状态为true
that.getLineInfo(jobId)
});
this.chart u003d 图
图形.data(this.data); // 将步骤2中的数据源读取到图表中
图.render(); // 渲染
// graph.fitView();
},
获取节点信息(值){
this.visible u003d true
获取节点信息(对象。分配({
id:值,
curId:this.id
})).then(响应 u003d> {
this.nodeList u003d response.data.data
// console.log(this.nodeList)
})
},
getLineInfo(值) {
this.visible u003d false
getLineInfo(值).then(响应 u003d> {
this.lineList u003d response.data.data
// console.log(this.lineList)
})
},
}
}
</脚本>
<样式>
.node 样式 {
背景颜色:#fff;
边框:1px 实心#5B8FF9;
}
.selected-style {
背景色:橙色;
}
.dom 节点样式 {
背景颜色:#fff;
边框:1px 实心#000;
}
</style>
更多推荐
所有评论(0)