@leafer-in/linker 2.3.2 → 2.3.4

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.
@@ -1,4 +1,4 @@
1
- import { LineData, AroundHelper, PointHelper, Direction9, BoundsHelper, decorateLeafAttr, attr, doBoundsType, doStrokeType, PathCommandDataHelper, dataProcessor, pathType, registerUI, Line, BoundsEvent, LeafHelper, isString, isObject, Plugin, registerPointsCurve } from "@leafer-ui/draw";
1
+ import { LineData, AroundHelper, PointHelper, Direction9, BoundsHelper, decorateLeafAttr, attr, doBoundsType, doStrokeType, PathCommandDataHelper, dataProcessor, boundsType, pathType, registerUI, Line, BoundsEvent, LeafHelper, isString, isObject, Plugin, registerPointsCurve } from "@leafer-ui/draw";
2
2
 
3
3
  import { PointHelper as PointHelper$1, PathCommandMap } from "@leafer-ui/core";
4
4
 
@@ -19,7 +19,7 @@ class LinkerData extends LineData {
19
19
  }
20
20
  }
21
21
 
22
- const {directionData: directionData} = AroundHelper;
22
+ const {directionData: directionData$1} = AroundHelper;
23
23
 
24
24
  const directionNames = [ "top-left", "top", "top-right", "right", "bottom-right", "bottom", "bottom-left", "left", "center" ];
25
25
 
@@ -135,8 +135,8 @@ function getPointDirection(boxPoint, bounds, eight) {
135
135
  const {width: width, height: height} = bounds;
136
136
  const hitRadiusX = width / 4;
137
137
  const hitRadiusY = height / 4;
138
- for (let i = 0; i < directionData.length; i++) {
139
- const unit = directionData[i];
138
+ for (let i = 0; i < directionData$1.length; i++) {
139
+ const unit = directionData$1[i];
140
140
  const px = unit.x * width;
141
141
  const py = unit.y * height;
142
142
  const dx = boxPoint.x - px;
@@ -181,7 +181,400 @@ function linkerPointType(defaultValue) {
181
181
  }));
182
182
  }
183
183
 
