@joint/core 4.0.0 → 4.0.2
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 +124 -5
- package/dist/geometry.js +1 -1
- package/dist/geometry.min.js +1 -1
- package/dist/joint.d.ts +23 -13
- package/dist/joint.js +543 -198
- package/dist/joint.min.js +2 -2
- package/dist/joint.nowrap.js +543 -198
- package/dist/joint.nowrap.min.js +2 -2
- package/dist/vectorizer.js +5 -1
- package/dist/vectorizer.min.js +2 -2
- package/dist/version.mjs +1 -1
- package/package.json +1 -2
- package/src/V/index.mjs +4 -0
- package/src/core.mjs +48 -0
- package/src/dia/Paper.mjs +2 -0
- package/src/dia/attributes/text.mjs +8 -4
- package/src/routers/rightAngle.mjs +486 -153
- package/types/joint.d.ts +22 -12
|
@@ -88,8 +88,14 @@ function resolveForTopSourceSide(source, target, nextInLine) {
|
|
|
88
88
|
const { x0: tx, y0: ty } = target;
|
|
89
89
|
|
|
90
90
|
if (tx === ax && ty < sy0) return Directions.BOTTOM;
|
|
91
|
-
if (tx < ax && ty < smy0)
|
|
92
|
-
|
|
91
|
+
if (tx < ax && ty < smy0) {
|
|
92
|
+
if (nextInLine.point.x === ax) return Directions.BOTTOM;
|
|
93
|
+
return Directions.RIGHT;
|
|
94
|
+
}
|
|
95
|
+
if (tx > ax && ty < smy0) {
|
|
96
|
+
if (nextInLine.point.x === ax) return Directions.BOTTOM;
|
|
97
|
+
return Directions.LEFT;
|
|
98
|
+
}
|
|
93
99
|
if (tx < smx0 && ty >= sy0) return Directions.TOP;
|
|
94
100
|
if (tx > smx1 && ty >= sy0) return Directions.TOP;
|
|
95
101
|
if (tx >= smx0 && tx <= ax && ty > sy1) {
|
|
@@ -122,8 +128,14 @@ function resolveForBottomSourceSide(source, target, nextInLine) {
|
|
|
122
128
|
const { x0: tx, y0: ty } = target;
|
|
123
129
|
|
|
124
130
|
if (tx === ax && ty > sy1) return Directions.TOP;
|
|
125
|
-
if (tx < ax && ty > smy1)
|
|
126
|
-
|
|
131
|
+
if (tx < ax && ty > smy1) {
|
|
132
|
+
if (nextInLine.point.x === ax) return Directions.TOP;
|
|
133
|
+
return Directions.RIGHT;
|
|
134
|
+
}
|
|
135
|
+
if (tx > ax && ty > smy1) {
|
|
136
|
+
if (nextInLine.point.x === ax) return Directions.TOP;
|
|
137
|
+
return Directions.LEFT;
|
|
138
|
+
}
|
|
127
139
|
if (tx < smx0 && ty <= sy1) return Directions.BOTTOM;
|
|
128
140
|
if (tx > smx1 && ty <= sy1) return Directions.BOTTOM;
|
|
129
141
|
if (tx >= smx0 && tx <= ax && ty < sy0) {
|
|
@@ -314,17 +326,16 @@ function getOutsidePoint(side, pointData, margin) {
|
|
|
314
326
|
return outsidePoint;
|
|
315
327
|
}
|
|
316
328
|
|
|
317
|
-
function routeBetweenPoints(source, target) {
|
|
318
|
-
const { point: sourcePoint, x0: sx0, y0: sy0,
|
|
329
|
+
function routeBetweenPoints(source, target, opt = {}) {
|
|
330
|
+
const { point: sourcePoint, x0: sx0, y0: sy0, width: sourceWidth, height: sourceHeight, margin: sourceMargin } = source;
|
|
319
331
|
const { point: targetPoint, x0: tx0, y0: ty0, width: targetWidth, height: targetHeight, margin: targetMargin } = target;
|
|
332
|
+
const { targetInSourceBBox = false } = opt;
|
|
320
333
|
|
|
321
334
|
const tx1 = tx0 + targetWidth;
|
|
322
335
|
const ty1 = ty0 + targetHeight;
|
|
323
336
|
const sx1 = sx0 + sourceWidth;
|
|
324
337
|
const sy1 = sy0 + sourceHeight;
|
|
325
338
|
|
|
326
|
-
const isSourceEl = sourceView && sourceView.model.isElement();
|
|
327
|
-
|
|
328
339
|
// Key coordinates including the margin
|
|
329
340
|
const smx0 = sx0 - sourceMargin;
|
|
330
341
|
const smx1 = sx1 + sourceMargin;
|
|
@@ -350,10 +361,15 @@ function routeBetweenPoints(source, target) {
|
|
|
350
361
|
const middleOfVerticalSides = (scx < tcx ? (sx1 + tx0) : (tx1 + sx0)) / 2;
|
|
351
362
|
const middleOfHorizontalSides = (scy < tcy ? (sy1 + ty0) : (ty1 + sy0)) / 2;
|
|
352
363
|
|
|
364
|
+
const sourceBBox = new g.Rect(sx0, sy0, sourceWidth, sourceHeight);
|
|
365
|
+
const targetBBox = new g.Rect(tx0, ty0, targetWidth, targetHeight);
|
|
366
|
+
const inflatedSourceBBox = sourceBBox.clone().inflate(sourceMargin);
|
|
367
|
+
const inflatedTargetBBox = targetBBox.clone().inflate(targetMargin);
|
|
368
|
+
|
|
353
369
|
if (sourceSide === 'left' && targetSide === 'right') {
|
|
354
370
|
if (smx0 <= tmx1) {
|
|
355
371
|
let y = middleOfHorizontalSides;
|
|
356
|
-
if (
|
|
372
|
+
if (sox <= tmx0) {
|
|
357
373
|
if (ty1 >= smy0 && toy < soy) {
|
|
358
374
|
y = Math.min(tmy0, smy0);
|
|
359
375
|
} else if (ty0 <= smy1 && toy >= soy) {
|
|
@@ -374,7 +390,7 @@ function routeBetweenPoints(source, target) {
|
|
|
374
390
|
{ x, y: toy }
|
|
375
391
|
];
|
|
376
392
|
} else if (sourceSide === 'right' && targetSide === 'left') {
|
|
377
|
-
if (
|
|
393
|
+
if (sox >= tmx0) {
|
|
378
394
|
let y = middleOfHorizontalSides;
|
|
379
395
|
if (sox > tx1) {
|
|
380
396
|
if (ty1 >= smy0 && toy < soy) {
|
|
@@ -398,16 +414,20 @@ function routeBetweenPoints(source, target) {
|
|
|
398
414
|
{ x, y: toy }
|
|
399
415
|
];
|
|
400
416
|
} else if (sourceSide === 'top' && targetSide === 'bottom') {
|
|
417
|
+
const isPointInsideSource = g.intersection.rectWithRect(inflatedSourceBBox, targetBBox);
|
|
418
|
+
|
|
401
419
|
if (soy < toy) {
|
|
402
420
|
let x = middleOfVerticalSides;
|
|
403
421
|
let y = soy;
|
|
404
422
|
|
|
405
|
-
if (
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
423
|
+
if (isPointInsideSource) {
|
|
424
|
+
y = Math.min(y, tmy0);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (tx1 >= smx0 && tox < sox) {
|
|
428
|
+
x = Math.min(tmx0, smx0);
|
|
429
|
+
} else if (tx0 <= smx1 && tox >= sox) {
|
|
430
|
+
x = Math.max(tmx1, smx1);
|
|
411
431
|
}
|
|
412
432
|
|
|
413
433
|
return [
|
|
@@ -423,16 +443,20 @@ function routeBetweenPoints(source, target) {
|
|
|
423
443
|
{ x: tox, y }
|
|
424
444
|
];
|
|
425
445
|
} else if (sourceSide === 'bottom' && targetSide === 'top') {
|
|
426
|
-
|
|
446
|
+
const isPointInsideSource = g.intersection.rectWithRect(inflatedSourceBBox, targetBBox);
|
|
447
|
+
|
|
448
|
+
if (soy > toy) {
|
|
427
449
|
let x = middleOfVerticalSides;
|
|
428
450
|
let y = soy;
|
|
429
451
|
|
|
430
|
-
if (
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
452
|
+
if (isPointInsideSource) {
|
|
453
|
+
y = Math.max(y, tmy1);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (tx1 >= smx0 && tox < sox) {
|
|
457
|
+
x = Math.min(tmx0, smx0);
|
|
458
|
+
} else if (tx0 <= smx1 && tox >= sox) {
|
|
459
|
+
x = Math.max(tmx1, smx1);
|
|
436
460
|
}
|
|
437
461
|
|
|
438
462
|
return [
|
|
@@ -448,28 +472,31 @@ function routeBetweenPoints(source, target) {
|
|
|
448
472
|
{ x: tox, y }
|
|
449
473
|
];
|
|
450
474
|
} else if (sourceSide === 'top' && targetSide === 'top') {
|
|
475
|
+
const useUShapeConnection =
|
|
476
|
+
targetInSourceBBox ||
|
|
477
|
+
g.intersection.rectWithRect(inflatedSourceBBox, targetBBox) ||
|
|
478
|
+
(soy <= ty0 && (inflatedSourceBBox.bottomRight().x <= tox || inflatedSourceBBox.bottomLeft().x >= tox)) ||
|
|
479
|
+
(soy >= ty0 && (inflatedTargetBBox.bottomRight().x <= sox || inflatedTargetBBox.bottomLeft().x >= sox));
|
|
480
|
+
|
|
481
|
+
if (useUShapeConnection) {
|
|
482
|
+
return [
|
|
483
|
+
{ x: sox, y: Math.min(soy, toy) },
|
|
484
|
+
{ x: tox, y: Math.min(soy, toy) }
|
|
485
|
+
];
|
|
486
|
+
}
|
|
487
|
+
|
|
451
488
|
let x;
|
|
452
489
|
let y1 = Math.min((sy1 + ty0) / 2, toy);
|
|
453
490
|
let y2 = Math.min((sy0 + ty1) / 2, soy);
|
|
454
491
|
|
|
455
492
|
if (toy < soy) {
|
|
456
|
-
if (
|
|
457
|
-
return [
|
|
458
|
-
{ x: sox, y: Math.min(soy, toy) },
|
|
459
|
-
{ x: tox, y: Math.min(soy, toy) }
|
|
460
|
-
];
|
|
461
|
-
} else if (tox > sox) {
|
|
493
|
+
if (tox > sox) {
|
|
462
494
|
x = Math.min(sox, tmx0);
|
|
463
495
|
} else {
|
|
464
496
|
x = Math.max(sox, tmx1);
|
|
465
497
|
}
|
|
466
498
|
} else {
|
|
467
|
-
if (tox >=
|
|
468
|
-
return [
|
|
469
|
-
{ x: sox, y: Math.min(soy, toy) },
|
|
470
|
-
{ x: tox, y: Math.min(soy, toy) }
|
|
471
|
-
];
|
|
472
|
-
} else if (tox >= sox) {
|
|
499
|
+
if (tox >= sox) {
|
|
473
500
|
x = Math.max(tox, smx1);
|
|
474
501
|
} else {
|
|
475
502
|
x = Math.min(tox, smx0);
|
|
@@ -483,28 +510,31 @@ function routeBetweenPoints(source, target) {
|
|
|
483
510
|
{ x: tox, y: y1 }
|
|
484
511
|
];
|
|
485
512
|
} else if (sourceSide === 'bottom' && targetSide === 'bottom') {
|
|
513
|
+
const useUShapeConnection =
|
|
514
|
+
targetInSourceBBox ||
|
|
515
|
+
g.intersection.rectWithRect(inflatedSourceBBox, targetBBox) ||
|
|
516
|
+
(soy >= toy && (inflatedSourceBBox.topRight().x <= tox || inflatedSourceBBox.topLeft().x >= tox)) ||
|
|
517
|
+
(soy <= toy && (inflatedTargetBBox.topRight().x <= sox || inflatedTargetBBox.topLeft().x >= sox));
|
|
518
|
+
|
|
519
|
+
if (useUShapeConnection) {
|
|
520
|
+
return [
|
|
521
|
+
{ x: sox, y: Math.max(soy, toy) },
|
|
522
|
+
{ x: tox, y: Math.max(soy, toy) }
|
|
523
|
+
];
|
|
524
|
+
}
|
|
525
|
+
|
|
486
526
|
let x;
|
|
487
527
|
let y1 = Math.max((sy0 + ty1) / 2, toy);
|
|
488
528
|
let y2 = Math.max((sy1 + ty0) / 2, soy);
|
|
489
529
|
|
|
490
530
|
if (toy > soy) {
|
|
491
|
-
if (
|
|
492
|
-
return [
|
|
493
|
-
{ x: sox, y: Math.max(soy, toy) },
|
|
494
|
-
{ x: tox, y: Math.max(soy, toy) }
|
|
495
|
-
];
|
|
496
|
-
} else if (tox > sox) {
|
|
531
|
+
if (tox > sox) {
|
|
497
532
|
x = Math.min(sox, tmx0);
|
|
498
533
|
} else {
|
|
499
534
|
x = Math.max(sox, tmx1);
|
|
500
535
|
}
|
|
501
536
|
} else {
|
|
502
|
-
if (tox >=
|
|
503
|
-
return [
|
|
504
|
-
{ x: sox, y: Math.max(soy, toy) },
|
|
505
|
-
{ x: tox, y: Math.max(soy, toy) }
|
|
506
|
-
];
|
|
507
|
-
} else if (tox >= sox) {
|
|
537
|
+
if (tox >= sox) {
|
|
508
538
|
x = Math.max(tox, smx1);
|
|
509
539
|
} else {
|
|
510
540
|
x = Math.min(tox, smx0);
|
|
@@ -518,6 +548,19 @@ function routeBetweenPoints(source, target) {
|
|
|
518
548
|
{ x: tox, y: y1 }
|
|
519
549
|
];
|
|
520
550
|
} else if (sourceSide === 'left' && targetSide === 'left') {
|
|
551
|
+
const useUShapeConnection =
|
|
552
|
+
targetInSourceBBox ||
|
|
553
|
+
g.intersection.rectWithRect(inflatedSourceBBox, targetBBox) ||
|
|
554
|
+
(sox <= tox && (inflatedSourceBBox.bottomRight().y <= toy || inflatedSourceBBox.topRight().y >= toy)) ||
|
|
555
|
+
(sox >= tox && (inflatedTargetBBox.bottomRight().y <= soy || inflatedTargetBBox.topRight().y >= soy));
|
|
556
|
+
|
|
557
|
+
if (useUShapeConnection) {
|
|
558
|
+
return [
|
|
559
|
+
{ x: Math.min(sox, tox), y: soy },
|
|
560
|
+
{ x: Math.min(sox, tox), y: toy }
|
|
561
|
+
];
|
|
562
|
+
}
|
|
563
|
+
|
|
521
564
|
let y;
|
|
522
565
|
let x1 = Math.min((sx1 + tx0) / 2, tox);
|
|
523
566
|
let x2 = Math.min((sx0 + tx1) / 2, sox);
|
|
@@ -543,11 +586,24 @@ function routeBetweenPoints(source, target) {
|
|
|
543
586
|
{ x: x1, y: toy }
|
|
544
587
|
];
|
|
545
588
|
} else if (sourceSide === 'right' && targetSide === 'right') {
|
|
589
|
+
const useUShapeConnection =
|
|
590
|
+
targetInSourceBBox ||
|
|
591
|
+
g.intersection.rectWithRect(inflatedSourceBBox, targetBBox) ||
|
|
592
|
+
(sox >= tox && (inflatedSourceBBox.bottomLeft().y <= toy || inflatedSourceBBox.topLeft().y >= toy)) ||
|
|
593
|
+
(sox <= tox && (inflatedTargetBBox.bottomLeft().y <= soy || inflatedTargetBBox.topLeft().y >= soy));
|
|
594
|
+
|
|
595
|
+
if (useUShapeConnection) {
|
|
596
|
+
return [
|
|
597
|
+
{ x: Math.max(sox, tox), y: soy },
|
|
598
|
+
{ x: Math.max(sox, tox), y: toy }
|
|
599
|
+
];
|
|
600
|
+
}
|
|
601
|
+
|
|
546
602
|
let y;
|
|
547
603
|
let x1 = Math.max((sx0 + tx1) / 2, tox);
|
|
548
604
|
let x2 = Math.max((sx1 + tx0) / 2, sox);
|
|
549
605
|
|
|
550
|
-
if (tox
|
|
606
|
+
if (tox <= sox) {
|
|
551
607
|
if (toy <= soy) {
|
|
552
608
|
y = Math.min(smy0, toy);
|
|
553
609
|
} else {
|
|
@@ -568,13 +624,41 @@ function routeBetweenPoints(source, target) {
|
|
|
568
624
|
{ x: x1, y: toy }
|
|
569
625
|
];
|
|
570
626
|
} else if (sourceSide === 'top' && targetSide === 'right') {
|
|
571
|
-
|
|
627
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
628
|
+
|
|
629
|
+
// The target point is inside the source element
|
|
630
|
+
if (isPointInsideSource) {
|
|
631
|
+
if (sox <= tmx1) {
|
|
632
|
+
const x = Math.max(sox + sourceMargin, tox);
|
|
633
|
+
const y = Math.min(smy0, tmy0);
|
|
634
|
+
|
|
635
|
+
// Target anchor is on the right side of the source anchor
|
|
636
|
+
return [
|
|
637
|
+
{ x: sox, y },
|
|
638
|
+
{ x: x, y },
|
|
639
|
+
{ x: x, y: toy }
|
|
640
|
+
];
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Target anchor is on the left side of the source anchor
|
|
644
|
+
// Subtract the `sourceMargin` since the source anchor is on the right side of the target anchor
|
|
645
|
+
const anchorMiddleX = (sox - sourceMargin + tox) / 2;
|
|
646
|
+
|
|
647
|
+
return [
|
|
648
|
+
{ x: sox, y: soy },
|
|
649
|
+
{ x: anchorMiddleX, y: soy },
|
|
650
|
+
{ x: anchorMiddleX, y: toy }
|
|
651
|
+
];
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (smy0 > toy) {
|
|
572
655
|
if (sox < tox) {
|
|
573
|
-
let y =
|
|
656
|
+
let y = tmy0;
|
|
574
657
|
|
|
575
|
-
if (
|
|
576
|
-
y =
|
|
658
|
+
if (tmy1 <= smy0 && tmx1 >= sox) {
|
|
659
|
+
y = middleOfHorizontalSides;
|
|
577
660
|
}
|
|
661
|
+
|
|
578
662
|
return [
|
|
579
663
|
{ x: sox, y },
|
|
580
664
|
{ x: tox, y },
|
|
@@ -587,17 +671,17 @@ function routeBetweenPoints(source, target) {
|
|
|
587
671
|
|
|
588
672
|
const x = Math.max(middleOfVerticalSides, tmx1);
|
|
589
673
|
|
|
590
|
-
if (
|
|
674
|
+
if (sox > tox && sy1 >= toy) {
|
|
591
675
|
return [
|
|
592
676
|
{ x: sox, y: soy },
|
|
593
|
-
{ x
|
|
594
|
-
{ x
|
|
677
|
+
{ x, y: soy },
|
|
678
|
+
{ x, y: toy }
|
|
595
679
|
];
|
|
596
680
|
}
|
|
597
681
|
|
|
598
|
-
if (
|
|
599
|
-
const y = Math.min(
|
|
600
|
-
const x = Math.max(
|
|
682
|
+
if (x > smx0 && soy < ty1) {
|
|
683
|
+
const y = Math.min(smy0, tmy0);
|
|
684
|
+
const x = Math.max(smx1, tmx1);
|
|
601
685
|
return [
|
|
602
686
|
{ x: sox, y },
|
|
603
687
|
{ x, y },
|
|
@@ -607,23 +691,52 @@ function routeBetweenPoints(source, target) {
|
|
|
607
691
|
|
|
608
692
|
return [
|
|
609
693
|
{ x: sox, y: soy },
|
|
610
|
-
{ x
|
|
611
|
-
{ x
|
|
694
|
+
{ x, y: soy },
|
|
695
|
+
{ x, y: toy }
|
|
612
696
|
];
|
|
613
697
|
} else if (sourceSide === 'top' && targetSide === 'left') {
|
|
614
|
-
|
|
698
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
699
|
+
|
|
700
|
+
// The target point is inside the source element
|
|
701
|
+
if (isPointInsideSource) {
|
|
702
|
+
if (sox >= tmx0) {
|
|
703
|
+
const x = Math.min(sox - sourceMargin, tox);
|
|
704
|
+
const y = Math.min(smy0, tmy0);
|
|
705
|
+
|
|
706
|
+
// Target anchor is on the left side of the source anchor
|
|
707
|
+
return [
|
|
708
|
+
{ x: sox, y },
|
|
709
|
+
{ x: x, y },
|
|
710
|
+
{ x: x, y: toy }
|
|
711
|
+
];
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Target anchor is on the right side of the source anchor
|
|
715
|
+
// Add the `sourceMargin` since the source anchor is on the left side of the target anchor
|
|
716
|
+
const anchorMiddleX = (sox + sourceMargin + tox) / 2;
|
|
717
|
+
|
|
718
|
+
return [
|
|
719
|
+
{ x: sox, y: soy },
|
|
720
|
+
{ x: anchorMiddleX, y: soy },
|
|
721
|
+
{ x: anchorMiddleX, y: toy }
|
|
722
|
+
];
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if (smy0 > toy) {
|
|
615
726
|
if (sox > tox) {
|
|
616
|
-
let y =
|
|
727
|
+
let y = tmy0;
|
|
617
728
|
|
|
618
|
-
if (
|
|
619
|
-
y =
|
|
729
|
+
if (tmy1 <= smy0 && tmx0 <= sox) {
|
|
730
|
+
y = middleOfHorizontalSides;
|
|
620
731
|
}
|
|
732
|
+
|
|
621
733
|
return [
|
|
622
734
|
{ x: sox, y },
|
|
623
735
|
{ x: tox, y },
|
|
624
736
|
{ x: tox, y: toy }
|
|
625
737
|
];
|
|
626
738
|
}
|
|
739
|
+
|
|
627
740
|
return [{ x: sox, y: toy }];
|
|
628
741
|
}
|
|
629
742
|
|
|
@@ -645,39 +758,77 @@ function routeBetweenPoints(source, target) {
|
|
|
645
758
|
{ x, y: toy }
|
|
646
759
|
];
|
|
647
760
|
}
|
|
761
|
+
|
|
648
762
|
return [
|
|
649
763
|
{ x: sox, y: soy },
|
|
650
764
|
{ x, y: soy },
|
|
651
765
|
{ x, y: toy }
|
|
652
766
|
];
|
|
653
767
|
} else if (sourceSide === 'bottom' && targetSide === 'right') {
|
|
654
|
-
|
|
768
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
769
|
+
|
|
770
|
+
// The target point is inside the source element
|
|
771
|
+
if (isPointInsideSource) {
|
|
772
|
+
if (sox <= tmx1) {
|
|
773
|
+
const x = Math.max(sox + sourceMargin, tox);
|
|
774
|
+
const y = Math.max(smy1, tmy1);
|
|
775
|
+
|
|
776
|
+
// Target anchor is on the right side of the source anchor
|
|
777
|
+
return [
|
|
778
|
+
{ x: sox, y },
|
|
779
|
+
{ x, y },
|
|
780
|
+
{ x, y: toy }
|
|
781
|
+
];
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// Target anchor is on the left side of the source anchor
|
|
785
|
+
// Subtract the `sourceMargin` since the source anchor is on the right side of the target anchor
|
|
786
|
+
const anchorMiddleX = (sox - sourceMargin + tox) / 2;
|
|
787
|
+
|
|
788
|
+
return [
|
|
789
|
+
{ x: sox, y: soy },
|
|
790
|
+
{ x: anchorMiddleX, y: soy },
|
|
791
|
+
{ x: anchorMiddleX, y: toy }
|
|
792
|
+
];
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (smy1 < toy) {
|
|
655
796
|
if (sox < tox) {
|
|
656
|
-
let y =
|
|
797
|
+
let y = tmy1;
|
|
657
798
|
|
|
658
|
-
if (
|
|
659
|
-
y =
|
|
799
|
+
if (tmy0 >= smy1 && tmx1 >= sox) {
|
|
800
|
+
y = middleOfHorizontalSides;
|
|
660
801
|
}
|
|
802
|
+
|
|
661
803
|
return [
|
|
662
804
|
{ x: sox, y },
|
|
663
805
|
{ x: tox, y },
|
|
664
806
|
{ x: tox, y: toy }
|
|
665
807
|
];
|
|
666
808
|
}
|
|
809
|
+
|
|
667
810
|
return [{ x: sox, y: toy }];
|
|
668
|
-
} else {
|
|
669
|
-
if (sx0 < tox) {
|
|
670
|
-
const y = Math.max(smy1, tmy1);
|
|
671
|
-
const x = Math.max(smx1, tmx1);
|
|
672
|
-
return [
|
|
673
|
-
{ x: sox, y },
|
|
674
|
-
{ x, y },
|
|
675
|
-
{ x, y: toy }
|
|
676
|
-
];
|
|
677
|
-
}
|
|
678
811
|
}
|
|
679
812
|
|
|
680
|
-
const x = middleOfVerticalSides;
|
|
813
|
+
const x = Math.max(middleOfVerticalSides, tmx1);
|
|
814
|
+
|
|
815
|
+
if (sox > tox && sy0 <= toy) {
|
|
816
|
+
return [
|
|
817
|
+
{ x: sox, y: soy },
|
|
818
|
+
{ x, y: soy },
|
|
819
|
+
{ x, y: toy }
|
|
820
|
+
];
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (x > smx0 && soy > ty0) {
|
|
824
|
+
const y = Math.max(smy1, tmy1);
|
|
825
|
+
const x = Math.max(smx1, tmx1);
|
|
826
|
+
return [
|
|
827
|
+
{ x: sox, y },
|
|
828
|
+
{ x, y },
|
|
829
|
+
{ x, y: toy }
|
|
830
|
+
];
|
|
831
|
+
}
|
|
681
832
|
|
|
682
833
|
return [
|
|
683
834
|
{ x: sox, y: soy },
|
|
@@ -685,58 +836,123 @@ function routeBetweenPoints(source, target) {
|
|
|
685
836
|
{ x, y: toy }
|
|
686
837
|
];
|
|
687
838
|
} else if (sourceSide === 'bottom' && targetSide === 'left') {
|
|
688
|
-
|
|
839
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
840
|
+
|
|
841
|
+
// The target point is inside the source element
|
|
842
|
+
if (isPointInsideSource) {
|
|
843
|
+
if (sox >= tmx0) {
|
|
844
|
+
const x = Math.min(sox - sourceMargin, tox);
|
|
845
|
+
const y = Math.max(smy1, tmy1);
|
|
846
|
+
|
|
847
|
+
// Target anchor is on the left side of the source anchor
|
|
848
|
+
return [
|
|
849
|
+
{ x: sox, y },
|
|
850
|
+
{ x, y },
|
|
851
|
+
{ x, y: toy }
|
|
852
|
+
];
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Target anchor is on the right side of the source anchor
|
|
856
|
+
// Add the `sourceMargin` since the source anchor is on the left side of the target anchor
|
|
857
|
+
const anchorMiddleX = (sox + sourceMargin + tox) / 2;
|
|
858
|
+
|
|
859
|
+
return [
|
|
860
|
+
{ x: sox, y: soy },
|
|
861
|
+
{ x: anchorMiddleX, y: soy },
|
|
862
|
+
{ x: anchorMiddleX, y: toy }
|
|
863
|
+
];
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
if (smy1 < toy) {
|
|
689
867
|
if (sox > tox) {
|
|
690
|
-
let y =
|
|
868
|
+
let y = tmy1;
|
|
691
869
|
|
|
692
|
-
if (
|
|
693
|
-
y =
|
|
870
|
+
if (tmy0 >= smy1 && tmx0 <= sox) {
|
|
871
|
+
y = middleOfHorizontalSides;
|
|
694
872
|
}
|
|
873
|
+
|
|
695
874
|
return [
|
|
696
875
|
{ x: sox, y },
|
|
697
876
|
{ x: tox, y },
|
|
698
877
|
{ x: tox, y: toy }
|
|
699
878
|
];
|
|
700
879
|
}
|
|
880
|
+
|
|
701
881
|
return [{ x: sox, y: toy }];
|
|
702
|
-
} else {
|
|
703
|
-
if (sx1 > tox) {
|
|
704
|
-
const y = Math.max(smy1, tmy1);
|
|
705
|
-
const x = Math.min(smx0, tmx0);
|
|
706
|
-
return [
|
|
707
|
-
{ x: sox, y },
|
|
708
|
-
{ x, y },
|
|
709
|
-
{ x, y: toy }
|
|
710
|
-
];
|
|
711
|
-
}
|
|
712
882
|
}
|
|
713
883
|
|
|
714
|
-
const x = middleOfVerticalSides;
|
|
884
|
+
const x = Math.min(tmx0, middleOfVerticalSides);
|
|
885
|
+
|
|
886
|
+
if (sox < tox && sy0 <= toy) {
|
|
887
|
+
return [
|
|
888
|
+
{ x: sox, y: soy },
|
|
889
|
+
{ x, y: soy },
|
|
890
|
+
{ x, y: toy }
|
|
891
|
+
];
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
if (x < smx1 && soy > ty0) {
|
|
895
|
+
const y = Math.max(smy1, tmy1);
|
|
896
|
+
const x = Math.min(smx0, tmx0);
|
|
897
|
+
return [
|
|
898
|
+
{ x: sox, y },
|
|
899
|
+
{ x, y },
|
|
900
|
+
{ x, y: toy }
|
|
901
|
+
];
|
|
902
|
+
}
|
|
715
903
|
|
|
716
904
|
return [
|
|
717
905
|
{ x: sox, y: soy },
|
|
718
906
|
{ x, y: soy },
|
|
719
907
|
{ x, y: toy }
|
|
720
908
|
];
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
909
|
+
} else if (sourceSide === 'left' && targetSide === 'bottom') {
|
|
910
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
911
|
+
|
|
912
|
+
// The target point is inside the source element
|
|
913
|
+
if (isPointInsideSource) {
|
|
914
|
+
if (soy <= tmy1) {
|
|
915
|
+
const x = Math.min(smx0, tmx0);
|
|
916
|
+
const y = Math.max(soy + sourceMargin, toy);
|
|
917
|
+
|
|
918
|
+
return [
|
|
919
|
+
{ x, y: soy },
|
|
920
|
+
{ x, y },
|
|
921
|
+
{ x: tox, y }
|
|
922
|
+
];
|
|
923
|
+
}
|
|
726
924
|
|
|
727
|
-
|
|
728
|
-
const
|
|
925
|
+
// Target anchor is above the source anchor
|
|
926
|
+
const anchorMiddleY = (soy - sourceMargin + toy) / 2;
|
|
729
927
|
|
|
730
928
|
return [
|
|
731
|
-
{ x, y: soy },
|
|
732
|
-
{ x, y:
|
|
733
|
-
{ x: tox, y:
|
|
929
|
+
{ x: sox, y: soy },
|
|
930
|
+
{ x: sox, y: anchorMiddleY },
|
|
931
|
+
{ x: tox, y: anchorMiddleY }
|
|
734
932
|
];
|
|
735
933
|
}
|
|
736
934
|
|
|
737
|
-
if (
|
|
738
|
-
|
|
935
|
+
if (smx0 > tox) {
|
|
936
|
+
if (soy < toy) {
|
|
937
|
+
let x = tmx0;
|
|
938
|
+
|
|
939
|
+
if (tmx1 <= smx0 && tmy1 >= soy) {
|
|
940
|
+
x = middleOfVerticalSides;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
return [
|
|
944
|
+
{ x, y: soy },
|
|
945
|
+
{ x, y: toy },
|
|
946
|
+
{ x: tox, y: toy }
|
|
947
|
+
];
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
return [{ x: tox, y: soy }];
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
const y = Math.max(tmy1, middleOfHorizontalSides);
|
|
739
954
|
|
|
955
|
+
if (soy > toy && sx1 >= tox) {
|
|
740
956
|
return [
|
|
741
957
|
{ x: sox, y: soy },
|
|
742
958
|
{ x: sox, y },
|
|
@@ -744,22 +960,57 @@ function routeBetweenPoints(source, target) {
|
|
|
744
960
|
];
|
|
745
961
|
}
|
|
746
962
|
|
|
747
|
-
|
|
748
|
-
|
|
963
|
+
if (y > smy0 && sox < tx1) {
|
|
964
|
+
const x = Math.min(smx0, tmx0);
|
|
965
|
+
const y = Math.max(smy1, tmy1);
|
|
966
|
+
|
|
967
|
+
return [
|
|
968
|
+
{ x, y: soy },
|
|
969
|
+
{ x, y },
|
|
970
|
+
{ x: tox, y }
|
|
971
|
+
];
|
|
972
|
+
}
|
|
749
973
|
|
|
750
974
|
return [
|
|
751
|
-
{ x, y: soy },
|
|
752
|
-
{ x, y },
|
|
975
|
+
{ x: sox, y: soy },
|
|
976
|
+
{ x: sox, y },
|
|
753
977
|
{ x: tox, y }
|
|
754
978
|
];
|
|
755
979
|
} else if (sourceSide === 'left' && targetSide === 'top') {
|
|
756
|
-
|
|
757
|
-
|
|
980
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
981
|
+
|
|
982
|
+
// The target point is inside the source element
|
|
983
|
+
if (isPointInsideSource) {
|
|
984
|
+
if (soy >= tmy0) {
|
|
985
|
+
const y = Math.min(soy - sourceMargin, toy);
|
|
986
|
+
const x = Math.min(smx0, tmx0);
|
|
987
|
+
|
|
988
|
+
// Target anchor is on the top side of the source anchor
|
|
989
|
+
return [
|
|
990
|
+
{ x, y: soy },
|
|
991
|
+
{ x, y },
|
|
992
|
+
{ x: tox, y }
|
|
993
|
+
];
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Target anchor is below the source anchor
|
|
997
|
+
// Add the `sourceMargin` since the source anchor is above the target anchor
|
|
998
|
+
const anchorMiddleY = (soy + sourceMargin + toy) / 2;
|
|
999
|
+
|
|
1000
|
+
return [
|
|
1001
|
+
{ x: sox, y: soy },
|
|
1002
|
+
{ x: sox, y: anchorMiddleY },
|
|
1003
|
+
{ x: tox, y: anchorMiddleY }
|
|
1004
|
+
];
|
|
758
1005
|
}
|
|
759
1006
|
|
|
760
|
-
if (
|
|
1007
|
+
if (smx0 > tox) {
|
|
761
1008
|
if (soy > toy) {
|
|
762
|
-
|
|
1009
|
+
let x = tmx0;
|
|
1010
|
+
|
|
1011
|
+
if (tmx1 <= smx0 && tmy0 <= soy) {
|
|
1012
|
+
x = middleOfVerticalSides;
|
|
1013
|
+
}
|
|
763
1014
|
|
|
764
1015
|
return [
|
|
765
1016
|
{ x, y: soy },
|
|
@@ -767,78 +1018,152 @@ function routeBetweenPoints(source, target) {
|
|
|
767
1018
|
{ x: tox, y: toy }
|
|
768
1019
|
];
|
|
769
1020
|
}
|
|
1021
|
+
|
|
1022
|
+
return [{ x: tox, y: soy }];
|
|
770
1023
|
}
|
|
771
1024
|
|
|
772
|
-
|
|
773
|
-
const y = middleOfHorizontalSides;
|
|
1025
|
+
const y = Math.min(tmy0, middleOfHorizontalSides);
|
|
774
1026
|
|
|
1027
|
+
if (soy < toy && sx1 >= tox) {
|
|
775
1028
|
return [
|
|
776
1029
|
{ x: sox, y: soy },
|
|
777
1030
|
{ x: sox, y },
|
|
778
|
-
{ x: tox, y }
|
|
779
|
-
];
|
|
1031
|
+
{ x: tox, y }];
|
|
780
1032
|
}
|
|
781
1033
|
|
|
782
|
-
|
|
783
|
-
|
|
1034
|
+
if (y < smy1 && sox < tx1) {
|
|
1035
|
+
const x = Math.min(smx0, tmx0);
|
|
1036
|
+
const y = Math.min(smy0, tmy0);
|
|
1037
|
+
return [
|
|
1038
|
+
{ x, y: soy },
|
|
1039
|
+
{ x, y },
|
|
1040
|
+
{ x: tox, y }
|
|
1041
|
+
];
|
|
1042
|
+
}
|
|
784
1043
|
|
|
785
1044
|
return [
|
|
786
|
-
{ x, y: soy },
|
|
787
|
-
{ x, y },
|
|
1045
|
+
{ x: sox, y: soy },
|
|
1046
|
+
{ x: sox, y },
|
|
788
1047
|
{ x: tox, y }
|
|
789
1048
|
];
|
|
790
|
-
|
|
791
1049
|
} else if (sourceSide === 'right' && targetSide === 'top') {
|
|
792
|
-
|
|
793
|
-
return [{ x: tox, y: soy }];
|
|
794
|
-
}
|
|
1050
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
795
1051
|
|
|
796
|
-
|
|
797
|
-
|
|
1052
|
+
// The target point is inside the source element
|
|
1053
|
+
if (isPointInsideSource) {
|
|
1054
|
+
if (soy >= tmy0) {
|
|
1055
|
+
const x = Math.max(smx1, tmx1);
|
|
1056
|
+
const y = Math.min(soy - sourceMargin, toy);
|
|
1057
|
+
|
|
1058
|
+
// Target anchor is on the top side of the source anchor
|
|
1059
|
+
return [
|
|
1060
|
+
{ x, y: soy },
|
|
1061
|
+
{ x, y }, // Path adjustment for right side start
|
|
1062
|
+
{ x: tox, y }
|
|
1063
|
+
];
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Target anchor is below the source anchor
|
|
1067
|
+
// Adjust sourceMargin calculation since the source anchor is now on the right
|
|
1068
|
+
const anchorMiddleY = (soy + sourceMargin + toy) / 2;
|
|
798
1069
|
|
|
799
1070
|
return [
|
|
800
|
-
{ x, y: soy },
|
|
801
|
-
{ x, y:
|
|
802
|
-
{ x: tox, y:
|
|
1071
|
+
{ x: sox, y: soy },
|
|
1072
|
+
{ x: sox, y: anchorMiddleY },
|
|
1073
|
+
{ x: tox, y: anchorMiddleY }
|
|
803
1074
|
];
|
|
804
1075
|
}
|
|
805
1076
|
|
|
806
|
-
if (
|
|
807
|
-
|
|
1077
|
+
if (smx1 < tox) {
|
|
1078
|
+
if (soy > toy) {
|
|
1079
|
+
let x = tmx1;
|
|
1080
|
+
|
|
1081
|
+
if (tmx0 >= smx1 && tmy0 <= soy) {
|
|
1082
|
+
x = middleOfVerticalSides;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
return [
|
|
1086
|
+
{ x, y: soy },
|
|
1087
|
+
{ x, y: toy },
|
|
1088
|
+
{ x: tox, y: toy }
|
|
1089
|
+
];
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
return [{ x: tox, y: soy }];
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
const y = Math.min(tmy0, middleOfHorizontalSides);
|
|
808
1096
|
|
|
1097
|
+
if (soy < toy && sx0 <= tox) {
|
|
809
1098
|
return [
|
|
810
1099
|
{ x: sox, y: soy },
|
|
811
1100
|
{ x: sox, y },
|
|
1101
|
+
{ x: tox, y }];
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
if (y < smy1 && sox > tx0) {
|
|
1105
|
+
const x = Math.max(smx1, tmx1);
|
|
1106
|
+
const y = Math.min(smy0, tmy0);
|
|
1107
|
+
|
|
1108
|
+
return [
|
|
1109
|
+
{ x, y: soy },
|
|
1110
|
+
{ x, y },
|
|
812
1111
|
{ x: tox, y }
|
|
813
1112
|
];
|
|
814
1113
|
}
|
|
815
1114
|
|
|
816
|
-
const x = Math.max(smx1, tmx1);
|
|
817
|
-
const y = Math.min(smy0, tmy0);
|
|
818
|
-
|
|
819
1115
|
return [
|
|
820
|
-
{ x, y: soy },
|
|
821
|
-
{ x, y },
|
|
1116
|
+
{ x: sox, y: soy },
|
|
1117
|
+
{ x: sox, y },
|
|
822
1118
|
{ x: tox, y }
|
|
823
1119
|
];
|
|
824
1120
|
} else if (sourceSide === 'right' && targetSide === 'bottom') {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1121
|
+
const isPointInsideSource = inflatedSourceBBox.containsPoint(targetPoint);
|
|
1122
|
+
|
|
1123
|
+
// The target point is inside the source element
|
|
1124
|
+
if (isPointInsideSource) {
|
|
1125
|
+
if (soy <= tmy1) {
|
|
1126
|
+
const x = Math.max(smx1, tmx1);
|
|
1127
|
+
const y = Math.max(soy + sourceMargin, toy);
|
|
1128
|
+
|
|
1129
|
+
return [
|
|
1130
|
+
{ x, y: soy },
|
|
1131
|
+
{ x, y },
|
|
1132
|
+
{ x: tox, y }
|
|
1133
|
+
];
|
|
1134
|
+
}
|
|
828
1135
|
|
|
829
|
-
|
|
830
|
-
const
|
|
1136
|
+
// Target anchor is above the source anchor
|
|
1137
|
+
const anchorMiddleY = (soy - sourceMargin + toy) / 2;
|
|
831
1138
|
|
|
832
1139
|
return [
|
|
833
|
-
{ x, y: soy },
|
|
834
|
-
{ x, y:
|
|
835
|
-
{ x: tox, y:
|
|
1140
|
+
{ x: sox, y: soy },
|
|
1141
|
+
{ x: sox, y: anchorMiddleY },
|
|
1142
|
+
{ x: tox, y: anchorMiddleY }
|
|
836
1143
|
];
|
|
837
1144
|
}
|
|
838
1145
|
|
|
839
|
-
if (
|
|
840
|
-
|
|
1146
|
+
if (smx1 < tox) {
|
|
1147
|
+
if (soy < toy) {
|
|
1148
|
+
let x = tmx1;
|
|
1149
|
+
|
|
1150
|
+
if (tmx0 >= smx1 && tmy1 >= soy) {
|
|
1151
|
+
x = middleOfVerticalSides;
|
|
1152
|
+
}
|
|
841
1153
|
|
|
1154
|
+
return [
|
|
1155
|
+
{ x, y: soy },
|
|
1156
|
+
{ x, y: toy },
|
|
1157
|
+
{ x: tox, y: toy }
|
|
1158
|
+
];
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
return [{ x: tox, y: soy }];
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
const y = Math.max(tmy1, middleOfHorizontalSides);
|
|
1165
|
+
|
|
1166
|
+
if (soy > toy && sx0 <= tox) {
|
|
842
1167
|
return [
|
|
843
1168
|
{ x: sox, y: soy },
|
|
844
1169
|
{ x: sox, y },
|
|
@@ -846,12 +1171,20 @@ function routeBetweenPoints(source, target) {
|
|
|
846
1171
|
];
|
|
847
1172
|
}
|
|
848
1173
|
|
|
849
|
-
|
|
850
|
-
|
|
1174
|
+
if (y > smy0 && sox > tx0) {
|
|
1175
|
+
const x = Math.max(smx1, tmx1);
|
|
1176
|
+
const y = Math.max(smy1, tmy1);
|
|
1177
|
+
|
|
1178
|
+
return [
|
|
1179
|
+
{ x, y: soy },
|
|
1180
|
+
{ x, y },
|
|
1181
|
+
{ x: tox, y }
|
|
1182
|
+
];
|
|
1183
|
+
}
|
|
851
1184
|
|
|
852
1185
|
return [
|
|
853
|
-
{ x, y: soy },
|
|
854
|
-
{ x, y },
|
|
1186
|
+
{ x: sox, y: soy },
|
|
1187
|
+
{ x: sox, y },
|
|
855
1188
|
{ x: tox, y }
|
|
856
1189
|
];
|
|
857
1190
|
}
|
|
@@ -886,7 +1219,7 @@ function rightAngleRouter(vertices, opt, linkView) {
|
|
|
886
1219
|
dummySource.direction = fromDirection;
|
|
887
1220
|
firstVertex.direction = toDirection;
|
|
888
1221
|
|
|
889
|
-
resultVertices.push(...routeBetweenPoints(dummySource, firstVertex), firstVertex.point);
|
|
1222
|
+
resultVertices.push(...routeBetweenPoints(dummySource, firstVertex, { targetInSourceBBox: true }), firstVertex.point);
|
|
890
1223
|
} else {
|
|
891
1224
|
// The first point responsible for the initial direction of the route
|
|
892
1225
|
const next = verticesData[1] || targetPoint;
|