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