項目背景 最近在準備開發工作流引擎相關模塊,完成表結構設計後開始著手流程設計器的技術選型,調研了眾多開源項目後決定基於jsplumb.js開源庫進行自研開發,保證定製化的便捷性,相關效果圖及項目地址如下 項目地址:https://gitee.com/code2roc/fast-flow-desgio ...
項目背景
最近在準備開發工作流引擎相關模塊,完成表結構設計後開始著手流程設計器的技術選型,調研了眾多開源項目後決定基於jsplumb.js開源庫進行自研開發,保證定製化的便捷性,相關效果圖及項目地址如下
項目地址:https://gitee.com/code2roc/fast-flow-desgion
需求概述
流程設計器中最基礎的兩個元素為活動(節點)和變遷(連接),我們需要以下基礎功能來配合相關介面進行工作流相關設計數據的保存/修改
- 活動的添加/刪除/移動
- 變遷的添加/刪除
- 活動/變遷數據的全部讀取
- 根據json渲染活動與變遷
相關引入依賴如下表所示
名稱 | 功能 |
---|---|
jsplumb.js | 設計器主要依賴,用於繪製相關圖形與動態操作實現 |
jquery.js | jsplumb依賴的庫 |
jquery-ui.js | jsplumb依賴的庫,進行拖拽綁定 |
contextMenu.js | 實現右擊菜單 |
mustache.js | 模板引擎渲染活動,避免字元串拼接 |
實現思路
活動添加
通過mustache的render方法渲染添加到html後,需要調用draggable方法讓活動能夠進行自由拖動,其中grid參數作用是固定每次拖拽移動最小距離,便於不同節點經過移動後對齊
<script type="text/x-mustache" id="jnode-template">
<div class="jnode-panel" id="{{id}}" jnode="{{jnode}}" style="top:{{top}}px;left:{{left}}px">
<div class="jnode-box {{jnodeClass}}">{{{jnodeHtml}}}</div>
</div>
</script>
jsPlumb.draggable(id, {
containment: 'parent',
grid: [8, 8]
})
活動刪除
通過jsPlumb.remove方法刪除,會刪除相關活動與連接的變遷,參數是活動id,通過右鍵菜單的點擊事件獲取屬性
callback: function(itemKey, opt, rootMenu, originalEvent) {
var id = $($(opt.$trigger[0]).parent()).attr("id");
jsPlumb.remove(id)
}
活動移動
在活動拖動的過程中位置進行變化,我們需要進行事件監聽獲取實時位置保存到資料庫,通過jsPlumb.draggable方法的stop方法註冊實現
jsPlumb.draggable(id, {
containment: 'parent',
grid: [8, 8],
stop: function(event, ui) {
var nodeID = $(ui.helper.context).attr("id");
moveActivity(nodeID, ui.position.left, ui.position.top);
}
});
變遷添加
jsplumb節點可以添加相關錨點,連接不同錨點會自動繪製連線,在實際操作時連線要求錨點對準操作精度較高不便捷,所以我們通過設置節點整體對象為連接對象,可實現滑鼠放置在活動div範圍內進行拖拽連線,需要註意makeSource和makeTarget需要同時執行,節點才能作為起點與終點
function registAutoConnect(id) {
jsPlumb.makeSource(id, {
endpoint: "Dot",
anchor: "Continuous"
})
jsPlumb.makeTarget(id, {
endpoint: "Dot",
anchor: "Continuous"
})
}
以上方法是手動在流程設計器中進行操作連接,如果我們通過介面獲取已有數據,需要通過connect方法進行代碼渲染變遷
需要註意jsplumb中connection的id為自動生成,我們需要通過setAttribute方法對canvas進行id賦值操作,才能綁定我要自己的id數據
function addConnect(id, sourceID, targetID) {
var connection = jsPlumb.connect(
{
source: sourceID,
target: targetID
});
connection.id = id
jsPlumb.setAttribute(connection.canvas, "id", connection.id)
}
通過監聽connection事件我們可以知道連接添加完成,進行相關介面調用,但我們需要區分是我們通過設計器操作還是代碼渲染,只要判斷originalEvent是否存在,存在則是通過滑鼠操作的
jsPlumb.bind("connection", function(connInfo, originalEvent) {
if (originalEvent) {
}
});
變遷刪除
通過jsPlumb.detach方法進行變遷的刪除,預設只刪除變遷不刪除連接的活動
function deleteConnect(id) {
var connects = jsPlumb.getAllConnections();
for (var i = 0; i < connects.length; i++) {
var connect = connects[i];
if (connect.id == id) {
jsPlumb.detach(connect)
}
}
}
其它
代碼還包含很多其他細節,如下所示,就不詳細贅述了,大家可以仔細閱讀,項目中包含了詳細的註釋
- 連接添加控制,例如開始節點不能為連接終點,結束節點不能為起點
- 導入預設配置控制連線樣式
- 各種操作模式指針變換及交互模式
- 流程圖整體移動
- 活動/變遷的選中效果及點擊空白處取消