@plait/draw 0.75.0 → 0.77.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 (38) hide show
  1. package/constants/default.d.ts +4 -0
  2. package/constants/index.d.ts +1 -0
  3. package/esm2022/arrow-line.component.mjs +14 -7
  4. package/esm2022/constants/default.mjs +6 -1
  5. package/esm2022/constants/index.mjs +2 -1
  6. package/esm2022/generators/arrow-line-auto-complete.generator.mjs +3 -3
  7. package/esm2022/generators/line-active.generator.mjs +14 -10
  8. package/esm2022/geometry.component.mjs +20 -11
  9. package/esm2022/image.component.mjs +12 -8
  10. package/esm2022/plugins/with-arrow-line-auto-complete-reaction.mjs +9 -7
  11. package/esm2022/plugins/with-arrow-line-auto-complete.mjs +9 -8
  12. package/esm2022/plugins/with-arrow-line-bound-reaction.mjs +4 -4
  13. package/esm2022/plugins/with-arrow-line-text.mjs +20 -8
  14. package/esm2022/plugins/with-draw-resize.mjs +28 -21
  15. package/esm2022/plugins/with-draw-rotate.mjs +23 -18
  16. package/esm2022/plugins/with-geometry-create.mjs +10 -10
  17. package/esm2022/plugins/with-swimlane-create.mjs +4 -4
  18. package/esm2022/plugins/with-table-resize.mjs +15 -11
  19. package/esm2022/plugins/with-table.mjs +8 -5
  20. package/esm2022/table.component.mjs +19 -12
  21. package/esm2022/utils/arrow-line/arrow-line-basic.mjs +3 -3
  22. package/esm2022/utils/common.mjs +14 -11
  23. package/esm2022/utils/geometry.mjs +12 -74
  24. package/esm2022/utils/hit.mjs +3 -3
  25. package/esm2022/utils/table-selected.mjs +1 -5
  26. package/esm2022/utils/table.mjs +3 -3
  27. package/esm2022/utils/uml.mjs +7 -5
  28. package/esm2022/utils/vector-line.mjs +2 -2
  29. package/esm2022/vector-line.component.mjs +12 -5
  30. package/fesm2022/plait-draw.mjs +1516 -1502
  31. package/fesm2022/plait-draw.mjs.map +1 -1
  32. package/generators/line-active.generator.d.ts +5 -1
  33. package/package.json +1 -1
  34. package/plugins/with-arrow-line-text.d.ts +1 -0
  35. package/plugins/with-draw-resize.d.ts +1 -0
  36. package/utils/common.d.ts +1 -0
  37. package/utils/geometry.d.ts +19 -21
  38. package/utils/table-selected.d.ts +0 -1
@@ -1,7 +1,7 @@
1
- import { ACTIVE_STROKE_WIDTH, DEFAULT_COLOR, ThemeColorMode, PlaitElement, RectangleClient, getSelectedElements, idCreator, catmullRomFitting, PlaitBoard, createG, drawLinearPath, setStrokeLinecap, setPathStrokeLinecap, getNearestPointBetweenPointAndArc, distanceBetweenPointAndPoint, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPointInPolygon, isLineHitRectangle, rotatePointsByAngle, createDebugGenerator, rotateAntiPointsByElement, getEllipseArcCenter, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, depthFirstRecursion, getIsRecursionFunc, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Point, arrowPoints, createPath, rotate, findElements, createMask, createRect, getElementById, rotatePointsByElement, PlaitNode, hasValidAngle, toViewBoxPoint, toHostPoint, Direction, rotatePoints, getRectangleByElements, getSelectionAngle, rotatedDataPoints, isAxisChangedByAngle, isSelectionMoving, drawRectangle, getRectangleByAngle, getSnapRectangles, getTripleAxis, getMinPointDelta, SNAP_TOLERANCE, drawPointSnapLines, drawSolidLines, getNearestPointBetweenPointAndSegments, isPointInEllipse, getNearestPointBetweenPointAndEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRoundRectangle, isPointInRoundRectangle, getCrossingPointsBetweenEllipseAndSegment, drawLine, getNearestPointBetweenPointAndDiscreteSegments, getNearestPointBetweenPointAndSegment, Path, RgbaToHEX, SELECTION_RECTANGLE_CLASS_NAME, getHitElementByPoint, WritableClipboardOperationType, WritableClipboardType, addOrCreateClipboardContext, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER, isMainPointer, throttleRAF, getAngleBetweenPoints, normalizeAngle, degreesToRadians, rotateElements, MERGING, ROTATE_HANDLE_CLASS_NAME, isSelectedElement, isDragging } from '@plait/core';
2
- import { DEFAULT_FILL, Alignment, WithTextPluginKey, TextManage, getMemorizedLatest, memorizeLatest, getPointOnPolyline, buildText, Generator, getStrokeLineDash, StrokeStyle, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getFirstTextEditor, sortElementsByArea, isFilled, getTextEditorsByElement, removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, getExtendPoint, getUnitVectorByPointAndPoint, getPointByVectorComponent, RESIZE_HANDLE_DIAMETER, measureElement, DEFAULT_FONT_FAMILY, getFirstTextManage, ActiveGenerator, isSourceAndTargetIntersect, getPoints, DEFAULT_ROUTE_MARGIN, normalizeShapePoints, resetPointsAfterResize, getDirectionByVector, getRectangleResizeHandleRefs, getRotatedResizeCursorClassByAngle, ROTATE_HANDLE_DISTANCE_TO_ELEMENT, ROTATE_HANDLE_SIZE, isCornerHandle, getIndexByResizeHandle, withResize, drawHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, getDirectionFactorByDirectionComponent, buildClipboardData as buildClipboardData$1, insertClipboardData as insertClipboardData$1, getDirectionByPointOfRectangle, getDirectionFactor, rotateVector, getOppositeDirection, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, PRIMARY_COLOR, CommonElementFlavour, hasResizeHandle, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, isResizingByCondition, getRatioByPoint, getTextManages, ImageGenerator, ResizeHandle, addRotating, removeRotating, drawRotateHandle } from '@plait/common';
3
- import { pointsOnBezierCurves } from 'points-on-curve';
1
+ import { ACTIVE_STROKE_WIDTH, DEFAULT_COLOR, ThemeColorMode, PlaitElement, RectangleClient, getSelectedElements, idCreator, createDebugGenerator, Point, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, catmullRomFitting, PlaitBoard, setStrokeLinecap, findElements, createMask, createRect, setPathStrokeLinecap, getNearestPointBetweenPointAndArc, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPointInPolygon, isLineHitRectangle, rotatePointsByAngle, rotateAntiPointsByElement, getEllipseArcCenter, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, depthFirstRecursion, getIsRecursionFunc, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, getI18nValue, toActiveRectangleFromViewBoxRectangle, getElementById, rotatePointsByElement, PlaitNode, hasValidAngle, toViewBoxPoint, toHostPoint, Direction, rotatePoints, getRectangleByElements, getSelectionAngle, rotatedDataPoints, isAxisChangedByAngle, isSelectionMoving, drawRectangle, getRectangleByAngle, getSnapRectangles, getTripleAxis, getMinPointDelta, SNAP_TOLERANCE, drawPointSnapLines, drawSolidLines, getNearestPointBetweenPointAndSegments, isPointInEllipse, getNearestPointBetweenPointAndEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRoundRectangle, isPointInRoundRectangle, getCrossingPointsBetweenEllipseAndSegment, drawLine, getNearestPointBetweenPointAndDiscreteSegments, getNearestPointBetweenPointAndSegment, Path, RgbaToHEX, SELECTION_RECTANGLE_CLASS_NAME, toActivePointFromViewBoxPoint, getHitElementByPoint, WritableClipboardOperationType, WritableClipboardType, addOrCreateClipboardContext, setAngleForG, CursorClass, toActivePoint, temporaryDisableSelection, toScreenPointFromActivePoint, PRESS_AND_MOVE_BUFFER, isMainPointer, throttleRAF, getAngleBetweenPoints, normalizeAngle, degreesToRadians, rotateElements, MERGING, ROTATE_HANDLE_CLASS_NAME, isSelectedElement, isDragging } from '@plait/core';
2
+ import { DEFAULT_FILL, Alignment, getMemorizedLatest, memorizeLatest, WithTextPluginKey, TextManage, StrokeStyle, removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, getExtendPoint, getUnitVectorByPointAndPoint, Generator, getPointByVectorComponent, getStrokeLineDash, getPointOnPolyline, buildText, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getFirstTextEditor, sortElementsByArea, isFilled, getTextEditorsByElement, RESIZE_HANDLE_DIAMETER, measureElement, DEFAULT_FONT_FAMILY, getFirstTextManage, isSourceAndTargetIntersect, getPoints, DEFAULT_ROUTE_MARGIN, normalizeShapePoints, resetPointsAfterResize, getDirectionByVector, getRectangleResizeHandleRefs, getRotatedResizeCursorClassByAngle, ROTATE_HANDLE_DISTANCE_TO_ELEMENT, ROTATE_HANDLE_SIZE, isCornerHandle, getIndexByResizeHandle, withResize, getSymmetricHandleIndex, getResizeHandlePointByIndex, drawHandle, getDirectionFactorByDirectionComponent, buildClipboardData as buildClipboardData$1, insertClipboardData as insertClipboardData$1, getDirectionByPointOfRectangle, getDirectionFactor, rotateVector, getOppositeDirection, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, PRIMARY_COLOR, CommonElementFlavour, createActiveGenerator, hasResizeHandle, ActiveGenerator, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, isResizingByCondition, getRatioByPoint, getTextManages, ImageGenerator, ResizeHandle, addRotating, removeRotating, drawRotateHandle } from '@plait/common';
4
3
  import { TEXT_DEFAULT_HEIGHT, DEFAULT_FONT_SIZE, AlignEditor } from '@plait/text-plugins';
4
+ import { pointsOnBezierCurves } from 'points-on-curve';
5
5
  import { Editor, Node } from 'slate';
6
6
  import { isKeyHotkey } from 'is-hotkey';
7
7
 
@@ -114,6 +114,11 @@ const PlaitTableElement = {
114
114
  };
115
115
 
116
116
  const WithDrawPluginKey = 'plait-draw-plugin-key';
117
+ var DrawI18nKey;
118
+ (function (DrawI18nKey) {
119
+ DrawI18nKey["lineText"] = "line-text";
120
+ DrawI18nKey["geometryText"] = "geometry-text";
121
+ })(DrawI18nKey || (DrawI18nKey = {}));
117
122
 
