@plait/draw 0.1.0-next.9 → 0.29.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 (128) hide show
  1. package/constants/geometry.d.ts +71 -1
  2. package/constants/image.d.ts +1 -0
  3. package/constants/index.d.ts +1 -0
  4. package/constants/pointer.d.ts +6 -10
  5. package/engines/basic-shapes/comment.d.ts +4 -0
  6. package/engines/basic-shapes/cross.d.ts +4 -0
  7. package/engines/basic-shapes/ellipse.d.ts +13 -0
  8. package/engines/basic-shapes/hexagon.d.ts +4 -0
  9. package/engines/basic-shapes/left-arrow.d.ts +4 -0
  10. package/engines/basic-shapes/octagon.d.ts +4 -0
  11. package/engines/basic-shapes/pentagon-arrow.d.ts +4 -0
  12. package/engines/basic-shapes/pentagon.d.ts +4 -0
  13. package/engines/basic-shapes/polygon.d.ts +8 -0
  14. package/engines/basic-shapes/process-arrow.d.ts +4 -0
  15. package/engines/basic-shapes/right-arrow.d.ts +4 -0
  16. package/engines/basic-shapes/round-comment.d.ts +4 -0
  17. package/engines/basic-shapes/star.d.ts +4 -0
  18. package/engines/basic-shapes/trapezoid.d.ts +4 -0
  19. package/engines/basic-shapes/triangle.d.ts +4 -0
  20. package/engines/basic-shapes/two-way-arrow.d.ts +4 -0
  21. package/engines/flowchart/delay.d.ts +2 -0
  22. package/engines/flowchart/manual-input.d.ts +4 -0
  23. package/engines/flowchart/manual-loop.d.ts +4 -0
  24. package/engines/flowchart/merge.d.ts +4 -0
  25. package/engines/flowchart/preparation.d.ts +4 -0
  26. package/engines/flowchart/stored-data.d.ts +2 -0
  27. package/engines/flowchart/terminal.d.ts +5 -0
  28. package/engines/index.d.ts +3 -0
  29. package/esm2022/constants/geometry.mjs +42 -4
  30. package/esm2022/constants/image.mjs +2 -0
  31. package/esm2022/constants/index.mjs +2 -1
  32. package/esm2022/constants/pointer.mjs +14 -19
  33. package/esm2022/engines/basic-shapes/comment.mjs +57 -0
  34. package/esm2022/engines/basic-shapes/cross.mjs +33 -0
  35. package/esm2022/engines/basic-shapes/diamond.mjs +16 -0
  36. package/esm2022/engines/basic-shapes/ellipse.mjs +100 -0
  37. package/esm2022/engines/basic-shapes/hexagon.mjs +27 -0
  38. package/esm2022/engines/basic-shapes/left-arrow.mjs +30 -0
  39. package/esm2022/engines/basic-shapes/octagon.mjs +29 -0
  40. package/esm2022/engines/basic-shapes/parallelogram.mjs +25 -0
  41. package/esm2022/engines/basic-shapes/pentagon-arrow.mjs +24 -0
  42. package/esm2022/engines/basic-shapes/pentagon.mjs +30 -0
  43. package/esm2022/engines/basic-shapes/polygon.mjs +40 -0
  44. package/esm2022/engines/basic-shapes/process-arrow.mjs +26 -0
  45. package/esm2022/engines/basic-shapes/rectangle.mjs +26 -0
  46. package/esm2022/engines/basic-shapes/right-arrow.mjs +28 -0
  47. package/esm2022/engines/basic-shapes/round-comment.mjs +81 -0
  48. package/esm2022/engines/basic-shapes/round-rectangle.mjs +59 -0
  49. package/esm2022/engines/basic-shapes/star.mjs +39 -0
  50. package/esm2022/engines/basic-shapes/trapezoid.mjs +25 -0
  51. package/esm2022/engines/basic-shapes/triangle.mjs +33 -0
  52. package/esm2022/engines/basic-shapes/two-way-arrow.mjs +25 -0
  53. package/esm2022/engines/flowchart/delay.mjs +45 -0
  54. package/esm2022/engines/flowchart/manual-input.mjs +32 -0
  55. package/esm2022/engines/flowchart/manual-loop.mjs +25 -0
  56. package/esm2022/engines/flowchart/merge.mjs +34 -0
  57. package/esm2022/engines/flowchart/preparation.mjs +27 -0
  58. package/esm2022/engines/flowchart/stored-data.mjs +74 -0
  59. package/esm2022/engines/flowchart/terminal.mjs +59 -0
  60. package/esm2022/engines/index.mjs +64 -0
  61. package/esm2022/generators/geometry-shape.generator.mjs +9 -4
  62. package/esm2022/generators/line-active.generator.mjs +71 -22
  63. package/esm2022/generators/line.generator.mjs +2 -11
  64. package/esm2022/geometry.component.mjs +20 -10
  65. package/esm2022/image.component.mjs +70 -0
  66. package/esm2022/interfaces/geometry.mjs +38 -10
  67. package/esm2022/interfaces/image.mjs +2 -0
  68. package/esm2022/interfaces/index.mjs +16 -4
  69. package/esm2022/interfaces/line.mjs +27 -4
  70. package/esm2022/interfaces/text.mjs +1 -1
  71. package/esm2022/line.component.mjs +17 -8
  72. package/esm2022/plugins/with-draw-fragment.mjs +37 -7
  73. package/esm2022/plugins/with-draw.mjs +38 -10
  74. package/esm2022/plugins/with-geometry-create.mjs +38 -23
  75. package/esm2022/plugins/with-geometry-resize.mjs +28 -20
  76. package/esm2022/plugins/with-line-bound-reaction.mjs +10 -5
  77. package/esm2022/plugins/with-line-create.mjs +7 -5
  78. package/esm2022/plugins/with-line-resize.mjs +12 -4
  79. package/esm2022/transforms/geometry-text.mjs +1 -1
  80. package/esm2022/transforms/geometry.mjs +6 -6
  81. package/esm2022/transforms/image.mjs +23 -0
  82. package/esm2022/transforms/index.mjs +4 -2
  83. package/esm2022/utils/clipboard.mjs +4 -3
  84. package/esm2022/utils/geometry.mjs +32 -10
  85. package/esm2022/utils/index.mjs +1 -1
  86. package/esm2022/utils/line-arrow.mjs +43 -18
  87. package/esm2022/utils/line.mjs +202 -51
  88. package/esm2022/utils/position/geometry.mjs +5 -4
  89. package/esm2022/utils/position/line.mjs +32 -22
  90. package/esm2022/utils/selected.mjs +5 -1
  91. package/esm2022/utils/shape.mjs +8 -0
  92. package/fesm2022/plait-draw.mjs +1704 -331
  93. package/fesm2022/plait-draw.mjs.map +1 -1
  94. package/generators/line-active.generator.d.ts +3 -0
  95. package/generators/line.generator.d.ts +1 -1
  96. package/geometry.component.d.ts +1 -1
  97. package/image.component.d.ts +20 -0
  98. package/interfaces/geometry.d.ts +39 -7
  99. package/interfaces/image.d.ts +7 -0
  100. package/interfaces/index.d.ts +7 -1
  101. package/interfaces/line.d.ts +19 -5
  102. package/interfaces/text.d.ts +2 -2
  103. package/line.component.d.ts +2 -1
  104. package/package.json +3 -2
  105. package/plugins/with-draw-fragment.d.ts +2 -0
  106. package/plugins/with-geometry-create.d.ts +6 -1
  107. package/styles/styles.scss +2 -2
  108. package/transforms/geometry.d.ts +2 -2
  109. package/transforms/image.d.ts +3 -0
  110. package/transforms/index.d.ts +2 -1
  111. package/utils/geometry.d.ts +23 -3
  112. package/utils/line.d.ts +14 -6
  113. package/utils/position/geometry.d.ts +2 -1
  114. package/utils/position/line.d.ts +7 -3
  115. package/utils/selected.d.ts +2 -0
  116. package/utils/shape.d.ts +2 -0
  117. package/esm2022/utils/engine/diamond.mjs +0 -22
  118. package/esm2022/utils/engine/ellipse.mjs +0 -55
  119. package/esm2022/utils/engine/index.mjs +0 -18
  120. package/esm2022/utils/engine/parallelogram.mjs +0 -32
  121. package/esm2022/utils/engine/rectangle.mjs +0 -18
  122. package/esm2022/utils/engine/round-rectangle.mjs +0 -49
  123. package/utils/engine/ellipse.d.ts +0 -4
  124. package/utils/engine/index.d.ts +0 -3
  125. package/{utils/engine → engines/basic-shapes}/diamond.d.ts +0 -0
  126. package/{utils/engine → engines/basic-shapes}/parallelogram.d.ts +1 -1
  127. /package/{utils/engine → engines/basic-shapes}/rectangle.d.ts +0 -0
  128. /package/{utils/engine → engines/basic-shapes}/round-rectangle.d.ts +0 -0
@@ -1,21 +1,50 @@
1
- import { PlaitElement, ACTIVE_STROKE_WIDTH, RectangleClient, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, arrowPoints, createPath, drawLinearPath, distanceBetweenPointAndSegments, createMask, createRect, getElementById, findElements, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, isSelectionMoving, PlaitPluginElementComponent, transformPoint, toPoint, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElements, isPolylineHitRectangle } from '@plait/core';
1
+ import { PlaitElement, ACTIVE_STROKE_WIDTH, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, RectangleClient, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegment, arrowPoints, createPath, drawLinearPath, rotate, getElementById, distanceBetweenPointAndPoint, distanceBetweenPointAndSegments, createMask, createRect, findElements, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, BOARD_TO_HOST, transformPoint, toPoint, isSelectionMoving, PlaitPluginElementComponent, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElements, isPolylineHitRectangle } from '@plait/core';
2
+ import { getRectangleByPoints, getFactorByPoints, getDirectionByVector, getOppositeDirection, getDirectionFactor, getPoints, getPointByVector, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVectorAnti90, Generator, normalizeShapePoints, CommonPluginElement, ActiveGenerator, WithTextPluginKey, RESIZE_HANDLE_DIAMETER, PRIMARY_COLOR, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, acceptImageTypes, buildImage, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint, ImageGenerator } from '@plait/common';
3
+ import { Alignment, buildText, AlignEditor, TextManage, DEFAULT_FONT_SIZE, getTextFromClipboard, getTextSize } from '@plait/text';
4
+ import { pointsOnBezierCurves } from 'points-on-curve';
2
5
  import * as i0 from '@angular/core';
3
6
  import { Component, ChangeDetectionStrategy } from '@angular/core';
4
7
  import { Subject } from 'rxjs';
5
- import { getRectangleByPoints, getFactorByPoints, Direction, getDirectionByPoint, getPoints, getPointOnPolyline, getDirectionFactor, Generator, normalizeShapePoints, CommonPluginElement, ActiveGenerator, WithTextPluginKey, RESIZE_HANDLE_DIAMETER, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint } from '@plait/common';
6
- import { Alignment, buildText, AlignEditor, TextManage, DEFAULT_FONT_SIZE, getTextFromClipboard, getTextSize } from '@plait/text';
7
8
  import { isKeyHotkey } from 'is-hotkey';
8
9
  import { Node } from 'slate';
9
10
 
10
- var GeometryShape;
11
- (function (GeometryShape) {
12
- GeometryShape["rectangle"] = "rectangle";
13
- GeometryShape["ellipse"] = "ellipse";
14
- GeometryShape["diamond"] = "diamond";
15
- GeometryShape["roundRectangle"] = "roundRectangle";
16
- GeometryShape["parallelogram"] = "parallelogram";
17
- GeometryShape["text"] = "text";
18
- })(GeometryShape || (GeometryShape = {}));
11
+ var BasicShapes;
12
+ (function (BasicShapes) {
13
+ BasicShapes["rectangle"] = "rectangle";
14
+ BasicShapes["ellipse"] = "ellipse";
15
+ BasicShapes["diamond"] = "diamond";
16
+ BasicShapes["roundRectangle"] = "roundRectangle";
17
+ BasicShapes["parallelogram"] = "parallelogram";
18
+ BasicShapes["text"] = "text";
19
+ BasicShapes["triangle"] = "triangle";
20
+ BasicShapes["leftArrow"] = "leftArrow";
21
+ BasicShapes["trapezoid"] = "trapezoid";
22
+ BasicShapes["rightArrow"] = "rightArrow";
23
+ BasicShapes["cross"] = "cross";
24
+ BasicShapes["star"] = "star";
25
+ BasicShapes["pentagon"] = "pentagon";
26
+ BasicShapes["hexagon"] = "hexagon";
27
+ BasicShapes["octagon"] = "octagon";
28
+ BasicShapes["pentagonArrow"] = "pentagonArrow";
29
+ BasicShapes["processArrow"] = "processArrow";
30
+ BasicShapes["twoWayArrow"] = "twoWayArrow";
31
+ BasicShapes["comment"] = "comment";
32
+ BasicShapes["roundComment"] = "roundComment";
33
+ })(BasicShapes || (BasicShapes = {}));
34
+ var FlowchartSymbols;
35
+ (function (FlowchartSymbols) {
36
+ FlowchartSymbols["process"] = "process";
37
+ FlowchartSymbols["decision"] = "decision";
38
+ FlowchartSymbols["data"] = "data";
39
+ FlowchartSymbols["connector"] = "connector";
40
+ FlowchartSymbols["terminal"] = "terminal";
41
+ FlowchartSymbols["manualInput"] = "manualInput";
42
+ FlowchartSymbols["preparation"] = "preparation";
43
+ FlowchartSymbols["manualLoop"] = "manualLoop";
44
+ FlowchartSymbols["merge"] = "merge";
45
+ FlowchartSymbols["delay"] = "delay";
46
+ FlowchartSymbols["storedData"] = "storedData";
47
+ })(FlowchartSymbols || (FlowchartSymbols = {}));
19
48
  const PlaitGeometry = {
20
49
  getTextEditor(element) {
21
50
  return PlaitGeometry.getTextManage(element).componentRef.instance.editor;
@@ -29,79 +58,6 @@ const PlaitGeometry = {
29
58
  }
30
59
  };
31
60
 
32
- var LineMarkerType;
33
- (function (LineMarkerType) {
34
- LineMarkerType["arrow"] = "arrow";
35
- LineMarkerType["none"] = "none";
36
- LineMarkerType["openTriangle"] = "open-triangle";
37
- LineMarkerType["solidTriangle"] = "solid-triangle";
38
- LineMarkerType["sharpArrow"] = "sharp-arrow";
39
- })(LineMarkerType || (LineMarkerType = {}));
40
- var LineShape;
41
- (function (LineShape) {
42
- LineShape["straight"] = "straight";
43
- LineShape["curve"] = "curve";
44
- LineShape["elbow"] = "elbow";
45
- })(LineShape || (LineShape = {}));
46
- var LineHandleKey;
47
- (function (LineHandleKey) {
48
- LineHandleKey["source"] = "source";
49
- LineHandleKey["target"] = "target";
50
- })(LineHandleKey || (LineHandleKey = {}));
51
- const PlaitLine = {
52
- getTextEditors(element) {
53
- const component = PlaitElement.getComponent(element);
54
- if (component) {
55
- const manage = component.textManages.find(manage => manage.isEditing);
56
- if (manage) {
57
- return [manage.componentRef.instance.editor];
58
- }
59
- else {
60
- return component.textManages.map(manage => manage.componentRef.instance.editor);
61
- }
62
- }
63
- throw new Error('can not get correctly component in get text editor');
64
- },
65
- isSourceMark(line, markType) {
66
- return line.source.marker === markType;
67
- },
68
- isTargetMark(line, markType) {
69
- return line.target.marker === markType;
70
- },
71
- isBoundElementOfSource(line, element) {
72
- return line.source.boundId === element.id;
73
- },
74
- isBoundElementOfTarget(line, element) {
75
- return line.target.boundId === element.id;
76
- }
77
- };
78
-
79
- var StrokeStyle;
80
- (function (StrokeStyle) {
81
- StrokeStyle["solid"] = "solid";
82
- StrokeStyle["dashed"] = "dashed";
83
- })(StrokeStyle || (StrokeStyle = {}));
84
-
85
- const PlaitDrawElement = {
86
- isGeometry: (value) => {
87
- return value.type === 'geometry';
88
- },
89
- isLine: (value) => {
90
- return value.type === 'line';
91
- },
92
- isText: (value) => {
93
- return value.type === 'geometry' && value.shape === GeometryShape.text;
94
- },
95
- isDrawElement: (value) => {
96
- if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value)) {
97
- return true;
98
- }
99
- else {
100
- return false;
101
- }
102
- }
103
- };
104
-
105
61
  const ShapeDefaultSpace = {
106
62
  rectangleAndText: 4
107
63
  };
@@ -115,7 +71,7 @@ const DefaultGeometryActiveStyle = {
115
71
  strokeWidth: ACTIVE_STROKE_WIDTH,
116
72
  selectionStrokeWidth: ACTIVE_STROKE_WIDTH
117
73
  };
