@metadev/daga 4.2.6 → 4.2.8

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/index.esm.js CHANGED
@@ -381,7 +381,20 @@ const linePath = (shape, points, startDirection, endDirection, minimumDistanceBe
381
381
  result += `M ${points[0][0]} ${points[0][1]}`;
382
382
  for (let i = 1; i < points.length; ++i) {
383
383
  if (i + 1 >= points.length) {
384
- nextDirection = endDirection;
384
+ switch (endDirection) {
385
+ case Side.Bottom:
386
+ nextDirection = Side.Top;
387
+ break;
388
+ case Side.Top:
389
+ nextDirection = Side.Bottom;
390
+ break;
391
+ case Side.Right:
392
+ nextDirection = Side.Left;
393
+ break;
394
+ case Side.Left:
395
+ nextDirection = Side.Right;
396
+ break;
397
+ }
385
398
  } else {
386
399
  if (Math.abs(points[i][0] - points[i - 1][0]) < Math.abs(points[i][1] - points[i - 1][1])) {
387
400
  if (points[i][1] > points[i - 1][1]) {
@@ -417,16 +430,16 @@ const linePath = (shape, points, startDirection, endDirection, minimumDistanceBe
417
430
  }
418
431
  if (nextDirection !== undefined) {
419
432
  switch (nextDirection) {
420
- case Side.Bottom:
433
+ case Side.Top:
421
434
  controlPoint2 = `${points[i][0]} ${points[i][1] + controlPointDistance}`;
422
435
  break;
423
- case Side.Top:
436
+ case Side.Bottom:
424
437
  controlPoint2 = `${points[i][0]} ${points[i][1] - controlPointDistance}`;
425
438
  break;
426
- case Side.Right:
439
+ case Side.Left:
427
440
  controlPoint2 = `${points[i][0] + controlPointDistance} ${points[i][1]}`;
428
441
  break;
429
- case Side.Left:
442
+ case Side.Right:
430
443
  controlPoint2 = `${points[i][0] - controlPointDistance} ${points[i][1]}`;
431
444
  break;
432
445
  }
@@ -439,16 +452,16 @@ const linePath = (shape, points, startDirection, endDirection, minimumDistanceBe
439
452
  let controlPoint = '';
440
453
  const controlPointDistance = (Math.abs(points[i][0] - points[i - 1][0]) + Math.abs(points[i][1] - points[i - 1][1])) / 2;
441
454
  switch (nextDirection) {
442
- case Side.Bottom:
455
+ case Side.Top:
443
456
  controlPoint = `${points[i][0]} ${points[i][1] + controlPointDistance}`;
444
457
  break;
445
- case Side.Top:
458
+ case Side.Bottom:
446
459
  controlPoint = `${points[i][0]} ${points[i][1] - controlPointDistance}`;
447
460
  break;
448
- case Side.Right:
461
+ case Side.Left:
449
462
  controlPoint = `${points[i][0] + controlPointDistance} ${points[i][1]}`;
450
463
  break;
451
- case Side.Left:
464
+ case Side.Right:
452
465
  controlPoint = `${points[i][0] - controlPointDistance} ${points[i][1]}`;
453
466
  break;
454
467
  }
@@ -461,152 +474,443 @@ const linePath = (shape, points, startDirection, endDirection, minimumDistanceBe
461
474
  }
462
475
  break;
463
476
  case LineShape.Square:
477
+ currentDirection = startDirection;
464
478
  result += `M ${points[0][0]} ${points[0][1]}`;
465
- if (startDirection) {
466
- switch (startDirection) {
467
- case Side.Bottom:
468
- points.splice(1, 0, [points[0][0], points[0][1] + minimumDistanceBeforeTurn]);
469
- break;
470
- case Side.Top:
471
- points.splice(1, 0, [points[0][0], points[0][1] - minimumDistanceBeforeTurn]);
472
- break;
473
- case Side.Right:
474
- points.splice(1, 0, [points[0][0] + minimumDistanceBeforeTurn, points[0][1]]);
475
- break;
476
- case Side.Left:
477
- points.splice(1, 0, [points[0][0] - minimumDistanceBeforeTurn, points[0][1]]);
478
- break;
479
- }
480
- }
481
- if (endDirection) {
482
- switch (endDirection) {
483
- case Side.Bottom:
484
- points.splice(points.length - 1, 0, [points[points.length - 1][0], points[points.length - 1][1] + minimumDistanceBeforeTurn]);
485
- break;
486
- case Side.Top:
487
- points.splice(points.length - 1, 0, [points[points.length - 1][0], points[points.length - 1][1] - minimumDistanceBeforeTurn]);
488
- break;
489
- case Side.Right:
490
- points.splice(points.length - 1, 0, [points[points.length - 1][0] + minimumDistanceBeforeTurn, points[points.length - 1][1]]);
491
- break;
492
- case Side.Left:
493
- points.splice(points.length - 1, 0, [points[points.length - 1][0] - minimumDistanceBeforeTurn, points[points.length - 1][1]]);
494
- break;
495
- }
496
- }
497
479
  for (let i = 1; i < points.length; ++i) {
498
- if (currentDirection !== undefined) {
499
- switch (currentDirection) {
480
+ if (i + 1 >= points.length) {
481
+ switch (endDirection) {
500
482
  case Side.Bottom:
501
- if (points[i][1] < points[i - 1][1] && points[i][0] !== points[i - 1][0]) {
502
- // next point is behind, we turn around
503
- result += ` H ${points[i][0]}`;
504
- result += ` V ${points[i][1]}`;
505
- currentDirection = Side.Top;
506
- } else if (points[i][1] < points[i - 1][1] && points[i][0] === points[i - 1][0]) {
507
- // next point is behind on the same line, we turn around
508
- result += ` H ${points[i][0] + minimumDistanceBeforeTurn}`;
509
- result += ` V ${points[i][1]}`;
510
- result += ` H ${points[i][0]}`;
511
- currentDirection = Side.Left;
512
- } else if (points[i][1] === points[i - 1][1] && points[i][0] !== points[i - 1][0]) {
513
- // next point is perpendicular to us
514
- result += ` H ${points[i][0]}`;
515
- currentDirection = points[i][0] > points[i - 1][0] ? Side.Right : Side.Left;
516
- } else if (points[i][1] > points[i - 1][1] && points[i][0] !== points[i - 1][0]) {
517
- // next point is after us, we turn and continue
518
- result += ` H ${points[i][0]}`;
519
- result += ` V ${points[i][1]}`;
520
- } else if (points[i][1] > points[i - 1][1] && points[i][0] === points[i - 1][0]) {
521
- // next point is in the same direction, we continue straight
522
- result += ` V ${points[i][1]}`;
523
- }
483
+ nextDirection = Side.Top;
524
484
  break;
525
485
  case Side.Top:
526
- if (points[i][1] > points[i - 1][1] && points[i][0] !== points[i - 1][0]) {
527
- // next point is behind, we turn around
528
- result += ` H ${points[i][0]}`;
529
- result += ` V ${points[i][1]}`;
530
- currentDirection = Side.Bottom;
531
- } else if (points[i][1] > points[i - 1][1] && points[i][0] === points[i - 1][0]) {
532
- // next point is behind on the same line, we turn around
533
- result += ` H ${points[i][0] - minimumDistanceBeforeTurn}`;
534
- result += ` V ${points[i][1]}`;
535
- result += ` H ${points[i][0]}`;
536
- currentDirection = Side.Right;
537
- } else if (points[i][1] === points[i - 1][1] && points[i][0] !== points[i - 1][0]) {
538
- // next point is perpendicular to us
539
- result += ` H ${points[i][0]}`;
540
- currentDirection = points[i][0] > points[i - 1][0] ? Side.Right : Side.Left;
541
- } else if (points[i][1] < points[i - 1][1] && points[i][0] !== points[i - 1][0]) {
542
- // next point is after us, we turn and continue
543
- result += ` H ${points[i][0]}`;
544
- result += ` V ${points[i][1]}`;
545
- } else if (points[i][1] < points[i - 1][1] && points[i][0] === points[i - 1][0]) {
546
- // next point is in the same direction, we continue straight
547
- result += ` V ${points[i][1]}`;
548
- }
486
+ nextDirection = Side.Bottom;
549
487
  break;
550
488
  case Side.Right:
551
- if (points[i][0] < points[i - 1][0] && points[i][1] !== points[i - 1][1]) {
552
- // next point is behind, we turn around
553
- result += ` V ${points[i][1]}`;
554
- result += ` H ${points[i][0]}`;
555
- currentDirection = Side.Left;
556
- } else if (points[i][0] < points[i - 1][0] && points[i][1] === points[i - 1][1]) {
557
- // next point is behind on the same line, we turn around
558
- result += ` V ${points[i][1] + minimumDistanceBeforeTurn}`;
559
- result += ` H ${points[i][0]}`;
560
- result += ` V ${points[i][1]}`;
561
- currentDirection = Side.Top;
562
- } else if (points[i][0] === points[i - 1][0] && points[i][1] !== points[i - 1][1]) {
563
- // next point is perpendicular to us
564
- result += ` V ${points[i][1]}`;
565
- currentDirection = points[i][1] > points[i - 1][1] ? Side.Bottom : Side.Top;
566
- } else if (points[i][0] > points[i - 1][0] && points[i][1] !== points[i - 1][1]) {
567
- // next point is after us, we turn and continue
568
- result += ` V ${points[i][1]}`;
569
- result += ` H ${points[i][0]}`;
570
- } else if (points[i][0] > points[i - 1][0] && points[i][1] === points[i - 1][1]) {
571
- // next point is in the same direction, we continue straight
572
- result += ` H ${points[i][0]}`;
573
- }
489
+ nextDirection = Side.Left;
574
490
  break;
575
491
  case Side.Left:
576
- if (points[i][0] > points[i - 1][0] && points[i][1] !== points[i - 1][1]) {
577
- // next point is behind, we turn around
578
- result += ` V ${points[i][1]}`;
579
- result += ` H ${points[i][0]}`;
580
- currentDirection = Side.Right;
581
- } else if (points[i][0] > points[i - 1][0] && points[i][1] === points[i - 1][1]) {
582
- // next point is behind on the same line, we turn around
583
- result += ` V ${points[i][1] - minimumDistanceBeforeTurn}`;
492
+ nextDirection = Side.Right;
493
+ break;
494
+ }
495
+ }
496
+ switch (currentDirection) {
497
+ case Side.Bottom:
498
+ switch (nextDirection) {
499
+ case Side.Bottom:
500
+ if (points[i][1] > points[i - 1][1]) {
501
+ if (points[i][0] !== points[i - 1][0]) {
502
+ result += ` V ${(points[i][1] + points[i - 1][1]) / 2}`;
503
+ result += ` H ${points[i][0]}`;
504
+ result += ` V ${points[i][1]}`;
505
+ } else {
506
+ result += ` V ${points[i][1]}`;
507
+ }
508
+ currentDirection = nextDirection;
509
+ } else {
510
+ if (points[i][0] > points[i - 1][0]) {
511
+ result += ` V ${points[i - 1][1] + minimumDistanceBeforeTurn}`;
512
+ result += ` H ${Math.max(points[i - 1][0], points[i][0]) + minimumDistanceBeforeTurn}`;
513
+ result += ` V ${points[i][1] - minimumDistanceBeforeTurn}`;
514
+ result += ` H ${points[i][0]}`;
515
+ result += ` V ${points[i][1]}`;
516
+ } else {
517
+ result += ` V ${points[i - 1][1] + minimumDistanceBeforeTurn}`;
518
+ result += ` H ${Math.min(points[i - 1][0], points[i][0]) - minimumDistanceBeforeTurn}`;
519
+ result += ` V ${points[i][1] - minimumDistanceBeforeTurn}`;
520
+ result += ` H ${points[i][0]}`;
521
+ result += ` V ${points[i][1]}`;
522
+ }
523
+ }
524
+ break;
525
+ case Side.Top:
526
+ result += ` V ${Math.max(points[i - 1][1], points[i][1]) + minimumDistanceBeforeTurn}`;
584
527
  result += ` H ${points[i][0]}`;
585
528
  result += ` V ${points[i][1]}`;
586
- currentDirection = Side.Bottom;
587
- } else if (points[i][0] === points[i - 1][0] && points[i][1] !== points[i - 1][1]) {
588
- // next point is perpendicular to us
529
+ break;
530
+ case Side.Left:
531
+ if (points[i][1] > points[i - 1][1] + minimumDistanceBeforeTurn) {
532
+ if (points[i][0] < points[i - 1][0] - minimumDistanceBeforeTurn) {
533
+ result += ` V ${points[i][1]}`;
534
+ result += ` H ${points[i][0]}`;
535
+ } else {
536
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
537
+ result += ` H ${points[i][0] + minimumDistanceBeforeTurn}`;
538
+ result += ` V ${points[i][1]}`;
539
+ result += ` H ${points[i][0]}`;
540
+ }
541
+ } else {
542
+ if (points[i][0] < points[i - 1][0] - minimumDistanceBeforeTurn) {
543
+ result += ` V ${points[i - 1][1] + minimumDistanceBeforeTurn}`;
544
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
545
+ result += ` V ${points[i][1]}`;
546
+ result += ` H ${points[i][0]}`;
547
+ } else {
548
+ result += ` V ${points[i - 1][1] + minimumDistanceBeforeTurn}`;
549
+ result += ` H ${points[i][0] + minimumDistanceBeforeTurn}`;
550
+ result += ` V ${points[i][1]}`;
551
+ result += ` H ${points[i][0]}`;
552
+ }
553
+ }
554
+ break;
555
+ case Side.Right:
556
+ if (points[i][1] > points[i - 1][1] + minimumDistanceBeforeTurn) {
557
+ if (points[i][0] > points[i - 1][0] + minimumDistanceBeforeTurn) {
558
+ result += ` V ${points[i][1]}`;
559
+ result += ` H ${points[i][0]}`;
560
+ } else {
561
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
562
+ result += ` H ${points[i][0] - minimumDistanceBeforeTurn}`;
563
+ result += ` V ${points[i][1]}`;
564
+ result += ` H ${points[i][0]}`;
565
+ }
566
+ } else {
567
+ if (points[i][0] > points[i - 1][0] + minimumDistanceBeforeTurn) {
568
+ result += ` V ${points[i - 1][1] + minimumDistanceBeforeTurn}`;
569
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
570
+ result += ` V ${points[i][1]}`;
571
+ result += ` H ${points[i][0]}`;
572
+ } else {
573
+ result += ` V ${points[i - 1][1] + minimumDistanceBeforeTurn}`;
574
+ result += ` H ${points[i][0] - minimumDistanceBeforeTurn}`;
575
+ result += ` V ${points[i][1]}`;
576
+ result += ` H ${points[i][0]}`;
577
+ }
578
+ }
579
+ break;
580
+ default:
581
+ if (points[i][1] < points[i - 1][1] + minimumDistanceBeforeTurn) {
582
+ result += ` V ${points[i - 1][1] + minimumDistanceBeforeTurn}`;
583
+ if (points[i][0] !== points[i - 1][0]) {
584
+ result += ` H ${points[i][0]}`;
585
+ }
586
+ result += ` V ${points[i][1]}`;
587
+ currentDirection = Side.Top;
588
+ } else {
589
+ result += ` V ${points[i][1]}`;
590
+ currentDirection = Side.Bottom;
591
+ if (points[i][0] !== points[i - 1][0]) {
592
+ result += ` H ${points[i][0]}`;
593
+ currentDirection = points[i][0] > points[i - 1][0] ? Side.Right : Side.Left;
594
+ }
595
+ }
596
+ break;
597
+ }
598
+ break;
599
+ case Side.Top:
600
+ switch (nextDirection) {
601
+ case Side.Top:
602
+ if (points[i][1] < points[i - 1][1]) {
603
+ if (points[i][0] !== points[i - 1][0]) {
604
+ result += ` V ${(points[i][1] + points[i - 1][1]) / 2}`;
605
+ result += ` H ${points[i][0]}`;
606
+ result += ` V ${points[i][1]}`;
607
+ } else {
608
+ result += ` V ${points[i][1]}`;
609
+ }
610
+ currentDirection = nextDirection;
611
+ } else {
612
+ if (points[i][0] < points[i - 1][0]) {
613
+ result += ` V ${points[i - 1][1] - minimumDistanceBeforeTurn}`;
614
+ result += ` H ${Math.min(points[i - 1][0], points[i][0]) - minimumDistanceBeforeTurn}`;
615
+ result += ` V ${points[i][1] + minimumDistanceBeforeTurn}`;
616
+ result += ` H ${points[i][0]}`;
617
+ result += ` V ${points[i][1]}`;
618
+ } else {
619
+ result += ` V ${points[i - 1][1] - minimumDistanceBeforeTurn}`;
620
+ result += ` H ${Math.max(points[i - 1][0], points[i][0]) + minimumDistanceBeforeTurn}`;
621
+ result += ` V ${points[i][1] + minimumDistanceBeforeTurn}`;
622
+ result += ` H ${points[i][0]}`;
623
+ result += ` V ${points[i][1]}`;
624
+ }
625
+ }
626
+ break;
627
+ case Side.Bottom:
628
+ result += ` V ${Math.min(points[i - 1][1], points[i][1]) - minimumDistanceBeforeTurn}`;
629
+ result += ` H ${points[i][0]}`;
589
630
  result += ` V ${points[i][1]}`;
590
- currentDirection = points[i][1] > points[i - 1][1] ? Side.Bottom : Side.Top;
591
- } else if (points[i][0] < points[i - 1][0] && points[i][1] !== points[i - 1][1]) {
592
- // next point is after us, we turn and continue
631
+ break;
632
+ case Side.Right:
633
+ if (points[i][1] < points[i - 1][1] - minimumDistanceBeforeTurn) {
634
+ if (points[i][0] > points[i - 1][0] + minimumDistanceBeforeTurn) {
635
+ result += ` V ${points[i][1]}`;
636
+ result += ` H ${points[i][0]}`;
637
+ } else {
638
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
639
+ result += ` H ${points[i][0] - minimumDistanceBeforeTurn}`;
640
+ result += ` V ${points[i][1]}`;
641
+ result += ` H ${points[i][0]}`;
642
+ }
643
+ } else {
644
+ if (points[i][0] > points[i - 1][0] + minimumDistanceBeforeTurn) {
645
+ result += ` V ${points[i - 1][1] - minimumDistanceBeforeTurn}`;
646
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
647
+ result += ` V ${points[i][1]}`;
648
+ result += ` H ${points[i][0]}`;
649
+ } else {
650
+ result += ` V ${points[i - 1][1] - minimumDistanceBeforeTurn}`;
651
+ result += ` H ${points[i][0] - minimumDistanceBeforeTurn}`;
652
+ result += ` V ${points[i][1]}`;
653
+ result += ` H ${points[i][0]}`;
654
+ }
655
+ }
656
+ break;
657
+ case Side.Left:
658
+ if (points[i][1] < points[i - 1][1] - minimumDistanceBeforeTurn) {
659
+ if (points[i][0] < points[i - 1][0] - minimumDistanceBeforeTurn) {
660
+ result += ` V ${points[i][1]}`;
661
+ result += ` H ${points[i][0]}`;
662
+ } else {
663
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
664
+ result += ` H ${points[i][0] + minimumDistanceBeforeTurn}`;
665
+ result += ` V ${points[i][1]}`;
666
+ result += ` H ${points[i][0]}`;
667
+ }
668
+ } else {
669
+ if (points[i][0] < points[i - 1][0] - minimumDistanceBeforeTurn) {
670
+ result += ` V ${points[i - 1][1] - minimumDistanceBeforeTurn}`;
671
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
672
+ result += ` V ${points[i][1]}`;
673
+ result += ` H ${points[i][0]}`;
674
+ } else {
675
+ result += ` V ${points[i - 1][1] - minimumDistanceBeforeTurn}`;
676
+ result += ` H ${points[i][0] + minimumDistanceBeforeTurn}`;
677
+ result += ` V ${points[i][1]}`;
678
+ result += ` H ${points[i][0]}`;
679
+ }
680
+ }
681
+ break;
682
+ default:
683
+ if (points[i][1] > points[i - 1][1] - minimumDistanceBeforeTurn) {
684
+ result += ` V ${points[i - 1][1] - minimumDistanceBeforeTurn}`;
685
+ if (points[i][0] !== points[i - 1][0]) {
686
+ result += ` H ${points[i][0]}`;
687
+ }
688
+ result += ` V ${points[i][1]}`;
689
+ currentDirection = Side.Bottom;
690
+ } else {
691
+ result += ` V ${points[i][1]}`;
692
+ currentDirection = Side.Top;
693
+ if (points[i][0] !== points[i - 1][0]) {
694
+ result += ` H ${points[i][0]}`;
695
+ currentDirection = points[i][0] > points[i - 1][0] ? Side.Right : Side.Left;
696
+ }
697
+ }
698
+ break;
699
+ }
700
+ break;
701
+ case Side.Left:
702
+ switch (nextDirection) {
703
+ case Side.Left:
704
+ if (points[i][0] < points[i - 1][0]) {
705
+ if (points[i][1] !== points[i - 1][1]) {
706
+ result += ` H ${(points[i][0] + points[i - 1][0]) / 2}`;
707
+ result += ` V ${points[i][1]}`;
708
+ result += ` H ${points[i][0]}`;
709
+ } else {
710
+ result += ` H ${points[i][0]}`;
711
+ }
712
+ currentDirection = nextDirection;
713
+ } else {
714
+ if (points[i][1] < points[i - 1][1]) {
715
+ result += ` H ${points[i - 1][0] - minimumDistanceBeforeTurn}`;
716
+ result += ` V ${Math.min(points[i - 1][1], points[i][1]) - minimumDistanceBeforeTurn}`;
717
+ result += ` H ${points[i][0] + minimumDistanceBeforeTurn}`;
718
+ result += ` V ${points[i][1]}`;
719
+ result += ` H ${points[i][0]}`;
720
+ } else {
721
+ result += ` H ${points[i - 1][0] - minimumDistanceBeforeTurn}`;
722
+ result += ` V ${Math.max(points[i - 1][1], points[i][1]) + minimumDistanceBeforeTurn}`;
723
+ result += ` H ${points[i][0] + minimumDistanceBeforeTurn}`;
724
+ result += ` V ${points[i][1]}`;
725
+ result += ` H ${points[i][0]}`;
726
+ }
727
+ }
728
+ break;
729
+ case Side.Right:
730
+ result += ` H ${Math.min(points[i - 1][0], points[i][0]) - minimumDistanceBeforeTurn}`;
593
731
  result += ` V ${points[i][1]}`;
594
732
  result += ` H ${points[i][0]}`;
595
- } else if (points[i][0] < points[i - 1][0] && points[i][1] === points[i - 1][1]) {
596
- // next point is in the same direction, we continue straight
733
+ break;
734
+ case Side.Bottom:
735
+ if (points[i][0] < points[i - 1][0] - minimumDistanceBeforeTurn) {
736
+ if (points[i][1] > points[i - 1][1] + minimumDistanceBeforeTurn) {
737
+ result += ` H ${points[i][0]}`;
738
+ result += ` V ${points[i][1]}`;
739
+ } else {
740
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
741
+ result += ` V ${points[i][1] - minimumDistanceBeforeTurn}`;
742
+ result += ` H ${points[i][0]}`;
743
+ result += ` V ${points[i][1]}`;
744
+ }
745
+ } else {
746
+ if (points[i][1] > points[i - 1][1] + minimumDistanceBeforeTurn) {
747
+ result += ` H ${points[i - 1][0] - minimumDistanceBeforeTurn}`;
748
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
749
+ result += ` H ${points[i][0]}`;
750
+ result += ` V ${points[i][1]}`;
751
+ } else {
752
+ result += ` H ${points[i - 1][0] - minimumDistanceBeforeTurn}`;
753
+ result += ` V ${points[i][1] - minimumDistanceBeforeTurn}`;
754
+ result += ` H ${points[i][0]}`;
755
+ result += ` V ${points[i][1]}`;
756
+ }
757
+ }
758
+ break;
759
+ case Side.Top:
760
+ if (points[i][0] < points[i - 1][0] - minimumDistanceBeforeTurn) {
761
+ if (points[i][1] < points[i - 1][1] - minimumDistanceBeforeTurn) {
762
+ result += ` H ${points[i][0]}`;
763
+ result += ` V ${points[i][1]}`;
764
+ } else {
765
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
766
+ result += ` V ${points[i][1] + minimumDistanceBeforeTurn}`;
767
+ result += ` H ${points[i][0]}`;
768
+ result += ` V ${points[i][1]}`;
769
+ }
770
+ } else {
771
+ if (points[i][1] < points[i - 1][1] - minimumDistanceBeforeTurn) {
772
+ result += ` H ${points[i - 1][0] - minimumDistanceBeforeTurn}`;
773
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
774
+ result += ` H ${points[i][0]}`;
775
+ result += ` V ${points[i][1]}`;
776
+ } else {
777
+ result += ` H ${points[i - 1][0] - minimumDistanceBeforeTurn}`;
778
+ result += ` V ${points[i][1] + minimumDistanceBeforeTurn}`;
779
+ result += ` H ${points[i][0]}`;
780
+ result += ` V ${points[i][1]}`;
781
+ }
782
+ }
783
+ break;
784
+ default:
785
+ if (points[i][0] > points[i - 1][0] - minimumDistanceBeforeTurn) {
786
+ result += ` H ${points[i - 1][0] - minimumDistanceBeforeTurn}`;
787
+ if (points[i][1] !== points[i - 1][1]) {
788
+ result += ` V ${points[i][1]}`;
789
+ }
790
+ result += ` H ${points[i][0]}`;
791
+ currentDirection = Side.Right;
792
+ } else {
793
+ result += ` H ${points[i][0]}`;
794
+ currentDirection = Side.Left;
795
+ if (points[i][1] !== points[i - 1][1]) {
796
+ result += ` V ${points[i][1]}`;
797
+ currentDirection = points[i][1] > points[i - 1][1] ? Side.Bottom : Side.Top;
798
+ }
799
+ }
800
+ break;
801
+ }
802
+ break;
803
+ case Side.Right:
804
+ switch (nextDirection) {
805
+ case Side.Right:
806
+ if (points[i][0] > points[i - 1][0]) {
807
+ if (points[i][1] !== points[i - 1][1]) {
808
+ result += ` H ${(points[i][0] + points[i - 1][0]) / 2}`;
809
+ result += ` V ${points[i][1]}`;
810
+ result += ` H ${points[i][0]}`;
811
+ } else {
812
+ result += ` H ${points[i][0]}`;
813
+ }
814
+ currentDirection = nextDirection;
815
+ } else {
816
+ if (points[i][1] > points[i - 1][1]) {
817
+ result += ` H ${points[i - 1][0] + minimumDistanceBeforeTurn}`;
818
+ result += ` V ${Math.max(points[i - 1][1], points[i][1]) + minimumDistanceBeforeTurn}`;
819
+ result += ` H ${points[i][0] - minimumDistanceBeforeTurn}`;
820
+ result += ` V ${points[i][1]}`;
821
+ result += ` H ${points[i][0]}`;
822
+ } else {
823
+ result += ` H ${points[i - 1][0] + minimumDistanceBeforeTurn}`;
824
+ result += ` V ${Math.min(points[i - 1][1], points[i][1]) - minimumDistanceBeforeTurn}`;
825
+ result += ` H ${points[i][0] - minimumDistanceBeforeTurn}`;
826
+ result += ` V ${points[i][1]}`;
827
+ result += ` H ${points[i][0]}`;
828
+ }
829
+ }
830
+ break;
831
+ case Side.Left:
832
+ result += ` H ${Math.max(points[i - 1][0], points[i][0]) + minimumDistanceBeforeTurn}`;
833
+ result += ` V ${points[i][1]}`;
597
834
  result += ` H ${points[i][0]}`;
598
- }
599
- break;
600
- }
601
- } else {
602
- if (points[i][0] !== points[i - 1][0]) {
603
- result += ` H ${points[i][0]}`;
604
- currentDirection = points[i][0] > points[i - 1][0] ? Side.Right : Side.Left;
605
- }
606
- if (points[i][1] !== points[i - 1][1]) {
607
- result += ` V ${points[i][1]}`;
608
- currentDirection = points[i][1] > points[i - 1][1] ? Side.Bottom : Side.Top;
609
- }
835
+ break;
836
+ case Side.Top:
837
+ if (points[i][0] > points[i - 1][0] + minimumDistanceBeforeTurn) {
838
+ if (points[i][1] < points[i - 1][1] - minimumDistanceBeforeTurn) {
839
+ result += ` H ${points[i][0]}`;
840
+ result += ` V ${points[i][1]}`;
841
+ } else {
842
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
843
+ result += ` V ${points[i][1] + minimumDistanceBeforeTurn}`;
844
+ result += ` H ${points[i][0]}`;
845
+ result += ` V ${points[i][1]}`;
846
+ }
847
+ } else {
848
+ if (points[i][1] < points[i - 1][1] - minimumDistanceBeforeTurn) {
849
+ result += ` H ${points[i - 1][0] + minimumDistanceBeforeTurn}`;
850
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
851
+ result += ` H ${points[i][0]}`;
852
+ result += ` V ${points[i][1]}`;
853
+ } else {
854
+ result += ` H ${points[i - 1][0] + minimumDistanceBeforeTurn}`;
855
+ result += ` V ${points[i][1] + minimumDistanceBeforeTurn}`;
856
+ result += ` H ${points[i][0]}`;
857
+ result += ` V ${points[i][1]}`;
858
+ }
859
+ }
860
+ break;
861
+ case Side.Bottom:
862
+ if (points[i][0] > points[i - 1][0] + minimumDistanceBeforeTurn) {
863
+ if (points[i][1] > points[i - 1][1] + minimumDistanceBeforeTurn) {
864
+ result += ` H ${points[i][0]}`;
865
+ result += ` V ${points[i][1]}`;
866
+ } else {
867
+ result += ` H ${(points[i - 1][0] + points[i][0]) / 2}`;
868
+ result += ` V ${points[i][1] - minimumDistanceBeforeTurn}`;
869
+ result += ` H ${points[i][0]}`;
870
+ result += ` V ${points[i][1]}`;
871
+ }
872
+ } else {
873
+ if (points[i][1] > points[i - 1][1] + minimumDistanceBeforeTurn) {
874
+ result += ` H ${points[i - 1][0] + minimumDistanceBeforeTurn}`;
875
+ result += ` V ${(points[i - 1][1] + points[i][1]) / 2}`;
876
+ result += ` H ${points[i][0]}`;
877
+ result += ` V ${points[i][1]}`;
878
+ } else {
879
+ result += ` H ${points[i - 1][0] + minimumDistanceBeforeTurn}`;
880
+ result += ` V ${points[i][1] - minimumDistanceBeforeTurn}`;
881
+ result += ` H ${points[i][0]}`;
882
+ result += ` V ${points[i][1]}`;
883
+ }
884
+ }
885
+ break;
886
+ default:
887
+ if (points[i][0] < points[i - 1][0] + minimumDistanceBeforeTurn) {
888
+ result += ` H ${points[i - 1][0] + minimumDistanceBeforeTurn}`;
889
+ if (points[i][1] !== points[i - 1][1]) {
890
+ result += ` V ${points[i][1]}`;
891
+ }
892
+ result += ` H ${points[i][0]}`;
893
+ currentDirection = Side.Left;
894
+ } else {
895
+ result += ` H ${points[i][0]}`;
896
+ currentDirection = Side.Right;
897
+ if (points[i][1] !== points[i - 1][1]) {
898
+ result += ` V ${points[i][1]}`;
899
+ currentDirection = points[i][1] > points[i - 1][1] ? Side.Bottom : Side.Top;
900
+ }
901
+ }
902
+ break;
903
+ }
904
+ break;
905
+ default:
906
+ if (points[i][0] !== points[i - 1][0]) {
907
+ result += ` H ${points[i][0]}`;
908
+ currentDirection = points[i][0] > points[i - 1][0] ? Side.Right : Side.Left;
909
+ }
910
+ if (points[i][1] !== points[i - 1][1]) {
911
+ result += ` V ${points[i][1]}`;
912
+ currentDirection = points[i][1] > points[i - 1][1] ? Side.Bottom : Side.Top;
913
+ }
610
914
  }
611
915
  }
612
916
  break;
@@ -904,13 +1208,14 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
904
1208
  const extractLooksFromConfig = lookConfig => {
905
1209
  const {
906
1210
  selected,
907
- highlighted
1211
+ highlighted,
1212
+ selectedAndHighlighted
908
1213
  } = lookConfig,
909
- rest = __rest(lookConfig, ["selected", "highlighted"]);
1214
+ rest = __rest(lookConfig, ["selected", "highlighted", "selectedAndHighlighted"]);
910
1215
  const defaultLook = rest;
911
1216
  const selectedLook = Object.assign(Object.assign({}, defaultLook), selected);
912
1217
  const highlightedLook = Object.assign(Object.assign({}, defaultLook), highlighted);
913
- const selectedAndHighlightedLook = Object.assign(Object.assign(Object.assign({}, defaultLook), highlighted), selected);
1218
+ const selectedAndHighlightedLook = Object.assign(Object.assign(Object.assign(Object.assign({}, defaultLook), highlighted), selected), selectedAndHighlighted);
914
1219
  return {
915
1220
  defaultLook,
916
1221
  selectedLook,
@@ -3088,6 +3393,7 @@ const DIAGRAM_NODE_TYPE_DEFAULTS = {
3088
3393
  minHeight: 1,
3089
3394
  resizableX: false,
3090
3395
  resizableY: false,
3396
+ snapToGridOffset: [0, 0, 0, 0],
3091
3397
  padding: 0,
3092
3398
  label: null,
3093
3399
  ports: [],
@@ -3116,6 +3422,7 @@ class DiagramNodeType {
3116
3422
  this.minHeight = values.minHeight;
3117
3423
  this.resizableX = values.resizableX;
3118
3424
  this.resizableY = values.resizableY;
3425
+ this.snapToGridOffset = values.snapToGridOffset;
3119
3426
  this.bottomPadding = getBottomPadding(values);
3120
3427
  this.leftPadding = getLeftPadding(values);
3121
3428
  this.rightPadding = getRightPadding(values);
@@ -6253,7 +6560,10 @@ const SHAPED_LOOK_DEFAULTS = {
6253
6560
  borderStyle: LineStyle.Solid
6254
6561
  };
6255
6562
  const updateLook = selection => {
6256
- selection.filter('.shaped-look').select('path').attr('d', d => generalClosedPath(d.look.shape || ClosedShape.Rectangle, 0, 0, d.width, d.height)).attr('fill', d => d.look.fillColor || SHAPED_LOOK_DEFAULTS.fillColor).attr('stroke', d => d.look.borderColor || SHAPED_LOOK_DEFAULTS.borderColor).attr('stroke-width', d => `${d.look.borderThickness || SHAPED_LOOK_DEFAULTS.borderThickness}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.look.borderStyle || SHAPED_LOOK_DEFAULTS.borderStyle, d.look.borderThickness || SHAPED_LOOK_DEFAULTS.borderThickness));
6563
+ selection.filter('.shaped-look').select('path').attr('d', d => generalClosedPath(d.look.shape || ClosedShape.Rectangle, 0, 0, d.width, d.height)).attr('fill', d => d.look.fillColor || SHAPED_LOOK_DEFAULTS.fillColor).attr('stroke', d => d.look.borderColor || SHAPED_LOOK_DEFAULTS.borderColor).attr('stroke-width', d => `${d.look.borderThickness || SHAPED_LOOK_DEFAULTS.borderThickness}px`).attr('stroke-dasharray', d => {
6564
+ var _a, _b, _c;
6565
+ return lineStyleDasharray(d.look.borderStyle || SHAPED_LOOK_DEFAULTS.borderStyle, ((_b = (_a = d.type) === null || _a === void 0 ? void 0 : _a.defaultLook) === null || _b === void 0 ? void 0 : _b.borderThickness) || ((_c = d.look) === null || _c === void 0 ? void 0 : _c.borderThickness) || SHAPED_LOOK_DEFAULTS.borderThickness);
6566
+ });
6257
6567
  selection.filter('.image-look').select('image').attr('x', 0).attr('y', 0).attr('width', d => d.width).attr('height', d => d.height).attr('href', d => d.look.backgroundImage);
6258
6568
  selection.filter('.stretchable-image-look').select('image.top-left-image').attr('x', 0).attr('y', 0).attr('width', d => d.look.leftMargin).attr('height', d => d.look.topMargin).attr('href', d => d.look.backgroundImageTopLeft);
6259
6569
  selection.filter('.stretchable-image-look').select('image.top-image').attr('x', d => d.look.leftMargin).attr('y', 0).attr('width', d => d.width - d.look.rightMargin - d.look.leftMargin).attr('height', d => d.look.topMargin).attr('href', d => d.look.backgroundImageTop);
@@ -7486,7 +7796,9 @@ class DiagramCanvas {
7486
7796
  if (this.canUserPerformAction(DiagramActions.StretchNode) && d.type.resizableX && !d.removed && this.currentAction instanceof SetGeometryAction && this.currentAction.intent === DiagramActions.StretchNode) {
7487
7797
  let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
7488
7798
  if (this.snapToGrid) {
7489
- pointerCoords = this.getClosestGridPoint(pointerCoords);
7799
+ pointerCoords = this.getClosestGridPoint([pointerCoords[0] - d.type.snapToGridOffset[0], pointerCoords[1] - d.type.snapToGridOffset[1]]);
7800
+ pointerCoords[0] += d.type.snapToGridOffset[0];
7801
+ pointerCoords[1] += d.type.snapToGridOffset[1];
7490
7802
  }
7491
7803
  d.stretch(Side.Left, d.coords[0] - pointerCoords[0]);
7492
7804
  this.currentAction.to = d.getGeometry();
@@ -7520,7 +7832,9 @@ class DiagramCanvas {
7520
7832
  if (this.canUserPerformAction(DiagramActions.StretchNode) && d.type.resizableY && !d.removed && this.currentAction instanceof SetGeometryAction && this.currentAction.intent === DiagramActions.StretchNode) {
7521
7833
  let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
7522
7834
  if (this.snapToGrid) {
7523
- pointerCoords = this.getClosestGridPoint(pointerCoords);
7835
+ pointerCoords = this.getClosestGridPoint([pointerCoords[0] - d.type.snapToGridOffset[0], pointerCoords[1] - d.type.snapToGridOffset[1]]);
7836
+ pointerCoords[0] += d.type.snapToGridOffset[0];
7837
+ pointerCoords[1] += d.type.snapToGridOffset[1];
7524
7838
  }
7525
7839
  d.stretch(Side.Top, d.coords[1] - pointerCoords[1]);
7526
7840
  this.currentAction.to = d.getGeometry();
@@ -7554,7 +7868,9 @@ class DiagramCanvas {
7554
7868
  if (this.canUserPerformAction(DiagramActions.StretchNode) && d.type.resizableX && !d.removed && this.currentAction instanceof SetGeometryAction && this.currentAction.intent === DiagramActions.StretchNode) {
7555
7869
  let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
7556
7870
  if (this.snapToGrid) {
7557
- pointerCoords = this.getClosestGridPoint(pointerCoords);
7871
+ pointerCoords = this.getClosestGridPoint([pointerCoords[0] - d.type.snapToGridOffset[2], pointerCoords[1] - d.type.snapToGridOffset[3]]);
7872
+ pointerCoords[0] += d.type.snapToGridOffset[2];
7873
+ pointerCoords[1] += d.type.snapToGridOffset[3];
7558
7874
  }
7559
7875
  d.stretch(Side.Right, pointerCoords[0] - (d.coords[0] + d.width));
7560
7876
  this.currentAction.to = d.getGeometry();
@@ -7588,7 +7904,11 @@ class DiagramCanvas {
7588
7904
  if (this.canUserPerformAction(DiagramActions.StretchNode) && d.type.resizableY && !d.removed && this.currentAction instanceof SetGeometryAction && this.currentAction.intent === DiagramActions.StretchNode) {
7589
7905
  let pointerCoords = this.getPointerLocationRelativeToCanvas(event);
7590
7906
  if (this.snapToGrid) {
7591
- pointerCoords = this.getClosestGridPoint(pointerCoords);
7907
+ if (this.snapToGrid) {
7908
+ pointerCoords = this.getClosestGridPoint([pointerCoords[0] - d.type.snapToGridOffset[2], pointerCoords[1] - d.type.snapToGridOffset[3]]);
7909
+ pointerCoords[0] += d.type.snapToGridOffset[2];
7910
+ pointerCoords[1] += d.type.snapToGridOffset[3];
7911
+ }
7592
7912
  }
7593
7913
  d.stretch(Side.Bottom, pointerCoords[1] - (d.coords[1] + d.height));
7594
7914
  this.currentAction.to = d.getGeometry();
@@ -7924,7 +8244,7 @@ class DiagramCanvas {
7924
8244
  if (this.canUserPerformAction(DiagramActions.AddConnection) && !d.removed) {
7925
8245
  if (this.unfinishedConnection !== undefined) {
7926
8246
  const endCoords = [event.x, event.y];
7927
- (_a = this.unfinishedConnectionTracer) === null || _a === void 0 ? void 0 : _a.attr('d', getConnectionPath(this.unfinishedConnection.look.shape || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.shape, this.unfinishedConnection.startCoords, endCoords, this.unfinishedConnection.startDirection, this.unfinishedConnection.endDirection, this.unfinishedConnection.look.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness, (_b = this.unfinishedConnection.startMarkerLook) === null || _b === void 0 ? void 0 : _b.width, (_c = this.unfinishedConnection.endMarkerLook) === null || _c === void 0 ? void 0 : _c.width));
8247
+ (_a = this.unfinishedConnectionTracer) === null || _a === void 0 ? void 0 : _a.attr('d', getConnectionPath(this.unfinishedConnection.look.shape || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.shape, this.unfinishedConnection.startCoords, endCoords, this.unfinishedConnection.startDirection, this.unfinishedConnection.endDirection, this.unfinishedConnection.type.defaultLook.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness, (_b = this.unfinishedConnection.type.defaultStartMarkerLook) === null || _b === void 0 ? void 0 : _b.width, (_c = this.unfinishedConnection.type.defaultEndMarkerLook) === null || _c === void 0 ? void 0 : _c.width));
7928
8248
  const unfinishedConnectionGhostNode = (_d = this.unfinishedConnectionTracer) === null || _d === void 0 ? void 0 : _d.node();
7929
8249
  if (unfinishedConnectionGhostNode) {
7930
8250
  let margin = 2;
@@ -8072,14 +8392,14 @@ class DiagramCanvas {
8072
8392
  enterSelection.select('g.diagram-connection-end-label').append('text').style('user-select', 'none');
8073
8393
  mergeSelection.attr('opacity', d => d.removed ? 0.5 : 1).select('path.diagram-connection-path').attr('d', d => {
8074
8394
  var _a, _b;
8075
- return getConnectionPath(d.look.shape || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.look.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness, (_a = d.startMarkerLook) === null || _a === void 0 ? void 0 : _a.width, (_b = d.endMarkerLook) === null || _b === void 0 ? void 0 : _b.width);
8076
- }).attr('marker-start', d => `url(#${d.id}-start-marker)`).attr('marker-end', d => `url(#${d.id}-end-marker)`).attr('stroke', d => d.look.color || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.color).attr('stroke-width', d => `${d.look.thickness}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.look.style || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.style, d.look.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness)).attr('fill', 'none');
8395
+ return getConnectionPath(d.look.shape || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.type.defaultLook.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness, (_a = d.type.defaultStartMarkerLook) === null || _a === void 0 ? void 0 : _a.width, (_b = d.type.defaultEndMarkerLook) === null || _b === void 0 ? void 0 : _b.width);
8396
+ }).attr('marker-start', d => `url(#${d.id}-start-marker)`).attr('marker-end', d => `url(#${d.id}-end-marker)`).attr('stroke', d => d.look.color || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.color).attr('stroke-width', d => `${d.look.thickness}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.look.style || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.style, d.type.defaultLook.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness)).attr('fill', 'none');
8077
8397
  mergeSelection.select('path.diagram-connection-path-box').attr('d', d => {
8078
8398
  var _a, _b;
8079
- return getConnectionPath(d.look.shape || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.look.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness, (_a = d.startMarkerLook) === null || _a === void 0 ? void 0 : _a.width, (_b = d.endMarkerLook) === null || _b === void 0 ? void 0 : _b.width);
8399
+ return getConnectionPath(d.look.shape || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.shape, d.startCoords, d.endCoords, d.startDirection, d.endDirection, d.type.defaultLook.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness, (_a = d.type.defaultStartMarkerLook) === null || _a === void 0 ? void 0 : _a.width, (_b = d.type.defaultEndMarkerLook) === null || _b === void 0 ? void 0 : _b.width);
8080
8400
  }).attr('stroke', 'transparent')
8081
8401
  // allow generating pointer events even when it is transparent
8082
- .attr('pointer-events', 'stroke').attr('stroke-width', d => `${(d.look.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness) + CONNECTION_PATH_BOX_THICKNESS}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.look.style || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.style, d.look.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness)).attr('fill', 'none');
8402
+ .attr('pointer-events', 'stroke').attr('stroke-width', d => `${(d.look.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness) + CONNECTION_PATH_BOX_THICKNESS}px`).attr('stroke-dasharray', d => lineStyleDasharray(d.look.style || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.style, d.type.defaultLook.thickness || DIAGRAM_CONNECTION_TYPE_DEFAULTS.look.thickness)).attr('fill', 'none');
8083
8403
  mergeSelection.data().forEach(connection => {
8084
8404
  this.updateConnectionLabelsInView(connection);
8085
8405
  this.updateConnectionMarkersInView(connection);
@@ -8370,20 +8690,16 @@ class DiagramCanvas {
8370
8690
  case Side.Top:
8371
8691
  startLabelShiftX = deltaX >= 0 ? -0.5 : 0.5;
8372
8692
  endLabelShiftX = startLabelShiftX;
8373
- startLabelShiftY = -0.5;
8374
8693
  break;
8375
8694
  case Side.Bottom:
8376
8695
  startLabelShiftX = deltaX >= 0 ? -0.5 : 0.5;
8377
8696
  endLabelShiftX = startLabelShiftX;
8378
- startLabelShiftY = 0.5;
8379
8697
  break;
8380
8698
  case Side.Left:
8381
- startLabelShiftX = -0.5;
8382
8699
  startLabelShiftY = deltaY > 0 ? -0.5 : 0.5;
8383
8700
  endLabelShiftY = startLabelShiftY;
8384
8701
  break;
8385
8702
  case Side.Right:
8386
- startLabelShiftX = 0.5;
8387
8703
  startLabelShiftY = deltaY > 0 ? -0.5 : 0.5;
8388
8704
  endLabelShiftY = startLabelShiftY;
8389
8705
  break;
@@ -8396,18 +8712,14 @@ class DiagramCanvas {
8396
8712
  switch (connection.endDirection) {
8397
8713
  case Side.Top:
8398
8714
  endLabelShiftX = deltaX >= 0 ? 0.5 : -0.5;
8399
- endLabelShiftY = 0.5;
8400
8715
  break;
8401
8716
  case Side.Bottom:
8402
8717
  endLabelShiftX = deltaX >= 0 ? 0.5 : -0.5;
8403
- endLabelShiftY = -0.5;
8404
8718
  break;
8405
8719
  case Side.Left:
8406
- endLabelShiftX = -0.5;
8407
8720
  endLabelShiftY = deltaY > 0 ? 0.5 : -0.5;
8408
8721
  break;
8409
8722
  case Side.Right:
8410
- endLabelShiftX = 0.5;
8411
8723
  endLabelShiftY = deltaY > 0 ? 0.5 : -0.5;
8412
8724
  break;
8413
8725
  default:
@@ -8431,7 +8743,23 @@ class DiagramCanvas {
8431
8743
  // don't create space for the label if the label is empty
8432
8744
  const boundingWidth = !connection.startLabel ? 0 : startLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8433
8745
  const boundingHeight = !connection.startLabel ? 0 : startLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8434
- const pathStartLabelPoint = pathNode.getPointAtLength(Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8746
+ let pathStartLabelPoint;
8747
+ switch (connection.startDirection) {
8748
+ case Side.Left:
8749
+ pathStartLabelPoint = pathNode.getPointAtLength(getRightMargin(labelConfiguration) + boundingWidth / 2);
8750
+ break;
8751
+ case Side.Right:
8752
+ pathStartLabelPoint = pathNode.getPointAtLength(getLeftMargin(labelConfiguration) + boundingWidth / 2);
8753
+ break;
8754
+ case Side.Top:
8755
+ pathStartLabelPoint = pathNode.getPointAtLength(getBottomMargin(labelConfiguration) + boundingWidth / 2);
8756
+ break;
8757
+ case Side.Bottom:
8758
+ pathStartLabelPoint = pathNode.getPointAtLength(getTopMargin(labelConfiguration) + boundingWidth / 2);
8759
+ break;
8760
+ default:
8761
+ pathStartLabelPoint = pathNode.getPointAtLength(Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8762
+ }
8435
8763
  connectionSelection.select('g.diagram-connection-start-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8436
8764
  connectionSelection.select('g.diagram-connection-start-label').attr('transform', `translate(${pathStartLabelPoint.x + startLabelShiftX * boundingWidth},${pathStartLabelPoint.y + startLabelShiftY * boundingHeight})`);
8437
8765
  }
@@ -8453,7 +8781,23 @@ class DiagramCanvas {
8453
8781
  // don't create space for the label if the label is empty
8454
8782
  const boundingWidth = !connection.endLabel ? 0 : endLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8455
8783
  const boundingHeight = !connection.endLabel ? 0 : endLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8456
- const pathEndLabelPoint = pathNode.getPointAtLength(pathLength - Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8784
+ let pathEndLabelPoint;
8785
+ switch (connection.endDirection) {
8786
+ case Side.Left:
8787
+ pathEndLabelPoint = pathNode.getPointAtLength(pathLength - (getRightMargin(labelConfiguration) + boundingWidth / 2));
8788
+ break;
8789
+ case Side.Right:
8790
+ pathEndLabelPoint = pathNode.getPointAtLength(pathLength - (getLeftMargin(labelConfiguration) + boundingWidth / 2));
8791
+ break;
8792
+ case Side.Top:
8793
+ pathEndLabelPoint = pathNode.getPointAtLength(pathLength - (getBottomMargin(labelConfiguration) + boundingWidth / 2));
8794
+ break;
8795
+ case Side.Bottom:
8796
+ pathEndLabelPoint = pathNode.getPointAtLength(pathLength - (getTopMargin(labelConfiguration) + boundingWidth / 2));
8797
+ break;
8798
+ default:
8799
+ pathEndLabelPoint = pathNode.getPointAtLength(pathLength - Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8800
+ }
8457
8801
  connectionSelection.select('g.diagram-connection-end-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8458
8802
  connectionSelection.select('g.diagram-connection-end-label').attr('transform', `translate(${pathEndLabelPoint.x + endLabelShiftX * boundingWidth},${pathEndLabelPoint.y + endLabelShiftY * boundingHeight})`);
8459
8803
  }
@@ -8814,7 +9158,9 @@ class DiagramCanvas {
8814
9158
  if (this.draggingFrom[0] !== event.x || this.draggingFrom[1] !== event.y) {
8815
9159
  let newNodeCoords = [event.x - d.width / 2, event.y - d.height / 2];
8816
9160
  if (this.snapToGrid) {
8817
- newNodeCoords = this.getClosestGridPoint(newNodeCoords);
9161
+ newNodeCoords = this.getClosestGridPoint([newNodeCoords[0] - d.type.snapToGridOffset[0], newNodeCoords[1] - d.type.snapToGridOffset[1]]);
9162
+ newNodeCoords[0] += d.type.snapToGridOffset[0];
9163
+ newNodeCoords[1] += d.type.snapToGridOffset[1];
8818
9164
  }
8819
9165
  if (this.currentAction instanceof MoveAction) {
8820
9166
  const movingFrom = this.currentAction.delta;
@@ -9508,7 +9854,9 @@ class ForceLayout {
9508
9854
  }
9509
9855
  if (model.canvas && model.canvas.snapToGrid) {
9510
9856
  for (const node of model.nodes) {
9511
- const snappedCoords = model.canvas.getClosestGridPoint(node.coords);
9857
+ const snappedCoords = model.canvas.getClosestGridPoint([node.coords[0] - node.type.snapToGridOffset[0], node.coords[1] - node.type.snapToGridOffset[1]]);
9858
+ snappedCoords[0] += node.type.snapToGridOffset[0];
9859
+ snappedCoords[1] += node.type.snapToGridOffset[1];
9512
9860
  node.move(snappedCoords);
9513
9861
  }
9514
9862
  }