近期项目中使用到d3插件绘制的流程图。
首先认识下dagre。dagre是专注于有向图布局的javascript库,由于dagre 仅仅专注于图形布局,需要使用其他方案根据 dagre 的布局信息来实际渲染图形,而 dagre-d3 就是 dagre 基于 D3 的渲染方案。
使用步骤
1、下载d3及dagreD3
import dagreD3
from "dagre-d3";
import * as d3
from "d3";
2、数据准备 流程图作为一种有向图,与树图、网络图一样,数据由节点以及两点之间的边组成。
dataSet
: {
nodes
: [
{
id
: 0,
label
: "申请人",
shape
: "rect",
color
: "fill:#d81b13;stroke:transparent",
toolText
: ""
},
{
id
: 1,
label
: "支撑需求填写\n销售",
shape
: "rect",
color
: "",
toolText
: ""
},
{
id
: 2,
label
: "支撑方案填写\n一级支撑经理",
shape
: "rect",
color
: "",
toolText
: ""
},
{
id
: 3,
label
: "评审意见填写\n客响",
shape
: "rect",
color
: "",
toolText
: ""
},
{
id
: 4,
label
: "支撑方案和评审填写\n一级支撑经理",
shape
: "rect",
color
: "",
toolText
: ""
},
{
id
: 5,
label
: " 已结束 ",
shape
: "rect",
color
: "",
toolText
: ""
}
],
edges
: [
{id
: 1, source
: 0, target
: 1, label
: "", color
: ""},
{id
: 2, source
: 1, target
: 2, label
: "", color
: ""},
{id
: 3, source
: 2, target
: 3, label
: "", color
: ""},
{id
: 4, source
: 3, target
: 4, label
: "", color
: ""},
{id
: 5, source
: 4, target
: 5, label
: "", color
: ""},
{id
: 6, source
: 2, target
: 5, label
: "", color
: ""}
]
},
3、绘制流程图
renderGagre () {
this.tooltip
= this.createTooltip();
const g
= new dagreD3.graphlib.Graph();
g
.setGraph({
rankdir
: "LR",
marginx
: 60,
marginy
: 80,
edgesep
: 100,
ranksep
: 60
});
this.dataSet
.nodes
.forEach((item
) => {
g
.setNode(item
.id
, {
label
: item
.label
,
shape
: item
.shape
,
toolText
: item
.toolText
,
style
: item
.color
? item
.color
: "fill:#c0c1c3;stroke:transparent",
labelStyle
: "fill:#fff;",
width
: 83,
height
: 40
});
});
this.dataSet
.edges
.forEach((item
) => {
g
.setEdge(item
.source
, item
.target
, {
label
: item
.label
,
arrowheadStyle
: item
.color
? item
.color
: "fill:#c0c1c3;",
style
: item
.color
? item
.color
: "fill:#ffffff;stroke:#c0c1c3;stroke-width:1.5px"
});
});
const render
= new dagreD3.render();
const svgGroup
= d3
.select('svg').append("g");
const svg
= d3
.select("svg");
const zoom
= d3
.zoom().on("zoom", function () {
svgGroup
.attr("transform", d3
.event
.transform
);
});
svg
.call(zoom
);
render(svgGroup
, g
);
svgGroup
.selectAll("g.node")
.on("mouseover", (v
) => {
if (g
.node(v
).toolText
=== "") {
return;
}
this.tipVisible(g
.node(v
).toolText
);
})
.on("mouseout", () => {
this.tipHidden();
});
},
哦,对了要想实现上面的鼠标悬停的tooltip,还需要下面的js和css
js代码
createTooltip () {
return d3
.select("body")
.append("div")
.classed("tooltip", true)
.style("opacity", 0)
.style("display", "none");
},
tipVisible (textContent
) {
this.tooltip
.transition()
.duration(400)
.style("opacity", 0.9)
.style("display", "block");
this.tooltip
.html(textContent
)
.style("left", `${d3.event.pageX + 15}px`)
.style("top", `${d3.event.pageY + 15}px`);
},
tipHidden () {
this.tooltip
.transition()
.duration(400)
.style("opacity", 0)
.style("display", "none");
}
css 代码
.tooltip {
position: absolute;
font-size: 12px;
text-align: center;
background-color: white;
border-radius: 3px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
cursor: pointer;
display: inline-block;
padding:10px;
}
.tooltip>div {
padding: 10px;
}
以上就能实现一个结合后台数据动态渲染的流程图,在绘制流程图的时候,也遇到一些问题:
1、要根据不同的状态,展示不同颜色的节点、连线。 解决:本来绘制流程图在mouted函数中绘制就可出现,但是现在要实时根据数据来改变,所以要先获取到后台数据,然后再渲染流程图,而且获取后台数据要在mouted中就要获取到(之前在mouted绘制流程要去除,不然后续页面会出现两个流程图),不然一开始加载就来不显示。
2、tooltip 显示不出来 这个问题真的找了很久,一开始以为这个tooltip没有没有在页面上加载出来,但是当触发这个事件的时候,页面上的滚动条是有变化的,所以tooltip是已经绘制出来的,但是不知为何显示不出来。后来才找到原因,是因为我在流程图这个组件的样式标签上加上了scoped,从而影响了样式。
3、在iview 模态框组件中使用组件,节点连线渲染出错 这个问题解决可以看我这条博客使用iview的Modal组件中包含子组件,子组件加载出现问题
总结
以上就是我在项目中的例子,有关一些配置及相关的解释,大家可以参考这篇文章d3绘制流程图