vue + gojs 實現(xiàn)拖拽流程圖效果
一、流程圖效果
最近一段時間在研究go.js,它是一款前端開發(fā)畫流程圖的一個插件,也是一個難點,要說為什么是難點,首先,它是依賴畫布canvas知識開發(fā)。其次,要依賴于內(nèi)部API開發(fā)需求,開發(fā)項目需求的時候就要花費大量的時間去熟悉go.js的API,然后才能進行開發(fā)。話不多說,我就先把我最近做的項目案例效果圖展示一下:
看到效果圖大家可能會想這個挺簡單的,會想沒什么難點,其實真正開發(fā)的時候才會知道的、才會領悟到。
二、為什么選go.js流程圖插件去開發(fā)項目?
在項目開發(fā)一期的時候我用的不是go.js,而用的是一款輕便的流程插件jsplumb.js,它也集成了各種功能性API,但是在開發(fā)二期的時候它的內(nèi)部功能已經(jīng)滿足不了需求了,所以我就開始在網(wǎng)上查找流程插件,看了很多插件,比如:G6,D3 等這些可視化流程插件都是不能滿足需求。要說為什么不能滿足需求,原因如下:
一、首先,看到效果圖里的內(nèi)置多點和其他模塊單點連線問題,其他插件是無法這個滿足需求的,可能我沒有深入去了解其他的流程插件吧,但是go.js里內(nèi)置點連線可以讓開發(fā)者很快的理解代碼邏輯,不用耗費大量的時間去想點與點的連線。
二、代碼上的數(shù)據(jù)結(jié)構(gòu)問題,其他插件里的API數(shù)據(jù)字段繁瑣量多,不夠清晰明了,而go.js里的數(shù)據(jù)結(jié)構(gòu)就兩個重要字段,一是所有模塊的字段集合二是連線字段集合,根據(jù)需求可以隨意加字段。
三、項目開發(fā)
(一)、首先直接使用go.js,畫布中是有水印的
其實這個問題不大,替換一行代碼就可以去除水印
引入go.js后,直接在編輯器中全局搜索7eba17a4ca3b1a8346,找到類似這樣結(jié)構(gòu)的代碼
a.ir=b.W[Ra("7eba17a4ca3b1a8346")][Ra("78a118b7")](b.W,ok,4,4);
注:不同的版本代碼不是完全相同的,可能是a.jv(屬性名是會變的) =‘xxxxx’,將這行代碼替換成
a.ir=function(){return true;}; //a.屬性名 要保持一致
去除水印的效果
(二)、HTML
<--第一種-->
<template> <div id="wrap"> <div id="chart-wrap"> <div id="chart-palette"></div><-- 畫布一 --> <div id="chart-diagram"></div><-- 畫布二 --> </div> </div> </template>
如圖:
第二種
結(jié)合vue的拖拽組件vuedraggable 實現(xiàn)業(yè)務需求。
<template> <div id="chart-wrap"> <div v-for="tab in tabLIst" :key="tab.id" class="tab"> //拖動 <vuedraggable @end.stop="end" @start.stop="move"> <i :class="tab.icon" /> {{ tab.text }} <el-tooltip effect="dark" :content="tab.tooltip" placement="top"> <i class="el-icon-question" /> </el-tooltip> </vuedraggable> </div> <div id="chart-diagram"/> <--畫布--> </div> </template>
如圖:
(三)、畫布的基本設置 。
this.diagram = $(go.Diagram, "chart-diagram", { // 畫布初始位置 initialContentAlignment: go.Spot.LeftSide, // 居中顯示 "undoManager.isEnabled": true, // 支持 Ctrl-Z 和 Ctrl-Y 操作 // 初始坐標 // initialPosition: new go.Point(0, 0), //allowSelect:false, ///禁止選中 // "toolManager.hoverDelay": 100, //tooltip提示顯示延時 // "toolManager.toolTipDuration": 10000, //tooltip持續(xù)顯示時間 // isReadOnly:true,//只讀 //禁止水平拖動畫布 //禁止水平滾動條 allowHorizontalScroll: false, // 禁止垂直拖動畫布 //禁止垂直滾動條 allowVerticalScroll: false, allowZoom: true,//畫布是否可以縮放 "grid.visible": false, //顯示網(wǎng)格 // allowMove: true, //允許拖動 // allowDragOut:true, allowDelete: true,//禁止刪除節(jié)點 allowCopy: true,//禁止復制 // 禁止撤銷和重做 // "undoManager.isEnabled": false, // 畫布比例 // scale:1.5, // minScale:1.2,//畫布最小比例 // maxScale:2.0,//畫布最大比例 // 畫布初始化動畫時間 // "animationManager.duration": 600, // 禁止畫布初始化動畫 "animationManager.isEnabled": false, // autoScale:go.Diagram.Uniform,//自適應 // autoScale:go.Diagram.UniformToFill,//自適應 // "draggingTool.dragsLink": false,//拖動線 // autoScale:go.Diagram.None,//默認值不自適應 // 畫布邊距padding // padding:80或者new go.Margin(2, 0)或new go.Margin(1, 0, 0, 1) // validCycle: go.Diagram.CycleDestinationTree,//只允許有一個父節(jié)點 //節(jié)點模塊動畫 S // "animationManager.initialAnimationStyle":go.Animation.EaseOutExpo, // "animationManager.initialAnimationStyle": go.Animation.EaseInOutQuad, "animationManager.initialAnimationStyle": go.AnimationManager.None, // "animationManager.initialAnimationStyle":go.AnimationManager.AnimateLocations, //節(jié)點模塊動畫 D // validCycle: go.Diagram.CycleNotUndirected, // validCycle: go.Diagram.CycleNotDirected, // validCycle: go.Diagram.CycleSourceTree, //ismodelfied:true //禁止拖拽 // 禁止鼠標拖動區(qū)域選中 // "dragSelectingTool.isEnabled" : false, //允許使用delete鍵刪除模塊 "commandHandler.deletesTree": true, // "hasHorizontalScrollbar":false,//去除水平滾動條 // "hasVerticalScrollbar":false,//去除豎直滾動條 // "canStart":false, // allowClipboard: true, // "toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom, //有鼠標滾輪事件放大和縮小,而不是向上和向下滾動 // layout: $(go.TreeLayout, // { angle: 90, layerSpacing: 80 }), } );
(三)、整體畫布事件及節(jié)點的監(jiān)聽
// 監(jiān)聽連線 this.diagram.addDiagramListener("LinkDrawn", (e) => { console.log(e.subject.part); }); // 監(jiān)聽刪除 this.diagram.addDiagramListener("SelectionDeleted", (e) => { e.subject.each(function (n) { console.log(n.data.key); }); }) // 修改節(jié)點 this.diagram.addDiagramListener("TextEdited", (evt) => { console.log(e.subject.part); }); // 監(jiān)聽點擊 this.diagram.addDiagramListener("ObjectSingleClicked", (e) => { //這是清除高亮的 // e.diagram.commit((d) => { // d.clearHighlighteds(); // }, "no highlighteds"); }); // // 移動事件 this.diagram.addDiagramListener("SelectionMoved", (e) => { console.log(e.diagram.lastInput.documentPoint); });
(四)、連線點封裝函數(shù)
// 節(jié)點連接線
makePort (name, align, spot, output, input) { var horizontal = align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom) return $(go.Shape, { fill: 'transparent', // 默認透明不現(xiàn)實 strokeWidth: 0, // 無邊框 fromMaxLinks: 1, // width: horizontal ? NaN : 10, // 垂直"port"則8像素寬 height: !horizontal ? NaN : 5, // 水平"port"則8像素 alignment: align, // 同其模塊對齊 stretch: horizontal ? go.GraphObject.Horizontal : go.GraphObject.Vertical, // 自動同其模塊一同伸縮 portId: name, // 聲明ID fromSpot: spot, // 聲明連線頭連出此"port"的位置 fromLinkable: output, // 布爾型,是否允許連線從此"port"連出 toLinkable: input, // 布爾型,是否允許連線從此"port"連出 toSpot: spot, // 聲明連線尾連入此"port"的位置 cursor: 'pointer', // 鼠標由指針改為手指,表示此處可點擊生成連線 mouseEnter: function (e, port) { // 鼠標移到"port"位置后,高亮 if (!e.diagram.isReadOnly) port.fill = 'rgba(255,0,255,0.3)' }, mouseLeave: function (e, port) { // 鼠標移出"port"位置后,透明 port.fill = 'transparent' } }) }
(五)、節(jié)點連線的高亮函數(shù)。
isHighlightedFun(link) { return $$(go.Shape, "RoundedRectangle", { fill: "rgba(217,236,255,.2)", stroke: "rgba(39,154,242,.1)", strokeWidth: 1, }, new go.Binding("stroke", "isHighlighted", (h) => { return h ? "rgba(39,154,242,1)" : "rgba(39,154,242,.8)"; }).ofObject(), new go.Binding("strokeWidth", "isHighlighted", (h) => { return h ? 2.5 : 1.3; }).ofObject(), ) }
如圖:
(六)、 節(jié)點連接線。(方法封裝)
makePort(name, align, spot, output, input) { var horizontal = align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom); return $$(go.Shape, { fill: "transparent", // 默認透明 strokeWidth: 0, // 無邊框 fromMaxLinks: 1, //最大連接數(shù) width: horizontal ? NaN : 10, // 垂直"port"則8像素寬 height: !horizontal ? NaN : 2, // 水平"port"則8像素 alignment: align, // 同其模塊對齊 stretch: (horizontal ? go.GraphObject.Horizontal : go.GraphObject.Vertical),//自動同其模塊一同伸縮 portId: name, // 聲明ID fromSpot: spot, // 聲明連線頭連出此"port"的位置 fromLinkable: output, // 布爾型,是否允許連線從此"port"連出 toLinkable: input, // 布爾型,是否允許連線從此"port"連出 toSpot: spot, // 聲明連線尾連入此"port"的位置 cursor: "pointer", // 鼠標由指針改為手指,表示此處可點擊生成連線 mouseEnter: (e, port) => { //鼠標移到"port"位置后,高亮 if (!e.diagram.isReadOnly) port.fill = "rgba(255,0,255,0.3)"; }, mouseLeave: (e, port) => {// 鼠標移出"port"位置后,透明 port.fill = "transparent"; } }); }
注意:要在this.diagram.nodeTemplateMap.add 增加模塊里調(diào)用。
示例:
this.diagram.nodeTemplateMap.add(type, $$(go.Node, "Auto", this.makePort("T", go.Spot.Top, go.Spot.TopCenter, false, true) ))
四、當前畫布的監(jiān)聽事件名稱包括
"AnimationStarting" :動畫渲染前事件,加載圖表的動畫即將開始;
"AnimationFinished" :動畫渲染完事件,加載圖表剛剛完成的動畫;
"BackgroundSingleClicked": 背景單擊事件, 單擊圖表背景;
"BackgroundDoubleClicked" :背景雙擊事件, 雙擊圖表背景;
"BackgroundContextClicked" :背景右鍵事件, 右鍵單擊圖表背景;
"ChangingSelection": 改變選擇前事件, 一個操作即將改變Diagram.selection圖表選擇集合,
"ChangedSelection" :改變選擇后事件, 一個操作已經(jīng)改變?Diagram.selection圖表選擇集合,
"ClipboardChanged" :剪切板改變事件, 零部件已被CommandHandler.copySelection復制到剪貼板上;
"ClipboardPasted" :剪切板粘貼事件,零部件已由CommandHandler.pasteSelection從剪貼板復制到圖表中;
"DocumentBoundsChanged": 文檔范圍改變事件, 圖表中各零部件的面積,?Diagram.documentBounds,已經(jīng)改變了;
"ExternalObjectsDropped" :(節(jié)點或線等)零部件拖放生成事件, 零部件已經(jīng)通過拖拽從圖的外部復制到圖中;
"GainedFocus" :獲得鍵盤焦點事件, 該圖獲得了鍵盤焦點,例如在調(diào)用Diagram.focus之后.
"LayoutCompleted" :布局完成事件, 整個圖表布局剛剛更新;
"LinkDrawn": 線創(chuàng)建事件,用戶剛剛使用LinkingTool創(chuàng)建了一個新鏈接;?
"LinkRelinked": 線重新連接事件, 用戶剛剛通過RelinkingTool?或?DraggingTool重新連接了現(xiàn)有線;
"LinkReshaped": 線路徑改變事件, 用戶剛剛通過LinkReshapingTool調(diào)整了線的路徑;
"LostFocus" :圖表失去焦點事件,這個圖表失去了鍵盤焦點,
"Modified" :圖表改變事件,?Diagram.isModified?屬性已被設置為一個新值——用于將窗口標記為自上次保存以來已被修改;
"ObjectSingleClicked": 對象單擊事件, 單擊了圖形對象(節(jié)點和線等);
"ObjectDoubleClicked":雙擊了圖形對象(節(jié)點和線等);
"ObjectContextClicked":右鍵單擊了圖形對象(節(jié)點和線等);
"PartCreated" :Part創(chuàng)建事件,用戶通過?ClickCreatingTool插入新的零部件;
"PartResized" :Part大小改變事件, 用戶通過ResizingTool 調(diào)整工具改變了一個圖形對象的大小;
"PartRotated" :Part旋轉(zhuǎn)事件, 用戶通過RotatingTool 旋轉(zhuǎn)工具改變了一個圖形對象的角度 ;
"SelectionMoved" :拖動事件, 用戶通過DraggingTool 拖動工具移動了選定的部分;
"SelectionCopied" :復制事件,戶通過DraggingTool 拖動工具復制了選定的部分;
"SelectionDeleted" :刪除后事件,用戶通過?CommandHandler.deleteSelection?已經(jīng)刪除了選定的部分;
"SelectionDeleting" :刪除前事件,用戶通過?CommandHandler.deleteSelection即將刪除選定的部分;
"SelectionGrouped" :選擇創(chuàng)建分組事件, 通過CommandHandler.groupSelection已經(jīng)從選擇的零部件中創(chuàng)建了一個新的組 ;
"SelectionUngrouped":用戶已刪除選定的組,但通過CommandHandler.ungroupSelection保留其成員;
"SubGraphCollapsed" :子圖折疊事件, 用戶通過CommandHandler.collapseSubGraph將選定的組折疊;
"SubGraphExpanded" :子圖展開事件, 用戶通過CommandHandler.expandSubGraph將選定的組展開;
"TextEdited" :文本塊修改事件,用戶通過文本編輯工具改變了文本塊的字符串值;
"TreeCollapsed": 樹折疊事件, 用戶通過CommandHandler.collapseTree折疊所選節(jié)點的子樹;
"TreeExpanded" :樹展開事件, 用戶通過CommandHandler.expandTree展開了所選節(jié)點的子樹;
"ViewportBoundsChanged":視窗范圍改變事件,圖表中可見的區(qū)域,?Diagram.viewportBounds,發(fā)生了改變;
五、迭代篇
(一)、項目的迭代。
從數(shù)據(jù)結(jié)構(gòu)到ui風格的整體重構(gòu),有了新的變化。
整體流程 如圖一:
模塊流程側(cè)邊設置圖二:
伸縮當前灰色意圖如圖三:
為什么收起意圖會有多條連線,是因為當前模塊下的意圖和部分模塊有關(guān)系線,所以在收起時要知道當前模塊下有幾個意圖和其他模塊有關(guān)系。
(二)、整體用的js方法
1、畫布里的功能js:
2、工具條js 方法:
(三)、功能分析
1、工具條中的功能方法
(1)、查看
注: 是通過gojs 實例中的makeSVG方法打開一個新窗口生成的一個svg
printDiagram() { var svgWindow = window.open(); if (!svgWindow) return; var printSize = new go.Size(3000, 2000); var bnds = this.diagram.documentBounds; var x = bnds.x; var y = bnds.y; while (y < bnds.bottom) { while (x < bnds.right) { var svg = this.diagram.makeSVG({scale: 1.0, position: new go.Point(x, y), size: printSize}); svgWindow.document.body.appendChild(svg); x += printSize.width; } x = bnds.x; y += printSize.height; } }
(2)、居中
這里將調(diào)用CommandHandler.scrollToPart,先還原畫布初始狀態(tài)后執(zhí)行動畫以將視口滾動到節(jié)點所在的位置。
注:如果節(jié)點靠近邊緣,除非您增加Diagram.scrollMargin,否則無法滾動視口,以使該節(jié)點更靠近視口的中心。
centerDiagram() { this.resetCanvas(); this.diagram.commandHandler.scrollToPart(this.diagram.findNodeForKey(this.initModuleId)); }, // 還原 resetCanvas() { this.diagram.scale = 1; this.$refs.set.zoom = 100; },
到此這篇關(guān)于vue + gojs 實現(xiàn)拖拽流程圖的文章就介紹到這了,更多相關(guān)vue拖拽 流程圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue.js實現(xiàn)開發(fā)購物車功能的方法詳解
這篇文章主要介紹了Vue.js實現(xiàn)開發(fā)購物車功能的方法,結(jié)合實例形式分析了基于vue.js開發(fā)的購物車功能相關(guān)操作步驟與實現(xiàn)技巧,需要的朋友可以參考下2019-02-02vuejs2.0實現(xiàn)分頁組件使用$emit進行事件監(jiān)聽數(shù)據(jù)傳遞的方法
這篇文章主要介紹了vuejs2.0實現(xiàn)分頁組件使用$emit進行事件監(jiān)聽數(shù)據(jù)傳遞的方法,非常不錯,具有參考借鑒價值,,需要的朋友可以參考下2017-02-02vue v-for出來的列表,點擊某個li使得當前被點擊的li字體變紅操作
這篇文章主要介紹了vue v-for出來的列表,點擊某個li使得當前被點擊的li字體變紅操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07vue新手入門出現(xiàn)function () { [native code]&nbs
這篇文章主要介紹了vue新手入門出現(xiàn)function () { [native code] }錯誤的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04