118
- const DefaultGeometryProperty = {
74
+ const DefaultBasicShapeProperty = {
119
75
  width: 100,
120
76
  height: 100,
121
77
  strokeColor: '#333',
@@ -127,27 +83,60 @@ const DefaultTextProperty = {
127
83
  text: '文本'
128
84
  };
129
85
  const GeometryThreshold = {
130
- defaultTextMaxWidth: 34 * 14,
131
- };
132
-
133
- var DrawPointerType;
134
- (function (DrawPointerType) {
135
- DrawPointerType["text"] = "text";
136
- DrawPointerType["rectangle"] = "rectangle";
137
- DrawPointerType["line"] = "line";
138
- DrawPointerType["diamond"] = "diamond";
139
- DrawPointerType["roundRectangle"] = "roundRectangle";
140
- DrawPointerType["parallelogram"] = "parallelogram";
141
- DrawPointerType["ellipse"] = "ellipse";
142
- })(DrawPointerType || (DrawPointerType = {}));
143
- const GeometryPointer = [
144
- DrawPointerType.rectangle,
145
- DrawPointerType.text,
146
- DrawPointerType.diamond,
147
- DrawPointerType.ellipse,
148
- DrawPointerType.parallelogram,
149
- DrawPointerType.roundRectangle
150
- ];
86
+ defaultTextMaxWidth: 34 * 14
87
+ };
88
+ const DefaultConnectorProperty = {
89
+ width: 44,
90
+ height: 44
91
+ };
92
+ const DefaultFlowchartProperty = {
93
+ width: 120,
94
+ height: 60
95
+ };
96
+ const DefaultDecisionProperty = {
97
+ width: 140,
98
+ height: 70
99
+ };
100
+ const DefaultDataProperty = {
101
+ width: 124,
102
+ height: 60
103
+ };
104
+ const DefaultManualInputProperty = {
105
+ width: 117,
106
+ height: 59
107
+ };
108
+ const DefaultMergeProperty = {
109
+ width: 47,
110
+ height: 33
111
+ };
112
+ const DefaultFlowchartPropertyMap = {
113
+ [FlowchartSymbols.connector]: DefaultConnectorProperty,
114
+ [FlowchartSymbols.process]: DefaultFlowchartProperty,
115
+ [FlowchartSymbols.decision]: DefaultDecisionProperty,
116
+ [FlowchartSymbols.data]: DefaultDataProperty,
117
+ [FlowchartSymbols.terminal]: DefaultFlowchartProperty,
118
+ [FlowchartSymbols.manualInput]: DefaultManualInputProperty,
119
+ [FlowchartSymbols.preparation]: DefaultFlowchartProperty,
120
+ [FlowchartSymbols.manualLoop]: DefaultFlowchartProperty,
121
+ [FlowchartSymbols.merge]: DefaultMergeProperty,
122
+ [FlowchartSymbols.delay]: DefaultFlowchartProperty,
123
+ [FlowchartSymbols.storedData]: DefaultFlowchartProperty
124
+ };
125
+
126
+ const getGeometryPointers = () => {
127
+ return [...Object.keys(BasicShapes), ...Object.keys(FlowchartSymbols)];
128
+ };
129
+ const getBasicPointers = () => {
130
+ return Object.keys(BasicShapes);
131
+ };
132
+ const getFlowchartPointers = () => {
133
+ return Object.keys(FlowchartSymbols);
134
+ };
135
+ const getLinePointers = () => {
136
+ return Object.keys(LineShape);
137
+ };
138
+
139
+ const DEFAULT_IMAGE_WIDTH = 1000;
151
140
 
152
141
  const getStrokeWidthByElement = (element) => {
153
142
  if (PlaitDrawElement.isText(element)) {
@@ -171,26 +160,138 @@ const getStrokeStyleByElement = (element) => {
171
160
  return element.strokeStyle || StrokeStyle.solid;
172
161
  };
173
162
 
174
- const DiamondEngine = {
163
+ const heightRatio$1 = 3 / 4;
164
+ const CommentEngine = {
175
165
  draw(board, rectangle, options) {
176
- const points = RectangleClient.getEdgeCenterPoints(rectangle);
166
+ const points = getCommentPoints(rectangle);
177
167
  const rs = PlaitBoard.getRoughSVG(board);
178
168
  const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
179
169
  setStrokeLinecap(polygon, 'round');
180
170
  return polygon;
181
171
  },
182
172
  isHit(rectangle, point) {
183
- const controlPoints = RectangleClient.getEdgeCenterPoints(rectangle);
184
- return isPointInPolygon(point, controlPoints);
173
+ const parallelogramPoints = getCommentPoints(rectangle);
174
+ return isPointInPolygon(point, parallelogramPoints);
175
+ },
176
+ getCornerPoints(rectangle) {
177
+ return getCommentPoints(rectangle);
185
178
  },
186
179
  getNearestPoint(rectangle, point) {
187
- const connectorPoints = RectangleClient.getEdgeCenterPoints(rectangle);
188
- return getNearestPointBetweenPointAndSegments(point, connectorPoints);
180
+ return getNearestPointBetweenPointAndSegments(point, getCommentPoints(rectangle));
181
+ },
182
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
183
+ const corners = getCommentPoints(rectangle);
184
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
185
+ return getEdgeOnPolygonByPoint(corners, point);
189
186
  },
190
187
  getConnectorPoints(rectangle) {
191
188
  return RectangleClient.getEdgeCenterPoints(rectangle);
189
+ },
190
+ getTextRectangle(element) {
191
+ const elementRectangle = getRectangleByPoints(element.points);
192
+ const strokeWidth = getStrokeWidthByElement(element);
193
+ const height = element.textHeight;
194
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
195
+ return {
196
+ height,
197
+ width: width > 0 ? width : 0,
198
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
199
+ y: elementRectangle.y + (elementRectangle.height * heightRatio$1 - height) / 2
200
+ };
201
+ }
202
+ };
203
+ const getCommentPoints = (rectangle) => {
204
+ return [
205
+ [rectangle.x, rectangle.y],
206
+ [rectangle.x + rectangle.width, rectangle.y],
207
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * heightRatio$1],
208
+ [rectangle.x + (rectangle.width * 3) / 5, rectangle.y + rectangle.height * heightRatio$1],
209
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
210
+ [rectangle.x + (rectangle.width * 2) / 5, rectangle.y + rectangle.height * heightRatio$1],
211
+ [rectangle.x, rectangle.y + rectangle.height * heightRatio$1]
212
+ ];
213
+ };
214
+
215
+ function createPolygonEngine(options) {
216
+ const getPoints = options.getPolygonPoints;
217
+ const engine = {
218
+ draw(board, rectangle, options) {
219
+ const points = getPoints(rectangle);
220
+ const rs = PlaitBoard.getRoughSVG(board);
221
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
222
+ setStrokeLinecap(polygon, 'round');
223
+ return polygon;
224
+ },
225
+ isHit(rectangle, point) {
226
+ const points = getPoints(rectangle);
227
+ return isPointInPolygon(point, points);
228
+ },
229
+ getCornerPoints(rectangle) {
230
+ return getPoints(rectangle);
231
+ },
232
+ getNearestPoint(rectangle, point) {
233
+ return getNearestPointBetweenPointAndSegments(point, getPoints(rectangle));
234
+ },
235
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
236
+ const corners = getPoints(rectangle);
237
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
238
+ return getEdgeOnPolygonByPoint(corners, point);
239
+ },
240
+ getConnectorPoints(rectangle) {
241
+ if (options.getConnectorPoints) {
242
+ return options.getConnectorPoints(rectangle);
243
+ }
244
+ return getPoints(rectangle);
245
+ }
246
+ };
247
+ if (options.getTextRectangle) {
248
+ engine.getTextRectangle = options.getTextRectangle;
192
249
  }
250
+ return engine;
251
+ }
252
+
253
+ const getCrossPoints = (rectangle) => {
254
+ return [
255
+ [rectangle.x + rectangle.width / 4, rectangle.y],
256
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y],
257
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 4],
258
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 4],
259
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 3) / 4],
260
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + (rectangle.height * 3) / 4],
261
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height],
262
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
263
+ [rectangle.x + rectangle.width / 4, rectangle.y + (rectangle.height * 3) / 4],
264
+ [rectangle.x, rectangle.y + (rectangle.height * 3) / 4],
265
+ [rectangle.x, rectangle.y + rectangle.height / 4],
266
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height / 4]
267
+ ];
193
268
  };
269
+ const CrossEngine = createPolygonEngine({
270
+ getPolygonPoints: getCrossPoints,
271
+ getConnectorPoints(rectangle) {
272
+ return RectangleClient.getEdgeCenterPoints(rectangle);
273
+ },
274
+ getTextRectangle(element) {
275
+ const rectangle = getTextRectangle(element);
276
+ const width = rectangle.width;
277
+ rectangle.width = rectangle.width / 2;
278
+ rectangle.x += width / 4;
279
+ return rectangle;
280
+ }
281
+ });
282
+
283
+ const DiamondEngine = createPolygonEngine({
284
+ getPolygonPoints: RectangleClient.getEdgeCenterPoints,
285
+ getConnectorPoints(rectangle) {
286
+ return RectangleClient.getEdgeCenterPoints(rectangle);
287
+ },
288
+ getTextRectangle(element) {
289
+ const rectangle = getTextRectangle(element);
290
+ rectangle.width = rectangle.width / 2;
291
+ rectangle.x += rectangle.width / 2;
292
+ return rectangle;
293
+ }
294
+ });
194
295
 
195
296
  const EllipseEngine = {
196
297
  draw(board, rectangle, options) {
@@ -202,12 +303,31 @@ const EllipseEngine = {
202
303
  const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
203
304
  return isPointInEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
204
305
  },
306
+ getCornerPoints(rectangle) {
307
+ return RectangleClient.getEdgeCenterPoints(rectangle);
308
+ },
205
309
  getNearestPoint(rectangle, point) {
206
310
  const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
207
311
  return getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
208
312
  },
313
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
314
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
315
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
316
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
317
+ const a = rectangle.width / 2;
318
+ const b = rectangle.height / 2;
319
+ const slope = getTangentSlope(point[0], point[1], a, b);
320
+ return getVectorBySlope(point[0], point[1], slope);
321
+ },
209
322
  getConnectorPoints(rectangle) {
210
323
  return RectangleClient.getEdgeCenterPoints(rectangle);
324
+ },
325
+ getTextRectangle(element) {
326
+ const rectangle = getTextRectangle(element);
327
+ const width = rectangle.width;
328
+ rectangle.width = (rectangle.width * 3) / 4;
329
+ rectangle.x += width / 8;
330
+ return rectangle;
211
331
  }
212
332
  };
213
333
  function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation = 0) {
@@ -245,28 +365,110 @@ function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation =
245
365
  const signY = point[1] > center[1] ? 1 : -1;
246
366
  return [center[0] + a * tx * signX, center[1] + b * ty * signY];
247
367
  }
368
+ /**
369
+ * the result of slope is based on Cartesian coordinate system
370
+ * x, y are based on the position in the Cartesian coordinate system
371
+ */
372
+ function getTangentSlope(x, y, a, b) {
373
+ const k = (-b * b * x) / (a * a * y);
374
+ return k;
375
+ }
376
+ /**
377
+ * x, y are based on the position in the Cartesian coordinate system
378
+ */
379
+ function getVectorBySlope(x, y, slope) {
380
+ const deltaX = 30;
381
+ const deltaY = -slope * deltaX;
382
+ let start = [0 - deltaX, 0 - deltaY];
383
+ let end = [0 + deltaX, 0 + deltaY];
384
+ // y < 0 acts on the lower half of the x-axis, with the starting point at the top and the end point at the bottom.
385
+ if (y < 0) {
386
+ const temp = start;
387
+ start = end;
388
+ end = temp;
389
+ }
390
+ const vector = [end[0] - start[0], end[1] - start[1]];
391
+ return vector;
392
+ }
248
393
 
249
- const ParallelogramEngine = {
250
- draw(board, rectangle, options) {
251
- const points = getParallelogramPoints(rectangle);
252
- const rs = PlaitBoard.getRoughSVG(board);
253
- const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
254
- setStrokeLinecap(polygon, 'round');
255
- return polygon;
256
- },
257
- isHit(rectangle, point) {
258
- const parallelogramPoints = getParallelogramPoints(rectangle);
259
- return isPointInPolygon(point, parallelogramPoints);
394
+ const getHexagonPoints = (rectangle) => {
395
+ return [
396
+ [rectangle.x + rectangle.width / 4, rectangle.y],
397
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y],
398
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
399
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height],
400
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
401
+ [rectangle.x, rectangle.y + rectangle.height / 2]
402
+ ];
403
+ };
404
+ const HexagonEngine = createPolygonEngine({
405
+ getPolygonPoints: getHexagonPoints,
406
+ getConnectorPoints(rectangle) {
407
+ return RectangleClient.getEdgeCenterPoints(rectangle);
260
408
  },
261
- getNearestPoint(rectangle, point) {
262
- const cornerPoints = getParallelogramPoints(rectangle);
263
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
409
+ getTextRectangle(element) {
410
+ const rectangle = getTextRectangle(element);
411
+ const width = rectangle.width;
412
+ rectangle.width = (rectangle.width * 3) / 4;
413
+ rectangle.x += width / 8;
414
+ return rectangle;
415
+ }
416
+ });
417
+
418
+ const getLeftArrowPoints = (rectangle) => {
419
+ return [
420
+ [rectangle.x, rectangle.y + rectangle.height / 2],
421
+ [rectangle.x + rectangle.width * 0.32, rectangle.y],
422
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height * 0.2],
423
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * 0.2],
424
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * 0.8],
425
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height * 0.8],
426
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height]
427
+ ];
428
+ };
429
+ const LeftArrowEngine = createPolygonEngine({
430
+ getPolygonPoints: getLeftArrowPoints,
431
+ getConnectorPoints: (rectangle) => {
432
+ return [
433
+ [rectangle.x, rectangle.y + rectangle.height / 2],
434
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
435
+ ];
264
436
  },
265
- getConnectorPoints(rectangle) {
266
- const cornerPoints = getParallelogramPoints(rectangle);
267
- return getCenterPointsOnPolygon(cornerPoints);
437
+ getTextRectangle(element) {
438
+ const rectangle = getTextRectangle(element);
439
+ const width = rectangle.width;
440
+ rectangle.width = rectangle.width * (1 - 0.32);
441
+ rectangle.x += width * 0.32;
442
+ return rectangle;
268
443
  }
444
+ });
445
+
446
+ const getOctagonPoints = (rectangle) => {
447
+ return [
448
+ [rectangle.x + (rectangle.width * 3) / 10, rectangle.y],
449
+ [rectangle.x + (rectangle.width * 7) / 10, rectangle.y],
450
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 3) / 10],
451
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 7) / 10],
452
+ [rectangle.x + (rectangle.width * 7) / 10, rectangle.y + rectangle.height],
453
+ [rectangle.x + (rectangle.width * 3) / 10, rectangle.y + rectangle.height],
454
+ [rectangle.x, rectangle.y + (rectangle.height * 7) / 10],
455
+ [rectangle.x, rectangle.y + (rectangle.height * 3) / 10]
456
+ ];
269
457
  };
458
+ const OctagonEngine = createPolygonEngine({
459
+ getPolygonPoints: getOctagonPoints,
460
+ getConnectorPoints(rectangle) {
461
+ return RectangleClient.getEdgeCenterPoints(rectangle);
462
+ },
463
+ getTextRectangle(element) {
464
+ const rectangle = getTextRectangle(element);
465
+ const width = rectangle.width;
466
+ rectangle.width = (rectangle.width * 3) / 4;
467
+ rectangle.x += width / 8;
468
+ return rectangle;
469
+ }
470
+ });
471
+
270
472
  const getParallelogramPoints = (rectangle) => {
271
473
  return [
272
474
  [rectangle.x + rectangle.width / 4, rectangle.y],
@@ -275,6 +477,90 @@ const getParallelogramPoints = (rectangle) => {
275
477
  [rectangle.x, rectangle.y + rectangle.height]
276
478
  ];
277
479
  };
480
+ const ParallelogramEngine = createPolygonEngine({
481
+ getPolygonPoints: getParallelogramPoints,
482
+ getConnectorPoints: (rectangle) => {
483
+ const cornerPoints = getParallelogramPoints(rectangle);
484
+ return getCenterPointsOnPolygon(cornerPoints);
485
+ },
486
+ getTextRectangle(element) {
487
+ const rectangle = getTextRectangle(element);
488
+ const width = rectangle.width;
489
+ rectangle.width = rectangle.width / 2;
490
+ rectangle.x += width / 4;
491
+ return rectangle;
492
+ }
493
+ });
494
+
495
+ const getPentagonPoints = (rectangle) => {
496
+ return [
497
+ [rectangle.x + rectangle.width / 2, rectangle.y],
498
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 2) / 5],
499
+ [rectangle.x + (rectangle.width * 4) / 5, rectangle.y + rectangle.height],
500
+ [rectangle.x + rectangle.width / 5, rectangle.y + rectangle.height],
501
+ [rectangle.x, rectangle.y + (rectangle.height * 2) / 5]
502
+ ];
503
+ };
504
+ const PentagonEngine = createPolygonEngine({
505
+ getPolygonPoints: getPentagonPoints,
506
+ getTextRectangle(element) {
507
+ const elementRectangle = getRectangleByPoints(element.points);
508
+ const strokeWidth = getStrokeWidthByElement(element);
509
+ const height = element.textHeight;
510
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
511
+ const width = (originWidth * 3) / 5;
512
+ return {
513
+ height,
514
+ width: width > 0 ? width : 0,
515
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 5,
516
+ y: elementRectangle.y + elementRectangle.height / 5 + ((elementRectangle.height * 4) / 5 - height) / 2
517
+ };
518
+ }
519
+ });
520
+
521
+ const getPentagonArrowPoints = (rectangle) => {
522
+ return [
523
+ [rectangle.x, rectangle.y],
524
+ [rectangle.x + (rectangle.width * 3) / 5, rectangle.y],
525
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
526
+ [rectangle.x + (rectangle.width * 3) / 5, rectangle.y + rectangle.height],
527
+ [rectangle.x, rectangle.y + rectangle.height]
528
+ ];
529
+ };
530
+ const PentagonArrowEngine = createPolygonEngine({
531
+ getPolygonPoints: getPentagonArrowPoints,
532
+ getConnectorPoints(rectangle) {
533
+ return RectangleClient.getEdgeCenterPoints(rectangle);
534
+ },
535
+ getTextRectangle(element) {
536
+ const rectangle = getTextRectangle(element);
537
+ rectangle.width = (rectangle.width * 3) / 5;
538
+ return rectangle;
539
+ }
540
+ });
541
+
542
+ const getProcessArrowPoints = (rectangle) => {
543
+ const wider = rectangle.width > rectangle.height / 2;
544
+ return [
545
+ [rectangle.x, rectangle.y],
546
+ [rectangle.x + (wider ? rectangle.width - rectangle.height / 2 : 0), rectangle.y],
547
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
548
+ [rectangle.x + (wider ? rectangle.width - rectangle.height / 2 : 0), rectangle.y + rectangle.height],
549
+ [rectangle.x, rectangle.y + rectangle.height],
550
+ [rectangle.x + (wider ? rectangle.height / 2 : rectangle.width), rectangle.y + rectangle.height / 2]
551
+ ];
552
+ };
553
+ const ProcessArrowEngine = createPolygonEngine({
554
+ getPolygonPoints: getProcessArrowPoints,
555
+ getTextRectangle(element) {
556
+ const rectangle = getTextRectangle(element);
557
+ const elementRectangle = getRectangleByPoints(element.points);
558
+ const width = rectangle.width;
559
+ rectangle.width = elementRectangle.height / 2;
560
+ rectangle.x += elementRectangle.height / 2;
561
+ return rectangle;
562
+ }
563
+ });
278
564
 
