@plait/draw 0.1.0-next.11 → 0.1.0-next.13

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 (105) hide show
  1. package/constants/image.d.ts +1 -0
  2. package/constants/index.d.ts +1 -0
  3. package/constants/pointer.d.ts +4 -10
  4. package/engines/comment.d.ts +4 -0
  5. package/engines/cross.d.ts +4 -0
  6. package/{utils/engine → engines}/diamond.d.ts +1 -1
  7. package/{utils/engine → engines}/ellipse.d.ts +1 -1
  8. package/engines/hexagon.d.ts +4 -0
  9. package/{utils/engine → engines}/index.d.ts +1 -1
  10. package/engines/left-arrow.d.ts +4 -0
  11. package/engines/octagon.d.ts +4 -0
  12. package/engines/parallelogram.d.ts +4 -0
  13. package/engines/pentagon-arrow.d.ts +4 -0
  14. package/engines/pentagon.d.ts +4 -0
  15. package/engines/process-arrow.d.ts +4 -0
  16. package/{utils/engine → engines}/rectangle.d.ts +1 -1
  17. package/engines/right-arrow.d.ts +4 -0
  18. package/engines/round-comment.d.ts +4 -0
  19. package/{utils/engine → engines}/round-rectangle.d.ts +1 -1
  20. package/engines/star.d.ts +4 -0
  21. package/engines/trapezoid.d.ts +4 -0
  22. package/engines/triangle.d.ts +4 -0
  23. package/engines/two-way-arrow.d.ts +4 -0
  24. package/esm2022/constants/geometry.mjs +3 -3
  25. package/esm2022/constants/image.mjs +2 -0
  26. package/esm2022/constants/index.mjs +2 -1
  27. package/esm2022/constants/pointer.mjs +8 -19
  28. package/esm2022/engines/comment.mjs +57 -0
  29. package/esm2022/engines/cross.mjs +46 -0
  30. package/esm2022/engines/diamond.mjs +30 -0
  31. package/esm2022/engines/ellipse.mjs +92 -0
  32. package/esm2022/engines/hexagon.mjs +40 -0
  33. package/esm2022/engines/index.mjs +46 -0
  34. package/esm2022/engines/left-arrow.mjs +45 -0
  35. package/esm2022/engines/octagon.mjs +42 -0
  36. package/esm2022/engines/parallelogram.mjs +39 -0
  37. package/esm2022/engines/pentagon-arrow.mjs +39 -0
  38. package/esm2022/engines/pentagon.mjs +39 -0
  39. package/esm2022/engines/process-arrow.mjs +41 -0
  40. package/esm2022/engines/rectangle.mjs +26 -0
  41. package/esm2022/engines/right-arrow.mjs +45 -0
  42. package/esm2022/engines/round-comment.mjs +81 -0
  43. package/esm2022/engines/round-rectangle.mjs +59 -0
  44. package/esm2022/engines/star.mjs +45 -0
  45. package/esm2022/engines/trapezoid.mjs +40 -0
  46. package/esm2022/engines/triangle.mjs +40 -0
  47. package/esm2022/engines/two-way-arrow.mjs +48 -0
  48. package/esm2022/generators/geometry-shape.generator.mjs +7 -2
  49. package/esm2022/generators/line-active.generator.mjs +49 -16
  50. package/esm2022/generators/line.generator.mjs +2 -11
  51. package/esm2022/geometry.component.mjs +13 -7
  52. package/esm2022/image.component.mjs +70 -0
  53. package/esm2022/interfaces/geometry.mjs +15 -1
  54. package/esm2022/interfaces/image.mjs +2 -0
  55. package/esm2022/interfaces/index.mjs +8 -2
  56. package/esm2022/interfaces/line.mjs +27 -4
  57. package/esm2022/line.component.mjs +4 -3
  58. package/esm2022/plugins/with-draw-fragment.mjs +20 -2
  59. package/esm2022/plugins/with-draw.mjs +25 -4
  60. package/esm2022/plugins/with-geometry-create.mjs +15 -12
  61. package/esm2022/plugins/with-geometry-resize.mjs +17 -11
  62. package/esm2022/plugins/with-line-bound-reaction.mjs +10 -5
  63. package/esm2022/plugins/with-line-create.mjs +7 -5
  64. package/esm2022/plugins/with-line-resize.mjs +12 -4
  65. package/esm2022/transforms/geometry-text.mjs +1 -1
  66. package/esm2022/transforms/image.mjs +23 -0
  67. package/esm2022/transforms/index.mjs +4 -2
  68. package/esm2022/utils/clipboard.mjs +3 -3
  69. package/esm2022/utils/geometry.mjs +20 -6
  70. package/esm2022/utils/index.mjs +1 -1
  71. package/esm2022/utils/line-arrow.mjs +43 -18
  72. package/esm2022/utils/line.mjs +197 -47
  73. package/esm2022/utils/position/geometry.mjs +5 -4
  74. package/esm2022/utils/position/line.mjs +32 -22
  75. package/esm2022/utils/selected.mjs +5 -1
  76. package/esm2022/utils/shape.mjs +8 -0
  77. package/fesm2022/plait-draw.mjs +1367 -253
  78. package/fesm2022/plait-draw.mjs.map +1 -1
  79. package/generators/line-active.generator.d.ts +2 -0
  80. package/generators/line.generator.d.ts +1 -1
  81. package/geometry.component.d.ts +1 -1
  82. package/image.component.d.ts +20 -0
  83. package/interfaces/geometry.d.ts +20 -2
  84. package/interfaces/image.d.ts +7 -0
  85. package/interfaces/index.d.ts +5 -1
  86. package/interfaces/line.d.ts +19 -5
  87. package/line.component.d.ts +1 -1
  88. package/package.json +3 -2
  89. package/plugins/with-geometry-create.d.ts +1 -1
  90. package/styles/styles.scss +1 -1
  91. package/transforms/image.d.ts +3 -0
  92. package/transforms/index.d.ts +1 -0
  93. package/utils/geometry.d.ts +1 -0
  94. package/utils/line.d.ts +14 -6
  95. package/utils/position/geometry.d.ts +2 -1
  96. package/utils/position/line.d.ts +7 -3
  97. package/utils/selected.d.ts +2 -0
  98. package/utils/shape.d.ts +2 -0
  99. package/esm2022/utils/engine/diamond.mjs +0 -22
  100. package/esm2022/utils/engine/ellipse.mjs +0 -55
  101. package/esm2022/utils/engine/index.mjs +0 -18
  102. package/esm2022/utils/engine/parallelogram.mjs +0 -32
  103. package/esm2022/utils/engine/rectangle.mjs +0 -18
  104. package/esm2022/utils/engine/round-rectangle.mjs +0 -49
  105. package/utils/engine/parallelogram.d.ts +0 -4
@@ -1,9 +1,10 @@
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, PRIMARY_COLOR, 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
 
@@ -15,6 +16,20 @@ var GeometryShape;
15
16
  GeometryShape["roundRectangle"] = "roundRectangle";
16
17
  GeometryShape["parallelogram"] = "parallelogram";
17
18
  GeometryShape["text"] = "text";
19
+ GeometryShape["triangle"] = "triangle";
20
+ GeometryShape["leftArrow"] = "leftArrow";
21
+ GeometryShape["trapezoid"] = "trapezoid";
22
+ GeometryShape["rightArrow"] = "rightArrow";
23
+ GeometryShape["cross"] = "cross";
24
+ GeometryShape["star"] = "star";
25
+ GeometryShape["pentagon"] = "pentagon";
26
+ GeometryShape["hexagon"] = "hexagon";
27
+ GeometryShape["octagon"] = "octagon";
28
+ GeometryShape["pentagonArrow"] = "pentagonArrow";
29
+ GeometryShape["processArrow"] = "processArrow";
30
+ GeometryShape["twoWayArrow"] = "twoWayArrow";
31
+ GeometryShape["comment"] = "comment";
32
+ GeometryShape["roundComment"] = "roundComment";
18
33
  })(GeometryShape || (GeometryShape = {}));
19
34
  const PlaitGeometry = {
20
35
  getTextEditor(element) {
@@ -29,79 +44,6 @@ const PlaitGeometry = {
29
44
  }
30
45
  };
31
46
 
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
47
  const ShapeDefaultSpace = {
106
48
  rectangleAndText: 4
107
49
  };
@@ -127,27 +69,17 @@ const DefaultTextProperty = {
127
69
  text: '文本'
128
70
  };
129
71
  const GeometryThreshold = {
130
- defaultTextMaxWidth: 34 * 14,
72
+ defaultTextMaxWidth: 34 * 14
131
73
  };
132
74
 
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
- ];
75
+ const getGeometryPointers = () => {
76
+ return Object.keys(GeometryShape);
77
+ };
78
+ const getLinePointers = () => {
79
+ return Object.keys(LineShape);
80
+ };
81
+
82
+ const DEFAULT_IMAGE_WIDTH = 1000;
151
83
 
152
84
  const getStrokeWidthByElement = (element) => {
153
85
  if (PlaitDrawElement.isText(element)) {
@@ -171,6 +103,102 @@ const getStrokeStyleByElement = (element) => {
171
103
  return element.strokeStyle || StrokeStyle.solid;
172
104
  };
173
105
 
106
+ const heightRatio$1 = 3 / 4;
107
+ const CommentEngine = {
108
+ draw(board, rectangle, options) {
109
+ const points = getCommentPoints(rectangle);
110
+ const rs = PlaitBoard.getRoughSVG(board);
111
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
112
+ setStrokeLinecap(polygon, 'round');
113
+ return polygon;
114
+ },
115
+ isHit(rectangle, point) {
116
+ const parallelogramPoints = getCommentPoints(rectangle);
117
+ return isPointInPolygon(point, parallelogramPoints);
118
+ },
119
+ getCornerPoints(rectangle) {
120
+ return getCommentPoints(rectangle);
121
+ },
122
+ getNearestPoint(rectangle, point) {
123
+ return getNearestPointBetweenPointAndSegments(point, getCommentPoints(rectangle));
124
+ },
125
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
126
+ const corners = getCommentPoints(rectangle);
127
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
128
+ return getEdgeOnPolygonByPoint(corners, point);
129
+ },
130
+ getConnectorPoints(rectangle) {
131
+ return RectangleClient.getEdgeCenterPoints(rectangle);
132
+ },
133
+ getTextRectangle(element) {
134
+ const elementRectangle = getRectangleByPoints(element.points);
135
+ const strokeWidth = getStrokeWidthByElement(element);
136
+ const height = element.textHeight;
137
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
138
+ return {
139
+ height,
140
+ width: width > 0 ? width : 0,
141
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
142
+ y: elementRectangle.y + (elementRectangle.height * heightRatio$1 - height) / 2
143
+ };
144
+ }
145
+ };
146
+ const getCommentPoints = (rectangle) => {
147
+ return [
148
+ [rectangle.x, rectangle.y],
149
+ [rectangle.x + rectangle.width, rectangle.y],
150
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * heightRatio$1],
151
+ [rectangle.x + (rectangle.width * 3) / 5, rectangle.y + rectangle.height * heightRatio$1],
152
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
153
+ [rectangle.x + (rectangle.width * 2) / 5, rectangle.y + rectangle.height * heightRatio$1],
154
+ [rectangle.x, rectangle.y + rectangle.height * heightRatio$1]
155
+ ];
156
+ };
157
+
158
+ const CrossEngine = {
159
+ draw(board, rectangle, options) {
160
+ const points = getCrossPoints(rectangle);
161
+ const rs = PlaitBoard.getRoughSVG(board);
162
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
163
+ setStrokeLinecap(polygon, 'round');
164
+ return polygon;
165
+ },
166
+ isHit(rectangle, point) {
167
+ const parallelogramPoints = getCrossPoints(rectangle);
168
+ return isPointInPolygon(point, parallelogramPoints);
169
+ },
170
+ getCornerPoints(rectangle) {
171
+ return getCrossPoints(rectangle);
172
+ },
173
+ getNearestPoint(rectangle, point) {
174
+ return getNearestPointBetweenPointAndSegments(point, getCrossPoints(rectangle));
175
+ },
176
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
177
+ const corners = getCrossPoints(rectangle);
178
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
179
+ return getEdgeOnPolygonByPoint(corners, point);
180
+ },
181
+ getConnectorPoints(rectangle) {
182
+ return RectangleClient.getEdgeCenterPoints(rectangle);
183
+ }
184
+ };
185
+ const getCrossPoints = (rectangle) => {
186
+ return [
187
+ [rectangle.x + rectangle.width / 4, rectangle.y],
188
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y],
189
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 4],
190
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 4],
191
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 3) / 4],
192
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + (rectangle.height * 3) / 4],
193
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height],
194
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
195
+ [rectangle.x + rectangle.width / 4, rectangle.y + (rectangle.height * 3) / 4],
196
+ [rectangle.x, rectangle.y + (rectangle.height * 3) / 4],
197
+ [rectangle.x, rectangle.y + rectangle.height / 4],
198
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height / 4]
199
+ ];
200
+ };
201
+
174
202
  const DiamondEngine = {
175
203
  draw(board, rectangle, options) {
176
204
  const points = RectangleClient.getEdgeCenterPoints(rectangle);
@@ -183,9 +211,16 @@ const DiamondEngine = {
183
211
  const controlPoints = RectangleClient.getEdgeCenterPoints(rectangle);
184
212
  return isPointInPolygon(point, controlPoints);
185
213
  },
214
+ getCornerPoints(rectangle) {
215
+ return RectangleClient.getEdgeCenterPoints(rectangle);
216
+ },
186
217
  getNearestPoint(rectangle, point) {
187
- const connectorPoints = RectangleClient.getEdgeCenterPoints(rectangle);
188
- return getNearestPointBetweenPointAndSegments(point, connectorPoints);
218
+ return getNearestPointBetweenPointAndSegments(point, DiamondEngine.getCornerPoints(rectangle));
219
+ },
220
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
221
+ const corners = DiamondEngine.getCornerPoints(rectangle);
222
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
223
+ return getEdgeOnPolygonByPoint(corners, point);
189
224
  },
190
225
  getConnectorPoints(rectangle) {
191
226
  return RectangleClient.getEdgeCenterPoints(rectangle);
@@ -202,10 +237,22 @@ const EllipseEngine = {
202
237
  const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
203
238
  return isPointInEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
204
239
  },
240
+ getCornerPoints(rectangle) {
241
+ return RectangleClient.getEdgeCenterPoints(rectangle);
242
+ },
205
243
  getNearestPoint(rectangle, point) {
206
244
  const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
207
245
  return getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
208
246
  },
247
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
248
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
249
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
250
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
251
+ const a = rectangle.width / 2;
252
+ const b = rectangle.height / 2;
253
+ const slope = getTangentSlope(point[0], point[1], a, b);
254
+ return getVectorBySlope(point[0], point[1], slope);
255
+ },
209
256
  getConnectorPoints(rectangle) {
210
257
  return RectangleClient.getEdgeCenterPoints(rectangle);
211
258
  }
@@ -245,29 +292,182 @@ function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation =
245
292
  const signY = point[1] > center[1] ? 1 : -1;
246
293
  return [center[0] + a * tx * signX, center[1] + b * ty * signY];
247
294
  }
