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

二、dagre-d3基礎(chǔ)

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

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

列表數(shù)據(jù)如下:
tableList: [{
name: "節(jié)點(diǎn)一",
pre: []
},{
name: "節(jié)點(diǎn)二",
pre: ["節(jié)點(diǎn)一"]
},{
name: "節(jié)點(diǎn)三",
pre: ["節(jié)點(diǎn)一"]
},{
name: "節(jié)點(diǎn)四",
pre: ["節(jié)點(diǎn)二", "節(jié)點(diǎn)三"]
},{
name: "節(jié)點(diǎn)五",
pre: ["節(jié)點(diǎn)四"]
},{
name: "節(jié)點(diǎn)六",
pre: ['節(jié)點(diǎn)四']
},{
name: "節(jié)點(diǎn)七",
pre: ['節(jié)點(diǎn)五', '節(jié)點(diǎn)六']
}]數(shù)據(jù)處理,把表格數(shù)據(jù)轉(zhuǎn)變成節(jié)點(diǎn)和線條數(shù)據(jù)
async changeData() {
// 給每個(gè)節(jié)點(diǎn)設(shè)置對(duì)應(yīng)的編號(hào)
this.tableList.map((v, i) => {
this.indexObj[v.name] = i;
});
await this.tableList.map(async (v, i) => {
// 點(diǎn)
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é)點(diǎn)ID:{{currentNode.id}}</div>
<div>節(jié)點(diǎn)名稱:{{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é)點(diǎn)和線條
this.changeData();
// this.draw();
},
methods: {
async changeData() {
// 給每個(gè)節(jié)點(diǎn)設(shè)置對(duì)應(yīng)的編號(hào)
this.tableList.map((v, i) => {
this.indexObj[v.name] = i;
});
await this.tableList.map(async (v, i) => {
// 點(diǎn)
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 對(duì)象
const g = new dagreD3.graphlib.Graph().setGraph({
rankdir: 'LR', // 流程圖從下向上顯示,默認(rèn)'TB',可取值'TB'、'BT'、'LR'、'RL'
}).setDefaultEdgeLabel(function () {
return {};
});
// Graph添加節(jié)點(diǎn)
this.nodes.forEach(node => {
g.setNode(node.id, {
id: node.id,
label: node.nodeName,
shape: node
.shape, //節(jié)點(diǎn)形狀,可以設(shè)置rect(長方形),circle,ellipse(橢圓),diamond(菱形) 四種形狀,還可以使用render.shapes()自定義形狀
style: 'fill:#fff;stroke:#70baff', //節(jié)點(diǎn)樣式,可設(shè)置節(jié)點(diǎn)的顏色填充、節(jié)點(diǎn)邊框 fill:#61b2e4;stroke:#fff
labelStyle: 'fill: #000;font-weight:bold', //節(jié)點(diǎn)標(biāo)簽樣式, 可設(shè)置節(jié)點(diǎn)標(biāo)簽的文本樣式(顏色、粗細(xì)、大?。ゝill: #fff;font-weight:bold
rx: 5, // 設(shè)置圓角
ry: 5, // 設(shè)置圓角
paddingBottom: 15,
paddingLeft: 20,
paddingRight: 20,
paddingTop: 15,
});
});
// Graph添加節(jié)點(diǎn)之間的連線
if (this.nodes.length > 1) {
this.edges.forEach(edge => {
g.setEdge(edge.start, edge.end, {
label: edge.label, //邊標(biāo)簽
style: 'stroke: #70baff; fill: none; stroke-width: 2px', // 連線樣式
arrowheadStyle: 'fill: #70baff;stroke: #70baff;', //箭頭樣式,可以設(shè)置箭頭顏色
arrowhead: 'normal', //箭頭形狀,可以設(shè)置 normal,vee,undirected 三種樣式,默認(rèn)為 normal
})
});
}
// 獲取要繪制流程圖的繪圖容器
const container = d3.select('svg.dagre').select('g.container');
// 創(chuàng)建渲染器
const render = new dagreD3.render();
// 在繪圖容器上運(yùn)行渲染器繪制流程圖
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);
// 鼠標(biāo)懸停顯示隱藏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é)點(diǎn)點(diǎn)擊事件
需求:點(diǎn)擊某個(gè)節(jié)點(diǎn),修改節(jié)點(diǎn)樣式,再次點(diǎn)擊恢復(fù)原來的樣式
代碼很簡單,只需要在流程圖繪制好后加上如下代碼即可
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ìn)制,但是經(jīng)過插件繪制后轉(zhuǎn)成了rgb格式,所以在比較的時(shí)候要用設(shè)置顏色的rgb格式比較

總結(jié)
到此這篇關(guān)于vue使用dagre-d3畫流程圖的文章就介紹到這了,更多相關(guān)vue dagre-d3畫流程圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3使用Vue Router實(shí)現(xiàn)前端路由控制
在現(xiàn)代Web應(yīng)用中,前端路由控制是非常重要的一部分,它可以幫助我們將不同的頁面內(nèi)容展示給用戶,同時(shí)保持用戶在瀏覽不同頁面時(shí)的連貫性,本文將介紹如何使用Vue Router來實(shí)現(xiàn)前端路由控制,需要的朋友可以參考下2024-10-10
vue設(shè)置路由title,但刷新頁面時(shí)title失效的解決
這篇文章主要介紹了vue設(shè)置路由title,但刷新頁面時(shí)title失效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
基于Vue自定義指令實(shí)現(xiàn)按鈕級(jí)權(quán)限控制思路詳解
這篇文章主要介紹了基于vue自定義指令實(shí)現(xiàn)按鈕級(jí)權(quán)限控制,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05
手寫Vue源碼之?dāng)?shù)據(jù)劫持示例詳解
這篇文章主要給大家介紹了手寫Vue源碼之?dāng)?shù)據(jù)劫持的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
vue3項(xiàng)目打包成apk(android)詳細(xì)圖文教程
Vue本身是一個(gè)構(gòu)建用戶界面的漸進(jìn)式框架,不能直接打包成APK文件,但是你可以使用工具將Vue應(yīng)用打包成一個(gè)可以在Android設(shè)備上安裝的APK文件,這篇文章主要給大家介紹了關(guān)于vue3項(xiàng)目打包成apk(android)的相關(guān)資料,需要的朋友可以參考下2024-05-05
vue2.0的計(jì)算屬性computed和watch的區(qū)別及各自?使用場景解讀
這篇文章主要介紹了vue2.0的計(jì)算屬性computed和watch的區(qū)別及各自?使用場景,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
vue刷新頁面后params參數(shù)丟失的原因和解決方法
這篇文章主要給大家介紹了vue刷新頁面后params參數(shù)丟失的原因和解決方法,文中通過代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-12-12
使用vue初用antd 用v-model來雙向綁定Form表單問題
這篇文章主要介紹了使用vue初用antd 用v-model來雙向綁定Form表單問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
vue實(shí)現(xiàn)點(diǎn)擊按鈕倒計(jì)時(shí)
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)點(diǎn)擊按鈕倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07