279
565
  const RectangleEngine = {
280
566
  draw(board, rectangle, options) {
@@ -284,15 +570,48 @@ const RectangleEngine = {
284
570
  const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
285
571
  return RectangleClient.isHit(rectangle, rangeRectangle);
286
572
  },
573
+ getCornerPoints(rectangle) {
574
+ return RectangleClient.getCornerPoints(rectangle);
575
+ },
287
576
  getNearestPoint(rectangle, point) {
288
- const cornerPoints = RectangleClient.getCornerPoints(rectangle);
289
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
577
+ return getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
578
+ },
579
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
580
+ const corners = RectangleEngine.getCornerPoints(rectangle);
581
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
582
+ return getEdgeOnPolygonByPoint(corners, point);
290
583
  },
291
584
  getConnectorPoints(rectangle) {
292
585
  return RectangleClient.getEdgeCenterPoints(rectangle);
293
586
  }
294
587
  };
295
588
 
589
+ const getRightArrowPoints = (rectangle) => {
590
+ return [
591
+ [rectangle.x, rectangle.y + rectangle.height * 0.2],
592
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.2],
593
+ [rectangle.x + rectangle.width * 0.68, rectangle.y],
594
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
595
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height],
596
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.8],
597
+ [rectangle.x, rectangle.y + rectangle.height * 0.8]
598
+ ];
599
+ };
600
+ const RightArrowEngine = createPolygonEngine({
601
+ getPolygonPoints: getRightArrowPoints,
602
+ getConnectorPoints: (rectangle) => {
603
+ return [
604
+ [rectangle.x, rectangle.y + rectangle.height / 2],
605
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
606
+ ];
607
+ },
608
+ getTextRectangle(element) {
609
+ const rectangle = getTextRectangle(element);
610
+ rectangle.width = rectangle.width * 0.68;
611
+ return rectangle;
612
+ }
613
+ });
614
+
296
615
  const RoundRectangleEngine = {
297
616
  draw(board, rectangle, options) {
298
617
  return drawRoundRectangle(PlaitBoard.getRoughSVG(board), rectangle.x, rectangle.y, rectangle.x + rectangle.width, rectangle.y + rectangle.height, { ...options, fillStyle: 'solid' }, false, getRoundRectangleRadius(rectangle));
@@ -300,8 +619,16 @@ const RoundRectangleEngine = {
300
619
  isHit(rectangle, point) {
301
620
  return isPointInRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
302
621
  },
622
+ getCornerPoints(rectangle) {
623
+ return RectangleClient.getCornerPoints(rectangle);
624
+ },
303
625
  getNearestPoint(rectangle, point) {
304
- return getNearestPointBetweenPointAndRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
626
+ return getNearestPointBetweenPointAndRoundRectangle$1(point, rectangle, getRoundRectangleRadius(rectangle));
627
+ },
628
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
629
+ const corners = RectangleEngine.getCornerPoints(rectangle);
630
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
631
+ return getEdgeOnPolygonByPoint(corners, point);
305
632
  },
306
633
  getConnectorPoints(rectangle) {
307
634
  return RectangleClient.getEdgeCenterPoints(rectangle);
@@ -310,6 +637,247 @@ const RoundRectangleEngine = {
310
637
  const getRoundRectangleRadius = (rectangle) => {
311
638
  return Math.min(rectangle.width * 0.1, rectangle.height * 0.1);
312
639
  };
640
+ function getNearestPointBetweenPointAndRoundRectangle$1(point, rectangle, radius) {
641
+ const { x: rectX, y: rectY, width, height } = rectangle;
642
+ const cornerPoints = RectangleClient.getCornerPoints(rectangle);
643
+ let result = getNearestPointBetweenPointAndSegments(point, cornerPoints);
644
+ let circleCenter = null;
645
+ const inLeftTop = point[0] >= rectX && point[0] <= rectX + radius && point[1] >= rectY && point[1] <= rectY + radius;
646
+ if (inLeftTop) {
647
+ circleCenter = [rectX + radius, rectY + radius];
648
+ }
649
+ const inLeftBottom = point[0] >= rectX && point[0] <= rectX + radius && point[1] >= rectY + height && point[1] <= rectY + height - radius;
650
+ if (inLeftBottom) {
651
+ circleCenter = [rectX + radius, rectY + height - radius];
652
+ }
653
+ const inRightTop = point[0] >= rectX + width - radius && point[0] <= rectX + width && point[1] >= rectY && point[1] <= rectY + radius;
654
+ if (inRightTop) {
655
+ circleCenter = [rectX + width - radius, rectY + radius];
656
+ }
657
+ const inRightBottom = point[0] >= rectX + width - radius &&
658
+ point[0] <= rectX + width &&
659
+ point[1] >= rectY + height - radius &&
660
+ point[1] <= rectY + height;
661
+ if (inRightBottom) {
662
+ circleCenter = [rectX + width - radius, rectY + height - radius];
663
+ }
664
+ if (circleCenter) {
665
+ result = getNearestPointBetweenPointAndEllipse(point, circleCenter, radius, radius);
666
+ }
667
+ return result;
668
+ }
669
+
670
+ const heightRatio = 3 / 4;
671
+ const RoundCommentEngine = {
672
+ draw(board, rectangle, options) {
673
+ const rs = PlaitBoard.getRoughSVG(board);
674
+ const x1 = rectangle.x;
675
+ const y1 = rectangle.y;
676
+ const x2 = rectangle.x + rectangle.width;
677
+ const y2 = rectangle.y + rectangle.height * heightRatio;
678
+ const radius = getRoundRectangleRadius(rectangle);
679
+ const point1 = [x1 + radius, y1];
680
+ const point2 = [x2 - radius, y1];
681
+ const point3 = [x2, y1 + radius];
682
+ const point4 = [x2, y2 - radius];
683
+ const point5 = [x2 - radius, y2];
684
+ const point6 = [x1 + radius, y2];
685
+ const point7 = [x1, y2 - radius];
686
+ const point8 = [x1, y1 + radius];
687
+ const point9 = [x1 + rectangle.width / 4, y2];
688
+ const point10 = [x1 + rectangle.width / 4, rectangle.y + rectangle.height];
689
+ const point11 = [x1 + rectangle.width / 2, y2];
690
+ return rs.path(`M${point2[0]} ${point2[1]} A ${radius} ${radius}, 0, 0, 1, ${point3[0]} ${point3[1]} L ${point4[0]} ${point4[1]} A ${radius} ${radius}, 0, 0, 1, ${point5[0]} ${point5[1]} L ${point11[0]} ${point11[1]} ${point10[0]} ${point10[1]} ${point9[0]} ${point9[1]} ${point6[0]} ${point6[1]} A ${radius} ${radius}, 0, 0, 1, ${point7[0]} ${point7[1]} L ${point8[0]} ${point8[1]} A ${radius} ${radius}, 0, 0, 1, ${point1[0]} ${point1[1]} Z`, { ...options, fillStyle: 'solid' });
691
+ },
692
+ isHit(rectangle, point) {
693
+ const points = [
694
+ [rectangle.x + rectangle.width / 4, rectangle.y + (rectangle.height * 3) / 4],
695
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
696
+ [rectangle.x + rectangle.width / 2, rectangle.y + (rectangle.height * 3) / 4]
697
+ ];
698
+ rectangle.height = (rectangle.height * 3) / 4;
699
+ return isPointInPolygon(point, points) || isPointInRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
700
+ },
701
+ getCornerPoints(rectangle) {
702
+ return getRoundCommentPoints(rectangle);
703
+ },
704
+ getNearestPoint(rectangle, point) {
705
+ return getNearestPointBetweenPointAndSegments(point, getRoundCommentPoints(rectangle));
706
+ },
707
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
708
+ const corners = getRoundCommentPoints(rectangle);
709
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
710
+ return getEdgeOnPolygonByPoint(corners, point);
711
+ },
712
+ getConnectorPoints(rectangle) {
713
+ return [
714
+ [rectangle.x + rectangle.width / 2, rectangle.y],
715
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
716
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height * heightRatio],
717
+ [rectangle.x, rectangle.y + rectangle.height / 2]
718
+ ];
719
+ },
720
+ getTextRectangle(element) {
721
+ const elementRectangle = getRectangleByPoints(element.points);
722
+ const strokeWidth = getStrokeWidthByElement(element);
723
+ const height = element.textHeight;
724
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
725
+ return {
726
+ height,
727
+ width: width > 0 ? width : 0,
728
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
729
+ y: elementRectangle.y + (elementRectangle.height * heightRatio - height) / 2
730
+ };
731
+ }
732
+ };
733
+ const getRoundCommentPoints = (rectangle) => {
734
+ return [
735
+ [rectangle.x, rectangle.y],
736
+ [rectangle.x + rectangle.width, rectangle.y],
737
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * heightRatio],
738
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height * heightRatio],
739
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
740
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height * heightRatio],
741
+ [rectangle.x, rectangle.y + rectangle.height * heightRatio]
742
+ ];
743
+ };
744
+
745
+ const getTrapezoidPoints = (rectangle) => {
746
+ return [
747
+ [rectangle.x + rectangle.width * 0.15, rectangle.y],
748
+ [rectangle.x + rectangle.width * 0.85, rectangle.y],
749
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
750
+ [rectangle.x, rectangle.y + rectangle.height]
751
+ ];
752
+ };
753
+ const TrapezoidEngine = createPolygonEngine({
754
+ getPolygonPoints: getTrapezoidPoints,
755
+ getConnectorPoints(rectangle) {
756
+ const points = getTrapezoidPoints(rectangle);
757
+ return getCenterPointsOnPolygon(points);
758
+ },
759
+ getTextRectangle(element) {
760
+ const rectangle = getTextRectangle(element);
761
+ const width = rectangle.width;
762
+ rectangle.width = (rectangle.width * 3) / 4;
763
+ rectangle.x += width / 8;
764
+ return rectangle;
765
+ }
766
+ });
767
+
768
+ const getTrianglePoints = (rectangle) => {
769
+ return [
770
+ [rectangle.x + rectangle.width / 2, rectangle.y],
771
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
772
+ [rectangle.x, rectangle.y + rectangle.height]
773
+ ];
774
+ };
775
+ const TriangleEngine = createPolygonEngine({
776
+ getPolygonPoints: getTrianglePoints,
777
+ getConnectorPoints(rectangle) {
778
+ const cornerPoints = getTrianglePoints(rectangle);
779
+ const lineCenterPoints = getCenterPointsOnPolygon(cornerPoints);
780
+ return [...lineCenterPoints, ...cornerPoints];
781
+ },
782
+ getTextRectangle(element) {
783
+ const elementRectangle = getRectangleByPoints(element.points);
784
+ const strokeWidth = getStrokeWidthByElement(element);
785
+ const height = element.textHeight;
786
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
787
+ const width = (originWidth * 2) / 3;
788
+ return {
789
+ height,
790
+ width: width > 0 ? width : 0,
791
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 6,
792
+ y: elementRectangle.y + (elementRectangle.height * 3) / 5 + ((elementRectangle.height * 2) / 5 - height) / 2
793
+ };
794
+ }
795
+ });
796
+
797
+ const getTwoWayArrowPoints = (rectangle) => {
798
+ return [
799
+ [rectangle.x, rectangle.y + rectangle.height / 2],
800
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y],
801
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + rectangle.height / 5],
802
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + rectangle.height / 5],
803
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y],
804
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
805
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + rectangle.height],
806
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + (rectangle.height * 4) / 5],
807
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + (rectangle.height * 4) / 5],
808
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + rectangle.height]
809
+ ];
810
+ };
811
+ const TwoWayArrowEngine = createPolygonEngine({
812
+ getPolygonPoints: getTwoWayArrowPoints,
813
+ getConnectorPoints: (rectangle) => {
814
+ return [
815
+ [rectangle.x, rectangle.y + rectangle.height / 2],
816
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
817
+ ];
818
+ }
819
+ });
820
+
821
+ const getStarPoints = (rectangle) => {
822
+ return [
823
+ [rectangle.x + rectangle.width / 2, rectangle.y + (rectangle.height * 75) / 91],
824
+ [rectangle.x + (rectangle.width * 18.61) / 96, rectangle.y + rectangle.height],
825
+ [rectangle.x + (rectangle.width * 24.2235871) / 96, rectangle.y + (rectangle.height * 57.7254249) / 91],
826
+ [rectangle.x, rectangle.y + (rectangle.height * 34.5491503) / 91],
827
+ [rectangle.x + (rectangle.width * 33.3053687) / 96, rectangle.y + (rectangle.height * 29.7745751) / 91],
828
+ [rectangle.x + rectangle.width / 2, rectangle.y],
829
+ [rectangle.x + (rectangle.width * 62.6946313) / 96, rectangle.y + (rectangle.height * 29.7745751) / 91],
830
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 34.5491503) / 91],
831
+ [rectangle.x + (rectangle.width * 71.7764129) / 96, rectangle.y + (rectangle.height * 57.7254249) / 91],
832
+ [rectangle.x + (rectangle.width * 77.3892626) / 96, rectangle.y + rectangle.height]
833
+ ];
834
+ };
835
+ const StarEngine = createPolygonEngine({
836
+ getPolygonPoints: getStarPoints,
837
+ getConnectorPoints: (rectangle) => {
838
+ const points = getStarPoints(rectangle);
839
+ return [points[1], points[3], points[5], points[7], points[9]];
840
+ },
841
+ getTextRectangle(element) {
842
+ const elementRectangle = getRectangleByPoints(element.points);
843
+ const strokeWidth = getStrokeWidthByElement(element);
844
+ const height = element.textHeight;
845
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
846
+ const width = originWidth / 2;
847
+ return {
848
+ height,
849
+ width: width > 0 ? width : 0,
850
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 4,
851
+ y: elementRectangle.y + (elementRectangle.height * 1) / 5 + ((elementRectangle.height * 4) / 5 - height) / 2
852
+ };
853
+ }
854
+ });
855
+
856
+ const TerminalEngine = {
857
+ draw(board, rectangle, options) {
858
+ return drawRoundRectangle(PlaitBoard.getRoughSVG(board), rectangle.x, rectangle.y, rectangle.x + rectangle.width, rectangle.y + rectangle.height, { ...options, fillStyle: 'solid' }, false, getStartEndRadius(rectangle));
859
+ },
860
+ isHit(rectangle, point) {
861
+ return isPointInRoundRectangle(point, rectangle, getStartEndRadius(rectangle));
862
+ },
863
+ getCornerPoints(rectangle) {
864
+ return RectangleClient.getCornerPoints(rectangle);
865
+ },
866
+ getNearestPoint(rectangle, point) {
867
+ return getNearestPointBetweenPointAndRoundRectangle(point, rectangle, getStartEndRadius(rectangle));
868
+ },
869
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
870
+ const corners = RectangleEngine.getCornerPoints(rectangle);
871
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
872
+ return getEdgeOnPolygonByPoint(corners, point);
873
+ },
874
+ getConnectorPoints(rectangle) {
875
+ return RectangleClient.getEdgeCenterPoints(rectangle);
876
+ }
877
+ };
878
+ const getStartEndRadius = (rectangle) => {
879
+ return Math.min(rectangle.width / 2, rectangle.height / 2);
880
+ };
313
881
  function getNearestPointBetweenPointAndRoundRectangle(point, rectangle, radius) {
314
882
  const { x: rectX, y: rectY, width, height } = rectangle;
315
883
  const cornerPoints = RectangleClient.getCornerPoints(rectangle);
@@ -340,25 +908,277 @@ function getNearestPointBetweenPointAndRoundRectangle(point, rectangle, radius)
340
908
  return result;
341
909
  }
342
910
 