295
+ /**
296
+ * the result of slope is based on Cartesian coordinate system
297
+ * x, y are based on the position in the Cartesian coordinate system
298
+ */
299
+ function getTangentSlope(x, y, a, b) {
300
+ const k = (-b * b * x) / (a * a * y);
301
+ return k;
302
+ }
303
+ /**
304
+ * x, y are based on the position in the Cartesian coordinate system
305
+ */
306
+ function getVectorBySlope(x, y, slope) {
307
+ const deltaX = 30;
308
+ const deltaY = -slope * deltaX;
309
+ let start = [0 - deltaX, 0 - deltaY];
310
+ let end = [0 + deltaX, 0 + deltaY];
311
+ // 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.
312
+ if (y < 0) {
313
+ const temp = start;
314
+ start = end;
315
+ end = temp;
316
+ }
317
+ const vector = [end[0] - start[0], end[1] - start[1]];
318
+ return vector;
319
+ }
248
320
 
249
- const ParallelogramEngine = {
321
+ const HexagonEngine = {
250
322
  draw(board, rectangle, options) {
251
- const points = getParallelogramPoints(rectangle);
323
+ const points = getHexagonPoints(rectangle);
252
324
  const rs = PlaitBoard.getRoughSVG(board);
253
325
  const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
254
326
  setStrokeLinecap(polygon, 'round');
255
327
  return polygon;
256
328
  },
257
329
  isHit(rectangle, point) {
258
- const parallelogramPoints = getParallelogramPoints(rectangle);
330
+ const parallelogramPoints = getHexagonPoints(rectangle);
259
331
  return isPointInPolygon(point, parallelogramPoints);
260
332
  },
333
+ getCornerPoints(rectangle) {
334
+ return getHexagonPoints(rectangle);
335
+ },
261
336
  getNearestPoint(rectangle, point) {
262
- const cornerPoints = getParallelogramPoints(rectangle);
337
+ return getNearestPointBetweenPointAndSegments(point, getHexagonPoints(rectangle));
338
+ },
339
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
340
+ const corners = getHexagonPoints(rectangle);
341
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
342
+ return getEdgeOnPolygonByPoint(corners, point);
343
+ },
344
+ getConnectorPoints(rectangle) {
345
+ return RectangleClient.getEdgeCenterPoints(rectangle);
346
+ }
347
+ };
348
+ const getHexagonPoints = (rectangle) => {
349
+ return [
350
+ [rectangle.x + rectangle.width / 4, rectangle.y],
351
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y],
352
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
353
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height],
354
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
355
+ [rectangle.x, rectangle.y + rectangle.height / 2]
356
+ ];
357
+ };
358
+
359
+ const LeftArrowEngine = {
360
+ draw(board, rectangle, options) {
361
+ const points = getLeftArrowPoints(rectangle);
362
+ const rs = PlaitBoard.getRoughSVG(board);
363
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
364
+ setStrokeLinecap(polygon, 'round');
365
+ return polygon;
366
+ },
367
+ getCornerPoints(rectangle) {
368
+ return getLeftArrowPoints(rectangle);
369
+ },
370
+ isHit(rectangle, point) {
371
+ const points = getLeftArrowPoints(rectangle);
372
+ return isPointInPolygon(point, points);
373
+ },
374
+ getNearestPoint(rectangle, point) {
375
+ const cornerPoints = getLeftArrowPoints(rectangle);
263
376
  return getNearestPointBetweenPointAndSegments(point, cornerPoints);
264
377
  },
378
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
379
+ const corners = getLeftArrowPoints(rectangle);
380
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
381
+ return getEdgeOnPolygonByPoint(corners, point);
382
+ },
265
383
  getConnectorPoints(rectangle) {
266
- const cornerPoints = getParallelogramPoints(rectangle);
384
+ return [
385
+ [rectangle.x, rectangle.y + rectangle.height / 2],
386
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
387
+ ];
388
+ }
389
+ };
390
+ const getLeftArrowPoints = (rectangle) => {
391
+ return [
392
+ [rectangle.x, rectangle.y + rectangle.height / 2],
393
+ [rectangle.x + rectangle.width * 0.32, rectangle.y],
394
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height * 0.2],
395
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * 0.2],
396
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * 0.8],
397
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height * 0.8],
398
+ [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height]
399
+ ];
400
+ };
401
+
402
+ const OctagonEngine = {
403
+ draw(board, rectangle, options) {
404
+ const points = getOctagonPoints(rectangle);
405
+ const rs = PlaitBoard.getRoughSVG(board);
406
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
407
+ setStrokeLinecap(polygon, 'round');
408
+ return polygon;
409
+ },
410
+ isHit(rectangle, point) {
411
+ const parallelogramPoints = getOctagonPoints(rectangle);
412
+ return isPointInPolygon(point, parallelogramPoints);
413
+ },
414
+ getCornerPoints(rectangle) {
415
+ return getOctagonPoints(rectangle);
416
+ },
417
+ getNearestPoint(rectangle, point) {
418
+ return getNearestPointBetweenPointAndSegments(point, getOctagonPoints(rectangle));
419
+ },
420
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
421
+ const corners = getOctagonPoints(rectangle);
422
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
423
+ return getEdgeOnPolygonByPoint(corners, point);
424
+ },
425
+ getConnectorPoints(rectangle) {
426
+ return RectangleClient.getEdgeCenterPoints(rectangle);
427
+ }
428
+ };
429
+ const getOctagonPoints = (rectangle) => {
430
+ return [
431
+ [rectangle.x + (rectangle.width * 3) / 10, rectangle.y],
432
+ [rectangle.x + (rectangle.width * 7) / 10, rectangle.y],
433
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 3) / 10],
434
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 7) / 10],
435
+ [rectangle.x + (rectangle.width * 7) / 10, rectangle.y + rectangle.height],
436
+ [rectangle.x + (rectangle.width * 3) / 10, rectangle.y + rectangle.height],
437
+ [rectangle.x, rectangle.y + (rectangle.height * 7) / 10],
438
+ [rectangle.x, rectangle.y + (rectangle.height * 3) / 10]
439
+ ];
440
+ };
441
+
442
+ const ParallelogramEngine = {
443
+ draw(board, rectangle, options) {
444
+ const points = getParallelogramCornerPoints(rectangle);
445
+ const rs = PlaitBoard.getRoughSVG(board);
446
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
447
+ setStrokeLinecap(polygon, 'round');
448
+ return polygon;
449
+ },
450
+ isHit(rectangle, point) {
451
+ const parallelogramPoints = getParallelogramCornerPoints(rectangle);
452
+ return isPointInPolygon(point, parallelogramPoints);
453
+ },
454
+ getCornerPoints(rectangle) {
455
+ return getParallelogramCornerPoints(rectangle);
456
+ },
457
+ getNearestPoint(rectangle, point) {
458
+ return getNearestPointBetweenPointAndSegments(point, ParallelogramEngine.getCornerPoints(rectangle));
459
+ },
460
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
461
+ const corners = getParallelogramCornerPoints(rectangle);
462
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
463
+ return getEdgeOnPolygonByPoint(corners, point);
464
+ },
465
+ getConnectorPoints(rectangle) {
466
+ const cornerPoints = getParallelogramCornerPoints(rectangle);
267
467
  return getCenterPointsOnPolygon(cornerPoints);
268
468
  }
269
469
  };
270
- const getParallelogramPoints = (rectangle) => {
470
+ const getParallelogramCornerPoints = (rectangle) => {
271
471
  return [
272
472
  [rectangle.x + rectangle.width / 4, rectangle.y],
273
473
  [rectangle.x + rectangle.width, rectangle.y],
@@ -276,6 +476,119 @@ const getParallelogramPoints = (rectangle) => {
276
476
  ];
277
477
  };
278
478
 
479
+ const PentagonEngine = {
480
+ draw(board, rectangle, options) {
481
+ const points = getPentagonPoints(rectangle);
482
+ const rs = PlaitBoard.getRoughSVG(board);
483
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
484
+ setStrokeLinecap(polygon, 'round');
485
+ return polygon;
486
+ },
487
+ isHit(rectangle, point) {
488
+ const parallelogramPoints = getPentagonPoints(rectangle);
489
+ return isPointInPolygon(point, parallelogramPoints);
490
+ },
491
+ getCornerPoints(rectangle) {
492
+ return getPentagonPoints(rectangle);
493
+ },
494
+ getNearestPoint(rectangle, point) {
495
+ return getNearestPointBetweenPointAndSegments(point, getPentagonPoints(rectangle));
496
+ },
497
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
498
+ const corners = getPentagonPoints(rectangle);
499
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
500
+ return getEdgeOnPolygonByPoint(corners, point);
501
+ },
502
+ getConnectorPoints(rectangle) {
503
+ return getPentagonPoints(rectangle);
504
+ }
505
+ };
506
+ const getPentagonPoints = (rectangle) => {
507
+ return [
508
+ [rectangle.x + rectangle.width / 2, rectangle.y],
509
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 2) / 5],
510
+ [rectangle.x + (rectangle.width * 4) / 5, rectangle.y + rectangle.height],
511
+ [rectangle.x + rectangle.width / 5, rectangle.y + rectangle.height],
512
+ [rectangle.x, rectangle.y + (rectangle.height * 2) / 5]
513
+ ];
514
+ };
515
+
516
+ const PentagonArrowEngine = {
517
+ draw(board, rectangle, options) {
518
+ const points = getPentagonArrowPoints(rectangle);
519
+ const rs = PlaitBoard.getRoughSVG(board);
520
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
521
+ setStrokeLinecap(polygon, 'round');
522
+ return polygon;
523
+ },
524
+ isHit(rectangle, point) {
525
+ const parallelogramPoints = getPentagonArrowPoints(rectangle);
526
+ return isPointInPolygon(point, parallelogramPoints);
527
+ },
528
+ getCornerPoints(rectangle) {
529
+ return getPentagonArrowPoints(rectangle);
530
+ },
531
+ getNearestPoint(rectangle, point) {
532
+ return getNearestPointBetweenPointAndSegments(point, getPentagonArrowPoints(rectangle));
533
+ },
534
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
535
+ const corners = getPentagonArrowPoints(rectangle);
536
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
537
+ return getEdgeOnPolygonByPoint(corners, point);
538
+ },
539
+ getConnectorPoints(rectangle) {
540
+ return RectangleClient.getEdgeCenterPoints(rectangle);
541
+ }
542
+ };
543
+ const getPentagonArrowPoints = (rectangle) => {
544
+ return [
545
+ [rectangle.x, rectangle.y],
546
+ [rectangle.x + (rectangle.width * 3) / 5, rectangle.y],
547
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
548
+ [rectangle.x + (rectangle.width * 3) / 5, rectangle.y + rectangle.height],
549
+ [rectangle.x, rectangle.y + rectangle.height]
550
+ ];
551
+ };
552
+
553
+ const ProcessArrowEngine = {
554
+ draw(board, rectangle, options) {
555
+ const points = getProcessArrowPoints(rectangle);
556
+ const rs = PlaitBoard.getRoughSVG(board);
557
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
558
+ setStrokeLinecap(polygon, 'round');
559
+ return polygon;
560
+ },
561
+ isHit(rectangle, point) {
562
+ const parallelogramPoints = getProcessArrowPoints(rectangle);
563
+ return isPointInPolygon(point, parallelogramPoints);
564
+ },
565
+ getCornerPoints(rectangle) {
566
+ return getProcessArrowPoints(rectangle);
567
+ },
568
+ getNearestPoint(rectangle, point) {
569
+ return getNearestPointBetweenPointAndSegments(point, getProcessArrowPoints(rectangle));
570
+ },
571
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
572
+ const corners = getProcessArrowPoints(rectangle);
573
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
574
+ return getEdgeOnPolygonByPoint(corners, point);
575
+ },
576
+ getConnectorPoints(rectangle) {
577
+ return getProcessArrowPoints(rectangle);
578
+ }
579
+ };
580
+ const getProcessArrowPoints = (rectangle) => {
581
+ const wider = rectangle.width > rectangle.height / 2;
582
+ return [
583
+ [rectangle.x, rectangle.y],
584
+ [rectangle.x + (wider ? rectangle.width - rectangle.height / 2 : 0), rectangle.y],
585
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
586
+ [rectangle.x + (wider ? rectangle.width - rectangle.height / 2 : 0), rectangle.y + rectangle.height],
587
+ [rectangle.x, rectangle.y + rectangle.height],
588
+ [rectangle.x + (wider ? rectangle.height / 2 : rectangle.width), rectangle.y + rectangle.height / 2]
589
+ ];
590
+ };
591
+
279
592
  const RectangleEngine = {
280
593
  draw(board, rectangle, options) {
281
594
  return drawRectangle(board, rectangle, { ...options, fillStyle: 'solid' });
@@ -284,15 +597,65 @@ const RectangleEngine = {
284
597
  const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
285
598
  return RectangleClient.isHit(rectangle, rangeRectangle);
286
599
  },
600
+ getCornerPoints(rectangle) {
601
+ return RectangleClient.getCornerPoints(rectangle);
602
+ },
287
603
  getNearestPoint(rectangle, point) {
288
- const cornerPoints = RectangleClient.getCornerPoints(rectangle);
289
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
604
+ return getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
605
+ },
606
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
607
+ const corners = RectangleEngine.getCornerPoints(rectangle);
608
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
609
+ return getEdgeOnPolygonByPoint(corners, point);
290
610
  },
291
611
  getConnectorPoints(rectangle) {
292
612
  return RectangleClient.getEdgeCenterPoints(rectangle);
293
613
  }
294
614
  };
