摘要:拖了這么久,現在終于要開始硬著頭皮寫一篇基于的流程圖偽教程文章了。本教程主要講述一個基于如何實現一個簡單的流程圖,更多引發的思考是,什么項目更適合使用這種模式的框架,以及如何發揮的價值。
嚴重拖延癥,一方面這項目模塊純屬個人娛樂。另一方面,流程圖這塊涉及的東西還是蠻多的,這次也只是介紹一些簡單的部分。拖了這么久,現在終于要開始硬著頭皮寫一篇基于vue+svg的流程圖"偽教程"文章了。初次獻丑,還請輕噴。
模塊簡介項目地址
出于學習vue而非兼容的目的,本項目僅考慮現代瀏覽器( 谷歌 ),部分兼容問題還請見諒。
本模塊的開發源于對流程圖的簡單需求( 純UI實現,暫不存在業務邏輯 ),這里不贅訴vue-cli生成的目錄結構(可以參考這篇或自行谷歌)。
項目實際用到的技術棧:SVG + vue + vuex
功能介紹:
畫布縮放
節點( 開始,基礎,判斷等 )添加,刪除
節點間連線( 直線/折線 )
文本添加
外部導入SVG圖形
撤銷與重做
畫布縮放考慮到畫布縮放后布局需保持一致,這里通過修改transform: scale(); transform-origin: ; 來實現,節點則相對父層定位。
節點相關TODO: SVG最優縮放解決方案?
下面我簡單說一下思路:
由于不存在業務邏輯,我把流程圖簡化為 開始 基礎 判斷 3個基礎組件( 基于SVG )。
如:
這里說一下判斷這個組件( 后期可能出現復雜形狀均以path實現 ),一般由AI軟件直接導出相關形狀。
左邊工具欄跟畫布中的相同圖形源于同個組件,故設有兩個樣式,即 defaultStyle 和 drawStyle。之前有考慮過,如果流程圖的圖形復雜多變的話,那這種模式豈不是每一個組件都得人為定義。同樣,采用導入SVG也有類似問題。因為如果圖形大小都不確定的話,除了支持圖形修改大小,否者將導致畫布出現大小不一的圖形。( 非常遺憾這方面沒有做出突破,不過這將成為未來改進的方向。)
最開始采用的解決方案是以scale的方式,也就是統一讓工具欄中的圖形跟拖入畫布中的圖形成等比縮放關系。不過該方式會造成stroke也同比縮放,并非我們想要的。
所以目前暫時采用寫死的方式。
注意: 在svg中 ellipse 定位相對于中心點,而rect定位是相對于左上角。
節點渲染TODO是否有辦法將各組件定位源點設置為組件中心點。
節點渲染方面,由于之前是將圖形作為組件,于是采用 component + is 的方式來渲染圖形。同時也是以數據驅動的方式來渲染,即數據決定視圖。
拖動節點涉及鏡像節點時:
代碼直通車
新增節點drag drop 的形式。采用該方式的好處是不需要模擬拖拽事件。也就是鏡像什么的不需要自己做。( 畫布內節點拖拽則使用原生模擬 )
代碼直通車
對節點的操作均以指令( directives )的形式( 直接操作DOM )。這引發了我對該類項目是否適合用vue類框架來做的疑問,從開發效率方面,還是首選vue,但是從性能方面,由于沒有深入研究,并沒有發言權。
TODO 場景模擬,假設我們需要移動畫布內節點,通過directives的el來獲取節點,然后通過el.onmousemove來修改data中對應的translate來實現位置的更改。這里修改data來驅動視圖是我們常用的方式,但是我想不通的就是el.onmousemove來修改data實現的雙向數據綁定所帶來的性能在這里是否有體現。
我所設想的是,是否涉及多依賴的時候,diff帶來的性能提升才有價值。舉個例子,我有一個列表,存在于data中的listData,然后在view中有多處關聯listData。那此時操作listData比直接操作DOM來得更好些。
獲取SVG大小看過相關vitrualDOM的介紹,通過diff可以只操作變化的DOM。
獲取節點大小使用 getBoundingClientRect ,同時由于前面做了縮放功能,這里獲取節點大小時需要除以縮放比例來獲取正確值。
let obj = el.getElementsByTagName("g")[0] let w = obj.getBoundingClientRect().width / _this.drawStyle.zoomRate let h = obj.getBoundingClientRect().height / _this.drawStyle.zoomRate let wh = { width: w, height: h }
代碼直通車
節點操作總結由于節點的顯示是基于NodeData,所以增刪其實就是對NodeData的增刪。
主要代碼
連線相關連線其實也只是用到了svg的line和polyline,這里跟節點類似,均以組件的形式存在,并以lineData驅動連線視圖。所以最終連線的增刪也是對數據的操作。
連接點的顯示首先是鏈接點的位置( 綠色遠點位置 ),之前基于jquery做的流程圖是用div布局,現在用svg增加了難度,由于svg不能使用position,所以無法基于當前元素定位。采用的是土辦法,即用圖形大小+padding動態獲取4個點的位置。期間,由于4個連線節點與圖形節點有空隙,當mouseover不處于圖形或節點時,事件無法觸發。在此是模擬一個區域來解決的。由于個人經驗問題,這部分代碼完全就是命令式的風格。勿噴
代碼直通車
代碼直通車2
節點間連線做了兩種情況:(這里不講訴從mousedown至mouseup具體細節,可以看這里)
其實很多人說,算法可以解決很多垃圾代碼。可惜我還沒掌握它的真諦,比如之前的圖形組件,以及接下來的不同線條。其實都可以通過一定的算法得出來。我這里只講講最笨的方法,待我成長到能用算法來說話的時候,在回來好好理下這篇文章。
line直線
直線無外乎就是兩個點坐標,通過svg中的line來顯示。這時候就得看項目的需求,我們假設最簡單的情況,就是上面講到過的4個連接點最為連線的起始或結束點。
下面是計算圖形中4個點的坐標位置
computeLine(direction, obj) { // low不止一點點 let { top, left, width, height } = obj let w = width / 2 let h = height / 2 switch (direction) { case "t": top = top - h break case "b": top = top + h break case "l": left = left - w break case "r": left = left + w break default: break } return { top, left } }
polyline折線
折線考慮的情況相對比較多一點,這邊由于使用的是polyline,它的點位設置長這樣子points="125,96 183.5,96 183.5,399 242,399"
這個時候一般會把字符轉化為較為好操作的數組或對象。折線涉及的開始點跟結束點跟上面介紹直線的點位一樣,不同的是中間線的位置,如果不考慮復雜的情況,
一般可以分為兩種,上下,左右。通過獲取開始與結束點的中點位置來確定中線即可以得到想要的折線。代碼如下:(都是用簡單粗暴的方式。)
computePolyLine(start, end, direction) { let startPoint = { x: +(start.split(",")[0]), y: +(start.split(",")[1]) } let endPoint = { x: +(end.split(",")[0]), y: +(end.split(",")[1]) } let m1, m2 switch (direction) { case "t": case "b": let mY = startPoint.y + (endPoint.y - startPoint.y) / 2 m1 = { x: startPoint.x, y: mY } m2 = { x: endPoint.x, y: mY } break case "l": case "r": let mX = startPoint.x + (endPoint.x - startPoint.x) / 2 m1 = { x: mX, y: startPoint.y } m2 = { x: mX, y: endPoint.y } break default: break } return `${startPoint.x},${startPoint.y} ${m1.x},${m1.y} ${m2.x},${m2.y} ${endPoint.x},${endPoint.y}` }連線總結
節點跟連線在渲染以及操作的處理上大同小異,這里不確定是否為最佳實踐的有兩個地方,一是采用component+is的形式來渲染組件,二是采用 diretives的方式來操作DOM。連線的計算形式也略顯簡單,這確實是需要一定時間來成長的。扯偏了,在這簡單總結一下,無論是哪種連線方式,我們需要做的就是正確獲取對應點的位置,然后修改數據來驅動視圖。不過能在各種復雜的情況下總結出算法,也是一種跨越,加油吧。
節點及連線的文本添加節點及連線的文本添加原理都一樣,這里采用的是設置 contenteditable 當contenteditable為true時,html結構自動添加文本節點并且可編輯。更多細節可以參考張鑫旭的這篇
順道講一下pointer-events本模塊有兩個地方用到該css屬性。一個是文本添加這塊,以及頭部工具欄部分。
CSS屬性pointer-events允許作者控制特定的圖形元素在何時成為鼠標事件的target。當未指定該屬性時,SVG內容表現如同visiblePainted。
除了指定元素不成為鼠標事件的目標,none值還指示鼠標事件穿過該元素,并指向位于元素下面的元素。
更多細節關于pointer-events
張鑫旭
MDN
外部導入SVGTODO 文本編輯雖已實現功能,但這塊BUG較多,還未完善。
這邊也是用到了HTML5的Drop功能,顯示則是用到了svg的images。拖拽實現比較簡單:
dropHandle (e) { let reader = new FileReader() let file = e.dataTransfer.files[0] reader.onload = (e) => { this.userImages.push(e.target.result) } reader.readAsDataURL(file) }, dragoverHandle () { }, dragstart (imgSrc) { event.dataTransfer.setData("URL", imgSrc) }
這邊需要注意的是@drop.stop.prevent="dropHandle" @dragover.stop.prevent="dragoverHandle"要阻止冒泡以及阻止瀏覽器默認行為。
還有一個要注意的是dataTransfer.getData()在dragover,dragenter,dragleave中無法獲取數據的問題
根據W3C標準,drag data store有三種模式,Read/write mode, Read-only mode跟Protected mode。細節
Read/write mode
讀/寫模式,在dragstart事件中使用,可以添加新數據到drag data store中。
Read-only mode
只讀模式,在drop事件中使用,可以讀取被拖拽數據,不可添加新數據。
Protected mode
保護模式,在所有其他的事件中使用,數據的列表可以被枚舉,但是數據本身不可用且不能添加新數據。
深入
撤銷與重做這一功能本質上是沒有完成的,因為采用了一種偷懶的方式,vuex 生成 State 快照,生產環境不建議使用。
基本原理就是通過vuex提交更高(mutation)來觸發回調。以此來記錄state 快照
代碼直通車
總結本項目屬于入門級的vue+vuex,但是并沒有講如何使用vue或者vuex,因為這些在官方文檔其實都已經講的非常清楚了。該項目也只是簡單使用了如vue的自定義指令,MiXin等常用方法。諸如vue Render函數組件,不在本文談論范圍,這里簡單講下使用體驗,render組件比較適合高自定義的組件(變化邏輯比較復雜)。因為一些簡單組件其實更適合用tempalte的形式,雖然使用Render可以提高一定的性能( 減少了從tempalte到render這一步 ),但是很多現有的如sync,是render組件所不具備的( 需自己實現 )。vuex的使用,則需要注意的是object引用地址的問題。也就是說,要避免數據間的潛在影響。(雖然vuex自身也有規避這個問題)可以了解一下immutable 。
本教程主要講述一個基于vue如何實現一個簡單的流程圖,更多引發的思考是,什么項目更適合使用這種MVVM模式的框架,以及如何發揮VitrualDOM的價值。其實上面幾個章節的點隨便拿個出來都可以深入探討出很多技術問題,以后有機會再陸續深入。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89141.html
摘要:拖了這么久,現在終于要開始硬著頭皮寫一篇基于的流程圖偽教程文章了。本教程主要講述一個基于如何實現一個簡單的流程圖,更多引發的思考是,什么項目更適合使用這種模式的框架,以及如何發揮的價值。 嚴重拖延癥,一方面這項目模塊純屬個人娛樂。另一方面,流程圖這塊涉及的東西還是蠻多的,這次也只是介紹一些簡單的部分。拖了這么久,現在終于要開始硬著頭皮寫一篇基于vue+svg的流程圖偽教程文章了。初次獻...
摘要:是目前唯一一個支持同步調用的跨平臺年度上最多的個項目前端掘金年接近尾聲,在最近的幾篇文章中,會整理總結一些年度開源項目。 JS 全棧教程 - 前端 - 掘金本課程是基于阮一峰的 js 全棧教程的視頻版本,免費供大家觀看... 2016 年 10 個最佳的 CodePen 作品 - 前端 - 掘金說到 CodePen,前端開發者們肯定不會陌生。如果說 Dribbble 是設計師們聚集的圣...
摘要:本項目是一個簡單的全棧項目,前端新手可以拿來練練手。項目實現了一些簡單的功能,后臺可以對圖書進行錄入錄出掃碼或手動,前臺顯示錄入的圖書,并且前臺注冊登錄后可以將書的訂單發給服務器,并存到服務器。 Vue-book 2.0 Github 地址:https://github.com/percy507/v... 【覺得不錯就來個 star 吧 ^_^】 說明(菜鳥請進,大神繞道 ~) 前端...
摘要:本項目是一個簡單的全棧項目,前端新手可以拿來練練手。項目實現了一些簡單的功能,后臺可以對圖書進行錄入錄出掃碼或手動,前臺顯示錄入的圖書,并且前臺注冊登錄后可以將書的訂單發給服務器,并存到服務器。 Vue-book 2.0 Github 地址:https://github.com/percy507/v... 【覺得不錯就來個 star 吧 ^_^】 說明(菜鳥請進,大神繞道 ~) 前端...
摘要:前端每周清單第期微服務實踐,與,組件技巧,攻防作者王下邀月熊編輯徐川前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。 前端每周清單第 26 期:Node.js 微服務實踐,Vue.js 與 GraphQL,Angular 組件技巧,HeadlessChrome 攻防 作者:王下邀月熊 編輯:徐川...
閱讀 3061·2021-10-27 14:16
閱讀 2879·2021-09-24 10:33
閱讀 2285·2021-09-23 11:21
閱讀 3229·2021-09-22 15:14
閱讀 812·2019-08-30 15:55
閱讀 1676·2019-08-30 15:53
閱讀 1742·2019-08-29 11:14
閱讀 2190·2019-08-28 18:11