vue使用dagre-d3畫流程圖的完整代碼
一、安裝依賴
npm install --save d3 dagre-d3

二、dagre-d3基礎(chǔ)

其實畫普通的流程圖很簡單,主要關(guān)注節(jié)點數(shù)據(jù)和線條數(shù)據(jù),以上圖為例nodes用來存儲節(jié)點數(shù)據(jù)id必須唯一,nodeName是節(jié)點名稱,shape是節(jié)點形狀:
1)rect(長方形)
2)circle,ellipse(橢圓)
3)diamond(菱形)
還可以使用render.shapes()自定義形狀
edges用來存儲線條數(shù)據(jù),start是開始節(jié)點,end是結(jié)束節(jié)點,label可以給線條命名

三、流程圖
需求:根據(jù)表格中的工序名稱和上工序生成流程圖

列表數(shù)據(jù)如下:
tableList: [{
name: "節(jié)點一",
pre: []
},{
name: "節(jié)點二",
pre: ["節(jié)點一"]
},{
name: "節(jié)點三",
pre: ["節(jié)點一"]
},{
name: "節(jié)點四",
pre: ["節(jié)點二", "節(jié)點三"]
},{
name: "節(jié)點五",
pre: ["節(jié)點四"]
},{
name: "節(jié)點六",
pre: ['節(jié)點四']
},{
name: "節(jié)點七",
pre: ['節(jié)點五', '節(jié)點六']
}]數(shù)據(jù)處理,把表格數(shù)據(jù)轉(zhuǎn)變成節(jié)點和線條數(shù)據(jù)
async changeData() {
// 給每個節(jié)點設(shè)置對應(yīng)的編號
this.tableList.map((v, i) => {
this.indexObj[v.name] = i;
});
await this.tableList.map(async (v, i) => {
// 點
this.nodes.push({
id: i,
nodeName: v.name,
shape: "rect"
});
// 線
let arr = await this.getLine(v);
this.edges = this.edges.concat(arr);
});
this.draw();
},
getLine(node) {
let brr = [];
if (node.pre.length) {
if (node.pre.length === 1) {
brr.push({
start: this.indexObj[node.pre[0]],
end: this.indexObj[node.name],
label: ""
});
} else {
node.pre.map(v => {
brr.push({
start: this.indexObj[v],
end: this.indexObj[node.name],
label: ""
});
});
}
}
return brr;
},完整代碼:
<template>
<div style="border: 1px solid #ccc; padding: 20px; width: 600px">
<svg class="dagre" width="600" height="600">
<g class="container"></g>
</svg>
<div ref="tooltip" class="tooltip">
<div>節(jié)點ID:{{currentNode.id}}</div>
<div>節(jié)點名稱:{{currentNode.nodeName}}</div>
</div>
</div>
</template>
<script>
import dagreD3 from 'dagre-d3';
import * as d3 from 'd3';
export default {
name: 'dagre',
props: {
tableList: {
type: Array,
default: []
}
},
data() {
return {
currentNode: {
id: null,
nodeName: '',
},
nodes: [],
edges: [],
indexObj: {},
// nodes: [
// {id: 0,nodeName: "A",shape: "rect"},
// {id: 1,nodeName: "B",shape: "diamond"},
// {id: 2,nodeName: "C",shape: "rect"},
// {id: 3,nodeName: "D",shape: "rect"},
// {id: 4,nodeName: "E",shape: "rect"},
// {id: 5,nodeName: "F",shape: "rect"}
// ],
// edges: [
// {start: 0,end: 1,label: "哈哈"},
// {start: 1,end: 2,label: ""},
// {start: 1,end: 3,label: ""},
// {start: 2,end: 4,label: ""},
// {start: 3,end: 5,label: ""},
// {start: 4,end: 5,label: ""}
// ],
};
},
mounted() {
// 把表格的數(shù)據(jù)轉(zhuǎn)成節(jié)點和線條
this.changeData();
// this.draw();
},
methods: {
async changeData() {
// 給每個節(jié)點設(shè)置對應(yīng)的編號
this.tableList.map((v, i) => {
this.indexObj[v.name] = i;
});
await this.tableList.map(async (v, i) => {
// 點
this.nodes.push({
id: i,
nodeName: v.name,
shape: "rect"
});
// 線
let arr = await this.getLine(v);
this.edges = this.edges.concat(arr);
});
this.draw();
},
getLine(node) {
let brr = [];
if (node.pre.length) {
if (node.pre.length === 1) {
brr.push({
start: this.indexObj[node.pre[0]],
end: this.indexObj[node.name],
label: ""
});
} else {
node.pre.map(v => {
brr.push({
start: this.indexObj[v],
end: this.indexObj[node.name],
label: ""
});
});
}
}
return brr;
},
// 繪制簡單的流程圖
draw() {
// 創(chuàng)建 Graph 對象
const g = new dagreD3.graphlib.Graph().setGraph({
rankdir: 'LR', // 流程圖從下向上顯示,默認'TB',可取值'TB'、'BT'、'LR'、'RL'
}).setDefaultEdgeLabel(function () {
return {};
});
// Graph添加節(jié)點
this.nodes.forEach(node => {
g.setNode(node.id, {
id: node.id,
label: node.nodeName,
shape: node
.shape, //節(jié)點形狀,可以設(shè)置rect(長方形),circle,ellipse(橢圓),diamond(菱形) 四種形狀,還可以使用render.shapes()自定義形狀
style: 'fill:#fff;stroke:#70baff', //節(jié)點樣式,可設(shè)置節(jié)點的顏色填充、節(jié)點邊框 fill:#61b2e4;stroke:#fff
labelStyle: 'fill: #000;font-weight:bold', //節(jié)點標簽樣式, 可設(shè)置節(jié)點標簽的文本樣式(顏色、粗細、大小)fill: #fff;font-weight:bold
rx: 5, // 設(shè)置圓角
ry: 5, // 設(shè)置圓角
paddingBottom: 15,
paddingLeft: 20,
paddingRight: 20,
paddingTop: 15,
});
});
// Graph添加節(jié)點之間的連線
if (this.nodes.length > 1) {
this.edges.forEach(edge => {
g.setEdge(edge.start, edge.end, {
label: edge.label, //邊標簽
style: 'stroke: #70baff; fill: none; stroke-width: 2px', // 連線樣式
arrowheadStyle: 'fill: #70baff;stroke: #70baff;', //箭頭樣式,可以設(shè)置箭頭顏色
arrowhead: 'normal', //箭頭形狀,可以設(shè)置 normal,vee,undirected 三種樣式,默認為 normal
})
});
}
// 獲取要繪制流程圖的繪圖容器
const container = d3.select('svg.dagre').select('g.container');
// 創(chuàng)建渲染器
const render = new dagreD3.render();
// 在繪圖容器上運行渲染器繪制流程圖
render(container, g);
// 拖拽縮放
const svg = d3.select('svg.dagre');
let zoom = d3.zoom().scaleExtent([0.5, 2]).on('zoom', current => {
container.attr('transform', current.transform);
});
svg.call(zoom);
// 鼠標懸停顯示隱藏tooltip
const that = this;
const tooltipBox = that.$refs.tooltip;
container.on('mouseover', e => {
if (e.target.nodeName === "rect") {
that.currentNode = that.nodes.filter(item => item.id === Number(e.target.__data__))[0];
tooltipBox.style.display = 'block';
tooltipBox.style.top = e.clientY + 20 + 'px';
tooltipBox.style.left = e.clientX + 'px';
}
}).on('mouseout', function () {
tooltipBox.style.display = 'none';
})
},
},
};
</script>
<style scoped>
.tooltip {
position: absolute;
font-size: 12px;
background-color: white;
border-radius: 3px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
cursor: pointer;
display: none;
padding: 10px;
}
.tooltip>div {
padding: 10px;
}
</style>
四、效果展示