184
- const {moveTo: moveTo, bezierCurveTo: bezierCurveTo, drawPoints: drawPoints$1} = PathCommandDataHelper;
184
+ const {directionData: directionData} = AroundHelper;
185
+
186
+ const {moveTo: moveTo$1, lineTo: lineTo$1} = PathCommandDataHelper;
187
+
188
+ const POLYLINE_X = 0, POLYLINE_Y = 1;
189
+
190
+ const POLYLINE_EPSILON = .001;
191
+
192
+ const POLYLINE_MIN_SEGMENT = 4;
193
+
194
+ const POLYLINE_TURN_WEIGHT = 1.5;
195
+
196
+ function getPolylineDirectionIndex(direction) {
197
+ switch (direction) {
198
+ case "top-left":
199
+ return 0;
200
+
201
+ case "top":
202
+ return 1;
203
+
204
+ case "top-right":
205
+ return 2;
206
+
207
+ case "right":
208
+ return 3;
209
+
210
+ case "bottom-right":
211
+ return 4;
212
+
213
+ case "bottom":
214
+ return 5;
215
+
216
+ case "bottom-left":
217
+ return 6;
218
+
219
+ case "left":
220
+ return 7;
221
+
222
+ default:
223
+ return 8;
224
+ }
225
+ }
226
+
227
+ function getPolylinePorts(direction, point, target, bounds, targetBounds) {
228
+ const data = directionData[getPolylineDirectionIndex(direction)];
229
+ const dx = Math.sign(data.x - .5), dy = Math.sign(data.y - .5);
230
+ const cx = bounds ? bounds.x + bounds.width / 2 : point.x;
231
+ const cy = bounds ? bounds.y + bounds.height / 2 : point.y;
232
+ const tx = targetBounds ? targetBounds.x + targetBounds.width / 2 : target.x;
233
+ const ty = targetBounds ? targetBounds.y + targetBounds.height / 2 : target.y;
234
+ const deltaX = tx - cx, deltaY = ty - cy;
235
+ const xPort = (dx || (deltaX >= 0 ? 1 : -1)) > 0 ? 1 : 0;
236
+ const yPort = (dy || (deltaY >= 0 ? 1 : -1)) > 0 ? 3 : 2;
237
+ if (dx && !dy) return [ xPort ];
238
+ if (dy && !dx) return [ yPort ];
239
+ return Math.abs(deltaX) >= Math.abs(deltaY) ? [ xPort, yPort ] : [ yPort, xPort ];
240
+ }
241
+
242
+ function getPolylineExit(point, bounds, port, clearance) {
243
+ const axis = port >> 1, sign = port & 1 ? 1 : -1;
244
+ if (axis === POLYLINE_X) {
245
+ const x = bounds ? bounds.x + (sign > 0 ? bounds.width : 0) : point.x;
246
+ return {
247
+ x: x + sign * clearance,
248
+ y: point.y
249
+ };
250
+ }
251
+ const y = bounds ? bounds.y + (sign > 0 ? bounds.height : 0) : point.y;
252
+ return {
253
+ x: point.x,
254
+ y: y + sign * clearance
255
+ };
256
+ }
257
+
258
+ function isPolylinePointBlocked(x, y, bounds, clearance) {
259
+ if (!bounds) return false;
260
+ const left = bounds.x - clearance, right = bounds.x + bounds.width + clearance;
261
+ const top = bounds.y - clearance, bottom = bounds.y + bounds.height + clearance;
262
+ return x > left + POLYLINE_EPSILON && x < right - POLYLINE_EPSILON && y > top + POLYLINE_EPSILON && y < bottom - POLYLINE_EPSILON;
263
+ }
264
+
265
+ function isPolylineSegmentBlocked(x1, y1, x2, y2, bounds, clearance) {
266
+ if (!bounds) return false;
267
+ const left = bounds.x - clearance, right = bounds.x + bounds.width + clearance;
268
+ const top = bounds.y - clearance, bottom = bounds.y + bounds.height + clearance;
269
+ if (Math.abs(y1 - y2) <= POLYLINE_EPSILON) {
270
+ return y1 > top + POLYLINE_EPSILON && y1 < bottom - POLYLINE_EPSILON && Math.max(Math.min(x1, x2), left + POLYLINE_EPSILON) < Math.min(Math.max(x1, x2), right - POLYLINE_EPSILON);
271
+ }
272
+ if (Math.abs(x1 - x2) <= POLYLINE_EPSILON) {
273
+ return x1 > left + POLYLINE_EPSILON && x1 < right - POLYLINE_EPSILON && Math.max(Math.min(y1, y2), top + POLYLINE_EPSILON) < Math.min(Math.max(y1, y2), bottom - POLYLINE_EPSILON);
274
+ }
275
+ return true;
276
+ }
277
+
278
+ function addPolylineBoundsCoordinates(xs, ys, bounds, clearance, margin) {
279
+ if (!bounds) return;
280
+ const left = bounds.x - clearance, right = bounds.x + bounds.width + clearance;
281
+ const top = bounds.y - clearance, bottom = bounds.y + bounds.height + clearance;
282
+ xs.push(left, right, left - margin, right + margin);
283
+ ys.push(top, bottom, top - margin, bottom + margin);
284
+ }
285
+
286
+ function sortPolylineCoordinates(values) {
287
+ values.sort((a, b) => a - b);
288
+ let write = 0;
289
+ for (let i = 0; i < values.length; i++) {
290
+ if (!write || Math.abs(values[i] - values[write - 1]) > POLYLINE_EPSILON) values[write++] = values[i];
291
+ }
292
+ values.length = write;
293
+ }
294
+
295
+ function getPolylineCoordinateIndex(values, value) {
296
+ for (let i = 0; i < values.length; i++) {
297
+ if (Math.abs(values[i] - value) <= POLYLINE_EPSILON) return i;
298
+ }
299
+ return -1;
300
+ }
301
+
302
+ function getPolylineMidpointAxis(startPort, endPort, sx, sy, ex, ey) {
303
+ const startAxis = startPort >> 1, endAxis = endPort >> 1;
304
+ const startSign = startPort & 1 ? 1 : -1, endSign = endPort & 1 ? 1 : -1;
305
+ if (startAxis === endAxis && startSign === -endSign) return startAxis;
306
+ return Math.abs(ex - sx) >= Math.abs(ey - sy) ? POLYLINE_X : POLYLINE_Y;
307
+ }
308
+
309
+ function isPolylinePortAligned(port, stub, dx, dy) {
310
+ const offset = port >> 1 === POLYLINE_X ? dx : dy;
311
+ const sign = port & 1 ? 1 : -1;
312
+ return Math.abs(offset) <= POLYLINE_EPSILON ? stub > POLYLINE_EPSILON : offset * sign > 0;
313
+ }
314
+
315
+ function isPolylineMidpointAligned(port, stub, dx, dy, axis) {
316
+ if (port === undefined) return true;
317
+ if (axis === POLYLINE_X && Math.abs(dx / 2) > POLYLINE_EPSILON) return isPolylinePortAligned(port, stub, dx, 0);
318
+ if (axis === POLYLINE_Y && Math.abs(dy / 2) > POLYLINE_EPSILON) return isPolylinePortAligned(port, stub, 0, dy);
319
+ if (Math.abs(dx) <= POLYLINE_EPSILON && Math.abs(dy) <= POLYLINE_EPSILON) return true;
320
+ return isPolylinePortAligned(port, stub, dx, dy);
321
+ }
322
+
323
+ function isPolylineApproachAligned(points, port) {
324
+ if (port === undefined) return true;
325
+ const last = points.length - 2, x = points[last], y = points[last + 1];
326
+ for (let i = last - 2; i >= 0; i -= 2) {
327
+ const dx = points[i] - x, dy = points[i + 1] - y;
328
+ if (Math.abs(dx) > POLYLINE_EPSILON || Math.abs(dy) > POLYLINE_EPSILON) return isPolylinePortAligned(port, 1, dx, dy);
329
+ }
330
+ return true;
331
+ }
332
+
333
+ function getPolylineRoute(result, startPoint, endPoint, startPort, endPort, startBounds, endBounds, clearance, strictPorts, approachPort) {
334
+ const startExit = getPolylineExit(startPoint, startBounds, startPort, clearance);
335
+ const endExit = endPort === undefined ? endPoint : getPolylineExit(endPoint, endBounds, endPort, clearance);
336
+ const {x: sx, y: sy} = startExit, {x: ex, y: ey} = endExit;
337
+ const startStub = Math.abs(sx - startPoint.x) + Math.abs(sy - startPoint.y);
338
+ const endStub = Math.abs(ex - endPoint.x) + Math.abs(ey - endPoint.y);
339
+ if (isPolylineSegmentBlocked(startPoint.x, startPoint.y, sx, sy, endBounds, clearance) || isPolylineSegmentBlocked(endPoint.x, endPoint.y, ex, ey, startBounds, clearance)) return Infinity;
340
+ if (endPort === undefined && (isPolylinePointBlocked(ex, ey, startBounds, clearance) || isPolylinePointBlocked(ex, ey, endBounds, clearance))) return Infinity;
341
+ const axis = endPort === undefined ? startPort >> 1 : getPolylineMidpointAxis(startPort, endPort, sx, sy, ex, ey);
342
+ const dx = ex - sx, dy = ey - sy;
343
+ result.length = 0;
344
+ result.push(startPoint.x, startPoint.y, sx, sy);
345
+ if ((!strictPorts || isPolylineMidpointAligned(startPort, startStub, dx, dy, axis) && isPolylineMidpointAligned(endPort, endStub, -dx, -dy, axis)) && isPolylineMidpointAligned(approachPort, 1, -dx, -dy, axis)) {
346
+ const mx = (sx + ex) / 2, my = (sy + ey) / 2;
347
+ if (axis === POLYLINE_X) result.push(mx, sy, mx, ey); else result.push(sx, my, ex, my);
348
+ result.push(ex, ey, endPoint.x, endPoint.y);
349
+ for (let i = 4; i < result.length - 2; i += 2) {
350
+ if (isPolylineSegmentBlocked(result[i - 2], result[i - 1], result[i], result[i + 1], startBounds, clearance) || isPolylineSegmentBlocked(result[i - 2], result[i - 1], result[i], result[i + 1], endBounds, clearance)) {
351
+ result.length = 4;
352
+ break;
353
+ }
354
+ }
355
+ if (result.length > 4 && isPolylineApproachAligned(result, approachPort)) return getPolylineScore(result, clearance);
356
+ result.length = 4;
357
+ }
358
+ const score = findPolylineGridRoute(result, startExit, endExit, startPort, endPort, startBounds, endBounds, clearance, axis, startStub, endStub, strictPorts, approachPort);
359
+ if (score === Infinity) return score;
360
+ result.push(endPoint.x, endPoint.y);
361
+ return isPolylineApproachAligned(result, approachPort) ? score + startStub + endStub : Infinity;
362
+ }
363
+
364
+ function findPolylineGridRoute(result, startExit, endExit, startPort, endPort, startBounds, endBounds, clearance, midpointAxis, startStub, endStub, strictPorts, approachPort) {
365
+ const {x: sx, y: sy} = startExit, {x: ex, y: ey} = endExit;
366
+ const margin = Math.max(clearance, POLYLINE_MIN_SEGMENT) * 2;
367
+ const xs = [ sx, ex, (sx + ex) / 2 ], ys = [ sy, ey, (sy + ey) / 2 ];
368
+ addPolylineBoundsCoordinates(xs, ys, startBounds, clearance, margin);
369
+ addPolylineBoundsCoordinates(xs, ys, endBounds, clearance, margin);
370
+ xs.push(Math.min(...xs) - margin * 2, Math.max(...xs) + margin * 2);
371
+ ys.push(Math.min(...ys) - margin * 2, Math.max(...ys) + margin * 2);
372
+ sortPolylineCoordinates(xs);
373
+ sortPolylineCoordinates(ys);
374
+ const nx = xs.length, ny = ys.length;
375
+ const startXIndex = getPolylineCoordinateIndex(xs, sx), startYIndex = getPolylineCoordinateIndex(ys, sy);
376
+ const endXIndex = getPolylineCoordinateIndex(xs, ex), endYIndex = getPolylineCoordinateIndex(ys, ey);
377
+ if (startXIndex < 0 || startYIndex < 0 || endXIndex < 0 || endYIndex < 0) return Infinity;
378
+ const startNode = startYIndex * nx + startXIndex, endNode = endYIndex * nx + endXIndex;
379
+ const total = nx * ny * 3;
380
+ const distance = new Float64Array(total), previous = new Int32Array(total), visited = new Uint8Array(total);
381
+ distance.fill(Infinity);
382
+ previous.fill(-1);
383
+ const startState = startNode * 3;
384
+ distance[startState] = 0;
385
+ const pending = [ startState ];
386
+ const turnCost = Math.max(POLYLINE_MIN_SEGMENT, clearance * POLYLINE_TURN_WEIGHT);
387
+ const preferredCoordinate = midpointAxis === POLYLINE_X ? (sx + ex) / 2 : (sy + ey) / 2;
388
+ let currentState = -1, currentNode = -1, currentAxis = 0;
389
+ let currentX = 0, currentY = 0, currentDistance = 0;
390
+ const relax = (nextXIndex, nextYIndex, axis) => {
391
+ const nextX = xs[nextXIndex], nextY = ys[nextYIndex];
392
+ const nextNode = nextYIndex * nx + nextXIndex;
393
+ const dx = nextX - currentX, dy = nextY - currentY;
394
+ if (nextNode === startNode) return;
395
+ if (approachPort !== undefined && nextNode === endNode && !isPolylinePortAligned(approachPort, 1, -dx, -dy)) return;
396
+ if (strictPorts && (currentState === startState && !isPolylinePortAligned(startPort, startStub, dx, dy) || endPort !== undefined && nextNode === endNode && !isPolylinePortAligned(endPort, endStub, -dx, -dy))) return;
397
+ if (isPolylinePointBlocked(nextX, nextY, startBounds, clearance) || isPolylinePointBlocked(nextX, nextY, endBounds, clearance) || isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, startBounds, clearance) || isPolylineSegmentBlocked(currentX, currentY, nextX, nextY, endBounds, clearance)) return;
398
+ const nextState = nextNode * 3 + axis;
399
+ if (visited[nextState]) return;
400
+ let cost = currentDistance + (Math.abs(dx) + Math.abs(dy));
401
+ if (currentAxis && currentAxis !== axis) {
402
+ cost += turnCost;
403
+ const turnCoordinate = currentAxis === POLYLINE_X + 1 ? currentX : currentY;
404
+ if (Math.abs(turnCoordinate - preferredCoordinate) > POLYLINE_EPSILON) cost += turnCost * 2;
405
+ }
406
+ if (cost < distance[nextState]) {
407
+ if (distance[nextState] === Infinity) pending.push(nextState);
408
+ distance[nextState] = cost;
409
+ previous[nextState] = currentState;
410
+ }
411
+ };
412
+ let bestState = -1;
413
+ while (pending.length) {
414
+ let index = 0, state = pending[0];
415
+ for (let i = 1; i < pending.length; i++) {
416
+ const next = pending[i];
417
+ if (distance[next] < distance[state] || distance[next] === distance[state] && next < state) {
418
+ index = i;
419
+ state = next;
420
+ }
421
+ }
422
+ pending[index] = pending[pending.length - 1];
423
+ pending.pop();
424
+ currentState = state;
425
+ currentNode = Math.floor(state / 3);
426
+ currentAxis = state % 3;
427
+ currentDistance = distance[state];
428
+ visited[state] = 1;
429
+ if (currentNode === endNode) {
430
+ bestState = state;
431
+ break;
432
+ }
433
+ const xIndex = currentNode % nx, yIndex = Math.floor(currentNode / nx);
434
+ currentX = xs[xIndex];
435
+ currentY = ys[yIndex];
436
+ if (xIndex > 0) relax(xIndex - 1, yIndex, POLYLINE_X + 1);
437
+ if (xIndex < nx - 1) relax(xIndex + 1, yIndex, POLYLINE_X + 1);
438
+ if (yIndex > 0) relax(xIndex, yIndex - 1, POLYLINE_Y + 1);
439
+ if (yIndex < ny - 1) relax(xIndex, yIndex + 1, POLYLINE_Y + 1);
440
+ }
441
+ if (bestState < 0) return Infinity;
442
+ const reverse = [];
443
+ let state = bestState;
444
+ while (state >= 0) {
445
+ const node = Math.floor(state / 3);
446
+ reverse.push(xs[node % nx], ys[Math.floor(node / nx)]);
447
+ if (state === startState) break;
448
+ state = previous[state];
449
+ }
450
+ if (state !== startState) return Infinity;
451
+ for (let i = reverse.length - 4; i >= 0; i -= 2) result.push(reverse[i], reverse[i + 1]);
452
+ return distance[bestState];
453
+ }
454
+
455
+ function getPolylineFallback(start, end, port, startBounds, endBounds) {
456
+ const {x: sx, y: sy} = start, {x: ex, y: ey} = end;
457
+ if (sx === ex || sy === ey) return [ sx, sy, ex, ey ];
458
+ const horizontal = port >> 1 === POLYLINE_X;
459
+ const crosses = (x, y) => {
460
+ let count = 0;
461
+ if (isPolylineSegmentBlocked(sx, sy, x, y, startBounds, 0)) count++;
462
+ if (isPolylineSegmentBlocked(x, y, ex, ey, startBounds, 0)) count++;
463
+ if (isPolylineSegmentBlocked(sx, sy, x, y, endBounds, 0)) count++;
464
+ if (isPolylineSegmentBlocked(x, y, ex, ey, endBounds, 0)) count++;
465
+ return count;
466
+ };
467
+ const xy = crosses(ex, sy), yx = crosses(sx, ey);
468
+ return xy < yx || xy === yx && horizontal ? [ sx, sy, ex, sy, ex, ey ] : [ sx, sy, sx, ey, ex, ey ];
469
+ }
470
+
471
+ function getBestPolyline(startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance, approachPort) {
472
+ const startPorts = getPolylinePorts(startDirection, startPoint, endPoint, startBounds, endDirection === undefined ? undefined : endBounds);
473
+ const endPorts = endDirection === undefined ? [ undefined ] : getPolylinePorts(endDirection, endPoint, startPoint, endBounds, startBounds);
474
+ let candidate = [], best = [], bestScore = Infinity;
475
+ for (let pass = clearance ? 0 : 1; pass < 3 && !best.length; pass++) {
476
+ const gap = pass ? 0 : clearance;
477
+ for (let i = 0; i < startPorts.length; i++) {
478
+ for (let j = 0; j < endPorts.length; j++) {
479
+ const score = getPolylineRoute(candidate, startPoint, endPoint, startPorts[i], endPorts[j], startBounds, endBounds, gap, pass < 2, approachPort);
480
+ if (score < bestScore) {
481
+ bestScore = score;
482
+ const previous = best;
483
+ best = candidate;
484
+ candidate = previous;
485
+ }
486
+ }
487
+ }
488
+ }
489
+ if (!best.length) return getPolylineFallback(startPoint, endPoint, startPorts[0], startBounds, endBounds);
490
+ simplifyPolyline(best);
491
+ const last = best.length - 2;
492
+ if (best[last] !== endPoint.x || best[last + 1] !== endPoint.y) best.push(endPoint.x, endPoint.y);
493
+ return best;
494
+ }
495
+
496
+ function getPolylineEditSide(point, waypoint, direction, bounds, otherBounds, clearance, points, index, step) {
497
+ if (point.x === waypoint.x && point.y === waypoint.y) return [];
498
+ let approachPort;
499
+ for (let i = index + step; i >= 0 && i < points.length; i += step) {
500
+ const dx = points[i] - waypoint.x, dy = points[i + 1] - waypoint.y;
501
+ if (Math.abs(dx) <= POLYLINE_EPSILON && Math.abs(dy) <= POLYLINE_EPSILON) continue;
502
+ if (Math.abs(dy) <= POLYLINE_EPSILON) approachPort = dx > 0 ? 0 : 1; else if (Math.abs(dx) <= POLYLINE_EPSILON) approachPort = dy > 0 ? 2 : 3;
503
+ break;
504
+ }
505
+ const side = getBestPolyline(point, waypoint, direction, undefined, bounds, otherBounds, clearance, approachPort);
506
+ side.length -= 2;
507
+ return side;
508
+ }
509
+
510
+ function drawPolylineEditPath(path, startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance, points) {
511
+ const length = points.length, last = length - 2;
512
+ if (length % 2) return false;
513
+ for (let i = 0; i < length; i++) if (!Number.isFinite(points[i])) return false;
514
+ const start = getPolylineEditSide(startPoint, {
515
+ x: points[0],
516
+ y: points[1]
517
+ }, startDirection, startBounds, endBounds, clearance, points, 0, 2);
518
+ const end = getPolylineEditSide(endPoint, {
519
+ x: points[last],
520
+ y: points[last + 1]
521
+ }, endDirection, endBounds, startBounds, clearance, points, last, -2);
522
+ const first = start.length ? start : points;
523
+ moveTo$1(path, first[0], first[1]);
524
+ for (let i = 2; i < start.length; i += 2) lineTo$1(path, start[i], start[i + 1]);
525
+ for (let i = start.length ? 0 : 2; i < length; i += 2) lineTo$1(path, points[i], points[i + 1]);
526
+ for (let i = end.length - 2; i >= 0; i -= 2) lineTo$1(path, end[i], end[i + 1]);
527
+ return true;
528
+ }
529
+
530
+ function getPolylineScore(points, clearance) {
531
+ let length = 0, turns = 0, previousAxis = -1;
532
+ for (let i = 2; i < points.length; i += 2) {
533
+ const dx = points[i] - points[i - 2], dy = points[i + 1] - points[i - 1];
534
+ if (Math.abs(dx) <= POLYLINE_EPSILON && Math.abs(dy) <= POLYLINE_EPSILON) continue;
535
+ const axis = Math.abs(dx) > POLYLINE_EPSILON ? POLYLINE_X : POLYLINE_Y;
536
+ length += Math.abs(dx) + Math.abs(dy);
537
+ if (previousAxis !== -1 && previousAxis !== axis) turns++;
538
+ previousAxis = axis;
539
+ }
540
+ return length + turns * Math.max(clearance, POLYLINE_MIN_SEGMENT) * POLYLINE_TURN_WEIGHT;
541
+ }
542
+
543
+ function simplifyPolyline(points) {
544
+ let write = 2;
545
+ for (let read = 2; read < points.length; read += 2) {
546
+ const x = points[read], y = points[read + 1];
547
+ const px = points[write - 2], py = points[write - 1];
548
+ if (Math.abs(x - px) <= POLYLINE_EPSILON && Math.abs(y - py) <= POLYLINE_EPSILON) continue;
549
+ if (write >= 4) {
550
+ const ax = points[write - 4], ay = points[write - 3];
551
+ const horizontal = Math.abs(ay - py) <= POLYLINE_EPSILON && Math.abs(py - y) <= POLYLINE_EPSILON && (px - ax) * (x - px) >= 0;
552
+ const vertical = Math.abs(ax - px) <= POLYLINE_EPSILON && Math.abs(px - x) <= POLYLINE_EPSILON && (py - ay) * (y - py) >= 0;
553
+ if (horizontal || vertical) {
554
+ points[write - 2] = x;
555
+ points[write - 1] = y;
556
+ continue;
557
+ }
558
+ }
559
+ points[write++] = x;
560
+ points[write++] = y;
561
+ }
562
+ points.length = write;
563
+ }
564
+
565
+ function drawPolyline(path, startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance = 8, points) {
566
+ if (!Number.isFinite(startPoint.x) || !Number.isFinite(startPoint.y) || !Number.isFinite(endPoint.x) || !Number.isFinite(endPoint.y)) return false;
567
+ if (startBounds && (!Number.isFinite(startBounds.x) || !Number.isFinite(startBounds.y) || !Number.isFinite(startBounds.width) || !Number.isFinite(startBounds.height) || startBounds.width < 0 || startBounds.height < 0)) return false;
568
+ if (endBounds && (!Number.isFinite(endBounds.x) || !Number.isFinite(endBounds.y) || !Number.isFinite(endBounds.width) || !Number.isFinite(endBounds.height) || endBounds.width < 0 || endBounds.height < 0)) return false;
569
+ clearance = Number.isFinite(clearance) ? Math.max(0, clearance) : 8;
570
+ if (points === null || points === void 0 ? void 0 : points.length) return drawPolylineEditPath(path, startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance, points);
571
+ const best = getBestPolyline(startPoint, endPoint, startDirection, endDirection, startBounds, endBounds, clearance);
572
+ moveTo$1(path, best[0], best[1]);
573
+ for (let i = 2; i < best.length; i += 2) lineTo$1(path, best[i], best[i + 1]);
574
+ return true;
575
+ }
576
+
577
+ const {moveTo: moveTo, lineTo: lineTo, bezierCurveTo: bezierCurveTo, drawPoints: drawPoints$1} = PathCommandDataHelper;
185
578
 