295
615
 
616
+ const RightArrowEngine = {
617
+ draw(board, rectangle, options) {
618
+ const points = getRightArrowPoints(rectangle);
619
+ const rs = PlaitBoard.getRoughSVG(board);
620
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
621
+ setStrokeLinecap(polygon, 'round');
622
+ return polygon;
623
+ },
624
+ getCornerPoints(rectangle) {
625
+ return getRightArrowPoints(rectangle);
626
+ },
627
+ isHit(rectangle, point) {
628
+ const points = getRightArrowPoints(rectangle);
629
+ return isPointInPolygon(point, points);
630
+ },
631
+ getNearestPoint(rectangle, point) {
632
+ const cornerPoints = getRightArrowPoints(rectangle);
633
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
634
+ },
635
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
636
+ const corners = getRightArrowPoints(rectangle);
637
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
638
+ return getEdgeOnPolygonByPoint(corners, point);
639
+ },
640
+ getConnectorPoints(rectangle) {
641
+ return [
642
+ [rectangle.x, rectangle.y + rectangle.height / 2],
643
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
644
+ ];
645
+ }
646
+ };
647
+ const getRightArrowPoints = (rectangle) => {
648
+ return [
649
+ [rectangle.x, rectangle.y + rectangle.height * 0.2],
650
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.2],
651
+ [rectangle.x + rectangle.width * 0.68, rectangle.y],
652
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
653
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height],
654
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.8],
655
+ [rectangle.x, rectangle.y + rectangle.height * 0.8]
656
+ ];
657
+ };
658
+
296
659
  const RoundRectangleEngine = {
297
660
  draw(board, rectangle, options) {
298
661
  return drawRoundRectangle(PlaitBoard.getRoughSVG(board), rectangle.x, rectangle.y, rectangle.x + rectangle.width, rectangle.y + rectangle.height, { ...options, fillStyle: 'solid' }, false, getRoundRectangleRadius(rectangle));
@@ -300,9 +663,17 @@ const RoundRectangleEngine = {
300
663
  isHit(rectangle, point) {
301
664
  return isPointInRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
302
665
  },
666
+ getCornerPoints(rectangle) {
667
+ return RectangleClient.getCornerPoints(rectangle);
668
+ },
303
669
  getNearestPoint(rectangle, point) {
304
670
  return getNearestPointBetweenPointAndRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
305
671
  },
672
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
673
+ const corners = RectangleEngine.getCornerPoints(rectangle);
674
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
675
+ return getEdgeOnPolygonByPoint(corners, point);
676
+ },
306
677
  getConnectorPoints(rectangle) {
307
678
  return RectangleClient.getEdgeCenterPoints(rectangle);
308
679
  }
@@ -337,8 +708,248 @@ function getNearestPointBetweenPointAndRoundRectangle(point, rectangle, radius)
337
708
  if (circleCenter) {
338
709
  result = getNearestPointBetweenPointAndEllipse(point, circleCenter, radius, radius);
339
710
  }
340
- return result;
341
- }
711
+ return result;
712
+ }
713
+
714
+ const heightRatio = 3 / 4;
715
+ const RoundCommentEngine = {
716
+ draw(board, rectangle, options) {
717
+ const rs = PlaitBoard.getRoughSVG(board);
718
+ const x1 = rectangle.x;
719
+ const y1 = rectangle.y;
720
+ const x2 = rectangle.x + rectangle.width;
721
+ const y2 = rectangle.y + rectangle.height * heightRatio;
722
+ const radius = getRoundRectangleRadius(rectangle);
723
+ const point1 = [x1 + radius, y1];
724
+ const point2 = [x2 - radius, y1];
725
+ const point3 = [x2, y1 + radius];
726
+ const point4 = [x2, y2 - radius];
727
+ const point5 = [x2 - radius, y2];
728
+ const point6 = [x1 + radius, y2];
729
+ const point7 = [x1, y2 - radius];
730
+ const point8 = [x1, y1 + radius];
731
+ const point9 = [x1 + rectangle.width / 4, y2];
732
+ const point10 = [x1 + rectangle.width / 4, rectangle.y + rectangle.height];
733
+ const point11 = [x1 + rectangle.width / 2, y2];
734
+ 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);
735
+ },
736
+ isHit(rectangle, point) {
737
+ const points = [
738
+ [rectangle.x + rectangle.width / 4, rectangle.y + (rectangle.height * 3) / 4],
739
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
740
+ [rectangle.x + rectangle.width / 2, rectangle.y + (rectangle.height * 3) / 4]
741
+ ];
742
+ rectangle.height = (rectangle.height * 3) / 4;
743
+ return isPointInPolygon(point, points) || isPointInRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
744
+ },
745
+ getCornerPoints(rectangle) {
746
+ return getRoundCommentPoints(rectangle);
747
+ },
748
+ getNearestPoint(rectangle, point) {
749
+ return getNearestPointBetweenPointAndSegments(point, getRoundCommentPoints(rectangle));
750
+ },
751
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
752
+ const corners = getRoundCommentPoints(rectangle);
753
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
754
+ return getEdgeOnPolygonByPoint(corners, point);
755
+ },
756
+ getConnectorPoints(rectangle) {
757
+ return [
758
+ [rectangle.x + rectangle.width / 2, rectangle.y],
759
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
760
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height * heightRatio],
761
+ [rectangle.x, rectangle.y + rectangle.height / 2]
762
+ ];
763
+ },
764
+ getTextRectangle(element) {
765
+ const elementRectangle = getRectangleByPoints(element.points);
766
+ const strokeWidth = getStrokeWidthByElement(element);
767
+ const height = element.textHeight;
768
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
769
+ return {
770
+ height,
771
+ width: width > 0 ? width : 0,
772
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
773
+ y: elementRectangle.y + (elementRectangle.height * heightRatio - height) / 2
774
+ };
775
+ }
776
+ };
777
+ const getRoundCommentPoints = (rectangle) => {
778
+ return [
779
+ [rectangle.x, rectangle.y],
780
+ [rectangle.x + rectangle.width, rectangle.y],
781
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height * heightRatio],
782
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height * heightRatio],
783
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height],
784
+ [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height * heightRatio],
785
+ [rectangle.x, rectangle.y + rectangle.height * heightRatio]
786
+ ];
787
+ };
788
+
789
+ const StarEngine = {
790
+ draw(board, rectangle, options) {
791
+ const points = getStarPoints(rectangle);
792
+ const rs = PlaitBoard.getRoughSVG(board);
793
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
794
+ setStrokeLinecap(polygon, 'round');
795
+ return polygon;
796
+ },
797
+ isHit(rectangle, point) {
798
+ const parallelogramPoints = getStarPoints(rectangle);
799
+ return isPointInPolygon(point, parallelogramPoints);
800
+ },
801
+ getCornerPoints(rectangle) {
802
+ return getStarPoints(rectangle);
803
+ },
804
+ getNearestPoint(rectangle, point) {
805
+ return getNearestPointBetweenPointAndSegments(point, getStarPoints(rectangle));
806
+ },
807
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
808
+ const corners = getStarPoints(rectangle);
809
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
810
+ return getEdgeOnPolygonByPoint(corners, point);
811
+ },
812
+ getConnectorPoints(rectangle) {
813
+ const points = getStarPoints(rectangle);
814
+ return [points[1], points[3], points[5], points[7], points[9]];
815
+ }
816
+ };
817
+ const getStarPoints = (rectangle) => {
818
+ return [
819
+ [rectangle.x + rectangle.width / 2, rectangle.y + (rectangle.height * 75) / 91],
820
+ [rectangle.x + (rectangle.width * 18.61) / 96, rectangle.y + rectangle.height],
821
+ [rectangle.x + (rectangle.width * 24.2235871) / 96, rectangle.y + (rectangle.height * 57.7254249) / 91],
822
+ [rectangle.x, rectangle.y + (rectangle.height * 34.5491503) / 91],
823
+ [rectangle.x + (rectangle.width * 33.3053687) / 96, rectangle.y + (rectangle.height * 29.7745751) / 91],
824
+ [rectangle.x + rectangle.width / 2, rectangle.y],
825
+ [rectangle.x + (rectangle.width * 62.6946313) / 96, rectangle.y + (rectangle.height * 29.7745751) / 91],
826
+ [rectangle.x + rectangle.width, rectangle.y + (rectangle.height * 34.5491503) / 91],
827
+ [rectangle.x + (rectangle.width * 71.7764129) / 96, rectangle.y + (rectangle.height * 57.7254249) / 91],
828
+ [rectangle.x + (rectangle.width * 77.3892626) / 96, rectangle.y + rectangle.height]
829
+ ];
830
+ };
831
+
832
+ const TrapezoidEngine = {
833
+ draw(board, rectangle, options) {
834
+ const points = getTrapezoidPoints(rectangle);
835
+ const rs = PlaitBoard.getRoughSVG(board);
836
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
837
+ setStrokeLinecap(polygon, 'round');
838
+ return polygon;
839
+ },
840
+ isHit(rectangle, point) {
841
+ const points = getTrapezoidPoints(rectangle);
842
+ return isPointInPolygon(point, points);
843
+ },
844
+ getNearestPoint(rectangle, point) {
845
+ const cornerPoints = getTrapezoidPoints(rectangle);
846
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
847
+ },
848
+ getConnectorPoints(rectangle) {
849
+ const points = getTrapezoidPoints(rectangle);
850
+ return getCenterPointsOnPolygon(points);
851
+ },
852
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
853
+ const corners = getTrapezoidPoints(rectangle);
854
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
855
+ return getEdgeOnPolygonByPoint(corners, point);
856
+ },
857
+ getCornerPoints(rectangle) {
858
+ return getTrapezoidPoints(rectangle);
859
+ }
860
+ };
861
+ const getTrapezoidPoints = (rectangle) => {
862
+ return [
863
+ [rectangle.x + rectangle.width * 0.15, rectangle.y],
864
+ [rectangle.x + rectangle.width * 0.85, rectangle.y],
865
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
866
+ [rectangle.x, rectangle.y + rectangle.height]
867
+ ];
868
+ };
869
+
870
+ const TriangleEngine = {
871
+ draw(board, rectangle, options) {
872
+ const points = getTrianglePoints(rectangle);
873
+ const rs = PlaitBoard.getRoughSVG(board);
874
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
875
+ setStrokeLinecap(polygon, 'round');
876
+ return polygon;
877
+ },
878
+ isHit(rectangle, point) {
879
+ const points = getTrianglePoints(rectangle);
880
+ return isPointInPolygon(point, points);
881
+ },
882
+ getNearestPoint(rectangle, point) {
883
+ const cornerPoints = getTrianglePoints(rectangle);
884
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
885
+ },
886
+ getConnectorPoints(rectangle) {
887
+ const cornerPoints = getTrianglePoints(rectangle);
888
+ const lineCenterPoints = getCenterPointsOnPolygon(cornerPoints);
889
+ return [...lineCenterPoints, ...cornerPoints];
890
+ },
891
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
892
+ const corners = getTrianglePoints(rectangle);
893
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
894
+ return getEdgeOnPolygonByPoint(corners, point);
895
+ },
896
+ getCornerPoints(rectangle) {
897
+ return getTrianglePoints(rectangle);
898
+ }
899
+ };
900
+ const getTrianglePoints = (rectangle) => {
901
+ return [
902
+ [rectangle.x + rectangle.width / 2, rectangle.y],
903
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
904
+ [rectangle.x, rectangle.y + rectangle.height]
905
+ ];
906
+ };
907
+
908
+ const TwoWayArrowEngine = {
909
+ draw(board, rectangle, options) {
910
+ const points = getTwoWayArrowPoints(rectangle);
911
+ const rs = PlaitBoard.getRoughSVG(board);
912
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
913
+ setStrokeLinecap(polygon, 'round');
914
+ return polygon;
915
+ },
916
+ getCornerPoints(rectangle) {
917
+ return getTwoWayArrowPoints(rectangle);
918
+ },
919
+ isHit(rectangle, point) {
920
+ const points = getTwoWayArrowPoints(rectangle);
921
+ return isPointInPolygon(point, points);
922
+ },
923
+ getNearestPoint(rectangle, point) {
924
+ const cornerPoints = getTwoWayArrowPoints(rectangle);
925
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
926
+ },
927
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
928
+ const corners = getTwoWayArrowPoints(rectangle);
929
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
930
+ return getEdgeOnPolygonByPoint(corners, point);
931
+ },
932
+ getConnectorPoints(rectangle) {
933
+ return [
934
+ [rectangle.x, rectangle.y + rectangle.height / 2],
935
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
936
+ ];
937
+ }
938
+ };
939
+ const getTwoWayArrowPoints = (rectangle) => {
940
+ return [
941
+ [rectangle.x, rectangle.y + rectangle.height / 2],
942
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y],
943
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + rectangle.height / 5],
944
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + rectangle.height / 5],
945
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y],
946
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
947
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + rectangle.height],
948
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + (rectangle.height * 4) / 5],
949
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + (rectangle.height * 4) / 5],
950
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + rectangle.height]
951
+ ];
952
+ };
342
953
 