五、節(jié)點點擊事件
需求:點擊某個節(jié)點,修改節(jié)點樣式,再次點擊恢復原來的樣式
代碼很簡單,只需要在流程圖繪制好后加上如下代碼即可
d3.selectAll('.node').on('mousedown', (e) => {
if(e.target.nodeName === "rect") {
if(e.target.style.fill === "rgb(97, 178, 228)") {
e.target.style = "fill:#877ee1;stroke:#fff";
} else {
e.target.style = "fill:#61b2e4;stroke:#fff";
}
}
});tips:代碼里我們設(shè)置的顏色是十六進制,但是經(jīng)過插件繪制后轉(zhuǎn)成了rgb格式,所以在比較的時候要用設(shè)置顏色的rgb格式比較

總結(jié)
到此這篇關(guān)于vue使用dagre-d3畫流程圖的文章就介紹到這了,更多相關(guān)vue dagre-d3畫流程圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中使用go()和back()兩種返回上一頁的區(qū)別說明
這篇文章主要介紹了vue中使用go()和back()兩種返回上一頁的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
vue2.0/3.0的響應(yīng)式原理及區(qū)別淺析
這篇文章主要給大家介紹了關(guān)于vue2.0/3.0響應(yīng)式原理及區(qū)別的相關(guān)資料,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-05-05
Vuejs第十一篇組件之slot內(nèi)容分發(fā)實例詳解
這篇文章主要介紹了Vuejs第十一篇之slot內(nèi)容分發(fā)組件詳解的相關(guān)資料2016-09-09
深入理解vue.js中$watch的oldvalue與newValue
這篇文章主要給大家介紹了關(guān)于vue.js中$watch的oldvalue與newValue的相關(guān)資料,文中通過示例代碼介紹的非常詳細,并且介紹了關(guān)于watch的其他測試,對大家學習或者使用vue.js具有一定的參考學習價值,需要的朋友們下面跟著小編來一起看看吧。2017-08-08
vue-router中query和params的區(qū)別解析
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,適合用于構(gòu)建單頁面應(yīng)用,這篇文章主要介紹了vue-router中query和params的區(qū)別 ,需要的朋友可以參考下2022-10-10

