近期项目中使用到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();
// 创建graph对象
const g = new dagreD3.graphlib.Graph();
// 设置图
g.setGraph({
rankdir: "LR", // T:top B:bottom
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();
// 选择svg并添加一个g元素作为绘图容器
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);
// 鼠标悬停显示隐藏tooptip
svgGroup
.selectAll("g.node")
.on("mouseover", (v) => {
// 假如当前toolText为"",则不展示
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");
},
// tooltip显示
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`);
},
// tooltip隐藏
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绘制流程图