343
954
  const ShapeEngineMap = {
344
955
  [GeometryShape.rectangle]: RectangleEngine,
@@ -346,12 +957,33 @@ const ShapeEngineMap = {
346
957
  [GeometryShape.ellipse]: EllipseEngine,
347
958
  [GeometryShape.parallelogram]: ParallelogramEngine,
348
959
  [GeometryShape.roundRectangle]: RoundRectangleEngine,
349
- [GeometryShape.text]: RectangleEngine
960
+ [GeometryShape.text]: RectangleEngine,
961
+ [GeometryShape.triangle]: TriangleEngine,
962
+ [GeometryShape.leftArrow]: LeftArrowEngine,
963
+ [GeometryShape.trapezoid]: TrapezoidEngine,
964
+ [GeometryShape.rightArrow]: RightArrowEngine,
965
+ [GeometryShape.cross]: CrossEngine,
966
+ [GeometryShape.star]: StarEngine,
967
+ [GeometryShape.pentagon]: PentagonEngine,
968
+ [GeometryShape.hexagon]: HexagonEngine,
969
+ [GeometryShape.octagon]: OctagonEngine,
970
+ [GeometryShape.pentagonArrow]: PentagonArrowEngine,
971
+ [GeometryShape.processArrow]: ProcessArrowEngine,
972
+ [GeometryShape.twoWayArrow]: TwoWayArrowEngine,
973
+ [GeometryShape.comment]: CommentEngine,
974
+ [GeometryShape.roundComment]: RoundCommentEngine
350
975
  };
351
976
  const getEngine = (shape) => {
352
977
  return ShapeEngineMap[shape];
353
978
  };
354
979
 
980
+ const getShape = (value) => {
981
+ if (PlaitDrawElement.isImage(value)) {
982
+ return GeometryShape.rectangle;
983
+ }
984
+ return value.shape;
985
+ };
986
+
355
987
  const createGeometryElement = (shape, points, text, options) => {
356
988
  let textOptions = {};
357
989
  let alignment = Alignment.center;
@@ -393,14 +1025,15 @@ const drawBoundMask = (board, element) => {
393
1025
  const G = createG();
394
1026
  const rectangle = getRectangleByPoints(element.points);
395
1027
  const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
396
- const maskG = drawGeometry(board, activeRectangle, element.shape, {
1028
+ const shape = getShape(element);
1029
+ const maskG = drawGeometry(board, activeRectangle, shape, {
397
1030
  stroke: SELECTION_BORDER_COLOR,
398
1031
  strokeWidth: 1,
399
1032
  fill: SELECTION_FILL_COLOR,
400
1033
  fillStyle: 'solid'
401
1034
  });
402
1035
  G.appendChild(maskG);
403
- const connectorPoints = getEngine(element.shape).getConnectorPoints(activeRectangle);
1036
+ const connectorPoints = getEngine(shape).getConnectorPoints(activeRectangle);
404
1037
  connectorPoints.forEach(point => {
405
1038
  const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
406
1039
  stroke: '#999999',
@@ -418,7 +1051,8 @@ const drawGeometry = (board, outerRectangle, shape, options) => {
418
1051
  const getNearestPoint = (element, point, inflateDelta = 0) => {
419
1052
  const rectangle = getRectangleByPoints(element.points);
420
1053
  const activeRectangle = RectangleClient.inflate(rectangle, inflateDelta);
421
- return getEngine(element.shape).getNearestPoint(activeRectangle, point);
1054
+ const shape = getShape(element);
1055
+ return getEngine(shape).getNearestPoint(activeRectangle, point);
422
1056
  };
423
1057
  const getCenterPointsOnPolygon = (points) => {
424
1058
  const centerPoint = [];
@@ -428,6 +1062,17 @@ const getCenterPointsOnPolygon = (points) => {
428
1062
  }
429
1063
  return centerPoint;
430
1064
  };
1065
+ const getEdgeOnPolygonByPoint = (corners, point) => {
1066
+ for (let index = 1; index <= corners.length; index++) {
1067
+ let start = corners[index - 1];
1068
+ let end = index === corners.length ? corners[0] : corners[index];
1069
+ const distance = distanceBetweenPointAndSegment(point[0], point[1], start[0], start[1], end[0], end[1]);
1070
+ if (distance < 1) {
1071
+ return [start, end];
1072
+ }
1073
+ }
1074
+ return null;
1075
+ };
431
1076
 
432
1077
  const drawLineArrow = (element, points, options) => {
433
1078
  const arrowG = createG();
@@ -435,16 +1080,19 @@ const drawLineArrow = (element, points, options) => {
435
1080
  return null;
436
1081
  }
437
1082
  if (!PlaitLine.isSourceMark(element, LineMarkerType.none)) {
438
- const sourceArrow = getArrow(element, element.source.marker, points[1], points[0], options);
1083
+ const source = getExtendPoint(points[0], points[1], 24);
1084
+ const sourceArrow = getArrow(element, { marker: element.source.marker, source, target: points[0], isSource: true }, options);
439
1085
  sourceArrow && arrowG.appendChild(sourceArrow);
440
1086
  }
441
1087
  if (!PlaitLine.isTargetMark(element, LineMarkerType.none)) {
442
- const arrow = getArrow(element, element.target.marker, points[points.length - 2], points[points.length - 1], options);
1088
+ const source = getExtendPoint(points[points.length - 1], points[points.length - 2], 24);
1089
+ const arrow = getArrow(element, { marker: element.target.marker, source, target: points[points.length - 1], isSource: false }, options);
443
1090
  arrow && arrowG.appendChild(arrow);
444
1091
  }
445
1092
  return arrowG;
446
1093
  };
447
- const getArrow = (element, marker, source, target, options) => {
1094
+ const getArrow = (element, arrowOptions, options) => {
1095
+ const { marker, source, target, isSource } = arrowOptions;
448
1096
  let targetArrow;
449
1097
  switch (marker) {
450
1098
  case LineMarkerType.openTriangle: {
@@ -463,16 +1111,27 @@ const getArrow = (element, marker, source, target, options) => {
463
1111
  targetArrow = drawSharpArrow(source, target, options);
464
1112
  break;
465
1113
  }
1114
+ case LineMarkerType.oneSideUp: {
1115
+ targetArrow = drawOneSideArrow(source, target, 'up', options);
1116
+ break;
1117
+ }
1118
+ case LineMarkerType.oneSideDown: {
1119
+ targetArrow = drawOneSideArrow(source, target, 'down', options);
1120
+ break;
1121
+ }
1122
+ case LineMarkerType.hollowTriangle: {
1123
+ targetArrow = drawHollowTriangleArrow(source, target, options);
1124
+ break;
1125
+ }
1126
+ case LineMarkerType.singleSlash: {
1127
+ targetArrow = drawSingleSlash(source, target, isSource, options);
1128
+ break;
1129
+ }
466
1130
  }
467
1131
  return targetArrow;
468
1132
  };
469
1133
  const drawSharpArrow = (source, target, options) => {
470
- const directionFactor = getFactorByPoints(source, target);
471
1134
  const startPoint = target;
472
- // const startPoint: Point = [
473
- // target[0],
474
- // target[1]
475
- // ];
476
1135
  const { pointLeft, pointRight } = arrowPoints(source, target, 12, 20);
477
1136
  const g = createG();
478
1137
  const path = createPath();
@@ -487,10 +1146,7 @@ const drawSharpArrow = (source, target, options) => {
487
1146
  const drawArrow = (element, source, target, options) => {
488
1147
  const directionFactor = getFactorByPoints(source, target);
489
1148
  const strokeWidth = getStrokeWidthByElement(element);
490
- const endPoint = [
491
- target[0] + strokeWidth * directionFactor.x / 2,
492
- target[1] + strokeWidth * directionFactor.y / 2
493
- ];
1149
+ const endPoint = [target[0] + (strokeWidth * directionFactor.x) / 2, target[1] + (strokeWidth * directionFactor.y) / 2];
494
1150
  const middlePoint = [endPoint[0] - 8 * directionFactor.x, endPoint[1] - 8 * directionFactor.y];
495
1151
  const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 30);
496
1152
  const arrowG = drawLinearPath([pointLeft, endPoint, pointRight, middlePoint], { ...options, fill: options.stroke }, true);
@@ -506,13 +1162,26 @@ const drawSolidTriangle = (source, target, options) => {
506
1162
  const drawOpenTriangle = (element, source, target, options) => {
507
1163
  const directionFactor = getFactorByPoints(source, target);
508
1164
  const strokeWidth = getStrokeWidthByElement(element);
509
- const endPoint = [
510
- target[0] + strokeWidth * directionFactor.x / 2,
511
- target[1] + strokeWidth * directionFactor.y / 2
512
- ];
1165
+ const endPoint = [target[0] + (strokeWidth * directionFactor.x) / 2, target[1] + (strokeWidth * directionFactor.y) / 2];
513
1166
  const { pointLeft, pointRight } = arrowPoints(source, endPoint, 12, 40);
514
1167
  return drawLinearPath([pointLeft, endPoint, pointRight], options);
515
1168
  };
1169
+ const drawOneSideArrow = (source, target, side, options) => {
1170
+ const { pointLeft, pointRight } = arrowPoints(source, target, 12, 40);
1171
+ return drawLinearPath([side === 'up' ? pointRight : pointLeft, target], options);
1172
+ };
1173
+ const drawSingleSlash = (source, target, isSource, options) => {
1174
+ source = getExtendPoint(target, source, 12);
1175
+ const middlePoint = getExtendPoint(target, source, 6);
1176
+ const angle = isSource ? 120 : 60;
1177
+ const start = rotate(...source, ...middlePoint, (angle * Math.PI) / 180);
1178
+ const end = rotate(...target, ...middlePoint, (angle * Math.PI) / 180);
1179
+ return drawLinearPath([start, end], options);
1180
+ };
1181
+ const drawHollowTriangleArrow = (source, target, options) => {
1182
+ const { pointLeft, pointRight } = arrowPoints(source, target, 12, 30);
1183
+ return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
1184
+ };
516
1185
 
517
1186
  const createLineElement = (shape, points, source, target, options) => {
518
1187
  return {
@@ -528,28 +1197,127 @@ const createLineElement = (shape, points, source, target, options) => {
528
1197
  };
529
1198
  };
530
1199
  const getLinePoints = (board, element) => {
531
- return element.shape === LineShape.elbow ? getElbowPoints(board, element) : getStraightPoints(board, element);
1200
+ switch (element.shape) {
1201
+ case LineShape.elbow: {
1202
+ return getElbowPoints(board, element);
1203
+ }
1204
+ case LineShape.curve: {
1205
+ return getCurvePoints(board, element);
1206
+ }
1207
+ default: {
1208
+ return PlaitLine.getPoints(board, element);
1209
+ }
1210
+ }
532
1211
  };
533
- const getStraightPoints = (board, element) => {
534
- return [getSourcePoint(board, element), getTargetPoint(board, element)];
1212
+ const getLineHandleRefPair = (board, element) => {
1213
+ const strokeWidth = getStrokeWidthByElement(element);
1214
+ const sourceBoundElement = element.source.boundId ? getElementById(board, element.source.boundId) : undefined;
1215
+ const targetBoundElement = element.target.boundId ? getElementById(board, element.target.boundId) : undefined;
1216
+ let sourcePoint = sourceBoundElement ? getConnectionPoint(sourceBoundElement, element.source.connection) : element.points[0];
1217
+ let targetPoint = targetBoundElement
1218
+ ? getConnectionPoint(targetBoundElement, element.target.connection)
1219
+ : element.points[element.points.length - 1];
1220
+ let sourceDirection = getDirectionByVector([targetPoint[0] - sourcePoint[0], targetPoint[1] - sourcePoint[1]]);
1221
+ let targetDirection = getOppositeDirection(sourceDirection);
1222
+ const sourceFactor = getDirectionFactor(sourceDirection);
1223
+ const targetFactor = getDirectionFactor(targetDirection);
1224
+ const sourceHandleRef = {
1225
+ key: LineHandleKey.source,
1226
+ point: sourcePoint,
1227
+ direction: sourceDirection,
1228
+ vector: [sourceFactor.x, sourceFactor.y]
1229
+ };
1230
+ const targetHandleRef = {
1231
+ key: LineHandleKey.target,
1232
+ point: targetPoint,
1233
+ direction: targetDirection,
1234
+ vector: [targetFactor.x, targetFactor.y]
1235
+ };
1236
+ if (sourceBoundElement) {
1237
+ const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.source) ? 0 : strokeWidth;
1238
+ const sourceVector = getVectorByConnection(sourceBoundElement, element.source.connection);
1239
+ const direction = getDirectionByVector(sourceVector);
1240
+ sourceDirection = direction ? direction : sourceDirection;
1241
+ sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
1242
+ sourceHandleRef.boundElement = sourceBoundElement;
1243
+ sourceHandleRef.direction = sourceDirection;
1244
+ sourceHandleRef.point = sourcePoint;
1245
+ sourceHandleRef.vector = sourceVector;
1246
+ }
1247
+ if (targetBoundElement) {
1248
+ const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.target) ? 0 : strokeWidth;
1249
+ const targetVector = getVectorByConnection(targetBoundElement, element.target.connection);
1250
+ const direction = getDirectionByVector(targetVector);
1251
+ targetDirection = direction ? direction : targetDirection;
1252
+ targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
1253
+ targetHandleRef.boundElement = targetBoundElement;
1254
+ targetHandleRef.direction = targetDirection;
1255
+ targetHandleRef.point = targetPoint;
1256
+ targetHandleRef.vector = targetVector;
1257
+ }
1258
+ return { source: sourceHandleRef, target: targetHandleRef };
535
1259
  };
536
1260
  const getElbowPoints = (board, element) => {
537
1261
  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);
1262
+ const handleRefPair = getLineHandleRefPair(board, element);
1263
+ const offset = element.source.boundId || element.target.boundId ? 30 : 0;
1264
+ let points = getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, offset);
1265
+ points = removeDuplicatePoints(points);
549
1266
  return points;
550
1267
  }
551
1268
  return element.points;
552
1269
  };
1270
+ const getCurvePoints = (board, element) => {
1271
+ if (element.points.length === 2) {
1272
+ const handleRefPair = getLineHandleRefPair(board, element);
1273
+ const { source, target } = handleRefPair;
1274
+ const sourceBoundElement = handleRefPair.source.boundElement;
1275
+ const targetBoundElement = handleRefPair.target.boundElement;
1276
+ let curvePoints = [source.point];
1277
+ const sumDistance = distanceBetweenPointAndPoint(...source.point, ...target.point);
1278
+ const offset = 12 + sumDistance / 3;
1279
+ if (sourceBoundElement) {
1280
+ curvePoints.push(getPointByVector(source.point, source.vector, offset));
1281
+ }
1282
+ if (targetBoundElement) {
1283
+ curvePoints.push(getPointByVector(target.point, target.vector, offset));
1284
+ }
1285
+ const isSingleBound = (sourceBoundElement && !targetBoundElement) || (!sourceBoundElement && targetBoundElement);
1286
+ if (isSingleBound) {
1287
+ curvePoints.push(target.point);
1288
+ const points = Q2C(curvePoints);
1289
+ return pointsOnBezierCurves(points);
1290
+ }
1291
+ if (!sourceBoundElement && !targetBoundElement) {
1292
+ curvePoints.push(getPointByVector(source.point, source.vector, offset));
1293
+ curvePoints.push(getPointByVector(target.point, target.vector, offset));
1294
+ }
1295
+ curvePoints.push(target.point);
1296
+ return pointsOnBezierCurves(curvePoints);
1297
+ }
1298
+ else {
1299
+ //TODO 直接获取贝塞尔曲线上高密度点
1300
+ const points = PlaitLine.getPoints(board, element);
1301
+ const draw = PlaitBoard.getRoughSVG(board).generator.curve(points);
1302
+ let bezierPoints = transformOpsToPoints(draw.sets[0].ops);
1303
+ bezierPoints = removeDuplicatePoints(bezierPoints);
1304
+ return pointsOnBezierCurves(bezierPoints);
1305
+ }
1306
+ };
1307
+ const transformOpsToPoints = (ops) => {
1308
+ const result = [];
1309
+ for (let item of ops) {
1310
+ if (item.op === 'move') {
1311
+ result.push([item.data[0], item.data[1]]);
1312
+ }
1313
+ else {
1314
+ result.push([item.data[0], item.data[1]]);
1315
+ result.push([item.data[2], item.data[3]]);
1316
+ result.push([item.data[4], item.data[5]]);
1317
+ }
1318
+ }
1319
+ return result;
1320
+ };
553
1321
  const isHitPolyLine = (pathPoints, point, strokeWidth, expand = 0) => {
554
1322
  const distance = distanceBetweenPointAndSegments(pathPoints, point);
555
1323
  return distance <= strokeWidth + expand;
@@ -579,8 +1347,15 @@ const drawLine = (board, element) => {
579
1347
  const strokeLineDash = getLineDashByElement(element);
580
1348
  const options = { stroke: strokeColor, strokeWidth, strokeLineDash };
581
1349
  const lineG = createG();
582
- const points = getLinePoints(board, element);
583
- const line = drawLinearPath(points, options);
1350
+ let points = getLinePoints(board, element);
1351
+ let line;
1352
+ if (element.shape === LineShape.curve) {
1353
+ //TODO element.points 应为曲线拐点
1354
+ line = PlaitBoard.getRoughSVG(board).curve(points, options);
1355
+ }
1356
+ else {
1357
+ line = drawLinearPath(points, options);
1358
+ }
584
1359
  const id = idCreator();
585
1360
  line.setAttribute('mask', `url(#${id})`);
586
1361
  lineG.appendChild(line);
@@ -614,33 +1389,16 @@ function drawMask(board, element, id) {
614
1389
  maskTargetFillRect.setAttribute('opacity', '0');
615
1390
  return { mask, maskTargetFillRect };
616
1391
  }
617
- const getSourcePoint = (board, element) => {
618
- if (element.source.boundId) {
619
- const strokeWidth = getStrokeWidthByElement(element);
620
- const connectionOffset = PlaitLine.isSourceMark(element, LineMarkerType.none) ? 0 : strokeWidth;
621
- const boundElement = getElementById(board, element.source.boundId);
622
- return boundElement ? getConnectionPoint(boundElement, element.source.connection, connectionOffset) : element.points[0];
1392
+ const getConnectionPoint = (geometry, connection, direction, delta) => {
1393
+ const rectangle = getRectangleByPoints(geometry.points);
1394
+ if (direction && delta) {
1395
+ const directionFactor = getDirectionFactor(direction);
1396
+ const point = RectangleClient.getConnectionPoint(rectangle, connection);
1397
+ return [point[0] + directionFactor.x * delta, point[1] + directionFactor.y * delta];
623
1398
  }
624
- return element.points[0];
625
- };
626
- const getTargetPoint = (board, element) => {
627
- if (element.target.boundId) {
628
- const strokeWidth = getStrokeWidthByElement(element);
629
- const connectionOffset = PlaitLine.isTargetMark(element, LineMarkerType.none) ? 0 : strokeWidth;
630
- const boundElement = getElementById(board, element.target.boundId);
631
- return boundElement
632
- ? getConnectionPoint(boundElement, element.target.connection, connectionOffset)
633
- : element.points[element.points.length - 1];
1399
+ else {
1400
+ return RectangleClient.getConnectionPoint(rectangle, connection);
634
1401
  }
635
- return element.points[element.points.length - 1];
636
- };
637
- const getConnectionPoint = (geometry, connection, offset) => {
638
- const rectangle = getRectangleByPoints(geometry.points);
639
- const directionFactor = getDirectionFactor(getDirectionByPoint(connection, Direction.bottom));
640
- return [
641
- rectangle.x + rectangle.width * connection[0] + directionFactor.x * offset,
642
- rectangle.y + rectangle.height * connection[1] + directionFactor.y * offset
643
- ];
644
1402
  };
645
1403
  const transformPointToConnection = (board, point, hitElement) => {
646
1404
  let rectangle = getRectangleByPoints(hitElement.points);
@@ -651,7 +1409,8 @@ const transformPointToConnection = (board, point, hitElement) => {
651
1409
  return [(nearestPoint[0] - rectangle.x) / rectangle.width, (nearestPoint[1] - rectangle.y) / rectangle.height];
652
1410
  };
653
1411
  const getHitConnectorPoint = (movingPoint, hitElement, rectangle) => {
654
- const connector = getEngine(hitElement.shape).getConnectorPoints(rectangle);
1412
+ const shape = getShape(hitElement);
1413
+ const connector = getEngine(shape).getConnectorPoints(rectangle);
655
1414
  const points = getPointsByCenterPoint(movingPoint, 5, 5);
656
1415
  const pointRectangle = getRectangleByPoints(points);
657
1416
  return connector.find(point => {
@@ -675,6 +1434,64 @@ const getBoardLines = (board) => {
675
1434
  recursion: (element) => PlaitDrawElement.isDrawElement(element)
676
1435
  });
677
1436
  };
1437
+ const removeDuplicatePoints = (points) => {
1438
+ const newArray = [];
1439
+ points.forEach(point => {
1440
+ const index = newArray.findIndex(otherPoint => {
1441
+ return point[0] === otherPoint[0] && point[1] === otherPoint[1];
1442
+ });
1443
+ if (index === -1)
1444
+ newArray.push(point);
1445
+ });
1446
+ return newArray;
1447
+ };
1448
+ const getExtendPoint = (source, target, extendDistance) => {
1449
+ const distance = distanceBetweenPointAndPoint(...source, ...target);
1450
+ const sin = (target[1] - source[1]) / distance;
1451
+ const cos = (target[0] - source[0]) / distance;
1452
+ return [source[0] + extendDistance * cos, source[1] + extendDistance * sin];
1453
+ };
1454
+ // quadratic Bezier to cubic Bezier
1455
+ const Q2C = (points) => {
1456
+ const result = [];
1457
+ const numSegments = points.length / 3;
1458
+ for (let i = 0; i < numSegments; i++) {
1459
+ const start = points[i];
1460
+ const qControl = points[i + 1];
1461
+ const end = points[i + 2];
1462
+ const startDistance = distanceBetweenPointAndPoint(...start, ...qControl);
1463
+ const endDistance = distanceBetweenPointAndPoint(...end, ...qControl);
1464
+ const cControl1 = getExtendPoint(start, qControl, (startDistance * 2) / 3);
1465
+ const cControl2 = getExtendPoint(end, qControl, (endDistance * 2) / 3);
1466
+ result.push(start, cControl1, cControl2, end);
1467
+ }
1468
+ return result;
1469
+ };
1470
+ const getVectorByConnection = (boundElement, connection) => {
1471
+ const rectangle = getRectangleByPoints(boundElement.points);
1472
+ const shape = getShape(boundElement);
1473
+ const engine = getEngine(shape);
1474
+ let vector = [0, 0];
1475
+ const direction = getDirectionByPointOfRectangle(connection);
1476
+ if (direction) {
1477
+ const factor = getDirectionFactor(direction);
1478
+ return [factor.x, factor.y];
1479
+ }
1480
+ if (engine.getEdgeByConnectionPoint) {
1481
+ const edge = engine.getEdgeByConnectionPoint(rectangle, connection);
1482
+ if (edge) {
1483
+ const lineVector = [edge[1][0] - edge[0][0], edge[1][1] - edge[0][1]];
1484
+ return rotateVectorAnti90(lineVector);
1485
+ }
1486
+ }
1487
+ if (engine.getTangentVectorByConnectionPoint) {
1488
+ const lineVector = engine.getTangentVectorByConnectionPoint(rectangle, connection);
1489
+ if (lineVector) {
1490
+ return rotateVectorAnti90(lineVector);
1491
+ }
1492
+ }
1493
+ return vector;
1494
+ };
678
1495
 
679
1496
  const getSelectedDrawElements = (board) => {
680
1497
  const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isDrawElement(value));
@@ -688,6 +1505,111 @@ const getSelectedLineElements = (board) => {
688
1505
  const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isLine(value));
689
1506
  return selectedElements;
690
1507
  };
1508
+ const getSelectedImageElements = (board) => {
1509
+ const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isImage(value));
1510
+ return selectedElements;
1511
+ };
1512
+
1513
+ var LineMarkerType;
1514
+ (function (LineMarkerType) {
1515
+ LineMarkerType["arrow"] = "arrow";
1516
+ LineMarkerType["none"] = "none";
1517
+ LineMarkerType["openTriangle"] = "open-triangle";
1518
+ LineMarkerType["solidTriangle"] = "solid-triangle";
1519
+ LineMarkerType["sharpArrow"] = "sharp-arrow";
1520
+ LineMarkerType["oneSideUp"] = "one-side-up";
1521
+ LineMarkerType["oneSideDown"] = "one-side-down";
1522
+ LineMarkerType["hollowTriangle"] = "hollow-triangle";
1523
+ LineMarkerType["singleSlash"] = "single-slash";
1524
+ })(LineMarkerType || (LineMarkerType = {}));
1525
+ var LineShape;
1526
+ (function (LineShape) {
1527
+ LineShape["straight"] = "straight";
1528
+ LineShape["curve"] = "curve";
1529
+ LineShape["elbow"] = "elbow";
1530
+ })(LineShape || (LineShape = {}));
1531
+ var LineHandleKey;
1532
+ (function (LineHandleKey) {
1533
+ LineHandleKey["source"] = "source";
1534
+ LineHandleKey["target"] = "target";
1535
+ })(LineHandleKey || (LineHandleKey = {}));
1536
+ const PlaitLine = {
1537
+ getTextEditors(element) {
1538
+ const component = PlaitElement.getComponent(element);
1539
+ if (component) {
1540
+ const manage = component.textManages.find(manage => manage.isEditing);
1541
+ if (manage) {
1542
+ return [manage.componentRef.instance.editor];
1543
+ }
1544
+ else {
1545
+ return component.textManages.map(manage => manage.componentRef.instance.editor);
1546
+ }
1547
+ }
1548
+ throw new Error('can not get correctly component in get text editor');
1549
+ },
1550
+ isSourceMarkOrTargetMark(line, markType, handleKey) {
1551
+ if (handleKey === LineHandleKey.source) {
1552
+ return line.source.marker === markType;
1553
+ }
1554
+ else {
1555
+ return line.target.marker === markType;
1556
+ }
1557
+ },
1558
+ isSourceMark(line, markType) {
1559
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.source);
1560
+ },
1561
+ isTargetMark(line, markType) {
1562
+ return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.target);
1563
+ },
1564
+ isBoundElementOfSource(line, element) {
1565
+ return line.source.boundId === element.id;
1566
+ },
1567
+ isBoundElementOfTarget(line, element) {
1568
+ return line.target.boundId === element.id;
1569
+ },
1570
+ getPoints(board, line) {
1571
+ let sourcePoint = line.source.boundId
1572
+ ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
1573
+ : line.points[0];
1574
+ let targetPoint = line.target.boundId
1575
+ ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
1576
+ : line.points[line.points.length - 1];
1577
+ const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
1578
+ return [sourcePoint, ...restPoints, targetPoint];
1579
+ }
1580
+ };
1581
+
1582
+ var StrokeStyle;
1583
+ (function (StrokeStyle) {
1584
+ StrokeStyle["solid"] = "solid";
1585
+ StrokeStyle["dashed"] = "dashed";
1586
+ })(StrokeStyle || (StrokeStyle = {}));
1587
+
1588
+ const PlaitDrawElement = {
1589
+ isGeometry: (value) => {
1590
+ return value.type === 'geometry';
1591
+ },
1592
+ isLine: (value) => {
1593
+ return value.type === 'line';
1594
+ },
1595
+ isText: (value) => {
1596
+ return value.type === 'geometry' && value.shape === GeometryShape.text;
1597
+ },
1598
+ isImage: (value) => {
1599
+ return value.type === 'image';
1600
+ },
1601
+ isDrawElement: (value) => {
1602
+ if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value) || PlaitDrawElement.isImage(value)) {
1603
+ return true;
1604
+ }
1605
+ else {
1606
+ return false;
1607
+ }
1608
+ },
1609
+ isShape: (value) => {
1610
+ return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
1611
+ }
1612
+ };
691
1613
 
692
1614
  class GeometryShapeGenerator extends Generator {
693
1615
  canDraw(element, data) {
@@ -703,7 +1625,12 @@ class GeometryShapeGenerator extends Generator {
703
1625
  const strokeColor = getStrokeColorByElement(element);
704
1626
  const fill = getFillByElement(element);
705
1627
  const strokeLineDash = getLineDashByElement(element);
706
- return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, { stroke: strokeColor, strokeWidth, fill, strokeLineDash });
1628
+ return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
1629
+ stroke: strokeColor,
1630
+ strokeWidth,
1631
+ fill,
1632
+ strokeLineDash
1633
+ });
707
1634
  }
708
1635
  }
709
1636
 
@@ -783,6 +1710,28 @@ const setTextSize = (board, element, textWidth, textHeight) => {
783
1710
  }
784
1711
  };
785
1712
 
1713
+ const insertImage = (board, imageItem, startPoint) => {
1714
+ const { width, height, url } = imageItem;
1715
+ const host = BOARD_TO_HOST.get(board);
1716
+ const viewportWidth = PlaitBoard.getComponent(board).nativeElement.clientWidth;
1717
+ const viewportHeight = PlaitBoard.getComponent(board).nativeElement.clientHeight;
1718
+ const point = transformPoint(board, toPoint(viewportWidth / 2, viewportHeight / 2, host));
1719
+ const points = startPoint
1720
+ ? [startPoint, [startPoint[0] + width, startPoint[1] + height]]
1721
+ : [
1722
+ [point[0] - width / 2, point[1] - height / 2],
1723
+ [point[0] + width / 2, point[1] + height / 2]
1724
+ ];
1725
+ const imageElement = {
1726
+ id: idCreator(),
1727
+ type: 'image',
1728
+ points,
1729
+ url
1730
+ };
1731
+ Transforms.insertNode(board, imageElement, [board.children.length]);
1732
+ Transforms.addSelectionWithTemporaryElements(board, [imageElement]);
1733
+ };
1734
+
786
1735
  const resizeLine = (board, options, path) => {
787
1736
  Transforms.setNode(board, options, path);
788
1737
  };
@@ -813,7 +1762,8 @@ const DrawTransforms = {
813
1762
  resizeLine,
814
1763
  setLineTexts,
815
1764
  removeLineText,
816
- setLineMark
1765
+ setLineMark,
1766
+ insertImage
817
1767
  };
818
1768
 
819
1769
  class GeometryComponent extends CommonPluginElement {
@@ -831,10 +1781,10 @@ class GeometryComponent extends CommonPluginElement {
831
1781
  getStrokeWidth: () => {
832
1782
  const selectedElements = getSelectedElements(this.board);
833
1783
  if (selectedElements.length === 1 && !isSelectionMoving(this.board)) {
834
- return DefaultGeometryActiveStyle.strokeWidth;
1784
+ return ACTIVE_STROKE_WIDTH;
835
1785
  }
836
1786
  else {
837
- return DefaultGeometryActiveStyle.selectionStrokeWidth;
1787
+ return ACTIVE_STROKE_WIDTH;
838
1788
  }
839
1789
  },
840
1790
  getStrokeOpacity: () => {
@@ -897,6 +1847,10 @@ class GeometryComponent extends CommonPluginElement {
897
1847
  const plugins = this.board.getPluginOptions(WithTextPluginKey).textPlugins;
898
1848
  const manage = new TextManage(this.board, this.viewContainerRef, {
899
1849
  getRectangle: () => {
1850
+ const getRectangle = getEngine(this.element.shape).getTextRectangle;
1851
+ if (getRectangle) {
1852
+ return getRectangle(this.element);
1853
+ }
900
1854
  return getTextRectangle(this.element);
901
1855
  },
902
1856
  onValueChangeHandle: (textManageRef) => {
@@ -924,14 +1878,15 @@ class GeometryComponent extends CommonPluginElement {
924
1878
  this.destroy$.complete();
925
1879
  }
926
1880
  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 }); }
927
- 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 }); }
1881
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: GeometryComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
928
1882
  }
929
1883
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: GeometryComponent, decorators: [{
930
1884
  type: Component,
931
1885
  args: [{
932
1886
  selector: 'plait-draw-geometry',
933
1887
  template: ``,
934
- changeDetection: ChangeDetectionStrategy.OnPush
1888
+ changeDetection: ChangeDetectionStrategy.OnPush,
1889
+ standalone: true
935
1890
  }]
936
1891
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
937
1892
 
@@ -940,16 +1895,8 @@ class LineShapeGenerator extends Generator {
940
1895
  return true;
941
1896
  }
942
1897
  baseDraw(element, data) {
943
- const shape = element.shape;
944
1898
  let lineG;
945
- switch (shape) {
946
- case LineShape.elbow:
947
- case LineShape.straight:
948
- lineG = drawLine(this.board, element);
949
- break;
950
- default:
951
- break;
952
- }
1899
+ lineG = drawLine(this.board, element);
953
1900
  return lineG;
954
1901
  }
955
1902
  }
@@ -972,22 +1919,25 @@ class LineActiveGenerator extends Generator {
972
1919
  if (this.hasResizeHandle) {
973
1920
  activeG.classList.add('active');
974
1921
  activeG.classList.add('line-handle');
975
- const sourcePoint = getSourcePoint(this.board, element);
976
- const targetPoint = getTargetPoint(this.board, element);
977
- const sourceCircle = drawCircle(PlaitBoard.getRoughSVG(this.board), sourcePoint, RESIZE_HANDLE_DIAMETER, {
978
- stroke: '#999999',
979
- strokeWidth: 1,
980
- fill: '#FFF',
981
- fillStyle: 'solid'
1922
+ const points = PlaitLine.getPoints(this.board, element);
1923
+ points.forEach(point => {
1924
+ const circle = drawCircle(PlaitBoard.getRoughSVG(this.board), point, RESIZE_HANDLE_DIAMETER, {
1925
+ stroke: '#999999',
1926
+ strokeWidth: 1,
1927
+ fill: '#FFF',
1928
+ fillStyle: 'solid'
1929
+ });
1930
+ activeG.appendChild(circle);
982
1931
  });
983
- const targetCircle = drawCircle(PlaitBoard.getRoughSVG(this.board), targetPoint, RESIZE_HANDLE_DIAMETER, {
984
- stroke: '#999999',
985
- strokeWidth: 1,
986
- fill: '#FFF',
987
- fillStyle: 'solid'
1932
+ getMiddlePoints(this.board, element).forEach(point => {
1933
+ const circle = drawCircle(PlaitBoard.getRoughSVG(this.board), point, RESIZE_HANDLE_DIAMETER, {
1934
+ stroke: '#FFFFFF80',
1935
+ strokeWidth: 1,
1936
+ fill: `${PRIMARY_COLOR}80`,
1937
+ fillStyle: 'solid'
1938
+ });
1939
+ activeG.appendChild(circle);
988
1940
  });
989
- activeG.appendChild(targetCircle);
990
- activeG.appendChild(sourceCircle);
991
1941
  }
992
1942
  else {
993
1943
  const points = getLinePoints(this.board, element);
@@ -1001,6 +1951,35 @@ class LineActiveGenerator extends Generator {
1001
1951
  return activeG;
1002
1952
  }
1003
1953
  }
1954
+ function getMiddlePoints(board, element) {
1955
+ const result = [];
1956
+ const shape = element.shape;
1957
+ if (shape === LineShape.straight) {
1958
+ const points = PlaitLine.getPoints(board, element);
1959
+ for (let i = 0; i < points.length - 1; i++) {
1960
+ result.push([(points[i][0] + points[i + 1][0]) / 2, (points[i][1] + points[i + 1][1]) / 2]);
1961
+ }
1962
+ }
1963
+ if (shape === LineShape.curve) {
1964
+ const points = PlaitLine.getPoints(board, element);
1965
+ const pointsOnBezier = getCurvePoints(board, element);
1966
+ if (points.length === 2) {
1967
+ const start = 0;
1968
+ const endIndex = pointsOnBezier.length - 1;
1969
+ const middleIndex = Math.round((start + endIndex) / 2);
1970
+ result.push(pointsOnBezier[middleIndex]);
1971
+ }
1972
+ else {
1973
+ for (let i = 0; i < points.length - 1; i++) {
1974
+ const startIndex = pointsOnBezier.findIndex(point => point[0] === points[i][0] && point[1] === points[i][1]);
1975
+ const endIndex = pointsOnBezier.findIndex(point => point[0] === points[i + 1][0] && point[1] === points[i + 1][1]);
1976
+ const middleIndex = Math.round((startIndex + endIndex) / 2);
1977
+ result.push(pointsOnBezier[middleIndex]);
1978
+ }
1979
+ }
1980
+ }
1981
+ return result;
1982
+ }
1004
1983
 
1005
1984
  class LineComponent extends PlaitPluginElementComponent {
1006
1985
  constructor(viewContainerRef, cdr) {
@@ -1140,14 +2119,15 @@ class LineComponent extends PlaitPluginElementComponent {
1140
2119
  this.destroy$.complete();
1141
2120
  }
1142
2121
  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 }); }
1143
- 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 }); }
2122
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: LineComponent, isStandalone: true, selector: "plait-draw-line", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1144
2123
  }
1145
2124
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: LineComponent, decorators: [{
1146
2125
  type: Component,
1147
2126
  args: [{
1148
2127
  selector: 'plait-draw-line',
1149
2128
  template: ``,
1150
- changeDetection: ChangeDetectionStrategy.OnPush
2129
+ changeDetection: ChangeDetectionStrategy.OnPush,
2130
+ standalone: true
1151
2131
  }]
1152
2132
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
1153
2133
 
@@ -1187,13 +2167,14 @@ const withGeometryCreateByDrag = (board) => {
1187
2167
  geometryShapeG?.remove();
1188
2168
  geometryShapeG = createG();
1189
2169
  const geometryGenerator = new GeometryShapeGenerator(board);
1190
- const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
2170
+ const geometryPointers = getGeometryPointers();
2171
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1191
2172
  const dragMode = isGeometryPointer && isDndMode(board);
1192
2173
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1193
2174
  const pointer = PlaitBoard.getPointer(board);
1194
2175
  if (dragMode) {
1195
2176
  const points = getDefaultGeometryPoints(pointer, movingPoint);
1196
- if (pointer === DrawPointerType.text) {
2177
+ if (pointer === GeometryShape.text) {
1197
2178
  const textG = getTemporaryTextG(movingPoint);
1198
2179
  geometryShapeG.appendChild(textG);
1199
2180
  PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
@@ -1211,12 +2192,13 @@ const withGeometryCreateByDrag = (board) => {
1211
2192
  };
1212
2193
  board.pointerUp = (event) => {
1213
2194
  const pointer = PlaitBoard.getPointer(board);
1214
- const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
2195
+ const geometryPointers = getGeometryPointers();
2196
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1215
2197
  const dragMode = isGeometryPointer && isDndMode(board);
1216
2198
  if (dragMode) {
1217
2199
  const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1218
2200
  const points = getDefaultGeometryPoints(pointer, targetPoint);
1219
- if (pointer === DrawPointerType.text) {
2201
+ if (pointer === GeometryShape.text) {
1220
2202
  DrawTransforms.insertText(board, points);
1221
2203
  }
1222
2204
  else {
@@ -1231,7 +2213,7 @@ const withGeometryCreateByDrag = (board) => {
1231
2213
  };
1232
2214
  return board;
1233
2215
  };
1234
- const withGeometryCreateByDraw = (board) => {
2216
+ const withGeometryCreateByDrawing = (board) => {
1235
2217
  const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
1236
2218
  let start = null;
1237
2219
  let geometryShapeG = null;
@@ -1246,13 +2228,14 @@ const withGeometryCreateByDraw = (board) => {
1246
2228
  keyup(event);
1247
2229
  };
1248
2230
  board.pointerDown = (event) => {
1249
- const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
2231
+ const geometryPointers = getGeometryPointers();
2232
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1250
2233
  if (isGeometryPointer && isDrawingMode(board)) {
1251
2234
  const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1252
2235
  start = point;
1253
2236
  const pointer = PlaitBoard.getPointer(board);
1254
2237
  preventTouchMove(board, event, true);
1255
- if (pointer === DrawPointerType.text) {
2238
+ if (pointer === GeometryShape.text) {
1256
2239
  const points = getDefaultGeometryPoints(pointer, point);
1257
2240
  const textElement = createGeometryElement(GeometryShape.text, points, DefaultTextProperty.text);
1258
2241
  Transforms.insertNode(board, textElement, [board.children.length]);
@@ -1271,7 +2254,7 @@ const withGeometryCreateByDraw = (board) => {
1271
2254
  const drawMode = !!start;
1272
2255
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1273
2256
  const pointer = PlaitBoard.getPointer(board);
1274
- if (drawMode && pointer !== DrawPointerType.text) {
2257
+ if (drawMode && pointer !== GeometryShape.text) {
1275
2258
  const points = normalizeShapePoints([start, movingPoint], isShift);
1276
2259
  temporaryElement = createGeometryElement(pointer, points, '', {
1277
2260
  strokeColor: DefaultGeometryProperty.strokeColor,
@@ -1290,7 +2273,7 @@ const withGeometryCreateByDraw = (board) => {
1290
2273
  if (Math.hypot(width, height) === 0) {
1291
2274
  const pointer = PlaitBoard.getPointer(board);
1292
2275
  const points = getDefaultGeometryPoints(pointer, targetPoint);
1293
- if (pointer !== DrawPointerType.text) {
2276
+ if (pointer !== GeometryShape.text) {
1294
2277
  temporaryElement = createGeometryElement(pointer, points, '', {
1295
2278
  strokeColor: DefaultGeometryProperty.strokeColor,
1296
2279
  strokeWidth: DefaultGeometryProperty.strokeWidth
@@ -1314,7 +2297,7 @@ const withGeometryCreateByDraw = (board) => {
1314
2297
  return board;
1315
2298
  };
1316
2299
  const getDefaultGeometryPoints = (pointer, targetPoint) => {
1317
- return pointer === DrawPointerType.text
2300
+ return pointer === GeometryShape.text
1318
2301
  ? getPointsByCenterPoint(targetPoint, DefaultTextProperty.width, DefaultTextProperty.height)
1319
2302
  : getPointsByCenterPoint(targetPoint, DefaultGeometryProperty.width, DefaultGeometryProperty.height);
1320
2303
  };
@@ -1333,7 +2316,7 @@ const getTemporaryTextG = (movingPoint) => {
1333
2316
 
1334
2317
  const buildClipboardData = (board, elements, startPoint) => {
1335
2318
  return elements.map(element => {
1336
- if (PlaitDrawElement.isGeometry(element)) {
2319
+ if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
1337
2320
  const points = element.points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
1338
2321
  return { ...element, points };
1339
2322
  }
@@ -1356,7 +2339,7 @@ const buildClipboardData = (board, elements, startPoint) => {
1356
2339
  };
1357
2340
  const insertClipboardData = (board, elements, startPoint) => {
1358
2341
  const lines = elements.filter(value => PlaitDrawElement.isLine(value));
1359
- const geometries = elements.filter(value => PlaitDrawElement.isGeometry(value));
2342
+ const geometries = elements.filter(value => PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isImage(value));
1360
2343
  geometries.forEach(element => {
1361
2344
  const sourceLines = [];
1362
2345
  const targetLines = [];
@@ -1391,8 +2374,14 @@ const withDrawFragment = (baseBoard) => {
1391
2374
  if (drawElements.length) {
1392
2375
  const geometryElements = drawElements.filter(value => PlaitDrawElement.isGeometry(value));
1393
2376
  const lineElements = drawElements.filter(value => PlaitDrawElement.isLine(value));
2377
+ const imageElements = drawElements.filter(value => PlaitDrawElement.isImage(value));
1394
2378
  const boundLineElements = getBoundedLineElements(board, geometryElements).filter(line => !lineElements.includes(line));
1395
- data.push(...[...geometryElements, ...lineElements, ...boundLineElements.filter(line => !lineElements.includes(line))]);
2379
+ data.push(...[
2380
+ ...geometryElements,
2381
+ ...lineElements,
2382
+ ...imageElements,
2383
+ ...boundLineElements.filter(line => !lineElements.includes(line))
2384
+ ]);
1396
2385
  }
1397
2386
  return getDeletedFragment(data);
1398
2387
  };
@@ -1428,6 +2417,16 @@ const withDrawFragment = (baseBoard) => {
1428
2417
  return;
1429
2418
  }
1430
2419
  }
2420
+ if (data?.files.length) {
2421
+ const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
2422
+ if (acceptImageArray.includes(data?.files[0].type)) {
2423
+ const imageFile = data.files[0];
2424
+ buildImage(board, imageFile, DEFAULT_IMAGE_WIDTH, imageItem => {
2425
+ DrawTransforms.insertImage(board, imageItem, targetPoint);
2426
+ });
2427
+ return;
2428
+ }
2429
+ }
1431
2430
  insertFragment(data, targetPoint);
1432
2431
  };
1433
2432
  return board;
@@ -1453,10 +2452,10 @@ const getHitGeometryResizeHandleRef = (board, element, point) => {
1453
2452
  const getHitOutlineGeometry = (board, point, offset = 0) => {
1454
2453
  let geometry = null;
1455
2454
  depthFirstRecursion(board, node => {
1456
- if (PlaitDrawElement.isGeometry(node)) {
1457
- const shape = node.shape;
2455
+ if (PlaitDrawElement.isGeometry(node) || PlaitDrawElement.isImage(node)) {
1458
2456
  let client = getRectangleByPoints(node.points);
1459
2457
  client = RectangleClient.getOutlineRectangle(client, offset);
2458
+ const shape = getShape(node);
1460
2459
  const isHit = getEngine(shape).isHit(client, point);
1461
2460
  if (isHit) {
1462
2461
  geometry = node;
@@ -1474,7 +2473,8 @@ const withLineCreateByDraw = (board) => {
1474
2473
  let lineShapeG = null;
1475
2474
  let temporaryElement = null;
1476
2475
  board.pointerDown = (event) => {
1477
- const isLinePointer = PlaitBoard.isPointer(board, DrawPointerType.line);
2476
+ const linePointers = getLinePointers();
2477
+ const isLinePointer = PlaitBoard.isInPointer(board, linePointers);
1478
2478
  if (isLinePointer && isDrawingMode(board)) {
1479
2479
  const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1480
2480
  start = point;
@@ -1496,7 +2496,8 @@ const withLineCreateByDraw = (board) => {
1496
2496
  targetRef.connection = hitElement ? transformPointToConnection(board, movingPoint, hitElement) : undefined;
1497
2497
  targetRef.boundId = hitElement ? hitElement.id : undefined;
1498
2498
  const lineGenerator = new LineShapeGenerator(board);
1499
- temporaryElement = createLineElement(LineShape.elbow, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, {
2499
+ const lineShape = PlaitBoard.getPointer(board);
2500
+ temporaryElement = createLineElement(lineShape, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, {
1500
2501
  strokeColor: DefaultLineStyle.strokeColor,
1501
2502
  strokeWidth: DefaultLineStyle.strokeWidth
1502
2503
  });
@@ -1541,12 +2542,12 @@ const withGeometryResize = (board) => {
1541
2542
  return true;
1542
2543
  },
1543
2544
  detect: (point) => {
1544
- const selectedGeometryElements = getSelectedGeometryElements(board);
1545
- if (selectedGeometryElements.length !== 1 || getSelectedElements(board).length !== 1) {
2545
+ const selectedElements = [...getSelectedGeometryElements(board), ...getSelectedImageElements(board)];
2546
+ if (selectedElements.length !== 1 || getSelectedElements(board).length !== 1) {
1546
2547
  return null;
1547
2548
  }
1548
- const target = selectedGeometryElements[0];
1549
- const targetComponent = PlaitElement.getComponent(selectedGeometryElements[0]);
2549
+ const target = selectedElements[0];
2550
+ const targetComponent = PlaitElement.getComponent(selectedElements[0]);
1550
2551
  if (targetComponent.activeGenerator.hasResizeHandle) {
1551
2552
  const handleRef = getHitGeometryResizeHandleRef(board, target, point);
1552
2553
  if (handleRef) {
@@ -1575,15 +2576,20 @@ const withGeometryResize = (board) => {
1575
2576
  if (resizeRef.handle === ResizeHandle.sw) {
1576
2577
  points = [resizeState.endTransformPoint, [resizeRef.element.points[1][0], resizeRef.element.points[0][1]]];
1577
2578
  }
1578
- if (isShift) {
2579
+ if (isShift || PlaitDrawElement.isImage(resizeRef.element)) {
1579
2580
  const rectangle = getRectangleByPoints(points);
1580
2581
  const factor = points[0][1] > points[1][1] ? 1 : -1;
1581
2582
  const height = rectangle.width * ratio * factor;
1582
2583
  points = [[resizeState.endTransformPoint[0], points[1][1] + height], points[1]];
1583
2584
  }
1584
- points = normalizeShapePoints(points);
1585
- const { height: textHeight } = PlaitGeometry.getTextManage(resizeRef.element).getSize();
1586
- DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
2585
+ if (PlaitDrawElement.isGeometry(resizeRef.element)) {
2586
+ const { height: textHeight } = PlaitGeometry.getTextManage(resizeRef.element).getSize();
2587
+ DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
2588
+ }
2589
+ else {
2590
+ points = normalizeShapePoints(points);
2591
+ Transforms.setNode(board, { points }, resizeRef.path);
2592
+ }
1587
2593
  }
1588
2594
  };
1589
2595
  withResize(board, options);
@@ -1594,34 +2600,44 @@ var LineResizeHandle;
1594
2600
  (function (LineResizeHandle) {
1595
2601
  LineResizeHandle["source"] = "source";
1596
2602
  LineResizeHandle["target"] = "target";
2603
+ LineResizeHandle["addHandle"] = "addHandle";
1597
2604
  })(LineResizeHandle || (LineResizeHandle = {}));
1598
2605
  const getHitLineResizeHandleRef = (board, element, point) => {
1599
- const sourcePoint = getSourcePoint(board, element);
1600
- const targetPoint = getTargetPoint(board, element);
1601
- const sourceRectangle = {
1602
- x: sourcePoint[0] - RESIZE_HANDLE_DIAMETER / 2,
1603
- y: sourcePoint[1] - RESIZE_HANDLE_DIAMETER / 2,
1604
- width: RESIZE_HANDLE_DIAMETER,
1605
- height: RESIZE_HANDLE_DIAMETER
1606
- };
1607
- const targetRectangle = {
1608
- x: targetPoint[0] - RESIZE_HANDLE_DIAMETER / 2,
1609
- y: targetPoint[1] - RESIZE_HANDLE_DIAMETER / 2,
1610
- width: RESIZE_HANDLE_DIAMETER,
1611
- height: RESIZE_HANDLE_DIAMETER
1612
- };
1613
- const isHitSourceRectangle = RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), sourceRectangle);
1614
- const isHitTargetRectangle = RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), targetRectangle);
1615
- if (isHitSourceRectangle) {
1616
- return { rectangle: sourceRectangle, handle: LineResizeHandle.source };
2606
+ const points = PlaitLine.getPoints(board, element);
2607
+ const index = getHitPointIndex(points, point);
2608
+ if (index !== -1) {
2609
+ if (index === 0) {
2610
+ return { handle: LineResizeHandle.source, index };
2611
+ }
2612
+ if (index === points.length - 1) {
2613
+ return { handle: LineResizeHandle.target, index };
2614
+ }
2615
+ return { index };
1617
2616
  }
1618
- if (isHitTargetRectangle) {
1619
- return { rectangle: targetRectangle, handle: LineResizeHandle.target };
2617
+ const middlePoints = getMiddlePoints(board, element);
2618
+ const middleIndex = getHitPointIndex(middlePoints, point);
2619
+ if (middleIndex !== -1) {
2620
+ return { handle: LineResizeHandle.addHandle, index: middleIndex };
1620
2621
  }
1621
2622
  return undefined;
1622
2623
  };
2624
+ function getHitPointIndex(points, movingPoint) {
2625
+ const rectangles = points.map(point => {
2626
+ return {
2627
+ x: point[0] - RESIZE_HANDLE_DIAMETER / 2,
2628
+ y: point[1] - RESIZE_HANDLE_DIAMETER / 2,
2629
+ width: RESIZE_HANDLE_DIAMETER,
2630
+ height: RESIZE_HANDLE_DIAMETER
2631
+ };
2632
+ });
2633
+ const rectangle = rectangles.find(rectangle => {
2634
+ return RectangleClient.isHit(RectangleClient.toRectangleClient([movingPoint, movingPoint]), rectangle);
2635
+ });
2636
+ return rectangle ? rectangles.indexOf(rectangle) : -1;
2637
+ }
1623
2638
 
1624
2639
  const withLineResize = (board) => {
2640
+ let pointIndex = 0;
1625
2641
  const options = {
1626
2642
  key: 'draw-line',
1627
2643
  canResize: () => {
@@ -1638,6 +2654,7 @@ const withLineResize = (board) => {
1638
2654
  element: value,
1639
2655
  handle: handleRef.handle
1640
2656
  };
2657
+ pointIndex = handleRef.index;
1641
2658
  }
1642
2659
  });
1643
2660
  return result;
@@ -1649,17 +2666,23 @@ const withLineResize = (board) => {
1649
2666
  let source = { ...resizeRef.element.source };
1650
2667
  let target = { ...resizeRef.element.target };
1651
2668
  if (resizeRef.handle === LineResizeHandle.source) {
1652
- points[0] = resizeState.endTransformPoint;
2669
+ points[pointIndex] = resizeState.endTransformPoint;
1653
2670
  const hitElement = getHitOutlineGeometry(board, resizeState.endTransformPoint, -4);
1654
2671
  source.connection = hitElement ? transformPointToConnection(board, resizeState.endTransformPoint, hitElement) : undefined;
1655
2672
  source.boundId = hitElement ? hitElement.id : undefined;
1656
2673
  }
1657
- if (resizeRef.handle === LineResizeHandle.target) {
1658
- points[1] = resizeState.endTransformPoint;
2674
+ else if (resizeRef.handle === LineResizeHandle.target) {
2675
+ points[pointIndex] = resizeState.endTransformPoint;
1659
2676
  const hitElement = getHitOutlineGeometry(board, resizeState.endTransformPoint, -4);
1660
2677
  target.connection = hitElement ? transformPointToConnection(board, resizeState.endTransformPoint, hitElement) : undefined;
1661
2678
  target.boundId = hitElement ? hitElement.id : undefined;
1662
2679
  }
2680
+ else if (resizeRef.handle === LineResizeHandle.addHandle) {
2681
+ points.splice(pointIndex + 1, 0, resizeState.endTransformPoint);
2682
+ }
2683
+ else {
2684
+ points[pointIndex] = resizeState.endTransformPoint;
2685
+ }
1663
2686
  DrawTransforms.resizeLine(board, { points, source, target }, resizeRef.path);
1664
2687
  }
1665
2688
  };
@@ -1672,9 +2695,14 @@ const withLineBoundReaction = (board) => {
1672
2695
  let boundShapeG = null;
1673
2696
  board.pointerMove = (event) => {
1674
2697
  boundShapeG?.remove();
1675
- const isLinePointer = PlaitBoard.isPointer(board, DrawPointerType.line);
2698
+ const linePointers = Object.keys(LineShape);
2699
+ const isLinePointer = PlaitBoard.isInPointer(board, linePointers);
1676
2700
  const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1677
- const isLineResizing = isResizingByCondition(board, element => PlaitDrawElement.isLine(element));
2701
+ const isLineResizing = isResizingByCondition(board, resizeRef => {
2702
+ const { element, handle } = resizeRef;
2703
+ const isSourceOrTarget = handle === LineResizeHandle.target || handle === LineResizeHandle.source;
2704
+ return PlaitDrawElement.isLine(element) && isSourceOrTarget;
2705
+ });
1678
2706
  if (isLinePointer || isLineResizing) {
1679
2707
  const hitElement = getHitOutlineGeometry(board, movingPoint, -4);
1680
2708
  if (hitElement) {
@@ -1752,8 +2780,74 @@ function editHandle(board, element, manageIndex, isFirstEdit = false) {
1752
2780
  });
1753
2781
  }
1754
2782
 
2783
+ class ImageComponent extends CommonPluginElement {
2784
+ get activeGenerator() {
2785
+ return this.imageGenerator.componentRef.instance.activeGenerator;
2786
+ }
2787
+ constructor(viewContainerRef, cdr) {
2788
+ super(cdr);
2789
+ this.viewContainerRef = viewContainerRef;
2790
+ this.cdr = cdr;
2791
+ this.destroy$ = new Subject();
2792
+ }
2793
+ initializeGenerator() {
2794
+ this.imageGenerator = new ImageGenerator(this.board, {
2795
+ getRectangle: (element) => {
2796
+ return {
2797
+ x: element.points[0][0],
2798
+ y: element.points[0][1],
2799
+ width: element.points[1][0] - element.points[0][0],
2800
+ height: element.points[1][1] - element.points[0][1]
2801
+ };
2802
+ },
2803
+ getImageItem: element => {
2804
+ return {
2805
+ url: element.url,
2806
+ width: element.points[1][0] - element.points[0][0],
2807
+ height: element.points[1][1] - element.points[0][1]
2808
+ };
2809
+ }
2810
+ });
2811
+ }
2812
+ ngOnInit() {
2813
+ super.ngOnInit();
2814
+ this.initializeGenerator();
2815
+ this.imageGenerator.draw(this.element, this.g, this.viewContainerRef);
2816
+ }
2817
+ onContextChanged(value, previous) {
2818
+ if (value.element !== previous.element) {
2819
+ this.imageGenerator.updateImage(this.g, previous.element, value.element);
2820
+ this.imageGenerator.componentRef.instance.isFocus = this.selected;
2821
+ }
2822
+ else {
2823
+ const hasSameSelected = value.selected === previous.selected;
2824
+ const hasSameHandleState = this.activeGenerator.options.hasResizeHandle() === this.activeGenerator.hasResizeHandle;
2825
+ if (!hasSameSelected || !hasSameHandleState) {
2826
+ this.imageGenerator.componentRef.instance.isFocus = this.selected;
2827
+ }
2828
+ }
2829
+ }
2830
+ ngOnDestroy() {
2831
+ super.ngOnDestroy();
2832
+ this.destroy$.next();
2833
+ this.destroy$.complete();
2834
+ this.imageGenerator.destroy();
2835
+ }
2836
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2837
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: ImageComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2838
+ }
2839
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: ImageComponent, decorators: [{
2840
+ type: Component,
2841
+ args: [{
2842
+ selector: 'plait-draw-geometry',
2843
+ template: ``,
2844
+ changeDetection: ChangeDetectionStrategy.OnPush,
2845
+ standalone: true
2846
+ }]
2847
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
2848
+
1755
2849
  const withDraw = (board) => {
1756
- const { drawElement, getRectangle, isHitSelection, isMovable, dblclick } = board;
2850
+ const { drawElement, getRectangle, isHitSelection, isMovable, isAlign } = board;
1757
2851
  board.drawElement = (context) => {
1758
2852
  if (PlaitDrawElement.isGeometry(context.element)) {
1759
2853
  return GeometryComponent;
@@ -1761,6 +2855,9 @@ const withDraw = (board) => {
1761
2855
  else if (PlaitDrawElement.isLine(context.element)) {
1762
2856
  return LineComponent;
1763
2857
  }
2858
+ else if (PlaitDrawElement.isImage(context.element)) {
2859
+ return ImageComponent;
2860
+ }
1764
2861
  return drawElement(context);
1765
2862
  };
1766
2863
  board.getRectangle = (element) => {
@@ -1771,6 +2868,9 @@ const withDraw = (board) => {
1771
2868
  const points = getLinePoints(board, element);
1772
2869
  return getRectangleByPoints(points);
1773
2870
  }
2871
+ if (PlaitDrawElement.isImage(element)) {
2872
+ return getRectangleByPoints(element.points);
2873
+ }
1774
2874
  return getRectangle(element);
1775
2875
  };
1776
2876
  board.isHitSelection = (element, range) => {
@@ -1783,6 +2883,11 @@ const withDraw = (board) => {
1783
2883
  }
1784
2884
  return RectangleClient.isHit(rangeRectangle, client);
1785
2885
  }
2886
+ if (PlaitDrawElement.isImage(element)) {
2887
+ const client = getRectangleByPoints(element.points);
2888
+ const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
2889
+ return RectangleClient.isHit(rangeRectangle, client);
2890
+ }
1786
2891
  if (PlaitDrawElement.isLine(element)) {
1787
2892
  const points = getLinePoints(board, element);
1788
2893
  const strokeWidth = getStrokeWidthByElement(element);
@@ -1801,17 +2906,26 @@ const withDraw = (board) => {
1801
2906
  if (PlaitDrawElement.isGeometry(element)) {
1802
2907
  return true;
1803
2908
  }
2909
+ if (PlaitDrawElement.isImage(element)) {
2910
+ return true;
2911
+ }
1804
2912
  if (PlaitDrawElement.isLine(element)) {
1805
2913
  return !element.source.boundId && !element.target.boundId;
1806
2914
  }
1807
2915
  return isMovable(element);
1808
2916
  };
1809
- return withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withGeometryCreateByDrag(withGeometryCreateByDraw(withDrawFragment(withDrawHotkey(board)))))))));
2917
+ board.isAlign = (element) => {
2918
+ if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
2919
+ return true;
2920
+ }
2921
+ return isAlign(element);
2922
+ };
2923
+ return withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withGeometryCreateByDrag(withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))))))));
1810
2924
  };
1811
2925
 
1812
2926
  /**
1813
2927
  * Generated bundle index. Do not edit.
1814
2928
  */
1815
2929
 
1816
- 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 };
2930
+ export { DEFAULT_IMAGE_WIDTH, DefaultGeometryActiveStyle, DefaultGeometryProperty, DefaultGeometryStyle, DefaultTextProperty, DrawTransforms, GeometryComponent, GeometryShape, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getEdgeOnPolygonByPoint, getElbowPoints, getExtendPoint, getFillByElement, 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 };
1817
2931
  //# sourceMappingURL=plait-draw.mjs.map