w-flow-vue 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/w-flow-vue.umd.js +3 -3
- package/dist/w-flow-vue.umd.js.map +1 -1
- package/docs/components_WFlowVue.vue.html +61 -6
- package/docs/components_ui_Controls.vue.html +1 -1
- package/docs/examples/app.html +1 -1
- package/docs/examples/app.umd.js +4 -4
- package/docs/examples/app.umd.js.map +1 -1
- package/docs/examples/ex-AppBasic.html +1 -1
- package/docs/examples/ex-AppConnectivity.html +1 -1
- package/docs/global.html +1 -1
- package/docs/index.html +1 -1
- package/docs/js_defaults.mjs.html +1 -1
- package/docs/js_edgePath.mjs.html +1 -1
- package/docs/js_fixSvgNs.mjs.html +1 -1
- package/docs/js_geometry.mjs.html +1 -1
- package/docs/js_graph.mjs.html +1 -1
- package/docs/js_stepRouting.mjs.html +1 -1
- package/docs/module-WFlowVue.html +1 -1
- package/package.json +1 -1
- package/src/components/WFlowVue.vue +60 -5
- package/src/components/nodes/NodeRenderer.vue +1 -0
- package/src/components/nodes/NodeWrapper.vue +81 -19
- package/test/pics/flow-E2E-011-node-settings-form.png +0 -0
- package/test/pics/flow-E2E-012-popup-exclusive.png +0 -0
- package/test/unit-WFlowVue-features.test.mjs +10 -8
- package/test/unit-WFlowVue.test.mjs +432 -421
- package/test/unit-components-canvas.test.mjs +104 -102
- package/test/unit-components-edge.test.mjs +157 -147
- package/test/unit-components-node.test.mjs +27 -5
- package/test/unit-geometry.test.mjs +248 -236
- package/test/unit-graph.test.mjs +72 -72
- package/test/unit-node-drag-gesture.test.mjs +254 -0
|
@@ -121,6 +121,7 @@
|
|
|
121
121
|
:snap-grid-size="snapToGrid ? snapGridSize : null"
|
|
122
122
|
:settings-enabled="nodesSettingsEnabled"
|
|
123
123
|
:settings-excludes="nodesSettingsExcludes"
|
|
124
|
+
@drag-prepare="onNodeDragPrepare"
|
|
124
125
|
@drag-start="onNodeDragStart"
|
|
125
126
|
@node-click="onNodeClick"
|
|
126
127
|
@node-double-click="onNodeDoubleClick"
|
|
@@ -424,6 +425,7 @@ export default {
|
|
|
424
425
|
document.addEventListener('keyup', this.onKeyUp)
|
|
425
426
|
document.addEventListener('mousemove', this.onDocMouseMove)
|
|
426
427
|
document.addEventListener('mouseup', this.onDocMouseUp)
|
|
428
|
+
window.addEventListener('blur', this.onWindowBlur)
|
|
427
429
|
},
|
|
428
430
|
beforeDestroy() {
|
|
429
431
|
if (this._panAnimId) {
|
|
@@ -434,6 +436,7 @@ export default {
|
|
|
434
436
|
document.removeEventListener('keyup', this.onKeyUp)
|
|
435
437
|
document.removeEventListener('mousemove', this.onDocMouseMove)
|
|
436
438
|
document.removeEventListener('mouseup', this.onDocMouseUp)
|
|
439
|
+
window.removeEventListener('blur', this.onWindowBlur)
|
|
437
440
|
},
|
|
438
441
|
computed: {
|
|
439
442
|
widthInp() {
|
|
@@ -813,6 +816,8 @@ export default {
|
|
|
813
816
|
},
|
|
814
817
|
onCanvasWheel(event) {
|
|
815
818
|
if (!this.zoomOnScroll) return
|
|
819
|
+
//滾輪縮放亦為viewport寫入者, 先取消程式動畫避免二者互相覆寫
|
|
820
|
+
this.cancelViewportAnimation()
|
|
816
821
|
const delta = -event.deltaY * 0.001
|
|
817
822
|
const currentZoom = this.viewport.zoom
|
|
818
823
|
// fitView may set zoom below zoomMin; use the current level as the
|
|
@@ -836,6 +841,14 @@ export default {
|
|
|
836
841
|
|
|
837
842
|
// --- Document-level mouse ---
|
|
838
843
|
onDocMouseMove(event) {
|
|
844
|
+
//按鍵已放開卻仍處於進行中狀態: 代表收尾事件未送達(於瀏覽器視窗外放開/視窗失焦/手勢被原生拖曳接管),
|
|
845
|
+
//此時須主動走既有收尾路徑清除狀態; 只return不清狀態無效, 旗標續留為真下次移動仍會誤判
|
|
846
|
+
if ((event.buttons & 1) === 0) {
|
|
847
|
+
if (this.isPanning || this.isDraggingNode || this.isConnecting || this.isSelecting) {
|
|
848
|
+
this.onDocMouseUp(event)
|
|
849
|
+
}
|
|
850
|
+
return
|
|
851
|
+
}
|
|
839
852
|
if (this.isPanning) {
|
|
840
853
|
this.doPan(event)
|
|
841
854
|
}
|
|
@@ -849,6 +862,19 @@ export default {
|
|
|
849
862
|
this.doSelection(event)
|
|
850
863
|
}
|
|
851
864
|
},
|
|
865
|
+
onWindowBlur(event) {
|
|
866
|
+
//視窗失焦後不會再收到mouseup與keyup, 於此統一收尾避免狀態黏住
|
|
867
|
+
if (this.isPanning) {
|
|
868
|
+
this.endPan()
|
|
869
|
+
}
|
|
870
|
+
//節點拖曳同樣須收尾: 否則isDraggingNode殘留為true, 回到視窗後在觸發mousemove守衛前
|
|
871
|
+
//點擊其他節點, 該次node-click會被onNodeClick之拖曳守衛以過期狀態誤擋
|
|
872
|
+
//event為blur事件(非MouseEvent), endDrag不讀取座標僅原樣轉交node-drag-stop, 故不偽造mouseup
|
|
873
|
+
if (this.isDraggingNode) {
|
|
874
|
+
this.endDrag(event)
|
|
875
|
+
}
|
|
876
|
+
this.keysPressed = {}
|
|
877
|
+
},
|
|
852
878
|
onDocMouseUp(event) {
|
|
853
879
|
if (this.isPanning) {
|
|
854
880
|
this.endPan()
|
|
@@ -866,6 +892,8 @@ export default {
|
|
|
866
892
|
|
|
867
893
|
// --- Pan ---
|
|
868
894
|
startPan(event) {
|
|
895
|
+
//手動平移優先於程式動畫, 否則二者同時寫viewport而互相覆寫
|
|
896
|
+
this.cancelViewportAnimation()
|
|
869
897
|
this.isPanning = true
|
|
870
898
|
this.panStartPos = { x: event.clientX, y: event.clientY }
|
|
871
899
|
},
|
|
@@ -893,16 +921,20 @@ export default {
|
|
|
893
921
|
},
|
|
894
922
|
|
|
895
923
|
// --- Node drag ---
|
|
896
|
-
onNodeDragStart
|
|
924
|
+
//於節點mousedown當下先行選取(拖曳本身延後至跨越位移門檻才由onNodeDragStart啟動)。
|
|
925
|
+
//守衛與選取條件皆與修正前之onNodeDragStart一致, 故選取時機不因拖曳延後而改變。
|
|
926
|
+
onNodeDragPrepare({ node }) {
|
|
897
927
|
if (this.locked || !this.nodesDraggable) return
|
|
898
|
-
this.isDraggingNode = true
|
|
899
|
-
this.draggingNodeId = node.id
|
|
900
|
-
this.dragStartPos = { x: event.clientX, y: event.clientY }
|
|
901
|
-
|
|
902
928
|
if (this.selectNodesOnDrag && !this.isMultiSelectPressed) {
|
|
903
929
|
this.setSelectedNodes([node.id])
|
|
904
930
|
this.setSelectedConns([])
|
|
905
931
|
}
|
|
932
|
+
},
|
|
933
|
+
onNodeDragStart({ node, event, moveEvent }) {
|
|
934
|
+
if (this.locked || !this.nodesDraggable) return
|
|
935
|
+
this.isDraggingNode = true
|
|
936
|
+
this.draggingNodeId = node.id
|
|
937
|
+
this.dragStartPos = { x: event.clientX, y: event.clientY }
|
|
906
938
|
|
|
907
939
|
// Cache start positions for drag
|
|
908
940
|
const starts = {}
|
|
@@ -925,6 +957,12 @@ export default {
|
|
|
925
957
|
}
|
|
926
958
|
|
|
927
959
|
this.$emit('node-drag-start', { node, event })
|
|
960
|
+
|
|
961
|
+
//立即套用跨門檻的這一次mousemove: document層之onDocMouseMove於本輪事件已先看過
|
|
962
|
+
//(當時isDraggingNode仍為false而返回), 不補這一次則跨門檻後立刻放開將完全沒有位移
|
|
963
|
+
if (moveEvent && this.isDraggingNode) {
|
|
964
|
+
this.doDrag(moveEvent)
|
|
965
|
+
}
|
|
928
966
|
},
|
|
929
967
|
doDrag(event) {
|
|
930
968
|
const zoom = this.viewport.zoom
|
|
@@ -1061,6 +1099,10 @@ export default {
|
|
|
1061
1099
|
|
|
1062
1100
|
// --- Selection ---
|
|
1063
1101
|
onNodeClick({ node, event }) {
|
|
1102
|
+
//本次手勢已被接受為拖曳者不再視為點擊: NodeWrapper之@mouseup綁在節點元素上,
|
|
1103
|
+
//必先於document層之onDocMouseUp→endDrag觸發, 故此刻isDraggingNode仍為true即代表拖曳成立。
|
|
1104
|
+
//(涵蓋「跨門檻拖出後又移回原點放開」之情形——該情形最終位移為0, 僅靠距離判準無法辨識)
|
|
1105
|
+
if (this.isDraggingNode) return
|
|
1064
1106
|
if (!this.elementsSelectable) return
|
|
1065
1107
|
if (this.isMultiSelectPressed) {
|
|
1066
1108
|
const idx = this.selectedNodes.indexOf(node.id)
|
|
@@ -1299,6 +1341,19 @@ export default {
|
|
|
1299
1341
|
emitViewportChange() {
|
|
1300
1342
|
this.$emit('viewport-change', { ...this.viewport })
|
|
1301
1343
|
},
|
|
1344
|
+
getViewport() {
|
|
1345
|
+
//即時視口: viewport-change僅於手勢結束才發出, 平移途中呼叫端需要當下值時走此方法
|
|
1346
|
+
//(呼叫端若以viewport-change快取之值為基準回寫setViewport, 會於平移途中以過期值覆寫使用者正在進行的平移)
|
|
1347
|
+
let vp = this.viewport
|
|
1348
|
+
return { x: vp.x, y: vp.y, zoom: vp.zoom }
|
|
1349
|
+
},
|
|
1350
|
+
cancelViewportAnimation() {
|
|
1351
|
+
//取消進行中之視口動畫(panToNode), 否則動畫與手動手勢會同時寫入同一個viewport
|
|
1352
|
+
if (this._panAnimId) {
|
|
1353
|
+
cancelAnimationFrame(this._panAnimId)
|
|
1354
|
+
this._panAnimId = null
|
|
1355
|
+
}
|
|
1356
|
+
},
|
|
1302
1357
|
emitSelectionChange() {
|
|
1303
1358
|
this.$emit('selection-change', this.getSelectedElements())
|
|
1304
1359
|
},
|
|
@@ -1449,7 +1504,7 @@ export default {
|
|
|
1449
1504
|
<br class="clear">
|
|
1450
1505
|
|
|
1451
1506
|
<footer>
|
|
1452
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
1507
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Aug 23 2026 15:03:25 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1453
1508
|
</footer>
|
|
1454
1509
|
|
|
1455
1510
|
<script>prettyPrint();</script>
|
|
@@ -265,7 +265,7 @@ export default {
|
|
|
265
265
|
<br class="clear">
|
|
266
266
|
|
|
267
267
|
<footer>
|
|
268
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
268
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Aug 23 2026 15:03:25 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
269
269
|
</footer>
|
|
270
270
|
|
|
271
271
|
<script>prettyPrint();</script>
|
package/docs/examples/app.html
CHANGED