@plait/draw 0.52.0 → 0.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/constants/geometry.d.ts +3 -1
  2. package/esm2022/constants/geometry.mjs +4 -2
  3. package/esm2022/generators/line-auto-complete.generator.mjs +1 -1
  4. package/esm2022/interfaces/index.mjs +2 -2
  5. package/esm2022/interfaces/line.mjs +20 -8
  6. package/esm2022/line.component.mjs +5 -17
  7. package/esm2022/plugins/with-draw-fragment.mjs +1 -1
  8. package/esm2022/plugins/with-draw-hotkey.mjs +9 -7
  9. package/esm2022/plugins/with-draw-resize.mjs +114 -13
  10. package/esm2022/plugins/with-draw.mjs +5 -12
  11. package/esm2022/plugins/with-geometry-resize.mjs +8 -5
  12. package/esm2022/plugins/with-line-auto-complete-reaction.mjs +7 -4
  13. package/esm2022/plugins/with-line-auto-complete.mjs +17 -16
  14. package/esm2022/plugins/with-line-bound-reaction.mjs +20 -19
  15. package/esm2022/plugins/with-line-create.mjs +4 -4
  16. package/esm2022/plugins/with-line-resize.mjs +10 -11
  17. package/esm2022/transforms/line.mjs +4 -4
  18. package/esm2022/utils/geometry.mjs +31 -22
  19. package/esm2022/utils/hit.mjs +29 -27
  20. package/esm2022/utils/line/elbow.mjs +22 -9
  21. package/esm2022/utils/line/line-basic.mjs +21 -25
  22. package/esm2022/utils/line/line-common.mjs +27 -15
  23. package/esm2022/utils/line/line-resize.mjs +7 -11
  24. package/esm2022/utils/position/geometry.mjs +52 -20
  25. package/esm2022/utils/resize-snap.mjs +361 -0
  26. package/esm2022/utils/shape.mjs +2 -2
  27. package/fesm2022/plait-draw.mjs +556 -437
  28. package/fesm2022/plait-draw.mjs.map +1 -1
  29. package/generators/line-auto-complete.generator.d.ts +3 -3
  30. package/interfaces/index.d.ts +2 -2
  31. package/package.json +1 -1
  32. package/plugins/with-draw-fragment.d.ts +2 -2
  33. package/plugins/with-draw-resize.d.ts +12 -0
  34. package/utils/geometry.d.ts +7 -4
  35. package/utils/hit.d.ts +3 -1
  36. package/utils/line/elbow.d.ts +6 -13
  37. package/utils/line/line-basic.d.ts +4 -4
  38. package/utils/line/line-common.d.ts +3 -13
  39. package/utils/position/geometry.d.ts +12 -5
  40. package/utils/resize-snap.d.ts +49 -0
  41. package/utils/shape.d.ts +2 -2
  42. package/esm2022/generators/group.generator.mjs +0 -20
  43. package/esm2022/group.component.mjs +0 -47
  44. package/esm2022/utils/resize-align-reaction.mjs +0 -316
  45. package/esm2022/utils/resize-align.mjs +0 -37
  46. package/generators/group.generator.d.ts +0 -6
  47. package/group.component.d.ts +0 -17
  48. package/utils/resize-align-reaction.d.ts +0 -42
  49. package/utils/resize-align.d.ts +0 -8
@@ -1,5 +1,5 @@
1
- import { ACTIVE_STROKE_WIDTH, ThemeColorMode, Point, RectangleClient, getElementById, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, depthFirstRecursion, getIsRecursionFunc, idCreator, catmullRomFitting, PlaitBoard, findElements, createMask, createRect, getSelectedElements, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPolylineHitRectangle, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, Direction, Path, PlaitNode, toViewBoxPoint, toHostPoint, isSelectionMoving, RgbaToHEX, PlaitElement, preventTouchMove, createClipboardContext, WritableClipboardType, addClipboardContext, getRectangleByElements, getHitElementByPoint, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER, getRectangleByGroup, getElementsInGroup, isSelectedElementOrGroup, PlaitGroupElement } from '@plait/core';
2
- import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator, getRectangleResizeHandleRefs, RESIZE_HANDLE_DIAMETER, getMemorizedLatest, memorizeLatest, getPointOnPolyline, rotatePoints, TRANSPARENT, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getDirectionByVector, getOppositeDirection, getDirectionFactor, getDirectionByPointOfRectangle, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, normalizeShapePoints, getFirstTextEditor, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, getDirectionFactorByDirectionComponent, isCornerHandle, getFirstTextManage, withResize, drawHandle, getIndexByResizeHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, isResizingByCondition, getRatioByPoint, ImageGenerator, ResizeHandle } from '@plait/common';
1
+ import { ACTIVE_STROKE_WIDTH, ThemeColorMode, createDebugGenerator, Point, RectangleClient, getElementById, rotatePointsByElement, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPolylineHitRectangle, rotateAntiPointsByElement, rotatePoints, depthFirstRecursion, PlaitBoard, getIsRecursionFunc, idCreator, catmullRomFitting, findElements, createMask, createRect, getSelectedElements, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, Direction, hasValidAngle, Path, PlaitNode, toViewBoxPoint, toHostPoint, isSelectionMoving, RgbaToHEX, PlaitElement, getHitElementByPoint, preventTouchMove, createClipboardContext, WritableClipboardType, addClipboardContext, getSelectionAngle, getRectangleByAngle, getRectangleByElements, rotatedDataPoints, isAxisChangedByAngle, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER } from '@plait/core';
2
+ import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, DEFAULT_ROUTE_MARGIN, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator, RESIZE_HANDLE_DIAMETER, getPointOnPolyline, TRANSPARENT, getRectangleResizeHandleRefs, getRotatedResizeCursorClassByAngle, getMemorizedLatest, memorizeLatest, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getDirectionByVector, getOppositeDirection, getDirectionFactor, rotateVector, getDirectionByPointOfRectangle, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, normalizeShapePoints, getFirstTextEditor, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, resetPointsAfterResize, getDirectionFactorByDirectionComponent, isCornerHandle, getFirstTextManage, withResize, drawHandle, getIndexByResizeHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, isResizingByCondition, getRatioByPoint, ImageGenerator, ResizeHandle } from '@plait/common';
3
3
  import { Alignment, buildText, DEFAULT_FONT_SIZE, getTextSize, AlignEditor, TextManage } from '@plait/text';
4
4
  import { pointsOnBezierCurves } from 'points-on-curve';
5
5
  import * as i0 from '@angular/core';
@@ -111,7 +111,9 @@ const DefaultFlowchartPropertyMap = {
111
111
  [FlowchartSymbols.delay]: DefaultFlowchartProperty,
112
112
  [FlowchartSymbols.storedData]: DefaultFlowchartProperty
113
113
  };
114
- const REACTION_MARGIN = -4;
114
+ const LINE_HIT_GEOMETRY_BUFFER = 10;
115
+ const LINE_SNAPPING_BUFFER = 6;
116
+ const LINE_SNAPPING_CONNECTOR_BUFFER = 8;
115
117
 
116
118
  const getGeometryPointers = () => {
117
119
  return [...Object.keys(BasicShapes), ...Object.keys(FlowchartSymbols)];
@@ -166,6 +168,8 @@ const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 0.8;
166
168
  const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 10;
167
169
  const LINE_ALIGN_TOLERANCE = 3;
168
170
 
171
+ const debugKey$3 = 'debug:plait:line-mirror';
172
+ const debugGenerator$3 = createDebugGenerator(debugKey$3);
169
173
  const alignPoints = (basePoint, movingPoint) => {
170
174
  const newPoint = [...movingPoint];
171
175
  if (Point.isVertical(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
@@ -302,7 +306,7 @@ function getIndexAndDeleteCountByKeyPoint(board, element, dataPoints, nextRender
302
306
  if (midDataPoints.length > 0) {
303
307
  const handleRefPair = getLineHandleRefPair(board, element);
304
308
  const params = getElbowLineRouteOptions(board, element, handleRefPair);
305
- const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params));
309
+ const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
306
310
  const nextKeyPoints = simplifyOrthogonalPoints(keyPoints.slice(1, keyPoints.length - 1));
307
311
  const nextDataPoints = [nextRenderPoints[0], ...midDataPoints, nextRenderPoints[nextRenderPoints.length - 1]];
308
312
  const mirrorDataPoints = getMirrorDataPoints(board, nextDataPoints, nextKeyPoints, params);
@@ -429,6 +433,7 @@ function findOrthogonalParallelSegments(segment, keyPoints) {
429
433
  return parallelSegments;
430
434
  }
431
435
  function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, targetRectangle) {
436
+ debugGenerator$3.isDebug() && debugGenerator$3.clear();
432
437
  const mirrorSegments = [];
433
438
  for (let index = 0; index < parallelSegments.length; index++) {
434
439
  const parallelPath = parallelSegments[index];
@@ -442,14 +447,7 @@ function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, t
442
447
  const isValid = !RectangleClient.isHit(fakeRectangle, sourceRectangle) && !RectangleClient.isHit(fakeRectangle, targetRectangle);
443
448
  if (isValid) {
444
449
  mirrorSegments.push([startPoint, endPoint]);
445
- // const fakeRectangleG = PlaitBoard.getRoughSVG(board).rectangle(
446
- // fakeRectangle.x,
447
- // fakeRectangle.y,
448
- // fakeRectangle.width,
449
- // fakeRectangle.height,
450
- // { stroke: 'blue' }
451
- // );
452
- // PlaitBoard.getElementActiveHost(board).append(fakeRectangleG);
450
+ debugGenerator$3.isDebug() && debugGenerator$3.drawPolygon(board, RectangleClient.getCornerPoints(fakeRectangle));
453
451
  }
454
452
  }
455
453
  return mirrorSegments;
@@ -475,15 +473,20 @@ const hasIllegalElbowPoint = (midDataPoints) => {
475
473
  });
476
474
  };
477
475
 
476
+ const isSelfLoop = (element) => {
477
+ return element.source.boundId && element.source.boundId === element.target.boundId;
478
+ };
479
+ const isUseDefaultOrthogonalRoute = (element, options) => {
480
+ return isSourceAndTargetIntersect(options) && !isSelfLoop(element);
481
+ };
478
482
  const getElbowPoints = (board, element) => {
479
483
  const handleRefPair = getLineHandleRefPair(board, element);
480
484
  const params = getElbowLineRouteOptions(board, element, handleRefPair);
481
485
  // console.log(params, 'params');
482
- const isIntersect = isSourceAndTargetIntersect(params);
483
- if (isIntersect) {
484
- return simplifyOrthogonalPoints(getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, 0));
486
+ if (isUseDefaultOrthogonalRoute(element, params)) {
487
+ return simplifyOrthogonalPoints(getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, DEFAULT_ROUTE_MARGIN));
485
488
  }
486
- const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params));
489
+ const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
487
490
  const nextKeyPoints = keyPoints.slice(1, keyPoints.length - 1);
