開發組在開發過程當中,都不可避免地遇到了一些困難或問題,但都最終想出辦法克服了。咱們認爲這樣的經驗是有必要記錄下來的,所以就有了【技術博客】。javascript
這篇技術博客基於軟件工程課程的VisualPytorch之上,代碼在必定程度上參考了http://www.javashuo.com/article/p-ntwdyfrg-du.html這篇博客。css
VisualPytorch項目連接以下:VisualPytorchhtml
對於這樣一個類流程圖或者模型圖,用戶會有保存、查看以及再編輯的需求,僅僅提供讓用戶拖拽連線的功能、讓用戶每次都從頭搭建是會嚴重影響用戶體驗的,所以須要可以保存模型圖。java
這篇博客主要用於提供思路,而非提供整套的解決方案,具體解決方案因人而異。node
保存流程圖是兩方面的問題:jquery
(1)選定合適的保存格式git
(2)確保保存的信息足夠來還原完整的圖github
在保存時,我採用的是將整個圖分爲兩個數組保存入數據庫中。圖主要由模塊(開始、reshape層)和連線兩部分組成,所以我選擇將模塊保存爲一個json,而連線保存爲數組。數據庫
$("#canvas").find(".node").each(function (index, element) { var id = $(element).attr('id'); nets[id] = { "name": $(element).attr('name'), "attribute": eval('(' + window.localStorage.getItem(id) + ')'), "left": $(element).css('left'), "top": $(element).css('top') } });
在畫布中遍歷全部的模塊類,nets對象的標籤爲模塊的id,而內容爲須要保存的屬性。須要注意的是,left與top屬性必須保存,其至關於x,y座標,用於還原時定位div的位置。json
for (var i = 0; i < conn_list.length; i++) { var source_id = conn_list[i]["sourceId"]; var target_id = conn_list[i]["targetId"]; var conn = { "source": { "id": source_id, "anchor_position": conn_list[i]["endpoints"][0]["anchor"]["type"] }, "target": { "id": target_id, "anchor_position": conn_list[i]["endpoints"][1]["anchor"]["type"] } }; nets_conn.push(conn); }
連線保存須要注意兩個地方,首先是conn_list的得到,即如何獲得目前的全部連線,這裏我調用了JsPlumb中現有的接口
conn_list = jsPlumb.getAllConnections()
另外一個地方時anchor_position。這裏涉及到了JsPlumb的部分,在連線的時候,只有有anchor的地方纔能夠連線,爲了復原整個圖,咱們須要記錄下anchor的位置。
如何將保存的數據從數據庫中取出不該該是本博客的內容,很少贅述。先貼上完整代碼
var structure = eval('(' + net_work["structure"] + ')'); var nets = structure['nets']; var nets_conn = structure['nets_conn']; var static_val = structure['static']; var drop_function = $("#canvas").droppable('option', 'drop'); var event; jQuery.each(nets, function (id, val) { jsPlumb.ready(function () { var ui = { 'offset': { 'left': parseInt(val['left'].split('px')) + $("#canvas").offset().left, 'top': parseInt(val['top'].split('px')) + $("#canvas").offset().top }, 'draggable': [{ "id": val['name'], "innerHTML": $("#" + val['name'])[0].innerHTML }], 'id': id }; drop_function(event, ui); }); window.localStorage.setItem(id, JSON.stringify(val['attribute'])); }); jQuery.each(nets_conn, function (id, val) { jsPlumb.ready(function () { jsPlumb.connect({ "source": val['source']['id'], "target": val['target']['id'], "anchors": [val['source']['anchor_position'], val['target']['anchor_position']], "endpoint": ["Dot", {radius: 5}], "paintStyle": { stroke: "#fc2f49", strokeWidth: 3, }, "maxConnections": -1, "connector": ["Flowchart", { stub: [40, 60], gap: 5, cornerRadius: 5, alwaysRespectStubs: true }], "overlays": [["Arrow", {width: 10, length: 10, location: 1}]], "connectionsDetachable": true, }) }); });
代碼看着不少,原理很是簡單,就是把用戶畫圖的操做再用js腳本作一遍。
首先第一點,用戶在拖拽div進入畫布時,畫布爲droppable狀態,會觸發JQuery-UI 的drop事件。
$("#canvas").droppable({ scope: "ss", drop: function (event, ui) { ....... } })
第一段代碼中的
var drop_function = $("#canvas").droppable('option', 'drop')
drop_function函數就對應了drop事件觸發後執行的代碼塊。
如此一來便很容易理解,只要讓每一個被保存的模塊去觸發drop事件便可,參數ui用保存的屬性來本身構造,詳情參照代碼。
從新連線部分,直接調用JsPlumb的連線方法
jsPlumb.connect()
便可。
注意咱們的anchor要選擇以前保存的anchor。