118
123
  const ShapeDefaultSpace = {
119
124
  rectangleAndText: 4
@@ -461,6 +466,18 @@ const DefaultSwimlanePropertyMap = {
461
466
 
462
467
  const MIN_TEXT_WIDTH = 5;
463
468
 
469
+ const DefaultLineStyle = {
470
+ strokeWidth: 2,
471
+ strokeColor: '#000'
472
+ };
473
+ const LINE_TEXT_SPACE = 4;
474
+ const LINE_AUTO_COMPLETE_DIAMETER = 6;
475
+ const LINE_AUTO_COMPLETE_OPACITY = 0.6;
476
+ const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 0.8;
477
+ const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 10;
478
+ const LINE_ALIGN_TOLERANCE = 3;
479
+ const LINE_TEXT = '文本';
480
+
464
481
  const getElementShape = (value) => {
465
482
  if (PlaitDrawElement.isImage(value)) {
466
483
  return BasicShapes.rectangle;
@@ -471,6 +488,97 @@ const getElementShape = (value) => {
471
488
  return value.shape;
472
489
  };
473
490
 
491
+ const SHAPE_MAX_LENGTH = 6;
492
+ const memorizedShape = new WeakMap();
493
+ const getMemorizeKey = (element) => {
494
+ let key = '';
495
+ switch (true) {
496
+ case PlaitDrawElement.isText(element): {
497
+ key = MemorizeKey.text;
498
+ break;
499
+ }
500
+ case PlaitDrawElement.isBasicShape(element): {
501
+ key = MemorizeKey.basicShape;
502
+ break;
503
+ }
504
+ case PlaitDrawElement.isFlowchart(element): {
505
+ key = MemorizeKey.flowchart;
506
+ break;
507
+ }
508
+ case PlaitDrawElement.isArrowLine(element): {
509
+ key = MemorizeKey.arrowLine;
510
+ break;
511
+ }
512
+ case PlaitDrawElement.isUML(element): {
513
+ key = MemorizeKey.UML;
514
+ }
515
+ }
516
+ return key;
517
+ };
518
+ const getLineMemorizedLatest = () => {
519
+ const properties = getMemorizedLatest(MemorizeKey.arrowLine);
520
+ return { ...properties } || {};
521
+ };
522
+ const getMemorizedLatestByPointer = (pointer) => {
523
+ let memorizeKey = '';
524
+ if (PlaitDrawElement.isBasicShape({ shape: pointer })) {
525
+ memorizeKey = pointer === BasicShapes.text ? MemorizeKey.text : MemorizeKey.basicShape;
526
+ }
527
+ else if (PlaitDrawElement.isUML({ shape: pointer })) {
528
+ memorizeKey = MemorizeKey.UML;
529
+ }
530
+ else {
531
+ memorizeKey = MemorizeKey.flowchart;
532
+ }
533
+ const properties = { ...getMemorizedLatest(memorizeKey) } || {};
534
+ const textProperties = { ...properties.text } || {};
535
+ delete properties.text;
536
+ return { textProperties, geometryProperties: properties };
537
+ };
538
+ const memorizeLatestText = (element, operations) => {
539
+ const memorizeKey = getMemorizeKey(element);
540
+ let textMemory = getMemorizedLatest(memorizeKey)?.text || {};
541
+ const setNodeOperation = operations.find(operation => operation.type === 'set_node');
542
+ if (setNodeOperation) {
543
+ const { properties, newProperties } = setNodeOperation;
544
+ for (const key in newProperties) {
545
+ const value = newProperties[key];
546
+ if (value == null) {
547
+ delete textMemory[key];
548
+ }
549
+ else {
550
+ textMemory[key] = value;
551
+ }
552
+ }
553
+ for (const key in properties) {
554
+ if (!newProperties.hasOwnProperty(key)) {
555
+ delete textMemory[key];
556
+ }
557
+ }
558
+ memorizeLatest(memorizeKey, 'text', textMemory);
559
+ }
560
+ };
561
+ const memorizeLatestShape = (board, shape) => {
562
+ const shapes = memorizedShape.has(board) ? memorizedShape.get(board) : [];
563
+ const shapeIndex = shapes.indexOf(shape);
564
+ if (shape === BasicShapes.text || shapeIndex === 0) {
565
+ return;
566
+ }
567
+ if (shapeIndex !== -1) {
568
+ shapes.splice(shapeIndex, 1);
569
+ }
570
+ else {
571
+ if (shapes.length === SHAPE_MAX_LENGTH) {
572
+ shapes.pop();
573
+ }
574
+ }
575
+ shapes.unshift(shape);
576
+ memorizedShape.set(board, shapes);
577
+ };
578
+ const getMemorizedLatestShape = (board) => {
579
+ return memorizedShape.get(board);
580
+ };
581
+
474
582
  // TODO: 是否可以完全基于位置定位 TextManager,实现 line 和 多文本 geometry 统一
475
583
  // 一个元素有多个文本时,单纯通过位置无法获取 TextManage,因此这里单独通过 Map 保存关键字 key 和 TextManage 的对应关系
476
584
  // 1. 单文本元素 key 就是元素的 id
@@ -602,10 +710,6 @@ const isSingleSelectTable = (board) => {
602
710
  const selectedElements = getSelectedElements(board);
603
711
  return selectedElements && selectedElements.length === 1 && PlaitDrawElement.isElementByTable(selectedElements[0]);
604
712
  };
605
- const isSingleSelectElementByTable = (board) => {
606
- const selectedElements = getSelectedElements(board);
607
- return selectedElements && selectedElements.length === 1 && PlaitDrawElement.isElementByTable(selectedElements[0]);
608
- };
609
713
  const getSelectedTableElements = (board, elements) => {
610
714
  const selectedElements = elements?.length ? elements : getSelectedElements(board);
611
715
  return selectedElements.filter(value => PlaitDrawElement.isElementByTable(value));
@@ -774,7 +878,7 @@ const createCell = (rowId, columnId, text = null) => {
774
878
  return cell;
775
879
  };
776
880
  const getSelectedTableCellsEditor = (board) => {
777
- if (isSingleSelectElementByTable(board)) {
881
+ if (isSingleSelectTable(board)) {
778
882
  const elements = getSelectedTableElements(board);
779
883
  const selectedCells = getSelectedCells(elements[0]);
780
884
  const selectedCellsEditor = selectedCells?.map(cell => {
@@ -788,1458 +892,1358 @@ const getSelectedTableCellsEditor = (board) => {
788
892
  return undefined;
789
893
  };
790
894
 
791
- const SHAPE_MAX_LENGTH = 6;
792
- const memorizedShape = new WeakMap();
793
- const getMemorizeKey = (element) => {
794
- let key = '';
795
- switch (true) {
796
- case PlaitDrawElement.isText(element): {
797
- key = MemorizeKey.text;
798
- break;
799
- }
800
- case PlaitDrawElement.isBasicShape(element): {
801
- key = MemorizeKey.basicShape;
802
- break;
803
- }
804
- case PlaitDrawElement.isFlowchart(element): {
805
- key = MemorizeKey.flowchart;
806
- break;
807
- }
808
- case PlaitDrawElement.isArrowLine(element): {
809
- key = MemorizeKey.arrowLine;
810
- break;
811
- }
812
- case PlaitDrawElement.isUML(element): {
813
- key = MemorizeKey.UML;
814
- }
815
- }
816
- return key;
895
+ const getStrokeColorByElement = (board, element) => {
896
+ const defaultColor = getDrawDefaultStrokeColor(board.theme.themeColorMode);
897
+ const strokeColor = element.strokeColor || defaultColor;
898
+ return strokeColor;
817
899
  };
818
- const getLineMemorizedLatest = () => {
819
- const properties = getMemorizedLatest(MemorizeKey.arrowLine);
820
- return { ...properties } || {};
900
+ const getFillByElement = (board, element) => {
901
+ const defaultFill = PlaitDrawElement.isFlowchart(element) && isClosedDrawElement(element)
902
+ ? getFlowchartDefaultFill(board.theme.themeColorMode)
903
+ : DefaultDrawStyle.fill;
904
+ const fill = element.fill || defaultFill;
905
+ return fill;
821
906
  };
822
- const getMemorizedLatestByPointer = (pointer) => {
823
- let memorizeKey = '';
824
- if (PlaitDrawElement.isBasicShape({ shape: pointer })) {
825
- memorizeKey = pointer === BasicShapes.text ? MemorizeKey.text : MemorizeKey.basicShape;
826
- }
827
- else if (PlaitDrawElement.isUML({ shape: pointer })) {
828
- memorizeKey = MemorizeKey.UML;
907
+ const getStrokeStyleByElement = (board, element) => {
908
+ return element.strokeStyle || StrokeStyle.solid;
909
+ };
910
+
911
+ const debugKey$4 = 'debug:plait:line-mirror';
912
+ const debugGenerator$4 = createDebugGenerator(debugKey$4);
913
+ const alignPoints = (basePoint, movingPoint) => {
914
+ const newPoint = [...movingPoint];
915
+ if (Point.isVertical(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
916
+ newPoint[0] = basePoint[0];
829
917
  }
830
- else {
831
- memorizeKey = MemorizeKey.flowchart;
918
+ if (Point.isHorizontal(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
919
+ newPoint[1] = basePoint[1];
832
920
  }
833
- const properties = { ...getMemorizedLatest(memorizeKey) } || {};
834
- const textProperties = { ...properties.text } || {};
835
- delete properties.text;
836
- return { textProperties, geometryProperties: properties };
921
+ return newPoint;
837
922
  };
838
- const memorizeLatestText = (element, operations) => {
839
- const memorizeKey = getMemorizeKey(element);
840
- let textMemory = getMemorizedLatest(memorizeKey)?.text || {};
841
- const setNodeOperation = operations.find(operation => operation.type === 'set_node');
842
- if (setNodeOperation) {
843
- const { properties, newProperties } = setNodeOperation;
844
- for (const key in newProperties) {
845
- const value = newProperties[key];
846
- if (value == null) {
847
- delete textMemory[key];
848
- }
849
- else {
850
- textMemory[key] = value;
851
- }
852
- }
853
- for (const key in properties) {
854
- if (!newProperties.hasOwnProperty(key)) {
855
- delete textMemory[key];
856
- }
857
- }
858
- memorizeLatest(memorizeKey, 'text', textMemory);
923
+ function getResizedPreviousAndNextPoint(nextRenderPoints, sourcePoint, targetPoint, handleIndex) {
924
+ const referencePoint = {
925
+ previous: null,
926
+ next: null
927
+ };
928
+ const startPoint = nextRenderPoints[handleIndex];
929
+ const endPoint = nextRenderPoints[handleIndex + 1];
930
+ const isHorizontal = Point.isHorizontal(startPoint, endPoint);
931
+ const isVertical = Point.isVertical(startPoint, endPoint);
932
+ const previousPoint = nextRenderPoints[handleIndex - 1] ?? nextRenderPoints[0];
933
+ const beforePreviousPoint = nextRenderPoints[handleIndex - 2] ?? sourcePoint;
934
+ if ((isHorizontal && Point.isHorizontal(beforePreviousPoint, previousPoint)) ||
935
+ (isVertical && Point.isVertical(beforePreviousPoint, previousPoint))) {
936
+ referencePoint.previous = previousPoint;
859
937
  }
860
- };
861
- const memorizeLatestShape = (board, shape) => {
862
- const shapes = memorizedShape.has(board) ? memorizedShape.get(board) : [];
863
- const shapeIndex = shapes.indexOf(shape);
864
- if (shape === BasicShapes.text || shapeIndex === 0) {
865
- return;
938
+ const nextPoint = nextRenderPoints[handleIndex + 2] ?? nextRenderPoints[nextRenderPoints.length - 1];
939
+ const afterNextPoint = nextRenderPoints[handleIndex + 3] ?? targetPoint;
940
+ if ((isHorizontal && Point.isHorizontal(nextPoint, afterNextPoint)) || (isVertical && Point.isVertical(nextPoint, afterNextPoint))) {
941
+ referencePoint.next = nextPoint;
866
942
  }
867
- if (shapeIndex !== -1) {
868
- shapes.splice(shapeIndex, 1);
943
+ return referencePoint;
944
+ }
945
+ function alignElbowSegment(startKeyPoint, endKeyPoint, resizeState, resizedPreviousAndNextPoint) {
946
+ let newStartPoint = startKeyPoint;
947
+ let newEndPoint = endKeyPoint;
948
+ if (Point.isHorizontal(startKeyPoint, endKeyPoint)) {
949
+ const offsetY = Point.getOffsetY(resizeState.startPoint, resizeState.endPoint);
950
+ let pointY = startKeyPoint[1] + offsetY;
951
+ if (resizedPreviousAndNextPoint.previous && Math.abs(resizedPreviousAndNextPoint.previous[1] - pointY) < LINE_ALIGN_TOLERANCE) {
952
+ pointY = resizedPreviousAndNextPoint.previous[1];
953
+ }
954
+ else if (resizedPreviousAndNextPoint.next && Math.abs(resizedPreviousAndNextPoint.next[1] - pointY) < LINE_ALIGN_TOLERANCE) {
955
+ pointY = resizedPreviousAndNextPoint.next[1];
956
+ }
957
+ newStartPoint = [startKeyPoint[0], pointY];
958
+ newEndPoint = [endKeyPoint[0], pointY];
869
959
  }
870
- else {
871
- if (shapes.length === SHAPE_MAX_LENGTH) {
872
- shapes.pop();
960
+ if (Point.isVertical(startKeyPoint, endKeyPoint)) {
961
+ const offsetX = Point.getOffsetX(resizeState.startPoint, resizeState.endPoint);
962
+ let pointX = startKeyPoint[0] + offsetX;
963
+ if (resizedPreviousAndNextPoint.previous && Math.abs(resizedPreviousAndNextPoint.previous[0] - pointX) < LINE_ALIGN_TOLERANCE) {
964
+ pointX = resizedPreviousAndNextPoint.previous[0];
965
+ }
966
+ else if (resizedPreviousAndNextPoint.next && Math.abs(resizedPreviousAndNextPoint.next[0] - pointX) < LINE_ALIGN_TOLERANCE) {
967
+ pointX = resizedPreviousAndNextPoint.next[0];
873
968
  }
969
+ newStartPoint = [pointX, startKeyPoint[1]];
970
+ newEndPoint = [pointX, endKeyPoint[1]];
874
971
  }
875
- shapes.unshift(shape);
876
- memorizedShape.set(board, shapes);
877
- };
878
- const getMemorizedLatestShape = (board) => {
879
- return memorizedShape.get(board);
880
- };
881
-
882
- const getHitArrowLineTextIndex = (board, element, point) => {
883
- const texts = element.texts;
884
- if (!texts.length)
885
- return -1;
886
- const points = getArrowLinePoints(board, element);
887
- return texts.findIndex(text => {
888
- const center = getPointOnPolyline(points, text.position);
889
- const rectangle = {
890
- x: center[0] - text.width / 2,
891
- y: center[1] - text.height / 2,
892
- width: text.width,
893
- height: text.height
894
- };
895
- return RectangleClient.isHit(rectangle, RectangleClient.getRectangleByPoints([point, point]));
896
- });
897
- };
898
-
899
- const isMultipleTextShape = (shape) => {
900
- return GEOMETRY_WITH_MULTIPLE_TEXT.includes(shape);
901
- };
902
- const isMultipleTextGeometry = (geometry) => {
903
- return PlaitDrawElement.isGeometry(geometry) && isMultipleTextShape(geometry.shape);
904
- };
905
- const getMultipleTextGeometryTextKeys = (shape) => {
906
- return MultipleTextGeometryTextKeys[shape];
907
- };
908
- const createMultipleTextGeometryElement = (shape, points, options = {}) => {
909
- const id = idCreator();
910
- const drawShapeTexts = buildDefaultTextsByShape(shape);
911
- return {
912
- id,
913
- type: 'geometry',
914
- shape,
915
- angle: 0,
916
- opacity: 1,
917
- texts: drawShapeTexts,
918
- points,
919
- ...options
920
- };
921
- };
922
- const buildDefaultTextsByShape = (shape) => {
923
- const memorizedLatest = getMemorizedLatestByPointer(shape);
924
- const textProperties = { ...memorizedLatest.textProperties };
925
- const alignment = textProperties?.align;
926
- const textHeight = textProperties?.textHeight || DefaultTextProperty.height;
927
- delete textProperties?.align;
928
- delete textProperties?.textHeight;
929
- const defaultTexts = getDefaultGeometryProperty(shape)?.texts || [];
930
- const textKeys = getMultipleTextGeometryTextKeys(shape);
931
- return (textKeys || []).map((textKey) => {
932
- const text = defaultTexts?.find((item) => item?.key === textKey);
972
+ return [newStartPoint, newEndPoint];
973
+ }
974
+ function getIndexAndDeleteCountByKeyPoint(board, element, dataPoints, nextRenderPoints, handleIndex) {
975
+ let index = null;
976
+ let deleteCount = null;
977
+ const startKeyPoint = nextRenderPoints[handleIndex];
978
+ const endKeyPoint = nextRenderPoints[handleIndex + 1];
979
+ if (!startKeyPoint || !endKeyPoint) {
933
980
  return {
934
- id: textKey,
935
- text: buildText(text?.text || '', alignment || text?.align || Alignment.center, textProperties),
936
- textHeight: textHeight
981
+ index,
982
+ deleteCount
937
983
  };
938
- });
939
- };
940
- const getHitMultipleGeometryText = (element, point) => {
941
- const engine = getEngine(element.shape);
942
- const rectangle = RectangleClient.getRectangleByPoints([point, point]);
943
- let hitText;
944
- if (engine.getTextRectangle) {
945
- hitText = element.texts.find(text => {
946
- const textRectangle = engine.getTextRectangle(element, { id: text.id });
947
- return RectangleClient.isHit(rectangle, textRectangle);
948
- });
949
- }
950
- return hitText;
951
- };
952
-
953
- const DefaultLineStyle = {
954
- strokeWidth: 2,
955
- strokeColor: '#000'
956
- };
957
- const LINE_TEXT_SPACE = 4;
958
- const LINE_AUTO_COMPLETE_DIAMETER = 6;
959
- const LINE_AUTO_COMPLETE_OPACITY = 0.6;
960
- const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 0.8;
961
- const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 10;
962
- const LINE_ALIGN_TOLERANCE = 3;
963
- const LINE_TEXT = '文本';
964
-
965
- class VectorLineShapeGenerator extends Generator {
966
- canDraw(element) {
967
- return true;
968
984
  }
969
- draw(element) {
970
- let lineG;
971
- lineG = drawVectorLine(this.board, element);
972
- return lineG;
985
+ const midDataPoints = dataPoints.slice(1, -1);
986
+ const startIndex = midDataPoints.findIndex(item => Point.isEquals(item, startKeyPoint));
987
+ const endIndex = midDataPoints.findIndex(item => Point.isEquals(item, endKeyPoint));
988
+ if (Math.max(startIndex, endIndex) > -1) {
989
+ if (startIndex > -1 && endIndex > -1) {
990
+ return {
991
+ index: startIndex,
992
+ deleteCount: 2
993
+ };
994
+ }
995
+ if (startIndex > -1 && endIndex === -1) {
996
+ const isReplace = startIndex < midDataPoints.length - 1 &&
997
+ Point.isAlign([midDataPoints[startIndex], midDataPoints[startIndex + 1], startKeyPoint, endKeyPoint]);
998
+ if (isReplace) {
999
+ return {
1000
+ index: startIndex,
1001
+ deleteCount: 2
1002
+ };
1003
+ }
1004
+ return {
1005
+ index: startIndex,
1006
+ deleteCount: 1
1007
+ };
1008
+ }
1009
+ if (startIndex === -1 && endIndex > -1) {
1010
+ const isReplace = endIndex > 0 && Point.isAlign([midDataPoints[endIndex], midDataPoints[endIndex - 1], startKeyPoint, endKeyPoint]);
1011
+ if (isReplace) {
1012
+ return {
1013
+ index: endIndex - 1,
1014
+ deleteCount: 2
1015
+ };
1016
+ }
1017
+ return {
1018
+ index: endIndex,
1019
+ deleteCount: 1
1020
+ };
1021
+ }
973
1022
  }
974
- }
975
-
976
- const getVectorLinePoints = (board, element) => {
977
- switch (element.shape) {
978
- case VectorLineShape.straight: {
979
- return element.points;
1023
+ else {
1024
+ for (let i = 0; i < midDataPoints.length - 1; i++) {
1025
+ const currentPoint = midDataPoints[i];
1026
+ const nextPoint = midDataPoints[i + 1];
1027
+ if (Point.isAlign([currentPoint, nextPoint, startKeyPoint, endKeyPoint])) {
1028
+ index = i;
1029
+ deleteCount = 2;
1030
+ break;
1031
+ }
1032
+ if (Point.isAlign([currentPoint, nextPoint, startKeyPoint])) {
1033
+ index = Math.min(i + 1, midDataPoints.length - 1);
1034
+ deleteCount = 1;
1035
+ break;
1036
+ }
1037
+ if (Point.isAlign([currentPoint, nextPoint, endKeyPoint])) {
1038
+ index = Math.max(i - 1, 0);
1039
+ deleteCount = 1;
1040
+ break;
1041
+ }
980
1042
  }
981
- case VectorLineShape.curve: {
982
- if (element.points.length === 2) {
983
- return pointsOnBezierCurves(element.points);
1043
+ }
1044
+ if (index === null) {
1045
+ deleteCount = 0;
1046
+ if (midDataPoints.length > 0) {
1047
+ const handleRefPair = getArrowLineHandleRefPair(board, element);
1048
+ const params = getElbowLineRouteOptions(board, element, handleRefPair);
1049
+ const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
1050
+ const nextKeyPoints = simplifyOrthogonalPoints(keyPoints.slice(1, keyPoints.length - 1));
1051
+ const nextDataPoints = [nextRenderPoints[0], ...midDataPoints, nextRenderPoints[nextRenderPoints.length - 1]];
1052
+ const mirrorDataPoints = getMirrorDataPoints(board, nextDataPoints, nextKeyPoints, params);
1053
+ for (let i = handleIndex - 1; i >= 0; i--) {
1054
+ const previousIndex = mirrorDataPoints.slice(1, -1).findIndex(item => Point.isEquals(item, nextRenderPoints[i]));
1055
+ if (previousIndex > -1) {
1056
+ index = previousIndex + 1;
1057
+ break;
1058
+ }
984
1059
  }
985
- else {
986
- let dataPoints = element.points;
987
- const points = catmullRomFitting(dataPoints);
988
- return pointsOnBezierCurves(points);
1060
+ if (index === null) {
1061
+ index = 0;
1062
+ // When renderPoints is a straight line and dataPoints are not on the line,
1063
+ // the default 'deleteCount' is set to midDataPoints.length.
1064
+ if (Point.isAlign(nextRenderPoints)) {
1065
+ deleteCount = midDataPoints.length;
1066
+ }
989
1067
  }
990
1068
  }
991
- default:
992
- return null;
1069
+ else {
1070
+ index = 0;
1071
+ }
993
1072
  }
994
- };
995
- const createVectorLineElement = (shape, points, options) => {
996
1073
  return {
997
- id: idCreator(),
998
- type: 'vector-line',
999
- shape,
1000
- opacity: 1,
1001
- points,
1002
- ...options
1074
+ index,
1075
+ deleteCount
1003
1076
  };
1004
- };
1005
- const vectorLineCreating = (board, lineShape, points, movingPoint, lineShapeG) => {
1006
- const lineGenerator = new VectorLineShapeGenerator(board);
1007
- const memorizedLatest = getLineMemorizedLatest();
1008
- const temporaryLineElement = createVectorLineElement(lineShape, [...points, movingPoint], {
1009
- strokeWidth: DefaultLineStyle.strokeWidth,
1010
- ...memorizedLatest
1011
- });
1012
- const otherPoint = points[points.length - 1];
1013
- temporaryLineElement.points[temporaryLineElement.points.length - 1] = alignPoints(otherPoint, movingPoint);
1014
- lineGenerator.processDrawing(temporaryLineElement, lineShapeG);
1015
- PlaitBoard.getElementActiveHost(board).append(lineShapeG);
1016
- return temporaryLineElement;
1017
- };
1018
- const drawVectorLine = (board, element) => {
1019
- const strokeWidth = getStrokeWidthByElement(element);
1020
- const strokeColor = getStrokeColorByElement(board, element);
1021
- const strokeStyle = getStrokeStyleByElement(board, element);
1022
- const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
1023
- const fill = getFillByElement(board, element);
1024
- const options = { stroke: strokeColor, strokeWidth, strokeLineDash, fill };
1025
- const lineG = createG();
1026
- let points = getVectorLinePoints(board, element);
1027
- const line = drawLinearPath(points, options);
1028
- const id = idCreator();
1029
- line.setAttribute('mask', `url(#${id})`);
1030
- if (element.strokeStyle === StrokeStyle.dotted) {
1031
- setStrokeLinecap(line, 'round');
1032
- }
1033
- lineG.appendChild(line);
1034
- return lineG;
1035
- };
1036
-
1037
- const getCenterPointsOnPolygon$1 = (points) => {
1038
- const centerPoints = [];
1039
- for (let i = 0; i < points.length; i++) {
1040
- let j = i == points.length - 1 ? 0 : i + 1;
1041
- centerPoints.push([(points[i][0] + points[j][0]) / 2, (points[i][1] + points[j][1]) / 2]);
1042
- }
1043
- return centerPoints;
1044
- };
1045
- const getCrossingPointBetweenPointAndPolygon = (corners, point) => {
1046
- const result = [];
1047
- for (let index = 1; index <= corners.length; index++) {
1048
- let start = corners[index - 1];
1049
- let end = index === corners.length ? corners[0] : corners[index];
1050
- const crossingPoint = getCrossingPointsBetweenPointAndSegment(point, start, end);
1051
- result.push(...crossingPoint);
1077
+ }
1078
+ function getMirrorDataPoints(board, nextDataPoints, nextKeyPoints, params) {
1079
+ for (let index = 1; index < nextDataPoints.length - 2; index++) {
1080
+ adjustByCustomPointStartIndex(board, index, nextDataPoints, nextKeyPoints, params);
1052
1081
  }
1053
- return result;
1054
- };
1055
- const getPolygonEdgeByConnectionPoint = (corners, point) => {
1056
- for (let index = 1; index <= corners.length; index++) {
1057
- let start = corners[index - 1];
1058
- let end = index === corners.length ? corners[0] : corners[index];
1059
- if (isPointOnSegment(point, start, end)) {
1060
- return [start, end];
1061
- }
1082
+ return nextDataPoints;
1083
+ }
1084
+ /**
1085
+ * adjust based parallel segment
1086
+ */
1087
+ const adjustByCustomPointStartIndex = (board, customPointStartIndex, nextDataPoints, nextKeyPoints, params) => {
1088
+ const beforePoint = nextDataPoints[customPointStartIndex - 1];
1089
+ const startPoint = nextDataPoints[customPointStartIndex];
1090
+ const endPoint = nextDataPoints[customPointStartIndex + 1];
1091
+ const afterPoint = nextDataPoints[customPointStartIndex + 2];
1092
+ const beforeSegment = [beforePoint, startPoint];
1093
+ const afterSegment = [endPoint, afterPoint];
1094
+ const isStraightWithBefore = Point.isAlign(beforeSegment);
1095
+ const isStraightWithAfter = Point.isAlign(afterSegment);
1096
+ let isAdjustStart = false;
1097
+ let isAdjustEnd = false;
1098
+ if (!isStraightWithBefore || !isStraightWithAfter) {
1099
+ const midKeyPointsWithBefore = getMidKeyPoints(nextKeyPoints, beforeSegment[0], beforeSegment[1]);
1100
+ const midKeyPointsWithAfter = getMidKeyPoints(nextKeyPoints, afterSegment[0], afterSegment[1]);
1101
+ const hasMidKeyPoints = midKeyPointsWithBefore.length > 0 && midKeyPointsWithAfter.length > 0;
1102
+ isAdjustStart = !isStraightWithBefore && !hasMidKeyPoints;
1103
+ isAdjustEnd = !isStraightWithAfter && !hasMidKeyPoints;
1062
1104
  }
1063
- return null;
1064
- };
1065
-
1066
- function generateCloudPath(rectangle) {
1067
- const divisionWidth = rectangle.width / 7;
1068
- const divisionHeight = rectangle.height / 3.2;
1069
- const xRadius = divisionWidth / 8.5;
1070
- const yRadius = divisionHeight / 20;
1071
- const startPoint = [rectangle.x + divisionWidth, rectangle.y + divisionHeight];
1072
- const arcCommands = [
1073
- {
1074
- rx: xRadius,
1075
- ry: yRadius * 1.2,
1076
- xAxisRotation: 0,
1077
- largeArcFlag: 1,
1078
- sweepFlag: 1,
1079
- endX: rectangle.x + divisionWidth * 2,
1080
- endY: rectangle.y + divisionHeight / 2
1081
- },
1082
- {
1083
- rx: xRadius,
1084
- ry: yRadius,
1085
- xAxisRotation: 0,
1086
- largeArcFlag: 1,
1087
- sweepFlag: 1,
1088
- endX: rectangle.x + divisionWidth * 4.2,
1089
- endY: rectangle.y + divisionHeight / 2.2
1090
- },
1091
- {
1092
- rx: xRadius,
1093
- ry: yRadius,
1094
- xAxisRotation: 0,
1095
- largeArcFlag: 1,
1096
- sweepFlag: 1,
1097
- endX: rectangle.x + divisionWidth * 5.8,
1098
- endY: rectangle.y + divisionHeight
1099
- },
1100
- {
1101
- rx: xRadius,
1102
- ry: yRadius * 1.3,
1103
- xAxisRotation: 0,
1104
- largeArcFlag: 1,
1105
- sweepFlag: 1,
1106
- endX: rectangle.x + divisionWidth * 6,
1107
- endY: rectangle.y + divisionHeight * 2.2
1108
- },
1109
- {
1110
- rx: xRadius,
1111
- ry: yRadius * 1.2,
1112
- xAxisRotation: 0,
1113
- largeArcFlag: 1,
1114
- sweepFlag: 1,
1115
- endX: rectangle.x + divisionWidth * 5,
1116
- endY: rectangle.y + divisionHeight * 2.8
1117
- },
1118
- {
1119
- rx: xRadius,
1120
- ry: yRadius / 1.2,
1121
- xAxisRotation: 0,
1122
- largeArcFlag: 1,
1123
- sweepFlag: 1,
1124
- endX: rectangle.x + divisionWidth * 2.8,
1125
- endY: rectangle.y + divisionHeight * 2.8
1126
- },
1127
- {
1128
- rx: xRadius,
1129
- ry: yRadius,
1130
- xAxisRotation: 0,
1131
- largeArcFlag: 1,
1132
- sweepFlag: 1,
1133
- endX: rectangle.x + divisionWidth,
1134
- endY: rectangle.y + divisionHeight * 2.2
1135
- },
1136
- {
1137
- rx: xRadius,
1138
- ry: yRadius * 1.42,
1139
- xAxisRotation: 0,
1140
- largeArcFlag: 1,
1141
- sweepFlag: 1,
1142
- endX: rectangle.x + divisionWidth,
1143
- endY: rectangle.y + divisionHeight
1105
+ if (isAdjustStart || isAdjustEnd) {
1106
+ const parallelSegment = [startPoint, endPoint];
1107
+ const parallelSegments = findOrthogonalParallelSegments(parallelSegment, nextKeyPoints);
1108
+ const mirrorSegments = findMirrorSegments(board, parallelSegment, parallelSegments, params.sourceRectangle, params.targetRectangle);
1109
+ if (mirrorSegments.length === 1) {
1110
+ const mirrorSegment = mirrorSegments[0];
1111
+ if (isAdjustStart) {
1112
+ nextDataPoints.splice(customPointStartIndex, 1, mirrorSegment[0]);
1113
+ }
1114
+ if (isAdjustEnd) {
1115
+ nextDataPoints.splice(customPointStartIndex + 1, 1, mirrorSegment[1]);
1116
+ }
1144
1117
  }
1145
- ];
1146
- return { startPoint, arcCommands };
1147
- }
1148
- const CloudEngine = {
1149
- draw(board, rectangle, options) {
1150
- const rs = PlaitBoard.getRoughSVG(board);
1151
- const { startPoint, arcCommands } = generateCloudPath(rectangle);
1152
- const pathData = `M ${startPoint[0]} ${startPoint[1]} ` +
1153
- arcCommands
1154
- .map((command) => `A ${command.rx} ${command.ry} ${command.xAxisRotation} ${command.largeArcFlag} ${command.sweepFlag} ${command.endX} ${command.endY}`)
1155
- .join('\n') +
1156
- ' Z';
1157
- const svgElement = rs.path(pathData, { ...options, fillStyle: 'solid' });
1158
- setPathStrokeLinecap(svgElement, 'round');
1159
- return svgElement;
1160
- },
1161
- isInsidePoint(rectangle, point) {
1162
- const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
1163
- return RectangleClient.isHit(rectangle, rangeRectangle);
1164
- },
1165
- getCornerPoints(rectangle) {
1166
- return RectangleClient.getCornerPoints(rectangle);
1167
- },
1168
- getNearestPoint(rectangle, point) {
1169
- const { startPoint, arcCommands } = generateCloudPath(rectangle);
1170
- let minDistance = Infinity;
1171
- let nearestPoint = point;
1172
- let currentStart = startPoint;
1173
- for (const arcCommand of arcCommands) {
1174
- const arcNearestPoint = getNearestPointBetweenPointAndArc(point, currentStart, arcCommand);
1175
- const distance = distanceBetweenPointAndPoint(point[0], point[1], arcNearestPoint[0], arcNearestPoint[1]);
1176
- if (distance < minDistance) {
1177
- minDistance = distance;
1178
- nearestPoint = arcNearestPoint;
1118
+ else {
1119
+ const isHorizontal = Point.isHorizontal(startPoint, endPoint);
1120
+ const adjustIndex = isHorizontal ? 0 : 1;
1121
+ if (isAdjustStart) {
1122
+ const newStartPoint = [startPoint[0], startPoint[1]];
1123
+ newStartPoint[adjustIndex] = beforePoint[adjustIndex];
1124
+ nextDataPoints.splice(customPointStartIndex, 1, newStartPoint);
1125
+ }
1126
+ if (isAdjustEnd) {
1127
+ const newEndPoint = [endPoint[0], endPoint[1]];
1128
+ newEndPoint[adjustIndex] = afterPoint[adjustIndex];
1129
+ nextDataPoints.splice(customPointStartIndex + 1, 1, newEndPoint);
1179
1130
  }
1180
- currentStart = [arcCommand.endX, arcCommand.endY];
1181
1131
  }
1182
- return nearestPoint;
1183
- },
1184
- getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
1185
- const corners = CloudEngine.getCornerPoints(rectangle);
1186
- const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1187
- return getPolygonEdgeByConnectionPoint(corners, point);
1188
- },
1189
- getConnectorPoints(rectangle) {
1190
- return RectangleClient.getEdgeCenterPoints(rectangle);
1191
- },
1192
- getTextRectangle(element) {
1193
- const elementRectangle = RectangleClient.getRectangleByPoints(element.points);
1194
- const strokeWidth = getStrokeWidthByElement(element);
1195
- const height = element.textHeight;
1196
- const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1197
- const width = originWidth / 1.5;
1198
- return {
1199
- height,
1200
- width: width > 0 ? width : 0,
1201
- x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 6,
1202
- y: elementRectangle.y + elementRectangle.height / 6 + ((elementRectangle.height * 4) / 6 - height) / 2
1203
- };
1204
1132
  }
1205
1133
  };
1206
-
1207
- const isTextExceedingBounds = (geometry) => {
1208
- const client = RectangleClient.getRectangleByPoints(geometry.points);
1209
- if (geometry.textHeight && geometry.textHeight > client.height) {
1134
+ function isUpdatedHandleIndex(board, element, dataPoints, nextRenderPoints, handleIndex) {
1135
+ const { deleteCount } = getIndexAndDeleteCountByKeyPoint(board, element, dataPoints, nextRenderPoints, handleIndex);
1136
+ if (deleteCount !== null && deleteCount > 1) {
1210
1137
  return true;
1211
1138
  }
1212
1139
  return false;
1213
- };
1214
- const isHitArrowLineText = (board, element, point) => {
1215
- return getHitArrowLineTextIndex(board, element, point) !== -1;
1216
- };
1217
- const isHitPolyLine = (pathPoints, point) => {
1218
- const distance = distanceBetweenPointAndSegments(point, pathPoints);
1219
- return distance <= HIT_DISTANCE_BUFFER;
1220
- };
1221
- const isHitArrowLine = (board, element, point) => {
1222
- const points = getArrowLinePoints(board, element);
1223
- const isHitText = isHitArrowLineText(board, element, point);
1224
- return isHitText || isHitPolyLine(points, point);
1225
- };
1226
- const isHitVectorLine = (board, element, point) => {
1227
- const points = getVectorLinePoints(board, element);
1228
- if (isClosedPoints(element.points)) {
1229
- return isPointInPolygon(point, points) || isHitPolyLine(points, point);
1230
- }
1231
- else {
1232
- return isHitPolyLine(points, point);
1233
- }
1234
- };
1235
- const isRectangleHitElementText = (element, rectangle) => {
1236
- const engine = getEngine(element.shape);
1237
- if (isMultipleTextGeometry(element)) {
1238
- const texts = element.texts;
1239
- return texts.some((item) => {
1240
- const textClient = engine.getTextRectangle(element, { id: item.id });
1241
- return isRectangleHitRotatedPoints(rectangle, RectangleClient.getCornerPoints(textClient), element.angle);
1242
- });
1140
+ }
1141
+ function getMidKeyPoints(simplifiedNextKeyPoints, startPoint, endPoint) {
1142
+ let midElbowPoints = [];
1143
+ let startPointIndex = -1;
1144
+ let endPointIndex = -1;
1145
+ for (let i = 0; i < simplifiedNextKeyPoints.length; i++) {
1146
+ if (Point.isAlign([simplifiedNextKeyPoints[i], startPoint])) {
1147
+ startPointIndex = i;
1148
+ }
1149
+ if (startPointIndex > -1 && Point.isAlign([simplifiedNextKeyPoints[i], endPoint])) {
1150
+ endPointIndex = i;
1151
+ break;
1152
+ }
1243
1153
  }
1244
- else {
1245
- const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
1246
- return isRectangleHitRotatedPoints(rectangle, RectangleClient.getCornerPoints(textClient), element.angle);
1154
+ if (startPointIndex > -1 && endPointIndex > -1) {
1155
+ midElbowPoints = simplifiedNextKeyPoints.slice(startPointIndex, endPointIndex + 1);
1247
1156
  }
1248
- };
1249
- const isHitElementText = (element, point) => {
1250
- const engine = getEngine(element.shape);
1251
- if (isMultipleTextGeometry(element)) {
1252
- const texts = element.texts;
1253
- return texts.some((item) => {
1254
- const textClient = engine.getTextRectangle(element, { id: item.id });
1255
- return RectangleClient.isPointInRectangle(textClient, point);
1256
- });
1157
+ return midElbowPoints;
1158
+ }
1159
+ function findOrthogonalParallelSegments(segment, keyPoints) {
1160
+ const isHorizontalSegment = Point.isHorizontal(segment[0], segment[1]);
1161
+ const parallelSegments = [];
1162
+ for (let i = 0; i < keyPoints.length - 1; i++) {
1163
+ const current = keyPoints[i];
1164
+ const next = keyPoints[i + 1];
1165
+ const isHorizontal = Point.isHorizontal(current, next, 0.1);
1166
+ if (isHorizontalSegment && isHorizontal) {
1167
+ parallelSegments.push([current, next]);
1168
+ }
1169
+ if (!isHorizontalSegment && !isHorizontal) {
1170
+ parallelSegments.push([current, next]);
1171
+ }
1257
1172
  }
1258
- else {
1259
- const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
1260
- return RectangleClient.isPointInRectangle(textClient, point);
1173
+ return parallelSegments;
1174
+ }
1175
+ function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, targetRectangle) {
1176
+ debugGenerator$4.isDebug() && debugGenerator$4.clear();
1177
+ const mirrorSegments = [];
1178
+ for (let index = 0; index < parallelSegments.length; index++) {
1179
+ const parallelPath = parallelSegments[index];
1180
+ const startPoint = [segment[0][0], segment[0][1]];
1181
+ const endPoint = [segment[1][0], segment[1][1]];
1182
+ const isHorizontal = Point.isHorizontal(startPoint, endPoint);
1183
+ const adjustDataIndex = isHorizontal ? 0 : 1;
1184
+ startPoint[adjustDataIndex] = parallelPath[0][adjustDataIndex];
1185
+ endPoint[adjustDataIndex] = parallelPath[1][adjustDataIndex];
1186
+ const fakeRectangle = RectangleClient.getRectangleByPoints([startPoint, endPoint, ...parallelPath]);
1187
+ const isValid = !RectangleClient.isHit(fakeRectangle, sourceRectangle) && !RectangleClient.isHit(fakeRectangle, targetRectangle);
1188
+ if (isValid) {
1189
+ mirrorSegments.push([startPoint, endPoint]);
1190
+ debugGenerator$4.isDebug() && debugGenerator$4.drawPolygon(board, RectangleClient.getCornerPoints(fakeRectangle));
1191
+ }
1261
1192
  }
1262
- };
1263
- const isEmptyTextElement = (element) => {
1264
- if (!isDrawElementIncludeText(element)) {
1193
+ return mirrorSegments;
1194
+ }
1195
+ const hasIllegalElbowPoint = (midDataPoints) => {
1196
+ if (midDataPoints.length === 1) {
1265
1197
  return true;
1266
1198
  }
1267
- const editor = getFirstTextEditor(element);
1268
- return Editor.isEmpty(editor, editor.children[0]);
1269
- };
1270
- const isRectangleHitDrawElement = (board, element, selection) => {
1271
- const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
1272
- if (PlaitDrawElement.isGeometry(element)) {
1273
- const isHitElement = isRectangleHitRotatedElement(board, rangeRectangle, element);
1274
- if (isHitElement) {
1275
- return isHitElement;
1199
+ return midDataPoints.some((item, index) => {
1200
+ const beforePoint = midDataPoints[index - 1];
1201
+ const afterPoint = midDataPoints[index + 1];
1202
+ const beforeSegment = beforePoint && [beforePoint, item];
1203
+ const afterSegment = afterPoint && [item, afterPoint];
1204
+ const isStraightWithBefore = beforeSegment && Point.isAlign(beforeSegment);
1205
+ const isStraightWithAfter = afterSegment && Point.isAlign(afterSegment);
1206
+ if (index === 0) {
1207
+ return !isStraightWithAfter;
1276
1208
  }
1277
- return !isEmptyTextElement(element) && isRectangleHitElementText(element, rangeRectangle);
1278
- }
1279
- if (PlaitDrawElement.isImage(element)) {
1280
- return isRectangleHitRotatedElement(board, rangeRectangle, element);
1281
- }
1282
- if (PlaitDrawElement.isArrowLine(element)) {
1283
- const points = getArrowLinePoints(board, element);
1284
- return isLineHitRectangle(points, rangeRectangle);
1285
- }
1286
- if (PlaitDrawElement.isVectorLine(element)) {
1287
- const points = getVectorLinePoints(board, element);
1288
- return isLineHitRectangle(points, rangeRectangle);
1289
- }
1290
- return null;
1291
- };
1292
- const isRectangleHitRotatedElement = (board, rectangle, element) => {
1293
- const client = RectangleClient.getRectangleByPoints(element.points);
1294
- return isRectangleHitRotatedPoints(rectangle, RectangleClient.getCornerPoints(client), element.angle);
1295
- };
1296
- const isRectangleHitRotatedPoints = (rectangle, points, angle) => {
1297
- let rotatedPoints = rotatePointsByAngle(points, angle) || points;
1298
- return isLineHitRectangle(rotatedPoints, rectangle);
1209
+ if (index === midDataPoints.length - 1) {
1210
+ return !isStraightWithBefore;
1211
+ }
1212
+ return !isStraightWithBefore && !isStraightWithAfter;
1213
+ });
1299
1214
  };
1300
- const getHitDrawElement = (board, elements) => {
1301
- let firstFilledElement = getFirstFilledDrawElement(board, elements);
1302
- let endIndex = elements.length;
1303
- if (firstFilledElement) {
1304
- endIndex = elements.indexOf(firstFilledElement) + 1;
1305
- }
1306
- const newElements = elements.slice(0, endIndex);
1307
- const element = getFirstTextOrLineElement(newElements);
1308
- if (element) {
1309
- return element;
1215
+
1216
+ const ARROW_LENGTH = 20;
1217
+ const drawArrowLineArrow = (element, points, options) => {
1218
+ const arrowG = createG();
1219
+ if (PlaitArrowLine.isSourceMark(element, ArrowLineMarkerType.none) && PlaitArrowLine.isTargetMark(element, ArrowLineMarkerType.none)) {
1220
+ return null;
1310
1221
  }
1311
- const sortElements = sortElementsByArea(board, newElements, 'asc');
1312
- return sortElements[0];
1313
- };
1314
- const getFirstFilledDrawElement = (board, elements) => {
1315
- let filledElement = null;
1316
- for (let i = 0; i < elements.length; i++) {
1317
- const element = elements[i];
1318
- if (isClosedCustomGeometry(board, element) || isClosedDrawElement(element)) {
1319
- const fill = getFillByElement(board, element);
1320
- if (isFilled(fill)) {
1321
- filledElement = element;
1322
- break;
1323
- }
1324
- }
1222
+ const strokeWidth = getStrokeWidthByElement(element);
1223
+ const offset = (strokeWidth * strokeWidth) / 3;
1224
+ if (points.length === 1) {
1225
+ points = [points[0], [points[0][0] + 0.1, points[0][1]]];
1325
1226
  }
1326
- return filledElement;
1327
- };
1328
- const isFilledDrawElement = (board, element) => {
1329
- return getFirstFilledDrawElement(board, [element]) !== null;
1330
- };
1331
- const getFirstTextOrLineElement = (elements) => {
1332
- const texts = elements.filter((item) => PlaitDrawElement.isText(item));
1333
- if (texts.length) {
1334
- return texts[0];
1227
+ if (!PlaitArrowLine.isSourceMark(element, ArrowLineMarkerType.none)) {
1228
+ const source = getExtendPoint(points[0], points[1], ARROW_LENGTH + offset);
1229
+ const sourceArrow = getArrow(element, { marker: element.source.marker, source, target: points[0], isSource: true }, options);
1230
+ sourceArrow && arrowG.appendChild(sourceArrow);
1335
1231
  }
1336
- const lines = elements.filter((item) => PlaitDrawElement.isArrowLine(item));
1337
- if (lines.length) {
1338
- return lines[0];
1232
+ if (!PlaitArrowLine.isTargetMark(element, ArrowLineMarkerType.none)) {
1233
+ const source = getExtendPoint(points[points.length - 1], points[points.length - 2], ARROW_LENGTH + offset);
1234
+ const arrow = getArrow(element, { marker: element.target.marker, source, target: points[points.length - 1], isSource: false }, options);
1235
+ arrow && arrowG.appendChild(arrow);
1339
1236
  }
1340
- return null;
1237
+ return arrowG;
1341
1238
  };
1342
- const debugKey$4 = 'debug:plait:hit:shape:edge:sample-points';
1343
- const debugGenerator$4 = createDebugGenerator(debugKey$4);
1344
- const shapes = [BasicShapes.cloud];
1345
- const isHitDrawElement = (board, element, point, isStrict = true) => {
1346
- const rectangle = board.getRectangle(element);
1347
- point = rotateAntiPointsByElement(point, element) || point;
1348
- if (PlaitDrawElement.isGeometry(element) && rectangle) {
1349
- if (debugGenerator$4.isDebug() && shapes.includes(element.shape)) {
1350
- debugGenerator$4.clear();
1351
- const { startPoint, arcCommands } = generateCloudPath(rectangle);
1352
- const points = [startPoint, ...arcCommands.map((arc) => [arc.endX, arc.endY])];
1353
- debugGenerator$4.drawCircles(board, points, 5, false);
1354
- let minDistance = Infinity;
1355
- let nearestPoint = point;
1356
- let currentStart = startPoint;
1357
- for (const arc of arcCommands) {
1358
- const arcNearestPoint = getNearestPointBetweenPointAndArc(point, currentStart, arc);
1359
- const distance = distanceBetweenPointAndPoint(point[0], point[1], arcNearestPoint[0], arcNearestPoint[1]);
1360
- const { center } = getEllipseArcCenter(currentStart, arc);
1361
- debugGenerator$4.drawCircles(board, [center], 8, false, { fill: 'yellow' });
1362
- if (distance < minDistance) {
1363
- minDistance = distance;
1364
- nearestPoint = arcNearestPoint;
1365
- }
1366
- currentStart = [arc.endX, arc.endY];
1367
- }
1368
- debugGenerator$4.drawCircles(board, [point], 12, false, { fill: 'black', stroke: 'black' });
1369
- debugGenerator$4.drawCircles(board, [nearestPoint], 12, false, { fill: 'green', stroke: 'green' });
1239
+ const getArrow = (element, arrowOptions, options) => {
1240
+ const { marker, target, source, isSource } = arrowOptions;
1241
+ let targetArrow;
1242
+ switch (marker) {
1243
+ case ArrowLineMarkerType.openTriangle: {
1244
+ targetArrow = drawOpenTriangle(element, source, target, options);
1245
+ break;
1370
1246
  }
1371
- if (isHitEdgeOfShape(board, element, point, HIT_DISTANCE_BUFFER)) {
1372
- return true;
1247
+ case ArrowLineMarkerType.solidTriangle: {
1248
+ targetArrow = drawSolidTriangle(source, target, options);
1249
+ break;
1373
1250
  }
1374
- const engine = getEngine(getElementShape(element));
1375
- if (PlaitDrawElement.isText(element)) {
1376
- const textClient = getTextRectangle(element);
1377
- return RectangleClient.isPointInRectangle(textClient, point);
1251
+ case ArrowLineMarkerType.arrow: {
1252
+ targetArrow = drawArrow(element, source, target, options);
1253
+ break;
1378
1254
  }
1379
- if (!!isStrict && isEmptyTextElement(element) && !isFilledDrawElement(board, element)) {
1380
- return false;
1255
+ case ArrowLineMarkerType.sharpArrow: {
1256
+ targetArrow = drawSharpArrow(source, target, options);
1257
+ break;
1381
1258
  }
1382
- const isHitText = isHitElementText(element, point);
1383
- return isHitText || engine.isInsidePoint(rectangle, point);
1384
- }
1385
- if (PlaitDrawElement.isImage(element)) {
1386
- const client = RectangleClient.getRectangleByPoints(element.points);
1387
- return RectangleClient.isPointInRectangle(client, point);
1388
- }
1389
- if (PlaitDrawElement.isArrowLine(element)) {
1390
- return isHitArrowLine(board, element, point);
1391
- }
1392
- if (PlaitDrawElement.isVectorLine(element)) {
1393
- return isHitVectorLine(board, element, point);
1394
- }
1395
- return null;
1396
- };
1397
- const isHitEdgeOfShape = (board, element, point, hitDistanceBuffer) => {
1398
- const nearestPoint = getNearestPoint(element, point);
1399
- const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
1400
- return distance <= hitDistanceBuffer;
1401
- };
1402
- const isInsideOfShape = (board, element, point, hitDistanceBuffer) => {
1403
- const client = RectangleClient.inflate(RectangleClient.getRectangleByPoints(element.points), hitDistanceBuffer);
1404
- return getEngine(getElementShape(element)).isInsidePoint(client, point);
1405
- };
1406
- const isHitElementInside = (board, element, point) => {
1407
- const rectangle = board.getRectangle(element);
1408
- point = rotateAntiPointsByElement(point, element) || point;
1409
- if (PlaitDrawElement.isGeometry(element) && !PlaitDrawElement.isGeometryByTable(element)) {
1410
- const engine = getEngine(getElementShape(element));
1411
- const isHitInside = engine.isInsidePoint(rectangle, point);
1412
- if (isHitInside) {
1413
- return isHitInside;
1259
+ case ArrowLineMarkerType.oneSideUp: {
1260
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'down' : 'up', options);
1261
+ break;
1414
1262
  }
1415
- if (engine.getTextRectangle) {
1416
- const isHitText = isHitElementText(element, point);
1417
- if (isHitText) {
1418
- return isHitText;
1419
- }
1263
+ case ArrowLineMarkerType.oneSideDown: {
1264
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'up' : 'down', options);
1265
+ break;
1266
+ }
1267
+ case ArrowLineMarkerType.hollowTriangle: {
1268
+ targetArrow = drawHollowTriangleArrow(source, target, options);
1269
+ break;
1270
+ }
1271
+ case ArrowLineMarkerType.singleSlash: {
1272
+ targetArrow = drawSingleSlash(source, target, isSource, options);
1273
+ break;
1420
1274
  }
1421
1275
  }
1422
- if (PlaitDrawElement.isImage(element)) {
1423
- const client = RectangleClient.getRectangleByPoints(element.points);
1424
- return RectangleClient.isPointInRectangle(client, point);
1425
- }
1426
- if (PlaitDrawElement.isArrowLine(element)) {
1427
- return isHitArrowLine(board, element, point);
1428
- }
1429
- if (PlaitDrawElement.isVectorLine(element)) {
1430
- return isHitVectorLine(board, element, point);
1431
- }
1432
- return null;
1276
+ return targetArrow;
1433
1277
  };
1434
-
1435
- const getTextRectangle = (element) => {
1436
- const elementRectangle = RectangleClient.getRectangleByPoints(element.points);
1437
- const strokeWidth = getStrokeWidthByElement(element);
1438
- const height = element.textHeight;
1439
- const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1440
- return {
1441
- height,
1442
- width: width > 0 ? width : 0,
1443
- x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
1444
- y: elementRectangle.y + (elementRectangle.height - height) / 2
1445
- };
1278
+ const drawSharpArrow = (source, target, options) => {
1279
+ const startPoint = target;
1280
+ const { pointLeft, pointRight } = arrowPoints(source, target, 20);
1281
+ const g = createG();
1282
+ const path = createPath();
1283
+ let polylinePath = `M${pointRight[0]},${pointRight[1]}A25,25,20,0,1,${pointLeft[0]},${pointLeft[1]}L${startPoint[0]},${startPoint[1]}Z`;
1284
+ path.setAttribute('d', polylinePath);
1285
+ path.setAttribute('stroke', `${options?.stroke}`);
1286
+ path.setAttribute('stroke-width', `${options?.strokeWidth}`);
1287
+ path.setAttribute('fill', `${options?.stroke}`);
1288
+ g.appendChild(path);
1289
+ return g;
1446
1290
  };
1447
- const getStrokeWidthByElement = (element) => {
1448
- if (PlaitDrawElement.isText(element)) {
1449
- return 0;
1450
- }
1451
- const strokeWidth = element.strokeWidth || DefaultDrawStyle.strokeWidth;
1452
- return strokeWidth;
1291
+ const drawArrow = (element, source, target, options) => {
1292
+ const unitVector = getUnitVectorByPointAndPoint(source, target);
1293
+ const strokeWidth = getStrokeWidthByElement(element);
1294
+ const endPoint = [target[0] + (strokeWidth * unitVector[0]) / 2, target[1] + (strokeWidth * unitVector[1]) / 2];
1295
+ const distance = distanceBetweenPointAndPoint(...source, ...endPoint);
1296
+ const middlePoint = [
1297
+ endPoint[0] - (((distance * 3) / 5 + strokeWidth) / 2) * unitVector[0],
1298
+ endPoint[1] - (((distance * 3) / 5 + strokeWidth) / 2) * unitVector[1]
1299
+ ];
1300
+ const { pointLeft, pointRight } = arrowPoints(source, endPoint, 30);
1301
+ const arrowG = drawLinearPath([pointLeft, endPoint, pointRight, middlePoint], { ...options, fill: options.stroke }, true);
1302
+ const path = arrowG.querySelector('path');
1303
+ path.setAttribute('stroke-linejoin', 'round');
1304
+ return arrowG;
1453
1305
  };
1454
- const insertElement = (board, element) => {
1455
- memorizeLatestShape(board, element.shape);
1456
- Transforms.insertNode(board, element, [board.children.length]);
1457
- clearSelectedElement(board);
1458
- addSelectedElement(board, element);
1459
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1306
+ const drawSolidTriangle = (source, target, options) => {
1307
+ const endPoint = target;
1308
+ const { pointLeft, pointRight } = arrowPoints(source, endPoint, 30);
1309
+ return drawLinearPath([pointLeft, endPoint, pointRight], { ...options, fill: options.stroke }, true);
1460
1310
  };
1461
- const isDrawElementIncludeText = (element) => {
1462
- if (PlaitDrawElement.isText(element)) {
1311
+ const drawOpenTriangle = (element, source, target, options) => {
1312
+ const unitVector = getUnitVectorByPointAndPoint(source, target);
1313
+ const strokeWidth = getStrokeWidthByElement(element);
1314
+ const endPoint = [target[0] + (strokeWidth * unitVector[0]) / 2, target[1] + (strokeWidth * unitVector[1]) / 2];
1315
+ const { pointLeft, pointRight } = arrowPoints(source, endPoint, 40);
1316
+ return drawLinearPath([pointLeft, endPoint, pointRight], options);
1317
+ };
1318
+ const drawOneSideArrow = (source, target, side, options) => {
1319
+ const { pointLeft, pointRight } = arrowPoints(source, target, 40);
1320
+ return drawLinearPath([side === 'up' ? pointRight : pointLeft, target], options);
1321
+ };
1322
+ const drawSingleSlash = (source, target, isSource, options) => {
1323
+ const length = distanceBetweenPointAndPoint(...source, ...target);
1324
+ const middlePoint = getExtendPoint(target, source, length / 2);
1325
+ const angle = isSource ? 120 : 60;
1326
+ const start = rotate(...source, ...middlePoint, (angle * Math.PI) / 180);
1327
+ const end = rotate(...target, ...middlePoint, (angle * Math.PI) / 180);
1328
+ return drawLinearPath([start, end], options);
1329
+ };
1330
+ const drawHollowTriangleArrow = (source, target, options) => {
1331
+ const { pointLeft, pointRight } = arrowPoints(source, target, 30);
1332
+ return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
1333
+ };
1334
+
1335
+ class ArrowLineShapeGenerator extends Generator {
1336
+ canDraw(element) {
1463
1337
  return true;
1464
1338
  }
1465
- if (PlaitDrawElement.isImage(element)) {
1466
- return false;
1467
- }
1468
- if (PlaitDrawElement.isGeometry(element)) {
1469
- return isGeometryIncludeText(element);
1470
- }
1471
- if (PlaitDrawElement.isArrowLine(element)) {
1472
- const editors = getTextEditorsByElement(element);
1473
- return editors.length > 0;
1474
- }
1475
- if (PlaitDrawElement.isElementByTable(element)) {
1476
- return element.cells.some(cell => isCellIncludeText(cell));
1339
+ draw(element) {
1340
+ let lineG;
1341
+ lineG = drawArrowLine(this.board, element);
1342
+ return lineG;
1477
1343
  }
1478
- return true;
1479
- };
1480
- const isDrawElementsIncludeText = (elements) => {
1481
- return elements.some(item => {
1482
- return isDrawElementIncludeText(item);
1483
- });
1344
+ }
1345
+
1346
+ const createArrowLineElement = (shape, points, source, target, texts, options) => {
1347
+ return {
1348
+ id: idCreator(),
1349
+ type: 'arrow-line',
1350
+ shape,
1351
+ source,
1352
+ texts: texts ? texts : [],
1353
+ target,
1354
+ opacity: 1,
1355
+ points,
1356
+ ...options
1357
+ };
1484
1358
  };
1485
- const isClosedDrawElement = (element) => {
1486
- if (PlaitDrawElement.isDrawElement(element)) {
1487
- if (PlaitDrawElement.isText(element) || PlaitDrawElement.isArrowLine(element) || PlaitDrawElement.isImage(element)) {
1488
- return false;
1359
+ const getArrowLinePoints = (board, element) => {
1360
+ switch (element.shape) {
1361
+ case ArrowLineShape.elbow: {
1362
+ return getElbowPoints(board, element);
1489
1363
  }
1490
- if (PlaitDrawElement.isVectorLine(element)) {
1491
- return isClosedPoints(element.points);
1364
+ case ArrowLineShape.curve: {
1365
+ return getCurvePoints(board, element);
1492
1366
  }
1493
- if (PlaitDrawElement.isGeometry(element)) {
1494
- return isGeometryClosed(element);
1367
+ default: {
1368
+ const points = PlaitArrowLine.getPoints(board, element);
1369
+ const handleRefPair = getArrowLineHandleRefPair(board, element);
1370
+ points[0] = handleRefPair.source.point;
1371
+ points[points.length - 1] = handleRefPair.target.point;
1372
+ return points;
1495
1373
  }
1496
- return true;
1497
1374
  }
1498
- return false;
1499
- };
1500
- const isClosedCustomGeometry = (board, value) => {
1501
- return PlaitDrawElement.isCustomGeometryElement(board, value) && isClosedPoints(value.points);
1502
1375
  };
1503
- const getSnappingShape = (board, point) => {
1504
- let hitElement = getHitShape(board, point);
1505
- if (hitElement) {
1506
- const ref = getSnappingRef(board, hitElement, point);
1507
- if (ref.isHitConnector || ref.isHitEdge) {
1508
- return hitElement;
1376
+ const getCurvePoints = (board, element) => {
1377
+ if (element.points.length === 2) {
1378
+ const handleRefPair = getArrowLineHandleRefPair(board, element);
1379
+ const { source, target } = handleRefPair;
1380
+ const sourceBoundElement = handleRefPair.source.boundElement;
1381
+ const targetBoundElement = handleRefPair.target.boundElement;
1382
+ let curvePoints = [source.point];
1383
+ const sumDistance = distanceBetweenPointAndPoint(...source.point, ...target.point);
1384
+ const offset = 12 + sumDistance / 3;
1385
+ if (sourceBoundElement) {
1386
+ curvePoints.push(getPointByVectorComponent(source.point, source.vector, offset));
1509
1387
  }
1510
- }
1511
- return null;
1512
- };
1513
- const getSnappingRef = (board, hitElement, point) => {
1514
- const rotatedPoint = rotateAntiPointsByElement(point, hitElement) || point;
1515
- const connectorPoint = getHitConnectorPoint(rotatedPoint, hitElement);
1516
- const edgePoint = getNearestPoint(hitElement, rotatedPoint);
1517
- const isHitEdge = isHitEdgeOfShape(board, hitElement, rotatedPoint, LINE_SNAPPING_BUFFER);
1518
- return { isHitEdge, isHitConnector: !!connectorPoint, connectorPoint, edgePoint };
1519
- };
1520
- const getHitShape = (board, point, offset = LINE_HIT_GEOMETRY_BUFFER) => {
1521
- let hitShape = null;
1522
- traverseDrawShapes(board, (element) => {
1523
- if (hitShape === null && isInsideOfShape(board, element, rotateAntiPointsByElement(point, element) || point, offset * 2)) {
1524
- hitShape = element;
1388
+ if (targetBoundElement) {
1389
+ curvePoints.push(getPointByVectorComponent(target.point, target.vector, offset));
1525
1390
  }
1526
- });
1527
- return hitShape;
1528
- };
1529
- const traverseDrawShapes = (board, callback) => {
1530
- depthFirstRecursion(board, node => {
1531
- if (!PlaitBoard.isBoard(node) && PlaitDrawElement.isShapeElement(node)) {
1532
- callback(node);
1391
+ const isSingleBound = (sourceBoundElement && !targetBoundElement) || (!sourceBoundElement && targetBoundElement);
1392
+ if (isSingleBound) {
1393
+ curvePoints.push(target.point);
1394
+ const points = Q2C(curvePoints);
1395
+ return pointsOnBezierCurves(points);
1533
1396
  }
1534
- }, getIsRecursionFunc(board), true);
1535
- };
1536
- const drawShape = (board, outerRectangle, shape, roughOptions, drawOptions) => {
1537
- return getEngine(shape).draw(board, outerRectangle, roughOptions, drawOptions);
1538
- };
1539
- const drawBoundReaction = (board, element, roughOptions = { hasMask: true, hasConnector: true }) => {
1540
- const g = createG();
1541
- const rectangle = RectangleClient.getRectangleByPoints(element.points);
1542
- const activeRectangle = RectangleClient.inflate(rectangle, SNAPPING_STROKE_WIDTH);
1543
- const shape = getElementShape(element);
1544
- let drawOptions;
1545
- if (PlaitDrawElement.isElementByTable(element)) {
1546
- drawOptions = { element };
1547
- }
1548
- const strokeG = drawShape(board, activeRectangle, shape, {
1549
- stroke: SELECTION_BORDER_COLOR,
1550
- strokeWidth: SNAPPING_STROKE_WIDTH
1551
- }, drawOptions);
1552
- g.appendChild(strokeG);
1553
- if (roughOptions.hasMask) {
1554
- const maskG = drawShape(board, activeRectangle, shape, {
1555
- stroke: SELECTION_BORDER_COLOR,
1556
- strokeWidth: 0,
1557
- fill: isClosedDrawElement(element) ? SELECTION_FILL_COLOR : DefaultDrawStyle.fill,
1558
- fillStyle: 'solid'
1559
- }, drawOptions);
1560
- g.appendChild(maskG);
1561
- }
1562
- if (roughOptions.hasConnector) {
1563
- const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
1564
- connectorPoints.forEach(point => {
1565
- const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 8, {
1566
- stroke: SELECTION_BORDER_COLOR,
1567
- strokeWidth: ACTIVE_STROKE_WIDTH,
1568
- fill: '#FFF',
1569
- fillStyle: 'solid'
1570
- });
1571
- g.appendChild(circleG);
1572
- });
1573
- }
1574
- return g;
1575
- };
1576
- const getTextKey = (element, text) => {
1577
- if (element && isMultipleTextGeometry(element)) {
1578
- return `${element.id}-${text.id}`;
1397
+ if (!sourceBoundElement && !targetBoundElement) {
1398
+ curvePoints.push(getPointByVectorComponent(source.point, source.vector, offset));
1399
+ curvePoints.push(getPointByVectorComponent(target.point, target.vector, offset));
1400
+ }
1401
+ curvePoints.push(target.point);
1402
+ return pointsOnBezierCurves(curvePoints);
1579
1403
  }
1580
1404
  else {
1581
- return text.id;
1405
+ let dataPoints = PlaitArrowLine.getPoints(board, element);
1406
+ dataPoints = removeDuplicatePoints(dataPoints);
1407
+ const points = catmullRomFitting(dataPoints);
1408
+ return pointsOnBezierCurves(points);
1582
1409
  }
1583
1410
  };
1584
- const getGeometryAlign = (board, element) => {
1585
- if (isMultipleTextGeometry(element)) {
1586
- const drawShapeText = element.texts.find(item => item.id.includes(GeometryCommonTextKeys.content));
1587
- return drawShapeText?.text.align || Alignment.center;
1411
+ const drawArrowLine = (board, element) => {
1412
+ const strokeWidth = getStrokeWidthByElement(element);
1413
+ const strokeColor = getStrokeColorByElement(board, element);
1414
+ const strokeStyle = getStrokeStyleByElement(board, element);
1415
+ const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
1416
+ const options = { stroke: strokeColor, strokeWidth, strokeLineDash };
1417
+ const lineG = createG();
1418
+ let points = getArrowLinePoints(board, element);
1419
+ let line;
1420
+ if (element.shape === ArrowLineShape.curve) {
1421
+ line = PlaitBoard.getRoughSVG(board).curve(points, options);
1588
1422
  }
1589
- if (isSingleTextGeometry(element)) {
1590
- return element.text?.align || Alignment.center;
1423
+ else {
1424
+ line = drawLinearPath(points, options);
1591
1425
  }
1592
- if (PlaitDrawElement.isElementByTable(element)) {
1593
- const firstTextCell = element.cells.find(item => item.text);
1594
- return firstTextCell?.text?.align || Alignment.center;
1426
+ const id = idCreator();
1427
+ line.setAttribute('mask', `url(#${id})`);
1428
+ if (element.strokeStyle === StrokeStyle.dotted) {
1429
+ setStrokeLinecap(line, 'round');
1595
1430
  }
1596
- return Alignment.center;
1431
+ lineG.appendChild(line);
1432
+ const { mask, maskTargetFillRect } = drawArrowLineMask(board, element, id);
1433
+ lineG.appendChild(mask);
1434
+ line.appendChild(maskTargetFillRect);
1435
+ const arrow = drawArrowLineArrow(element, points, { stroke: strokeColor, strokeWidth });
1436
+ arrow && lineG.appendChild(arrow);
1437
+ return lineG;
1597
1438
  };
1598
- const isClosedPoints = (points) => {
1599
- const startPoint = points[0];
1600
- const endPoint = points[points.length - 1];
1601
- return startPoint[0] === endPoint[0] && startPoint[1] === endPoint[1];
1439
+ const getHitConnection = (board, point, hitElement) => {
1440
+ let rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
1441
+ const ref = getSnappingRef(board, hitElement, point);
1442
+ const connectionPoint = ref.connectorPoint || ref.edgePoint;
1443
+ return [(connectionPoint[0] - rectangle.x) / rectangle.width, (connectionPoint[1] - rectangle.y) / rectangle.height];
1602
1444
  };
1603
-
1604
- const getStrokeColorByElement = (board, element) => {
1605
- const defaultColor = getDrawDefaultStrokeColor(board.theme.themeColorMode);
1606
- const strokeColor = element.strokeColor || defaultColor;
1607
- return strokeColor;
1445
+ const getHitConnectorPoint = (point, hitElement) => {
1446
+ const rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
1447
+ const shape = getElementShape(hitElement);
1448
+ const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
1449
+ return connectorPoints.find((connectorPoint) => {
1450
+ return distanceBetweenPointAndPoint(...connectorPoint, ...point) <= LINE_SNAPPING_CONNECTOR_BUFFER;
1451
+ });
1608
1452
  };
1609
- const getFillByElement = (board, element) => {
1610
- const defaultFill = PlaitDrawElement.isFlowchart(element) && isClosedDrawElement(element)
1611
- ? getFlowchartDefaultFill(board.theme.themeColorMode)
1612
- : DefaultDrawStyle.fill;
1613
- const fill = element.fill || defaultFill;
1614
- return fill;
1453
+ const getArrowLineTextRectangle = (board, element, index) => {
1454
+ const text = element.texts[index];
1455
+ const elbowPoints = getArrowLinePoints(board, element);
1456
+ const point = getPointOnPolyline(elbowPoints, text.position);
1457
+ return {
1458
+ x: point[0] - text.width / 2,
1459
+ y: point[1] - text.height / 2,
1460
+ width: text.width,
1461
+ height: text.height
1462
+ };
1615
1463
  };
1616
- const getStrokeStyleByElement = (board, element) => {
1617
- return element.strokeStyle || StrokeStyle.solid;
1464
+ const getArrowLines = (board) => {
1465
+ return findElements(board, {
1466
+ match: (element) => PlaitDrawElement.isArrowLine(element),
1467
+ recursion: (element) => PlaitDrawElement.isDrawElement(element)
1468
+ });
1618
1469
  };
1619
-
1620
- const debugKey$3 = 'debug:plait:line-mirror';
1621
- const debugGenerator$3 = createDebugGenerator(debugKey$3);
1622
- const alignPoints = (basePoint, movingPoint) => {
1623
- const newPoint = [...movingPoint];
1624
- if (Point.isVertical(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
1625
- newPoint[0] = basePoint[0];
1626
- }
1627
- if (Point.isHorizontal(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
1628
- newPoint[1] = basePoint[1];
1470
+ // quadratic Bezier to cubic Bezier
1471
+ const Q2C = (points) => {
1472
+ const result = [];
1473
+ const numSegments = points.length / 3;
1474
+ for (let i = 0; i < numSegments; i++) {
1475
+ const start = points[i];
1476
+ const qControl = points[i + 1];
1477
+ const end = points[i + 2];
1478
+ const startDistance = distanceBetweenPointAndPoint(...start, ...qControl);
1479
+ const endDistance = distanceBetweenPointAndPoint(...end, ...qControl);
1480
+ const cControl1 = getExtendPoint(start, qControl, (startDistance * 2) / 3);
1481
+ const cControl2 = getExtendPoint(end, qControl, (endDistance * 2) / 3);
1482
+ result.push(start, cControl1, cControl2, end);
1629
1483
  }
1630
- return newPoint;
1484
+ return result;
1631
1485
  };
1632
- function getResizedPreviousAndNextPoint(nextRenderPoints, sourcePoint, targetPoint, handleIndex) {
1633
- const referencePoint = {
1634
- previous: null,
1635
- next: null
1486
+ const handleArrowLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceElement, lineShapeG) => {
1487
+ const hitElement = getSnappingShape(board, movingPoint);
1488
+ const targetConnection = hitElement ? getHitConnection(board, movingPoint, hitElement) : undefined;
1489
+ const sourceConnection = sourceElement ? getHitConnection(board, sourcePoint, sourceElement) : undefined;
1490
+ const targetBoundId = hitElement ? hitElement.id : undefined;
1491
+ const lineGenerator = new ArrowLineShapeGenerator(board);
1492
+ const memorizedLatest = getLineMemorizedLatest();
1493
+ let sourceMarker, targetMarker;
1494
+ sourceMarker = memorizedLatest.source;
1495
+ targetMarker = memorizedLatest.target;
1496
+ sourceMarker && delete memorizedLatest.source;
1497
+ targetMarker && delete memorizedLatest.target;
1498
+ const temporaryLineElement = createArrowLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || ArrowLineMarkerType.none, connection: sourceConnection, boundId: sourceElement?.id }, { marker: targetMarker || ArrowLineMarkerType.arrow, connection: targetConnection, boundId: targetBoundId }, [], {
1499
+ strokeWidth: DefaultLineStyle.strokeWidth,
1500
+ ...memorizedLatest
1501
+ });
1502
+ const linePoints = getArrowLinePoints(board, temporaryLineElement);
1503
+ const otherPoint = linePoints[0];
1504
+ temporaryLineElement.points[1] = alignPoints(otherPoint, movingPoint);
1505
+ lineGenerator.processDrawing(temporaryLineElement, lineShapeG);
1506
+ PlaitBoard.getElementTopHost(board).append(lineShapeG);
1507
+ return temporaryLineElement;
1508
+ };
1509
+ function drawArrowLineMask(board, element, id) {
1510
+ const mask = createMask();
1511
+ mask.setAttribute('id', id);
1512
+ const points = getArrowLinePoints(board, element);
1513
+ let rectangle = RectangleClient.getRectangleByPoints(points);
1514
+ rectangle = RectangleClient.getOutlineRectangle(rectangle, -30);
1515
+ const maskFillRect = createRect(rectangle, {
1516
+ fill: 'white'
1517
+ });
1518
+ mask.appendChild(maskFillRect);
1519
+ const texts = element.texts;
1520
+ texts.forEach((text, index) => {
1521
+ let textRectangle = getArrowLineTextRectangle(board, element, index);
1522
+ textRectangle = RectangleClient.inflate(textRectangle, LINE_TEXT_SPACE * 2);
1523
+ const rect = createRect(textRectangle, {
1524
+ fill: 'black'
1525
+ });
1526
+ mask.appendChild(rect);
1527
+ });
1528
+ // open line
1529
+ const maskTargetFillRect = createRect(rectangle);
1530
+ maskTargetFillRect.setAttribute('opacity', '0');
1531
+ maskTargetFillRect.setAttribute('fill', 'none');
1532
+ return { mask, maskTargetFillRect };
1533
+ }
1534
+
1535
+ const getHitArrowLineTextIndex = (board, element, point) => {
1536
+ const texts = element.texts;
1537
+ if (!texts.length)
1538
+ return -1;
1539
+ const points = getArrowLinePoints(board, element);
1540
+ return texts.findIndex(text => {
1541
+ const center = getPointOnPolyline(points, text.position);
1542
+ const rectangle = {
1543
+ x: center[0] - text.width / 2,
1544
+ y: center[1] - text.height / 2,
1545
+ width: text.width,
1546
+ height: text.height
1547
+ };
1548
+ return RectangleClient.isHit(rectangle, RectangleClient.getRectangleByPoints([point, point]));
1549
+ });
1550
+ };
1551
+
1552
+ const isMultipleTextShape = (shape) => {
1553
+ return GEOMETRY_WITH_MULTIPLE_TEXT.includes(shape);
1554
+ };
1555
+ const isMultipleTextGeometry = (geometry) => {
1556
+ return PlaitDrawElement.isGeometry(geometry) && isMultipleTextShape(geometry.shape);
1557
+ };
1558
+ const getMultipleTextGeometryTextKeys = (shape) => {
1559
+ return MultipleTextGeometryTextKeys[shape];
1560
+ };
1561
+ const createMultipleTextGeometryElement = (shape, points, options = {}) => {
1562
+ const id = idCreator();
1563
+ const drawShapeTexts = buildDefaultTextsByShape(shape);
1564
+ return {
1565
+ id,
1566
+ type: 'geometry',
1567
+ shape,
1568
+ angle: 0,
1569
+ opacity: 1,
1570
+ texts: drawShapeTexts,
1571
+ points,
1572
+ ...options
1636
1573
  };
1637
- const startPoint = nextRenderPoints[handleIndex];
1638
- const endPoint = nextRenderPoints[handleIndex + 1];
1639
- const isHorizontal = Point.isHorizontal(startPoint, endPoint);
1640
- const isVertical = Point.isVertical(startPoint, endPoint);
1641
- const previousPoint = nextRenderPoints[handleIndex - 1] ?? nextRenderPoints[0];
1642
- const beforePreviousPoint = nextRenderPoints[handleIndex - 2] ?? sourcePoint;
1643
- if ((isHorizontal && Point.isHorizontal(beforePreviousPoint, previousPoint)) ||
1644
- (isVertical && Point.isVertical(beforePreviousPoint, previousPoint))) {
1645
- referencePoint.previous = previousPoint;
1574
+ };
1575
+ const buildDefaultTextsByShape = (shape) => {
1576
+ const memorizedLatest = getMemorizedLatestByPointer(shape);
1577
+ const textProperties = { ...memorizedLatest.textProperties };
1578
+ const alignment = textProperties?.align;
1579
+ const textHeight = textProperties?.textHeight || DefaultTextProperty.height;
1580
+ delete textProperties?.align;
1581
+ delete textProperties?.textHeight;
1582
+ const defaultTexts = getDefaultGeometryProperty(shape)?.texts || [];
1583
+ const textKeys = getMultipleTextGeometryTextKeys(shape);
1584
+ return (textKeys || []).map((textKey) => {
1585
+ const text = defaultTexts?.find((item) => item?.key === textKey);
1586
+ return {
1587
+ id: textKey,
1588
+ text: buildText(text?.text || '', alignment || text?.align || Alignment.center, textProperties),
1589
+ textHeight: textHeight
1590
+ };
1591
+ });
1592
+ };
1593
+ const getHitMultipleGeometryText = (element, point) => {
1594
+ const engine = getEngine(element.shape);
1595
+ const rectangle = RectangleClient.getRectangleByPoints([point, point]);
1596
+ let hitText;
1597
+ if (engine.getTextRectangle) {
1598
+ hitText = element.texts.find(text => {
1599
+ const textRectangle = engine.getTextRectangle(element, { id: text.id });
1600
+ return RectangleClient.isHit(rectangle, textRectangle);
1601
+ });
1646
1602
  }
1647
- const nextPoint = nextRenderPoints[handleIndex + 2] ?? nextRenderPoints[nextRenderPoints.length - 1];
1648
- const afterNextPoint = nextRenderPoints[handleIndex + 3] ?? targetPoint;
1649
- if ((isHorizontal && Point.isHorizontal(nextPoint, afterNextPoint)) || (isVertical && Point.isVertical(nextPoint, afterNextPoint))) {
1650
- referencePoint.next = nextPoint;
1603
+ return hitText;
1604
+ };
1605
+
1606
+ class VectorLineShapeGenerator extends Generator {
1607
+ canDraw(element) {
1608
+ return true;
1609
+ }
1610
+ draw(element) {
1611
+ let lineG;
1612
+ lineG = drawVectorLine(this.board, element);
1613
+ return lineG;
1651
1614
  }
1652
- return referencePoint;
1653
1615
  }
1654
- function alignElbowSegment(startKeyPoint, endKeyPoint, resizeState, resizedPreviousAndNextPoint) {
1655
- let newStartPoint = startKeyPoint;
1656
- let newEndPoint = endKeyPoint;
1657
- if (Point.isHorizontal(startKeyPoint, endKeyPoint)) {
1658
- const offsetY = Point.getOffsetY(resizeState.startPoint, resizeState.endPoint);
1659
- let pointY = startKeyPoint[1] + offsetY;
1660
- if (resizedPreviousAndNextPoint.previous && Math.abs(resizedPreviousAndNextPoint.previous[1] - pointY) < LINE_ALIGN_TOLERANCE) {
1661
- pointY = resizedPreviousAndNextPoint.previous[1];
1616
+
1617
+ const getVectorLinePoints = (board, element) => {
1618
+ switch (element.shape) {
1619
+ case VectorLineShape.straight: {
1620
+ return element.points;
1662
1621
  }
1663
- else if (resizedPreviousAndNextPoint.next && Math.abs(resizedPreviousAndNextPoint.next[1] - pointY) < LINE_ALIGN_TOLERANCE) {
1664
- pointY = resizedPreviousAndNextPoint.next[1];
1622
+ case VectorLineShape.curve: {
1623
+ if (element.points.length === 2) {
1624
+ return pointsOnBezierCurves(element.points);
1625
+ }
1626
+ else {
1627
+ let dataPoints = element.points;
1628
+ const points = catmullRomFitting(dataPoints);
1629
+ return pointsOnBezierCurves(points);
1630
+ }
1665
1631
  }
1666
- newStartPoint = [startKeyPoint[0], pointY];
1667
- newEndPoint = [endKeyPoint[0], pointY];
1632
+ default:
1633
+ return null;
1668
1634
  }
1669
- if (Point.isVertical(startKeyPoint, endKeyPoint)) {
1670
- const offsetX = Point.getOffsetX(resizeState.startPoint, resizeState.endPoint);
1671
- let pointX = startKeyPoint[0] + offsetX;
1672
- if (resizedPreviousAndNextPoint.previous && Math.abs(resizedPreviousAndNextPoint.previous[0] - pointX) < LINE_ALIGN_TOLERANCE) {
1673
- pointX = resizedPreviousAndNextPoint.previous[0];
1674
- }
1675
- else if (resizedPreviousAndNextPoint.next && Math.abs(resizedPreviousAndNextPoint.next[0] - pointX) < LINE_ALIGN_TOLERANCE) {
1676
- pointX = resizedPreviousAndNextPoint.next[0];
1677
- }
1678
- newStartPoint = [pointX, startKeyPoint[1]];
1679
- newEndPoint = [pointX, endKeyPoint[1]];
1635
+ };
1636
+ const createVectorLineElement = (shape, points, options) => {
1637
+ return {
1638
+ id: idCreator(),
1639
+ type: 'vector-line',
1640
+ shape,
1641
+ opacity: 1,
1642
+ points,
1643
+ ...options
1644
+ };
1645
+ };
1646
+ const vectorLineCreating = (board, lineShape, points, movingPoint, lineShapeG) => {
1647
+ const lineGenerator = new VectorLineShapeGenerator(board);
1648
+ const memorizedLatest = getLineMemorizedLatest();
1649
+ const temporaryLineElement = createVectorLineElement(lineShape, [...points, movingPoint], {
1650
+ strokeWidth: DefaultLineStyle.strokeWidth,
1651
+ ...memorizedLatest
1652
+ });
1653
+ const otherPoint = points[points.length - 1];
1654
+ temporaryLineElement.points[temporaryLineElement.points.length - 1] = alignPoints(otherPoint, movingPoint);
1655
+ lineGenerator.processDrawing(temporaryLineElement, lineShapeG);
1656
+ PlaitBoard.getElementTopHost(board).append(lineShapeG);
1657
+ return temporaryLineElement;
1658
+ };
1659
+ const drawVectorLine = (board, element) => {
1660
+ const strokeWidth = getStrokeWidthByElement(element);
1661
+ const strokeColor = getStrokeColorByElement(board, element);
1662
+ const strokeStyle = getStrokeStyleByElement(board, element);
1663
+ const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
1664
+ const fill = getFillByElement(board, element);
1665
+ const options = { stroke: strokeColor, strokeWidth, strokeLineDash, fill };
1666
+ const lineG = createG();
1667
+ let points = getVectorLinePoints(board, element);
1668
+ const line = drawLinearPath(points, options);
1669
+ const id = idCreator();
1670
+ line.setAttribute('mask', `url(#${id})`);
1671
+ if (element.strokeStyle === StrokeStyle.dotted) {
1672
+ setStrokeLinecap(line, 'round');
1680
1673
  }
1681
- return [newStartPoint, newEndPoint];
1682
- }
1683
- function getIndexAndDeleteCountByKeyPoint(board, element, dataPoints, nextRenderPoints, handleIndex) {
1684
- let index = null;
1685
- let deleteCount = null;
1686
- const startKeyPoint = nextRenderPoints[handleIndex];
1687
- const endKeyPoint = nextRenderPoints[handleIndex + 1];
1688
- if (!startKeyPoint || !endKeyPoint) {
1689
- return {
1690
- index,
1691
- deleteCount
1692
- };
1674
+ lineG.appendChild(line);
1675
+ return lineG;
1676
+ };
1677
+
1678
+ const getCenterPointsOnPolygon$1 = (points) => {
1679
+ const centerPoints = [];
1680
+ for (let i = 0; i < points.length; i++) {
1681
+ let j = i == points.length - 1 ? 0 : i + 1;
1682
+ centerPoints.push([(points[i][0] + points[j][0]) / 2, (points[i][1] + points[j][1]) / 2]);
1693
1683
  }
1694
- const midDataPoints = dataPoints.slice(1, -1);
1695
- const startIndex = midDataPoints.findIndex(item => Point.isEquals(item, startKeyPoint));
1696
- const endIndex = midDataPoints.findIndex(item => Point.isEquals(item, endKeyPoint));
1697
- if (Math.max(startIndex, endIndex) > -1) {
1698
- if (startIndex > -1 && endIndex > -1) {
1699
- return {
1700
- index: startIndex,
1701
- deleteCount: 2
1702
- };
1703
- }
1704
- if (startIndex > -1 && endIndex === -1) {
1705
- const isReplace = startIndex < midDataPoints.length - 1 &&
1706
- Point.isAlign([midDataPoints[startIndex], midDataPoints[startIndex + 1], startKeyPoint, endKeyPoint]);
1707
- if (isReplace) {
1708
- return {
1709
- index: startIndex,
1710
- deleteCount: 2
1711
- };
1712
- }
1713
- return {
1714
- index: startIndex,
1715
- deleteCount: 1
1716
- };
1717
- }
1718
- if (startIndex === -1 && endIndex > -1) {
1719
- const isReplace = endIndex > 0 && Point.isAlign([midDataPoints[endIndex], midDataPoints[endIndex - 1], startKeyPoint, endKeyPoint]);
1720
- if (isReplace) {
1721
- return {
1722
- index: endIndex - 1,
1723
- deleteCount: 2
1724
- };
1725
- }
1726
- return {
1727
- index: endIndex,
1728
- deleteCount: 1
1729
- };
1730
- }
1684
+ return centerPoints;
1685
+ };
1686
+ const getCrossingPointBetweenPointAndPolygon = (corners, point) => {
1687
+ const result = [];
1688
+ for (let index = 1; index <= corners.length; index++) {
1689
+ let start = corners[index - 1];
1690
+ let end = index === corners.length ? corners[0] : corners[index];
1691
+ const crossingPoint = getCrossingPointsBetweenPointAndSegment(point, start, end);
1692
+ result.push(...crossingPoint);
1731
1693
  }
1732
- else {
1733
- for (let i = 0; i < midDataPoints.length - 1; i++) {
1734
- const currentPoint = midDataPoints[i];
1735
- const nextPoint = midDataPoints[i + 1];
1736
- if (Point.isAlign([currentPoint, nextPoint, startKeyPoint, endKeyPoint])) {
1737
- index = i;
1738
- deleteCount = 2;
1739
- break;
1740
- }
1741
- if (Point.isAlign([currentPoint, nextPoint, startKeyPoint])) {
1742
- index = Math.min(i + 1, midDataPoints.length - 1);
1743
- deleteCount = 1;
1744
- break;
1745
- }
1746
- if (Point.isAlign([currentPoint, nextPoint, endKeyPoint])) {
1747
- index = Math.max(i - 1, 0);
1748
- deleteCount = 1;
1749
- break;
1750
- }
1694
+ return result;
1695
+ };
1696
+ const getPolygonEdgeByConnectionPoint = (corners, point) => {
1697
+ for (let index = 1; index <= corners.length; index++) {
1698
+ let start = corners[index - 1];
1699
+ let end = index === corners.length ? corners[0] : corners[index];
1700
+ if (isPointOnSegment(point, start, end)) {
1701
+ return [start, end];
1751
1702
  }
1752
1703
  }
1753
- if (index === null) {
1754
- deleteCount = 0;
1755
- if (midDataPoints.length > 0) {
1756
- const handleRefPair = getArrowLineHandleRefPair(board, element);
1757
- const params = getElbowLineRouteOptions(board, element, handleRefPair);
1758
- const keyPoints = removeDuplicatePoints(generateElbowLineRoute(params, board));
1759
- const nextKeyPoints = simplifyOrthogonalPoints(keyPoints.slice(1, keyPoints.length - 1));
1760
- const nextDataPoints = [nextRenderPoints[0], ...midDataPoints, nextRenderPoints[nextRenderPoints.length - 1]];
1761
- const mirrorDataPoints = getMirrorDataPoints(board, nextDataPoints, nextKeyPoints, params);
1762
- for (let i = handleIndex - 1; i >= 0; i--) {
1763
- const previousIndex = mirrorDataPoints.slice(1, -1).findIndex(item => Point.isEquals(item, nextRenderPoints[i]));
1764
- if (previousIndex > -1) {
1765
- index = previousIndex + 1;
1766
- break;
1767
- }
1768
- }
1769
- if (index === null) {
1770
- index = 0;
1771
- // When renderPoints is a straight line and dataPoints are not on the line,
1772
- // the default 'deleteCount' is set to midDataPoints.length.
1773
- if (Point.isAlign(nextRenderPoints)) {
1774
- deleteCount = midDataPoints.length;
1775
- }
1776
- }
1777
- }
1778
- else {
1779
- index = 0;
1704
+ return null;
1705
+ };
1706
+
1707
+ function generateCloudPath(rectangle) {
1708
+ const divisionWidth = rectangle.width / 7;
1709
+ const divisionHeight = rectangle.height / 3.2;
1710
+ const xRadius = divisionWidth / 8.5;
1711
+ const yRadius = divisionHeight / 20;
1712
+ const startPoint = [rectangle.x + divisionWidth, rectangle.y + divisionHeight];
1713
+ const arcCommands = [
1714
+ {
1715
+ rx: xRadius,
1716
+ ry: yRadius * 1.2,
1717
+ xAxisRotation: 0,
1718
+ largeArcFlag: 1,
1719
+ sweepFlag: 1,
1720
+ endX: rectangle.x + divisionWidth * 2,
1721
+ endY: rectangle.y + divisionHeight / 2
1722
+ },
1723
+ {
1724
+ rx: xRadius,
1725
+ ry: yRadius,
1726
+ xAxisRotation: 0,
1727
+ largeArcFlag: 1,
1728
+ sweepFlag: 1,
1729
+ endX: rectangle.x + divisionWidth * 4.2,
1730
+ endY: rectangle.y + divisionHeight / 2.2
1731
+ },
1732
+ {
1733
+ rx: xRadius,
1734
+ ry: yRadius,
1735
+ xAxisRotation: 0,
1736
+ largeArcFlag: 1,
1737
+ sweepFlag: 1,
1738
+ endX: rectangle.x + divisionWidth * 5.8,
1739
+ endY: rectangle.y + divisionHeight
1740
+ },
1741
+ {
1742
+ rx: xRadius,
1743
+ ry: yRadius * 1.3,
1744
+ xAxisRotation: 0,
1745
+ largeArcFlag: 1,
1746
+ sweepFlag: 1,
1747
+ endX: rectangle.x + divisionWidth * 6,
1748
+ endY: rectangle.y + divisionHeight * 2.2
1749
+ },
1750
+ {
1751
+ rx: xRadius,
1752
+ ry: yRadius * 1.2,
1753
+ xAxisRotation: 0,
1754
+ largeArcFlag: 1,
1755
+ sweepFlag: 1,
1756
+ endX: rectangle.x + divisionWidth * 5,
1757
+ endY: rectangle.y + divisionHeight * 2.8
1758
+ },
1759
+ {
1760
+ rx: xRadius,
1761
+ ry: yRadius / 1.2,
1762
+ xAxisRotation: 0,
1763
+ largeArcFlag: 1,
1764
+ sweepFlag: 1,
1765
+ endX: rectangle.x + divisionWidth * 2.8,
1766
+ endY: rectangle.y + divisionHeight * 2.8
1767
+ },
1768
+ {
1769
+ rx: xRadius,
1770
+ ry: yRadius,
1771
+ xAxisRotation: 0,
1772
+ largeArcFlag: 1,
1773
+ sweepFlag: 1,
1774
+ endX: rectangle.x + divisionWidth,
1775
+ endY: rectangle.y + divisionHeight * 2.2
1776
+ },
1777
+ {
1778
+ rx: xRadius,
1779
+ ry: yRadius * 1.42,
1780
+ xAxisRotation: 0,
1781
+ largeArcFlag: 1,
1782
+ sweepFlag: 1,
1783
+ endX: rectangle.x + divisionWidth,
1784
+ endY: rectangle.y + divisionHeight
1780
1785
  }
1781
- }
1782
- return {
1783
- index,
1784
- deleteCount
1785
- };
1786
- }
1787
- function getMirrorDataPoints(board, nextDataPoints, nextKeyPoints, params) {
1788
- for (let index = 1; index < nextDataPoints.length - 2; index++) {
1789
- adjustByCustomPointStartIndex(board, index, nextDataPoints, nextKeyPoints, params);
1790
- }
1791
- return nextDataPoints;
1786
+ ];
1787
+ return { startPoint, arcCommands };
1792
1788
  }
1793
- /**
1794
- * adjust based parallel segment
1795
- */
1796
- const adjustByCustomPointStartIndex = (board, customPointStartIndex, nextDataPoints, nextKeyPoints, params) => {
1797
- const beforePoint = nextDataPoints[customPointStartIndex - 1];
1798
- const startPoint = nextDataPoints[customPointStartIndex];
1799
- const endPoint = nextDataPoints[customPointStartIndex + 1];
1800
- const afterPoint = nextDataPoints[customPointStartIndex + 2];
1801
- const beforeSegment = [beforePoint, startPoint];
1802
- const afterSegment = [endPoint, afterPoint];
1803
- const isStraightWithBefore = Point.isAlign(beforeSegment);
1804
- const isStraightWithAfter = Point.isAlign(afterSegment);
1805
- let isAdjustStart = false;
1806
- let isAdjustEnd = false;
1807
- if (!isStraightWithBefore || !isStraightWithAfter) {
1808
- const midKeyPointsWithBefore = getMidKeyPoints(nextKeyPoints, beforeSegment[0], beforeSegment[1]);
1809
- const midKeyPointsWithAfter = getMidKeyPoints(nextKeyPoints, afterSegment[0], afterSegment[1]);
1810
- const hasMidKeyPoints = midKeyPointsWithBefore.length > 0 && midKeyPointsWithAfter.length > 0;
1811
- isAdjustStart = !isStraightWithBefore && !hasMidKeyPoints;
1812
- isAdjustEnd = !isStraightWithAfter && !hasMidKeyPoints;
1813
- }
1814
- if (isAdjustStart || isAdjustEnd) {
1815
- const parallelSegment = [startPoint, endPoint];
1816
- const parallelSegments = findOrthogonalParallelSegments(parallelSegment, nextKeyPoints);
1817
- const mirrorSegments = findMirrorSegments(board, parallelSegment, parallelSegments, params.sourceRectangle, params.targetRectangle);
1818
- if (mirrorSegments.length === 1) {
1819
- const mirrorSegment = mirrorSegments[0];
1820
- if (isAdjustStart) {
1821
- nextDataPoints.splice(customPointStartIndex, 1, mirrorSegment[0]);
1822
- }
1823
- if (isAdjustEnd) {
1824
- nextDataPoints.splice(customPointStartIndex + 1, 1, mirrorSegment[1]);
1825
- }
1826
- }
1827
- else {
1828
- const isHorizontal = Point.isHorizontal(startPoint, endPoint);
1829
- const adjustIndex = isHorizontal ? 0 : 1;
1830
- if (isAdjustStart) {
1831
- const newStartPoint = [startPoint[0], startPoint[1]];
1832
- newStartPoint[adjustIndex] = beforePoint[adjustIndex];
1833
- nextDataPoints.splice(customPointStartIndex, 1, newStartPoint);
1834
- }
1835
- if (isAdjustEnd) {
1836
- const newEndPoint = [endPoint[0], endPoint[1]];
1837
- newEndPoint[adjustIndex] = afterPoint[adjustIndex];
1838
- nextDataPoints.splice(customPointStartIndex + 1, 1, newEndPoint);
1789
+ const CloudEngine = {
1790
+ draw(board, rectangle, options) {
1791
+ const rs = PlaitBoard.getRoughSVG(board);
1792
+ const { startPoint, arcCommands } = generateCloudPath(rectangle);
1793
+ const pathData = `M ${startPoint[0]} ${startPoint[1]} ` +
1794
+ arcCommands
1795
+ .map((command) => `A ${command.rx} ${command.ry} ${command.xAxisRotation} ${command.largeArcFlag} ${command.sweepFlag} ${command.endX} ${command.endY}`)
1796
+ .join('\n') +
1797
+ ' Z';
1798
+ const svgElement = rs.path(pathData, { ...options, fillStyle: 'solid' });
1799
+ setPathStrokeLinecap(svgElement, 'round');
1800
+ return svgElement;
1801
+ },
1802
+ isInsidePoint(rectangle, point) {
1803
+ const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
1804
+ return RectangleClient.isHit(rectangle, rangeRectangle);
1805
+ },
1806
+ getCornerPoints(rectangle) {
1807
+ return RectangleClient.getCornerPoints(rectangle);
1808
+ },
1809
+ getNearestPoint(rectangle, point) {
1810
+ const { startPoint, arcCommands } = generateCloudPath(rectangle);
1811
+ let minDistance = Infinity;
1812
+ let nearestPoint = point;
1813
+ let currentStart = startPoint;
1814
+ for (const arcCommand of arcCommands) {
1815
+ const arcNearestPoint = getNearestPointBetweenPointAndArc(point, currentStart, arcCommand);
1816
+ const distance = distanceBetweenPointAndPoint(point[0], point[1], arcNearestPoint[0], arcNearestPoint[1]);
1817
+ if (distance < minDistance) {
1818
+ minDistance = distance;
1819
+ nearestPoint = arcNearestPoint;
1839
1820
  }
1821
+ currentStart = [arcCommand.endX, arcCommand.endY];
1840
1822
  }
1823
+ return nearestPoint;
1824
+ },
1825
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
1826
+ const corners = CloudEngine.getCornerPoints(rectangle);
1827
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1828
+ return getPolygonEdgeByConnectionPoint(corners, point);
1829
+ },
1830
+ getConnectorPoints(rectangle) {
1831
+ return RectangleClient.getEdgeCenterPoints(rectangle);
1832
+ },
1833
+ getTextRectangle(element) {
1834
+ const elementRectangle = RectangleClient.getRectangleByPoints(element.points);
1835
+ const strokeWidth = getStrokeWidthByElement(element);
1836
+ const height = element.textHeight;
1837
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1838
+ const width = originWidth / 1.5;
1839
+ return {
1840
+ height,
1841
+ width: width > 0 ? width : 0,
1842
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 6,
1843
+ y: elementRectangle.y + elementRectangle.height / 6 + ((elementRectangle.height * 4) / 6 - height) / 2
1844
+ };
1841
1845
  }
1842
1846
  };
1843
- function isUpdatedHandleIndex(board, element, dataPoints, nextRenderPoints, handleIndex) {
1844
- const { deleteCount } = getIndexAndDeleteCountByKeyPoint(board, element, dataPoints, nextRenderPoints, handleIndex);
1845
- if (deleteCount !== null && deleteCount > 1) {
1847
+
1848
+ const isTextExceedingBounds = (geometry) => {
1849
+ const client = RectangleClient.getRectangleByPoints(geometry.points);
1850
+ if (geometry.textHeight && geometry.textHeight > client.height) {
1846
1851
  return true;
1847
1852
  }
1848
1853
  return false;
1849
- }
1850
- function getMidKeyPoints(simplifiedNextKeyPoints, startPoint, endPoint) {
1851
- let midElbowPoints = [];
1852
- let startPointIndex = -1;
1853
- let endPointIndex = -1;
1854
- for (let i = 0; i < simplifiedNextKeyPoints.length; i++) {
1855
- if (Point.isAlign([simplifiedNextKeyPoints[i], startPoint])) {
1856
- startPointIndex = i;
1857
- }
1858
- if (startPointIndex > -1 && Point.isAlign([simplifiedNextKeyPoints[i], endPoint])) {
1859
- endPointIndex = i;
1860
- break;
1861
- }
1854
+ };
1855
+ const isHitArrowLineText = (board, element, point) => {
1856
+ return getHitArrowLineTextIndex(board, element, point) !== -1;
1857
+ };
1858
+ const isHitPolyLine = (pathPoints, point) => {
1859
+ const distance = distanceBetweenPointAndSegments(point, pathPoints);
1860
+ return distance <= HIT_DISTANCE_BUFFER;
1861
+ };
1862
+ const isHitArrowLine = (board, element, point) => {
1863
+ const points = getArrowLinePoints(board, element);
1864
+ const isHitText = isHitArrowLineText(board, element, point);
1865
+ return isHitText || isHitPolyLine(points, point);
1866
+ };
1867
+ const isHitVectorLine = (board, element, point) => {
1868
+ const points = getVectorLinePoints(board, element);
1869
+ if (isClosedPoints(element.points)) {
1870
+ return isPointInPolygon(point, points) || isHitPolyLine(points, point);
1862
1871
  }
1863
- if (startPointIndex > -1 && endPointIndex > -1) {
1864
- midElbowPoints = simplifiedNextKeyPoints.slice(startPointIndex, endPointIndex + 1);
1872
+ else {
1873
+ return isHitPolyLine(points, point);
1865
1874
  }
1866
- return midElbowPoints;
1867
- }
1868
- function findOrthogonalParallelSegments(segment, keyPoints) {
1869
- const isHorizontalSegment = Point.isHorizontal(segment[0], segment[1]);
1870
- const parallelSegments = [];
1871
- for (let i = 0; i < keyPoints.length - 1; i++) {
1872
- const current = keyPoints[i];
1873
- const next = keyPoints[i + 1];
1874
- const isHorizontal = Point.isHorizontal(current, next, 0.1);
1875
- if (isHorizontalSegment && isHorizontal) {
1876
- parallelSegments.push([current, next]);
1877
- }
1878
- if (!isHorizontalSegment && !isHorizontal) {
1879
- parallelSegments.push([current, next]);
1880
- }
1875
+ };
1876
+ const isRectangleHitElementText = (element, rectangle) => {
1877
+ const engine = getEngine(element.shape);
1878
+ if (isMultipleTextGeometry(element)) {
1879
+ const texts = element.texts;
1880
+ return texts.some((item) => {
1881
+ const textClient = engine.getTextRectangle(element, { id: item.id });
1882
+ return isRectangleHitRotatedPoints(rectangle, RectangleClient.getCornerPoints(textClient), element.angle);
1883
+ });
1881
1884
  }
1882
- return parallelSegments;
1883
- }
1884
- function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, targetRectangle) {
1885
- debugGenerator$3.isDebug() && debugGenerator$3.clear();
1886
- const mirrorSegments = [];
1887
- for (let index = 0; index < parallelSegments.length; index++) {
1888
- const parallelPath = parallelSegments[index];
1889
- const startPoint = [segment[0][0], segment[0][1]];
1890
- const endPoint = [segment[1][0], segment[1][1]];
1891
- const isHorizontal = Point.isHorizontal(startPoint, endPoint);
1892
- const adjustDataIndex = isHorizontal ? 0 : 1;
1893
- startPoint[adjustDataIndex] = parallelPath[0][adjustDataIndex];
1894
- endPoint[adjustDataIndex] = parallelPath[1][adjustDataIndex];
1895
- const fakeRectangle = RectangleClient.getRectangleByPoints([startPoint, endPoint, ...parallelPath]);
1896
- const isValid = !RectangleClient.isHit(fakeRectangle, sourceRectangle) && !RectangleClient.isHit(fakeRectangle, targetRectangle);
1897
- if (isValid) {
1898
- mirrorSegments.push([startPoint, endPoint]);
1899
- debugGenerator$3.isDebug() && debugGenerator$3.drawPolygon(board, RectangleClient.getCornerPoints(fakeRectangle));
1900
- }
1885
+ else {
1886
+ const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
1887
+ return isRectangleHitRotatedPoints(rectangle, RectangleClient.getCornerPoints(textClient), element.angle);
1901
1888
  }
1902
- return mirrorSegments;
1903
- }
1904
- const hasIllegalElbowPoint = (midDataPoints) => {
1905
- if (midDataPoints.length === 1) {
1889
+ };
1890
+ const isHitElementText = (element, point) => {
1891
+ const engine = getEngine(element.shape);
1892
+ if (isMultipleTextGeometry(element)) {
1893
+ const texts = element.texts;
1894
+ return texts.some((item) => {
1895
+ const textClient = engine.getTextRectangle(element, { id: item.id });
1896
+ return RectangleClient.isPointInRectangle(textClient, point);
1897
+ });
1898
+ }
1899
+ else {
1900
+ const textClient = engine.getTextRectangle ? engine.getTextRectangle(element) : getTextRectangle(element);
1901
+ return RectangleClient.isPointInRectangle(textClient, point);
1902
+ }
1903
+ };
1904
+ const isEmptyTextElement = (element) => {
1905
+ if (!isDrawElementIncludeText(element)) {
1906
1906
  return true;
1907
1907
  }
1908
- return midDataPoints.some((item, index) => {
1909
- const beforePoint = midDataPoints[index - 1];
1910
- const afterPoint = midDataPoints[index + 1];
1911
- const beforeSegment = beforePoint && [beforePoint, item];
1912
- const afterSegment = afterPoint && [item, afterPoint];
1913
- const isStraightWithBefore = beforeSegment && Point.isAlign(beforeSegment);
1914
- const isStraightWithAfter = afterSegment && Point.isAlign(afterSegment);
1915
- if (index === 0) {
1916
- return !isStraightWithAfter;
1917
- }
1918
- if (index === midDataPoints.length - 1) {
1919
- return !isStraightWithBefore;
1920
- }
1921
- return !isStraightWithBefore && !isStraightWithAfter;
1922
- });
1908
+ const editor = getFirstTextEditor(element);
1909
+ return Editor.isEmpty(editor, editor.children[0]);
1923
1910
  };
1924
-
1925
- const ARROW_LENGTH = 20;
1926
- const drawArrowLineArrow = (element, points, options) => {
1927
- const arrowG = createG();
1928
- if (PlaitArrowLine.isSourceMark(element, ArrowLineMarkerType.none) && PlaitArrowLine.isTargetMark(element, ArrowLineMarkerType.none)) {
1929
- return null;
1911
+ const isRectangleHitDrawElement = (board, element, selection) => {
1912
+ const rangeRectangle = RectangleClient.getRectangleByPoints([selection.anchor, selection.focus]);
1913
+ if (PlaitDrawElement.isGeometry(element)) {
1914
+ const isHitElement = isRectangleHitRotatedElement(board, rangeRectangle, element);
1915
+ if (isHitElement) {
1916
+ return isHitElement;
1917
+ }
1918
+ return !isEmptyTextElement(element) && isRectangleHitElementText(element, rangeRectangle);
1930
1919
  }
1931
- const strokeWidth = getStrokeWidthByElement(element);
1932
- const offset = (strokeWidth * strokeWidth) / 3;
1933
- if (points.length === 1) {
1934
- points = [points[0], [points[0][0] + 0.1, points[0][1]]];
1920
+ if (PlaitDrawElement.isImage(element)) {
1921
+ return isRectangleHitRotatedElement(board, rangeRectangle, element);
1935
1922
  }
1936
- if (!PlaitArrowLine.isSourceMark(element, ArrowLineMarkerType.none)) {
1937
- const source = getExtendPoint(points[0], points[1], ARROW_LENGTH + offset);
1938
- const sourceArrow = getArrow(element, { marker: element.source.marker, source, target: points[0], isSource: true }, options);
1939
- sourceArrow && arrowG.appendChild(sourceArrow);
1923
+ if (PlaitDrawElement.isArrowLine(element)) {
1924
+ const points = getArrowLinePoints(board, element);
1925
+ return isLineHitRectangle(points, rangeRectangle);
1940
1926
  }
1941
- if (!PlaitArrowLine.isTargetMark(element, ArrowLineMarkerType.none)) {
1942
- const source = getExtendPoint(points[points.length - 1], points[points.length - 2], ARROW_LENGTH + offset);
1943
- const arrow = getArrow(element, { marker: element.target.marker, source, target: points[points.length - 1], isSource: false }, options);
1944
- arrow && arrowG.appendChild(arrow);
1927
+ if (PlaitDrawElement.isVectorLine(element)) {
1928
+ const points = getVectorLinePoints(board, element);
1929
+ return isLineHitRectangle(points, rangeRectangle);
1945
1930
  }
1946
- return arrowG;
1931
+ return null;
1947
1932
  };
1948
- const getArrow = (element, arrowOptions, options) => {
1949
- const { marker, target, source, isSource } = arrowOptions;
1950
- let targetArrow;
1951
- switch (marker) {
1952
- case ArrowLineMarkerType.openTriangle: {
1953
- targetArrow = drawOpenTriangle(element, source, target, options);
1954
- break;
1955
- }
1956
- case ArrowLineMarkerType.solidTriangle: {
1957
- targetArrow = drawSolidTriangle(source, target, options);
1958
- break;
1959
- }
1960
- case ArrowLineMarkerType.arrow: {
1961
- targetArrow = drawArrow(element, source, target, options);
1962
- break;
1963
- }
1964
- case ArrowLineMarkerType.sharpArrow: {
1965
- targetArrow = drawSharpArrow(source, target, options);
1966
- break;
1933
+ const isRectangleHitRotatedElement = (board, rectangle, element) => {
1934
+ const client = RectangleClient.getRectangleByPoints(element.points);
1935
+ return isRectangleHitRotatedPoints(rectangle, RectangleClient.getCornerPoints(client), element.angle);
1936
+ };
1937
+ const isRectangleHitRotatedPoints = (rectangle, points, angle) => {
1938
+ let rotatedPoints = rotatePointsByAngle(points, angle) || points;
1939
+ return isLineHitRectangle(rotatedPoints, rectangle);
1940
+ };
1941
+ const getHitDrawElement = (board, elements) => {
1942
+ let firstFilledElement = getFirstFilledDrawElement(board, elements);
1943
+ let endIndex = elements.length;
1944
+ if (firstFilledElement) {
1945
+ endIndex = elements.indexOf(firstFilledElement) + 1;
1946
+ }
1947
+ const newElements = elements.slice(0, endIndex);
1948
+ const element = getFirstTextOrLineElement(newElements);
1949
+ if (element) {
1950
+ return element;
1951
+ }
1952
+ const sortElements = sortElementsByArea(board, newElements, 'asc');
1953
+ return sortElements[0];
1954
+ };
1955
+ const getFirstFilledDrawElement = (board, elements) => {
1956
+ let filledElement = null;
1957
+ for (let i = 0; i < elements.length; i++) {
1958
+ const element = elements[i];
1959
+ if (isClosedCustomGeometry(board, element) || isClosedDrawElement(element)) {
1960
+ const fill = getFillByElement(board, element);
1961
+ if (isFilled(fill)) {
1962
+ filledElement = element;
1963
+ break;
1964
+ }
1967
1965
  }
1968
- case ArrowLineMarkerType.oneSideUp: {
1969
- targetArrow = drawOneSideArrow(source, target, isSource ? 'down' : 'up', options);
1970
- break;
1966
+ }
1967
+ return filledElement;
1968
+ };
1969
+ const isFilledDrawElement = (board, element) => {
1970
+ return getFirstFilledDrawElement(board, [element]) !== null;
1971
+ };
1972
+ const getFirstTextOrLineElement = (elements) => {
1973
+ const texts = elements.filter((item) => PlaitDrawElement.isText(item));
1974
+ if (texts.length) {
1975
+ return texts[0];
1976
+ }
1977
+ const lines = elements.filter((item) => PlaitDrawElement.isArrowLine(item));
1978
+ if (lines.length) {
1979
+ return lines[0];
1980
+ }
1981
+ return null;
1982
+ };
1983
+ const debugKey$3 = 'debug:plait:hit:shape:edge:sample-points';
1984
+ const debugGenerator$3 = createDebugGenerator(debugKey$3);
1985
+ const shapes = [BasicShapes.cloud];
1986
+ const isHitDrawElement = (board, element, point, isStrict = true) => {
1987
+ const rectangle = board.getRectangle(element);
1988
+ point = rotateAntiPointsByElement(board, point, element) || point;
1989
+ if (PlaitDrawElement.isGeometry(element) && rectangle) {
1990
+ if (debugGenerator$3.isDebug() && shapes.includes(element.shape)) {
1991
+ debugGenerator$3.clear();
1992
+ const { startPoint, arcCommands } = generateCloudPath(rectangle);
1993
+ const points = [startPoint, ...arcCommands.map((arc) => [arc.endX, arc.endY])];
1994
+ debugGenerator$3.drawCircles(board, points, 5, false);
1995
+ let minDistance = Infinity;
1996
+ let nearestPoint = point;
1997
+ let currentStart = startPoint;
1998
+ for (const arc of arcCommands) {
1999
+ const arcNearestPoint = getNearestPointBetweenPointAndArc(point, currentStart, arc);
2000
+ const distance = distanceBetweenPointAndPoint(point[0], point[1], arcNearestPoint[0], arcNearestPoint[1]);
2001
+ const { center } = getEllipseArcCenter(currentStart, arc);
2002
+ debugGenerator$3.drawCircles(board, [center], 8, false, { fill: 'yellow' });
2003
+ if (distance < minDistance) {
2004
+ minDistance = distance;
2005
+ nearestPoint = arcNearestPoint;
2006
+ }
2007
+ currentStart = [arc.endX, arc.endY];
2008
+ }
2009
+ debugGenerator$3.drawCircles(board, [point], 12, false, { fill: 'black', stroke: 'black' });
2010
+ debugGenerator$3.drawCircles(board, [nearestPoint], 12, false, { fill: 'green', stroke: 'green' });
1971
2011
  }
1972
- case ArrowLineMarkerType.oneSideDown: {
1973
- targetArrow = drawOneSideArrow(source, target, isSource ? 'up' : 'down', options);
1974
- break;
2012
+ if (isHitEdgeOfShape(board, element, point, HIT_DISTANCE_BUFFER)) {
2013
+ return true;
1975
2014
  }
1976
- case ArrowLineMarkerType.hollowTriangle: {
1977
- targetArrow = drawHollowTriangleArrow(source, target, options);
1978
- break;
2015
+ const engine = getEngine(getElementShape(element));
2016
+ if (PlaitDrawElement.isText(element)) {
2017
+ const textClient = getTextRectangle(element);
2018
+ return RectangleClient.isPointInRectangle(textClient, point);
1979
2019
  }
1980
- case ArrowLineMarkerType.singleSlash: {
1981
- targetArrow = drawSingleSlash(source, target, isSource, options);
1982
- break;
2020
+ if (!!isStrict && isEmptyTextElement(element) && !isFilledDrawElement(board, element)) {
2021
+ return false;
1983
2022
  }
2023
+ const isHitText = isHitElementText(element, point);
2024
+ return isHitText || engine.isInsidePoint(rectangle, point);
1984
2025
  }
1985
- return targetArrow;
2026
+ if (PlaitDrawElement.isImage(element)) {
2027
+ const client = RectangleClient.getRectangleByPoints(element.points);
2028
+ return RectangleClient.isPointInRectangle(client, point);
2029
+ }
2030
+ if (PlaitDrawElement.isArrowLine(element)) {
2031
+ return isHitArrowLine(board, element, point);
2032
+ }
2033
+ if (PlaitDrawElement.isVectorLine(element)) {
2034
+ return isHitVectorLine(board, element, point);
2035
+ }
2036
+ return null;
1986
2037
  };
1987
- const drawSharpArrow = (source, target, options) => {
1988
- const startPoint = target;
1989
- const { pointLeft, pointRight } = arrowPoints(source, target, 20);
1990
- const g = createG();
1991
- const path = createPath();
1992
- let polylinePath = `M${pointRight[0]},${pointRight[1]}A25,25,20,0,1,${pointLeft[0]},${pointLeft[1]}L${startPoint[0]},${startPoint[1]}Z`;
1993
- path.setAttribute('d', polylinePath);
1994
- path.setAttribute('stroke', `${options?.stroke}`);
1995
- path.setAttribute('stroke-width', `${options?.strokeWidth}`);
1996
- path.setAttribute('fill', `${options?.stroke}`);
1997
- g.appendChild(path);
1998
- return g;
2038
+ const isHitEdgeOfShape = (board, element, point, hitDistanceBuffer) => {
2039
+ const nearestPoint = getNearestPoint(element, point);
2040
+ const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
2041
+ return distance <= hitDistanceBuffer;
1999
2042
  };
2000
- const drawArrow = (element, source, target, options) => {
2001
- const unitVector = getUnitVectorByPointAndPoint(source, target);
2002
- const strokeWidth = getStrokeWidthByElement(element);
2003
- const endPoint = [target[0] + (strokeWidth * unitVector[0]) / 2, target[1] + (strokeWidth * unitVector[1]) / 2];
2004
- const distance = distanceBetweenPointAndPoint(...source, ...endPoint);
2005
- const middlePoint = [
2006
- endPoint[0] - (((distance * 3) / 5 + strokeWidth) / 2) * unitVector[0],
2007
- endPoint[1] - (((distance * 3) / 5 + strokeWidth) / 2) * unitVector[1]
2008
- ];
2009
- const { pointLeft, pointRight } = arrowPoints(source, endPoint, 30);
2010
- const arrowG = drawLinearPath([pointLeft, endPoint, pointRight, middlePoint], { ...options, fill: options.stroke }, true);
2011
- const path = arrowG.querySelector('path');
2012
- path.setAttribute('stroke-linejoin', 'round');
2013
- return arrowG;
2043
+ const isInsideOfShape = (board, element, point, hitDistanceBuffer) => {
2044
+ const client = RectangleClient.inflate(RectangleClient.getRectangleByPoints(element.points), hitDistanceBuffer);
2045
+ return getEngine(getElementShape(element)).isInsidePoint(client, point);
2014
2046
  };
2015
- const drawSolidTriangle = (source, target, options) => {
2016
- const endPoint = target;
2017
- const { pointLeft, pointRight } = arrowPoints(source, endPoint, 30);
2018
- return drawLinearPath([pointLeft, endPoint, pointRight], { ...options, fill: options.stroke }, true);
2047
+ const isHitElementInside = (board, element, point) => {
2048
+ const rectangle = board.getRectangle(element);
2049
+ point = rotateAntiPointsByElement(board, point, element) || point;
2050
+ if (PlaitDrawElement.isGeometry(element) && !PlaitDrawElement.isGeometryByTable(element)) {
2051
+ const engine = getEngine(getElementShape(element));
2052
+ const isHitInside = engine.isInsidePoint(rectangle, point);
2053
+ if (isHitInside) {
2054
+ return isHitInside;
2055
+ }
2056
+ if (engine.getTextRectangle) {
2057
+ const isHitText = isHitElementText(element, point);
2058
+ if (isHitText) {
2059
+ return isHitText;
2060
+ }
2061
+ }
2062
+ }
2063
+ if (PlaitDrawElement.isImage(element)) {
2064
+ const client = RectangleClient.getRectangleByPoints(element.points);
2065
+ return RectangleClient.isPointInRectangle(client, point);
2066
+ }
2067
+ if (PlaitDrawElement.isArrowLine(element)) {
2068
+ return isHitArrowLine(board, element, point);
2069
+ }
2070
+ if (PlaitDrawElement.isVectorLine(element)) {
2071
+ return isHitVectorLine(board, element, point);
2072
+ }
2073
+ return null;
2019
2074
  };
2020
- const drawOpenTriangle = (element, source, target, options) => {
2021
- const unitVector = getUnitVectorByPointAndPoint(source, target);
2075
+
2076
+ const getTextRectangle = (element) => {
2077
+ const elementRectangle = RectangleClient.getRectangleByPoints(element.points);
2022
2078
  const strokeWidth = getStrokeWidthByElement(element);
2023
- const endPoint = [target[0] + (strokeWidth * unitVector[0]) / 2, target[1] + (strokeWidth * unitVector[1]) / 2];
2024
- const { pointLeft, pointRight } = arrowPoints(source, endPoint, 40);
2025
- return drawLinearPath([pointLeft, endPoint, pointRight], options);
2026
- };
2027
- const drawOneSideArrow = (source, target, side, options) => {
2028
- const { pointLeft, pointRight } = arrowPoints(source, target, 40);
2029
- return drawLinearPath([side === 'up' ? pointRight : pointLeft, target], options);
2079
+ const height = element.textHeight;
2080
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
2081
+ return {
2082
+ height,
2083
+ width: width > 0 ? width : 0,
2084
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
2085
+ y: elementRectangle.y + (elementRectangle.height - height) / 2
2086
+ };
2030
2087
  };
2031
- const drawSingleSlash = (source, target, isSource, options) => {
2032
- const length = distanceBetweenPointAndPoint(...source, ...target);
2033
- const middlePoint = getExtendPoint(target, source, length / 2);
2034
- const angle = isSource ? 120 : 60;
2035
- const start = rotate(...source, ...middlePoint, (angle * Math.PI) / 180);
2036
- const end = rotate(...target, ...middlePoint, (angle * Math.PI) / 180);
2037
- return drawLinearPath([start, end], options);
2088
+ const getStrokeWidthByElement = (element) => {
2089
+ if (PlaitDrawElement.isText(element)) {
2090
+ return 0;
2091
+ }
2092
+ const strokeWidth = element.strokeWidth || DefaultDrawStyle.strokeWidth;
2093
+ return strokeWidth;
2038
2094
  };
2039
- const drawHollowTriangleArrow = (source, target, options) => {
2040
- const { pointLeft, pointRight } = arrowPoints(source, target, 30);
2041
- return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
2095
+ const insertElement = (board, element) => {
2096
+ memorizeLatestShape(board, element.shape);
2097
+ Transforms.insertNode(board, element, [board.children.length]);
2098
+ clearSelectedElement(board);
2099
+ addSelectedElement(board, element);
2100
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2042
2101
  };
2043
-
2044
- class ArrowLineShapeGenerator extends Generator {
2045
- canDraw(element) {
2102
+ const isDrawElementIncludeText = (element) => {
2103
+ if (PlaitDrawElement.isText(element)) {
2046
2104
  return true;
2047
2105
  }
2048
- draw(element) {
2049
- let lineG;
2050
- lineG = drawArrowLine(this.board, element);
2051
- return lineG;
2106
+ if (PlaitDrawElement.isImage(element)) {
2107
+ return false;
2052
2108
  }
2053
- }
2054
-
2055
- const createArrowLineElement = (shape, points, source, target, texts, options) => {
2056
- return {
2057
- id: idCreator(),
2058
- type: 'arrow-line',
2059
- shape,
2060
- source,
2061
- texts: texts ? texts : [],
2062
- target,
2063
- opacity: 1,
2064
- points,
2065
- ...options
2066
- };
2109
+ if (PlaitDrawElement.isGeometry(element)) {
2110
+ return isGeometryIncludeText(element);
2111
+ }
2112
+ if (PlaitDrawElement.isArrowLine(element)) {
2113
+ const editors = getTextEditorsByElement(element);
2114
+ return editors.length > 0;
2115
+ }
2116
+ if (PlaitDrawElement.isElementByTable(element)) {
2117
+ return element.cells.some((cell) => isCellIncludeText(cell));
2118
+ }
2119
+ return true;
2067
2120
  };
2068
- const getArrowLinePoints = (board, element) => {
2069
- switch (element.shape) {
2070
- case ArrowLineShape.elbow: {
2071
- return getElbowPoints(board, element);
2121
+ const isDrawElementsIncludeText = (elements) => {
2122
+ return elements.some((item) => {
2123
+ return isDrawElementIncludeText(item);
2124
+ });
2125
+ };
2126
+ const isClosedDrawElement = (element) => {
2127
+ if (PlaitDrawElement.isDrawElement(element)) {
2128
+ if (PlaitDrawElement.isText(element) || PlaitDrawElement.isArrowLine(element) || PlaitDrawElement.isImage(element)) {
2129
+ return false;
2072
2130
  }
2073
- case ArrowLineShape.curve: {
2074
- return getCurvePoints(board, element);
2131
+ if (PlaitDrawElement.isVectorLine(element)) {
2132
+ return isClosedPoints(element.points);
2075
2133
  }
2076
- default: {
2077
- const points = PlaitArrowLine.getPoints(board, element);
2078
- const handleRefPair = getArrowLineHandleRefPair(board, element);
2079
- points[0] = handleRefPair.source.point;
2080
- points[points.length - 1] = handleRefPair.target.point;
2081
- return points;
2134
+ if (PlaitDrawElement.isGeometry(element)) {
2135
+ return isGeometryClosed(element);
2082
2136
  }
2137
+ return true;
2083
2138
  }
2139
+ return false;
2084
2140
  };
2085
- const getCurvePoints = (board, element) => {
2086
- if (element.points.length === 2) {
2087
- const handleRefPair = getArrowLineHandleRefPair(board, element);
2088
- const { source, target } = handleRefPair;
2089
- const sourceBoundElement = handleRefPair.source.boundElement;
2090
- const targetBoundElement = handleRefPair.target.boundElement;
2091
- let curvePoints = [source.point];
2092
- const sumDistance = distanceBetweenPointAndPoint(...source.point, ...target.point);
2093
- const offset = 12 + sumDistance / 3;
2094
- if (sourceBoundElement) {
2095
- curvePoints.push(getPointByVectorComponent(source.point, source.vector, offset));
2096
- }
2097
- if (targetBoundElement) {
2098
- curvePoints.push(getPointByVectorComponent(target.point, target.vector, offset));
2141
+ const isClosedCustomGeometry = (board, value) => {
2142
+ return PlaitDrawElement.isCustomGeometryElement(board, value) && isClosedPoints(value.points);
2143
+ };
2144
+ const getSnappingShape = (board, point) => {
2145
+ let hitElement = getHitShape(board, point);
2146
+ if (hitElement) {
2147
+ const ref = getSnappingRef(board, hitElement, point);
2148
+ if (ref.isHitConnector || ref.isHitEdge) {
2149
+ return hitElement;
2099
2150
  }
2100
- const isSingleBound = (sourceBoundElement && !targetBoundElement) || (!sourceBoundElement && targetBoundElement);
2101
- if (isSingleBound) {
2102
- curvePoints.push(target.point);
2103
- const points = Q2C(curvePoints);
2104
- return pointsOnBezierCurves(points);
2151
+ }
2152
+ return null;
2153
+ };
2154
+ const getSnappingRef = (board, hitElement, point) => {
2155
+ const rotatedPoint = rotateAntiPointsByElement(board, point, hitElement) || point;
2156
+ const connectorPoint = getHitConnectorPoint(rotatedPoint, hitElement);
2157
+ const edgePoint = getNearestPoint(hitElement, rotatedPoint);
2158
+ const isHitEdge = isHitEdgeOfShape(board, hitElement, rotatedPoint, LINE_SNAPPING_BUFFER);
2159
+ return { isHitEdge, isHitConnector: !!connectorPoint, connectorPoint, edgePoint };
2160
+ };
2161
+ const getHitShape = (board, point, offset = LINE_HIT_GEOMETRY_BUFFER) => {
2162
+ let hitShape = null;
2163
+ traverseDrawShapes(board, (element) => {
2164
+ if (hitShape === null && isInsideOfShape(board, element, rotateAntiPointsByElement(board, point, element) || point, offset * 2)) {
2165
+ hitShape = element;
2105
2166
  }
2106
- if (!sourceBoundElement && !targetBoundElement) {
2107
- curvePoints.push(getPointByVectorComponent(source.point, source.vector, offset));
2108
- curvePoints.push(getPointByVectorComponent(target.point, target.vector, offset));
2167
+ });
2168
+ return hitShape;
2169
+ };
2170
+ const traverseDrawShapes = (board, callback) => {
2171
+ depthFirstRecursion(board, (node) => {
2172
+ if (!PlaitBoard.isBoard(node) && PlaitDrawElement.isShapeElement(node)) {
2173
+ callback(node);
2109
2174
  }
2110
- curvePoints.push(target.point);
2111
- return pointsOnBezierCurves(curvePoints);
2175
+ }, getIsRecursionFunc(board), true);
2176
+ };
2177
+ const drawShape = (board, outerRectangle, shape, roughOptions, drawOptions) => {
2178
+ return getEngine(shape).draw(board, outerRectangle, roughOptions, drawOptions);
2179
+ };
2180
+ const drawBoundReaction = (board, element, roughOptions = { hasMask: true, hasConnector: true }) => {
2181
+ const g = createG();
2182
+ const rectangle = RectangleClient.getRectangleByPoints(element.points);
2183
+ const activeRectangle = RectangleClient.inflate(rectangle, SNAPPING_STROKE_WIDTH);
2184
+ const shape = getElementShape(element);
2185
+ let drawOptions;
2186
+ if (PlaitDrawElement.isElementByTable(element)) {
2187
+ drawOptions = { element };
2112
2188
  }
2113
- else {
2114
- let dataPoints = PlaitArrowLine.getPoints(board, element);
2115
- dataPoints = removeDuplicatePoints(dataPoints);
2116
- const points = catmullRomFitting(dataPoints);
2117
- return pointsOnBezierCurves(points);
2189
+ const strokeG = drawShape(board, activeRectangle, shape, {
2190
+ stroke: SELECTION_BORDER_COLOR,
2191
+ strokeWidth: SNAPPING_STROKE_WIDTH
2192
+ }, drawOptions);
2193
+ g.appendChild(strokeG);
2194
+ if (roughOptions.hasMask) {
2195
+ const maskG = drawShape(board, activeRectangle, shape, {
2196
+ stroke: SELECTION_BORDER_COLOR,
2197
+ strokeWidth: 0,
2198
+ fill: isClosedDrawElement(element) ? SELECTION_FILL_COLOR : DefaultDrawStyle.fill,
2199
+ fillStyle: 'solid'
2200
+ }, drawOptions);
2201
+ g.appendChild(maskG);
2202
+ }
2203
+ if (roughOptions.hasConnector) {
2204
+ const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
2205
+ connectorPoints.forEach((point) => {
2206
+ const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 8, {
2207
+ stroke: SELECTION_BORDER_COLOR,
2208
+ strokeWidth: ACTIVE_STROKE_WIDTH,
2209
+ fill: '#FFF',
2210
+ fillStyle: 'solid'
2211
+ });
2212
+ g.appendChild(circleG);
2213
+ });
2118
2214
  }
2215
+ return g;
2119
2216
  };
2120
- const drawArrowLine = (board, element) => {
2121
- const strokeWidth = getStrokeWidthByElement(element);
2122
- const strokeColor = getStrokeColorByElement(board, element);
2123
- const strokeStyle = getStrokeStyleByElement(board, element);
2124
- const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
2125
- const options = { stroke: strokeColor, strokeWidth, strokeLineDash };
2126
- const lineG = createG();
2127
- let points = getArrowLinePoints(board, element);
2128
- let line;
2129
- if (element.shape === ArrowLineShape.curve) {
2130
- line = PlaitBoard.getRoughSVG(board).curve(points, options);
2217
+ const getTextKey = (element, text) => {
2218
+ if (element && isMultipleTextGeometry(element)) {
2219
+ return `${element.id}-${text.id}`;
2131
2220
  }
2132
2221
  else {
2133
- line = drawLinearPath(points, options);
2134
- }
2135
- const id = idCreator();
2136
- line.setAttribute('mask', `url(#${id})`);
2137
- if (element.strokeStyle === StrokeStyle.dotted) {
2138
- setStrokeLinecap(line, 'round');
2222
+ return text.id;
2139
2223
  }
2140
- lineG.appendChild(line);
2141
- const { mask, maskTargetFillRect } = drawArrowLineMask(board, element, id);
2142
- lineG.appendChild(mask);
2143
- line.appendChild(maskTargetFillRect);
2144
- const arrow = drawArrowLineArrow(element, points, { stroke: strokeColor, strokeWidth });
2145
- arrow && lineG.appendChild(arrow);
2146
- return lineG;
2147
- };
2148
- const getHitConnection = (board, point, hitElement) => {
2149
- let rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
2150
- const ref = getSnappingRef(board, hitElement, point);
2151
- const connectionPoint = ref.connectorPoint || ref.edgePoint;
2152
- return [(connectionPoint[0] - rectangle.x) / rectangle.width, (connectionPoint[1] - rectangle.y) / rectangle.height];
2153
- };
2154
- const getHitConnectorPoint = (point, hitElement) => {
2155
- const rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
2156
- const shape = getElementShape(hitElement);
2157
- const connectorPoints = getEngine(shape).getConnectorPoints(rectangle);
2158
- return connectorPoints.find(connectorPoint => {
2159
- return distanceBetweenPointAndPoint(...connectorPoint, ...point) <= LINE_SNAPPING_CONNECTOR_BUFFER;
2160
- });
2161
- };
2162
- const getArrowLineTextRectangle = (board, element, index) => {
2163
- const text = element.texts[index];
2164
- const elbowPoints = getArrowLinePoints(board, element);
2165
- const point = getPointOnPolyline(elbowPoints, text.position);
2166
- return {
2167
- x: point[0] - text.width / 2,
2168
- y: point[1] - text.height / 2,
2169
- width: text.width,
2170
- height: text.height
2171
- };
2172
- };
2173
- const getArrowLines = (board) => {
2174
- return findElements(board, {
2175
- match: (element) => PlaitDrawElement.isArrowLine(element),
2176
- recursion: (element) => PlaitDrawElement.isDrawElement(element)
2177
- });
2178
2224
  };
2179
- // quadratic Bezier to cubic Bezier
2180
- const Q2C = (points) => {
2181
- const result = [];
2182
- const numSegments = points.length / 3;
2183
- for (let i = 0; i < numSegments; i++) {
2184
- const start = points[i];
2185
- const qControl = points[i + 1];
2186
- const end = points[i + 2];
2187
- const startDistance = distanceBetweenPointAndPoint(...start, ...qControl);
2188
- const endDistance = distanceBetweenPointAndPoint(...end, ...qControl);
2189
- const cControl1 = getExtendPoint(start, qControl, (startDistance * 2) / 3);
2190
- const cControl2 = getExtendPoint(end, qControl, (endDistance * 2) / 3);
2191
- result.push(start, cControl1, cControl2, end);
2225
+ const getGeometryAlign = (board, element) => {
2226
+ if (isMultipleTextGeometry(element)) {
2227
+ const drawShapeText = element.texts.find((item) => item.id.includes(GeometryCommonTextKeys.content));
2228
+ return drawShapeText?.text.align || Alignment.center;
2192
2229
  }
2193
- return result;
2230
+ if (isSingleTextGeometry(element)) {
2231
+ return element.text?.align || Alignment.center;
2232
+ }
2233
+ if (PlaitDrawElement.isElementByTable(element)) {
2234
+ const firstTextCell = element.cells.find((item) => item.text);
2235
+ return firstTextCell?.text?.align || Alignment.center;
2236
+ }
2237
+ return Alignment.center;
2194
2238
  };
2195
- const handleArrowLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceElement, lineShapeG) => {
2196
- const hitElement = getSnappingShape(board, movingPoint);
2197
- const targetConnection = hitElement ? getHitConnection(board, movingPoint, hitElement) : undefined;
2198
- const sourceConnection = sourceElement ? getHitConnection(board, sourcePoint, sourceElement) : undefined;
2199
- const targetBoundId = hitElement ? hitElement.id : undefined;
2200
- const lineGenerator = new ArrowLineShapeGenerator(board);
2201
- const memorizedLatest = getLineMemorizedLatest();
2202
- let sourceMarker, targetMarker;
2203
- sourceMarker = memorizedLatest.source;
2204
- targetMarker = memorizedLatest.target;
2205
- sourceMarker && delete memorizedLatest.source;
2206
- targetMarker && delete memorizedLatest.target;
2207
- const temporaryLineElement = createArrowLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || ArrowLineMarkerType.none, connection: sourceConnection, boundId: sourceElement?.id }, { marker: targetMarker || ArrowLineMarkerType.arrow, connection: targetConnection, boundId: targetBoundId }, [], {
2208
- strokeWidth: DefaultLineStyle.strokeWidth,
2209
- ...memorizedLatest
2210
- });
2211
- const linePoints = getArrowLinePoints(board, temporaryLineElement);
2212
- const otherPoint = linePoints[0];
2213
- temporaryLineElement.points[1] = alignPoints(otherPoint, movingPoint);
2214
- lineGenerator.processDrawing(temporaryLineElement, lineShapeG);
2215
- PlaitBoard.getElementActiveHost(board).append(lineShapeG);
2216
- return temporaryLineElement;
2239
+ const isClosedPoints = (points) => {
2240
+ const startPoint = points[0];
2241
+ const endPoint = points[points.length - 1];
2242
+ return startPoint[0] === endPoint[0] && startPoint[1] === endPoint[1];
2243
+ };
2244
+ const getDefaultGeometryText = (board) => {
2245
+ return getI18nValue(board, DrawI18nKey.geometryText, DefaultTextProperty.text);
2217
2246
  };
2218
- function drawArrowLineMask(board, element, id) {
2219
- const mask = createMask();
2220
- mask.setAttribute('id', id);
2221
- const points = getArrowLinePoints(board, element);
2222
- let rectangle = RectangleClient.getRectangleByPoints(points);
2223
- rectangle = RectangleClient.getOutlineRectangle(rectangle, -30);
2224
- const maskFillRect = createRect(rectangle, {
2225
- fill: 'white'
2226
- });
2227
- mask.appendChild(maskFillRect);
2228
- const texts = element.texts;
2229
- texts.forEach((text, index) => {
2230
- let textRectangle = getArrowLineTextRectangle(board, element, index);
2231
- textRectangle = RectangleClient.inflate(textRectangle, LINE_TEXT_SPACE * 2);
2232
- const rect = createRect(textRectangle, {
2233
- fill: 'black'
2234
- });
2235
- mask.appendChild(rect);
2236
- });
2237
- // open line
2238
- const maskTargetFillRect = createRect(rectangle);
2239
- maskTargetFillRect.setAttribute('opacity', '0');
2240
- maskTargetFillRect.setAttribute('fill', 'none');
2241
- return { mask, maskTargetFillRect };
2242
- }
2243
2247
 
2244
2248
  const createUMLClassOrInterfaceGeometryElement = (board, shape, points) => {
2245
2249
  const memorizedLatest = getMemorizedLatestByPointer(shape);
@@ -2301,8 +2305,9 @@ const buildTableCellsForGeometry = (board, rows, columns, shape) => {
2301
2305
  const memorizedLatest = getMemorizedLatestByPointer(shape);
2302
2306
  const cellCount = rows.length * columns.length;
2303
2307
  const defaultTexts = getDefaultGeometryProperty(shape)?.texts || [];
2304
- const testHeights = defaultTexts.map((textItem) => {
2305
- return getTextShapeProperty(board, textItem.text || DefaultTextProperty.text, memorizedLatest.textProperties['font-size']).height;
2308
+ const textHeights = defaultTexts.map((textItem) => {
2309
+ return getTextShapeProperty(board, textItem.text || getDefaultGeometryText(board), memorizedLatest.textProperties['font-size'])
2310
+ .height;
2306
2311
  });
2307
2312
  return new Array(cellCount).fill('').map((item, index) => {
2308
2313
  const rowIndex = Math.floor(index / columns.length);
@@ -2311,7 +2316,7 @@ const buildTableCellsForGeometry = (board, rows, columns, shape) => {
2311
2316
  id: idCreator(),
2312
2317
  rowId: rows[rowIndex].id,
2313
2318
  columnId: columns[columnIndex].id,
2314
- textHeight: testHeights[index],
2319
+ textHeight: textHeights[index],
2315
2320
  text: {
2316
2321
  children: [
2317
2322
  {
@@ -2394,66 +2399,12 @@ const getDefaultBasicShapeProperty = (shape) => {
2394
2399
  const getDefaultUMLProperty = (shape) => {
2395
2400
  return DefaultUMLPropertyMap[shape];
2396
2401
  };
2397
- const createDefaultFlowchart = (point) => {
2398
- const decisionProperty = getDefaultFlowchartProperty(FlowchartSymbols.decision);
2399
- const processProperty = getDefaultFlowchartProperty(FlowchartSymbols.process);
2400
- const terminalProperty = getDefaultFlowchartProperty(FlowchartSymbols.terminal);
2401
- const options = {
2402
- strokeWidth: DefaultBasicShapeProperty.strokeWidth
2403
- };
2404
- const lineOptions = {
2405
- strokeWidth: DefaultLineStyle.strokeWidth
2406
- };
2407
- const startElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, point), '开始', options);
2408
- const processPoint1 = [point[0], point[1] + terminalProperty.height / 2 + 55 + processProperty.height / 2];
2409
- const processElement1 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint1), '过程', options);
2410
- const decisionPoint = [processPoint1[0], processPoint1[1] + processProperty.height / 2 + 55 + decisionProperty.height / 2];
2411
- const decisionElement = createGeometryElement(FlowchartSymbols.decision, getDefaultGeometryPoints(FlowchartSymbols.decision, decisionPoint), '判断', options);
2412
- const processPoint2 = [decisionPoint[0] + decisionProperty.width / 2 + 75 + processProperty.width / 2, decisionPoint[1]];
2413
- const processElement2 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint2), '过程', options);
2414
- const endPoint = [decisionPoint[0], decisionPoint[1] + decisionProperty.height / 2 + 95 + terminalProperty.height / 2];
2415
- const endElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, endPoint), '结束', options);
2416
- const line1 = createArrowLineElement(ArrowLineShape.elbow, [
2417
- [0, 0],
2418
- [0, 0]
2419
- ], { marker: ArrowLineMarkerType.none, connection: [0.5, 1], boundId: startElement.id }, { marker: ArrowLineMarkerType.arrow, connection: [0.5, 0], boundId: processElement1.id }, [], lineOptions);
2420
- const line2 = createArrowLineElement(ArrowLineShape.elbow, [
2421
- [0, 0],
2422
- [0, 0]
2423
- ], { marker: ArrowLineMarkerType.none, connection: [0.5, 1], boundId: processElement1.id }, { marker: ArrowLineMarkerType.arrow, connection: [0.5, 0], boundId: decisionElement.id }, [], lineOptions);
2424
- const line3 = createArrowLineElement(ArrowLineShape.elbow, [
2425
- [0, 0],
2426
- [0, 0]
2427
- ], { marker: ArrowLineMarkerType.none, connection: [0.5, 1], boundId: decisionElement.id }, { marker: ArrowLineMarkerType.arrow, connection: [0.5, 0], boundId: endElement.id }, [
2428
- {
2429
- text: buildText('是'),
2430
- position: 0.5,
2431
- width: 14,
2432
- height: 20
2433
- }
2434
- ], lineOptions);
2435
- const line4 = createArrowLineElement(ArrowLineShape.elbow, [
2436
- [0, 0],
2437
- [0, 0]
2438
- ], { marker: ArrowLineMarkerType.none, connection: [1, 0.5], boundId: decisionElement.id }, { marker: ArrowLineMarkerType.arrow, connection: [0, 0.5], boundId: processElement2.id }, [
2439
- {
2440
- text: buildText('否'),
2441
- position: 0.5,
2442
- width: 14,
2443
- height: 20
2444
- }
2445
- ], lineOptions);
2446
- const line5 = createArrowLineElement(ArrowLineShape.elbow, [
2447
- [0, 0],
2448
- [0, 0]
2449
- ], { marker: ArrowLineMarkerType.none, connection: [0.5, 1], boundId: processElement2.id }, { marker: ArrowLineMarkerType.arrow, connection: [1, 0.5], boundId: endElement.id }, [], lineOptions);
2450
- return [startElement, processElement1, decisionElement, processElement2, endElement, line1, line2, line3, line4, line5];
2451
- };
2452
- const getAutoCompletePoints = (element) => {
2402
+ const getAutoCompletePoints = (board, element, isToActive = false) => {
2453
2403
  const AutoCompleteMargin = (12 + RESIZE_HANDLE_DIAMETER / 2) * 2;
2454
- let rectangle = RectangleClient.getRectangleByPoints(element.points);
2455
- rectangle = RectangleClient.inflate(rectangle, AutoCompleteMargin);
2456
- return RectangleClient.getEdgeCenterPoints(rectangle);
2404
+ const rectangle = RectangleClient.getRectangleByPoints(element.points);
2405
+ const activeRectangle = toActiveRectangleFromViewBoxRectangle(board, rectangle);
2406
+ const targetRectangle = isToActive ? activeRectangle : rectangle;
2407
+ return RectangleClient.getEdgeCenterPoints(RectangleClient.inflate(targetRectangle, AutoCompleteMargin));
2457
2408
  };
2458
2409
  const getHitIndexOfAutoCompletePoint = (movingPoint, points) => {
2459
2410
  return points.findIndex((point) => {
@@ -2469,7 +2420,7 @@ const getDrawDefaultStrokeColor = (theme) => {
2469
2420
  const getFlowchartDefaultFill = (theme) => {
2470
2421
  return DrawThemeColors[theme].fill;
2471
2422
  };
2472
- const getTextShapeProperty = (board, text = DefaultTextProperty.text, fontSize) => {
2423
+ const getTextShapeProperty = (board, text, fontSize) => {
2473
2424
  fontSize = fontSize ? Number(fontSize) : DEFAULT_FONT_SIZE;
2474
2425
  const textSize = measureElement(buildText(text), { fontSize, fontFamily: DEFAULT_FONT_FAMILY });
2475
2426
  return {
@@ -2498,7 +2449,7 @@ const getDefaultTextPoints = (board, centerPoint, fontSize) => {
2498
2449
  const property = getTextShapeProperty(board, DefaultTextProperty.text, fontSize);
2499
2450
  return RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(centerPoint, property.width, property.height));
2500
2451
  };
2501
- const createTextElement = (board, points, text = DefaultTextProperty.text, textHeight) => {
2452
+ const createTextElement = (board, points, text, textHeight) => {
2502
2453
  const memorizedLatest = getMemorizedLatestByPointer(BasicShapes.text);
2503
2454
  textHeight = textHeight ? textHeight : RectangleClient.getRectangleByPoints(points).height;
2504
2455
  return createGeometryElement(BasicShapes.text, points, text, memorizedLatest.geometryProperties, {
@@ -2531,12 +2482,6 @@ const editText = (board, element, text) => {
2531
2482
  textManage.edit(() => { });
2532
2483
  }
2533
2484
  };
2534
- const rerenderGeometryActive = (board, element) => {
2535
- const elementRef = PlaitElement.getElementRef(element);
2536
- const activeGenerator = elementRef.getGenerator(ActiveGenerator.key);
2537
- const selected = getSelectedElements(board).includes(element);
2538
- activeGenerator.processDrawing(element, PlaitBoard.getElementActiveHost(board), { selected });
2539
- };
2540
2485
  const isGeometryIncludeText = (element) => {
2541
2486
  return isSingleTextGeometry(element) || isMultipleTextGeometry(element);
2542
2487
  };
@@ -3392,7 +3337,7 @@ function withDrawResize(board) {
3392
3337
  const resizeSnapRef = getSnapResizingRef(board, resizeRef.element, resizeSnapRefOptions);
3393
3338
  resizeActivePoints = resizeSnapRef.activePoints;
3394
3339
  snapG = resizeSnapRef.snapG;
3395
- PlaitBoard.getElementActiveHost(board).append(snapG);
3340
+ PlaitBoard.getElementTopHost(board).append(snapG);
3396
3341
  if (bulkRotationRef) {
3397
3342
  const boundingBoxCornerPoints = RectangleClient.getPoints(resizeRef.rectangle);
3398
3343
  const resizedBoundingBoxCornerPoints = boundingBoxCornerPoints.map((p) => {
@@ -3485,29 +3430,17 @@ function withDrawResize(board) {
3485
3430
  handleG.remove();
3486
3431
  handleG = null;
3487
3432
  }
3488
- if (canResize() && !isSelectionMoving(board)) {
3489
- handleG = createG();
3490
- const elements = getSelectedElements(board);
3491
- const boundingRectangle = needCustomActiveRectangle
3492
- ? RectangleClient.getRectangleByPoints(resizeActivePoints)
3493
- : getRectangleByElements(board, elements, false);
3494
- let corners = RectangleClient.getCornerPoints(boundingRectangle);
3495
- const angle = getSelectionAngle(elements);
3496
- if (angle) {
3497
- const centerPoint = RectangleClient.getCenterPoint(boundingRectangle);
3498
- corners = rotatePoints(corners, centerPoint, angle);
3499
- }
3500
- corners.forEach((corner) => {
3501
- const g = drawHandle(board, corner);
3502
- handleG && handleG.append(g);
3503
- });
3504
- PlaitBoard.getElementActiveHost(board).append(handleG);
3433
+ const selectedElements = getSelectedElements(board);
3434
+ if (canResize() && !isSelectionMoving(board) && selectedElements.length > 1) {
3435
+ handleG = generatorResizeHandles(board, resizeActivePoints, needCustomActiveRectangle);
3436
+ PlaitBoard.getActiveHost(board).append(handleG);
3505
3437
  }
3506
3438
  };
3507
3439
  board.drawSelectionRectangle = () => {
3508
3440
  if (needCustomActiveRectangle) {
3509
3441
  const rectangle = RectangleClient.getRectangleByPoints(resizeActivePoints);
3510
- return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
3442
+ const activeRectangle = toActiveRectangleFromViewBoxRectangle(board, rectangle);
3443
+ return drawRectangle(board, RectangleClient.inflate(activeRectangle, ACTIVE_STROKE_WIDTH), {
3511
3444
  stroke: SELECTION_BORDER_COLOR,
3512
3445
  strokeWidth: ACTIVE_STROKE_WIDTH
3513
3446
  });
@@ -3585,6 +3518,25 @@ const getResizePointsByOtherwiseAxis = (board, points, resizeOriginPoint, xZoom,
3585
3518
  const newRectangle = RectangleClient.getRectangleByPoints(resultPoints);
3586
3519
  return rotatePoints(resultPoints, RectangleClient.getCenterPoint(newRectangle), -(1 / 2) * Math.PI);
3587
3520
  };
3521
+ const generatorResizeHandles = (board, resizeActivePoints, needCustomActiveRectangle) => {
3522
+ const handleG = createG();
3523
+ const elements = getSelectedElements(board);
3524
+ const boundingRectangle = needCustomActiveRectangle
3525
+ ? RectangleClient.getRectangleByPoints(resizeActivePoints)
3526
+ : getRectangleByElements(board, elements, false);
3527
+ const boundingActiveRectangle = toActiveRectangleFromViewBoxRectangle(board, boundingRectangle);
3528
+ let corners = RectangleClient.getCornerPoints(boundingActiveRectangle);
3529
+ const angle = getSelectionAngle(elements);
3530
+ if (angle) {
3531
+ const centerPoint = RectangleClient.getCenterPoint(boundingActiveRectangle);
3532
+ corners = rotatePoints(corners, centerPoint, angle);
3533
+ }
3534
+ corners.forEach((corner) => {
3535
+ const g = drawHandle(board, corner);
3536
+ handleG.append(g);
3537
+ });
3538
+ return handleG;
3539
+ };
3588
3540
 
3589
3541
  const debugKey$1 = 'debug:plait:point-for-geometry';
3590
3542
  const debugGenerator$1 = createDebugGenerator(debugKey$1);
@@ -7094,7 +7046,7 @@ class GeometryShapeGenerator extends Generator {
7094
7046
  class ArrowLineAutoCompleteGenerator extends Generator {
7095
7047
  static { this.key = 'line-auto-complete-generator'; }
7096
7048
  constructor(board) {
7097
- super(board);
7049
+ super(board, { active: true });
7098
7050
  this.board = board;
7099
7051
  this.hoverElement = null;
7100
7052
  }
@@ -7109,7 +7061,7 @@ class ArrowLineAutoCompleteGenerator extends Generator {
7109
7061
  }
7110
7062
  draw(element, data) {
7111
7063
  this.autoCompleteG = createG();
7112
- const middlePoints = getAutoCompletePoints(element);
7064
+ const middlePoints = getAutoCompletePoints(this.board, element, true);
7113
7065
  middlePoints.forEach((point, index) => {
7114
7066
  const circle = drawCircle(PlaitBoard.getRoughSVG(this.board), point, LINE_AUTO_COMPLETE_DIAMETER, {
7115
7067
  stroke: 'none',
@@ -7152,7 +7104,7 @@ class GeometryComponent extends CommonElementFlavour {
7152
7104
  super();
7153
7105
  }
7154
7106
  initializeGenerator() {
7155
- this.activeGenerator = new ActiveGenerator(this.board, {
7107
+ this.activeGenerator = createActiveGenerator(this.board, {
7156
7108
  getStrokeWidth: () => {
7157
7109
  const selectedElements = getSelectedElements(this.board);
7158
7110
  if (selectedElements.length === 1 && !isSelectionMoving(this.board)) {
@@ -7185,15 +7137,23 @@ class GeometryComponent extends CommonElementFlavour {
7185
7137
  }
7186
7138
  this.getRef().addGenerator(ArrowLineAutoCompleteGenerator.key, this.lineAutoCompleteGenerator);
7187
7139
  this.getRef().addGenerator(ActiveGenerator.key, this.activeGenerator);
7140
+ this.getRef().updateActiveSection = () => {
7141
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7142
+ selected: this.selected
7143
+ });
7144
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7145
+ selected: this.selected
7146
+ });
7147
+ };
7188
7148
  }
7189
7149
  initialize() {
7190
7150
  super.initialize();
7191
7151
  this.initializeGenerator();
7192
7152
  this.shapeGenerator.processDrawing(this.element, this.getElementG());
7193
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7153
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7194
7154
  selected: this.selected
7195
7155
  });
7196
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7156
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementTopHost(this.board), {
7197
7157
  selected: this.selected
7198
7158
  });
7199
7159
  this.textGenerator && this.textGenerator.draw(this.getElementG());
@@ -7201,18 +7161,19 @@ class GeometryComponent extends CommonElementFlavour {
7201
7161
  onContextChanged(value, previous) {
7202
7162
  if (value.element !== previous.element || value.hasThemeChanged) {
7203
7163
  this.shapeGenerator.processDrawing(this.element, this.getElementG());
7204
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
7205
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7164
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), { selected: this.selected });
7165
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7206
7166
  selected: this.selected
7207
7167
  });
7208
7168
  this.textGenerator && this.updateText(previous.element, value.element);
7209
7169
  }
7210
7170
  else {
7211
7171
  const hasSameSelected = value.selected === previous.selected;
7212
- const hasSameHandleState = this.activeGenerator.options.hasResizeHandle() === this.activeGenerator.hasResizeHandle;
7213
- if (!hasSameSelected || !hasSameHandleState) {
7214
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
7215
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7172
+ if (!hasSameSelected || value.selected) {
7173
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7174
+ selected: this.selected
7175
+ });
7176
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7216
7177
  selected: this.selected
7217
7178
  });
7218
7179
  }
@@ -7321,8 +7282,9 @@ function getHitPointIndex(points, movingPoint) {
7321
7282
  }
7322
7283
 
7323
7284
  class LineActiveGenerator extends Generator {
7324
- constructor() {
7325
- super(...arguments);
7285
+ constructor(board, options = { active: true }) {
7286
+ super(board, options);
7287
+ this.board = board;
7326
7288
  this.onlySelectedCurrentLine = false;
7327
7289
  }
7328
7290
  canDraw(element, data) {
@@ -7346,16 +7308,18 @@ class LineActiveGenerator extends Generator {
7346
7308
  updatePoints = points.slice(0, 1).concat(points.slice(-1));
7347
7309
  elbowNextRenderPoints = getNextRenderPoints(this.board, element, data.linePoints);
7348
7310
  }
7349
- updatePoints.forEach(point => {
7311
+ const activePoints = updatePoints.map((point) => toActivePointFromViewBoxPoint(this.board, point));
7312
+ activePoints.forEach((point) => {
7350
7313
  const updateHandle = drawPrimaryHandle(this.board, point);
7351
7314
  activeG.appendChild(updateHandle);
7352
7315
  });
7353
7316
  const middlePoints = getMiddlePoints(this.board, element);
7317
+ const activeMiddlePoints = middlePoints.map((point) => toActivePointFromViewBoxPoint(this.board, point));
7354
7318
  if (!PlaitBoard.hasBeenTextEditing(this.board)) {
7355
- for (let i = 0; i < middlePoints.length; i++) {
7356
- const point = middlePoints[i];
7319
+ for (let i = 0; i < activeMiddlePoints.length; i++) {
7320
+ const point = activeMiddlePoints[i];
7357
7321
  if (element.shape === ArrowLineShape.elbow && elbowNextRenderPoints.length) {
7358
- const handleIndex = getHitPointIndex(middlePoints, point);
7322
+ const handleIndex = getHitPointIndex(activeMiddlePoints, point);
7359
7323
  const isUpdateHandleIndex = isUpdatedHandleIndex(this.board, element, [...points], elbowNextRenderPoints, handleIndex);
7360
7324
  if (isUpdateHandleIndex) {
7361
7325
  const updateHandle = drawPrimaryHandle(this.board, point);
@@ -7369,8 +7333,9 @@ class LineActiveGenerator extends Generator {
7369
7333
  }
7370
7334
  }
7371
7335
  else {
7372
- const activeRectangle = this.board.getRectangle(element);
7373
- if (activeRectangle) {
7336
+ const rectangle = this.board.getRectangle(element);
7337
+ if (rectangle) {
7338
+ const activeRectangle = toActiveRectangleFromViewBoxRectangle(this.board, rectangle);
7374
7339
  let opacity = '0.5';
7375
7340
  if (activeRectangle.height === 0 || activeRectangle.width === 0) {
7376
7341
  opacity = '0.8';
@@ -7408,13 +7373,20 @@ class ArrowLineComponent extends CommonElementFlavour {
7408
7373
  this.initializeGenerator();
7409
7374
  this.shapeGenerator.processDrawing(this.element, this.getElementG());
7410
7375
  const linePoints = getArrowLinePoints(this.board, this.element);
7411
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7376
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7412
7377
  selected: this.selected,
7413
7378
  linePoints
7414
7379
  });
7415
7380
  super.initialize();
7416
7381
  this.boundedElements = this.getBoundedElements();
7417
7382
  this.drawText();
7383
+ this.getRef().updateActiveSection = () => {
7384
+ const linePoints = getArrowLinePoints(this.board, this.element);
7385
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7386
+ selected: this.selected,
7387
+ linePoints
7388
+ });
7389
+ };
7418
7390
  debugGenerator.isDebug() && debugGenerator.drawCircles(this.board, this.element.points.slice(1, -1), 4, true);
7419
7391
  }
7420
7392
  getBoundedElements() {
@@ -7440,7 +7412,7 @@ class ArrowLineComponent extends CommonElementFlavour {
7440
7412
  const linePoints = getArrowLinePoints(this.board, this.element);
7441
7413
  if (value.element !== previous.element || value.hasThemeChanged) {
7442
7414
  this.shapeGenerator.processDrawing(this.element, this.getElementG());
7443
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7415
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7444
7416
  selected: this.selected,
7445
7417
  linePoints
7446
7418
  });
@@ -7449,8 +7421,8 @@ class ArrowLineComponent extends CommonElementFlavour {
7449
7421
  }
7450
7422
  else {
7451
7423
  const needUpdate = value.selected !== previous.selected || this.activeGenerator.needUpdate();
7452
- if (needUpdate) {
7453
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7424
+ if (needUpdate || value.selected) {
7425
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7454
7426
  selected: this.selected,
7455
7427
  linePoints
7456
7428
  });
@@ -7458,7 +7430,7 @@ class ArrowLineComponent extends CommonElementFlavour {
7458
7430
  }
7459
7431
  if (isBoundedElementsChanged) {
7460
7432
  this.shapeGenerator.processDrawing(this.element, this.getElementG());
7461
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7433
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7462
7434
  selected: this.selected,
7463
7435
  linePoints
7464
7436
  });
@@ -7530,7 +7502,7 @@ class ArrowLineComponent extends CommonElementFlavour {
7530
7502
  }
7531
7503
  updateTextRectangle() {
7532
7504
  const textManages = this.getRef().getTextManages();
7533
- textManages.forEach(manage => {
7505
+ textManages.forEach((manage) => {
7534
7506
  manage.updateRectangle();
7535
7507
  });
7536
7508
  }
@@ -7548,12 +7520,19 @@ class VectorLineComponent extends CommonElementFlavour {
7548
7520
  initializeGenerator() {
7549
7521
  this.shapeGenerator = new VectorLineShapeGenerator(this.board);
7550
7522
  this.activeGenerator = new LineActiveGenerator(this.board);
7523
+ this.getRef().updateActiveSection = () => {
7524
+ const linePoints = getVectorLinePoints(this.board, this.element);
7525
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7526
+ selected: this.selected,
7527
+ linePoints
7528
+ });
7529
+ };
7551
7530
  }
7552
7531
  initialize() {
7553
7532
  this.initializeGenerator();
7554
7533
  this.shapeGenerator.processDrawing(this.element, this.getElementG());
7555
7534
  const linePoints = getVectorLinePoints(this.board, this.element);
7556
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7535
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7557
7536
  selected: this.selected,
7558
7537
  linePoints
7559
7538
  });
@@ -7563,15 +7542,15 @@ class VectorLineComponent extends CommonElementFlavour {
7563
7542
  const linePoints = getVectorLinePoints(this.board, this.element);
7564
7543
  if (value.element !== previous.element || value.hasThemeChanged) {
7565
7544
  this.shapeGenerator.processDrawing(this.element, this.getElementG());
7566
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7545
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7567
7546
  selected: this.selected,
7568
7547
  linePoints
7569
7548
  });
7570
7549
  }
7571
7550
  else {
7572
- const needUpdate = value.selected !== previous.selected || this.activeGenerator.needUpdate();
7551
+ const needUpdate = value.selected !== previous.selected || this.activeGenerator.needUpdate() || value.selected;
7573
7552
  if (needUpdate) {
7574
- this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
7553
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
7575
7554
  selected: this.selected,
7576
7555
  linePoints
7577
7556
  });
@@ -7681,9 +7660,9 @@ const withGeometryCreateByDrag = (board) => {
7681
7660
  if (dragMode) {
7682
7661
  const memorizedLatest = getMemorizedLatestByPointer(pointer);
7683
7662
  if (pointer === BasicShapes.text) {
7684
- const property = getTextShapeProperty(board, DefaultTextProperty.text, memorizedLatest.textProperties['font-size']);
7663
+ const property = getTextShapeProperty(board, getDefaultGeometryText(board), memorizedLatest.textProperties['font-size']);
7685
7664
  const points = RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(movingPoint, property.width, property.height));
7686
- temporaryElement = createTextElement(board, points);
7665
+ temporaryElement = createTextElement(board, points, getDefaultGeometryText(board));
7687
7666
  if (!fakeCreateTextRef) {
7688
7667
  const textManage = new TextManage(board, {
7689
7668
  getRectangle: () => {
@@ -7707,7 +7686,7 @@ const withGeometryCreateByDrag = (board) => {
7707
7686
  const points = getDefaultGeometryPoints(pointer, movingPoint);
7708
7687
  temporaryElement = createDefaultGeometry(board, points, pointer);
7709
7688
  geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
7710
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
7689
+ PlaitBoard.getElementTopHost(board).append(geometryShapeG);
7711
7690
  }
7712
7691
  }
7713
7692
  pointerMove(event);
@@ -7754,9 +7733,9 @@ const withGeometryCreateByDrawing = (board) => {
7754
7733
  const pointer = PlaitBoard.getPointer(board);
7755
7734
  if (pointer === BasicShapes.text) {
7756
7735
  const memorizedLatest = getMemorizedLatestByPointer(pointer);
7757
- const property = getTextShapeProperty(board, DefaultTextProperty.text, memorizedLatest.textProperties['font-size']);
7736
+ const property = getTextShapeProperty(board, getDefaultGeometryText(board), memorizedLatest.textProperties['font-size']);
7758
7737
  const points = RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(point, property.width, property.height));
7759
- const textElement = createTextElement(board, points);
7738
+ const textElement = createTextElement(board, points, getDefaultGeometryText(board));
7760
7739
  insertElement(board, textElement);
7761
7740
  start = null;
7762
7741
  }
@@ -7783,11 +7762,11 @@ const withGeometryCreateByDrawing = (board) => {
7783
7762
  isCreate: true
7784
7763
  });
7785
7764
  snapG = resizeSnapRef.snapG;
7786
- PlaitBoard.getElementActiveHost(board).append(snapG);
7765
+ PlaitBoard.getElementTopHost(board).append(snapG);
7787
7766
  points = normalizeShapePoints(resizeSnapRef.activePoints, isShift);
7788
7767
  temporaryElement = createDefaultGeometry(board, points, pointer);
7789
7768
  geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
7790
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
7769
+ PlaitBoard.getElementTopHost(board).append(geometryShapeG);
7791
7770
  }
7792
7771
  pointerMove(event);
7793
7772
  };
@@ -8112,7 +8091,7 @@ const withArrowLineBoundReaction = (board) => {
8112
8091
  const linePointers = Object.keys(ArrowLineShape);
8113
8092
  const isLinePointer = PlaitBoard.isInPointer(board, linePointers);
8114
8093
  const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
8115
- const isLineResizing = isResizingByCondition(board, resizeRef => {
8094
+ const isLineResizing = isResizingByCondition(board, (resizeRef) => {
8116
8095
  const { element, handle } = resizeRef;
8117
8096
  const isSourceOrTarget = handle === LineResizeHandle.target || handle === LineResizeHandle.source;
8118
8097
  return PlaitDrawElement.isArrowLine(element) && isSourceOrTarget;
@@ -8135,12 +8114,12 @@ const withArrowLineBoundReaction = (board) => {
8135
8114
  if (hasValidAngle(hitElement)) {
8136
8115
  setAngleForG(boundShapeG, RectangleClient.getCenterPointByPoints(hitElement.points), hitElement.angle);
8137
8116
  }
8138
- PlaitBoard.getElementActiveHost(board).append(boundShapeG);
8117
+ PlaitBoard.getElementTopHost(board).append(boundShapeG);
8139
8118
  }
8140
8119
  }
8141
8120
  pointerMove(event);
8142
8121
  };
8143
- board.pointerUp = event => {
8122
+ board.pointerUp = (event) => {
8144
8123
  boundShapeG?.remove();
8145
8124
  boundShapeG = null;
8146
8125
  pointerUp(event);
@@ -8148,6 +8127,9 @@ const withArrowLineBoundReaction = (board) => {
8148
8127
  return board;
8149
8128
  };
8150
8129
 
8130
+ const getDefaultLineText = (board) => {
8131
+ return getI18nValue(board, DrawI18nKey.lineText, LINE_TEXT);
8132
+ };
8151
8133
  const withArrowLineText = (board) => {
8152
8134
  const { dblClick } = board;
8153
8135
  board.dblClick = (event) => {
@@ -8165,13 +8147,19 @@ const withArrowLineText = (board) => {
8165
8147
  editHandle(board, hitTarget, textIndex);
8166
8148
  }
8167
8149
  else {
8168
- const ratio = getRatioByPoint(points, point);
8150
+ const defaultLineText = getDefaultLineText(board);
8169
8151
  const textMemory = getMemorizedLatest('arrow-line')?.text || {};
8152
+ const textElement = buildText(defaultLineText, undefined, textMemory);
8153
+ const { width, height } = measureElement(textElement, {
8154
+ fontSize: DEFAULT_FONT_SIZE,
8155
+ fontFamily: DEFAULT_FONT_FAMILY
8156
+ });
8157
+ const ratio = getRatioByPoint(points, point);
8170
8158
  texts.push({
8171
- text: buildText(LINE_TEXT, undefined, textMemory),
8159
+ text: textElement,
8172
8160
  position: ratio,
8173
- width: 28,
8174
- height: 20
8161
+ width,
8162
+ height
8175
8163
  });
8176
8164
  DrawTransforms.setArrowLineTexts(board, hitTarget, texts);
8177
8165
  setTimeout(() => {
@@ -8193,7 +8181,8 @@ function editHandle(board, element, manageIndex, isFirstEdit = false) {
8193
8181
  const textManage = textManages[manageIndex];
8194
8182
  textManage.edit(() => {
8195
8183
  const text = Node.string(textManage.getText());
8196
- const shouldRemove = !text || (isFirstEdit && text === LINE_TEXT);
8184
+ const defaultLineText = getDefaultLineText(board);
8185
+ const shouldRemove = !text || (isFirstEdit && text === defaultLineText);
8197
8186
  if (shouldRemove) {
8198
8187
  DrawTransforms.removeArrowLineText(board, element, manageIndex);
8199
8188
  }
@@ -8214,7 +8203,7 @@ class ImageComponent extends CommonElementFlavour {
8214
8203
  height: element.points[1][1] - element.points[0][1]
8215
8204
  };
8216
8205
  },
8217
- getImageItem: element => {
8206
+ getImageItem: (element) => {
8218
8207
  return {
8219
8208
  url: element.url,
8220
8209
  width: element.points[1][0] - element.points[0][0],
@@ -8224,12 +8213,18 @@ class ImageComponent extends CommonElementFlavour {
8224
8213
  });
8225
8214
  this.lineAutoCompleteGenerator = new ArrowLineAutoCompleteGenerator(this.board);
8226
8215
  this.getRef().addGenerator(ArrowLineAutoCompleteGenerator.key, this.lineAutoCompleteGenerator);
8216
+ this.getRef().updateActiveSection = () => {
8217
+ this.imageGenerator.setFocus(this.element, this.selected);
8218
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8219
+ selected: this.selected
8220
+ });
8221
+ };
8227
8222
  }
8228
8223
  initialize() {
8229
8224
  super.initialize();
8230
8225
  this.initializeGenerator();
8231
8226
  this.imageGenerator.processDrawing(this.element, this.getElementG());
8232
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
8227
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8233
8228
  selected: this.selected
8234
8229
  });
8235
8230
  }
@@ -8237,17 +8232,15 @@ class ImageComponent extends CommonElementFlavour {
8237
8232
  if (value.element !== previous.element) {
8238
8233
  this.imageGenerator.updateImage(this.getElementG(), previous.element, value.element);
8239
8234
  this.imageGenerator.setFocus(this.element, this.selected);
8240
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
8235
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8241
8236
  selected: this.selected
8242
8237
  });
8243
8238
  }
8244
8239
  else {
8245
8240
  const hasSameSelected = value.selected === previous.selected;
8246
- const hasSameHandleState = this.imageGenerator.activeGenerator &&
8247
- this.imageGenerator.activeGenerator.options.hasResizeHandle() === this.imageGenerator.activeGenerator.hasResizeHandle;
8248
- if (!hasSameSelected || !hasSameHandleState) {
8241
+ if (!hasSameSelected || value.selected) {
8249
8242
  this.imageGenerator.setFocus(this.element, this.selected);
8250
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
8243
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8251
8244
  selected: this.selected
8252
8245
  });
8253
8246
  }
@@ -8268,10 +8261,10 @@ const withArrowLineAutoCompleteReaction = (board) => {
8268
8261
  PlaitBoard.getBoardContainer(board).classList.remove(CursorClass.crosshair);
8269
8262
  const selectedElements = getSelectedDrawElements(board);
8270
8263
  const targetElement = selectedElements.length === 1 && selectedElements[0];
8271
- const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
8264
+ const activePoint = toActivePoint(board, event.x, event.y);
8272
8265
  if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
8273
- const points = getAutoCompletePoints(targetElement);
8274
- const hitIndex = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(movingPoint, targetElement) || movingPoint, points);
8266
+ const points = getAutoCompletePoints(board, targetElement, true);
8267
+ const hitIndex = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(board, activePoint, targetElement, true) || activePoint, points);
8275
8268
  const hitPoint = points[hitIndex];
8276
8269
  const ref = PlaitElement.getElementRef(targetElement);
8277
8270
  const lineAutoCompleteGenerator = ref.getGenerator(ArrowLineAutoCompleteGenerator.key);
@@ -8283,10 +8276,12 @@ const withArrowLineAutoCompleteReaction = (board) => {
8283
8276
  fill: RgbaToHEX(PRIMARY_COLOR, LINE_AUTO_COMPLETE_HOVERED_OPACITY),
8284
8277
  fillStyle: 'solid'
8285
8278
  });
8286
- PlaitBoard.getElementActiveHost(board).append(reactionG);
8279
+ PlaitBoard.getActiveHost(board).append(reactionG);
8287
8280
  PlaitBoard.getBoardContainer(board).classList.add(CursorClass.crosshair);
8288
8281
  if (hasValidAngle(targetElement)) {
8289
- setAngleForG(reactionG, RectangleClient.getCenterPoint(board.getRectangle(targetElement)), targetElement.angle);
8282
+ const rectangle = board.getRectangle(targetElement);
8283
+ const activeRectangle = toActiveRectangleFromViewBoxRectangle(board, rectangle);
8284
+ setAngleForG(reactionG, RectangleClient.getCenterPoint(activeRectangle), targetElement.angle);
8290
8285
  }
8291
8286
  }
8292
8287
  }
@@ -8305,14 +8300,15 @@ const withArrowLineAutoComplete = (board) => {
8305
8300
  board.pointerDown = (event) => {
8306
8301
  const selectedElements = getSelectedDrawElements(board);
8307
8302
  const targetElement = selectedElements.length === 1 && selectedElements[0];
8308
- const clickPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
8303
+ const activePoint = toActivePoint(board, event.x, event.y);
8309
8304
  if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.isShapeElement(targetElement)) {
8310
- const points = getAutoCompletePoints(targetElement);
8311
- const index = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(clickPoint, targetElement) || clickPoint, points);
8305
+ const points = getAutoCompletePoints(board, targetElement, true);
8306
+ const index = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(board, activePoint, targetElement, true) || activePoint, points);
8312
8307
  const hitPoint = points[index];
8313
8308
  if (hitPoint) {
8314
8309
  temporaryDisableSelection(board);
8315
- autoCompletePoint = hitPoint;
8310
+ const screenPoint = toScreenPointFromActivePoint(board, hitPoint);
8311
+ autoCompletePoint = toViewBoxPoint(board, toHostPoint(board, screenPoint[0], screenPoint[1]));
8316
8312
  sourceElement = targetElement;
8317
8313
  BoardTransforms.updatePointerType(board, ArrowLineShape.elbow);
8318
8314
  }
@@ -8324,7 +8320,7 @@ const withArrowLineAutoComplete = (board) => {
8324
8320
  lineShapeG = createG();
8325
8321
  let movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
8326
8322
  if (autoCompletePoint && sourceElement) {
8327
- const distance = distanceBetweenPointAndPoint(...(rotateAntiPointsByElement(movingPoint, sourceElement) || movingPoint), ...autoCompletePoint);
8323
+ const distance = distanceBetweenPointAndPoint(...(rotateAntiPointsByElement(board, movingPoint, sourceElement) || movingPoint), ...autoCompletePoint);
8328
8324
  if (distance > PRESS_AND_MOVE_BUFFER) {
8329
8325
  const rectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
8330
8326
  const shape = getElementShape(sourceElement);
@@ -8342,7 +8338,7 @@ const withArrowLineAutoComplete = (board) => {
8342
8338
  }
8343
8339
  pointerMove(event);
8344
8340
  };
8345
- board.globalPointerUp = event => {
8341
+ board.globalPointerUp = (event) => {
8346
8342
  if (temporaryElement) {
8347
8343
  Transforms.insertNode(board, temporaryElement, [board.children.length]);
8348
8344
  clearSelectedElement(board);
@@ -8418,7 +8414,7 @@ const withDrawRotate = (board) => {
8418
8414
  const canRotate = () => {
8419
8415
  const elements = getSelectedElements(board);
8420
8416
  return (elements.length > 0 &&
8421
- elements.every(el => (PlaitDrawElement.isDrawElement(el) && !PlaitDrawElement.isArrowLine(el)) ||
8417
+ elements.every((el) => (PlaitDrawElement.isDrawElement(el) && !PlaitDrawElement.isArrowLine(el)) ||
8422
8418
  PlaitDrawElement.isCustomGeometryElement(board, el)));
8423
8419
  };
8424
8420
  board.pointerDown = (event) => {
@@ -8426,16 +8422,17 @@ const withDrawRotate = (board) => {
8426
8422
  pointerDown(event);
8427
8423
  return;
8428
8424
  }
8429
- const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
8425
+ const activePoint = toActivePoint(board, event.x, event.y);
8430
8426
  const elements = getSelectedElements(board);
8431
- const boundingRectangle = getRectangleByElements(board, elements, false);
8432
- const handleRectangle = getRotateHandleRectangle(boundingRectangle);
8427
+ const rectangle = getRectangleByElements(board, elements, false);
8428
+ const activeRectangle = toActiveRectangleFromViewBoxRectangle(board, rectangle);
8429
+ const handleRectangle = getRotateHandleRectangle(activeRectangle);
8433
8430
  const angle = getSelectionAngle(elements);
8434
- const rotatedPoint = angle ? rotatePoints(point, RectangleClient.getCenterPoint(boundingRectangle), -angle) : point;
8431
+ const rotatedPoint = angle ? rotatePoints(activePoint, RectangleClient.getCenterPoint(activeRectangle), -angle) : activePoint;
8435
8432
  if (handleRectangle && RectangleClient.isHit(RectangleClient.getRectangleByPoints([rotatedPoint, rotatedPoint]), handleRectangle)) {
8436
8433
  rotateRef = {
8437
8434
  elements: [...elements],
8438
- startPoint: point
8435
+ startPoint: activePoint
8439
8436
  };
8440
8437
  }
8441
8438
  pointerDown(event);
@@ -8445,9 +8442,10 @@ const withDrawRotate = (board) => {
8445
8442
  event.preventDefault();
8446
8443
  const isShift = !!event.shiftKey;
8447
8444
  addRotating(board, rotateRef);
8448
- const endPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
8449
- const selectionRectangle = getRectangleByElements(board, rotateRef.elements, false);
8450
- const selectionCenterPoint = RectangleClient.getCenterPoint(selectionRectangle);
8445
+ const endPoint = toActivePoint(board, event.x, event.y);
8446
+ const rectangle = getRectangleByElements(board, rotateRef.elements, false);
8447
+ const activeRectangle = toActiveRectangleFromViewBoxRectangle(board, rectangle);
8448
+ const selectionCenterPoint = RectangleClient.getCenterPoint(activeRectangle);
8451
8449
  if (!getSelectionAngle(rotateRef.elements) && rotateRef.elements.length > 1) {
8452
8450
  needCustomActiveRectangle = true;
8453
8451
  }
@@ -8499,32 +8497,35 @@ const withDrawRotate = (board) => {
8499
8497
  if (canRotate() && !isSelectionMoving(board)) {
8500
8498
  if (needCustomActiveRectangle && rotateRef) {
8501
8499
  const boundingRectangle = getRectangleByElements(board, rotateRef.elements, false);
8502
- rotateHandleG = drawRotateHandle(board, boundingRectangle);
8500
+ const boundingActiveRectangle = toActiveRectangleFromViewBoxRectangle(board, boundingRectangle);
8501
+ rotateHandleG = drawRotateHandle(board, boundingActiveRectangle);
8503
8502
  rotateHandleG.classList.add(ROTATE_HANDLE_CLASS_NAME);
8504
8503
  if (rotateRef.angle) {
8505
- setAngleForG(rotateHandleG, RectangleClient.getCenterPoint(boundingRectangle), rotateRef.angle);
8504
+ setAngleForG(rotateHandleG, RectangleClient.getCenterPoint(boundingActiveRectangle), rotateRef.angle);
8506
8505
  }
8507
8506
  }
8508
8507
  else {
8509
8508
  const elements = getSelectedElements(board);
8510
8509
  const boundingRectangle = getRectangleByElements(board, elements, false);
8511
- rotateHandleG = drawRotateHandle(board, boundingRectangle);
8510
+ const boundingActiveRectangle = toActiveRectangleFromViewBoxRectangle(board, boundingRectangle);
8511
+ rotateHandleG = drawRotateHandle(board, boundingActiveRectangle);
8512
8512
  rotateHandleG.classList.add(ROTATE_HANDLE_CLASS_NAME);
8513
- setAngleForG(rotateHandleG, RectangleClient.getCenterPoint(boundingRectangle), getSelectionAngle(elements));
8513
+ setAngleForG(rotateHandleG, RectangleClient.getCenterPoint(boundingActiveRectangle), getSelectionAngle(elements));
8514
8514
  }
8515
- PlaitBoard.getElementActiveHost(board).append(rotateHandleG);
8515
+ PlaitBoard.getActiveHost(board).append(rotateHandleG);
8516
8516
  }
8517
8517
  };
8518
8518
  board.drawSelectionRectangle = () => {
8519
8519
  if (needCustomActiveRectangle && rotateRef) {
8520
8520
  const rectangle = getRectangleByElements(board, rotateRef.elements, false);
8521
- const rectangleG = drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
8521
+ const activeRectangle = toActiveRectangleFromViewBoxRectangle(board, rectangle);
8522
+ const rectangleG = drawRectangle(board, RectangleClient.inflate(activeRectangle, ACTIVE_STROKE_WIDTH), {
8522
8523
  stroke: SELECTION_BORDER_COLOR,
8523
8524
  strokeWidth: ACTIVE_STROKE_WIDTH
8524
8525
  });
8525
8526
  rectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
8526
8527
  if (rotateRef.angle) {
8527
- setAngleForG(rectangleG, RectangleClient.getCenterPoint(rectangle), rotateRef.angle);
8528
+ setAngleForG(rectangleG, RectangleClient.getCenterPoint(activeRectangle), rotateRef.angle);
8528
8529
  }
8529
8530
  return rectangleG;
8530
8531
  }
@@ -8538,7 +8539,7 @@ class TableComponent extends CommonElementFlavour {
8538
8539
  super();
8539
8540
  }
8540
8541
  initializeGenerator() {
8541
- this.activeGenerator = new ActiveGenerator(this.board, {
8542
+ this.activeGenerator = createActiveGenerator(this.board, {
8542
8543
  getStrokeWidth: () => {
8543
8544
  return ACTIVE_STROKE_WIDTH;
8544
8545
  },
@@ -8564,6 +8565,14 @@ class TableComponent extends CommonElementFlavour {
8564
8565
  this.initializeTextManage();
8565
8566
  this.lineAutoCompleteGenerator = new ArrowLineAutoCompleteGenerator(this.board);
8566
8567
  this.getRef().addGenerator(ArrowLineAutoCompleteGenerator.key, this.lineAutoCompleteGenerator);
8568
+ this.getRef().updateActiveSection = () => {
8569
+ this.activeGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8570
+ selected: this.selected
8571
+ });
8572
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8573
+ selected: this.selected
8574
+ });
8575
+ };
8567
8576
  }
8568
8577
  initialize() {
8569
8578
  super.initialize();
@@ -8574,13 +8583,13 @@ class TableComponent extends CommonElementFlavour {
8574
8583
  this.tableGenerator.processDrawing(this.element, this.getElementG());
8575
8584
  this.textGenerator.draw(this.getElementG());
8576
8585
  this.rotateVerticalText();
8577
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
8586
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8578
8587
  selected: this.selected
8579
8588
  });
8580
8589
  }
8581
8590
  rotateVerticalText() {
8582
8591
  const table = this.board.buildTable(this.element);
8583
- table.cells.forEach(item => {
8592
+ table.cells.forEach((item) => {
8584
8593
  if (PlaitTableElement.isVerticalText(item)) {
8585
8594
  const textManage = getTextManageByCell(this.board, item);
8586
8595
  if (textManage) {
@@ -8594,8 +8603,8 @@ class TableComponent extends CommonElementFlavour {
8594
8603
  }
8595
8604
  getDrawShapeTexts(cells) {
8596
8605
  return cells
8597
- .filter(item => isCellIncludeText(item))
8598
- .map(item => {
8606
+ .filter((item) => isCellIncludeText(item))
8607
+ .map((item) => {
8599
8608
  return {
8600
8609
  id: item.id,
8601
8610
  text: item.text,
@@ -8643,7 +8652,7 @@ class TableComponent extends CommonElementFlavour {
8643
8652
  setSelectedCells(value.element, previousSelectedCells);
8644
8653
  }
8645
8654
  this.tableGenerator.processDrawing(value.element, this.getElementG());
8646
- this.activeGenerator.processDrawing(value.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
8655
+ this.activeGenerator.processDrawing(value.element, PlaitBoard.getActiveHost(this.board), { selected: this.selected });
8647
8656
  const previousTexts = this.getDrawShapeTexts(previous.element.cells);
8648
8657
  const currentTexts = this.getDrawShapeTexts(value.element.cells);
8649
8658
  this.textGenerator.update(value.element, previousTexts, currentTexts, this.getElementG());
@@ -8651,10 +8660,9 @@ class TableComponent extends CommonElementFlavour {
8651
8660
  }
8652
8661
  else {
8653
8662
  const hasSameSelected = value.selected === previous.selected;
8654
- const hasSameHandleState = this.activeGenerator.options.hasResizeHandle() === this.activeGenerator.hasResizeHandle;
8655
8663
  const currentSelectedCells = getSelectedCells(value.element);
8656
- if (!hasSameSelected || !hasSameHandleState || currentSelectedCells?.length) {
8657
- this.activeGenerator.processDrawing(value.element, PlaitBoard.getElementActiveHost(this.board), {
8664
+ if (!hasSameSelected || currentSelectedCells?.length || value.selected) {
8665
+ this.activeGenerator.processDrawing(value.element, PlaitBoard.getActiveHost(this.board), {
8658
8666
  selected: this.selected
8659
8667
  });
8660
8668
  }
@@ -8662,7 +8670,7 @@ class TableComponent extends CommonElementFlavour {
8662
8670
  clearSelectedCells(value.element);
8663
8671
  }
8664
8672
  }
8665
- this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
8673
+ this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getActiveHost(this.board), {
8666
8674
  selected: this.selected
8667
8675
  });
8668
8676
  }
@@ -8681,17 +8689,21 @@ function withTableResize(board) {
8681
8689
  const options = {
8682
8690
  key: 'draw-table',
8683
8691
  canResize: () => {
8684
- return true;
8692
+ const selectedElements = getSelectedElements(board);
8693
+ return isSingleSelectTable(board) && !hasValidAngle(selectedElements[0]);
8685
8694
  },
8686
8695
  hitTest: (point) => {
8687
- const hitElement = getHitElementByPoint(board, point);
8696
+ const selectedElements = getSelectedElements(board);
8697
+ const hitElement = selectedElements[0];
8698
+ // debugGenerator.clear();
8688
8699
  if (hitElement && PlaitDrawElement.isElementByTable(hitElement)) {
8689
8700
  let rectangle = board.getRectangle(hitElement);
8701
+ // debugGenerator.drawRectangle(board, rectangle);
8702
+ // debugGenerator.drawCircles(board, [point], 5);
8690
8703
  let handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, hitElement.angle);
8691
8704
  if (handleRef) {
8692
8705
  const selectElement = isSelectedElement(board, hitElement);
8693
- if ((selectElement && isSingleSelectElementByTable(board)) ||
8694
- (!selectElement && !isCornerHandle(board, handleRef.handle))) {
8706
+ if ((selectElement && isSingleSelectTable(board)) || (!selectElement && !isCornerHandle(board, handleRef.handle))) {
8695
8707
  return {
8696
8708
  element: hitElement,
8697
8709
  handle: handleRef.handle,
@@ -8728,7 +8740,7 @@ function withTableResize(board) {
8728
8740
  const resizePoints = [resizeState.startPoint, resizeState.endPoint];
8729
8741
  const { xZoom, yZoom } = getResizeZoom(resizePoints, originPoint, handlePoint, false, false);
8730
8742
  const originPoints = resizeRef.options?.cell.points;
8731
- const targetPoints = originPoints.map(p => {
8743
+ const targetPoints = originPoints.map((p) => {
8732
8744
  return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
8733
8745
  });
8734
8746
  const offsetX = targetPoints[1][0] - originPoints[1][0];
@@ -8755,7 +8767,7 @@ function withTableResize(board) {
8755
8767
  }, isAspectRatio, isFromCorner);
8756
8768
  const resizeSnapRef = getSnapResizingRef(board, [resizeRef.element], resizeSnapRefOptions);
8757
8769
  snapG = resizeSnapRef.snapG;
8758
- PlaitBoard.getElementActiveHost(board).append(snapG);
8770
+ PlaitBoard.getElementTopHost(board).append(snapG);
8759
8771
  const points = resizeSnapRef.activePoints;
8760
8772
  const originPoints = resizeRef.element.points;
8761
8773
  const originRect = RectangleClient.getRectangleByPoints(originPoints);
@@ -8765,7 +8777,7 @@ function withTableResize(board) {
8765
8777
  let columns = [...resizeRef.element.columns];
8766
8778
  let rows = [...resizeRef.element.rows];
8767
8779
  if (offsetWidth !== 0) {
8768
- columns = columns.map(item => {
8780
+ columns = columns.map((item) => {
8769
8781
  if (item.width) {
8770
8782
  return {
8771
8783
  ...item,
@@ -8776,7 +8788,7 @@ function withTableResize(board) {
8776
8788
  });
8777
8789
  }
8778
8790
  if (offsetHeight !== 0) {
8779
- rows = rows.map(item => {
8791
+ rows = rows.map((item) => {
8780
8792
  if (item.height) {
8781
8793
  return {
8782
8794
  ...item,
@@ -8810,7 +8822,9 @@ const withTable = (board) => {
8810
8822
  tableBoard.isHit = (element, point, isStrict) => {
8811
8823
  if (PlaitDrawElement.isElementByTable(element)) {
8812
8824
  const client = RectangleClient.getRectangleByPoints(element.points);
8813
- return RectangleClient.isPointInRectangle(client, point);
8825
+ const nearestPoint = TableEngine.getNearestPoint(client, point);
8826
+ const distance = distanceBetweenPointAndPoint(nearestPoint[0], nearestPoint[1], point[0], point[1]);
8827
+ return distance <= HIT_DISTANCE_BUFFER || RectangleClient.isPointInRectangle(client, point);
8814
8828
  }
8815
8829
  return isHit(element, point, isStrict);
8816
8830
  };
@@ -8847,9 +8861,9 @@ const withTable = (board) => {
8847
8861
  event.preventDefault();
8848
8862
  if (PlaitDrawElement.isElementByTable(targetElement)) {
8849
8863
  const cells = getSelectedCells(targetElement);
8850
- let cell = targetElement.cells.find(item => item.text && item.textHeight);
8864
+ let cell = targetElement.cells.find((item) => item.text && item.textHeight);
8851
8865
  if (cells?.length) {
8852
- cell = cells.find(item => item.text && item.textHeight);
8866
+ cell = cells.find((item) => item.text && item.textHeight);
8853
8867
  }
8854
8868
  if (cell) {
8855
8869
  editCell(board, cell);
@@ -8922,7 +8936,7 @@ const withSwimlaneCreateByDrag = (board) => {
8922
8936
  const points = getDefaultSwimlanePoints(pointer, movingPoint);
8923
8937
  temporaryElement = createDefaultSwimlane(pointer, points);
8924
8938
  tableGenerator.processDrawing(temporaryElement, swimlaneG);
8925
- PlaitBoard.getElementActiveHost(board).append(swimlaneG);
8939
+ PlaitBoard.getElementTopHost(board).append(swimlaneG);
8926
8940
  }
8927
8941
  pointerMove(event);
8928
8942
  };
@@ -8985,11 +8999,11 @@ const withSwimlaneCreateByDrawing = (board) => {
8985
8999
  isCreate: true
8986
9000
  });
8987
9001
  snapG = resizeSnapRef.snapG;
8988
- PlaitBoard.getElementActiveHost(board).append(snapG);
9002
+ PlaitBoard.getElementTopHost(board).append(snapG);
8989
9003
  points = normalizeShapePoints(resizeSnapRef.activePoints, isShift);
8990
9004
  temporaryElement = createDefaultSwimlane(pointer, points);
8991
9005
  tableGenerator.processDrawing(temporaryElement, swimlaneG);
8992
- PlaitBoard.getElementActiveHost(board).append(swimlaneG);
9006
+ PlaitBoard.getElementTopHost(board).append(swimlaneG);
8993
9007
  }
8994
9008
  pointerMove(event);
8995
9009
  };
@@ -9291,5 +9305,5 @@ const withDraw = (board) => {
9291
9305
  * Generated bundle index. Do not edit.
9292
9306
  */
9293
9307
 
9294
- export { ArrowLineAutoCompleteGenerator, ArrowLineComponent, ArrowLineHandleKey, ArrowLineMarkerType, ArrowLineShape, BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultActivationProperty, DefaultActorProperty, DefaultArrowProperty, DefaultAssemblyProperty, DefaultBasicShapeProperty, DefaultBasicShapePropertyMap, DefaultClassProperty, DefaultCloudProperty, DefaultCombinedFragmentProperty, DefaultComponentBoxProperty, DefaultConnectorProperty, DefaultContainerProperty, DefaultDataBaseProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultDeletionProperty, DefaultDocumentProperty, DefaultDrawActiveStyle, DefaultDrawStyle, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultInterfaceProperty, DefaultInternalStorageProperty, DefaultManualInputProperty, DefaultMergeProperty, DefaultMultiDocumentProperty, DefaultNoteProperty, DefaultObjectProperty, DefaultPackageProperty, DefaultPentagonArrowProperty, DefaultPortProperty, DefaultProvidedInterfaceProperty, DefaultRequiredInterfaceProperty, DefaultSwimlaneHorizontalProperty, DefaultSwimlaneHorizontalWithHeaderProperty, DefaultSwimlanePropertyMap, DefaultSwimlaneVerticalProperty, DefaultSwimlaneVerticalWithHeaderProperty, DefaultTextProperty, DefaultTwoWayArrowProperty, DefaultUMLPropertyMap, DrawThemeColors, DrawTransforms, FlowchartSymbols, GEOMETRY_NOT_CLOSED, GEOMETRY_WITHOUT_TEXT, GEOMETRY_WITH_MULTIPLE_TEXT, GeometryCommonTextKeys, GeometryComponent, GeometryShapeGenerator, GeometryThreshold, KEY_TO_TEXT_MANAGE, LINE_HIT_GEOMETRY_BUFFER, LINE_SNAPPING_BUFFER, LINE_SNAPPING_CONNECTOR_BUFFER, LineActiveGenerator, MIN_TEXT_WIDTH, MemorizeKey, MultipleTextGeometryTextKeys, PlaitArrowLine, PlaitDrawElement, PlaitGeometry, PlaitTableElement, Q2C, SELECTED_CELLS, SWIMLANE_HEADER_SIZE, ShapeDefaultSpace, SingleTextGenerator, SwimlaneDrawSymbols, SwimlaneSymbols, TableGenerator, TableSymbols, TextGenerator, UMLSymbols, VectorLineComponent, VectorLinePointerType, VectorLineShape, WithArrowLineAutoCompletePluginKey, WithDrawPluginKey, adjustSwimlaneShape, alignElbowSegment, alignPoints, buildClipboardData, buildDefaultTextsByShape, buildSwimlaneTable, clearSelectedCells, collectArrowLineUpdatedRefsByGeometry, createArrowLineElement, createCell, createDefaultCells, createDefaultFlowchart, createDefaultGeometry, createDefaultRowsOrColumns, createDefaultSwimlane, createGeometryElement, createGeometryElementWithText, createGeometryElementWithoutText, createMultipleTextGeometryElement, createTextElement, createUMLClassOrInterfaceGeometryElement, createVectorLineElement, debugGenerator$1 as debugGenerator, deleteTextManage, drawArrowLine, drawArrowLineArrow, drawBoundReaction, drawGeometry, drawShape, drawVectorLine, editCell, editText, getArrowLineHandleRefPair, getArrowLinePointers, getArrowLinePoints, getArrowLineTextRectangle, getArrowLines, getAutoCompletePoints, getBasicPointers, getCellWithPoints, getCellsRectangle, getCellsWithPoints, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultBasicShapeProperty, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultSwimlanePoints, getDefaultTextPoints, getDefaultUMLProperty, getDrawDefaultStrokeColor, getElbowLineRouteOptions, getElbowPoints, getFillByElement, getFirstFilledDrawElement, getFirstTextOrLineElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryAlign, getGeometryPointers, getHitCell, getHitConnection, getHitConnectorPoint, getHitDrawElement, getHitIndexOfAutoCompletePoint, getHitMultipleGeometryText, getHitShape, getIndexAndDeleteCountByKeyPoint, getLineMemorizedLatest, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getMidKeyPoints, getMiddlePoints, getMirrorDataPoints, getMultipleTextGeometryTextKeys, getNearestPoint, getNextRenderPoints, getNextSourceAndTargetPoints, getResizedPreviousAndNextPoint, getSelectedArrowLineElements, getSelectedCells, getSelectedCustomGeometryElements, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedSwimlane, getSelectedTableCellsEditor, getSelectedTableElements, getSelectedVectorLineElements, getSnapResizingRef, getSnapResizingRefOptions, getSnappingRef, getSnappingShape, getSourceAndTargetRectangle, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getSwimlaneCount, getSwimlanePointers, getTextKey, getTextManage, getTextManageByCell, getTextRectangle, getTextShapeProperty, getUMLPointers, getVectorByConnection, getVectorLinePointers, getVectorLinePoints, handleArrowLineCreating, hasIllegalElbowPoint, insertClipboardData, insertElement, isCellIncludeText, isClosedCustomGeometry, isClosedDrawElement, isClosedPoints, isDrawElementIncludeText, isDrawElementsIncludeText, isEmptyTextElement, isFilledDrawElement, isGeometryClosed, isGeometryIncludeText, isHitArrowLine, isHitArrowLineText, isHitDrawElement, isHitEdgeOfShape, isHitElementInside, isHitElementText, isHitPolyLine, isHitVectorLine, isInsideOfShape, isMultipleTextGeometry, isMultipleTextShape, isRectangleHitDrawElement, isRectangleHitElementText, isRectangleHitRotatedElement, isRectangleHitRotatedPoints, isSelfLoop, isSingleSelectElementByTable, isSingleSelectLine, isSingleSelectSwimlane, isSingleSelectTable, isSingleTextGeometry, isSingleTextShape, isSwimlanePointers, isSwimlaneWithHeader, isTextExceedingBounds, isUpdatedHandleIndex, isUseDefaultOrthogonalRoute, memorizeLatestShape, memorizeLatestText, rerenderGeometryActive, setSelectedCells, setTextManage, traverseDrawShapes, updateCellIds, updateCellIdsByRowOrColumn, updateColumns, updateRowOrColumnIds, updateRows, vectorLineCreating, withArrowLineAutoComplete, withDraw };
9308
+ export { ArrowLineAutoCompleteGenerator, ArrowLineComponent, ArrowLineHandleKey, ArrowLineMarkerType, ArrowLineShape, BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultActivationProperty, DefaultActorProperty, DefaultArrowProperty, DefaultAssemblyProperty, DefaultBasicShapeProperty, DefaultBasicShapePropertyMap, DefaultClassProperty, DefaultCloudProperty, DefaultCombinedFragmentProperty, DefaultComponentBoxProperty, DefaultConnectorProperty, DefaultContainerProperty, DefaultDataBaseProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultDeletionProperty, DefaultDocumentProperty, DefaultDrawActiveStyle, DefaultDrawStyle, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultInterfaceProperty, DefaultInternalStorageProperty, DefaultLineStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultMultiDocumentProperty, DefaultNoteProperty, DefaultObjectProperty, DefaultPackageProperty, DefaultPentagonArrowProperty, DefaultPortProperty, DefaultProvidedInterfaceProperty, DefaultRequiredInterfaceProperty, DefaultSwimlaneHorizontalProperty, DefaultSwimlaneHorizontalWithHeaderProperty, DefaultSwimlanePropertyMap, DefaultSwimlaneVerticalProperty, DefaultSwimlaneVerticalWithHeaderProperty, DefaultTextProperty, DefaultTwoWayArrowProperty, DefaultUMLPropertyMap, DrawI18nKey, DrawThemeColors, DrawTransforms, FlowchartSymbols, GEOMETRY_NOT_CLOSED, GEOMETRY_WITHOUT_TEXT, GEOMETRY_WITH_MULTIPLE_TEXT, GeometryCommonTextKeys, GeometryComponent, GeometryShapeGenerator, GeometryThreshold, KEY_TO_TEXT_MANAGE, LINE_ALIGN_TOLERANCE, LINE_AUTO_COMPLETE_DIAMETER, LINE_AUTO_COMPLETE_HOVERED_DIAMETER, LINE_AUTO_COMPLETE_HOVERED_OPACITY, LINE_AUTO_COMPLETE_OPACITY, LINE_HIT_GEOMETRY_BUFFER, LINE_SNAPPING_BUFFER, LINE_SNAPPING_CONNECTOR_BUFFER, LINE_TEXT, LINE_TEXT_SPACE, LineActiveGenerator, MIN_TEXT_WIDTH, MemorizeKey, MultipleTextGeometryTextKeys, PlaitArrowLine, PlaitDrawElement, PlaitGeometry, PlaitTableElement, Q2C, SELECTED_CELLS, SWIMLANE_HEADER_SIZE, ShapeDefaultSpace, SingleTextGenerator, SwimlaneDrawSymbols, SwimlaneSymbols, TableGenerator, TableSymbols, TextGenerator, UMLSymbols, VectorLineComponent, VectorLinePointerType, VectorLineShape, WithArrowLineAutoCompletePluginKey, WithDrawPluginKey, adjustSwimlaneShape, alignElbowSegment, alignPoints, buildClipboardData, buildDefaultTextsByShape, buildSwimlaneTable, clearSelectedCells, collectArrowLineUpdatedRefsByGeometry, createArrowLineElement, createCell, createDefaultCells, createDefaultGeometry, createDefaultRowsOrColumns, createDefaultSwimlane, createGeometryElement, createGeometryElementWithText, createGeometryElementWithoutText, createMultipleTextGeometryElement, createTextElement, createUMLClassOrInterfaceGeometryElement, createVectorLineElement, debugGenerator$1 as debugGenerator, deleteTextManage, drawArrowLine, drawArrowLineArrow, drawBoundReaction, drawGeometry, drawShape, drawVectorLine, editCell, editText, getArrowLineHandleRefPair, getArrowLinePointers, getArrowLinePoints, getArrowLineTextRectangle, getArrowLines, getAutoCompletePoints, getBasicPointers, getCellWithPoints, getCellsRectangle, getCellsWithPoints, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultBasicShapeProperty, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultGeometryText, getDefaultSwimlanePoints, getDefaultTextPoints, getDefaultUMLProperty, getDrawDefaultStrokeColor, getElbowLineRouteOptions, getElbowPoints, getFillByElement, getFirstFilledDrawElement, getFirstTextOrLineElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryAlign, getGeometryPointers, getHitCell, getHitConnection, getHitConnectorPoint, getHitDrawElement, getHitIndexOfAutoCompletePoint, getHitMultipleGeometryText, getHitShape, getIndexAndDeleteCountByKeyPoint, getLineMemorizedLatest, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getMidKeyPoints, getMiddlePoints, getMirrorDataPoints, getMultipleTextGeometryTextKeys, getNearestPoint, getNextRenderPoints, getNextSourceAndTargetPoints, getResizedPreviousAndNextPoint, getSelectedArrowLineElements, getSelectedCells, getSelectedCustomGeometryElements, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedSwimlane, getSelectedTableCellsEditor, getSelectedTableElements, getSelectedVectorLineElements, getSnapResizingRef, getSnapResizingRefOptions, getSnappingRef, getSnappingShape, getSourceAndTargetRectangle, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getSwimlaneCount, getSwimlanePointers, getTextKey, getTextManage, getTextManageByCell, getTextRectangle, getTextShapeProperty, getUMLPointers, getVectorByConnection, getVectorLinePointers, getVectorLinePoints, handleArrowLineCreating, hasIllegalElbowPoint, insertClipboardData, insertElement, isCellIncludeText, isClosedCustomGeometry, isClosedDrawElement, isClosedPoints, isDrawElementIncludeText, isDrawElementsIncludeText, isEmptyTextElement, isFilledDrawElement, isGeometryClosed, isGeometryIncludeText, isHitArrowLine, isHitArrowLineText, isHitDrawElement, isHitEdgeOfShape, isHitElementInside, isHitElementText, isHitPolyLine, isHitVectorLine, isInsideOfShape, isMultipleTextGeometry, isMultipleTextShape, isRectangleHitDrawElement, isRectangleHitElementText, isRectangleHitRotatedElement, isRectangleHitRotatedPoints, isSelfLoop, isSingleSelectLine, isSingleSelectSwimlane, isSingleSelectTable, isSingleTextGeometry, isSingleTextShape, isSwimlanePointers, isSwimlaneWithHeader, isTextExceedingBounds, isUpdatedHandleIndex, isUseDefaultOrthogonalRoute, memorizeLatestShape, memorizeLatestText, setSelectedCells, setTextManage, traverseDrawShapes, updateCellIds, updateCellIdsByRowOrColumn, updateColumns, updateRowOrColumnIds, updateRows, vectorLineCreating, withArrowLineAutoComplete, withDraw };
9295
9309
  //# sourceMappingURL=plait-draw.mjs.map