<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近接到一個需求——給後臺開發一個工作流程圖,方便給領導看工作流程具體到哪一步。
先寫了一個demo,大概樣子如下:
官網檔案Home | jsPlumb Toolkit Documentation
先安裝外掛
npm install jsplumb --save
安裝panzoom,主要用於滑鼠滾輪縮放流程圖
npm install panzoom --save
在需要的頁面引入外掛
import panzoom from 'panzoom' import { jsPlumb } from 'jsplumb'
接下來先寫佈局
父元件
<template> <div class="workflow"> <div class="flow_region"> <div id="flowWrap" ref="flowWrap" class="flow-wrap" @drop="drop($event)" @dragover="allowDrop($event)"> <div id="flow"> <flowNode v-for="item in data.nodeList" :id="item.id" :key="item.id" :node="item" @setNodeName="setNodeName" @changeLineState="changeLineState" /> </div> </div> </div> </div> </template>
flowNode是子元件
<template> <div ref="node" class="node-item" :class="{ isStart: node.type === 'start', isEnd: node.type === 'end', 'common-circle-node':node.type === 'start' || node.type === 'end' || node.type === 'event', 'common-rectangle-node':node.type === 'common' || node.type === 'freedom' || node.type === 'child-flow', 'common-diamond-node':node.type === 'gateway', 'common-x-lane-node':node.type === 'x-lane', 'common-y-lane-node':node.type === 'y-lane' }" :style="{ top: node.y + 'px', left: node.x + 'px' }" @click="setNotActive" @mouseenter="showAnchor" @mouseleave="hideAnchor" > <div class="nodeName">{{ node.nodeName }}</div> </div> </template>
樣式主要是子元件的,父元件樣式隨意就行
<style lang="less" scoped> @labelColor: #409eff; @nodeSize: 20px; @viewSize: 10px; .node-item { position: absolute; display: flex; height: 40px; width: 120px; justify-content: center; align-items: center; border: 1px solid #b7b6b6; border-radius: 4px; cursor: move; box-sizing: content-box; font-size: 12px; z-index: 9995; &:hover { z-index: 9998; .delete-btn{ display: block; } } .log-wrap{ width: 40px; height: 40px; border-right: 1px solid #b7b6b6; } .nodeName { flex-grow: 1; width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; } .node-anchor { display: flex; position: absolute; width: @nodeSize; height: @nodeSize; align-items: center; justify-content: center; border-radius: 10px; cursor: crosshair; z-index: 9999; background: -webkit-radial-gradient(sandybrown 10%, white 30%, #9a54ff 60%); } .anchor-top{ top: calc((@nodeSize / 2)*-1); left: 50%; margin-left: calc((@nodeSize/2)*-1); } .anchor-right{ top: 50%; right: calc((@nodeSize / 2)*-1); margin-top: calc((@nodeSize / 2)*-1); } .anchor-bottom{ bottom: calc((@nodeSize / 2)*-1); left: 50%; margin-left: calc((@nodeSize / 2)*-1); } .anchor-left{ top: 50%; left: calc((@nodeSize / 2)*-1); margin-top: calc((@nodeSize / 2)*-1); } } .active{ border: 1px dashed @labelColor; box-shadow: 0px 5px 9px 0px rgba(0,0,0,0.5); } .common-circle-node{ border-radius: 50%; height: 60px; width: 60px; } </style>
頁面樣式寫完,接下來寫外掛設定
jsPlumb.ready() 是一個勾點函數,它會在 jsPlumb 準備完畢時執行。
連線線的建立是通過 jsPlumb.connect() 方法實現的。該方法接受一個物件作為設定項。其中包含了與上述概念一一對應的設定項,以及一些額外的樣式。
source: 源物件,可以是物件的 id 屬性、Element 物件或者 Endpoint 物件。
target: 目標物件,可以是物件的 id 屬性、Element 物件或者 Endpoint 物件。
anchor: 是一個陣列,陣列中每一項定義一個錨點。
初始化方法
init() { this.jsPlumb.ready(() => { // 匯入預設設定 this.jsPlumb.importDefaults(this.jsplumbSetting) // 完成連線前的校驗 this.jsPlumb.bind('beforeDrop', evt => { const res = () => { } // 此處可以新增是否建立連線的校驗, 返回 false 則不新增; return res }) this.loadEasyFlow() // 會使整個jsPlumb立即重繪。 this.jsPlumb.setSuspendDrawing(false, true) }) this.initPanZoom() }, // 載入流程圖 loadEasyFlow() { // 初始化節點 for (let i = 0; i < this.data.nodeList.length; i++) { const node = this.data.nodeList[i] // 設定源點,可以拖出線連線其他節點 this.jsPlumb.makeSource(node.id, this.jsplumbSourceOptions) // // 設定目標點,其他源點拖出的線可以連線該節點 this.jsPlumb.makeTarget(node.id, this.jsplumbTargetOptions) // this.jsPlumb.draggable(node.id); this.draggableNode(node.id) } // 初始化連線 this.jsPlumb.unbind('connection') // 取消連線事件 console.log(this.data.lineList) for (let i = 0; i < this.data.lineList.length; i++) { const line = this.data.lineList[i] const conn = this.jsPlumb.connect( { source: line.sourceId, target: line.targetId, paintStyle: { stroke: line.cls.linkColor, strokeWidth: 2 // strokeWidth: line.cls.linkThickness } }, this.jsplumbConnectOptions ) conn.setLabel({ label: line.label, cssClass: `linkLabel ${line.id}` }) } },
this.data 是需要渲染的資料,放在文章末尾,具體資料按照介面實際返回的來寫
this.jsplumbSourceOptions 是jsplumb設定資訊,新建一個檔案編寫,具體如下:
export const jsplumbSetting = { grid: [10, 10], // 動態錨點、位置自適應 anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'], Container: 'flow', // 連線的樣式 StateMachine、Flowchart,有四種預設型別:Bezier(貝塞爾曲線),Straight(直線),Flowchart(流程圖),State machine(狀態機) Connector: ['Flowchart', { cornerRadius: 5, alwaysRespectStubs: true, stub: 5 }], // 滑鼠不能拖動刪除線 ConnectionsDetachable: false, // 刪除線的時候節點不刪除 DeleteEndpointsOnDetach: false, // 連線的端點 // Endpoint: ["Dot", {radius: 5}], Endpoint: [ 'Rectangle', { height: 10, width: 10 } ], // 線端點的樣式 EndpointStyle: { fill: 'rgba(255,255,255,0)', outlineWidth: 1 }, LogEnabled: false, // 是否開啟jsPlumb的內部紀錄檔記錄 // 繪製線 PaintStyle: { stroke: '#409eff', strokeWidth: 2 }, HoverPaintStyle: { stroke: '#409eff' }, // 繪製箭頭 Overlays: [ [ 'Arrow', { width: 8, length: 8, location: 1 } ] ], RenderMode: 'svg' } // jsplumb連線引數 export const jsplumbConnectOptions = { isSource: true, isTarget: true, // 動態錨點、提供了4個方向 Continuous、AutoDefault anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'] } export const jsplumbSourceOptions = { filter: '.node-anchor', // 觸發連線的區域 /* "span"表示標籤,".className"表示類,"#id"表示元素id*/ filterExclude: false, anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'], allowLoopback: false } export const jsplumbTargetOptions = { filter: '.node-anchor', /* "span"表示標籤,".className"表示類,"#id"表示元素id*/ filterExclude: false, anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'], allowLoopback: false }
在父元件引入組態檔和方法
import { jsplumbSetting, jsplumbConnectOptions, jsplumbSourceOptions, jsplumbTargetOptions } from './config/commonConfig'
接下來在上面說的初始化方法檔案裡面設定滑鼠滾輪縮放外掛的方法 this.initPanZoom():
// 滑鼠捲動放大縮小 initPanZoom() { const mainContainer = this.jsPlumb.getContainer() const mainContainerWrap = mainContainer.parentNode const pan = panzoom(mainContainer, { smoothScroll: false, bounds: true, // autocenter: true, zoomDoubleClickSpeed: 1, minZoom: 0.5, maxZoom: 2, // 設定捲動縮放的組合鍵,預設不需要組合鍵 beforeWheel: (e) => { // console.log(e) // let shouldIgnore = !e.ctrlKey // return shouldIgnore }, beforeMouseDown: function(e) { // allow mouse-down panning only if altKey is down. Otherwise - ignore var shouldIgnore = e.ctrlKey return shouldIgnore } }) this.jsPlumb.mainContainerWrap = mainContainerWrap this.jsPlumb.pan = pan // 縮放時設定jsPlumb的縮放比率 pan.on('zoom', e => { const { scale } = e.getTransform() this.jsPlumb.setZoom(scale) }) pan.on('panend', (e) => { }) // 平移時設定滑鼠樣式 mainContainerWrap.style.cursor = 'grab' mainContainerWrap.addEventListener('mousedown', function wrapMousedown() { this.style.cursor = 'grabbing' mainContainerWrap.addEventListener('mouseout', function wrapMouseout() { this.style.cursor = 'grab' }) }) mainContainerWrap.addEventListener('mouseup', function wrapMouseup() { this.style.cursor = 'grab' }) },
大功告成,data的資料放在這裡,測試使用:
{ "FlowJson": { "nodeList": [ { "type": "start", "nodeName": "已新建", "id": "start-HiXWf8wsAcrWXjAAXVWc6AQk00000001", "node_code": "已新建", "trigger_event": "", "branch_flow": "", "icon": "play-circle", "x": 175, "y": 60, "width": 50, "height": 50 }, { "type": "freedom", "nodeName": "待審批", "id": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "node_code": "待審批", "trigger_event": "", "branch_flow": "", "icon": "sync", "x": 330, "y": 160, "width": 50, "height": 120 }, { "type": "end", "nodeName": "已通過", "id": "end-JjRvtD5J2GIJKCn8MF7IYwxh00000999", "node_code": "已通過", "trigger_event": "", "branch_flow": "", "icon": "stop", "x": 330, "y": 360, "width": 50, "height": 50 }, { "type": "end", "nodeName": "審批拒絕", "id": "end-J1DMScH5YjSKyk0HeNkbt62F00010001", "node_code": "審批拒絕", "trigger_event": "", "branch_flow": "", "icon": "stop", "x": 500, "y": 350, "width": 50, "height": 50 } ], "linkList": [ { "type": "link", "id": "link-BpI6ZuX1bJywz5SEi3R5QaWoi7g3QiSr", "sourceId": "start-HiXWf8wsAcrWXjAAXVWc6AQk00000001", "targetId": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "label": "LINE000000", "role": [], "organize": [], "audit_role": [], "audit_organize": [], "audit_organize_same": "0", "audit_dealer_same": "0", "audit_dealers": [], "notice": "0", "plug": "", "pass_option": "pass", "row_par_json": "", "judge_fields": "", "auth_at": "", "auth_user": "", "auth_stat": "", "auth_mark": "", "cls": { "linkType": "Flowchart", "linkColor": "#008000", "linkThickness": 4 } }, { "type": "link", "id": "link-5xJWzGlkIpUCsjmpfgesJxAOMHwkPlno", "sourceId": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "targetId": "end-J1DMScH5YjSKyk0HeNkbt62F00010001", "label": "LINE000001", "role": [], "organize": [], "audit_role": [ "PROJECT_SUPPORT_PLAN_CODE" ], "audit_organize": [], "audit_organize_same": "0", "audit_dealer_same": "0", "audit_dealers": [], "notice": "0", "plug": "", "pass_option": "reject", "row_par_json": "", "judge_fields": "", "auth_at": "", "auth_user": "", "auth_stat": "", "auth_mark": "", "cls": { "linkType": "Flowchart", "linkColor": "#808080", "linkThickness": 1 } }, { "type": "link", "id": "link-g05V3usXa86wAtpcMkvGzybdBlpasMjU", "sourceId": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "targetId": "end-JjRvtD5J2GIJKCn8MF7IYwxh00000999", "label": "LINE000002", "role": [], "organize": [], "audit_role": [ "PROJECT_SUPPORT_PLAN_CODE" ], "audit_organize": [], "audit_organize_same": "0", "audit_dealer_same": "0", "audit_dealers": [], "notice": "0", "plug": "", "pass_option": "approve", "row_par_json": "", "judge_fields": "", "auth_at": "", "auth_user": "", "auth_stat": "", "auth_mark": "", "cls": { "linkType": "Flowchart", "linkColor": "#808080", "linkThickness": 1 } } ] } }
到此這篇關於vue+jsplumb實現工作流程圖的專案實踐的文章就介紹到這了,更多相關vue jsplumb工作流程圖內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45