186
579
  const {isEmpty: isEmpty, getPoint: getPoint} = BoundsHelper;
187
580
 
@@ -274,7 +667,7 @@ let Linker = class Linker extends Line {
274
667
  }
275
668
  }
276
669
  updateLinkerPoint(type) {
277
- const {startPoint: startPoint, endPoint: endPoint} = this;
670
+ const {startPoint: startPoint, endPoint: endPoint, lineType: lineType} = this;
278
671
  const nowPoint = type === "end" ? endPoint : startPoint;
279
672
  if (nowPoint) {
280
673
  const data = {};
@@ -299,6 +692,7 @@ let Linker = class Linker extends Line {
299
692
  if (isEmpty(boxBounds)) LeafHelper.updateBounds(ui);
300
693
  p = getPoint(boxBounds, point, true);
301
694
  ui.getWorldPointByBox(p, this, false, true);
695
+ if (lineType === "polyline") data.bounds = ui.getBounds("box", this.parent);
302
696
  }
303
697
  } else {
304
698
  if (isObject(point)) p = point;
@@ -324,56 +718,69 @@ let Linker = class Linker extends Line {
324
718
  }
325
719
  const startPoint = startData.point, endPoint = endData.point;
326
720
  const startDirection = startData.direction, endDirection = endData.direction;
327
- const half = {
328
- x: abs((startPoint.x - endPoint.x) / 2),
329
- y: abs((startPoint.y - endPoint.y) / 2)
330
- };
331
721
  const arrowWidth = this.__.strokeWidth * 8;
332
- let minCtrl;
333
- if (this.__.__useArrow) {
334
- const ratio = min(getDistance(startPoint, endPoint) / (arrowWidth * 25), 1);
335
- minCtrl = max(arrowWidth * ratio * 12, arrowWidth * 3);
336
- } else {
337
- minCtrl = arrowWidth * 2;
338
- }
339
- if (endDirection) {
340
- if (isOppositeDirection(startDirection, endDirection) && startDirection === getDirectionForFromPoint(startPoint, endPoint)) {
722
+ switch (data.lineType) {
723
+ case "straight":
724
+ moveTo(path, startPoint.x, startPoint.y);
725
+ lineTo(path, endPoint.x, endPoint.y);
726
+ break;
727
+
728
+ case "polyline":
729
+ drawPolyline(path, startPoint, endPoint, startDirection, endDirection, startData.bounds, endData.bounds, arrowWidth, hasPoints && PointHelper.toNumberPoints(data.points));
730
+ break;
731
+
732
+ case "curve":
733
+ default:
734
+ const half = {
735
+ x: abs((startPoint.x - endPoint.x) / 2),
736
+ y: abs((startPoint.y - endPoint.y) / 2)
737
+ };
738
+ let minCtrl;
739
+ if (this.__.__useArrow) {
740
+ const ratio = min(getDistance(startPoint, endPoint) / (arrowWidth * 25), 1);
741
+ minCtrl = max(arrowWidth * ratio * 12, arrowWidth * 3);
742
+ } else {
341
743
  minCtrl = arrowWidth * 2;
342
744
  }
343
- }
344
- half.x = max(minCtrl, half.x);
345
- half.y = max(minCtrl, half.y);
346
- if (hasPoints) {
347
- minCtrl *= .6;
348
- const points = PointHelper.toNumberPoints(data.points);
349
- drawPoints$1(path, [ startPoint.x, startPoint.y, ...points, endPoint.x, endPoint.y ], data.curve, false, data);
350
- if (startDirection) {
351
- const handleX = path[4];
352
- const handleY = path[5];
353
- half.x = max(minCtrl, abs(handleX - startPoint.x));
354
- half.y = max(minCtrl, abs(handleY - startPoint.y));
355
- const startCtrlPoint = getCtrlPoint(this, startNode, startPoint, startDirection, half);
356
- path[4] = startCtrlPoint.x;
357
- path[5] = startCtrlPoint.y;
358
- }
359
- const len = path.length;
360
745
  if (endDirection) {
361
- const handleX = path[len - 4];
362
- const handleY = path[len - 3];
363
- half.x = max(minCtrl, abs(handleX - endPoint.x));
364
- half.y = max(minCtrl, abs(handleY - endPoint.y));
365
- const endCtrlPoint = getCtrlPoint(this, endNode, endPoint, endDirection, half);
366
- path[len - 4] = endCtrlPoint.x;
367
- path[len - 3] = endCtrlPoint.y;
746
+ if (isOppositeDirection(startDirection, endDirection) && startDirection === getDirectionForFromPoint(startPoint, endPoint)) {
747
+ minCtrl = arrowWidth * 2;
748
+ }
749
+ }
750
+ half.x = max(minCtrl, half.x);
751
+ half.y = max(minCtrl, half.y);
752
+ if (hasPoints) {
753
+ minCtrl *= .6;
754
+ const points = PointHelper.toNumberPoints(data.points);
755
+ drawPoints$1(path, [ startPoint.x, startPoint.y, ...points, endPoint.x, endPoint.y ], data.curve, false, data);
756
+ if (startDirection) {
757
+ const handleX = path[4];
758
+ const handleY = path[5];
759
+ half.x = max(minCtrl, abs(handleX - startPoint.x));
760
+ half.y = max(minCtrl, abs(handleY - startPoint.y));
761
+ const startCtrlPoint = getCtrlPoint(this, startNode, startPoint, startDirection, half);
762
+ path[4] = startCtrlPoint.x;
763
+ path[5] = startCtrlPoint.y;
764
+ }
765
+ const len = path.length;
766
+ if (endDirection) {
767
+ const handleX = path[len - 4];
768
+ const handleY = path[len - 3];
769
+ half.x = max(minCtrl, abs(handleX - endPoint.x));
770
+ half.y = max(minCtrl, abs(handleY - endPoint.y));
771
+ const endCtrlPoint = getCtrlPoint(this, endNode, endPoint, endDirection, half);
772
+ path[len - 4] = endCtrlPoint.x;
773
+ path[len - 3] = endCtrlPoint.y;
774
+ } else {
775
+ path[len - 4] = endPoint.x;
776
+ path[len - 3] = endPoint.y;
777
+ }
368
778
  } else {
369
- path[len - 4] = endPoint.x;
370
- path[len - 3] = endPoint.y;
779
+ const startCtrlPoint = startDirection ? getCtrlPoint(this, startNode, startPoint, startDirection, half) : startPoint;
780
+ const endCtrlPoint = endDirection ? getCtrlPoint(this, endNode, endPoint, endDirection, half) : endPoint;
781
+ moveTo(path, startPoint.x, startPoint.y);
782
+ bezierCurveTo(path, startCtrlPoint.x, startCtrlPoint.y, endCtrlPoint.x, endCtrlPoint.y, endPoint.x, endPoint.y);
371
783
  }
372
- } else {
373
- const startCtrlPoint = startDirection ? getCtrlPoint(this, startNode, startPoint, startDirection, half) : startPoint;
374
- const endCtrlPoint = endDirection ? getCtrlPoint(this, endNode, endPoint, endDirection, half) : endPoint;
375
- moveTo(path, startPoint.x, startPoint.y);
376
- bezierCurveTo(path, startCtrlPoint.x, startCtrlPoint.y, endCtrlPoint.x, endCtrlPoint.y, endPoint.x, endPoint.y);
377
784
  }
378
785
  }
379
786
  createStartPoint(worldPoint, node, options) {
@@ -443,6 +850,8 @@ let Linker = class Linker extends Line {
443
850
 
444
851
  __decorate([ dataProcessor(LinkerData) ], Linker.prototype, "__", void 0);
445
852
 
853
+ __decorate([ boundsType("curve") ], Linker.prototype, "lineType", void 0);
854
+
446
855
  __decorate([ linkerPointType() ], Linker.prototype, "startPoint", void 0);
447
856
 
448
857
  __decorate([ linkerPointType() ], Linker.prototype, "endPoint", void 0);
@@ -1,2 +1,2 @@
1
- import{LineData as t,AroundHelper as e,PointHelper as n,Direction9 as o,BoundsHelper as i,decorateLeafAttr as r,attr as s,doBoundsType as a,doStrokeType as d,PathCommandDataHelper as h,dataProcessor as c,pathType as u,registerUI as l,Line as p,BoundsEvent as f,LeafHelper as y,isString as g,isObject as x,Plugin as P,registerPointsCurve as k}from"@leafer-ui/draw";import{PointHelper as b,PathCommandMap as L}from"@leafer-ui/core";function N(t,e,n,o){var i,r=arguments.length,s=r<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,n):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(t,e,n,o);else for(var a=t.length-1;a>=0;a--)(i=t[a])&&(s=(r<3?i(s):r>3?i(e,n,s):i(e,n))||s);return r>3&&s&&Object.defineProperty(e,n,s),s}"function"==typeof SuppressedError&&SuppressedError;class m extends t{get __usePathBox(){return this.path||this.__pathInputed}}const{directionData:C}=e,M=["top-left","top","top-right","right","bottom-right","bottom","bottom-left","left","center"],_={getCtrlPoint(t,e,n,o,i,r){let s;switch(e&&(n=e.getBoxPoint(n,t)),o){case"left":case"top-left":case"bottom-left":s={x:n.x-i.x,y:n.y};break;case"top":s={x:n.x,y:n.y-i.y};break;case"right":case"top-right":case"bottom-right":s={x:n.x+i.x,y:n.y};break;case"bottom":s={x:n.x,y:n.y+i.y};break;default:s={x:n.x,y:n.y}}return r&&(r=r/180*Math.PI,s={x:(s.x-n.x)*Math.cos(r)-(s.y-n.y)*Math.sin(r)+n.x,y:(s.x-n.x)*Math.sin(r)+(s.y-n.y)*Math.cos(r)+n.y}),e&&e.getWorldPointByBox(s,t,void 0,!0),s},isOppositeDirection(t,e){switch(t){case"left":return"right"==e;case"top":return"bottom"==e;case"right":return"left"==e;case"bottom":return"top"==e;case"center":return"center"==e;default:return!1}},getDirectionForFromPoint(t,e){const n=t.x-e.x,o=t.y-e.y;let i,r=180*Math.atan2(o,n)/Math.PI;return r<0&&(r=360+r),i=r>315||r<45?"left":r>45&&r<135?"top":r>135&&r<225?"right":"bottom",i},getRotateDirection(t,e,n=8){let i=o[t];return i=(i+Math.round(e/(360/n)))%n,i<0&&(i+=n),M[i]},getDirection:function(t,e,n){const{width:o,height:r}=e,s=i.getPoint(e,"center",!0),a=t.x-s.x,d=t.y-s.y;if(!n&&Math.abs(a)<o/4&&Math.abs(d)<r/4)return"center";const h=Math.abs(a)*r,c=Math.abs(d)*o;if(h>c)return a>0?"right":"left";return d>0?"bottom":"top"},getPointDirection:function(t,e,n){const{width:o,height:i}=e,r=o/4,s=i/4;for(let e=0;e<C.length;e++){const a=C[e],d=a.x*o,h=a.y*i,c=t.x-d,u=t.y-h;if(Math.abs(c)<=r&&Math.abs(u)<=s){if(!n)return M[e];if("center"!==M[e])return M[e]}}return},autoRotatePoint(t,e,o){const{rotation:i,scaleX:r,scaleY:s}=o,a=r*s<0;(i||a)&&n.rotate(t,a?-i:i,e)}};function D(t){return r(t,t=>s({set(e){if(this.__setAttr(t,e)){const t=this.__layout;t.linkerChanged||(a(this),d(this),t.linkerChanged=!0)}}}))}const{moveTo:B,bezierCurveTo:v,drawPoints:w}=h,{isEmpty:E,getPoint:R}=i,{getDistance:O}=n,{getCtrlPoint:S,getDirectionForFromPoint:W,isOppositeDirection:q}=_,{max:I,min:j,abs:F}=Math;let z=class extends p{get __tag(){return"Linker"}constructor(t){super(t),this.onStartNodeChange=this.onStartNodeChange.bind(this),this.onEndNodeChange=this.onEndNodeChange.bind(this)}__updatePath(){const t=this.__layout,{startNode:e,endNode:n}=this;t.linkerChanged&&(this.updateLinkerNode("start"),this.updateLinkerNode("end"),this.updateLinkerPoint("start"),this.updateLinkerPoint("end"),e!==this.startNode&&this.listenLinkerNode(this.startNode,e,"start"),n!==this.endNode&&this.listenLinkerNode(this.endNode,n,"end"),t.linkerChanged=!1),this.updateLinkerPath()}listenLinkerNode(t,e,n){if(e){e.off(f.WORLD,"end"===n?this.onEndNodeChange:this.onStartNodeChange);const t="end"===n?e.endLinker:e.startLinker;if(t){const e=t.indexOf(this);e>-1&&t.splice(e,1)}}if(t){t.on(f.WORLD,"end"===n?this.onEndNodeChange:this.onStartNodeChange);("end"===n?t.endLinker||(t.endLinker=[]):t.startLinker||(t.startLinker=[])).push(this)}}onStartNodeChange(){this.onLinkerNodeChange("start")}onEndNodeChange(){this.onLinkerNodeChange("end")}onLinkerNodeChange(t){if(this.leaferIsCreated){const{layouter:t,zoomLayer:e}=this.leafer;if(t.__updatedList.has(e))return;t.addExtra(this,!0)}const{startData:e,endData:n}=this;"start"==t?(this.updateLinkerPoint("start"),n&&n.auto&&this.updateLinkerPoint("end")):(e&&e.auto&&this.updateLinkerPoint("start"),this.updateLinkerPoint("end")),this.__layout.boxChange(),y.updateBounds(this)}updateLinkerNode(t){const{startPoint:e,endPoint:n}=this,o="end"===t?n:e;if(o){const{id:e}=o,n=e&&(g(e)?this.app.findId(e):e);"end"===t?this.endNode=n:this.startNode=n}}getLinkerNodeCenter(t){const{startPoint:e,endPoint:n,startNode:o,endNode:i,startData:r,endData:s}=this,a="end"===t?i:o,d="end"===t?s||n:r||e;if(a){const{worldRenderBounds:t}=a;return E(t)&&y.updateBounds(a),R(a.worldRenderBounds,"center")}return d&&x(d.point)&&this.getWorldPointByLocal(d.point)}updateLinkerPoint(t){const{startPoint:e,endPoint:o}=this,i="end"===t?o:e;if(i){const e={},{id:o,offset:r}=i;let{direction:s,point:a}=i;if("center"===s||!s&&o&&!a){const n=this.getLinkerNodeCenter("start"),o=this.getLinkerNodeCenter("end"),i="end"===t?o:n,r="end"===t?n:o;i&&r&&(s=W(i,r)),e.auto=!0}!s&&g(a)&&(s=a),e.direction=s;const d="end"===t?this.endNode:this.startNode;let h;if(d){if(a||(a=s),a){const{boxBounds:t}=d;E(t)&&y.updateBounds(d),h=R(t,a,!0),d.getWorldPointByBox(h,this,!1,!0)}}else x(a)&&(h=a);if(h&&r){const t=Object.assign({},r);r.x||(t.x=0),r.y||(t.y=0),d&&d.getWorldPoint(t,this,!0,!0),n.move(h,t)}e.point=h,"end"===t?this.endData=h&&e:this.startData=h&&e}}updateLinkerPath(){const t=this.__,e=t.path=[],o=t.points&&t.points.length,{startData:i,endData:r,startNode:s,endNode:a}=this;if(!i||!r)return;const d=i.point,h=r.point,c=i.direction,u=r.direction,l={x:F((d.x-h.x)/2),y:F((d.y-h.y)/2)},p=8*this.__.strokeWidth;let f;if(this.__.__useArrow){const t=j(O(d,h)/(25*p),1);f=I(p*t*12,3*p)}else f=2*p;if(u&&q(c,u)&&c===W(d,h)&&(f=2*p),l.x=I(f,l.x),l.y=I(f,l.y),o){f*=.6;const o=n.toNumberPoints(t.points);if(w(e,[d.x,d.y,...o,h.x,h.y],t.curve,!1,t),c){const t=e[4],n=e[5];l.x=I(f,F(t-d.x)),l.y=I(f,F(n-d.y));const o=S(this,s,d,c,l);e[4]=o.x,e[5]=o.y}const i=e.length;if(u){const t=e[i-4],n=e[i-3];l.x=I(f,F(t-h.x)),l.y=I(f,F(n-h.y));const o=S(this,a,h,u,l);e[i-4]=o.x,e[i-3]=o.y}else e[i-4]=h.x,e[i-3]=h.y}else{const t=c?S(this,s,d,c,l):d,n=u?S(this,a,h,u,l):h;B(e,d.x,d.y),v(e,t.x,t.y,n.x,n.y,h.x,h.y)}}createStartPoint(t,e,n){const o=this.createLinkerPoint(t,e,n);return this.startPoint=o,o}createEndPoint(t,e,n){const o=this.createLinkerPoint(t,e,n);return this.endPoint=o,o}createLinkerPoint(t,e,n){const o={};if(e&&e.id){const r=e.getBoxPoint(t),{boxBounds:s}=e,a=n&&n.mode,d="edge"===a||!a,h="four"===a,c="free"===a;if(!("auto"===a))if(h)o.point=_.getDirection(r,s,h);else if(o.direction=_.getDirection(r,s,d),o.point=_.getPointDirection(r,s,d)||o.direction,o.point===o.direction&&delete o.direction,c||d){const t=i.getPoint(s,o.point),e=r.x-t.x,a=r.y-t.y,h=n&&n.snapRadius||10;if(Math.abs(e)>h||Math.abs(a)>h){const t=o.offset={x:Math.abs(e)>h?e:0,y:Math.abs(a)>h?a:0};if(d&&(t.x||t.y))switch(o.direction||o.point){case"top":case"bottom":t.y=0;break;case"right":case"left":t.x=0;break;default:t.x>t.y?t.y=0:t.x=0}}}o.id=e.id}else o.point=this.getLocalPoint(t);return o}};N([c(m)],z.prototype,"__",void 0),N([D()],z.prototype,"startPoint",void 0),N([D()],z.prototype,"endPoint",void 0),N([u({type:"C",value:.5})],z.prototype,"curve",void 0),z=N([l()],z);const{toNumberPoints:A}=b,{M:T,L:H,C:X,Z:Y}=L;P.add("linker"),k("C",function(t,e,n,o){const i=A(e),r=i.length>>1;if(r<2)return;if(t.push(T,i[0],i[1]),!n||r<3){for(let e=1;e<r;e++)t.push(H,i[2*e],i[2*e+1]);return void(o&&t.push(Y))}let s=!0===n?.5:n;s<0?s=0:s>1&&(s=1);const a=o?r:r-1;let d=i[0],h=i[1];{const t=i[2]-i[0],e=i[3]-i[1],n=Math.sqrt(t*t+e*e);n&&(d=i[0]+t/n*n*s,h=i[1]+e/n*n*s)}for(let e=0;e<a;e++){const n=e+1===r?0:e+1,o=i[2*n],a=i[2*n+1],c=0===n?r-1:n-1,u=n+1===r?0:n+1;let l=i[2*c]-o,p=i[2*c+1]-a,f=i[2*u]-o,y=i[2*u+1]-a;const g=Math.sqrt(l*l+p*p),x=Math.sqrt(f*f+y*y);let P=o,k=a,b=o,L=a;if(g||x){let t=0,e=0;g&&(t+=l/g,e+=p/g),x&&(t+=f/x,e+=y/x);let n=Math.sqrt(t*t+e*e);n||(x?(t=f/x,e=y/x):(t=l/g,e=p/g),n=1),t/=n,e/=n;let i=-e,r=t;x&&i*f+r*y<0&&(i=-i,r=-r);let d=0;g&&x&&(d=(l*f+p*y)/(g*x),d>1?d=1:d<-1&&(d=-1));let h=Math.sqrt(Math.sqrt(Math.max(0,1-d*d)));h<.15&&(h=.15);let c=g*s*h,u=x*s*h;const N=.5*Math.min(g||x,x||g);c>N&&(c=N),u>N&&(u=N),P=o-i*c,k=a-r*c,b=o+i*u,L=a+r*u}t.push(X,d,h,P,k,o,a),d=b,h=L}o&&t.push(Y)});export{z as Linker,m as LinkerData};
1
+ import{LineData as t,AroundHelper as e,PointHelper as n,Direction9 as i,BoundsHelper as o,decorateLeafAttr as r,attr as s,doBoundsType as a,doStrokeType as h,PathCommandDataHelper as c,dataProcessor as u,boundsType as d,pathType as l,registerUI as f,Line as y,BoundsEvent as x,LeafHelper as g,isString as p,isObject as b,Plugin as M,registerPointsCurve as m}from"@leafer-ui/draw";import{PointHelper as N,PathCommandMap as P}from"@leafer-ui/core";function k(t,e,n,i){var o,r=arguments.length,s=r<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(t,e,n,i);else for(var a=t.length-1;a>=0;a--)(o=t[a])&&(s=(r<3?o(s):r>3?o(e,n,s):o(e,n))||s);return r>3&&s&&Object.defineProperty(e,n,s),s}"function"==typeof SuppressedError&&SuppressedError;class L extends t{get __usePathBox(){return this.path||this.__pathInputed}}const{directionData:v}=e,C=["top-left","top","top-right","right","bottom-right","bottom","bottom-left","left","center"],_={getCtrlPoint(t,e,n,i,o,r){let s;switch(e&&(n=e.getBoxPoint(n,t)),i){case"left":case"top-left":case"bottom-left":s={x:n.x-o.x,y:n.y};break;case"top":s={x:n.x,y:n.y-o.y};break;case"right":case"top-right":case"bottom-right":s={x:n.x+o.x,y:n.y};break;case"bottom":s={x:n.x,y:n.y+o.y};break;default:s={x:n.x,y:n.y}}return r&&(r=r/180*Math.PI,s={x:(s.x-n.x)*Math.cos(r)-(s.y-n.y)*Math.sin(r)+n.x,y:(s.x-n.x)*Math.sin(r)+(s.y-n.y)*Math.cos(r)+n.y}),e&&e.getWorldPointByBox(s,t,void 0,!0),s},isOppositeDirection(t,e){switch(t){case"left":return"right"==e;case"top":return"bottom"==e;case"right":return"left"==e;case"bottom":return"top"==e;case"center":return"center"==e;default:return!1}},getDirectionForFromPoint(t,e){const n=t.x-e.x,i=t.y-e.y;let o,r=180*Math.atan2(i,n)/Math.PI;return r<0&&(r=360+r),o=r>315||r<45?"left":r>45&&r<135?"top":r>135&&r<225?"right":"bottom",o},getRotateDirection(t,e,n=8){let o=i[t];return o=(o+Math.round(e/(360/n)))%n,o<0&&(o+=n),C[o]},getDirection:function(t,e,n){const{width:i,height:r}=e,s=o.getPoint(e,"center",!0),a=t.x-s.x,h=t.y-s.y;if(!n&&Math.abs(a)<i/4&&Math.abs(h)<r/4)return"center";const c=Math.abs(a)*r,u=Math.abs(h)*i;if(c>u)return a>0?"right":"left";return h>0?"bottom":"top"},getPointDirection:function(t,e,n){const{width:i,height:o}=e,r=i/4,s=o/4;for(let e=0;e<v.length;e++){const a=v[e],h=a.x*i,c=a.y*o,u=t.x-h,d=t.y-c;if(Math.abs(u)<=r&&Math.abs(d)<=s){if(!n)return C[e];if("center"!==C[e])return C[e]}}return},autoRotatePoint(t,e,i){const{rotation:o,scaleX:r,scaleY:s}=i,a=r*s<0;(o||a)&&n.rotate(t,a?-o:o,e)}};function w(t){return r(t,t=>s({set(e){if(this.__setAttr(t,e)){const t=this.__layout;t.linkerChanged||(a(this),h(this),t.linkerChanged=!0)}}}))}const{directionData:D}=e,{moveTo:F,lineTo:B}=c,E=.001,R=1.5;function O(t,e,n,i,o){const r=D[function(t){switch(t){case"top-left":return 0;case"top":return 1;case"top-right":return 2;case"right":return 3;case"bottom-right":return 4;case"bottom":return 5;case"bottom-left":return 6;case"left":return 7;default:return 8}}(t)],s=Math.sign(r.x-.5),a=Math.sign(r.y-.5),h=i?i.x+i.width/2:e.x,c=i?i.y+i.height/2:e.y,u=(o?o.x+o.width/2:n.x)-h,d=(o?o.y+o.height/2:n.y)-c,l=(s||(u>=0?1:-1))>0?1:0,f=(a||(d>=0?1:-1))>0?3:2;return s&&!a?[l]:a&&!s?[f]:Math.abs(u)>=Math.abs(d)?[l,f]:[f,l]}function S(t,e,n,i){const o=1&n?1:-1;if(0===n>>1){return{x:(e?e.x+(o>0?e.width:0):t.x)+o*i,y:t.y}}const r=e?e.y+(o>0?e.height:0):t.y;return{x:t.x,y:r+o*i}}function T(t,e,n,i){if(!n)return!1;const o=n.x-i,r=n.x+n.width+i,s=n.y-i,a=n.y+n.height+i;return t>o+E&&t<r-E&&e>s+E&&e<a-E}function W(t,e,n,i,o,r){if(!o)return!1;const s=o.x-r,a=o.x+o.width+r,h=o.y-r,c=o.y+o.height+r;return Math.abs(e-i)<=E?e>h+E&&e<c-E&&Math.max(Math.min(t,n),s+E)<Math.min(Math.max(t,n),a-E):!(Math.abs(t-n)<=E)||t>s+E&&t<a-E&&Math.max(Math.min(e,i),h+E)<Math.min(Math.max(e,i),c-E)}function q(t,e,n,i,o){if(!n)return;const r=n.x-i,s=n.x+n.width+i,a=n.y-i,h=n.y+n.height+i;t.push(r,s,r-o,s+o),e.push(a,h,a-o,h+o)}function I(t){t.sort((t,e)=>t-e);let e=0;for(let n=0;n<t.length;n++)(!e||Math.abs(t[n]-t[e-1])>E)&&(t[e++]=t[n]);t.length=e}function A(t,e){for(let n=0;n<t.length;n++)if(Math.abs(t[n]-e)<=E)return n;return-1}function j(t,e,n,i){const o=t>>1?i:n,r=1&t?1:-1;return Math.abs(o)<=E?e>E:o*r>0}function z(t,e,n,i,o){return void 0===t||(0===o&&Math.abs(n/2)>E?j(t,e,n,0):1===o&&Math.abs(i/2)>E?j(t,e,0,i):Math.abs(n)<=E&&Math.abs(i)<=E||j(t,e,n,i))}function H(t,e){if(void 0===e)return!0;const n=t.length-2,i=t[n],o=t[n+1];for(let r=n-2;r>=0;r-=2){const n=t[r]-i,s=t[r+1]-o;if(Math.abs(n)>E||Math.abs(s)>E)return j(e,1,n,s)}return!0}function U(t,e,n,i,o,r,s,a,h,c){const u=S(e,r,i,a),d=void 0===o?n:S(n,s,o,a),{x:l,y:f}=u,{x:y,y:x}=d,g=Math.abs(l-e.x)+Math.abs(f-e.y),p=Math.abs(y-n.x)+Math.abs(x-n.y);if(W(e.x,e.y,l,f,s,a)||W(n.x,n.y,y,x,r,a))return 1/0;if(void 0===o&&(T(y,x,r,a)||T(y,x,s,a)))return 1/0;const b=void 0===o?i>>1:function(t,e,n,i,o,r){const s=t>>1;return s===e>>1&&(1&t?1:-1)==-(1&e?1:-1)?s:Math.abs(o-n)>=Math.abs(r-i)?0:1}(i,o,l,f,y,x),M=y-l,m=x-f;if(t.length=0,t.push(e.x,e.y,l,f),(!h||z(i,g,M,m,b)&&z(o,p,-M,-m,b))&&z(c,1,-M,-m,b)){const e=(l+y)/2,i=(f+x)/2;0===b?t.push(e,f,e,x):t.push(l,i,y,i),t.push(y,x,n.x,n.y);for(let e=4;e<t.length-2;e+=2)if(W(t[e-2],t[e-1],t[e],t[e+1],r,a)||W(t[e-2],t[e-1],t[e],t[e+1],s,a)){t.length=4;break}if(t.length>4&&H(t,c))return function(t,e){let n=0,i=0,o=-1;for(let e=2;e<t.length;e+=2){const r=t[e]-t[e-2],s=t[e+1]-t[e-1];if(Math.abs(r)<=E&&Math.abs(s)<=E)continue;const a=Math.abs(r)>E?0:1;n+=Math.abs(r)+Math.abs(s),-1!==o&&o!==a&&i++,o=a}return n+i*Math.max(e,4)*1.5}(t,a);t.length=4}const N=function(t,e,n,i,o,r,s,a,h,c,u,d,l){const{x:f,y:y}=e,{x:x,y:g}=n,p=2*Math.max(a,4),b=[f,x,(f+x)/2],M=[y,g,(y+g)/2];q(b,M,r,a,p),q(b,M,s,a,p),b.push(Math.min(...b)-2*p,Math.max(...b)+2*p),M.push(Math.min(...M)-2*p,Math.max(...M)+2*p),I(b),I(M);const m=b.length,N=M.length,P=A(b,f),k=A(M,y),L=A(b,x),v=A(M,g);if(P<0||k<0||L<0||v<0)return 1/0;const C=k*m+P,_=v*m+L,w=m*N*3,D=new Float64Array(w),F=new Int32Array(w),B=new Uint8Array(w);D.fill(1/0),F.fill(-1);const O=3*C;D[O]=0;const S=[O],z=Math.max(4,a*R),H=0===h?(f+x)/2:(y+g)/2;let U=-1,X=-1,Y=0,Z=0,G=0,J=0;const K=(t,e,n)=>{const h=b[t],f=M[e],y=e*m+t,x=h-Z,g=f-G;if(y===C)return;if(void 0!==l&&y===_&&!j(l,1,-x,-g))return;if(d&&(U===O&&!j(i,c,x,g)||void 0!==o&&y===_&&!j(o,u,-x,-g)))return;if(T(h,f,r,a)||T(h,f,s,a)||W(Z,G,h,f,r,a)||W(Z,G,h,f,s,a))return;const p=3*y+n;if(B[p])return;let N=J+(Math.abs(x)+Math.abs(g));if(Y&&Y!==n){N+=z;const t=1===Y?Z:G;Math.abs(t-H)>E&&(N+=2*z)}N<D[p]&&(D[p]===1/0&&S.push(p),D[p]=N,F[p]=U)};let Q=-1;for(;S.length;){let t=0,e=S[0];for(let n=1;n<S.length;n++){const i=S[n];(D[i]<D[e]||D[i]===D[e]&&i<e)&&(t=n,e=i)}if(S[t]=S[S.length-1],S.pop(),U=e,X=Math.floor(e/3),Y=e%3,J=D[e],B[e]=1,X===_){Q=e;break}const n=X%m,i=Math.floor(X/m);Z=b[n],G=M[i],n>0&&K(n-1,i,1),n<m-1&&K(n+1,i,1),i>0&&K(n,i-1,2),i<N-1&&K(n,i+1,2)}if(Q<0)return 1/0;const V=[];let $=Q;for(;$>=0;){const t=Math.floor($/3);if(V.push(b[t%m],M[Math.floor(t/m)]),$===O)break;$=F[$]}if($!==O)return 1/0;for(let e=V.length-4;e>=0;e-=2)t.push(V[e],V[e+1]);return D[Q]}(t,u,d,i,o,r,s,a,b,g,p,h,c);return N===1/0?N:(t.push(n.x,n.y),H(t,c)?N+g+p:1/0)}function X(t,e,n,i,o,r,s,a){const h=O(n,t,e,o,void 0===i?void 0:r),c=void 0===i?[void 0]:O(i,e,t,r,o);let u=[],d=[],l=1/0;for(let n=s?0:1;n<3&&!d.length;n++){const i=n?0:s;for(let s=0;s<h.length;s++)for(let f=0;f<c.length;f++){const y=U(u,t,e,h[s],c[f],o,r,i,n<2,a);if(y<l){l=y;const t=d;d=u,u=t}}}if(!d.length)return function(t,e,n,i,o){const{x:r,y:s}=t,{x:a,y:h}=e;if(r===a||s===h)return[r,s,a,h];const c=!(n>>1),u=(t,e)=>{let n=0;return W(r,s,t,e,i,0)&&n++,W(t,e,a,h,i,0)&&n++,W(r,s,t,e,o,0)&&n++,W(t,e,a,h,o,0)&&n++,n},d=u(a,s),l=u(r,h);return d<l||d===l&&c?[r,s,a,s,a,h]:[r,s,r,h,a,h]}(t,e,h[0],o,r);!function(t){let e=2;for(let n=2;n<t.length;n+=2){const i=t[n],o=t[n+1],r=t[e-2],s=t[e-1];if(!(Math.abs(i-r)<=E&&Math.abs(o-s)<=E)){if(e>=4){const n=t[e-4],a=t[e-3],h=Math.abs(a-s)<=E&&Math.abs(s-o)<=E&&(r-n)*(i-r)>=0,c=Math.abs(n-r)<=E&&Math.abs(r-i)<=E&&(s-a)*(o-s)>=0;if(h||c){t[e-2]=i,t[e-1]=o;continue}}t[e++]=i,t[e++]=o}}t.length=e}(d);const f=d.length-2;return d[f]===e.x&&d[f+1]===e.y||d.push(e.x,e.y),d}function Y(t,e,n,i,o,r,s,a,h){if(t.x===e.x&&t.y===e.y)return[];let c;for(let t=a+h;t>=0&&t<s.length;t+=h){const n=s[t]-e.x,i=s[t+1]-e.y;if(!(Math.abs(n)<=E&&Math.abs(i)<=E)){Math.abs(i)<=E?c=n>0?0:1:Math.abs(n)<=E&&(c=i>0?2:3);break}}const u=X(t,e,n,void 0,i,o,r,c);return u.length-=2,u}function Z(t,e,n,i,o,r,s,a=8,h){if(!(Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(n.x)&&Number.isFinite(n.y)))return!1;if(r&&(!Number.isFinite(r.x)||!Number.isFinite(r.y)||!Number.isFinite(r.width)||!Number.isFinite(r.height)||r.width<0||r.height<0))return!1;if(s&&(!Number.isFinite(s.x)||!Number.isFinite(s.y)||!Number.isFinite(s.width)||!Number.isFinite(s.height)||s.width<0||s.height<0))return!1;if(a=Number.isFinite(a)?Math.max(0,a):8,null==h?void 0:h.length)return function(t,e,n,i,o,r,s,a,h){const c=h.length,u=c-2;if(c%2)return!1;for(let t=0;t<c;t++)if(!Number.isFinite(h[t]))return!1;const d=Y(e,{x:h[0],y:h[1]},i,r,s,a,h,0,2),l=Y(n,{x:h[u],y:h[u+1]},o,s,r,a,h,u,-2),f=d.length?d:h;F(t,f[0],f[1]);for(let e=2;e<d.length;e+=2)B(t,d[e],d[e+1]);for(let e=d.length?0:2;e<c;e+=2)B(t,h[e],h[e+1]);for(let e=l.length-2;e>=0;e-=2)B(t,l[e],l[e+1]);return!0}(t,e,n,i,o,r,s,a,h);const c=X(e,n,i,o,r,s,a);F(t,c[0],c[1]);for(let e=2;e<c.length;e+=2)B(t,c[e],c[e+1]);return!0}const{moveTo:G,lineTo:J,bezierCurveTo:K,drawPoints:Q}=c,{isEmpty:V,getPoint:$}=o,{getDistance:tt}=n,{getCtrlPoint:et,getDirectionForFromPoint:nt,isOppositeDirection:it}=_,{max:ot,min:rt,abs:st}=Math;let at=class extends y{get __tag(){return"Linker"}constructor(t){super(t),this.onStartNodeChange=this.onStartNodeChange.bind(this),this.onEndNodeChange=this.onEndNodeChange.bind(this)}__updatePath(){const t=this.__layout,{startNode:e,endNode:n}=this;t.linkerChanged&&(this.updateLinkerNode("start"),this.updateLinkerNode("end"),this.updateLinkerPoint("start"),this.updateLinkerPoint("end"),e!==this.startNode&&this.listenLinkerNode(this.startNode,e,"start"),n!==this.endNode&&this.listenLinkerNode(this.endNode,n,"end"),t.linkerChanged=!1),this.updateLinkerPath()}listenLinkerNode(t,e,n){if(e){e.off(x.WORLD,"end"===n?this.onEndNodeChange:this.onStartNodeChange);const t="end"===n?e.endLinker:e.startLinker;if(t){const e=t.indexOf(this);e>-1&&t.splice(e,1)}}if(t){t.on(x.WORLD,"end"===n?this.onEndNodeChange:this.onStartNodeChange);("end"===n?t.endLinker||(t.endLinker=[]):t.startLinker||(t.startLinker=[])).push(this)}}onStartNodeChange(){this.onLinkerNodeChange("start")}onEndNodeChange(){this.onLinkerNodeChange("end")}onLinkerNodeChange(t){if(this.leaferIsCreated){const{layouter:t,zoomLayer:e}=this.leafer;if(t.__updatedList.has(e))return;t.addExtra(this,!0)}const{startData:e,endData:n}=this;"start"==t?(this.updateLinkerPoint("start"),n&&n.auto&&this.updateLinkerPoint("end")):(e&&e.auto&&this.updateLinkerPoint("start"),this.updateLinkerPoint("end")),this.__layout.boxChange(),g.updateBounds(this)}updateLinkerNode(t){const{startPoint:e,endPoint:n}=this,i="end"===t?n:e;if(i){const{id:e}=i,n=e&&(p(e)?this.app.findId(e):e);"end"===t?this.endNode=n:this.startNode=n}}getLinkerNodeCenter(t){const{startPoint:e,endPoint:n,startNode:i,endNode:o,startData:r,endData:s}=this,a="end"===t?o:i,h="end"===t?s||n:r||e;if(a){const{worldRenderBounds:t}=a;return V(t)&&g.updateBounds(a),$(a.worldRenderBounds,"center")}return h&&b(h.point)&&this.getWorldPointByLocal(h.point)}updateLinkerPoint(t){const{startPoint:e,endPoint:i,lineType:o}=this,r="end"===t?i:e;if(r){const e={},{id:i,offset:s}=r;let{direction:a,point:h}=r;if("center"===a||!a&&i&&!h){const n=this.getLinkerNodeCenter("start"),i=this.getLinkerNodeCenter("end"),o="end"===t?i:n,r="end"===t?n:i;o&&r&&(a=nt(o,r)),e.auto=!0}!a&&p(h)&&(a=h),e.direction=a;const c="end"===t?this.endNode:this.startNode;let u;if(c){if(h||(h=a),h){const{boxBounds:t}=c;V(t)&&g.updateBounds(c),u=$(t,h,!0),c.getWorldPointByBox(u,this,!1,!0),"polyline"===o&&(e.bounds=c.getBounds("box",this.parent))}}else b(h)&&(u=h);if(u&&s){const t=Object.assign({},s);s.x||(t.x=0),s.y||(t.y=0),c&&c.getWorldPoint(t,this,!0,!0),n.move(u,t)}e.point=u,"end"===t?this.endData=u&&e:this.startData=u&&e}}updateLinkerPath(){const t=this.__,e=t.path=[],i=t.points&&t.points.length,{startData:o,endData:r,startNode:s,endNode:a}=this;if(!o||!r)return;const h=o.point,c=r.point,u=o.direction,d=r.direction,l=8*this.__.strokeWidth;switch(t.lineType){case"straight":G(e,h.x,h.y),J(e,c.x,c.y);break;case"polyline":Z(e,h,c,u,d,o.bounds,r.bounds,l,i&&n.toNumberPoints(t.points));break;default:const f={x:st((h.x-c.x)/2),y:st((h.y-c.y)/2)};let y;if(this.__.__useArrow){const t=rt(tt(h,c)/(25*l),1);y=ot(l*t*12,3*l)}else y=2*l;if(d&&it(u,d)&&u===nt(h,c)&&(y=2*l),f.x=ot(y,f.x),f.y=ot(y,f.y),i){y*=.6;const i=n.toNumberPoints(t.points);if(Q(e,[h.x,h.y,...i,c.x,c.y],t.curve,!1,t),u){const t=e[4],n=e[5];f.x=ot(y,st(t-h.x)),f.y=ot(y,st(n-h.y));const i=et(this,s,h,u,f);e[4]=i.x,e[5]=i.y}const o=e.length;if(d){const t=e[o-4],n=e[o-3];f.x=ot(y,st(t-c.x)),f.y=ot(y,st(n-c.y));const i=et(this,a,c,d,f);e[o-4]=i.x,e[o-3]=i.y}else e[o-4]=c.x,e[o-3]=c.y}else{const t=u?et(this,s,h,u,f):h,n=d?et(this,a,c,d,f):c;G(e,h.x,h.y),K(e,t.x,t.y,n.x,n.y,c.x,c.y)}}}createStartPoint(t,e,n){const i=this.createLinkerPoint(t,e,n);return this.startPoint=i,i}createEndPoint(t,e,n){const i=this.createLinkerPoint(t,e,n);return this.endPoint=i,i}createLinkerPoint(t,e,n){const i={};if(e&&e.id){const r=e.getBoxPoint(t),{boxBounds:s}=e,a=n&&n.mode,h="edge"===a||!a,c="four"===a,u="free"===a;if(!("auto"===a))if(c)i.point=_.getDirection(r,s,c);else if(i.direction=_.getDirection(r,s,h),i.point=_.getPointDirection(r,s,h)||i.direction,i.point===i.direction&&delete i.direction,u||h){const t=o.getPoint(s,i.point),e=r.x-t.x,a=r.y-t.y,c=n&&n.snapRadius||10;if(Math.abs(e)>c||Math.abs(a)>c){const t=i.offset={x:Math.abs(e)>c?e:0,y:Math.abs(a)>c?a:0};if(h&&(t.x||t.y))switch(i.direction||i.point){case"top":case"bottom":t.y=0;break;case"right":case"left":t.x=0;break;default:t.x>t.y?t.y=0:t.x=0}}}i.id=e.id}else i.point=this.getLocalPoint(t);return i}};k([u(L)],at.prototype,"__",void 0),k([d("curve")],at.prototype,"lineType",void 0),k([w()],at.prototype,"startPoint",void 0),k([w()],at.prototype,"endPoint",void 0),k([l({type:"C",value:.5})],at.prototype,"curve",void 0),at=k([f()],at);const{toNumberPoints:ht}=N,{M:ct,L:ut,C:dt,Z:lt}=P;M.add("linker"),m("C",function(t,e,n,i){const o=ht(e),r=o.length>>1;if(r<2)return;if(t.push(ct,o[0],o[1]),!n||r<3){for(let e=1;e<r;e++)t.push(ut,o[2*e],o[2*e+1]);return void(i&&t.push(lt))}let s=!0===n?.5:n;s<0?s=0:s>1&&(s=1);const a=i?r:r-1;let h=o[0],c=o[1];{const t=o[2]-o[0],e=o[3]-o[1],n=Math.sqrt(t*t+e*e);n&&(h=o[0]+t/n*n*s,c=o[1]+e/n*n*s)}for(let e=0;e<a;e++){const n=e+1===r?0:e+1,i=o[2*n],a=o[2*n+1],u=0===n?r-1:n-1,d=n+1===r?0:n+1;let l=o[2*u]-i,f=o[2*u+1]-a,y=o[2*d]-i,x=o[2*d+1]-a;const g=Math.sqrt(l*l+f*f),p=Math.sqrt(y*y+x*x);let b=i,M=a,m=i,N=a;if(g||p){let t=0,e=0;g&&(t+=l/g,e+=f/g),p&&(t+=y/p,e+=x/p);let n=Math.sqrt(t*t+e*e);n||(p?(t=y/p,e=x/p):(t=l/g,e=f/g),n=1),t/=n,e/=n;let o=-e,r=t;p&&o*y+r*x<0&&(o=-o,r=-r);let h=0;g&&p&&(h=(l*y+f*x)/(g*p),h>1?h=1:h<-1&&(h=-1));let c=Math.sqrt(Math.sqrt(Math.max(0,1-h*h)));c<.15&&(c=.15);let u=g*s*c,d=p*s*c;const P=.5*Math.min(g||p,p||g);u>P&&(u=P),d>P&&(d=P),b=i-o*u,M=a-r*u,m=i+o*d,N=a+r*d}t.push(dt,h,c,b,M,i,a),h=m,c=N}i&&t.push(lt)});export{at as Linker,L as LinkerData};
2
2
  //# sourceMappingURL=linker.esm.min.js.map