911
+ const getManualInputPoints = (rectangle) => {
912
+ return [
913
+ [rectangle.x, rectangle.y + rectangle.height / 4],
914
+ [rectangle.x + rectangle.width, rectangle.y],
915
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
916
+ [rectangle.x, rectangle.y + rectangle.height]
917
+ ];
918
+ };
919
+ const ManualInputEngine = createPolygonEngine({
920
+ getPolygonPoints: getManualInputPoints,
921
+ getConnectorPoints: (rectangle) => {
922
+ const cornerPoints = getManualInputPoints(rectangle);
923
+ return getCenterPointsOnPolygon(cornerPoints);
924
+ },
925
+ getTextRectangle: (element) => {
926
+ const elementRectangle = getRectangleByPoints(element.points);
927
+ const strokeWidth = getStrokeWidthByElement(element);
928
+ const height = element.textHeight;
929
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
930
+ return {
931
+ height,
932
+ width: width > 0 ? width : 0,
933
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
934
+ y: elementRectangle.y + elementRectangle.height / 4 + ((elementRectangle.height * 3) / 4 - height) / 2
935
+ };
936
+ }
937
+ });
938
+
939
+ const getPreparationPoints = (rectangle) => {
940
+ return [
941
+ [rectangle.x, rectangle.y + rectangle.height / 2],
942
+ [rectangle.x + rectangle.width / 6, rectangle.y],
943
+ [rectangle.x + (rectangle.width * 5) / 6, rectangle.y],
944
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
945
+ [rectangle.x + (rectangle.width * 5) / 6, rectangle.y + rectangle.height],
946
+ [rectangle.x + rectangle.width / 6, rectangle.y + rectangle.height]
947
+ ];
948
+ };
949
+ const PreparationEngine = createPolygonEngine({
950
+ getPolygonPoints: getPreparationPoints,
951
+ getConnectorPoints: (rectangle) => {
952
+ return RectangleClient.getEdgeCenterPoints(rectangle);
953
+ },
954
+ getTextRectangle(element) {
955
+ const rectangle = getTextRectangle(element);
956
+ const width = rectangle.width;
957
+ rectangle.width = (rectangle.width * 2) / 3;
958
+ rectangle.x += width / 6;
959
+ return rectangle;
960
+ }
961
+ });
962
+
963
+ const getManualLoopPoints = (rectangle) => {
964
+ return [
965
+ [rectangle.x, rectangle.y],
966
+ [rectangle.x + rectangle.width, rectangle.y],
967
+ [rectangle.x + (rectangle.width * 7) / 8, rectangle.y + rectangle.height],
968
+ [rectangle.x + rectangle.width / 8, rectangle.y + rectangle.height]
969
+ ];
970
+ };
971
+ const ManualLoopEngine = createPolygonEngine({
972
+ getPolygonPoints: getManualLoopPoints,
973
+ getConnectorPoints: (rectangle) => {
974
+ const cornerPoints = getManualLoopPoints(rectangle);
975
+ return getCenterPointsOnPolygon(cornerPoints);
976
+ },
977
+ getTextRectangle(element) {
978
+ const rectangle = getTextRectangle(element);
979
+ const width = rectangle.width;
980
+ rectangle.width = (rectangle.width * 3) / 4;
981
+ rectangle.x += width / 8;
982
+ return rectangle;
983
+ }
984
+ });
985
+
986
+ const getMergePoints = (rectangle) => {
987
+ return [
988
+ [rectangle.x, rectangle.y],
989
+ [rectangle.x + rectangle.width, rectangle.y],
990
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height]
991
+ ];
992
+ };
993
+ const MergeEngine = createPolygonEngine({
994
+ getPolygonPoints: getMergePoints,
995
+ getConnectorPoints: (rectangle) => {
996
+ const cornerPoints = getMergePoints(rectangle);
997
+ const lineCenterPoints = getCenterPointsOnPolygon(cornerPoints);
998
+ return [...lineCenterPoints, ...cornerPoints];
999
+ },
1000
+ getTextRectangle(element) {
1001
+ const elementRectangle = getRectangleByPoints(element.points);
1002
+ const strokeWidth = getStrokeWidthByElement(element);
1003
+ const height = element.textHeight;
1004
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1005
+ const width = (originWidth * 2) / 3;
1006
+ return {
1007
+ height,
1008
+ width: width > 0 ? width : 0,
1009
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 6,
1010
+ y: elementRectangle.y + ((elementRectangle.height * 2) / 3 - height) / 2
1011
+ };
1012
+ }
1013
+ });
1014
+
1015
+ const DelayEngine = {
1016
+ draw(board, rectangle, options) {
1017
+ const rs = PlaitBoard.getRoughSVG(board);
1018
+ const shape = rs.path(`M${rectangle.x} ${rectangle.y} L${rectangle.x + (rectangle.width * 3) / 4} ${rectangle.y} A ${rectangle.width /
1019
+ 4} ${rectangle.height / 2}, 0, 0, 1,${rectangle.x + (rectangle.width * 3) / 4} ${rectangle.y + rectangle.height} L${rectangle.x} ${rectangle.y + rectangle.height} Z`, { ...options, fillStyle: 'solid' });
1020
+ setStrokeLinecap(shape, 'round');
1021
+ return shape;
1022
+ },
1023
+ isHit(rectangle, point) {
1024
+ //split shape to rectangle and a half ellipse
1025
+ const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
1026
+ const isInRectangle = RectangleClient.isHit({
1027
+ ...rectangle,
1028
+ width: (rectangle.width * 3) / 4
1029
+ }, rangeRectangle);
1030
+ const isInEllipse = isPointInEllipse(point, [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 2], rectangle.width / 4, rectangle.height / 2);
1031
+ return isInRectangle || isInEllipse;
1032
+ },
1033
+ getCornerPoints(rectangle) {
1034
+ return RectangleClient.getCornerPoints(rectangle);
1035
+ },
1036
+ getNearestPoint(rectangle, point) {
1037
+ const nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
1038
+ if (nearestPoint[0] > rectangle.x + (rectangle.width * 3) / 4) {
1039
+ return getNearestPointBetweenPointAndEllipse(point, [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 2], rectangle.width / 4, rectangle.height / 2);
1040
+ }
1041
+ return nearestPoint;
1042
+ },
1043
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
1044
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1045
+ const centerPoint = [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 2];
1046
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
1047
+ const a = rectangle.width / 4;
1048
+ const b = rectangle.height / 2;
1049
+ const slope = getTangentSlope(point[0], point[1], a, b);
1050
+ return getVectorBySlope(point[0], point[1], slope);
1051
+ },
1052
+ getConnectorPoints(rectangle) {
1053
+ return RectangleClient.getEdgeCenterPoints(rectangle);
1054
+ }
1055
+ };
1056
+
1057
+ const StoredDataEngine = {
1058
+ draw(board, rectangle, options) {
1059
+ const rs = PlaitBoard.getRoughSVG(board);
1060
+ const shape = rs.path(`M${rectangle.x + rectangle.width / 10} ${rectangle.y} L${rectangle.x + rectangle.width} ${rectangle.y} A ${rectangle.width /
1061
+ 10} ${rectangle.height / 2}, 1, 0, 0,${rectangle.x + rectangle.width} ${rectangle.y + rectangle.height} L${rectangle.x +
1062
+ rectangle.width / 10} ${rectangle.y + rectangle.height}A ${rectangle.width / 10} ${rectangle.height /
1063
+ 2}, 0, 0, 1,${rectangle.x + rectangle.width / 10} ${rectangle.y}`, { ...options, fillStyle: 'solid' });
1064
+ setStrokeLinecap(shape, 'round');
1065
+ return shape;
1066
+ },
1067
+ isHit(rectangle, point) {
1068
+ //split shape to rectangle and a half ellipse
1069
+ const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
1070
+ const isInRectangle = RectangleClient.isHit({
1071
+ ...rectangle,
1072
+ x: rectangle.x + rectangle.width / 10,
1073
+ width: (rectangle.width * 9) / 10
1074
+ }, rangeRectangle);
1075
+ const isInFrontEllipse = isPointInEllipse(point, [rectangle.x + rectangle.width / 10, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1076
+ const notInBackEllipse = !isPointInEllipse(point, [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1077
+ return (isInRectangle && notInBackEllipse) || isInFrontEllipse;
1078
+ },
1079
+ getCornerPoints(rectangle) {
1080
+ return RectangleClient.getCornerPoints(rectangle);
1081
+ },
1082
+ getNearestPoint(rectangle, point) {
1083
+ const nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
1084
+ if (nearestPoint[0] < rectangle.x + rectangle.width / 10) {
1085
+ const nearestPoint = getNearestPointBetweenPointAndEllipse(point, [rectangle.x + rectangle.width / 10, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1086
+ if (nearestPoint[0] > rectangle.x + rectangle.width / 10) {
1087
+ nearestPoint[0] = (rectangle.x + rectangle.width / 10) * 2 - nearestPoint[0];
1088
+ }
1089
+ return nearestPoint;
1090
+ }
1091
+ if (nearestPoint[0] > rectangle.x + (rectangle.width * 9) / 10) {
1092
+ return getNearestPointBetweenPointAndEllipse(point, [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1093
+ }
1094
+ return nearestPoint;
1095
+ },
1096
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
1097
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1098
+ let centerPoint = [rectangle.x + rectangle.width / 10, rectangle.y + rectangle.height / 2];
1099
+ let a = rectangle.width / 10;
1100
+ let b = rectangle.height / 2;
1101
+ const isBackEllipse = connectionPoint[0] > rectangle.x + (rectangle.width * 9) / 10 && connectionPoint[1] > rectangle.y;
1102
+ if (isBackEllipse) {
1103
+ centerPoint = [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2];
1104
+ }
1105
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
1106
+ const slope = getTangentSlope(point[0], point[1], a, b);
1107
+ const vector = getVectorBySlope(point[0], point[1], slope);
1108
+ return isBackEllipse ? vector.map(num => -num) : vector;
1109
+ },
1110
+ getConnectorPoints(rectangle) {
1111
+ return [
1112
+ [rectangle.x + rectangle.width / 2, rectangle.y],
1113
+ [rectangle.x + (rectangle.width * 9) / 10, rectangle.y + rectangle.height / 2],
1114
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
1115
+ [rectangle.x, rectangle.y + rectangle.height / 2]
1116
+ ];
1117
+ },
1118
+ getTextRectangle(element) {
1119
+ const rectangle = getTextRectangle(element);
1120
+ const width = rectangle.width;
1121
+ rectangle.width = (rectangle.width * 3) / 4;
1122
+ rectangle.x += width / 8;
1123
+ return rectangle;
1124
+ }
1125
+ };
1126
+
343
1127
  const ShapeEngineMap = {
344
- [GeometryShape.rectangle]: RectangleEngine,
345
- [GeometryShape.diamond]: DiamondEngine,
346
- [GeometryShape.ellipse]: EllipseEngine,
347
- [GeometryShape.parallelogram]: ParallelogramEngine,
348
- [GeometryShape.roundRectangle]: RoundRectangleEngine,
349
- [GeometryShape.text]: RectangleEngine
1128
+ [BasicShapes.rectangle]: RectangleEngine,
1129
+ [BasicShapes.diamond]: DiamondEngine,
1130
+ [BasicShapes.ellipse]: EllipseEngine,
1131
+ [BasicShapes.parallelogram]: ParallelogramEngine,
1132
+ [BasicShapes.roundRectangle]: RoundRectangleEngine,
1133
+ [BasicShapes.text]: RectangleEngine,
1134
+ [BasicShapes.triangle]: TriangleEngine,
1135
+ [BasicShapes.leftArrow]: LeftArrowEngine,
1136
+ [BasicShapes.trapezoid]: TrapezoidEngine,
1137
+ [BasicShapes.rightArrow]: RightArrowEngine,
1138
+ [BasicShapes.cross]: CrossEngine,
1139
+ [BasicShapes.star]: StarEngine,
1140
+ [BasicShapes.pentagon]: PentagonEngine,
1141
+ [BasicShapes.hexagon]: HexagonEngine,
1142
+ [BasicShapes.octagon]: OctagonEngine,
1143
+ [BasicShapes.pentagonArrow]: PentagonArrowEngine,
1144
+ [BasicShapes.processArrow]: ProcessArrowEngine,
1145
+ [BasicShapes.twoWayArrow]: TwoWayArrowEngine,
1146
+ [BasicShapes.comment]: CommentEngine,
1147
+ [BasicShapes.roundComment]: RoundCommentEngine,
1148
+ [FlowchartSymbols.process]: RectangleEngine,
1149
+ [FlowchartSymbols.decision]: DiamondEngine,
1150
+ [FlowchartSymbols.connector]: EllipseEngine,
1151
+ [FlowchartSymbols.data]: ParallelogramEngine,
1152
+ [FlowchartSymbols.terminal]: TerminalEngine,
1153
+ [FlowchartSymbols.manualInput]: ManualInputEngine,
1154
+ [FlowchartSymbols.preparation]: PreparationEngine,
1155
+ [FlowchartSymbols.manualLoop]: ManualLoopEngine,
1156
+ [FlowchartSymbols.merge]: MergeEngine,
1157
+ [FlowchartSymbols.delay]: DelayEngine,
1158
+ [FlowchartSymbols.storedData]: StoredDataEngine
350
1159
  };
351
1160
  const getEngine = (shape) => {
352
1161
  return ShapeEngineMap[shape];
353
1162
  };
354
1163
 
1164
+ const getShape = (value) => {
1165
+ if (PlaitDrawElement.isImage(value)) {
1166
+ return BasicShapes.rectangle;
1167
+ }
1168
+ return value.shape;
1169
+ };
1170
+
355
1171
  const createGeometryElement = (shape, points, text, options) => {
356
1172
  let textOptions = {};
357
1173
  let alignment = Alignment.center;
358
- if (shape === GeometryShape.text) {
1174
+ if (shape === BasicShapes.text) {
359
1175
  textOptions = { autoSize: true };
360
1176
  alignment = undefined;
361
1177
  }
1178
+ let flowchartOptions = {};
1179
+ if (getFlowchartPointers().includes(shape)) {
1180
+ flowchartOptions = { fill: '#ffffff' };
1181
+ }
362
1182
  return {
363
1183
  id: idCreator(),
364
1184
  type: 'geometry',
@@ -369,7 +1189,8 @@ const createGeometryElement = (shape, points, text, options) => {
369
1189
  text: buildText(text, alignment),
370
1190
  points,
371
1191
  ...textOptions,
372
- ...options
1192
+ ...options,
1193
+ ...flowchartOptions
373
1194
  };
374
1195
  };
375
1196
  const getPointsByCenterPoint = (point, width, height) => {
@@ -393,14 +1214,15 @@ const drawBoundMask = (board, element) => {
393
1214
  const G = createG();
394
1215
  const rectangle = getRectangleByPoints(element.points);
395
1216
  const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
396
- const maskG = drawGeometry(board, activeRectangle, element.shape, {
1217
+ const shape = getShape(element);
1218
+ const maskG = drawGeometry(board, activeRectangle, shape, {
397
1219
  stroke: SELECTION_BORDER_COLOR,
398
1220
  strokeWidth: 1,
399
1221
  fill: SELECTION_FILL_COLOR,
400
1222
  fillStyle: 'solid'
401
1223
  });
402
1224
  G.appendChild(maskG);
403
- const connectorPoints = getEngine(element.shape).getConnectorPoints(activeRectangle);
1225
+ const connectorPoints = getEngine(shape).getConnectorPoints(activeRectangle);
404
1226
  connectorPoints.forEach(point => {
405
1227
  const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
406
1228
  stroke: '#999999',
@@ -418,7 +1240,8 @@ const drawGeometry = (board, outerRectangle, shape, options) => {
418
1240
  const getNearestPoint = (element, point, inflateDelta = 0) => {
419
1241
  const rectangle = getRectangleByPoints(element.points);
420
1242
  const activeRectangle = RectangleClient.inflate(rectangle, inflateDelta);
421
- return getEngine(element.shape).getNearestPoint(activeRectangle, point);
1243
+ const shape = getShape(element);
1244
+ return getEngine(shape).getNearestPoint(activeRectangle, point);
422
1245
  };
423
1246
  const getCenterPointsOnPolygon = (points) => {
424
1247
  const centerPoint = [];
@@ -428,6 +1251,20 @@ const getCenterPointsOnPolygon = (points) => {
428
1251
  }
429
1252
  return centerPoint;
430
1253
  };
1254
+ const getEdgeOnPolygonByPoint = (corners, point) => {
1255
+ for (let index = 1; index <= corners.length; index++) {
1256
+ let start = corners[index - 1];
1257
+ let end = index === corners.length ? corners[0] : corners[index];
1258
+ const distance = distanceBetweenPointAndSegment(point[0], point[1], start[0], start[1], end[0], end[1]);
1259
+ if (distance < 1) {
1260
+ return [start, end];
1261
+ }
1262
+ }
1263
+ return null;
1264
+ };
1265
+ const getDefaultFlowchartProperty = (symbol) => {
1266
+ return DefaultFlowchartPropertyMap[symbol];
1267
+ };
431
1268
 
432
1269
  const drawLineArrow = (element, points, options) => {
433
1270
  const arrowG = createG();
@@ -435,16 +1272,19 @@ const drawLineArrow = (element, points, options) => {
435
1272
  return null;
436
1273
  }
437
1274
  if (!PlaitLine.isSourceMark(element, LineMarkerType.none)) {
438
- const sourceArrow = getArrow(element, element.source.marker, points[1], points[0], options);
1275
+ const source = getExtendPoint(points[0], points[1], 24);
1276
+ const sourceArrow = getArrow(element, { marker: element.source.marker, source, target: points[0], isSource: true }, options);
439
1277
  sourceArrow && arrowG.appendChild(sourceArrow);
440
1278
  }
441
1279
  if (!PlaitLine.isTargetMark(element, LineMarkerType.none)) {
442
- const arrow = getArrow(element, element.target.marker, points[points.length - 2], points[points.length - 1], options);
1280
+ const source = getExtendPoint(points[points.length - 1], points[points.length - 2], 24);
1281
+ const arrow = getArrow(element, { marker: element.target.marker, source, target: points[points.length - 1], isSource: false }, options);
443
1282
  arrow && arrowG.appendChild(arrow);
444
1283
  }
445
1284
  return arrowG;
446
1285
  };
447
- const getArrow = (element, marker, source, target, options) => {
1286
+ const getArrow = (element, arrowOptions, options) => {
1287
+ const { marker, source, target, isSource } = arrowOptions;
448
1288
  let targetArrow;
449
1289
  switch (marker) {
450
1290
  case LineMarkerType.openTriangle: {
@@ -463,16 +1303,27 @@ const getArrow = (element, marker, source, target, options) => {
463
1303
  targetArrow = drawSharpArrow(source, target, options);
464
1304
  break;
465
1305
  }
1306
+ case LineMarkerType.oneSideUp: {
1307
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'down' : 'up', options);
1308
+ break;
1309
+ }
1310
+ case LineMarkerType.oneSideDown: {
1311
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'up' : 'down', options);
1312
+ break;
1313
+ }
1314
+ case LineMarkerType.hollowTriangle: {
1315
+ targetArrow = drawHollowTriangleArrow(source, target, options);
1316
+ break;
1317
+ }
1318
+ case LineMarkerType.singleSlash: {
1319
+ targetArrow = drawSingleSlash(source, target, isSource, options);
1320
+ break;
1321
+ }
466
1322
  }
467
1323
  return targetArrow;
468
1324
  };
469
1325
  const drawSharpArrow = (source, target, options) => {
470
- const directionFactor = getFactorByPoints(source, target);
471
1326
  const startPoint = target;
472
- // const startPoint: Point = [
473
- // target[0],
474
- // target[1]
475
- // ];
476
1327
  const { pointLeft, pointRight } = arrowPoints(source, target, 12, 20);
477
1328
  const g = createG();
478
1329
  const path = createPath();
@@ -487,10 +1338,7 @@ const drawSharpArrow = (source, target, options) => {
487
1338
  const drawArrow = (element, source, target, options) => {
488
1339
  const directionFactor = getFactorByPoints(source, target);
489
1340
  const strokeWidth = getStrokeWidthByElement(element);
490
- const endPoint = [
491
- target[0] + strokeWidth * directionFactor.x / 2,
492
- target[1] + strokeWidth * directionFactor.y / 2
493
- ];
1341
+ const endPoint = [target[0] + (strokeWidth * directionFactor.x) / 2, target[1] + (strokeWidth * directionFactor.y) / 2];
494
1342
  const middlePoint = [endPoint[0] - 8 * directionFactor.x, endPoint[1] - 8 * directionFactor.y];
495
1343
  const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 30);
496
1344
  const arrowG = drawLinearPath([pointLeft, endPoint, pointRight, middlePoint], { ...options, fill: options.stroke }, true);
@@ -506,13 +1354,26 @@ const drawSolidTriangle = (source, target, options) => {
506
1354
  const drawOpenTriangle = (element, source, target, options) => {
507
1355
  const directionFactor = getFactorByPoints(source, target);
508
1356
  const strokeWidth = getStrokeWidthByElement(element);
509
- const endPoint = [
510
- target[0] + strokeWidth * directionFactor.x / 2,
511
- target[1] + strokeWidth * directionFactor.y / 2
512
- ];
1357
+ const endPoint = [target[0] + (strokeWidth * directionFactor.x) / 2, target[1] + (strokeWidth * directionFactor.y) / 2];
513
1358
  const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 40);
514
1359
  return drawLinearPath([pointLeft, endPoint, pointRight], options);
515
1360
  };
1361
+ const drawOneSideArrow = (source, target, side, options) => {
1362
+ const { pointLeft, pointRight } = arrowPoints(source, target, 12, 40);
1363
+ return drawLinearPath([side === 'up' ? pointRight : pointLeft, target], options);
1364
+ };
1365
+ const drawSingleSlash = (source, target, isSource, options) => {
1366
+ source = getExtendPoint(target, source, 12);
1367
+ const middlePoint = getExtendPoint(target, source, 6);
1368
+ const angle = isSource ? 120 : 60;
1369
+ const start = rotate(...source, ...middlePoint, (angle * Math.PI) / 180);
1370
+ const end = rotate(...target, ...middlePoint, (angle * Math.PI) / 180);
1371
+ return drawLinearPath([start, end], options);
1372
+ };
1373
+ const drawHollowTriangleArrow = (source, target, options) => {
1374
+ const { pointLeft, pointRight } = arrowPoints(source, target, 12, 30);
1375
+ return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
1376
+ };
516
1377
 
517
1378
  const createLineElement = (shape, points, source, target, options) => {
518
1379
  return {
@@ -528,28 +1389,127 @@ const createLineElement = (shape, points, source, target, options) => {
528
1389
  };
529
1390
  };
530
1391
  const getLinePoints = (board, element) => {
531
- return element.shape === LineShape.elbow ? getElbowPoints(board, element) : getStraightPoints(board, element);
1392
+ switch (element.shape) {
1393
+ case LineShape.elbow: {
1394
+ return getElbowPoints(board, element);
1395
+ }
1396
+ case LineShape.curve: {
1397
+ return getCurvePoints(board, element);
1398
+ }
1399
+ default: {
1400
+ return PlaitLine.getPoints(board, element);
1401
+ }
1402
+ }
532
1403
  };
533
- const getStraightPoints = (board, element) => {
534
- return [getSourcePoint(board, element), getTargetPoint(board, element)];
1404
+ const getLineHandleRefPair = (board, element) => {
1405
+ const strokeWidth = getStrokeWidthByElement(element);
1406
+ const sourceBoundElement = element.source.boundId ? getElementById(board, element.source.boundId) : undefined;
1407
+ const targetBoundElement = element.target.boundId ? getElementById(board, element.target.boundId) : undefined;
1408
+ let sourcePoint = sourceBoundElement ? getConnectionPoint(sourceBoundElement, element.source.connection) : element.points[0];
1409
+ let targetPoint = targetBoundElement
1410
+ ? getConnectionPoint(targetBoundElement, element.target.connection)
1411
+ : element.points[element.points.length - 1];
1412
+ let sourceDirection = getDirectionByVector([targetPoint[0] - sourcePoint[0], targetPoint[1] - sourcePoint[1]]);
1413
+ let targetDirection = getOppositeDirection(sourceDirection);
1414
+ const sourceFactor = getDirectionFactor(sourceDirection);
1415
+ const targetFactor = getDirectionFactor(targetDirection);
1416
+ const sourceHandleRef = {
1417
+ key: LineHandleKey.source,
1418
+ point: sourcePoint,
1419
+ direction: sourceDirection,
1420
+ vector: [sourceFactor.x, sourceFactor.y]
1421
+ };
1422
+ const targetHandleRef = {
1423
+ key: LineHandleKey.target,
1424
+ point: targetPoint,
1425
+ direction: targetDirection,
1426
+ vector: [targetFactor.x, targetFactor.y]
1427
+ };
1428
+ if (sourceBoundElement) {
1429
+ const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.source) ? 0 : strokeWidth;
1430
+ const sourceVector = getVectorByConnection(sourceBoundElement, element.source.connection);
1431
+ const direction = getDirectionByVector(sourceVector);
1432
+ sourceDirection = direction ? direction : sourceDirection;
1433
+ sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
1434
+ sourceHandleRef.boundElement = sourceBoundElement;
1435
+ sourceHandleRef.direction = sourceDirection;
1436
+ sourceHandleRef.point = sourcePoint;
1437
+ sourceHandleRef.vector = sourceVector;
1438
+ }
1439
+ if (targetBoundElement) {
1440
+ const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.target) ? 0 : strokeWidth;
1441
+ const targetVector = getVectorByConnection(targetBoundElement, element.target.connection);
1442
+ const direction = getDirectionByVector(targetVector);
1443
+ targetDirection = direction ? direction : targetDirection;
1444
+ targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
1445
+ targetHandleRef.boundElement = targetBoundElement;
1446
+ targetHandleRef.direction = targetDirection;
1447
+ targetHandleRef.point = targetPoint;
1448
+ targetHandleRef.vector = targetVector;
1449
+ }
1450
+ return { source: sourceHandleRef, target: targetHandleRef };
535
1451
  };
536
1452
  const getElbowPoints = (board, element) => {
537
1453
  if (element.points.length === 2) {
538
- const source = getSourcePoint(board, element);
539
- const target = getTargetPoint(board, element);
540
- let sourceDirection = source[0] < target[0] ? Direction.right : Direction.left;
541
- let targetDirection = source[0] < target[0] ? Direction.left : Direction.right;
542
- if (element.source.connection) {
543
- sourceDirection = getDirectionByPoint(element.source.connection, sourceDirection);
544
- }
545
- if (element.target.connection) {
546
- targetDirection = getDirectionByPoint(element.target.connection, targetDirection);
547
- }
548
- const points = getPoints(source, sourceDirection, target, targetDirection, 30);
1454
+ const handleRefPair = getLineHandleRefPair(board, element);
1455
+ const offset = element.source.boundId || element.target.boundId ? 30 : 0;
1456
+ let points = getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, offset);
1457
+ points = removeDuplicatePoints(points);
549
1458
  return points;
550
1459
  }
551
1460
  return element.points;
552
1461
  };
1462
+ const getCurvePoints = (board, element) => {
1463
+ if (element.points.length === 2) {
1464
+ const handleRefPair = getLineHandleRefPair(board, element);
1465
+ const { source, target } = handleRefPair;
1466
+ const sourceBoundElement = handleRefPair.source.boundElement;
1467
+ const targetBoundElement = handleRefPair.target.boundElement;
1468
+ let curvePoints = [source.point];
1469
+ const sumDistance = distanceBetweenPointAndPoint(...source.point, ...target.point);
1470
+ const offset = 12 + sumDistance / 3;
1471
+ if (sourceBoundElement) {
1472
+ curvePoints.push(getPointByVector(source.point, source.vector, offset));
1473
+ }
1474
+ if (targetBoundElement) {
1475
+ curvePoints.push(getPointByVector(target.point, target.vector, offset));
1476
+ }
1477
+ const isSingleBound = (sourceBoundElement && !targetBoundElement) || (!sourceBoundElement && targetBoundElement);
1478
+ if (isSingleBound) {
1479
+ curvePoints.push(target.point);
1480
+ const points = Q2C(curvePoints);
1481
+ return pointsOnBezierCurves(points);
1482
+ }
1483
+ if (!sourceBoundElement && !targetBoundElement) {
1484
+ curvePoints.push(getPointByVector(source.point, source.vector, offset));
1485
+ curvePoints.push(getPointByVector(target.point, target.vector, offset));
1486
+ }
1487
+ curvePoints.push(target.point);
1488
+ return pointsOnBezierCurves(curvePoints);
1489
+ }
1490
+ else {
1491
+ //TODO 直接获取贝塞尔曲线上高密度点
1492
+ const points = PlaitLine.getPoints(board, element);
1493
+ const draw = PlaitBoard.getRoughSVG(board).generator.curve(points);
1494
+ let bezierPoints = transformOpsToPoints(draw.sets[0].ops);
1495
+ bezierPoints = removeDuplicatePoints(bezierPoints);
1496
+ return pointsOnBezierCurves(bezierPoints);
1497
+ }
1498
+ };
1499
+ const transformOpsToPoints = (ops) => {
1500
+ const result = [];
1501
+ for (let item of ops) {
1502
+ if (item.op === 'move') {
1503
+ result.push([item.data[0], item.data[1]]);
1504
+ }
1505
+ else {
1506
+ result.push([item.data[0], item.data[1]]);
1507
+ result.push([item.data[2], item.data[3]]);
1508
+ result.push([item.data[4], item.data[5]]);
1509
+ }
1510
+ }
1511
+ return result;
1512
+ };
553
1513
  const isHitPolyLine = (pathPoints, point, strokeWidth, expand = 0) => {
554
1514
  const distance = distanceBetweenPointAndSegments(pathPoints, point);
555
1515
  return distance <= strokeWidth + expand;
@@ -579,20 +1539,28 @@ const drawLine = (board, element) => {
579
1539
  const strokeLineDash = getLineDashByElement(element);
580
1540
  const options = { stroke: strokeColor, strokeWidth, strokeLineDash };
581
1541
  const lineG = createG();
582
- const points = getLinePoints(board, element);
583
- const line = drawLinearPath(points, options);
584
- line.setAttribute('mask', `url(#${element.id})`);
1542
+ let points = getLinePoints(board, element);
1543
+ let line;
1544
+ if (element.shape === LineShape.curve) {
1545
+ //TODO element.points 应为曲线拐点
1546
+ line = PlaitBoard.getRoughSVG(board).curve(points, options);
1547
+ }
1548
+ else {
1549
+ line = drawLinearPath(points, options);
1550
+ }
1551
+ const id = idCreator();
1552
+ line.setAttribute('mask', `url(#${id})`);
585
1553
  lineG.appendChild(line);
586
- const { mask, maskTargetFillRect } = drawMask(board, element);
1554
+ const { mask, maskTargetFillRect } = drawMask(board, element, id);
587
1555
  lineG.appendChild(mask);
588
1556
  line.appendChild(maskTargetFillRect);
589
1557
  const arrow = drawLineArrow(element, points, { stroke: strokeColor, strokeWidth });
590
1558
  arrow && lineG.appendChild(arrow);
591
1559
  return lineG;
592
1560
  };
593
- function drawMask(board, element) {
1561
+ function drawMask(board, element, id) {
594
1562
  const mask = createMask();
595
- mask.setAttribute('id', element.id);
1563
+ mask.setAttribute('id', id);
596
1564
  const points = getLinePoints(board, element);
597
1565
  let rectangle = getRectangleByPoints(points);
598
1566
  rectangle = RectangleClient.getOutlineRectangle(rectangle, -30);
@@ -613,33 +1581,16 @@ function drawMask(board, element) {
613
1581
  maskTargetFillRect.setAttribute('opacity', '0');
614
1582
  return { mask, maskTargetFillRect };
615
1583
  }
616
- const getSourcePoint = (board, element) => {
617
- if (element.source.boundId) {
618
- const strokeWidth = getStrokeWidthByElement(element);
619
- const connectionOffset = PlaitLine.isSourceMark(element, LineMarkerType.none) ? 0 : strokeWidth;
620
- const boundElement = getElementById(board, element.source.boundId);
621
- return boundElement ? getConnectionPoint(boundElement, element.source.connection, connectionOffset) : element.points[0];
1584
+ const getConnectionPoint = (geometry, connection, direction, delta) => {
1585
+ const rectangle = getRectangleByPoints(geometry.points);
1586
+ if (direction && delta) {
1587
+ const directionFactor = getDirectionFactor(direction);
1588
+ const point = RectangleClient.getConnectionPoint(rectangle, connection);
1589
+ return [point[0] + directionFactor.x * delta, point[1] + directionFactor.y * delta];
622
1590
  }
623
- return element.points[0];
624
- };
625
- const getTargetPoint = (board, element) => {
626
- if (element.target.boundId) {
627
- const strokeWidth = getStrokeWidthByElement(element);
628
- const connectionOffset = PlaitLine.isTargetMark(element, LineMarkerType.none) ? 0 : strokeWidth;
629
- const boundElement = getElementById(board, element.target.boundId);
630
- return boundElement
631
- ? getConnectionPoint(boundElement, element.target.connection, connectionOffset)
632
- : element.points[element.points.length - 1];
1591
+ else {
1592
+ return RectangleClient.getConnectionPoint(rectangle, connection);
633
1593
  }
634
- return element.points[element.points.length - 1];
635
- };
636
- const getConnectionPoint = (geometry, connection, offset) => {
637
- const rectangle = getRectangleByPoints(geometry.points);
638
- const directionFactor = getDirectionFactor(getDirectionByPoint(connection, Direction.bottom));
639
- return [
640
- rectangle.x + rectangle.width * connection[0] + directionFactor.x * offset,
641
- rectangle.y + rectangle.height * connection[1] + directionFactor.y * offset
642
- ];
643
1594
  };
644
1595
  const transformPointToConnection = (board, point, hitElement) => {
645
1596
  let rectangle = getRectangleByPoints(hitElement.points);
@@ -650,7 +1601,8 @@ const transformPointToConnection = (board, point, hitElement) => {
650
1601
  return [(nearestPoint[0] - rectangle.x) / rectangle.width, (nearestPoint[1] - rectangle.y) / rectangle.height];
651
1602
  };
652
1603
  const getHitConnectorPoint = (movingPoint, hitElement, rectangle) => {
653
- const connector = getEngine(hitElement.shape).getConnectorPoints(rectangle);
1604
+ const shape = getShape(hitElement);
1605
+ const connector = getEngine(shape).getConnectorPoints(rectangle);
654
1606
  const points = getPointsByCenterPoint(movingPoint, 5, 5);
655
1607
  const pointRectangle = getRectangleByPoints(points);
656
1608
  return connector.find(point => {
@@ -674,6 +1626,64 @@ const getBoardLines = (board) => {
674
1626
  recursion: (element) => PlaitDrawElement.isDrawElement(element)
675
1627
  });
676
1628
  };
1629
+ const removeDuplicatePoints = (points) => {
1630
+ const newArray = [];
1631
+ points.forEach(point => {
1632
+ const index = newArray.findIndex(otherPoint => {
1633
+ return point[0] === otherPoint[0] && point[1] === otherPoint[1];
1634
+ });
1635
+ if (index === -1)
1636
+ newArray.push(point);
1637
+ });
1638
+ return newArray;
1639
+ };
1640
+ const getExtendPoint = (source, target, extendDistance) => {
1641
+ const distance = distanceBetweenPointAndPoint(...source, ...target);
1642
+ const sin = (target[1] - source[1]) / distance;
1643
+ const cos = (target[0] - source[0]) / distance;
1644
+ return [source[0] + extendDistance * cos, source[1] + extendDistance * sin];
1645
+ };
1646
+ // quadratic Bezier to cubic Bezier
1647
+ const Q2C = (points) => {
1648
+ const result = [];
1649
+ const numSegments = points.length / 3;
1650
+ for (let i = 0; i < numSegments; i++) {
1651
+ const start = points[i];
1652
+ const qControl = points[i + 1];
1653
+ const end = points[i + 2];
1654
+ const startDistance = distanceBetweenPointAndPoint(...start, ...qControl);
1655
+ const endDistance = distanceBetweenPointAndPoint(...end, ...qControl);
1656
+ const cControl1 = getExtendPoint(start, qControl, (startDistance * 2) / 3);
1657
+ const cControl2 = getExtendPoint(end, qControl, (endDistance * 2) / 3);
1658
+ result.push(start, cControl1, cControl2, end);
1659
+ }
1660
+ return result;
1661
+ };
1662
+ const getVectorByConnection = (boundElement, connection) => {
1663
+ const rectangle = getRectangleByPoints(boundElement.points);
1664
+ const shape = getShape(boundElement);
1665
+ const engine = getEngine(shape);
1666
+ let vector = [0, 0];
1667
+ const direction = getDirectionByPointOfRectangle(connection);
1668
+ if (direction) {
1669
+ const factor = getDirectionFactor(direction);
1670
+ return [factor.x, factor.y];
1671
+ }
1672
+ if (engine.getEdgeByConnectionPoint) {
1673
+ const edge = engine.getEdgeByConnectionPoint(rectangle, connection);
1674
+ if (edge) {
1675
+ const lineVector = [edge[1][0] - edge[0][0], edge[1][1] - edge[0][1]];
1676
+ return rotateVectorAnti90(lineVector);
1677
+ }
1678
+ }
1679
+ if (engine.getTangentVectorByConnectionPoint) {
1680
+ const lineVector = engine.getTangentVectorByConnectionPoint(rectangle, connection);
1681
+ if (lineVector) {
1682
+ return rotateVectorAnti90(lineVector);
1683
+ }
1684
+ }
1685
+ return vector;
1686
+ };
677
1687
 
678
1688
  const getSelectedDrawElements = (board) => {
679
1689
  const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isDrawElement(value));
@@ -687,6 +1697,117 @@ const getSelectedLineElements = (board) => {
687
1697
  const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isLine(value));
688
1698
  return selectedElements;
689
1699
  };
1700
+ const getSelectedImageElements = (board) => {
1701
+ const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isImage(value));
1702
+ return selectedElements;
1703
+ };
1704
+
1705
+ var LineMarkerType;
1706
+ (function (LineMarkerType) {
1707
+ LineMarkerType["arrow"] = "arrow";
1708
+ LineMarkerType["none"] = "none";
1709
+ LineMarkerType["openTriangle"] = "open-triangle";
1710
+ LineMarkerType["solidTriangle"] = "solid-triangle";
1711
+ LineMarkerType["sharpArrow"] = "sharp-arrow";
1712
+ LineMarkerType["oneSideUp"] = "one-side-up";
1713
+ LineMarkerType["oneSideDown"] = "one-side-down";
1714
+ LineMarkerType["hollowTriangle"] = "hollow-triangle";
1715
+ LineMarkerType["singleSlash"] = "single-slash";
1716
+ })(LineMarkerType || (LineMarkerType = {}));
1717
+ var LineShape;
1718
+ (function (LineShape) {
1719
+ LineShape["straight"] = "straight";
1720
+ LineShape["curve"] = "curve";
1721
+ LineShape["elbow"] = "elbow";
1722
+ })(LineShape || (LineShape = {}));
1723
+ var LineHandleKey;
1724
+ (function (LineHandleKey) {
1725
+ LineHandleKey["source"] = "source";
1726
+ LineHandleKey["target"] = "target";
1727
+ })(LineHandleKey || (LineHandleKey = {}));
1728
+ const PlaitLine = {
1729
+ getTextEditors(element) {
1730
+ const component = PlaitElement.getComponent(element);
1731
+ if (component) {
1732
+ const manage = component.textManages.find(manage => manage.isEditing);
1733
+ if (manage) {
1734
+ return [manage.componentRef.instance.editor];
1735
+ }
1736
+ else {
1737
+ return component.textManages.map(manage => manage.componentRef.instance.editor);
1738
+ }
1739
+ }
1740
+ throw new Error('can not get correctly component in get text editor');
1741
+ },
1742
+ isSourceMarkOrTargetMark(line, markType, handleKey) {
1743
+ if (handleKey === LineHandleKey.source) {
1744
+ return line.source.marker === markType;
1745
+ }
1746
+ else {
1747
+ return line.target.marker === markType;
1748
+ }
1749
+ },
1750
+ isSourceMark(line, markType) {
1751
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.source);
1752
+ },
1753
+ isTargetMark(line, markType) {
1754
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.target);
1755
+ },
1756
+ isBoundElementOfSource(line, element) {
1757
+ return line.source.boundId === element.id;
1758
+ },
1759
+ isBoundElementOfTarget(line, element) {
1760
+ return line.target.boundId === element.id;
1761
+ },
1762
+ getPoints(board, line) {
1763
+ let sourcePoint = line.source.boundId
1764
+ ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
1765
+ : line.points[0];
1766
+ let targetPoint = line.target.boundId
1767
+ ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
1768
+ : line.points[line.points.length - 1];
1769
+ const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
1770
+ return [sourcePoint, ...restPoints, targetPoint];
1771
+ }
1772
+ };
1773
+
1774
+ var StrokeStyle;
1775
+ (function (StrokeStyle) {
1776
+ StrokeStyle["solid"] = "solid";
1777
+ StrokeStyle["dashed"] = "dashed";
1778
+ })(StrokeStyle || (StrokeStyle = {}));
1779
+
1780
+ const PlaitDrawElement = {
1781
+ isGeometry: (value) => {
1782
+ return value.type === 'geometry';
1783
+ },
1784
+ isLine: (value) => {
1785
+ return value.type === 'line';
1786
+ },
1787
+ isText: (value) => {
1788
+ return value.type === 'geometry' && value.shape === BasicShapes.text;
1789
+ },
1790
+ isImage: (value) => {
1791
+ return value.type === 'image';
1792
+ },
1793
+ isDrawElement: (value) => {
1794
+ if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value) || PlaitDrawElement.isImage(value)) {
1795
+ return true;
1796
+ }
1797
+ else {
1798
+ return false;
1799
+ }
1800
+ },
1801
+ isShape: (value) => {
1802
+ return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
1803
+ },
1804
+ isBaseShape: (value) => {
1805
+ return Object.keys(BasicShapes).includes(value.type);
1806
+ },
1807
+ isFlowchart: (value) => {
1808
+ return Object.keys(FlowchartSymbols).includes(value.type);
1809
+ }
1810
+ };
690
1811
 
691
1812
  class GeometryShapeGenerator extends Generator {
692
1813
  canDraw(element, data) {
@@ -695,28 +1816,33 @@ class GeometryShapeGenerator extends Generator {
695
1816
  baseDraw(element, data) {
696
1817
  const rectangle = getRectangleByPoints(element.points);
697
1818
  const shape = element.shape;
698
- if (shape === GeometryShape.text) {
1819
+ if (shape === BasicShapes.text) {
699
1820
  return;
700
1821
  }
701
1822
  const strokeWidth = getStrokeWidthByElement(element);
702
1823
  const strokeColor = getStrokeColorByElement(element);
703
1824
  const fill = getFillByElement(element);
704
1825
  const strokeLineDash = getLineDashByElement(element);
705
- return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, { stroke: strokeColor, strokeWidth, fill, strokeLineDash });
1826
+ return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
1827
+ stroke: strokeColor,
1828
+ strokeWidth,
1829
+ fill,
1830
+ strokeLineDash
1831
+ });
706
1832
  }
707
1833
  }
708
1834
 
709
1835
  const insertGeometry = (board, points, shape) => {
710
1836
  let newElement = createGeometryElement(shape, points, '', {
711
- strokeColor: DefaultGeometryProperty.strokeColor,
712
- strokeWidth: DefaultGeometryProperty.strokeWidth
1837
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1838
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
713
1839
  });
714
1840
  Transforms.insertNode(board, newElement, [board.children.length]);
715
1841
  clearSelectedElement(board);
716
1842
  addSelectedElement(board, newElement);
717
1843
  };
718
1844
  const insertText = (board, points, text = '文本') => {
719
- let newElement = createGeometryElement(GeometryShape.text, points, text);
1845
+ let newElement = createGeometryElement(BasicShapes.text, points, text);
720
1846
  Transforms.insertNode(board, newElement, [board.children.length]);
721
1847
  clearSelectedElement(board);
722
1848
  addSelectedElement(board, newElement);
@@ -782,6 +1908,28 @@ const setTextSize = (board, element, textWidth, textHeight) => {
782
1908
  }
783
1909
  };
784
1910
 
1911
+ const insertImage = (board, imageItem, startPoint) => {
1912
+ const { width, height, url } = imageItem;
1913
+ const host = BOARD_TO_HOST.get(board);
1914
+ const viewportWidth = PlaitBoard.getComponent(board).nativeElement.clientWidth;
1915
+ const viewportHeight = PlaitBoard.getComponent(board).nativeElement.clientHeight;
1916
+ const point = transformPoint(board, toPoint(viewportWidth / 2, viewportHeight / 2, host));
1917
+ const points = startPoint
1918
+ ? [startPoint, [startPoint[0] + width, startPoint[1] + height]]
1919
+ : [
1920
+ [point[0] - width / 2, point[1] - height / 2],
1921
+ [point[0] + width / 2, point[1] + height / 2]
1922
+ ];
1923
+ const imageElement = {
1924
+ id: idCreator(),
1925
+ type: 'image',
1926
+ points,
1927
+ url
1928
+ };
1929
+ Transforms.insertNode(board, imageElement, [board.children.length]);
1930
+ Transforms.addSelectionWithTemporaryElements(board, [imageElement]);
1931
+ };
1932
+
785
1933
  const resizeLine = (board, options, path) => {
786
1934
  Transforms.setNode(board, options, path);
787
1935
  };
@@ -812,7 +1960,8 @@ const DrawTransforms = {
812
1960
  resizeLine,
813
1961
  setLineTexts,
814
1962
  removeLineText,
815
- setLineMark
1963
+ setLineMark,
1964
+ insertImage
816
1965
  };
817
1966
 
818
1967
  class GeometryComponent extends CommonPluginElement {
@@ -830,10 +1979,10 @@ class GeometryComponent extends CommonPluginElement {
830
1979
  getStrokeWidth: () => {
831
1980
  const selectedElements = getSelectedElements(this.board);
832
1981
  if (selectedElements.length === 1 && !isSelectionMoving(this.board)) {
833
- return DefaultGeometryActiveStyle.strokeWidth;
1982
+ return ACTIVE_STROKE_WIDTH;
834
1983
  }
835
1984
  else {
836
- return DefaultGeometryActiveStyle.selectionStrokeWidth;
1985
+ return ACTIVE_STROKE_WIDTH;
837
1986
  }
838
1987
  },
839
1988
  getStrokeOpacity: () => {
@@ -896,6 +2045,10 @@ class GeometryComponent extends CommonPluginElement {
896
2045
  const plugins = this.board.getPluginOptions(WithTextPluginKey).textPlugins;
897
2046
  const manage = new TextManage(this.board, this.viewContainerRef, {
898
2047
  getRectangle: () => {
2048
+ const getRectangle = getEngine(this.element.shape).getTextRectangle;
2049
+ if (getRectangle) {
2050
+ return getRectangle(this.element);
2051
+ }
899
2052
  return getTextRectangle(this.element);
900
2053
  },
901
2054
  onValueChangeHandle: (textManageRef) => {
@@ -909,7 +2062,11 @@ class GeometryComponent extends CommonPluginElement {
909
2062
  }
910
2063
  },
911
2064
  getMaxWidth: () => {
912
- const width = getTextRectangle(this.element).width;
2065
+ let width = getTextRectangle(this.element).width;
2066
+ const getRectangle = getEngine(this.element.shape).getTextRectangle;
2067
+ if (getRectangle) {
2068
+ width = getRectangle(this.element).width;
2069
+ }
913
2070
  return this.element?.autoSize ? GeometryThreshold.defaultTextMaxWidth : width;
914
2071
  },
915
2072
  textPlugins: plugins
@@ -922,15 +2079,16 @@ class GeometryComponent extends CommonPluginElement {
922
2079
  this.destroy$.next();
923
2080
  this.destroy$.complete();
924
2081
  }
925
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: GeometryComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
926
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: GeometryComponent, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2082
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GeometryComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2083
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: GeometryComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
927
2084
  }
928
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: GeometryComponent, decorators: [{
2085
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GeometryComponent, decorators: [{
929
2086
  type: Component,
930
2087
  args: [{
931
2088
  selector: 'plait-draw-geometry',
932
2089
  template: ``,
933
- changeDetection: ChangeDetectionStrategy.OnPush
2090
+ changeDetection: ChangeDetectionStrategy.OnPush,
2091
+ standalone: true
934
2092
  }]
935
2093
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
936
2094
 
@@ -939,21 +2097,17 @@ class LineShapeGenerator extends Generator {
939
2097
  return true;
940
2098
  }
941
2099
  baseDraw(element, data) {
942
- const shape = element.shape;
943
2100
  let lineG;
944
- switch (shape) {
945
- case LineShape.elbow:
946
- case LineShape.straight:
947
- lineG = drawLine(this.board, element);
948
- break;
949
- default:
950
- break;
951
- }
2101
+ lineG = drawLine(this.board, element);
952
2102
  return lineG;
953
2103
  }
954
2104
  }
955
2105
 
956
2106
  class LineActiveGenerator extends Generator {
2107
+ constructor() {
2108
+ super(...arguments);
2109
+ this.hasResizeHandle = false;
2110
+ }
957
2111
  canDraw(element, data) {
958
2112
  if (data.selected) {
959
2113
  return true;
@@ -964,27 +2118,70 @@ class LineActiveGenerator extends Generator {
964
2118
  }
965
2119
  baseDraw(element, data) {
966
2120
  const activeG = createG();
967
- activeG.classList.add('active');
968
- activeG.classList.add('line-handle');
969
- const sourcePoint = getSourcePoint(this.board, element);
970
- const targetPoint = getTargetPoint(this.board, element);
971
- const sourceCircle = drawCircle(PlaitBoard.getRoughSVG(this.board), sourcePoint, RESIZE_HANDLE_DIAMETER, {
972
- stroke: '#999999',
973
- strokeWidth: 1,
974
- fill: '#FFF',
975
- fillStyle: 'solid'
976
- });
977
- const targetCircle = drawCircle(PlaitBoard.getRoughSVG(this.board), targetPoint, RESIZE_HANDLE_DIAMETER, {
978
- stroke: '#999999',
979
- strokeWidth: 1,
980
- fill: '#FFF',
981
- fillStyle: 'solid'
982
- });
983
- activeG.appendChild(targetCircle);
984
- activeG.appendChild(sourceCircle);
2121
+ if (this.hasResizeHandle) {
2122
+ activeG.classList.add('active');
2123
+ activeG.classList.add('line-handle');
2124
+ const points = PlaitLine.getPoints(this.board, element);
2125
+ points.forEach(point => {
2126
+ const circle = drawCircle(PlaitBoard.getRoughSVG(this.board), point, RESIZE_HANDLE_DIAMETER, {
2127
+ stroke: '#999999',
2128
+ strokeWidth: 1,
2129
+ fill: '#FFF',
2130
+ fillStyle: 'solid'
2131
+ });
2132
+ activeG.appendChild(circle);
2133
+ });
2134
+ getMiddlePoints(this.board, element).forEach(point => {
2135
+ const circle = drawCircle(PlaitBoard.getRoughSVG(this.board), point, RESIZE_HANDLE_DIAMETER, {
2136
+ stroke: '#FFFFFF80',
2137
+ strokeWidth: 1,
2138
+ fill: `${PRIMARY_COLOR}80`,
2139
+ fillStyle: 'solid'
2140
+ });
2141
+ activeG.appendChild(circle);
2142
+ });
2143
+ }
2144
+ else {
2145
+ const points = getLinePoints(this.board, element);
2146
+ const activeRectangle = getRectangleByPoints(points);
2147
+ const strokeG = drawRectangle(this.board, activeRectangle, {
2148
+ stroke: PRIMARY_COLOR,
2149
+ strokeWidth: DefaultGeometryActiveStyle.selectionStrokeWidth
2150
+ });
2151
+ activeG.appendChild(strokeG);
2152
+ }
985
2153
  return activeG;
986
2154
  }
987
2155
  }
2156
+ function getMiddlePoints(board, element) {
2157
+ const result = [];
2158
+ const shape = element.shape;
2159
+ if (shape === LineShape.straight) {
2160
+ const points = PlaitLine.getPoints(board, element);
2161
+ for (let i = 0; i < points.length - 1; i++) {
2162
+ result.push([(points[i][0] + points[i + 1][0]) / 2, (points[i][1] + points[i + 1][1]) / 2]);
2163
+ }
2164
+ }
2165
+ if (shape === LineShape.curve) {
2166
+ const points = PlaitLine.getPoints(board, element);
2167
+ const pointsOnBezier = getCurvePoints(board, element);
2168
+ if (points.length === 2) {
2169
+ const start = 0;
2170
+ const endIndex = pointsOnBezier.length - 1;
2171
+ const middleIndex = Math.round((start + endIndex) / 2);
2172
+ result.push(pointsOnBezier[middleIndex]);
2173
+ }
2174
+ else {
2175
+ for (let i = 0; i < points.length - 1; i++) {
2176
+ const startIndex = pointsOnBezier.findIndex(point => point[0] === points[i][0] && point[1] === points[i][1]);
2177
+ const endIndex = pointsOnBezier.findIndex(point => point[0] === points[i + 1][0] && point[1] === points[i + 1][1]);
2178
+ const middleIndex = Math.round((startIndex + endIndex) / 2);
2179
+ result.push(pointsOnBezier[middleIndex]);
2180
+ }
2181
+ }
2182
+ }
2183
+ return result;
2184
+ }
988
2185
 
989
2186
  class LineComponent extends PlaitPluginElementComponent {
990
2187
  constructor(viewContainerRef, cdr) {
@@ -1040,11 +2237,18 @@ class LineComponent extends PlaitPluginElementComponent {
1040
2237
  this.updateTextRectangle();
1041
2238
  return;
1042
2239
  }
1043
- const hasSameSelected = value.selected === previous.selected;
1044
- if (!hasSameSelected) {
2240
+ if (!isSelectionMoving(this.board)) {
2241
+ this.activeGenerator.hasResizeHandle = this.hasResizeHandle();
1045
2242
  this.activeGenerator.draw(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
1046
2243
  }
1047
2244
  }
2245
+ hasResizeHandle() {
2246
+ const selectedElements = getSelectedElements(this.board);
2247
+ if (PlaitBoard.hasBeenTextEditing(this.board) && PlaitDrawElement.isText(this.element)) {
2248
+ return false;
2249
+ }
2250
+ return selectedElements.length === 1 && !isSelectionMoving(this.board);
2251
+ }
1048
2252
  initializeTextManages() {
1049
2253
  if (this.element.texts?.length) {
1050
2254
  this.element.texts.forEach((text, index) => {
@@ -1116,15 +2320,16 @@ class LineComponent extends PlaitPluginElementComponent {
1116
2320
  this.destroy$.next();
1117
2321
  this.destroy$.complete();
1118
2322
  }
1119
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: LineComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
1120
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: LineComponent, selector: "plait-draw-line", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2323
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LineComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2324
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LineComponent, isStandalone: true, selector: "plait-draw-line", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1121
2325
  }
1122
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: LineComponent, decorators: [{
2326
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LineComponent, decorators: [{
1123
2327
  type: Component,
1124
2328
  args: [{
1125
2329
  selector: 'plait-draw-line',
1126
2330
  template: ``,
1127
- changeDetection: ChangeDetectionStrategy.OnPush
2331
+ changeDetection: ChangeDetectionStrategy.OnPush,
2332
+ standalone: true
1128
2333
  }]
1129
2334
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
1130
2335
 
@@ -1164,21 +2369,22 @@ const withGeometryCreateByDrag = (board) => {
1164
2369
  geometryShapeG?.remove();
1165
2370
  geometryShapeG = createG();
1166
2371
  const geometryGenerator = new GeometryShapeGenerator(board);
1167
- const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
2372
+ const geometryPointers = getGeometryPointers();
2373
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1168
2374
  const dragMode = isGeometryPointer && isDndMode(board);
1169
2375
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1170
2376
  const pointer = PlaitBoard.getPointer(board);
1171
2377
  if (dragMode) {
1172
2378
  const points = getDefaultGeometryPoints(pointer, movingPoint);
1173
- if (pointer === DrawPointerType.text) {
2379
+ if (pointer === BasicShapes.text) {
1174
2380
  const textG = getTemporaryTextG(movingPoint);
1175
2381
  geometryShapeG.appendChild(textG);
1176
2382
  PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1177
2383
  }
1178
2384
  else {
1179
2385
  const temporaryElement = createGeometryElement(pointer, points, '', {
1180
- strokeColor: DefaultGeometryProperty.strokeColor,
1181
- strokeWidth: DefaultGeometryProperty.strokeWidth
2386
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
2387
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1182
2388
  });
1183
2389
  geometryGenerator.draw(temporaryElement, geometryShapeG);
1184
2390
  PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
@@ -1188,12 +2394,13 @@ const withGeometryCreateByDrag = (board) => {
1188
2394
  };
1189
2395
  board.pointerUp = (event) => {
1190
2396
  const pointer = PlaitBoard.getPointer(board);
1191
- const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
2397
+ const geometryPointers = getGeometryPointers();
2398
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1192
2399
  const dragMode = isGeometryPointer && isDndMode(board);
1193
2400
  if (dragMode) {
1194
2401
  const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1195
2402
  const points = getDefaultGeometryPoints(pointer, targetPoint);
1196
- if (pointer === DrawPointerType.text) {
2403
+ if (pointer === BasicShapes.text) {
1197
2404
  DrawTransforms.insertText(board, points);
1198
2405
  }
1199
2406
  else {
@@ -1208,7 +2415,7 @@ const withGeometryCreateByDrag = (board) => {
1208
2415
  };
1209
2416
  return board;
1210
2417
  };
1211
- const withGeometryCreateByDraw = (board) => {
2418
+ const withGeometryCreateByDrawing = (board) => {
1212
2419
  const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
1213
2420
  let start = null;
1214
2421
  let geometryShapeG = null;
@@ -1223,15 +2430,16 @@ const withGeometryCreateByDraw = (board) => {
1223
2430
  keyup(event);
1224
2431
  };
1225
2432
  board.pointerDown = (event) => {
1226
- const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
2433
+ const geometryPointers = getGeometryPointers();
2434
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1227
2435
  if (isGeometryPointer && isDrawingMode(board)) {
1228
2436
  const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1229
2437
  start = point;
1230
2438
  const pointer = PlaitBoard.getPointer(board);
1231
2439
  preventTouchMove(board, event, true);
1232
- if (pointer === DrawPointerType.text) {
2440
+ if (pointer === BasicShapes.text) {
1233
2441
  const points = getDefaultGeometryPoints(pointer, point);
1234
- const textElement = createGeometryElement(GeometryShape.text, points, DefaultTextProperty.text);
2442
+ const textElement = createGeometryElement(BasicShapes.text, points, DefaultTextProperty.text);
1235
2443
  Transforms.insertNode(board, textElement, [board.children.length]);
1236
2444
  clearSelectedElement(board);
1237
2445
  addSelectedElement(board, textElement);
@@ -1248,11 +2456,11 @@ const withGeometryCreateByDraw = (board) => {
1248
2456
  const drawMode = !!start;
1249
2457
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1250
2458
  const pointer = PlaitBoard.getPointer(board);
1251
- if (drawMode && pointer !== DrawPointerType.text) {
2459
+ if (drawMode && pointer !== BasicShapes.text) {
1252
2460
  const points = normalizeShapePoints([start, movingPoint], isShift);
1253
2461
  temporaryElement = createGeometryElement(pointer, points, '', {
1254
- strokeColor: DefaultGeometryProperty.strokeColor,
1255
- strokeWidth: DefaultGeometryProperty.strokeWidth
2462
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
2463
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1256
2464
  });
1257
2465
  geometryGenerator.draw(temporaryElement, geometryShapeG);
1258
2466
  PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
@@ -1267,10 +2475,10 @@ const withGeometryCreateByDraw = (board) => {
1267
2475
  if (Math.hypot(width, height) === 0) {
1268
2476
  const pointer = PlaitBoard.getPointer(board);
1269
2477
  const points = getDefaultGeometryPoints(pointer, targetPoint);
1270
- if (pointer !== DrawPointerType.text) {
2478
+ if (pointer !== BasicShapes.text) {
1271
2479
  temporaryElement = createGeometryElement(pointer, points, '', {
1272
- strokeColor: DefaultGeometryProperty.strokeColor,
1273
- strokeWidth: DefaultGeometryProperty.strokeWidth
2480
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
2481
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1274
2482
  });
1275
2483
  }
1276
2484
  }
@@ -1291,9 +2499,21 @@ const withGeometryCreateByDraw = (board) => {
1291
2499
  return board;
1292
2500
  };
1293
2501
  const getDefaultGeometryPoints = (pointer, targetPoint) => {
1294
- return pointer === DrawPointerType.text
1295
- ? getPointsByCenterPoint(targetPoint, DefaultTextProperty.width, DefaultTextProperty.height)
1296
- : getPointsByCenterPoint(targetPoint, DefaultGeometryProperty.width, DefaultGeometryProperty.height);
2502
+ const defaultProperty = getGeometryDefaultProperty(pointer);
2503
+ return getPointsByCenterPoint(targetPoint, defaultProperty.width, defaultProperty.height);
2504
+ };
2505
+ const getGeometryDefaultProperty = (pointer) => {
2506
+ const isText = pointer === BasicShapes.text;
2507
+ const isFlowChart = getFlowchartPointers().includes(pointer);
2508
+ if (isText) {
2509
+ return DefaultTextProperty;
2510
+ }
2511
+ else if (isFlowChart) {
2512
+ return getDefaultFlowchartProperty(pointer);
2513
+ }
2514
+ else {
2515
+ return DefaultBasicShapeProperty;
2516
+ }
1297
2517
  };
1298
2518
  const getTemporaryTextG = (movingPoint) => {
1299
2519
  const textG = createG();
@@ -1310,7 +2530,7 @@ const getTemporaryTextG = (movingPoint) => {
1310
2530
 
1311
2531
  const buildClipboardData = (board, elements, startPoint) => {
1312
2532
  return elements.map(element => {
1313
- if (PlaitDrawElement.isGeometry(element)) {
2533
+ if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
1314
2534
  const points = element.points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
1315
2535
  return { ...element, points };
1316
2536
  }
@@ -1333,7 +2553,7 @@ const buildClipboardData = (board, elements, startPoint) => {
1333
2553
  };
1334
2554
  const insertClipboardData = (board, elements, startPoint) => {
1335
2555
  const lines = elements.filter(value => PlaitDrawElement.isLine(value));
1336
- const geometries = elements.filter(value => PlaitDrawElement.isGeometry(value));
2556
+ const geometries = elements.filter(value => PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isImage(value));
1337
2557
  geometries.forEach(element => {
1338
2558
  const sourceLines = [];
1339
2559
  const targetLines = [];
@@ -1357,6 +2577,7 @@ const insertClipboardData = (board, elements, startPoint) => {
1357
2577
  element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
1358
2578
  Transforms.insertNode(board, element, [board.children.length]);
1359
2579
  });
2580
+ Transforms.addSelectionWithTemporaryElements(board, elements);
1360
2581
  };
1361
2582
 
1362
2583
  const withDrawFragment = (baseBoard) => {
@@ -1365,21 +2586,35 @@ const withDrawFragment = (baseBoard) => {
1365
2586
  board.getDeletedFragment = (data) => {
1366
2587
  const drawElements = getSelectedDrawElements(board);
1367
2588
  if (drawElements.length) {
1368
- const lines = getBoardLines(board);
1369
2589
  const geometryElements = drawElements.filter(value => PlaitDrawElement.isGeometry(value));
1370
2590
  const lineElements = drawElements.filter(value => PlaitDrawElement.isLine(value));
1371
- const boundLineElements = lines.filter(line => geometryElements.find(geometry => PlaitLine.isBoundElementOfSource(line, geometry) || PlaitLine.isBoundElementOfTarget(line, geometry)));
1372
- data.push(...[...geometryElements, ...lineElements, ...boundLineElements.filter(line => !lineElements.includes(line))]);
2591
+ const imageElements = drawElements.filter(value => PlaitDrawElement.isImage(value));
2592
+ const boundLineElements = [
2593
+ ...getBoundedLineElements(board, geometryElements),
2594
+ ...getBoundedLineElements(board, imageElements)
2595
+ ].filter(line => !lineElements.includes(line));
2596
+ data.push(...[
2597
+ ...geometryElements,
2598
+ ...lineElements,
2599
+ ...imageElements,
2600
+ ...boundLineElements.filter(line => !lineElements.includes(line))
2601
+ ]);
1373
2602
  }
1374
2603
  return getDeletedFragment(data);
1375
2604
  };
1376
- board.setFragment = (data, rectangle) => {
2605
+ board.setFragment = (data, rectangle, type) => {
1377
2606
  const targetDrawElements = getSelectedDrawElements(board);
2607
+ let boundLineElements = [];
1378
2608
  if (targetDrawElements.length) {
1379
- const elements = buildClipboardData(board, targetDrawElements, rectangle ? [rectangle.x, rectangle.y] : [0, 0]);
2609
+ if (type === 'cut') {
2610
+ const geometryElements = targetDrawElements.filter(value => PlaitDrawElement.isGeometry(value));
2611
+ const lineElements = targetDrawElements.filter(value => PlaitDrawElement.isLine(value));
2612
+ boundLineElements = getBoundedLineElements(board, geometryElements).filter(line => !lineElements.includes(line));
2613
+ }
2614
+ const elements = buildClipboardData(board, [...targetDrawElements, ...boundLineElements], rectangle ? [rectangle.x, rectangle.y] : [0, 0]);
1380
2615
  setClipboardData(data, elements);
1381
2616
  }
1382
- setFragment(data, rectangle);
2617
+ setFragment(data, rectangle, type);
1383
2618
  };
1384
2619
  board.insertFragment = (data, targetPoint) => {
1385
2620
  const elements = getDataFromClipboard(data);
@@ -1399,10 +2634,24 @@ const withDrawFragment = (baseBoard) => {
1399
2634
  return;
1400
2635
  }
1401
2636
  }
2637
+ if (data?.files.length) {
2638
+ const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
2639
+ if (acceptImageArray.includes(data?.files[0].type)) {
2640
+ const imageFile = data.files[0];
2641
+ buildImage(board, imageFile, DEFAULT_IMAGE_WIDTH, imageItem => {
2642
+ DrawTransforms.insertImage(board, imageItem, targetPoint);
2643
+ });
2644
+ return;
2645
+ }
2646
+ }
1402
2647
  insertFragment(data, targetPoint);
1403
2648
  };
1404
2649
  return board;
1405
2650
  };
2651
+ const getBoundedLineElements = (board, plaitShapes) => {
2652
+ const lines = getBoardLines(board);
2653
+ return lines.filter(line => plaitShapes.find(shape => PlaitLine.isBoundElementOfSource(line, shape) || PlaitLine.isBoundElementOfTarget(line, shape)));
2654
+ };
1406
2655
 
1407
2656
  const DefaultLineStyle = {
1408
2657
  strokeWidth: 2,
@@ -1420,10 +2669,10 @@ const getHitGeometryResizeHandleRef = (board, element, point) => {
1420
2669
  const getHitOutlineGeometry = (board, point, offset = 0) => {
1421
2670
  let geometry = null;
1422
2671
  depthFirstRecursion(board, node => {
1423
- if (PlaitDrawElement.isGeometry(node)) {
1424
- const shape = node.shape;
2672
+ if (PlaitDrawElement.isGeometry(node) || PlaitDrawElement.isImage(node)) {
1425
2673
  let client = getRectangleByPoints(node.points);
1426
2674
  client = RectangleClient.getOutlineRectangle(client, offset);
2675
+ const shape = getShape(node);
1427
2676
  const isHit = getEngine(shape).isHit(client, point);
1428
2677
  if (isHit) {
1429
2678
  geometry = node;
@@ -1441,7 +2690,8 @@ const withLineCreateByDraw = (board) => {
1441
2690
  let lineShapeG = null;
1442
2691
  let temporaryElement = null;
1443
2692
  board.pointerDown = (event) => {
1444
- const isLinePointer = PlaitBoard.isPointer(board, DrawPointerType.line);
2693
+ const linePointers = getLinePointers();
2694
+ const isLinePointer = PlaitBoard.isInPointer(board, linePointers);
1445
2695
  if (isLinePointer && isDrawingMode(board)) {
1446
2696
  const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1447
2697
  start = point;
@@ -1463,7 +2713,8 @@ const withLineCreateByDraw = (board) => {
1463
2713
  targetRef.connection = hitElement ? transformPointToConnection(board, movingPoint, hitElement) : undefined;
1464
2714
  targetRef.boundId = hitElement ? hitElement.id : undefined;
1465
2715
  const lineGenerator = new LineShapeGenerator(board);
1466
- temporaryElement = createLineElement(LineShape.elbow, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, {
2716
+ const lineShape = PlaitBoard.getPointer(board);
2717
+ temporaryElement = createLineElement(lineShape, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, {
1467
2718
  strokeColor: DefaultLineStyle.strokeColor,
1468
2719
  strokeWidth: DefaultLineStyle.strokeWidth
1469
2720
  });
@@ -1508,12 +2759,12 @@ const withGeometryResize = (board) => {
1508
2759
  return true;
1509
2760
  },
1510
2761
  detect: (point) => {
1511
- const selectedGeometryElements = getSelectedGeometryElements(board);
1512
- if (selectedGeometryElements.length !== 1 || getSelectedElements(board).length !== 1) {
2762
+ const selectedElements = [...getSelectedGeometryElements(board), ...getSelectedImageElements(board)];
2763
+ if (selectedElements.length !== 1 || getSelectedElements(board).length !== 1) {
1513
2764
  return null;
1514
2765
  }
1515
- const target = selectedGeometryElements[0];
1516
- const targetComponent = PlaitElement.getComponent(selectedGeometryElements[0]);
2766
+ const target = selectedElements[0];
2767
+ const targetComponent = PlaitElement.getComponent(selectedElements[0]);
1517
2768
  if (targetComponent.activeGenerator.hasResizeHandle) {
1518
2769
  const handleRef = getHitGeometryResizeHandleRef(board, target, point);
1519
2770
  if (handleRef) {
@@ -1528,27 +2779,34 @@ const withGeometryResize = (board) => {
1528
2779
  },
1529
2780
  onResize: (resizeRef, resizeState) => {
1530
2781
  let points = [...resizeRef.element.points];
2782
+ const rectangle = getRectangleByPoints(resizeRef.element.points);
2783
+ const ratio = rectangle.height / rectangle.width;
1531
2784
  if (resizeRef.handle === ResizeHandle.nw) {
1532
2785
  points = [resizeState.endTransformPoint, resizeRef.element.points[1]];
1533
2786
  }
1534
2787
  if (resizeRef.handle === ResizeHandle.ne) {
1535
- points = [
1536
- [resizeRef.element.points[0][0], resizeState.endTransformPoint[1]],
1537
- [resizeState.endTransformPoint[0], resizeRef.element.points[1][1]]
1538
- ];
2788
+ points = [resizeState.endTransformPoint, [resizeRef.element.points[0][0], resizeRef.element.points[1][1]]];
1539
2789
  }
1540
2790
  if (resizeRef.handle === ResizeHandle.se) {
1541
- points = [resizeRef.element.points[0], resizeState.endTransformPoint];
2791
+ points = [resizeState.endTransformPoint, resizeRef.element.points[0]];
1542
2792
  }
1543
2793
  if (resizeRef.handle === ResizeHandle.sw) {
1544
- points = [
1545
- [resizeState.endTransformPoint[0], resizeRef.element.points[0][1]],
1546
- [resizeRef.element.points[1][0], resizeState.endTransformPoint[1]]
1547
- ];
2794
+ points = [resizeState.endTransformPoint, [resizeRef.element.points[1][0], resizeRef.element.points[0][1]]];
2795
+ }
2796
+ if (isShift || PlaitDrawElement.isImage(resizeRef.element)) {
2797
+ const rectangle = getRectangleByPoints(points);
2798
+ const factor = points[0][1] > points[1][1] ? 1 : -1;
2799
+ const height = rectangle.width * ratio * factor;
2800
+ points = [[resizeState.endTransformPoint[0], points[1][1] + height], points[1]];
2801
+ }
2802
+ if (PlaitDrawElement.isGeometry(resizeRef.element)) {
2803
+ const { height: textHeight } = PlaitGeometry.getTextManage(resizeRef.element).getSize();
2804
+ DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
2805
+ }
2806
+ else {
2807
+ points = normalizeShapePoints(points);
2808
+ Transforms.setNode(board, { points }, resizeRef.path);
1548
2809
  }
1549
- points = normalizeShapePoints(points, isShift);
1550
- const { height: textHeight } = PlaitGeometry.getTextManage(resizeRef.element).getSize();
1551
- DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
1552
2810
  }
1553
2811
  };
1554
2812
  withResize(board, options);
@@ -1559,34 +2817,44 @@ var LineResizeHandle;
1559
2817
  (function (LineResizeHandle) {
1560
2818
  LineResizeHandle["source"] = "source";
1561
2819
  LineResizeHandle["target"] = "target";
2820
+ LineResizeHandle["addHandle"] = "addHandle";
1562
2821
  })(LineResizeHandle || (LineResizeHandle = {}));
1563
2822
  const getHitLineResizeHandleRef = (board, element, point) => {
1564
- const sourcePoint = getSourcePoint(board, element);
1565
- const targetPoint = getTargetPoint(board, element);
1566
- const sourceRectangle = {
1567
- x: sourcePoint[0] - RESIZE_HANDLE_DIAMETER / 2,
1568
- y: sourcePoint[1] - RESIZE_HANDLE_DIAMETER / 2,
1569
- width: RESIZE_HANDLE_DIAMETER,
1570
- height: RESIZE_HANDLE_DIAMETER
1571
- };
1572
- const targetRectangle = {
1573
- x: targetPoint[0] - RESIZE_HANDLE_DIAMETER / 2,
1574
- y: targetPoint[1] - RESIZE_HANDLE_DIAMETER / 2,
1575
- width: RESIZE_HANDLE_DIAMETER,
1576
- height: RESIZE_HANDLE_DIAMETER
1577
- };
1578
- const isHitSourceRectangle = RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), sourceRectangle);
1579
- const isHitTargetRectangle = RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), targetRectangle);
1580
- if (isHitSourceRectangle) {
1581
- return { rectangle: sourceRectangle, handle: LineResizeHandle.source };
2823
+ const points = PlaitLine.getPoints(board, element);
2824
+ const index = getHitPointIndex(points, point);
2825
+ if (index !== -1) {
2826
+ if (index === 0) {
2827
+ return { handle: LineResizeHandle.source, index };
2828
+ }
2829
+ if (index === points.length - 1) {
2830
+ return { handle: LineResizeHandle.target, index };
2831
+ }
2832
+ return { index };
1582
2833
  }
1583
- if (isHitTargetRectangle) {
1584
- return { rectangle: targetRectangle, handle: LineResizeHandle.target };
2834
+ const middlePoints = getMiddlePoints(board, element);
2835
+ const middleIndex = getHitPointIndex(middlePoints, point);
2836
+ if (middleIndex !== -1) {
2837
+ return { handle: LineResizeHandle.addHandle, index: middleIndex };
1585
2838
  }
1586
2839
  return undefined;
1587
2840
  };
2841
+ function getHitPointIndex(points, movingPoint) {
2842
+ const rectangles = points.map(point => {
2843
+ return {
2844
+ x: point[0] - RESIZE_HANDLE_DIAMETER / 2,
2845
+ y: point[1] - RESIZE_HANDLE_DIAMETER / 2,
2846
+ width: RESIZE_HANDLE_DIAMETER,
2847
+ height: RESIZE_HANDLE_DIAMETER
2848
+ };
2849
+ });
2850
+ const rectangle = rectangles.find(rectangle => {
2851
+ return RectangleClient.isHit(RectangleClient.toRectangleClient([movingPoint, movingPoint]), rectangle);
2852
+ });
2853
+ return rectangle ? rectangles.indexOf(rectangle) : -1;
2854
+ }
1588
2855
 
1589
2856
  const withLineResize = (board) => {
2857
+ let pointIndex = 0;
1590
2858
  const options = {
1591
2859
  key: 'draw-line',
1592
2860
  canResize: () => {
@@ -1603,6 +2871,7 @@ const withLineResize = (board) => {
1603
2871
  element: value,
1604
2872
  handle: handleRef.handle
1605
2873
  };
2874
+ pointIndex = handleRef.index;
1606
2875
  }
1607
2876
  });
1608
2877
  return result;
@@ -1614,17 +2883,23 @@ const withLineResize = (board) => {
1614
2883
  let source = { ...resizeRef.element.source };
1615
2884
  let target = { ...resizeRef.element.target };
1616
2885
  if (resizeRef.handle === LineResizeHandle.source) {
1617
- points[0] = resizeState.endTransformPoint;
2886
+ points[pointIndex] = resizeState.endTransformPoint;
1618
2887
  const hitElement = getHitOutlineGeometry(board, resizeState.endTransformPoint, -4);
1619
2888
  source.connection = hitElement ? transformPointToConnection(board, resizeState.endTransformPoint, hitElement) : undefined;
1620
2889
  source.boundId = hitElement ? hitElement.id : undefined;
1621
2890
  }
1622
- if (resizeRef.handle === LineResizeHandle.target) {
1623
- points[1] = resizeState.endTransformPoint;
2891
+ else if (resizeRef.handle === LineResizeHandle.target) {
2892
+ points[pointIndex] = resizeState.endTransformPoint;
1624
2893
  const hitElement = getHitOutlineGeometry(board, resizeState.endTransformPoint, -4);
1625
2894
  target.connection = hitElement ? transformPointToConnection(board, resizeState.endTransformPoint, hitElement) : undefined;
1626
2895
  target.boundId = hitElement ? hitElement.id : undefined;
1627
2896
  }
2897
+ else if (resizeRef.handle === LineResizeHandle.addHandle) {
2898
+ points.splice(pointIndex + 1, 0, resizeState.endTransformPoint);
2899
+ }
2900
+ else {
2901
+ points[pointIndex] = resizeState.endTransformPoint;
2902
+ }
1628
2903
  DrawTransforms.resizeLine(board, { points, source, target }, resizeRef.path);
1629
2904
  }
1630
2905
  };
@@ -1637,9 +2912,14 @@ const withLineBoundReaction = (board) => {
1637
2912
  let boundShapeG = null;
1638
2913
  board.pointerMove = (event) => {
1639
2914
  boundShapeG?.remove();
1640
- const isLinePointer = PlaitBoard.isPointer(board, DrawPointerType.line);
2915
+ const linePointers = Object.keys(LineShape);
2916
+ const isLinePointer = PlaitBoard.isInPointer(board, linePointers);
1641
2917
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1642
- const isLineResizing = isResizingByCondition(board, element => PlaitDrawElement.isLine(element));
2918
+ const isLineResizing = isResizingByCondition(board, resizeRef => {
2919
+ const { element, handle } = resizeRef;
2920
+ const isSourceOrTarget = handle === LineResizeHandle.target || handle === LineResizeHandle.source;
2921
+ return PlaitDrawElement.isLine(element) && isSourceOrTarget;
2922
+ });
1643
2923
  if (isLinePointer || isLineResizing) {
1644
2924
  const hitElement = getHitOutlineGeometry(board, movingPoint, -4);
1645
2925
  if (hitElement) {
@@ -1717,8 +2997,74 @@ function editHandle(board, element, manageIndex, isFirstEdit = false) {
1717
2997
  });
1718
2998
  }
1719
2999
 
3000
+ class ImageComponent extends CommonPluginElement {
3001
+ get activeGenerator() {
3002
+ return this.imageGenerator.componentRef.instance.activeGenerator;
3003
+ }
3004
+ constructor(viewContainerRef, cdr) {
3005
+ super(cdr);
3006
+ this.viewContainerRef = viewContainerRef;
3007
+ this.cdr = cdr;
3008
+ this.destroy$ = new Subject();
3009
+ }
3010
+ initializeGenerator() {
3011
+ this.imageGenerator = new ImageGenerator(this.board, {
3012
+ getRectangle: (element) => {
3013
+ return {
3014
+ x: element.points[0][0],
3015
+ y: element.points[0][1],
3016
+ width: element.points[1][0] - element.points[0][0],
3017
+ height: element.points[1][1] - element.points[0][1]
3018
+ };
3019
+ },
3020
+ getImageItem: element => {
3021
+ return {
3022
+ url: element.url,
3023
+ width: element.points[1][0] - element.points[0][0],
3024
+ height: element.points[1][1] - element.points[0][1]
3025
+ };
3026
+ }
3027
+ });
3028
+ }
3029
+ ngOnInit() {
3030
+ super.ngOnInit();
3031
+ this.initializeGenerator();
3032
+ this.imageGenerator.draw(this.element, this.g, this.viewContainerRef);
3033
+ }
3034
+ onContextChanged(value, previous) {
3035
+ if (value.element !== previous.element) {
3036
+ this.imageGenerator.updateImage(this.g, previous.element, value.element);
3037
+ this.imageGenerator.componentRef.instance.isFocus = this.selected;
3038
+ }
3039
+ else {
3040
+ const hasSameSelected = value.selected === previous.selected;
3041
+ const hasSameHandleState = this.activeGenerator.options.hasResizeHandle() === this.activeGenerator.hasResizeHandle;
3042
+ if (!hasSameSelected || !hasSameHandleState) {
3043
+ this.imageGenerator.componentRef.instance.isFocus = this.selected;
3044
+ }
3045
+ }
3046
+ }
3047
+ ngOnDestroy() {
3048
+ super.ngOnDestroy();
3049
+ this.destroy$.next();
3050
+ this.destroy$.complete();
3051
+ this.imageGenerator.destroy();
3052
+ }
3053
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3054
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ImageComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3055
+ }
3056
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageComponent, decorators: [{
3057
+ type: Component,
3058
+ args: [{
3059
+ selector: 'plait-draw-geometry',
3060
+ template: ``,
3061
+ changeDetection: ChangeDetectionStrategy.OnPush,
3062
+ standalone: true
3063
+ }]
3064
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
3065
+
1720
3066
  const withDraw = (board) => {
1721
- const { drawElement, getRectangle, isHitSelection, isMovable, dblclick } = board;
3067
+ const { drawElement, getRectangle, isHitSelection, isMovable, isAlign } = board;
1722
3068
  board.drawElement = (context) => {
1723
3069
  if (PlaitDrawElement.isGeometry(context.element)) {
1724
3070
  return GeometryComponent;
@@ -1726,6 +3072,9 @@ const withDraw = (board) => {
1726
3072
  else if (PlaitDrawElement.isLine(context.element)) {
1727
3073
  return LineComponent;
1728
3074
  }
3075
+ else if (PlaitDrawElement.isImage(context.element)) {
3076
+ return ImageComponent;
3077
+ }
1729
3078
  return drawElement(context);
1730
3079
  };
1731
3080
  board.getRectangle = (element) => {
@@ -1733,9 +3082,11 @@ const withDraw = (board) => {
1733
3082
  return getRectangleByPoints(element.points);
1734
3083
  }
1735
3084
  if (PlaitDrawElement.isLine(element)) {
1736
- const source = getSourcePoint(board, element);
1737
- const target = getTargetPoint(board, element);
1738
- return getRectangleByPoints([source, target]);
3085
+ const points = getLinePoints(board, element);
3086
+ return getRectangleByPoints(points);
3087
+ }
3088
+ if (PlaitDrawElement.isImage(element)) {
3089
+ return getRectangleByPoints(element.points);
1739
3090
  }
1740
3091
  return getRectangle(element);
1741
3092
  };
@@ -1749,6 +3100,11 @@ const withDraw = (board) => {
1749
3100
  }
1750
3101
  return RectangleClient.isHit(rangeRectangle, client);
1751
3102
  }
3103
+ if (PlaitDrawElement.isImage(element)) {
3104
+ const client = getRectangleByPoints(element.points);
3105
+ const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
3106
+ return RectangleClient.isHit(rangeRectangle, client);
3107
+ }
1752
3108
  if (PlaitDrawElement.isLine(element)) {
1753
3109
  const points = getLinePoints(board, element);
1754
3110
  const strokeWidth = getStrokeWidthByElement(element);
@@ -1767,17 +3123,34 @@ const withDraw = (board) => {
1767
3123
  if (PlaitDrawElement.isGeometry(element)) {
1768
3124
  return true;
1769
3125
  }
3126
+ if (PlaitDrawElement.isImage(element)) {
3127
+ return true;
3128
+ }
1770
3129
  if (PlaitDrawElement.isLine(element)) {
1771
- return !element.source.boundId && !element.target.boundId;
3130
+ const selectedElements = getSelectedElements(board);
3131
+ const isSelected = (boundId) => {
3132
+ return !!selectedElements.find(value => value.id === boundId);
3133
+ };
3134
+ if ((element.source.boundId && !isSelected(element.source.boundId)) ||
3135
+ (element.target.boundId && !isSelected(element.target.boundId))) {
3136
+ return false;
3137
+ }
3138
+ return true;
1772
3139
  }
1773
3140
  return isMovable(element);
1774
3141
  };
1775
- return withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withGeometryCreateByDrag(withGeometryCreateByDraw(withDrawFragment(withDrawHotkey(board)))))))));
3142
+ board.isAlign = (element) => {
3143
+ if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
3144
+ return true;
3145
+ }
3146
+ return isAlign(element);
3147
+ };
3148
+ return withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withGeometryCreateByDrag(withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))))))));
1776
3149
  };
1777
3150
 
1778
3151
  /**
1779
3152
  * Generated bundle index. Do not edit.
1780
3153
  */
1781
3154
 
1782
- export { DefaultGeometryActiveStyle, DefaultGeometryProperty, DefaultGeometryStyle, DefaultTextProperty, DrawPointerType, DrawTransforms, GeometryComponent, GeometryPointer, GeometryShape, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, ShapeDefaultSpace, StrokeStyle, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getElbowPoints, getFillByElement, getHitConnectorPoint, getHitLineTextIndex, getLineDashByElement, getLinePoints, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedLineElements, getSourcePoint, getStraightPoints, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTargetPoint, getTextRectangle, isHitLineText, isHitPolyLine, transformPointToConnection, withDraw };
3155
+ export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBasicPointers, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getEdgeOnPolygonByPoint, getElbowPoints, getExtendPoint, getFillByElement, getFlowchartPointers, getGeometryPointers, getHitConnectorPoint, getHitLineTextIndex, getLineDashByElement, getLineHandleRefPair, getLinePointers, getLinePoints, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getVectorByConnection, isHitLineText, isHitPolyLine, removeDuplicatePoints, transformOpsToPoints, transformPointToConnection, withDraw };
1783
3156
  //# sourceMappingURL=plait-draw.mjs.map