488
491
  if (element.points.length === 2) {
489
492
  return simplifyOrthogonalPoints(keyPoints);
@@ -549,8 +552,16 @@ const getSourceAndTargetRectangle = (board, element, handleRefPair) => {
549
552
  const target = handleRefPair.target;
550
553
  targetElement = createFakeElement(target.point, target.vector);
551
554
  }
552
- const sourceRectangle = RectangleClient.inflate(RectangleClient.getRectangleByPoints(sourceElement.points), getStrokeWidthByElement(sourceElement) * 2);
553
- const targetRectangle = RectangleClient.inflate(RectangleClient.getRectangleByPoints(targetElement.points), getStrokeWidthByElement(targetElement) * 2);
555
+ let sourceRectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
556
+ const rotatedSourceCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(sourceRectangle), sourceElement) ||
557
+ RectangleClient.getCornerPoints(sourceRectangle);
558
+ sourceRectangle = RectangleClient.getRectangleByPoints(rotatedSourceCornerPoints);
559
+ sourceRectangle = RectangleClient.inflate(sourceRectangle, getStrokeWidthByElement(sourceElement) * 2);
560
+ let targetRectangle = RectangleClient.getRectangleByPoints(targetElement.points);
561
+ const rotatedTargetCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(targetRectangle), targetElement) ||
562
+ RectangleClient.getCornerPoints(targetRectangle);
563
+ targetRectangle = RectangleClient.getRectangleByPoints(rotatedTargetCornerPoints);
564
+ targetRectangle = RectangleClient.inflate(targetRectangle, getStrokeWidthByElement(targetElement) * 2);
554
565
  return {
555
566
  sourceRectangle,
556
567
  targetRectangle
@@ -688,7 +699,7 @@ const drawHollowTriangleArrow = (source, target, options) => {
688
699
  return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
689
700
  };
690
701
 
691
- const getShape = (value) => {
702
+ const getElementShape = (value) => {
692
703
  if (PlaitDrawElement.isImage(value)) {
693
704
  return BasicShapes.rectangle;
694
705
  }
@@ -706,27 +717,238 @@ class LineShapeGenerator extends Generator {
706
717
  }
707
718
  }
708
719
 
709
- const getHitRectangleResizeHandleRef = (board, rectangle, point) => {
720
+ var LineResizeHandle;
721
+ (function (LineResizeHandle) {
722
+ LineResizeHandle["source"] = "source";
723
+ LineResizeHandle["target"] = "target";
724
+ LineResizeHandle["addHandle"] = "addHandle";
725
+ })(LineResizeHandle || (LineResizeHandle = {}));
726
+ const getHitLineResizeHandleRef = (board, element, point) => {
727
+ let dataPoints = PlaitLine.getPoints(board, element);
728
+ const index = getHitPointIndex(dataPoints, point);
729
+ if (index !== -1) {
730
+ const handleIndex = index;
731
+ if (index === 0) {
732
+ return { handle: LineResizeHandle.source, handleIndex };
733
+ }
734
+ if (index === dataPoints.length - 1) {
735
+ return { handle: LineResizeHandle.target, handleIndex };
736
+ }
737
+ // elbow line, data points only verify source connection point and target connection point
738
+ if (element.shape !== LineShape.elbow) {
739
+ return { handleIndex };
740
+ }
741
+ }
742
+ const middlePoints = getMiddlePoints(board, element);
743
+ const indexOfMiddlePoints = getHitPointIndex(middlePoints, point);
744
+ if (indexOfMiddlePoints !== -1) {
745
+ return {
746
+ handle: LineResizeHandle.addHandle,
747
+ handleIndex: indexOfMiddlePoints
748
+ };
749
+ }
750
+ return undefined;
751
+ };
752
+ function getHitPointIndex(points, movingPoint) {
753
+ const rectangles = points.map(point => {
754
+ return {
755
+ x: point[0] - RESIZE_HANDLE_DIAMETER / 2,
756
+ y: point[1] - RESIZE_HANDLE_DIAMETER / 2,
757
+ width: RESIZE_HANDLE_DIAMETER,
758
+ height: RESIZE_HANDLE_DIAMETER
759
+ };
760
+ });
761
+ const rectangle = rectangles.find(rectangle => {
762
+ return RectangleClient.isHit(RectangleClient.getRectangleByPoints([movingPoint, movingPoint]), rectangle);
763
+ });
764
+ return rectangle ? rectangles.indexOf(rectangle) : -1;
765
+ }
766
+ const getHitLineTextIndex = (board, element, point) => {
767
+ const texts = element.texts;
768
+ if (!texts.length)
769
+ return -1;
770
+ const points = getLinePoints(board, element);
771
+ return texts.findIndex(text => {
772
+ const center = getPointOnPolyline(points, text.position);
773
+ const rectangle = {
774
+ x: center[0] - text.width / 2,
775
+ y: center[1] - text.height / 2,
776
+ width: text.width,
777
+ height: text.height
778
+ };
779
+ return RectangleClient.isHit(rectangle, RectangleClient.getRectangleByPoints([point, point]));
780
+ });
781
+ };
782
+
783
+ const isTextExceedingBounds = (geometry) => {
784
+ const client = RectangleClient.getRectangleByPoints(geometry.points);
785
+ if (geometry.textHeight > client.height) {
786
+ return true;
787
+ }
788
+ return false;
789
+ };
790
+ const isHitLineText = (board, element, point) => {
791
+ return getHitLineTextIndex(board, element, point) !== -1;
792
+ };
793
+ const isHitPolyLine = (pathPoints, point) => {
794
+ const distance = distanceBetweenPointAndSegments(pathPoints, point);
795
+ return distance <= HIT_DISTANCE_BUFFER;
796
+ };
797
+ const isHitLine = (board, element, point) => {
798
+ const points = getLinePoints(board, element);
799
+ const isHitText = isHitLineText(board, element, point);
800
+ return isHitText || isHitPolyLine(points, point);
801
+ };
802
+ const isRectangleHitDrawElement = (board, element, selection) => {
803
+ const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
804
+ if (PlaitDrawElement.isGeometry(element)) {
805
+ const client = RectangleClient.getRectangleByPoints(element.points);
806
+ let rotatedCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(client), element) || RectangleClient.getCornerPoints(client);
807
+ if (isTextExceedingBounds(element)) {
808
+ const textClient = getTextRectangle(element);
809
+ rotatedCornerPoints =
810
+ rotatePointsByElement(RectangleClient.getCornerPoints(textClient), element) || RectangleClient.getCornerPoints(textClient);
811
+ }
812
+ return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
813
+ }
814
+ if (PlaitDrawElement.isImage(element)) {
815
+ const client = RectangleClient.getRectangleByPoints(element.points);
816
+ const rotatedCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(client), element) || RectangleClient.getCornerPoints(client);
817
+ return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
818
+ }
819
+ if (PlaitDrawElement.isLine(element)) {
820
+ const points = getLinePoints(board, element);
821
+ return isPolylineHitRectangle(points, rangeRectangle);
822
+ }
823
+ return null;
824
+ };
825
+ const isHitDrawElement = (board, element, point) => {
826
+ const rectangle = board.getRectangle(element);
827
+ point = rotateAntiPointsByElement(point, element) || point;
828
+ if (PlaitDrawElement.isGeometry(element)) {
829
+ const fill = getFillByElement(board, element);
830
+ if (isHitEdgeOfShape(board, element, point, HIT_DISTANCE_BUFFER)) {
831
+ return true;
832
+ }
833
+ const engine = getEngine(getElementShape(element));
834
+ // when shape equals text, fill is not allowed
835
+ if (fill !== DefaultGeometryStyle.fill && fill !== TRANSPARENT && !PlaitDrawElement.isText(element)) {
836
+ const isHitInside = engine.isInsidePoint(rectangle, point);
837
+ if (isHitInside) {
838
+ return isHitInside;
839
+ }
840
+ }
841
+ else {
842
+ // if shape equals text, only check text rectangle
843
+ if (PlaitDrawElement.isText(element)) {
844
+ const textClient = getTextRectangle(element);
845
+ let isHitText = RectangleClient.isPointInRectangle(textClient, point);
846
+ return isHitText;
847
+ }
848
+ // check textRectangle of element
849
+ const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
850
+ const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
851
+ if (isHitTextRectangle) {
852
+ return isHitTextRectangle;
853
+ }
854
+ }
855
+ }
856
+ if (PlaitDrawElement.isImage(element)) {
857
+ const client = RectangleClient.getRectangleByPoints(element.points);
858
+ return RectangleClient.isPointInRectangle(client, point);
859
+ }
860
+ if (PlaitDrawElement.isLine(element)) {
861
+ return isHitLine(board, element, point);
862
+ }
863
+ return null;
864
+ };
865
+ const isHitEdgeOfShape = (board, element, point, hitDistanceBuffer) => {
866
+ const nearestPoint = getNearestPoint(element, point);
867
+ const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
868
+ return distance <= hitDistanceBuffer;
869
+ };
870
+ const isInsideOfShape = (board, element, point, hitDistanceBuffer) => {
871
+ const client = RectangleClient.inflate(RectangleClient.getRectangleByPoints(element.points), hitDistanceBuffer);
872
+ return getEngine(getElementShape(element)).isInsidePoint(client, point);
873
+ };
874
+ const isHitElementInside = (board, element, point) => {
875
+ const rectangle = board.getRectangle(element);
876
+ point = rotateAntiPointsByElement(point, element) || point;
877
+ if (PlaitDrawElement.isGeometry(element)) {
878
+ const engine = getEngine(getElementShape(element));
879
+ const isHitInside = engine.isInsidePoint(rectangle, point);
880
+ if (isHitInside) {
881
+ return isHitInside;
882
+ }
883
+ if (engine.getTextRectangle) {
884
+ const textClient = engine.getTextRectangle(element);
885
+ const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
886
+ if (isHitTextRectangle) {
887
+ return isHitTextRectangle;
888
+ }
889
+ }
890
+ }
891
+ if (PlaitDrawElement.isImage(element)) {
892
+ const client = RectangleClient.getRectangleByPoints(element.points);
893
+ return RectangleClient.isPointInRectangle(client, point);
894
+ }
895
+ if (PlaitDrawElement.isLine(element)) {
896
+ return isHitLine(board, element, point);
897
+ }
898
+ return null;
899
+ };
900
+
901
+ const getHitRectangleResizeHandleRef = (board, rectangle, point, angle = 0) => {
902
+ const centerPoint = RectangleClient.getCenterPoint(rectangle);
710
903
  const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER);
711
- const result = resizeHandleRefs.find(resizeHandleRef => {
712
- return RectangleClient.isHit(RectangleClient.getRectangleByPoints([point, point]), resizeHandleRef.rectangle);
904
+ if (angle) {
905
+ const rotatedPoint = rotatePoints([point], centerPoint, -angle)[0];
906
+ let result = resizeHandleRefs.find(resizeHandleRef => {
907
+ return RectangleClient.isHit(RectangleClient.getRectangleByPoints([rotatedPoint, rotatedPoint]), resizeHandleRef.rectangle);
908
+ });
909
+ if (result) {
910
+ result.cursorClass = getRotatedResizeCursorClassByAngle(result.cursorClass, angle);
911
+ }
912
+ return result;
913
+ }
914
+ else {
915
+ return resizeHandleRefs.find(resizeHandleRef => {
916
+ return RectangleClient.isHit(RectangleClient.getRectangleByPoints([point, point]), resizeHandleRef.rectangle);
917
+ });
918
+ }
919
+ };
920
+ const getSnappingGeometry = (board, point) => {
921
+ let hitElement = getHitGeometry(board, point);
922
+ if (hitElement) {
923
+ const ref = getSnappingRef(board, hitElement, point);
924
+ if (ref.isHitConnector || ref.isHitEdge) {
925
+ return hitElement;
926
+ }
927
+ }
928
+ return null;
929
+ };
930
+ const getSnappingRef = (board, hitElement, point) => {
931
+ const rotatedPoint = rotateAntiPointsByElement(point, hitElement) || point;
932
+ const connectorPoint = getHitConnectorPoint(rotatedPoint, hitElement);
933
+ const edgePoint = getNearestPoint(hitElement, rotatedPoint);
934
+ const isHitEdge = isHitEdgeOfShape(board, hitElement, rotatedPoint, LINE_SNAPPING_BUFFER);
935
+ return { isHitEdge, isHitConnector: !!connectorPoint, connectorPoint, edgePoint };
936
+ };
937
+ const getHitGeometry = (board, point, offset = LINE_HIT_GEOMETRY_BUFFER) => {
938
+ let hitShape = null;
939
+ traverseDrawShapes(board, (element) => {
940
+ if (hitShape === null && isInsideOfShape(board, element, rotateAntiPointsByElement(point, element) || point, offset * 2)) {
941
+ hitShape = element;
942
+ }
713
943
  });
714
- return result;
944
+ return hitShape;
715
945
  };
716
- const getHitOutlineGeometry = (board, point, offset = 0) => {
717
- let geometry = null;
946
+ const traverseDrawShapes = (board, callback) => {
718
947
  depthFirstRecursion(board, node => {
719
- if (PlaitDrawElement.isGeometry(node) || PlaitDrawElement.isImage(node)) {
720
- let client = RectangleClient.getRectangleByPoints(node.points);
721
- client = RectangleClient.getOutlineRectangle(client, offset);
722
- const shape = getShape(node);
723
- const isHit = getEngine(shape).isInsidePoint(client, point);
724
- if (isHit) {
725
- geometry = node;
726
- }
948
+ if (!PlaitBoard.isBoard(node) && PlaitDrawElement.isShapeElement(node)) {
949
+ callback(node);
727
950
  }
728
951
  }, getIsRecursionFunc(board), true);
729
- return geometry;
730
952
  };
731
953
 
732
954
  const SHAPE_MAX_LENGTH = 6;
@@ -904,8 +1126,7 @@ function getMiddlePoints(board, element) {
904
1126
  if (shape === LineShape.elbow) {
905
1127
  const renderPoints = getElbowPoints(board, element);
906
1128
  const options = getElbowLineRouteOptions(board, element);
907
- const isIntersect = isSourceAndTargetIntersect(options);
908
- if (!isIntersect) {
1129
+ if (!isUseDefaultOrthogonalRoute(element, options)) {
909
1130
  const [nextSourcePoint, nextTargetPoint] = getNextSourceAndTargetPoints(board, element);
910
1131
  for (let i = 0; i < renderPoints.length - 1; i++) {
911
1132
  if ((i == 0 && Point.isEquals(renderPoints[i + 1], nextSourcePoint)) ||
@@ -945,20 +1166,18 @@ const drawLine = (board, element) => {
945
1166
  arrow && lineG.appendChild(arrow);
946
1167
  return lineG;
947
1168
  };
948
- const getConnectionByNearestPoint = (board, point, hitElement) => {
1169
+ const getHitConnection = (board, point, hitElement) => {
949
1170
  let rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
950
- let nearestPoint = getNearestPoint(hitElement, point);
951
- const hitConnector = getHitConnectorPoint(nearestPoint, hitElement, rectangle);
952
- nearestPoint = hitConnector ? hitConnector : nearestPoint;
953
- return [(nearestPoint[0] - rectangle.x) / rectangle.width, (nearestPoint[1] - rectangle.y) / rectangle.height];
954
- };
955
- const getHitConnectorPoint = (point, hitElement, rectangle) => {
956
- const shape = getShape(hitElement);
957
- const connector = getEngine(shape).getConnectorPoints(rectangle);
958
- const points = RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(point, 10, 10));
959
- const pointRectangle = RectangleClient.getRectangleByPoints(points);
960
- return connector.find(point => {
961
- return RectangleClient.isHit(pointRectangle, RectangleClient.getRectangleByPoints([point, point]));
1171
+ const ref = getSnappingRef(board, hitElement, point);
1172
+ const connectionPoint = ref.connectorPoint || ref.edgePoint;
1173
+ return [(connectionPoint[0] - rectangle.x) / rectangle.width, (connectionPoint[1] - rectangle.y) / rectangle.height];
1174
+ };
1175
+ const getHitConnectorPoint = (point, hitElement) => {
1176
+ const rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
1177
+ const shape = getElementShape(hitElement);
1178
+ const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
1179
+ return connectorPoints.find(connectorPoint => {
1180
+ return distanceBetweenPointAndPoint(...connectorPoint, ...point) <= LINE_SNAPPING_CONNECTOR_BUFFER;
962
1181
  });
963
1182
  };
964
1183
  const getLineTextRectangle = (board, element, index) => {
@@ -995,9 +1214,9 @@ const Q2C = (points) => {
995
1214
  return result;
996
1215
  };
997
1216
  const handleLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceElement, lineShapeG) => {
998
- const hitElement = getHitOutlineGeometry(board, movingPoint, REACTION_MARGIN);
999
- const targetConnection = hitElement ? getConnectionByNearestPoint(board, movingPoint, hitElement) : undefined;
1000
- const connection = sourceElement ? getConnectionByNearestPoint(board, sourcePoint, sourceElement) : undefined;
1217
+ const hitElement = getSnappingGeometry(board, movingPoint);
1218
+ const targetConnection = hitElement ? getHitConnection(board, movingPoint, hitElement) : undefined;
1219
+ const sourceConnection = sourceElement ? getHitConnection(board, sourcePoint, sourceElement) : undefined;
1001
1220
  const targetBoundId = hitElement ? hitElement.id : undefined;
1002
1221
  const lineGenerator = new LineShapeGenerator(board);
1003
1222
  const memorizedLatest = getLineMemorizedLatest();
@@ -1006,7 +1225,7 @@ const handleLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceEl
1006
1225
  targetMarker = memorizedLatest.target;
1007
1226
  sourceMarker && delete memorizedLatest.source;
1008
1227
  targetMarker && delete memorizedLatest.target;
1009
- const temporaryLineElement = createLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || LineMarkerType.none, connection: connection, boundId: sourceElement?.id }, { marker: targetMarker || LineMarkerType.arrow, connection: targetConnection, boundId: targetBoundId }, [], {
1228
+ const temporaryLineElement = createLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || LineMarkerType.none, connection: sourceConnection, boundId: sourceElement?.id }, { marker: targetMarker || LineMarkerType.arrow, connection: targetConnection, boundId: targetBoundId }, [], {
1010
1229
  strokeWidth: DefaultLineStyle.strokeWidth,
1011
1230
  ...memorizedLatest
1012
1231
  });
@@ -1060,185 +1279,6 @@ const getSelectedImageElements = (board) => {
1060
1279
  return selectedElements;
1061
1280
  };
1062
1281
 
1063
- var LineResizeHandle;
1064
- (function (LineResizeHandle) {
1065
- LineResizeHandle["source"] = "source";
1066
- LineResizeHandle["target"] = "target";
1067
- LineResizeHandle["addHandle"] = "addHandle";
1068
- })(LineResizeHandle || (LineResizeHandle = {}));
1069
- const getHitLineResizeHandleRef = (board, element, point) => {
1070
- let dataPoints = PlaitLine.getPoints(board, element);
1071
- const index = getHitPointIndex(dataPoints, point);
1072
- if (index !== -1) {
1073
- const handleIndex = index;
1074
- if (index === 0) {
1075
- return { handle: LineResizeHandle.source, handleIndex };
1076
- }
1077
- if (index === dataPoints.length - 1) {
1078
- return { handle: LineResizeHandle.target, handleIndex };
1079
- }
1080
- // elbow line, data points only verify source connection point and target connection point
1081
- if (element.shape !== LineShape.elbow) {
1082
- return { handleIndex };
1083
- }
1084
- }
1085
- const middlePoints = getMiddlePoints(board, element);
1086
- const indexOfMiddlePoints = getHitPointIndex(middlePoints, point);
1087
- if (indexOfMiddlePoints !== -1) {
1088
- return {
1089
- handle: LineResizeHandle.addHandle,
1090
- handleIndex: indexOfMiddlePoints
1091
- };
1092
- }
1093
- return undefined;
1094
- };
1095
- function getHitPointIndex(points, movingPoint) {
1096
- const rectangles = points.map(point => {
1097
- return {
1098
- x: point[0] - RESIZE_HANDLE_DIAMETER / 2,
1099
- y: point[1] - RESIZE_HANDLE_DIAMETER / 2,
1100
- width: RESIZE_HANDLE_DIAMETER,
1101
- height: RESIZE_HANDLE_DIAMETER
1102
- };
1103
- });
1104
- const rectangle = rectangles.find(rectangle => {
1105
- return RectangleClient.isHit(RectangleClient.getRectangleByPoints([movingPoint, movingPoint]), rectangle);
1106
- });
1107
- return rectangle ? rectangles.indexOf(rectangle) : -1;
1108
- }
1109
- const getHitLineTextIndex = (board, element, point) => {
1110
- const texts = element.texts;
1111
- if (!texts.length)
1112
- return -1;
1113
- const points = getLinePoints(board, element);
1114
- return texts.findIndex(text => {
1115
- const center = getPointOnPolyline(points, text.position);
1116
- const rectangle = {
1117
- x: center[0] - text.width / 2,
1118
- y: center[1] - text.height / 2,
1119
- width: text.width,
1120
- height: text.height
1121
- };
1122
- return RectangleClient.isHit(rectangle, RectangleClient.getRectangleByPoints([point, point]));
1123
- });
1124
- };
1125
-
1126
- const isTextExceedingBounds = (geometry) => {
1127
- const client = RectangleClient.getRectangleByPoints(geometry.points);
1128
- if (geometry.textHeight > client.height) {
1129
- return true;
1130
- }
1131
- return false;
1132
- };
1133
- const isHitLineText = (board, element, point) => {
1134
- return getHitLineTextIndex(board, element, point) !== -1;
1135
- };
1136
- const isHitPolyLine = (pathPoints, point) => {
1137
- const distance = distanceBetweenPointAndSegments(pathPoints, point);
1138
- return distance <= HIT_DISTANCE_BUFFER;
1139
- };
1140
- const isHitLine = (board, element, point) => {
1141
- const points = getLinePoints(board, element);
1142
- const isHitText = isHitLineText(board, element, point);
1143
- return isHitText || isHitPolyLine(points, point);
1144
- };
1145
- const isRectangleHitDrawElement = (board, element, selection) => {
1146
- const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
1147
- if (PlaitDrawElement.isGeometry(element)) {
1148
- const client = RectangleClient.getRectangleByPoints(element.points);
1149
- const centerPoint = RectangleClient.getCenterPoint(client);
1150
- let rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), centerPoint, element.angle);
1151
- if (isTextExceedingBounds(element)) {
1152
- const textClient = getTextRectangle(element);
1153
- rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(textClient), centerPoint, element.angle);
1154
- }
1155
- return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
1156
- }
1157
- if (PlaitDrawElement.isImage(element)) {
1158
- const client = RectangleClient.getRectangleByPoints(element.points);
1159
- const rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), RectangleClient.getCenterPoint(client), element.angle);
1160
- return isPolylineHitRectangle(rotatedCornerPoints, client);
1161
- }
1162
- if (PlaitDrawElement.isLine(element)) {
1163
- const points = getLinePoints(board, element);
1164
- return isPolylineHitRectangle(points, rangeRectangle);
1165
- }
1166
- return null;
1167
- };
1168
- const isHitDrawElement = (board, element, point) => {
1169
- const rectangle = board.getRectangle(element);
1170
- const centerPoint = RectangleClient.getCenterPoint(rectangle);
1171
- if (element.angle) {
1172
- point = rotate(point[0], point[1], centerPoint[0], centerPoint[1], -element.angle);
1173
- }
1174
- if (PlaitDrawElement.isGeometry(element)) {
1175
- const fill = getFillByElement(board, element);
1176
- const engine = getEngine(getShape(element));
1177
- const nearestPoint = engine.getNearestPoint(rectangle, point);
1178
- const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
1179
- const isHitEdge = distance <= HIT_DISTANCE_BUFFER;
1180
- if (isHitEdge) {
1181
- return isHitEdge;
1182
- }
1183
- // when shape equals text, fill is not allowed
1184
- if (fill !== DefaultGeometryStyle.fill && fill !== TRANSPARENT && !PlaitDrawElement.isText(element)) {
1185
- const isHitInside = engine.isInsidePoint(rectangle, point);
1186
- if (isHitInside) {
1187
- return isHitInside;
1188
- }
1189
- }
1190
- else {
1191
- // if shape equals text, only check text rectangle
1192
- if (PlaitDrawElement.isText(element)) {
1193
- const textClient = getTextRectangle(element);
1194
- let isHitText = RectangleClient.isPointInRectangle(textClient, point);
1195
- return isHitText;
1196
- }
1197
- // check textRectangle of element
1198
- const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
1199
- const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
1200
- if (isHitTextRectangle) {
1201
- return isHitTextRectangle;
1202
- }
1203
- }
1204
- }
1205
- if (PlaitDrawElement.isImage(element)) {
1206
- return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
1207
- }
1208
- if (PlaitDrawElement.isLine(element)) {
1209
- return isHitLine(board, element, point);
1210
- }
1211
- return null;
1212
- };
1213
- const isHitElementInside = (board, element, point) => {
1214
- const rectangle = board.getRectangle(element);
1215
- const centerPoint = RectangleClient.getCenterPoint(rectangle);
1216
- if (element.angle) {
1217
- point = rotate(point[0], point[1], centerPoint[0], centerPoint[1], -element.angle);
1218
- }
1219
- if (PlaitDrawElement.isGeometry(element)) {
1220
- const engine = getEngine(getShape(element));
1221
- const isHitInside = engine.isInsidePoint(rectangle, point);
1222
- if (isHitInside) {
1223
- return isHitInside;
1224
- }
1225
- if (engine.getTextRectangle) {
1226
- const textClient = engine.getTextRectangle(element);
1227
- const isHitTextRectangle = RectangleClient.isPointInRectangle(textClient, point);
1228
- if (isHitTextRectangle) {
1229
- return isHitTextRectangle;
1230
- }
1231
- }
1232
- }
1233
- if (PlaitDrawElement.isImage(element)) {
1234
- return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
1235
- }
1236
- if (PlaitDrawElement.isLine(element)) {
1237
- return isHitLine(board, element, point);
1238
- }
1239
- return null;
1240
- };
1241
-
1242
1282
  const getCenterPointsOnPolygon$1 = (points) => {
1243
1283
  const centerPoints = [];
1244
1284
  for (let i = 0; i < points.length; i++) {
@@ -2317,36 +2357,45 @@ const getTextRectangle = (element) => {
2317
2357
  y: elementRectangle.y + (elementRectangle.height - height) / 2
2318
2358
  };
2319
2359
  };
2320
- const drawBoundMask = (board, element) => {
2321
- const G = createG();
2360
+ const drawBoundReaction = (board, element, options = { hasMask: true, hasConnector: true }) => {
2361
+ const g = createG();
2322
2362
  const rectangle = RectangleClient.getRectangleByPoints(element.points);
2323
- const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
2324
- const shape = getShape(element);
2325
- const maskG = drawGeometry(board, activeRectangle, shape, {
2363
+ const activeRectangle = RectangleClient.inflate(rectangle, SNAPPING_STROKE_WIDTH);
2364
+ const shape = getElementShape(element);
2365
+ const strokeG = drawGeometry(board, activeRectangle, shape, {
2326
2366
  stroke: SELECTION_BORDER_COLOR,
2327
- strokeWidth: 1,
2328
- fill: SELECTION_FILL_COLOR,
2329
- fillStyle: 'solid'
2367
+ strokeWidth: SNAPPING_STROKE_WIDTH
2330
2368
  });
2331
- G.appendChild(maskG);
2332
- const connectorPoints = getEngine(shape).getConnectorPoints(activeRectangle);
2333
- connectorPoints.forEach(point => {
2334
- const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
2335
- stroke: '#999999',
2336
- strokeWidth: 1,
2337
- fill: '#FFF',
2369
+ g.appendChild(strokeG);
2370
+ if (options.hasMask) {
2371
+ const maskG = drawGeometry(board, activeRectangle, shape, {
2372
+ stroke: SELECTION_BORDER_COLOR,
2373
+ strokeWidth: 0,
2374
+ fill: SELECTION_FILL_COLOR,
2338
2375
  fillStyle: 'solid'
2339
2376
  });
2340
- G.appendChild(circleG);
2341
- });
2342
- return G;
2377
+ g.appendChild(maskG);
2378
+ }
2379
+ if (options.hasConnector) {
2380
+ const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
2381
+ connectorPoints.forEach(point => {
2382
+ const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 8, {
2383
+ stroke: SELECTION_BORDER_COLOR,
2384
+ strokeWidth: ACTIVE_STROKE_WIDTH,
2385
+ fill: '#FFF',
2386
+ fillStyle: 'solid'
2387
+ });
2388
+ g.appendChild(circleG);
2389
+ });
2390
+ }
2391
+ return g;
2343
2392
  };
2344
2393
  const drawGeometry = (board, outerRectangle, shape, options) => {
2345
2394
  return getEngine(shape).draw(board, outerRectangle, options);
2346
2395
  };
2347
2396
  const getNearestPoint = (element, point) => {
2348
2397
  const rectangle = RectangleClient.getRectangleByPoints(element.points);
2349
- const shape = getShape(element);
2398
+ const shape = getElementShape(element);
2350
2399
  return getEngine(shape).getNearestPoint(rectangle, point);
2351
2400
  };
2352
2401
  const getCenterPointsOnPolygon = (points) => {
@@ -2537,24 +2586,36 @@ const getLineHandleRefPair = (board, element) => {
2537
2586
  if (sourceBoundElement) {
2538
2587
  const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.source) ? 0 : strokeWidth;
2539
2588
  const sourceVector = getVectorByConnection(sourceBoundElement, element.source.connection);
2540
- const direction = getDirectionByVector(sourceVector);
2541
- sourceDirection = direction ? direction : sourceDirection;
2542
- sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
2589
+ sourceHandleRef.vector = sourceVector;
2543
2590
  sourceHandleRef.boundElement = sourceBoundElement;
2591
+ if (hasValidAngle(sourceBoundElement)) {
2592
+ const direction = getDirectionByVector(rotateVector(sourceVector, sourceBoundElement.angle));
2593
+ sourceDirection = direction ? direction : sourceDirection;
2594
+ }
2595
+ else {
2596
+ const direction = getDirectionByVector(sourceVector);
2597
+ sourceDirection = direction ? direction : sourceDirection;
2598
+ }
2544
2599
  sourceHandleRef.direction = sourceDirection;
2545
- sourceHandleRef.point = sourcePoint;
2546
- sourceHandleRef.vector = sourceVector;
2600
+ sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
2601
+ sourceHandleRef.point = rotatePointsByElement(sourcePoint, sourceBoundElement) || sourcePoint;
2547
2602
  }
2548
2603
  if (targetBoundElement) {
2549
2604
  const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.target) ? 0 : strokeWidth;
2550
2605
  const targetVector = getVectorByConnection(targetBoundElement, element.target.connection);
2551
- const direction = getDirectionByVector(targetVector);
2552
- targetDirection = direction ? direction : targetDirection;
2553
- targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
2606
+ targetHandleRef.vector = targetVector;
2554
2607
  targetHandleRef.boundElement = targetBoundElement;
2608
+ if (hasValidAngle(targetBoundElement)) {
2609
+ const direction = getDirectionByVector(rotateVector(targetVector, targetBoundElement.angle));
2610
+ targetDirection = direction ? direction : targetDirection;
2611
+ }
2612
+ else {
2613
+ const direction = getDirectionByVector(targetVector);
2614
+ targetDirection = direction ? direction : targetDirection;
2615
+ }
2555
2616
  targetHandleRef.direction = targetDirection;
2556
- targetHandleRef.point = targetPoint;
2557
- targetHandleRef.vector = targetVector;
2617
+ targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
2618
+ targetHandleRef.point = rotatePointsByElement(targetPoint, targetBoundElement) || targetPoint;
2558
2619
  }
2559
2620
  return { source: sourceHandleRef, target: targetHandleRef };
2560
2621
  };
@@ -2571,7 +2632,7 @@ const getConnectionPoint = (geometry, connection, direction, delta) => {
2571
2632
  };
2572
2633
  const getVectorByConnection = (boundElement, connection) => {
2573
2634
  const rectangle = RectangleClient.getRectangleByPoints(boundElement.points);
2574
- const shape = getShape(boundElement);
2635
+ const shape = getElementShape(boundElement);
2575
2636
  const engine = getEngine(shape);
2576
2637
  let vector = [0, 0];
2577
2638
  const direction = getDirectionByPointOfRectangle(connection);
@@ -2659,12 +2720,24 @@ const PlaitLine = {
2659
2720
  return line.target.boundId === element.id;
2660
2721
  },
2661
2722
  getPoints(board, line) {
2662
- let sourcePoint = line.source.boundId
2663
- ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
2664
- : line.points[0];
2665
- let targetPoint = line.target.boundId
2666
- ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
2667
- : line.points[line.points.length - 1];
2723
+ let sourcePoint;
2724
+ if (line.source.boundId) {
2725
+ const sourceElement = getElementById(board, line.source.boundId);
2726
+ const sourceConnectionPoint = getConnectionPoint(sourceElement, line.source.connection);
2727
+ sourcePoint = rotatePointsByElement(sourceConnectionPoint, sourceElement) || sourceConnectionPoint;
2728
+ }
2729
+ else {
2730
+ sourcePoint = line.points[0];
2731
+ }
2732
+ let targetPoint;
2733
+ if (line.target.boundId) {
2734
+ const targetElement = getElementById(board, line.target.boundId);
2735
+ const targetConnectionPoint = getConnectionPoint(targetElement, line.target.connection);
2736
+ targetPoint = rotatePointsByElement(targetConnectionPoint, targetElement) || targetConnectionPoint;
2737
+ }
2738
+ else {
2739
+ targetPoint = line.points[line.points.length - 1];
2740
+ }
2668
2741
  const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
2669
2742
  return [sourcePoint, ...restPoints, targetPoint];
2670
2743
  }
@@ -2704,7 +2777,7 @@ const PlaitDrawElement = {
2704
2777
  return false;
2705
2778
  }
2706
2779
  },
2707
- isShape: (value) => {
2780
+ isShapeElement: (value) => {
2708
2781
  return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
2709
2782
  },
2710
2783
  isBasicShape: (value) => {
@@ -2790,7 +2863,7 @@ const collectLineUpdatedRefsByGeometry = (board, geometry, refs) => {
2790
2863
  const object = { ...line[handle] };
2791
2864
  const linePoints = getLinePoints(board, line);
2792
2865
  const point = isSourceBound ? linePoints[0] : linePoints[linePoints.length - 1];
2793
- object.connection = getConnectionByNearestPoint(board, point, geometry);
2866
+ object.connection = getHitConnection(board, point, geometry);
2794
2867
  const path = PlaitBoard.findPath(board, line);
2795
2868
  const index = refs.findIndex(obj => Path.equals(obj.path, path));
2796
2869
  if (index === -1) {
@@ -2810,7 +2883,7 @@ const collectLineUpdatedRefsByGeometry = (board, geometry, refs) => {
2810
2883
  const connectLineToGeometry = (board, lineElement, handle, geometryElement) => {
2811
2884
  const linePoints = PlaitLine.getPoints(board, lineElement);
2812
2885
  const point = handle === LineHandleKey.source ? linePoints[0] : linePoints[linePoints.length - 1];
2813
- const connection = getConnectionByNearestPoint(board, point, geometryElement);
2886
+ const connection = getHitConnection(board, point, geometryElement);
2814
2887
  if (connection) {
2815
2888
  let source = lineElement.source;
2816
2889
  let target = lineElement.target;
@@ -3235,6 +3308,8 @@ class LineActiveGenerator extends Generator {
3235
3308
  }
3236
3309
  }
3237
3310
 
3311
+ const debugKey$2 = 'debug:plait:line-turning';
3312
+ const debugGenerator$2 = createDebugGenerator(debugKey$2);
3238
3313
  class LineComponent extends CommonPluginElement {
3239
3314
  constructor(viewContainerRef, cdr) {
3240
3315
  super(cdr);
@@ -3259,21 +3334,7 @@ class LineComponent extends CommonPluginElement {
3259
3334
  super.ngOnInit();
3260
3335
  this.boundedElements = this.getBoundedElements();
3261
3336
  this.drawText();
3262
- // const points = this.element.points;
3263
- // points.forEach((p, index) => {
3264
- // if (index === 0) {
3265
- // return;
3266
- // }
3267
- // if (index === points.length - 1) {
3268
- // return;
3269
- // }
3270
- // const dataPointG = PlaitBoard.getRoughSVG(this.board).circle(p[0], p[1], 8 * index, {
3271
- // stroke: '#f08c02',
3272
- // fill: '#f08c02',
3273
- // fillStyle: 'solid'
3274
- // });
3275
- // PlaitBoard.getElementActiveHost(this.board).append(dataPointG);
3276
- // });
3337
+ debugGenerator$2.isDebug() && debugGenerator$2.drawCircles(this.board, this.element.points.slice(1, -1), 4, true);
3277
3338
  }
3278
3339
  getBoundedElements() {
3279
3340
  const boundedElements = {};
@@ -3429,10 +3490,13 @@ const withDrawHotkey = (board) => {
3429
3490
  };
3430
3491
  board.dblClick = (event) => {
3431
3492
  event.preventDefault();
3432
- const geometries = getSelectedGeometryElements(board);
3433
- if (!PlaitBoard.isReadonly(board) && geometries.length === 1) {
3434
- const component = PlaitElement.getComponent(geometries[0]);
3435
- component.editText();
3493
+ if (!PlaitBoard.isReadonly(board)) {
3494
+ const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3495
+ const hitElement = getHitElementByPoint(board, point);
3496
+ if (hitElement && PlaitDrawElement.isGeometry(hitElement)) {
3497
+ const component = PlaitElement.getComponent(hitElement);
3498
+ component.editText();
3499
+ }
3436
3500
  }
3437
3501
  dblClick(event);
3438
3502
  };
@@ -3739,7 +3803,7 @@ const withLineCreateByDraw = (board) => {
3739
3803
  if (!PlaitBoard.isReadonly(board) && isLinePointer && isDrawingMode(board)) {
3740
3804
  const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3741
3805
  start = point;
3742
- const hitElement = getHitOutlineGeometry(board, point, REACTION_MARGIN);
3806
+ const hitElement = getSnappingGeometry(board, point);
3743
3807
  if (hitElement) {
3744
3808
  sourceElement = hitElement;
3745
3809
  }
@@ -3775,14 +3839,17 @@ const withLineCreateByDraw = (board) => {
3775
3839
  return board;
3776
3840
  };
3777
3841
 
3842
+ const debugKey$1 = 'debug:plait:align-for-geometry';
3843
+ const debugGenerator$1 = createDebugGenerator(debugKey$1);
3778
3844
  const ALIGN_TOLERANCE = 2;
3779
3845
  const EQUAL_SPACING = 10;
3780
3846
  const ALIGN_SPACING = 24;
3781
- class ResizeAlignReaction {
3847
+ class ResizeSnapReaction {
3782
3848
  constructor(board, activeElements) {
3783
3849
  this.board = board;
3784
3850
  this.activeElements = activeElements;
3785
3851
  this.alignRectangles = this.getAlignRectangle();
3852
+ this.angle = getSelectionAngle(activeElements);
3786
3853
  }
3787
3854
  getAlignRectangle() {
3788
3855
  const elements = findElements(this.board, {
@@ -3790,19 +3857,22 @@ class ResizeAlignReaction {
3790
3857
  recursion: () => false,
3791
3858
  isReverse: false
3792
3859
  });
3793
- return elements.map(item => this.board.getRectangle(item));
3860
+ return elements.map(item => getRectangleByAngle(this.board.getRectangle(item), item.angle) || this.board.getRectangle(item));
3794
3861
  }
3795
- getAlignLineRef(resizeAlignDelta, resizeAlignOptions) {
3862
+ getSnapRef(resizeAlignDelta, resizeSnapOptions) {
3796
3863
  const { deltaX, deltaY } = resizeAlignDelta;
3797
- const { resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoints } = resizeAlignOptions;
3864
+ const { resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoints } = resizeSnapOptions;
3798
3865
  const newResizeState = {
3799
3866
  ...resizeState,
3800
3867
  endPoint: [resizeState.endPoint[0] + deltaX, resizeState.endPoint[1] + deltaY]
3801
3868
  };
3802
3869
  const { xZoom, yZoom } = getResizeZoom(newResizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
3803
- const activePoints = resizeOriginPoints.map(p => {
3870
+ let activePoints = resizeOriginPoints.map(p => {
3804
3871
  return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
3805
3872
  });
3873
+ if (this.angle) {
3874
+ activePoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(resizeOriginPoints), RectangleClient.getRectangleByPoints(activePoints), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeOriginPoints)), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(activePoints)), this.angle);
3875
+ }
3806
3876
  return {
3807
3877
  deltaX,
3808
3878
  deltaY,
@@ -3811,40 +3881,41 @@ class ResizeAlignReaction {
3811
3881
  activePoints
3812
3882
  };
3813
3883
  }
3814
- getEqualLineDelta(resizeAlignOptions) {
3884
+ getEqualLineDelta(resizeSnapOptions) {
3815
3885
  let equalLineDelta = {
3816
3886
  deltaX: 0,
3817
3887
  deltaY: 0
3818
3888
  };
3819
- const { isAspectRatio, activeRectangle } = resizeAlignOptions;
3889
+ const { isAspectRatio, activeRectangle } = resizeSnapOptions;
3820
3890
  const widthAlignRectangle = this.alignRectangles.find(item => Math.abs(item.width - activeRectangle.width) < ALIGN_TOLERANCE);
3821
3891
  if (widthAlignRectangle) {
3822
3892
  const deltaWidth = widthAlignRectangle.width - activeRectangle.width;
3823
- equalLineDelta.deltaX = deltaWidth * resizeAlignOptions.directionFactors[0];
3893
+ equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
3824
3894
  if (isAspectRatio) {
3825
3895
  const deltaHeight = deltaWidth / (activeRectangle.width / activeRectangle.height);
3826
- equalLineDelta.deltaY = deltaHeight * resizeAlignOptions.directionFactors[1];
3896
+ equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
3827
3897
  return equalLineDelta;
3828
3898
  }
3829
3899
  }
3830
3900
  const heightAlignRectangle = this.alignRectangles.find(item => Math.abs(item.height - activeRectangle.height) < ALIGN_TOLERANCE);
3831
3901
  if (heightAlignRectangle) {
3832
3902
  const deltaHeight = heightAlignRectangle.height - activeRectangle.height;
3833
- equalLineDelta.deltaY = deltaHeight * resizeAlignOptions.directionFactors[1];
3903
+ equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
3834
3904
  if (isAspectRatio) {
3835
3905
  const deltaWidth = deltaHeight * (activeRectangle.width / activeRectangle.height);
3836
- equalLineDelta.deltaX = deltaWidth * resizeAlignOptions.directionFactors[0];
3906
+ equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
3837
3907
  return equalLineDelta;
3838
3908
  }
3839
3909
  }
3840
3910
  return equalLineDelta;
3841
3911
  }
3842
- drawEqualLines(activePoints, resizeAlignOptions) {
3912
+ drawEqualLines(activePoints, resizeSnapOptions) {
3843
3913
  let widthEqualPoints = [];
3844
3914
  let heightEqualPoints = [];
3845
- const drawHorizontalLine = resizeAlignOptions.directionFactors[0] !== 0 || resizeAlignOptions.isAspectRatio;
3846
- const drawVerticalLine = resizeAlignOptions.directionFactors[1] !== 0 || resizeAlignOptions.isAspectRatio;
3847
- const activeRectangle = RectangleClient.getRectangleByPoints(activePoints);
3915
+ const drawHorizontalLine = resizeSnapOptions.directionFactors[0] !== 0 || resizeSnapOptions.isAspectRatio;
3916
+ const drawVerticalLine = resizeSnapOptions.directionFactors[1] !== 0 || resizeSnapOptions.isAspectRatio;
3917
+ const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), this.angle) ||
3918
+ RectangleClient.getRectangleByPoints(activePoints);
3848
3919
  for (let alignRectangle of this.alignRectangles) {
3849
3920
  if (activeRectangle.width === alignRectangle.width && drawHorizontalLine) {
3850
3921
  widthEqualPoints.push(getEqualLinePoints(alignRectangle, true));
@@ -3862,12 +3933,12 @@ class ResizeAlignReaction {
3862
3933
  const equalLinePoints = [...widthEqualPoints, ...heightEqualPoints];
3863
3934
  return drawEqualLines(this.board, equalLinePoints);
3864
3935
  }
3865
- getAlignLineDelta(resizeAlignOptions) {
3936
+ getAlignLineDelta(resizeSnapOptions) {
3866
3937
  let alignLineDelta = {
3867
3938
  deltaX: 0,
3868
3939
  deltaY: 0
3869
3940
  };
3870
- const { isAspectRatio, activeRectangle, directionFactors } = resizeAlignOptions;
3941
+ const { isAspectRatio, activeRectangle, directionFactors } = resizeSnapOptions;
3871
3942
  const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
3872
3943
  const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
3873
3944
  if (drawHorizontal) {
@@ -3896,9 +3967,12 @@ class ResizeAlignReaction {
3896
3967
  }
3897
3968
  return alignLineDelta;
3898
3969
  }
3899
- drawAlignLines(activePoints, resizeAlignOptions) {
3970
+ drawAlignLines(activePoints, resizeSnapOptions) {
3971
+ debugGenerator$1.isDebug() && debugGenerator$1.clear();
3900
3972
  let alignLinePoints = [];
3901
- const activeRectangle = RectangleClient.getRectangleByPoints(activePoints);
3973
+ const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), this.angle) ||
3974
+ RectangleClient.getRectangleByPoints(activePoints);
3975
+ debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(this.board, activeRectangle, { stroke: 'green' });
3902
3976
  const alignAxisX = getTripleAlignAxis(activeRectangle, true);
3903
3977
  const alignAxisY = getTripleAlignAxis(activeRectangle, false);
3904
3978
  const alignLineRefs = [
@@ -3936,11 +4010,12 @@ class ResizeAlignReaction {
3936
4010
  alignLinePoints.push([pointStart, pointEnd]);
3937
4011
  }
3938
4012
  };
3939
- const { isAspectRatio, directionFactors } = resizeAlignOptions;
4013
+ const { isAspectRatio, directionFactors } = resizeSnapOptions;
3940
4014
  const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
3941
4015
  const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
3942
4016
  for (let index = 0; index < this.alignRectangles.length; index++) {
3943
4017
  const element = this.alignRectangles[index];
4018
+ debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(this.board, element);
3944
4019
  if (isAlign(alignLineRefs[0].axis, element, alignLineRefs[0].isHorizontal)) {
3945
4020
  alignLineRefs[0].alignRectangles.push(element);
3946
4021
  }
@@ -3980,15 +4055,15 @@ class ResizeAlignReaction {
3980
4055
  }
3981
4056
  return drawAlignLines(this.board, alignLinePoints);
3982
4057
  }
3983
- handleResizeAlign(resizeAlignOptions) {
4058
+ handleResizeSnap(resizeSnapOptions) {
3984
4059
  const alignG = createG();
3985
- let alignLineDelta = this.getEqualLineDelta(resizeAlignOptions);
4060
+ let alignLineDelta = this.getEqualLineDelta(resizeSnapOptions);
3986
4061
  if (alignLineDelta.deltaX === 0 && alignLineDelta.deltaY === 0) {
3987
- alignLineDelta = this.getAlignLineDelta(resizeAlignOptions);
4062
+ alignLineDelta = this.getAlignLineDelta(resizeSnapOptions);
3988
4063
  }
3989
- const equalLineRef = this.getAlignLineRef(alignLineDelta, resizeAlignOptions);
3990
- const equalLinesG = this.drawEqualLines(equalLineRef.activePoints, resizeAlignOptions);
3991
- const alignLinesG = this.drawAlignLines(equalLineRef.activePoints, resizeAlignOptions);
4064
+ const equalLineRef = this.getSnapRef(alignLineDelta, resizeSnapOptions);
4065
+ const equalLinesG = this.drawEqualLines(equalLineRef.activePoints, resizeSnapOptions);
4066
+ const alignLinesG = this.drawAlignLines(equalLineRef.activePoints, resizeSnapOptions);
3992
4067
  alignG.append(equalLinesG, alignLinesG);
3993
4068
  return { ...equalLineRef, alignG };
3994
4069
  }
@@ -4088,8 +4163,7 @@ function getNearestAlignRectangle(alignRectangles, activeRectangle) {
4088
4163
  });
4089
4164
  return nearestRectangle;
4090
4165
  }
4091
-
4092
- function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
4166
+ function getResizeSnapRef(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
4093
4167
  const { originPoint, handlePoint } = resizeOriginPointAndHandlePoint;
4094
4168
  const { xZoom, yZoom } = getResizeZoom(resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
4095
4169
  let activeElements;
@@ -4106,11 +4180,12 @@ function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHa
4106
4180
  const points = resizeOriginPoints.map(p => {
4107
4181
  return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
4108
4182
  });
4109
- const activeRectangle = RectangleClient.getRectangleByPoints(points);
4110
- const resizeAlignReaction = new ResizeAlignReaction(board, activeElements);
4183
+ const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(points), getSelectionAngle(activeElements)) ||
4184
+ RectangleClient.getRectangleByPoints(points);
4185
+ const resizeSnapReaction = new ResizeSnapReaction(board, activeElements);
4111
4186
  const resizeHandlePoint = movePointByZoomAndOriginPoint(handlePoint, originPoint, xZoom, yZoom);
4112
4187
  const [x, y] = getUnitVectorByPointAndPoint(originPoint, resizeHandlePoint);
4113
- return resizeAlignReaction.handleResizeAlign({
4188
+ return resizeSnapReaction.handleResizeSnap({
4114
4189
  resizeState,
4115
4190
  resizeOriginPoints,
4116
4191
  activeRectangle,
@@ -4122,10 +4197,14 @@ function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHa
4122
4197
  });
4123
4198
  }
4124
4199
 
4200
+ const debugKey = 'debug:plait:resize-for-rotation';
4201
+ const debugGenerator = createDebugGenerator(debugKey);
4125
4202
  function withDrawResize(board) {
4126
- const { afterChange } = board;
4203
+ const { afterChange, drawActiveRectangle } = board;
4127
4204
  let alignG;
4128
4205
  let handleG;
4206
+ let needCustomActiveRectangle = false;
4207
+ let resizeActivePoints = null;
4129
4208
  const canResize = () => {
4130
4209
  const elements = getSelectedElements(board);
4131
4210
  return elements.length > 1 && elements.every(el => PlaitDrawElement.isDrawElement(el));
@@ -4136,7 +4215,8 @@ function withDrawResize(board) {
4136
4215
  hitTest: (point) => {
4137
4216
  const elements = getSelectedElements(board);
4138
4217
  const boundingRectangle = getRectangleByElements(board, elements, false);
4139
- const handleRef = getHitRectangleResizeHandleRef(board, boundingRectangle, point);
4218
+ const angle = getSelectionAngle(elements);
4219
+ const handleRef = getHitRectangleResizeHandleRef(board, boundingRectangle, point, angle);
4140
4220
  if (handleRef) {
4141
4221
  return {
4142
4222
  element: elements,
@@ -4149,20 +4229,75 @@ function withDrawResize(board) {
4149
4229
  },
4150
4230
  onResize: (resizeRef, resizeState) => {
4151
4231
  alignG?.remove();
4232
+ debugGenerator.isDebug() && debugGenerator.clear();
4152
4233
  const isFromCorner = isCornerHandle(board, resizeRef.handle);
4153
4234
  const isAspectRatio = resizeState.isShift || isFromCorner;
4235
+ const centerPoint = RectangleClient.getCenterPoint(resizeRef.rectangle);
4154
4236
  const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
4155
- const resizeAlignRef = getResizeAlignRef(board, resizeRef, resizeState, {
4237
+ const angle = getSelectionAngle(resizeRef.element);
4238
+ let bulkRotationRef;
4239
+ if (angle) {
4240
+ bulkRotationRef = {
4241
+ angle: angle,
4242
+ offsetX: 0,
4243
+ offsetY: 0,
4244
+ newCenterPoint: [0, 0]
4245
+ };
4246
+ const [rotatedStartPoint, rotateEndPoint] = rotatePoints([resizeState.startPoint, resizeState.endPoint], centerPoint, -bulkRotationRef.angle);
4247
+ resizeState.startPoint = rotatedStartPoint;
4248
+ resizeState.endPoint = rotateEndPoint;
4249
+ }
4250
+ const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
4156
4251
  originPoint,
4157
4252
  handlePoint
4158
4253
  }, isAspectRatio, isFromCorner);
4254
+ resizeActivePoints = resizeAlignRef.activePoints;
4159
4255
  alignG = resizeAlignRef.alignG;
4160
4256
  PlaitBoard.getElementActiveHost(board).append(alignG);
4161
- resizeRef.element.forEach(target => {
4162
- const path = PlaitBoard.findPath(board, target);
4163
- let points = target.points.map(p => {
4257
+ if (bulkRotationRef) {
4258
+ const boundingBoxCornerPoints = RectangleClient.getPoints(resizeRef.rectangle);
4259
+ const resizedBoundingBoxCornerPoints = boundingBoxCornerPoints.map(p => {
4164
4260
  return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4165
4261
  });
4262
+ const newBoundingBox = RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints);
4263
+ debugGenerator.isDebug() && debugGenerator.drawRectangle(board, newBoundingBox, { stroke: 'blue' });
4264
+ const newBoundingBoxCenter = RectangleClient.getCenterPoint(newBoundingBox);
4265
+ const adjustedNewBoundingBoxPoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(boundingBoxCornerPoints), RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints), centerPoint, newBoundingBoxCenter, bulkRotationRef.angle);
4266
+ const newCenter = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(adjustedNewBoundingBoxPoints));
4267
+ bulkRotationRef = Object.assign(bulkRotationRef, {
4268
+ offsetX: newCenter[0] - newBoundingBoxCenter[0],
4269
+ offsetY: newCenter[1] - newBoundingBoxCenter[1],
4270
+ newCenterPoint: newCenter
4271
+ });
4272
+ debugGenerator.isDebug() && debugGenerator.drawRectangle(board, adjustedNewBoundingBoxPoints);
4273
+ }
4274
+ resizeRef.element.forEach(target => {
4275
+ const path = PlaitBoard.findPath(board, target);
4276
+ let points;
4277
+ if (bulkRotationRef) {
4278
+ const reversedPoints = rotatedDataPoints(target.points, centerPoint, -bulkRotationRef.angle);
4279
+ points = reversedPoints.map((p) => {
4280
+ return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4281
+ });
4282
+ const adjustTargetPoints = points.map(p => [
4283
+ p[0] + bulkRotationRef.offsetX,
4284
+ p[1] + bulkRotationRef.offsetY
4285
+ ]);
4286
+ points = rotatedDataPoints(adjustTargetPoints, bulkRotationRef.newCenterPoint, bulkRotationRef.angle);
4287
+ }
4288
+ else {
4289
+ if (hasValidAngle(target)) {
4290
+ needCustomActiveRectangle = true;
4291
+ }
4292
+ if (hasValidAngle(target) && isAxisChangedByAngle(target.angle)) {
4293
+ points = getResizePointsByOtherwiseAxis(board, target.points, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4294
+ }
4295
+ else {
4296
+ points = target.points.map(p => {
4297
+ return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4298
+ });
4299
+ }
4300
+ }
4166
4301
  if (PlaitDrawElement.isGeometry(target)) {
4167
4302
  const { height: textHeight } = getFirstTextManage(target).getSize();
4168
4303
  DrawTransforms.resizeGeometry(board, points, textHeight, path);
@@ -4188,6 +4323,12 @@ function withDrawResize(board) {
4188
4323
  afterResize: (resizeRef) => {
4189
4324
  alignG?.remove();
4190
4325
  alignG = null;
4326
+ if (needCustomActiveRectangle) {
4327
+ needCustomActiveRectangle = false;
4328
+ resizeActivePoints = null;
4329
+ const selectedElements = getSelectedElements(board);
4330
+ Transforms.addSelectionWithTemporaryElements(board, selectedElements);
4331
+ }
4191
4332
  }
4192
4333
  };
4193
4334
  withResize(board, options);
@@ -4200,15 +4341,32 @@ function withDrawResize(board) {
4200
4341
  if (canResize() && !isSelectionMoving(board)) {
4201
4342
  handleG = createG();
4202
4343
  const elements = getSelectedElements(board);
4203
- const boundingRectangle = getRectangleByElements(board, elements, false);
4204
- const corners = RectangleClient.getCornerPoints(boundingRectangle);
4205
- corners.forEach((corner) => {
4344
+ const boundingRectangle = needCustomActiveRectangle
4345
+ ? RectangleClient.getRectangleByPoints(resizeActivePoints)
4346
+ : getRectangleByElements(board, elements, false);
4347
+ let corners = RectangleClient.getCornerPoints(boundingRectangle);
4348
+ const angle = getSelectionAngle(elements);
4349
+ if (angle) {
4350
+ const centerPoint = RectangleClient.getCenterPoint(boundingRectangle);
4351
+ corners = rotatePoints(corners, centerPoint, angle);
4352
+ }
4353
+ corners.forEach(corner => {
4206
4354
  const g = drawHandle(board, corner);
4207
4355
  handleG && handleG.append(g);
4208
4356
  });
4209
4357
  PlaitBoard.getElementActiveHost(board).append(handleG);
4210
4358
  }
4211
4359
  };
4360
+ board.drawActiveRectangle = () => {
4361
+ if (needCustomActiveRectangle) {
4362
+ const rectangle = RectangleClient.getRectangleByPoints(resizeActivePoints);
4363
+ return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
4364
+ stroke: SELECTION_BORDER_COLOR,
4365
+ strokeWidth: ACTIVE_STROKE_WIDTH
4366
+ });
4367
+ }
4368
+ return drawActiveRectangle();
4369
+ };
4212
4370
  return board;
4213
4371
  }
4214
4372
  const getResizeOriginPointAndHandlePoint = (board, resizeRef) => {
@@ -4264,6 +4422,24 @@ const movePointByZoomAndOriginPoint = (p, resizeOriginPoint, xZoom, yZoom) => {
4264
4422
  const offsetY = (p[1] - resizeOriginPoint[1]) * yZoom;
4265
4423
  return [p[0] + offsetX, p[1] + offsetY];
4266
4424
  };
4425
+ /**
4426
+ * 1. Rotate 90°
4427
+ * 2. Scale based on the rotated points
4428
+ * 3. Reverse rotate the scaled points by 90°
4429
+ */
4430
+ const getResizePointsByOtherwiseAxis = (board, points, resizeOriginPoint, xZoom, yZoom) => {
4431
+ const currentRectangle = RectangleClient.getRectangleByPoints(points);
4432
+ debugGenerator.isDebug() && debugGenerator.drawRectangle(board, currentRectangle, { stroke: 'black' });
4433
+ let resultPoints = points;
4434
+ resultPoints = rotatePoints(resultPoints, RectangleClient.getCenterPoint(currentRectangle), (1 / 2) * Math.PI);
4435
+ debugGenerator.isDebug() && debugGenerator.drawRectangle(board, resultPoints, { stroke: 'blue' });
4436
+ resultPoints = resultPoints.map(p => {
4437
+ return movePointByZoomAndOriginPoint(p, resizeOriginPoint, xZoom, yZoom);
4438
+ });
4439
+ debugGenerator.isDebug() && debugGenerator.drawRectangle(board, resultPoints);
4440
+ const newRectangle = RectangleClient.getRectangleByPoints(resultPoints);
4441
+ return rotatePoints(resultPoints, RectangleClient.getCenterPoint(newRectangle), -(1 / 2) * Math.PI);
4442
+ };
4267
4443
 
4268
4444
  const withGeometryResize = (board) => {
4269
4445
  let alignG;
@@ -4281,7 +4457,7 @@ const withGeometryResize = (board) => {
4281
4457
  const targetComponent = PlaitElement.getComponent(selectedElements[0]);
4282
4458
  if (targetComponent.activeGenerator.hasResizeHandle) {
4283
4459
  const rectangle = board.getRectangle(target);
4284
- const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point);
4460
+ const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, target.angle);
4285
4461
  if (handleRef) {
4286
4462
  return {
4287
4463
  element: target,
@@ -4294,11 +4470,14 @@ const withGeometryResize = (board) => {
4294
4470
  return null;
4295
4471
  },
4296
4472
  onResize: (resizeRef, resizeState) => {
4473
+ const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeRef.element.points));
4474
+ resizeState.startPoint = rotateAntiPointsByElement(resizeState.startPoint, resizeRef.element) || resizeState.startPoint;
4475
+ resizeState.endPoint = rotateAntiPointsByElement(resizeState.endPoint, resizeRef.element) || resizeState.endPoint;
4297
4476
  alignG?.remove();
4298
4477
  const isFromCorner = isCornerHandle(board, resizeRef.handle);
4299
4478
  const isAspectRatio = resizeState.isShift || PlaitDrawElement.isImage(resizeRef.element);
4300
4479
  const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
4301
- const resizeAlignRef = getResizeAlignRef(board, resizeRef, resizeState, {
4480
+ const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
4302
4481
  originPoint,
4303
4482
  handlePoint
4304
4483
  }, isAspectRatio, isFromCorner);
@@ -4357,8 +4536,7 @@ const withLineResize = (board) => {
4357
4536
  resizeRef.handle !== LineResizeHandle.source &&
4358
4537
  resizeRef.handle !== LineResizeHandle.target) {
4359
4538
  const params = getElbowLineRouteOptions(board, resizeRef.element);
4360
- const isIntersect = isSourceAndTargetIntersect(params);
4361
- if (isIntersect) {
4539
+ if (isUseDefaultOrthogonalRoute(resizeRef.element, params)) {
4362
4540
  return;
4363
4541
  }
4364
4542
  const points = [...resizeRef.element.points];
@@ -4377,12 +4555,12 @@ const withLineResize = (board) => {
4377
4555
  let source = { ...resizeRef.element.source };
4378
4556
  let target = { ...resizeRef.element.target };
4379
4557
  let handleIndex = resizeRef.handleIndex;
4380
- const hitElement = getHitOutlineGeometry(board, resizeState.endPoint, REACTION_MARGIN);
4558
+ const hitElement = getSnappingGeometry(board, resizeState.endPoint);
4381
4559
  if (resizeRef.handle === LineResizeHandle.source || resizeRef.handle === LineResizeHandle.target) {
4382
4560
  const object = resizeRef.handle === LineResizeHandle.source ? source : target;
4383
4561
  points[handleIndex] = resizeState.endPoint;
4384
4562
  if (hitElement) {
4385
- object.connection = getConnectionByNearestPoint(board, resizeState.endPoint, hitElement);
4563
+ object.connection = getHitConnection(board, resizeState.endPoint, hitElement);
4386
4564
  object.boundId = hitElement.id;
4387
4565
  }
4388
4566
  else {
@@ -4424,7 +4602,8 @@ const withLineResize = (board) => {
4424
4602
  const newPoints = [...points];
4425
4603
  newPoints[0] = drawPoints[0];
4426
4604
  newPoints[newPoints.length - 1] = drawPoints[drawPoints.length - 1];
4427
- if (resizeRef.element.shape !== LineShape.elbow) {
4605
+ if (resizeRef.element.shape !== LineShape.elbow ||
4606
+ (resizeRef.element.shape === LineShape.elbow && newPoints.length === 2)) {
4428
4607
  newPoints.forEach((point, index) => {
4429
4608
  if (index === handleIndex)
4430
4609
  return;
@@ -4488,21 +4667,23 @@ const withLineBoundReaction = (board) => {
4488
4667
  return PlaitDrawElement.isLine(element) && isSourceOrTarget;
4489
4668
  });
4490
4669
  if (isLinePointer || isLineResizing) {
4491
- const hitElement = getHitOutlineGeometry(board, movingPoint, -4);
4670
+ const hitElement = getHitGeometry(board, movingPoint);
4492
4671
  if (hitElement) {
4493
- boundShapeG = drawBoundMask(board, hitElement);
4494
- let nearestPoint = getNearestPoint(hitElement, movingPoint);
4495
- const rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
4496
- const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
4497
- const hitConnector = getHitConnectorPoint(nearestPoint, hitElement, activeRectangle);
4498
- nearestPoint = hitConnector ? hitConnector : nearestPoint;
4499
- const circleG = drawCircle(PlaitBoard.getRoughSVG(board), nearestPoint, 6, {
4500
- stroke: SELECTION_BORDER_COLOR,
4501
- strokeWidth: ACTIVE_STROKE_WIDTH,
4502
- fill: SELECTION_BORDER_COLOR,
4503
- fillStyle: 'solid'
4504
- });
4505
- boundShapeG.appendChild(circleG);
4672
+ const ref = getSnappingRef(board, hitElement, movingPoint);
4673
+ const isSnapping = ref.isHitEdge || ref.isHitConnector;
4674
+ boundShapeG = drawBoundReaction(board, hitElement, { hasMask: isSnapping, hasConnector: true });
4675
+ if (isSnapping) {
4676
+ const circleG = drawCircle(PlaitBoard.getRoughSVG(board), ref.connectorPoint || ref.edgePoint, 6, {
4677
+ stroke: SELECTION_BORDER_COLOR,
4678
+ strokeWidth: SNAPPING_STROKE_WIDTH,
4679
+ fill: SELECTION_BORDER_COLOR,
4680
+ fillStyle: 'solid'
4681
+ });
4682
+ boundShapeG.appendChild(circleG);
4683
+ }
4684
+ if (hasValidAngle(hitElement)) {
4685
+ setAngleForG(boundShapeG, RectangleClient.getCenterPointByPoints(hitElement.points), hitElement.angle);
4686
+ }
4506
4687
  PlaitBoard.getElementActiveHost(board).append(boundShapeG);
4507
4688
  }
4508
4689
  }
@@ -4652,9 +4833,9 @@ const withLineAutoCompleteReaction = (board) => {
4652
4833
  const selectedElements = getSelectedDrawElements(board);
4653
4834
  const targetElement = selectedElements.length === 1 && selectedElements[0];
4654
4835
  const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4655
- if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.isShape(targetElement)) {
4836
+ if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
4656
4837
  const points = getAutoCompletePoints(targetElement);
4657
- const hitIndex = getHitIndexOfAutoCompletePoint(movingPoint, points);
4838
+ const hitIndex = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(movingPoint, targetElement) || movingPoint, points);
4658
4839
  const hitPoint = points[hitIndex];
4659
4840
  const component = PlaitElement.getComponent(targetElement);
4660
4841
  component.lineAutoCompleteGenerator.recoverAutoCompleteG();
@@ -4667,6 +4848,9 @@ const withLineAutoCompleteReaction = (board) => {
4667
4848
  });
4668
4849
  PlaitBoard.getElementActiveHost(board).append(reactionG);
4669
4850
  PlaitBoard.getBoardContainer(board).classList.add(CursorClass.crosshair);
4851
+ if (hasValidAngle(targetElement)) {
4852
+ setAngleForG(reactionG, RectangleClient.getCenterPoint(board.getRectangle(targetElement)), targetElement.angle);
4853
+ }
4670
4854
  }
4671
4855
  }
4672
4856
  pointerMove(event);
@@ -4677,7 +4861,7 @@ const withLineAutoCompleteReaction = (board) => {
4677
4861
  const WithLineAutoCompletePluginKey = 'plait-line-auto-complete-plugin-key';
4678
4862
  const withLineAutoComplete = (board) => {
4679
4863
  const { pointerDown, pointerMove, globalPointerUp } = board;
4680
- let startPoint = null;
4864
+ let autoCompletePoint = null;
4681
4865
  let lineShapeG = null;
4682
4866
  let sourceElement;
4683
4867
  let temporaryElement;
@@ -4685,13 +4869,13 @@ const withLineAutoComplete = (board) => {
4685
4869
  const selectedElements = getSelectedDrawElements(board);
4686
4870
  const targetElement = selectedElements.length === 1 && selectedElements[0];
4687
4871
  const clickPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4688
- if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.isShape(targetElement)) {
4872
+ if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
4689
4873
  const points = getAutoCompletePoints(targetElement);
4690
- const index = getHitIndexOfAutoCompletePoint(clickPoint, points);
4874
+ const index = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(clickPoint, targetElement) || clickPoint, points);
4691
4875
  const hitPoint = points[index];
4692
4876
  if (hitPoint) {
4693
4877
  temporaryDisableSelection(board);
4694
- startPoint = hitPoint;
4878
+ autoCompletePoint = hitPoint;
4695
4879
  sourceElement = targetElement;
4696
4880
  BoardTransforms.updatePointerType(board, LineShape.elbow);
4697
4881
  }
@@ -4702,18 +4886,19 @@ const withLineAutoComplete = (board) => {
4702
4886
  lineShapeG?.remove();
4703
4887
  lineShapeG = createG();
4704
4888
  let movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4705
- if (startPoint && sourceElement) {
4706
- const distance = distanceBetweenPointAndPoint(...movingPoint, ...startPoint);
4889
+ if (autoCompletePoint && sourceElement) {
4890
+ const distance = distanceBetweenPointAndPoint(...(rotateAntiPointsByElement(movingPoint, sourceElement) || movingPoint), ...autoCompletePoint);
4707
4891
  if (distance > PRESS_AND_MOVE_BUFFER) {
4708
4892
  const rectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
4709
- const shape = getShape(sourceElement);
4893
+ const shape = getElementShape(sourceElement);
4710
4894
  const engine = getEngine(shape);
4711
- let sourcePoint = startPoint;
4712
4895
  if (engine.getNearestCrossingPoint) {
4713
- const crossingPoint = engine.getNearestCrossingPoint(rectangle, startPoint);
4714
- sourcePoint = crossingPoint;
4896
+ const crossingPoint = engine.getNearestCrossingPoint(rectangle, autoCompletePoint);
4897
+ autoCompletePoint = crossingPoint;
4715
4898
  }
4716
- temporaryElement = handleLineCreating(board, LineShape.elbow, sourcePoint, movingPoint, sourceElement, lineShapeG);
4899
+ // source point must be click point
4900
+ const rotatedSourcePoint = rotatePointsByElement(autoCompletePoint, sourceElement) || autoCompletePoint;
4901
+ temporaryElement = handleLineCreating(board, LineShape.elbow, rotatedSourcePoint, movingPoint, sourceElement, lineShapeG);
4717
4902
  }
4718
4903
  }
4719
4904
  pointerMove(event);
@@ -4727,9 +4912,9 @@ const withLineAutoComplete = (board) => {
4727
4912
  ?.afterComplete;
4728
4913
  afterComplete && afterComplete(temporaryElement);
4729
4914
  }
4730
- if (startPoint) {
4915
+ if (autoCompletePoint) {
4731
4916
  BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
4732
- startPoint = null;
4917
+ autoCompletePoint = null;
4733
4918
  }
4734
4919
  lineShapeG?.remove();
4735
4920
  lineShapeG = null;
@@ -4787,66 +4972,6 @@ const withLineTextMove = (board) => {
4787
4972
  return board;
4788
4973
  };
4789
4974
 
4790
- class GroupGenerator extends Generator {
4791
- canDraw(element) {
4792
- return true;
4793
- }
4794
- draw(element, partialSelected) {
4795
- const options = {
4796
- stroke: '',
4797
- strokeWidth: ACTIVE_STROKE_WIDTH,
4798
- strokeLineDash: [5]
4799
- };
4800
- if (partialSelected) {
4801
- options.stroke = '#999';
4802
- }
4803
- const rectangle = getRectangleByGroup(this.board, element, true);
4804
- return drawRectangle(this.board, rectangle, options);
4805
- }
4806
- }
4807
-
4808
- class GroupComponent extends CommonPluginElement {
4809
- constructor(viewContainerRef, cdr) {
4810
- super(cdr);
4811
- this.viewContainerRef = viewContainerRef;
4812
- this.cdr = cdr;
4813
- }
4814
- initializeGenerator() {
4815
- this.activeGenerator = new ActiveGenerator(this.board, {
4816
- getRectangle: (element) => {
4817
- return getRectangleByGroup(this.board, element);
4818
- },
4819
- getStrokeWidth: () => 0,
4820
- getStrokeOpacity: () => 0,
4821
- hasResizeHandle: () => {
4822
- return !isSelectionMoving(this.board);
4823
- }
4824
- });
4825
- this.groupGenerator = new GroupGenerator(this.board);
4826
- }
4827
- ngOnInit() {
4828
- super.ngOnInit();
4829
- this.initializeGenerator();
4830
- }
4831
- onContextChanged(value, previous) {
4832
- const elementsInGroup = getElementsInGroup(this.board, value.element, false, true);
4833
- const isPartialSelectGroup = elementsInGroup.some(item => isSelectedElementOrGroup(this.board, item)) &&
4834
- !elementsInGroup.every(item => isSelectedElementOrGroup(this.board, item));
4835
- this.groupGenerator.processDrawing(value.element, this.g, isPartialSelectGroup);
4836
- }
4837
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GroupComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
4838
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.2.4", type: GroupComponent, isStandalone: true, selector: "plait-group", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4839
- }
4840
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GroupComponent, decorators: [{
4841
- type: Component,
4842
- args: [{
4843
- selector: 'plait-group',
4844
- template: ``,
4845
- changeDetection: ChangeDetectionStrategy.OnPush,
4846
- standalone: true
4847
- }]
4848
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }] });
4849
-
4850
4975
  const withDraw = (board) => {
4851
4976
  const { drawElement, getRectangle, isRectangleHit, isHit, isInsidePoint, isMovable, isAlign, getRelatedFragment } = board;
4852
4977
  board.drawElement = (context) => {
@@ -4859,9 +4984,6 @@ const withDraw = (board) => {
4859
4984
  else if (PlaitDrawElement.isImage(context.element)) {
4860
4985
  return ImageComponent;
4861
4986
  }
4862
- else if (PlaitGroupElement.isGroup(context.element)) {
4863
- return GroupComponent;
4864
- }
4865
4987
  return drawElement(context);
4866
4988
  };
4867
4989
  board.getRectangle = (element) => {
@@ -4880,9 +5002,6 @@ const withDraw = (board) => {
4880
5002
  if (PlaitDrawElement.isImage(element)) {
4881
5003
  return RectangleClient.getRectangleByPoints(element.points);
4882
5004
  }
4883
- if (PlaitGroupElement.isGroup(element)) {
4884
- return getRectangleByGroup(board, element);
4885
- }
4886
5005
  return getRectangle(element);
4887
5006
  };
4888
5007
  board.isRectangleHit = (element, selection) => {
@@ -4937,8 +5056,8 @@ const withDraw = (board) => {
4937
5056
  }
4938
5057
  return isAlign(element);
4939
5058
  };
4940
- board.getRelatedFragment = (elements) => {
4941
- const selectedElements = getSelectedElements(board);
5059
+ board.getRelatedFragment = (elements, originData) => {
5060
+ const selectedElements = originData || getSelectedElements(board);
4942
5061
  const lineElements = board.children.filter(element => PlaitDrawElement.isLine(element));
4943
5062
  const activeLines = lineElements.filter(line => {
4944
5063
  const source = selectedElements.find(element => element.id === line.source.boundId);
@@ -4946,7 +5065,7 @@ const withDraw = (board) => {
4946
5065
  const isSelected = selectedElements.includes(line);
4947
5066
  return source && target && !isSelected;
4948
5067
  });
4949
- return getRelatedFragment([...elements, ...activeLines]);
5068
+ return getRelatedFragment([...elements, ...activeLines], originData);
4950
5069
  };
4951
5070
  return withDrawResize(withLineTextMove(withLineAutoCompleteReaction(withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withLineAutoComplete(withGeometryCreateByDrag(withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))))))))))));
4952
5071
  };
@@ -4955,5 +5074,5 @@ const withDraw = (board) => {
4955
5074
  * Generated bundle index. Do not edit.
4956
5075
  */
4957
5076
 
4958
- export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, REACTION_MARGIN, ShapeDefaultSpace, StrokeStyle, WithLineAutoCompletePluginKey, alignElbowSegment, alignPoints, createDefaultFlowchart, createDefaultGeometry, createGeometryElement, createLineElement, createTextElement, drawBoundMask, drawGeometry, drawLine, drawLineArrow, getAutoCompletePoints, getBasicPointers, getCenterPointsOnPolygon, getConnectionByNearestPoint, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultTextPoints, getDrawDefaultStrokeColor, getElbowLineRouteOptions, getElbowPoints, getFillByElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryPointers, getHitConnectorPoint, getHitIndexOfAutoCompletePoint, getIndexAndDeleteCountByKeyPoint, getLineDashByElement, getLineHandleRefPair, getLineMemorizedLatest, getLinePointers, getLinePoints, getLineTextRectangle, getLines, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getMidKeyPoints, getMiddlePoints, getMirrorDataPoints, getNearestPoint, getNextRenderPoints, getNextSourceAndTargetPoints, getResizedPreviousAndNextPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getSourceAndTargetRectangle, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getTextShapeProperty, getVectorByConnection, handleLineCreating, hasIllegalElbowPoint, insertElement, isHitDrawElement, isHitElementInside, isHitLine, isHitLineText, isHitPolyLine, isRectangleHitDrawElement, isTextExceedingBounds, isUpdatedHandleIndex, memorizeLatestShape, memorizeLatestText, withDraw, withLineAutoComplete };
5077
+ export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LINE_HIT_GEOMETRY_BUFFER, LINE_SNAPPING_BUFFER, LINE_SNAPPING_CONNECTOR_BUFFER, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, WithLineAutoCompletePluginKey, alignElbowSegment, alignPoints, createDefaultFlowchart, createDefaultGeometry, createGeometryElement, createLineElement, createTextElement, drawBoundReaction, drawGeometry, drawLine, drawLineArrow, getAutoCompletePoints, getBasicPointers, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultTextPoints, getDrawDefaultStrokeColor, getElbowLineRouteOptions, getElbowPoints, getFillByElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryPointers, getHitConnection, getHitConnectorPoint, getHitIndexOfAutoCompletePoint, getIndexAndDeleteCountByKeyPoint, getLineDashByElement, getLineHandleRefPair, getLineMemorizedLatest, getLinePointers, getLinePoints, getLineTextRectangle, getLines, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getMidKeyPoints, getMiddlePoints, getMirrorDataPoints, getNearestPoint, getNextRenderPoints, getNextSourceAndTargetPoints, getResizedPreviousAndNextPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getSourceAndTargetRectangle, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getTextShapeProperty, getVectorByConnection, handleLineCreating, hasIllegalElbowPoint, insertElement, isHitDrawElement, isHitEdgeOfShape, isHitElementInside, isHitLine, isHitLineText, isHitPolyLine, isInsideOfShape, isRectangleHitDrawElement, isSelfLoop, isTextExceedingBounds, isUpdatedHandleIndex, isUseDefaultOrthogonalRoute, memorizeLatestShape, memorizeLatestText, withDraw, withLineAutoComplete };
4959
5078
  //# sourceMappingURL=plait-draw.mjs.map