w-flow-vue 1.0.0
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/.editorconfig +9 -0
- package/.eslintignore +3 -0
- package/.eslintrc.js +55 -0
- package/.jsdoc +25 -0
- package/AGENT.md +223 -0
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/SECURITY.md +5 -0
- package/babel.config.js +16 -0
- package/dist/w-flow-vue.umd.js +15 -0
- package/dist/w-flow-vue.umd.js.map +1 -0
- package/docs/components_WFlowVue.vue.html +1214 -0
- package/docs/examples/app.html +62 -0
- package/docs/examples/app.umd.js +20 -0
- package/docs/examples/app.umd.js.map +1 -0
- package/docs/examples/ex-AppBasic.html +440 -0
- package/docs/examples/ex-AppConnectivity.html +131 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/global.html +1919 -0
- package/docs/index.html +84 -0
- package/docs/js_defaults.mjs.html +105 -0
- package/docs/js_edge-path.mjs.html +237 -0
- package/docs/js_geometry.mjs.html +298 -0
- package/docs/js_graph.mjs.html +103 -0
- package/docs/js_step-routing.mjs.html +346 -0
- package/docs/module-WFlowVue.html +2790 -0
- package/docs/scripts/collapse.js +39 -0
- package/docs/scripts/commonNav.js +28 -0
- package/docs/scripts/linenumber.js +25 -0
- package/docs/scripts/nav.js +12 -0
- package/docs/scripts/polyfill.js +4 -0
- package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/scripts/prettify/lang-css.js +2 -0
- package/docs/scripts/prettify/prettify.js +28 -0
- package/docs/scripts/search.js +99 -0
- package/docs/styles/jsdoc.css +776 -0
- package/docs/styles/prettify.css +80 -0
- package/jest.config.js +20 -0
- package/package.json +80 -0
- package/public/index.html +38 -0
- package/script.txt +22 -0
- package/src/App.vue +326 -0
- package/src/AppBasic.vue +125 -0
- package/src/AppConnectivity.vue +186 -0
- package/src/components/WFlowVue.vue +1142 -0
- package/src/components/canvas/BackgroundLayer.vue +78 -0
- package/src/components/canvas/FlowCanvas.vue +64 -0
- package/src/components/canvas/SelectionBox.vue +36 -0
- package/src/components/canvas/ViewportTransform.vue +35 -0
- package/src/components/edges/ConnectionLine.vue +65 -0
- package/src/components/edges/EdgeMarkerDefs.vue +76 -0
- package/src/components/edges/EdgeRenderer.vue +120 -0
- package/src/components/edges/EdgeWrapper.vue +379 -0
- package/src/components/nodes/DefaultNode.vue +276 -0
- package/src/components/nodes/Handle.vue +101 -0
- package/src/components/nodes/InputNode.vue +47 -0
- package/src/components/nodes/NodeBody.vue +103 -0
- package/src/components/nodes/NodeFace.vue +128 -0
- package/src/components/nodes/NodeRenderer.vue +95 -0
- package/src/components/nodes/NodeWrapper.vue +475 -0
- package/src/components/nodes/OutputNode.vue +47 -0
- package/src/components/ui/ConnSettingsForm.vue +158 -0
- package/src/components/ui/Controls.vue +83 -0
- package/src/components/ui/NodeSettingsForm.vue +185 -0
- package/src/js/defaults.mjs +33 -0
- package/src/js/edge-path.mjs +165 -0
- package/src/js/geometry.mjs +226 -0
- package/src/js/graph.mjs +31 -0
- package/src/js/step-routing.mjs +274 -0
- package/src/main.js +22 -0
- package/test/WFlowVue-features.test.mjs +760 -0
- package/test/WFlowVue.test.mjs +421 -0
- package/test/components-canvas.test.mjs +102 -0
- package/test/components-edge.test.mjs +147 -0
- package/test/components-node.test.mjs +174 -0
- package/test/components-ui.test.mjs +69 -0
- package/test/defaults.test.mjs +86 -0
- package/test/edge-path.test.mjs +102 -0
- package/test/generate-routing-snapshots.mjs +77 -0
- package/test/generate-visual-baselines.mjs +206 -0
- package/test/geometry.test.mjs +236 -0
- package/test/graph.test.mjs +72 -0
- package/test/jsons/routing-snapshots.json +24994 -0
- package/test/pics/_check2.png +0 -0
- package/test/pics/_check3.png +0 -0
- package/test/pics/_check4.png +0 -0
- package/test/pics/_check5.png +0 -0
- package/test/pics/_v1.png +0 -0
- package/test/pics/_v2.png +0 -0
- package/test/pics/_v3.png +0 -0
- package/test/pics/_v4.png +0 -0
- package/test/pics/_v5.png +0 -0
- package/test/pics/_v6.png +0 -0
- package/test/pics/_v7.png +0 -0
- package/test/pics/vb-edge-hovered.png +0 -0
- package/test/pics/vb-edges-normal.png +0 -0
- package/test/pics/vb-locked-edge-hovered.png +0 -0
- package/test/pics/vb-locked-node-hovered.png +0 -0
- package/test/pics/vb-locked-node-selected.png +0 -0
- package/test/pics/vb-locked-overview.png +0 -0
- package/test/pics/vb-node-1.png +0 -0
- package/test/pics/vb-node-10.png +0 -0
- package/test/pics/vb-node-11.png +0 -0
- package/test/pics/vb-node-12.png +0 -0
- package/test/pics/vb-node-2.png +0 -0
- package/test/pics/vb-node-3.png +0 -0
- package/test/pics/vb-node-4.png +0 -0
- package/test/pics/vb-node-5.png +0 -0
- package/test/pics/vb-node-6.png +0 -0
- package/test/pics/vb-node-7.png +0 -0
- package/test/pics/vb-node-8.png +0 -0
- package/test/pics/vb-node-9.png +0 -0
- package/test/pics/vb-node-hovered.png +0 -0
- package/test/pics/vb-node-selected.png +0 -0
- package/test/pics/vb-overview.png +0 -0
- package/test/step-routing-connectivity.test.mjs +78 -0
- package/test/step-routing.test.mjs +88 -0
- package/test/visual-regression.test.mjs +274 -0
- package/toolg/addVersion.mjs +4 -0
- package/toolg/cleanFolder.mjs +4 -0
- package/toolg/gDistApp.mjs +34 -0
- package/toolg/gDistRollupComps.mjs +22 -0
- package/toolg/gDocExams.mjs +47 -0
- package/toolg/gExtractHtml.mjs +179 -0
- package/toolg/modifyReadme.mjs +4 -0
- package/vue.config.js +9 -0
- package/vue2/344/271/213foreignObject/345/205/247/346/270/262/346/237/223/345/225/217/351/241/214/350/210/207/344/277/256/346/255/243.md +151 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>js/step-routing.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-WFlowVue.html">WFlowVue</a></li></ul><h3>Global</h3><ul><li><a href="global.html#NODE_DEFAULTS">NODE_DEFAULTS</a></li><li><a href="global.html#clampPosition">clampPosition</a></li><li><a href="global.html#generateId">generateId</a></li><li><a href="global.html#getBezierPath">getBezierPath</a></li><li><a href="global.html#getControlOffset">getControlOffset</a></li><li><a href="global.html#getDiamondEdgePoint">getDiamondEdgePoint</a></li><li><a href="global.html#getEllipseEdgePoint">getEllipseEdgePoint</a></li><li><a href="global.html#getHandlePosition">getHandlePosition</a></li><li><a href="global.html#getOverlappingNodes">getOverlappingNodes</a></li><li><a href="global.html#getSmoothStepPath">getSmoothStepPath</a></li><li><a href="global.html#getStepPath">getStepPath</a></li><li><a href="global.html#getStraightPath">getStraightPath</a></li><li><a href="global.html#getTriangleEdgePoint">getTriangleEdgePoint</a></li><li><a href="global.html#isValidConnection">isValidConnection</a></li><li><a href="global.html#labelAtHalfLength">labelAtHalfLength</a></li><li><a href="global.html#lookupRoute">lookupRoute</a></li><li><a href="global.html#rectsOverlap">rectsOverlap</a></li><li><a href="global.html#segmentFallback">segmentFallback</a></li><li><a href="global.html#snapPosition">snapPosition</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">js/step-routing.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>// --- Step path routing using draw.io OrthConnector algorithm ---
|
|
49
|
+
|
|
50
|
+
let _cache = new Map()
|
|
51
|
+
let _cacheFrame = -1
|
|
52
|
+
|
|
53
|
+
export function clearStepCache() {
|
|
54
|
+
_cache.clear()
|
|
55
|
+
_cacheFrame = -1
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function calculateStepPoints(
|
|
59
|
+
sourceX, sourceY, sourcePosition,
|
|
60
|
+
targetX, targetY, targetPosition,
|
|
61
|
+
offset, allNodes, nodeInternals, connFromId, connToId
|
|
62
|
+
) {
|
|
63
|
+
// --- Per-frame cache ---
|
|
64
|
+
let frame = Math.floor(Date.now() / 16)
|
|
65
|
+
if (frame !== _cacheFrame) {
|
|
66
|
+
_cache.clear(); _cacheFrame = frame
|
|
67
|
+
}
|
|
68
|
+
let ck = Math.round(sourceX / 10) + ',' + Math.round(sourceY / 10) + ',' +
|
|
69
|
+
Math.round(targetX / 10) + ',' + Math.round(targetY / 10) + ',' +
|
|
70
|
+
sourcePosition + ',' + targetPosition
|
|
71
|
+
let cached = _cache.get(ck)
|
|
72
|
+
if (cached) return cached
|
|
73
|
+
|
|
74
|
+
// Collect obstacles (bbox for all visible nodes)
|
|
75
|
+
let obs = []
|
|
76
|
+
if (allNodes && allNodes.length > 0) {
|
|
77
|
+
let ni = nodeInternals || {}
|
|
78
|
+
for (let i = 0; i < allNodes.length; i++) {
|
|
79
|
+
let n = allNodes[i]
|
|
80
|
+
if (n.hidden) continue
|
|
81
|
+
let w = (ni[n.id] && ni[n.id].width) || n.width || 100
|
|
82
|
+
let h = (ni[n.id] && ni[n.id].height) || n.height || 40
|
|
83
|
+
obs.push({ l: n.position.x, t: n.position.y, r: n.position.x + w, b: n.position.y + h })
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let sObs = findObstacleAt(obs, sourceX, sourceY)
|
|
88
|
+
let tObs = findObstacleAt(obs, targetX, targetY)
|
|
89
|
+
let hOff = offset || 24
|
|
90
|
+
|
|
91
|
+
let result = lookupRoute(sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition, sObs, tObs, hOff)
|
|
92
|
+
if (!result) {
|
|
93
|
+
result = segmentFallback(sourceX, sourceY, targetX, targetY, sObs, tObs)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (_cache.size > 200) _cache.clear()
|
|
97
|
+
_cache.set(ck, result)
|
|
98
|
+
return result
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ==================== Helpers ====================
|
|
102
|
+
|
|
103
|
+
function findObstacleAt(obs, hx, hy) {
|
|
104
|
+
for (let i = 0; i < obs.length; i++) {
|
|
105
|
+
let o = obs[i]
|
|
106
|
+
if (hx >= o.l - 5 && hx <= o.r + 5 && hy >= o.t - 5 && hy <= o.b + 5) return o
|
|
107
|
+
}
|
|
108
|
+
return null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// === draw.io OrthConnector algorithm (adapted from mxEdgeStyle.js) ===
|
|
112
|
+
// Route patterns encode movement steps as bit-packed integers.
|
|
113
|
+
// Each step: direction(0-3) | side_mask(5-8) | center(9) | source(10) | target(11)
|
|
114
|
+
// The quad rotation normalizes geometry so a 4×4 table covers all 16 direction combos.
|
|
115
|
+
// Constants match draw.io: WEST=1, NORTH=2, SOUTH=4, EAST=8
|
|
116
|
+
|
|
117
|
+
let _W = 1; let _N = 2; let _S = 4; let _E = 8
|
|
118
|
+
let _SIDE = 480; let _CTR = 512; let _SRC = 1024; let _TGT = 2048
|
|
119
|
+
let _dirV = [[-1, 0], [0, -1], [1, 0], [0, 1], [-1, 0], [0, -1], [1, 0]]
|
|
120
|
+
|
|
121
|
+
let _rp = [
|
|
122
|
+
[[513, 2308, 2081, 2562], [513, 1090, 514, 2184, 2114, 2561], [513, 1090, 514, 2564, 2184, 2562], [513, 2308, 2561, 1090, 514, 2568, 2308]],
|
|
123
|
+
[[514, 1057, 513, 2308, 2081, 2562], [514, 2184, 2114, 2561], [514, 2184, 2562, 1057, 513, 2564, 2184], [514, 1057, 513, 2568, 2308, 2561]],
|
|
124
|
+
[[1090, 514, 1057, 513, 2308, 2081, 2562], [2114, 2561], [1090, 2562, 1057, 513, 2564, 2184], [1090, 514, 1057, 513, 2308, 2561, 2568]],
|
|
125
|
+
[[2081, 2562], [1057, 513, 1090, 514, 2184, 2114, 2561], [1057, 513, 1090, 514, 2184, 2562, 2564], [1057, 2561, 1090, 514, 2568, 2308]]
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
function posToDirMask(pos) {
|
|
129
|
+
switch (pos) {
|
|
130
|
+
case 'left': return _W
|
|
131
|
+
case 'top': return _N
|
|
132
|
+
case 'right': return _E
|
|
133
|
+
case 'bottom': return _S
|
|
134
|
+
default: return _S
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* draw.io OrthConnector route generation.
|
|
140
|
+
* Uses bit-encoded route patterns + quad rotation + limits clamping.
|
|
141
|
+
* Returns waypoint array or null (fallback needed).
|
|
142
|
+
*/
|
|
143
|
+
function lookupRoute(sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition, sObs, tObs, buf) {
|
|
144
|
+
if (!sObs || !tObs) return null
|
|
145
|
+
|
|
146
|
+
let sDir = posToDirMask(sourcePosition)
|
|
147
|
+
let tDir = posToDirMask(targetPosition)
|
|
148
|
+
|
|
149
|
+
// Node geometry [x, y, width, height]
|
|
150
|
+
let geo = [
|
|
151
|
+
[sObs.l, sObs.t, sObs.r - sObs.l, sObs.b - sObs.t],
|
|
152
|
+
[tObs.l, tObs.t, tObs.r - tObs.l, tObs.b - tObs.t]
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
// Too-close check: distance < 2*buf → fallback
|
|
156
|
+
let ddx = sourceX - targetX; let ddy = sourceY - targetY
|
|
157
|
+
let totalBuf = buf * 2
|
|
158
|
+
if (ddx * ddx + ddy * ddy < totalBuf * totalBuf) return null
|
|
159
|
+
|
|
160
|
+
// Limits: expanded bbox per node (prevents lines crossing nodes)
|
|
161
|
+
// draw.io hardcoded indices: [1]=left, [2]=top, [4]=right, [8]=bottom
|
|
162
|
+
let lim = [[], []]
|
|
163
|
+
for (let i = 0; i < 2; i++) {
|
|
164
|
+
lim[i][1] = geo[i][0] - buf
|
|
165
|
+
lim[i][2] = geo[i][1] - buf
|
|
166
|
+
lim[i][4] = geo[i][0] + geo[i][2] + buf
|
|
167
|
+
lim[i][8] = geo[i][1] + geo[i][3] + buf
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Constraint: handle position relative to node (0–1)
|
|
171
|
+
let con = [[0.5, 0.5], [0.5, 0.5]]
|
|
172
|
+
let gw0 = geo[0][2] || 1; let gh0 = geo[0][3] || 1
|
|
173
|
+
let gw1 = geo[1][2] || 1; let gh1 = geo[1][3] || 1
|
|
174
|
+
con[0][0] = (sourceX - geo[0][0]) / gw0
|
|
175
|
+
con[0][1] = (sourceY - geo[0][1]) / gh0
|
|
176
|
+
con[1][0] = (targetX - geo[1][0]) / gw1
|
|
177
|
+
con[1][1] = (targetY - geo[1][1]) / gh1
|
|
178
|
+
|
|
179
|
+
// Quad: which quadrant is target center relative to source center
|
|
180
|
+
// 0 | 1
|
|
181
|
+
// -----
|
|
182
|
+
// 3 | 2
|
|
183
|
+
let sCx = geo[0][0] + geo[0][2] / 2; let sCy = geo[0][1] + geo[0][3] / 2
|
|
184
|
+
let tCx = geo[1][0] + geo[1][2] / 2; let tCy = geo[1][1] + geo[1][3] / 2
|
|
185
|
+
let qx = sCx - tCx; let qy = sCy - tCy
|
|
186
|
+
let quad = 0
|
|
187
|
+
if (qx < 0) {
|
|
188
|
+
quad = qy < 0 ? 2 : 1
|
|
189
|
+
}
|
|
190
|
+
else if (qy <= 0) {
|
|
191
|
+
quad = qx === 0 ? 2 : 3
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Vertex separations (gap between nodes minus buffer, min 0)
|
|
195
|
+
let vs = []
|
|
196
|
+
vs[1] = Math.max(geo[0][0] - (geo[1][0] + geo[1][2]) - totalBuf, 0)
|
|
197
|
+
vs[2] = Math.max(geo[0][1] - (geo[1][1] + geo[1][3]) - totalBuf, 0)
|
|
198
|
+
vs[3] = Math.max(geo[1][0] - (geo[0][0] + geo[0][2]) - totalBuf, 0)
|
|
199
|
+
vs[4] = Math.max(geo[1][1] - (geo[0][1] + geo[0][3]) - totalBuf, 0)
|
|
200
|
+
|
|
201
|
+
// Route pattern lookup (with quad rotation)
|
|
202
|
+
// draw.io: only map EAST(8)→3, others are already in range 1-4
|
|
203
|
+
let si = sDir === _E ? 3 : sDir
|
|
204
|
+
let ti = tDir === _E ? 3 : tDir
|
|
205
|
+
si -= quad; ti -= quad
|
|
206
|
+
if (si < 1) si += 4
|
|
207
|
+
if (ti < 1) ti += 4
|
|
208
|
+
let rp = _rp[si - 1][ti - 1]
|
|
209
|
+
|
|
210
|
+
// Initial waypoint: handle position moved outward by buffer
|
|
211
|
+
let wp = []
|
|
212
|
+
for (let k = 0; k < 12; k++) wp[k] = [0, 0]
|
|
213
|
+
wp[0][0] = geo[0][0]
|
|
214
|
+
wp[0][1] = geo[0][1]
|
|
215
|
+
switch (sDir) {
|
|
216
|
+
case _W: wp[0][0] -= buf; wp[0][1] += con[0][1] * geo[0][3]; break
|
|
217
|
+
case _S: wp[0][0] += con[0][0] * geo[0][2]; wp[0][1] += geo[0][3] + buf; break
|
|
218
|
+
case _E: wp[0][0] += geo[0][2] + buf; wp[0][1] += con[0][1] * geo[0][3]; break
|
|
219
|
+
case _N: wp[0][0] += con[0][0] * geo[0][2]; wp[0][1] -= buf; break
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Waypoint generation loop
|
|
223
|
+
let ci = 0
|
|
224
|
+
let lastOr = (sDir & (_E | _W)) > 0 ? 0 : 1
|
|
225
|
+
let initOr = lastOr
|
|
226
|
+
|
|
227
|
+
for (let i = 0; i < rp.length; i++) {
|
|
228
|
+
let nd = rp[i] & 0xF
|
|
229
|
+
// draw.io: only map EAST(8)→3
|
|
230
|
+
let di = nd === _E ? 3 : nd
|
|
231
|
+
di += quad
|
|
232
|
+
if (di > 4) di -= 4
|
|
233
|
+
let dir = _dirV[di - 1]
|
|
234
|
+
let curOr = (di % 2 > 0) ? 0 : 1
|
|
235
|
+
|
|
236
|
+
if (curOr !== lastOr) {
|
|
237
|
+
ci++
|
|
238
|
+
wp[ci] = [wp[ci - 1][0], wp[ci - 1][1]]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
let tar = (rp[i] & _TGT) > 0
|
|
242
|
+
let sou = (rp[i] & _SRC) > 0
|
|
243
|
+
let side = (rp[i] & _SIDE) >> 5
|
|
244
|
+
side = side << quad
|
|
245
|
+
if (side > 0xF) side = side >> 4
|
|
246
|
+
let ctr = (rp[i] & _CTR) > 0
|
|
247
|
+
|
|
248
|
+
if ((sou || tar) && side < 9) {
|
|
249
|
+
let st = sou ? 0 : 1
|
|
250
|
+
let limit
|
|
251
|
+
if (ctr && curOr === 0) {
|
|
252
|
+
limit = geo[st][0] + con[st][0] * geo[st][2]
|
|
253
|
+
}
|
|
254
|
+
else if (ctr) {
|
|
255
|
+
limit = geo[st][1] + con[st][1] * geo[st][3]
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
limit = lim[st][side]
|
|
259
|
+
}
|
|
260
|
+
if (curOr === 0) {
|
|
261
|
+
let delta = (limit - wp[ci][0]) * dir[0]
|
|
262
|
+
if (delta > 0) wp[ci][0] += dir[0] * delta
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
let delta = (limit - wp[ci][1]) * dir[1]
|
|
266
|
+
if (delta > 0) wp[ci][1] += dir[1] * delta
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else if (ctr) {
|
|
270
|
+
wp[ci][0] += dir[0] * Math.abs(vs[di] / 2)
|
|
271
|
+
wp[ci][1] += dir[1] * Math.abs(vs[di] / 2)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Collapse zero-length segments
|
|
275
|
+
if (ci > 0 && wp[ci][curOr] === wp[ci - 1][curOr]) {
|
|
276
|
+
ci--
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
lastOr = curOr
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Build result: source handle → waypoints → target handle
|
|
284
|
+
let pts = [{ x: sourceX, y: sourceY }]
|
|
285
|
+
let tOr = (tDir & (_E | _W)) > 0 ? 0 : 1
|
|
286
|
+
let sameOr = tOr === initOr ? 0 : 1
|
|
287
|
+
|
|
288
|
+
for (let i = 0; i <= ci; i++) {
|
|
289
|
+
if (i === ci && sameOr !== (ci + 1) % 2) break
|
|
290
|
+
pts.push({ x: Math.round(wp[i][0] * 10) / 10, y: Math.round(wp[i][1] * 10) / 10 })
|
|
291
|
+
}
|
|
292
|
+
pts.push({ x: targetX, y: targetY })
|
|
293
|
+
|
|
294
|
+
// Remove consecutive duplicates
|
|
295
|
+
let result = [pts[0]]
|
|
296
|
+
for (let i = 1; i < pts.length; i++) {
|
|
297
|
+
if (Math.abs(pts[i].x - result[result.length - 1].x) > 0.5 ||
|
|
298
|
+
Math.abs(pts[i].y - result[result.length - 1].y) > 0.5) {
|
|
299
|
+
result.push(pts[i])
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return result
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* SegmentConnector fallback (draw.io style).
|
|
307
|
+
* Used when nodes are too close for OrthConnector (tooShort).
|
|
308
|
+
*/
|
|
309
|
+
function segmentFallback(sx, sy, tx, ty, sObs, tObs) {
|
|
310
|
+
let pts = [{ x: sx, y: sy }]
|
|
311
|
+
if (tObs && tx >= tObs.l && tx <= tObs.r && sy >= tObs.t && sy <= tObs.b) {
|
|
312
|
+
if (!(sObs && sx >= sObs.l && sx <= sObs.r && ty >= sObs.t && ty <= sObs.b)) {
|
|
313
|
+
pts.push({ x: sx, y: ty })
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else if (sx !== tx && sy !== ty) {
|
|
317
|
+
pts.push({ x: tx, y: sy })
|
|
318
|
+
}
|
|
319
|
+
pts.push({ x: tx, y: ty })
|
|
320
|
+
return pts
|
|
321
|
+
}
|
|
322
|
+
</code></pre>
|
|
323
|
+
</article>
|
|
324
|
+
</section>
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
</div>
|
|
332
|
+
|
|
333
|
+
<br class="clear">
|
|
334
|
+
|
|
335
|
+
<footer>
|
|
336
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Apr 12 2026 22:18:33 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
337
|
+
</footer>
|
|
338
|
+
|
|
339
|
+
<script>prettyPrint();</script>
|
|
340
|
+
<script src="scripts/polyfill.js"></script>
|
|
341
|
+
<script src="scripts/linenumber.js"></script>
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
</body>
|
|
346
|
+
</html>
|