@plait/draw 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/constants/geometry.d.ts +71 -1
  2. package/constants/pointer.d.ts +4 -2
  3. package/engines/{comment.d.ts → basic-shapes/comment.d.ts} +1 -1
  4. package/engines/{cross.d.ts → basic-shapes/cross.d.ts} +2 -2
  5. package/engines/{diamond.d.ts → basic-shapes/diamond.d.ts} +1 -1
  6. package/engines/basic-shapes/ellipse.d.ts +13 -0
  7. package/engines/{hexagon.d.ts → basic-shapes/hexagon.d.ts} +2 -2
  8. package/engines/{left-arrow.d.ts → basic-shapes/left-arrow.d.ts} +2 -2
  9. package/engines/{octagon.d.ts → basic-shapes/octagon.d.ts} +2 -2
  10. package/engines/basic-shapes/parallelogram.d.ts +4 -0
  11. package/engines/{pentagon-arrow.d.ts → basic-shapes/pentagon-arrow.d.ts} +2 -2
  12. package/engines/{pentagon.d.ts → basic-shapes/pentagon.d.ts} +2 -2
  13. package/engines/basic-shapes/polygon.d.ts +8 -0
  14. package/engines/{process-arrow.d.ts → basic-shapes/process-arrow.d.ts} +2 -2
  15. package/engines/{rectangle.d.ts → basic-shapes/rectangle.d.ts} +1 -1
  16. package/engines/{right-arrow.d.ts → basic-shapes/right-arrow.d.ts} +2 -2
  17. package/engines/{round-comment.d.ts → basic-shapes/round-comment.d.ts} +1 -1
  18. package/engines/{round-rectangle.d.ts → basic-shapes/round-rectangle.d.ts} +1 -1
  19. package/engines/{star.d.ts → basic-shapes/star.d.ts} +2 -2
  20. package/engines/{trapezoid.d.ts → basic-shapes/trapezoid.d.ts} +2 -2
  21. package/engines/{triangle.d.ts → basic-shapes/triangle.d.ts} +2 -2
  22. package/engines/{two-way-arrow.d.ts → basic-shapes/two-way-arrow.d.ts} +2 -2
  23. package/engines/flowchart/delay.d.ts +2 -0
  24. package/engines/flowchart/manual-input.d.ts +4 -0
  25. package/engines/flowchart/manual-loop.d.ts +4 -0
  26. package/engines/flowchart/merge.d.ts +4 -0
  27. package/engines/flowchart/preparation.d.ts +4 -0
  28. package/engines/flowchart/stored-data.d.ts +2 -0
  29. package/engines/flowchart/terminal.d.ts +5 -0
  30. package/engines/index.d.ts +3 -3
  31. package/esm2022/constants/geometry.mjs +40 -2
  32. package/esm2022/constants/line.mjs +1 -1
  33. package/esm2022/constants/pointer.mjs +9 -3
  34. package/esm2022/engines/basic-shapes/comment.mjs +57 -0
  35. package/esm2022/engines/basic-shapes/cross.mjs +33 -0
  36. package/esm2022/engines/basic-shapes/diamond.mjs +16 -0
  37. package/esm2022/engines/basic-shapes/ellipse.mjs +100 -0
  38. package/esm2022/engines/basic-shapes/hexagon.mjs +27 -0
  39. package/esm2022/engines/basic-shapes/left-arrow.mjs +30 -0
  40. package/esm2022/engines/basic-shapes/octagon.mjs +29 -0
  41. package/esm2022/engines/basic-shapes/parallelogram.mjs +25 -0
  42. package/esm2022/engines/basic-shapes/pentagon-arrow.mjs +24 -0
  43. package/esm2022/engines/basic-shapes/pentagon.mjs +30 -0
  44. package/esm2022/engines/basic-shapes/polygon.mjs +40 -0
  45. package/esm2022/engines/basic-shapes/process-arrow.mjs +26 -0
  46. package/esm2022/engines/basic-shapes/rectangle.mjs +26 -0
  47. package/esm2022/engines/basic-shapes/right-arrow.mjs +28 -0
  48. package/esm2022/engines/basic-shapes/round-comment.mjs +81 -0
  49. package/esm2022/engines/basic-shapes/round-rectangle.mjs +59 -0
  50. package/esm2022/engines/basic-shapes/star.mjs +39 -0
  51. package/esm2022/engines/basic-shapes/trapezoid.mjs +25 -0
  52. package/esm2022/engines/basic-shapes/triangle.mjs +33 -0
  53. package/esm2022/engines/basic-shapes/two-way-arrow.mjs +25 -0
  54. package/esm2022/engines/flowchart/delay.mjs +45 -0
  55. package/esm2022/engines/flowchart/manual-input.mjs +32 -0
  56. package/esm2022/engines/flowchart/manual-loop.mjs +25 -0
  57. package/esm2022/engines/flowchart/merge.mjs +34 -0
  58. package/esm2022/engines/flowchart/preparation.mjs +27 -0
  59. package/esm2022/engines/flowchart/stored-data.mjs +74 -0
  60. package/esm2022/engines/flowchart/terminal.mjs +59 -0
  61. package/esm2022/engines/index.mjs +59 -41
  62. package/esm2022/generators/geometry-shape.generator.mjs +3 -3
  63. package/esm2022/generators/line-active.generator.mjs +1 -1
  64. package/esm2022/generators/line.generator.mjs +1 -1
  65. package/esm2022/geometry.component.mjs +9 -5
  66. package/esm2022/image.component.mjs +4 -4
  67. package/esm2022/interfaces/geometry.mjs +38 -24
  68. package/esm2022/interfaces/index.mjs +9 -3
  69. package/esm2022/interfaces/text.mjs +1 -1
  70. package/esm2022/line.component.mjs +4 -4
  71. package/esm2022/plugins/with-draw-fragment.mjs +5 -4
  72. package/esm2022/plugins/with-draw.mjs +15 -31
  73. package/esm2022/plugins/with-geometry-create.mjs +32 -20
  74. package/esm2022/plugins/with-line-create.mjs +2 -2
  75. package/esm2022/plugins/with-line-text.mjs +4 -4
  76. package/esm2022/transforms/geometry.mjs +6 -6
  77. package/esm2022/utils/geometry.mjs +74 -5
  78. package/esm2022/utils/hit.mjs +58 -0
  79. package/esm2022/utils/index.mjs +2 -1
  80. package/esm2022/utils/line-arrow.mjs +3 -3
  81. package/esm2022/utils/line.mjs +39 -17
  82. package/esm2022/utils/shape.mjs +3 -3
  83. package/fesm2022/plait-draw.mjs +1200 -872
  84. package/fesm2022/plait-draw.mjs.map +1 -1
  85. package/interfaces/geometry.d.ts +19 -5
  86. package/interfaces/index.d.ts +2 -0
  87. package/interfaces/text.d.ts +2 -2
  88. package/package.json +1 -1
  89. package/plugins/with-geometry-create.d.ts +7 -1
  90. package/transforms/geometry.d.ts +2 -2
  91. package/transforms/index.d.ts +1 -1
  92. package/utils/geometry.d.ts +23 -3
  93. package/utils/hit.d.ts +3 -0
  94. package/utils/index.d.ts +1 -0
  95. package/utils/line.d.ts +2 -3
  96. package/utils/shape.d.ts +2 -2
  97. package/engines/ellipse.d.ts +0 -4
  98. package/engines/parallelogram.d.ts +0 -4
  99. package/esm2022/engines/comment.mjs +0 -57
  100. package/esm2022/engines/cross.mjs +0 -46
  101. package/esm2022/engines/diamond.mjs +0 -30
  102. package/esm2022/engines/ellipse.mjs +0 -92
  103. package/esm2022/engines/hexagon.mjs +0 -40
  104. package/esm2022/engines/left-arrow.mjs +0 -45
  105. package/esm2022/engines/octagon.mjs +0 -42
  106. package/esm2022/engines/parallelogram.mjs +0 -39
  107. package/esm2022/engines/pentagon-arrow.mjs +0 -39
  108. package/esm2022/engines/pentagon.mjs +0 -39
  109. package/esm2022/engines/process-arrow.mjs +0 -41
  110. package/esm2022/engines/rectangle.mjs +0 -26
  111. package/esm2022/engines/right-arrow.mjs +0 -45
  112. package/esm2022/engines/round-comment.mjs +0 -81
  113. package/esm2022/engines/round-rectangle.mjs +0 -59
  114. package/esm2022/engines/star.mjs +0 -45
  115. package/esm2022/engines/trapezoid.mjs +0 -40
  116. package/esm2022/engines/triangle.mjs +0 -40
  117. package/esm2022/engines/two-way-arrow.mjs +0 -48
@@ -1,36 +1,50 @@
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';
1
+ import { PlaitElement, ACTIVE_STROKE_WIDTH, PlaitBoard, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, RectangleClient, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, BOARD_TO_HOST, transformPoint, toPoint, idCreator, createG, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegment, arrowPoints, createPath, drawLinearPath, rotate, getElementById, distanceBetweenPointAndPoint, distanceBetweenPointAndSegments, createMask, createRect, findElements, getSelectedElements, isPolylineHitRectangle, isSelectionMoving, PlaitPluginElementComponent, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElementByPoint } from '@plait/core';
2
+ import { getRectangleByPoints, Generator, normalizeShapePoints, isDndMode, isDrawingMode, getFactorByPoints, getDirectionByVector, getOppositeDirection, getDirectionFactor, DEFAULT_ROUTE_MARGIN, reduceRouteMargin, getNextPoint, generateElbowLineRoute, getPoints, removeDuplicatePoints, getPointByVector, getPointOnPolyline, getDirectionByPointOfRectangle, rotateVectorAnti90, CommonPluginElement, ActiveGenerator, WithTextPluginKey, RESIZE_HANDLE_DIAMETER, PRIMARY_COLOR, isVirtualKey, isDelete, isSpaceHotkey, acceptImageTypes, getElementOfFocusedImage, buildImage, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint, ImageGenerator } from '@plait/common';
3
+ import { AlignEditor, Alignment, DEFAULT_FONT_SIZE, buildText, TextManage, getTextFromClipboard, getTextSize } from '@plait/text';
4
+ import { isKeyHotkey } from 'is-hotkey';
4
5
  import { pointsOnBezierCurves } from 'points-on-curve';
5
6
  import * as i0 from '@angular/core';
6
7
  import { Component, ChangeDetectionStrategy } from '@angular/core';
7
8
  import { Subject } from 'rxjs';
8
- import { isKeyHotkey } from 'is-hotkey';
9
9
  import { Node } from 'slate';
10
10
 
11
- var GeometryShape;
12
- (function (GeometryShape) {
13
- GeometryShape["rectangle"] = "rectangle";
14
- GeometryShape["ellipse"] = "ellipse";
15
- GeometryShape["diamond"] = "diamond";
16
- GeometryShape["roundRectangle"] = "roundRectangle";
17
- GeometryShape["parallelogram"] = "parallelogram";
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";
33
- })(GeometryShape || (GeometryShape = {}));
11
+ var BasicShapes;
12
+ (function (BasicShapes) {
13
+ BasicShapes["rectangle"] = "rectangle";
14
+ BasicShapes["ellipse"] = "ellipse";
15
+ BasicShapes["diamond"] = "diamond";
16
+ BasicShapes["roundRectangle"] = "roundRectangle";
17
+ BasicShapes["parallelogram"] = "parallelogram";
18
+ BasicShapes["text"] = "text";
19
+ BasicShapes["triangle"] = "triangle";
20
+ BasicShapes["leftArrow"] = "leftArrow";
21
+ BasicShapes["trapezoid"] = "trapezoid";
22
+ BasicShapes["rightArrow"] = "rightArrow";
23
+ BasicShapes["cross"] = "cross";
24
+ BasicShapes["star"] = "star";
25
+ BasicShapes["pentagon"] = "pentagon";
26
+ BasicShapes["hexagon"] = "hexagon";
27
+ BasicShapes["octagon"] = "octagon";
28
+ BasicShapes["pentagonArrow"] = "pentagonArrow";
29
+ BasicShapes["processArrow"] = "processArrow";
30
+ BasicShapes["twoWayArrow"] = "twoWayArrow";
31
+ BasicShapes["comment"] = "comment";
32
+ BasicShapes["roundComment"] = "roundComment";
33
+ })(BasicShapes || (BasicShapes = {}));
34
+ var FlowchartSymbols;
35
+ (function (FlowchartSymbols) {
36
+ FlowchartSymbols["process"] = "process";
37
+ FlowchartSymbols["decision"] = "decision";
38
+ FlowchartSymbols["data"] = "data";
39
+ FlowchartSymbols["connector"] = "connector";
40
+ FlowchartSymbols["terminal"] = "terminal";
41
+ FlowchartSymbols["manualInput"] = "manualInput";
42
+ FlowchartSymbols["preparation"] = "preparation";
43
+ FlowchartSymbols["manualLoop"] = "manualLoop";
44
+ FlowchartSymbols["merge"] = "merge";
45
+ FlowchartSymbols["delay"] = "delay";
46
+ FlowchartSymbols["storedData"] = "storedData";
47
+ })(FlowchartSymbols || (FlowchartSymbols = {}));
34
48
  const PlaitGeometry = {
35
49
  getTextEditor(element) {
36
50
  return PlaitGeometry.getTextManage(element).componentRef.instance.editor;
@@ -57,7 +71,7 @@ const DefaultGeometryActiveStyle = {
57
71
  strokeWidth: ACTIVE_STROKE_WIDTH,
58
72
  selectionStrokeWidth: ACTIVE_STROKE_WIDTH
59
73
  };
60
- const DefaultGeometryProperty = {
74
+ const DefaultBasicShapeProperty = {
61
75
  width: 100,
62
76
  height: 100,
63
77
  strokeColor: '#333',
@@ -71,9 +85,52 @@ const DefaultTextProperty = {
71
85
  const GeometryThreshold = {
72
86
  defaultTextMaxWidth: 34 * 14
73
87
  };
88
+ const DefaultConnectorProperty = {
89
+ width: 44,
90
+ height: 44
91
+ };
92
+ const DefaultFlowchartProperty = {
93
+ width: 120,
94
+ height: 60
95
+ };
96
+ const DefaultDecisionProperty = {
97
+ width: 140,
98
+ height: 70
99
+ };
100
+ const DefaultDataProperty = {
101
+ width: 124,
102
+ height: 60
103
+ };
104
+ const DefaultManualInputProperty = {
105
+ width: 117,
106
+ height: 59
107
+ };
108
+ const DefaultMergeProperty = {
109
+ width: 47,
110
+ height: 33
111
+ };
112
+ const DefaultFlowchartPropertyMap = {
113
+ [FlowchartSymbols.connector]: DefaultConnectorProperty,
114
+ [FlowchartSymbols.process]: DefaultFlowchartProperty,
115
+ [FlowchartSymbols.decision]: DefaultDecisionProperty,
116
+ [FlowchartSymbols.data]: DefaultDataProperty,
117
+ [FlowchartSymbols.terminal]: DefaultFlowchartProperty,
118
+ [FlowchartSymbols.manualInput]: DefaultManualInputProperty,
119
+ [FlowchartSymbols.preparation]: DefaultFlowchartProperty,
120
+ [FlowchartSymbols.manualLoop]: DefaultFlowchartProperty,
121
+ [FlowchartSymbols.merge]: DefaultMergeProperty,
122
+ [FlowchartSymbols.delay]: DefaultFlowchartProperty,
123
+ [FlowchartSymbols.storedData]: DefaultFlowchartProperty
124
+ };
74
125
 
75
126
  const getGeometryPointers = () => {
76
- return Object.keys(GeometryShape);
127
+ return [...Object.keys(BasicShapes), ...Object.keys(FlowchartSymbols)];
128
+ };
129
+ const getBasicPointers = () => {
130
+ return Object.keys(BasicShapes);
131
+ };
132
+ const getFlowchartPointers = () => {
133
+ return Object.keys(FlowchartSymbols);
77
134
  };
78
135
  const getLinePointers = () => {
79
136
  return Object.keys(LineShape);
@@ -155,33 +212,44 @@ const getCommentPoints = (rectangle) => {
155
212
  ];
156
213
  };
157
214
 
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);
215
+ function createPolygonEngine(options) {
216
+ const getPoints = options.getPolygonPoints;
217
+ const engine = {
218
+ draw(board, rectangle, options) {
219
+ const points = getPoints(rectangle);
220
+ const rs = PlaitBoard.getRoughSVG(board);
221
+ const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
222
+ setStrokeLinecap(polygon, 'round');
223
+ return polygon;
224
+ },
225
+ isHit(rectangle, point) {
226
+ const points = getPoints(rectangle);
227
+ return isPointInPolygon(point, points);
228
+ },
229
+ getCornerPoints(rectangle) {
230
+ return getPoints(rectangle);
231
+ },
232
+ getNearestPoint(rectangle, point) {
233
+ return getNearestPointBetweenPointAndSegments(point, getPoints(rectangle));
234
+ },
235
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
236
+ const corners = getPoints(rectangle);
237
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
238
+ return getEdgeOnPolygonByPoint(corners, point);
239
+ },
240
+ getConnectorPoints(rectangle) {
241
+ if (options.getConnectorPoints) {
242
+ return options.getConnectorPoints(rectangle);
243
+ }
244
+ return getPoints(rectangle);
245
+ }
246
+ };
247
+ if (options.getTextRectangle) {
248
+ engine.getTextRectangle = options.getTextRectangle;
183
249
  }
184
- };
250
+ return engine;
251
+ }
252
+
185
253
  const getCrossPoints = (rectangle) => {
186
254
  return [
187
255
  [rectangle.x + rectangle.width / 4, rectangle.y],
@@ -198,34 +266,32 @@ const getCrossPoints = (rectangle) => {
198
266
  [rectangle.x + rectangle.width / 4, rectangle.y + rectangle.height / 4]
199
267
  ];
200
268
  };
201
-
202
- const DiamondEngine = {
203
- draw(board, rectangle, options) {
204
- const points = RectangleClient.getEdgeCenterPoints(rectangle);
205
- const rs = PlaitBoard.getRoughSVG(board);
206
- const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
207
- setStrokeLinecap(polygon, 'round');
208
- return polygon;
209
- },
210
- isHit(rectangle, point) {
211
- const controlPoints = RectangleClient.getEdgeCenterPoints(rectangle);
212
- return isPointInPolygon(point, controlPoints);
213
- },
214
- getCornerPoints(rectangle) {
269
+ const CrossEngine = createPolygonEngine({
270
+ getPolygonPoints: getCrossPoints,
271
+ getConnectorPoints(rectangle) {
215
272
  return RectangleClient.getEdgeCenterPoints(rectangle);
216
273
  },
217
- getNearestPoint(rectangle, point) {
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);
224
- },
274
+ getTextRectangle(element) {
275
+ const rectangle = getTextRectangle(element);
276
+ const width = rectangle.width;
277
+ rectangle.width = rectangle.width / 2;
278
+ rectangle.x += width / 4;
279
+ return rectangle;
280
+ }
281
+ });
282
+
283
+ const DiamondEngine = createPolygonEngine({
284
+ getPolygonPoints: RectangleClient.getEdgeCenterPoints,
225
285
  getConnectorPoints(rectangle) {
226
286
  return RectangleClient.getEdgeCenterPoints(rectangle);
287
+ },
288
+ getTextRectangle(element) {
289
+ const rectangle = getTextRectangle(element);
290
+ rectangle.width = rectangle.width / 2;
291
+ rectangle.x += rectangle.width / 2;
292
+ return rectangle;
227
293
  }
228
- };
294
+ });
229
295
 
230
296
  const EllipseEngine = {
231
297
  draw(board, rectangle, options) {
@@ -255,6 +321,13 @@ const EllipseEngine = {
255
321
  },
256
322
  getConnectorPoints(rectangle) {
257
323
  return RectangleClient.getEdgeCenterPoints(rectangle);
324
+ },
325
+ getTextRectangle(element) {
326
+ const rectangle = getTextRectangle(element);
327
+ const width = rectangle.width;
328
+ rectangle.width = (rectangle.width * 3) / 4;
329
+ rectangle.x += width / 8;
330
+ return rectangle;
258
331
  }
259
332
  };
260
333
  function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation = 0) {
@@ -318,33 +391,6 @@ function getVectorBySlope(x, y, slope) {
318
391
  return vector;
319
392
  }
320
393
 
321
- const HexagonEngine = {
322
- draw(board, rectangle, options) {
323
- const points = getHexagonPoints(rectangle);
324
- const rs = PlaitBoard.getRoughSVG(board);
325
- const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
326
- setStrokeLinecap(polygon, 'round');
327
- return polygon;
328
- },
329
- isHit(rectangle, point) {
330
- const parallelogramPoints = getHexagonPoints(rectangle);
331
- return isPointInPolygon(point, parallelogramPoints);
332
- },
333
- getCornerPoints(rectangle) {
334
- return getHexagonPoints(rectangle);
335
- },
336
- getNearestPoint(rectangle, point) {
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
394
  const getHexagonPoints = (rectangle) => {
349
395
  return [
350
396
  [rectangle.x + rectangle.width / 4, rectangle.y],
@@ -355,38 +401,20 @@ const getHexagonPoints = (rectangle) => {
355
401
  [rectangle.x, rectangle.y + rectangle.height / 2]
356
402
  ];
357
403
  };
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);
376
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
377
- },
378
- getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
379
- const corners = getLeftArrowPoints(rectangle);
380
- const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
381
- return getEdgeOnPolygonByPoint(corners, point);
382
- },
404
+ const HexagonEngine = createPolygonEngine({
405
+ getPolygonPoints: getHexagonPoints,
383
406
  getConnectorPoints(rectangle) {
384
- return [
385
- [rectangle.x, rectangle.y + rectangle.height / 2],
386
- [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
387
- ];
407
+ return RectangleClient.getEdgeCenterPoints(rectangle);
408
+ },
409
+ getTextRectangle(element) {
410
+ const rectangle = getTextRectangle(element);
411
+ const width = rectangle.width;
412
+ rectangle.width = (rectangle.width * 3) / 4;
413
+ rectangle.x += width / 8;
414
+ return rectangle;
388
415
  }
389
- };
416
+ });
417
+
390
418
  const getLeftArrowPoints = (rectangle) => {
391
419
  return [
392
420
  [rectangle.x, rectangle.y + rectangle.height / 2],
@@ -398,34 +426,23 @@ const getLeftArrowPoints = (rectangle) => {
398
426
  [rectangle.x + rectangle.width * 0.32, rectangle.y + rectangle.height]
399
427
  ];
400
428
  };
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);
429
+ const LeftArrowEngine = createPolygonEngine({
430
+ getPolygonPoints: getLeftArrowPoints,
431
+ getConnectorPoints: (rectangle) => {
432
+ return [
433
+ [rectangle.x, rectangle.y + rectangle.height / 2],
434
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
435
+ ];
424
436
  },
425
- getConnectorPoints(rectangle) {
426
- return RectangleClient.getEdgeCenterPoints(rectangle);
437
+ getTextRectangle(element) {
438
+ const rectangle = getTextRectangle(element);
439
+ const width = rectangle.width;
440
+ rectangle.width = rectangle.width * (1 - 0.32);
441
+ rectangle.x += width * 0.32;
442
+ return rectangle;
427
443
  }
428
- };
444
+ });
445
+
429
446
  const getOctagonPoints = (rectangle) => {
430
447
  return [
431
448
  [rectangle.x + (rectangle.width * 3) / 10, rectangle.y],
@@ -438,36 +455,21 @@ const getOctagonPoints = (rectangle) => {
438
455
  [rectangle.x, rectangle.y + (rectangle.height * 3) / 10]
439
456
  ];
440
457
  };
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
- },
458
+ const OctagonEngine = createPolygonEngine({
459
+ getPolygonPoints: getOctagonPoints,
465
460
  getConnectorPoints(rectangle) {
466
- const cornerPoints = getParallelogramCornerPoints(rectangle);
467
- return getCenterPointsOnPolygon(cornerPoints);
461
+ return RectangleClient.getEdgeCenterPoints(rectangle);
462
+ },
463
+ getTextRectangle(element) {
464
+ const rectangle = getTextRectangle(element);
465
+ const width = rectangle.width;
466
+ rectangle.width = (rectangle.width * 3) / 4;
467
+ rectangle.x += width / 8;
468
+ return rectangle;
468
469
  }
469
- };
470
- const getParallelogramCornerPoints = (rectangle) => {
470
+ });
471
+
472
+ const getParallelogramPoints = (rectangle) => {
471
473
  return [
472
474
  [rectangle.x + rectangle.width / 4, rectangle.y],
473
475
  [rectangle.x + rectangle.width, rectangle.y],
@@ -475,34 +477,21 @@ const getParallelogramCornerPoints = (rectangle) => {
475
477
  [rectangle.x, rectangle.y + rectangle.height]
476
478
  ];
477
479
  };
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);
480
+ const ParallelogramEngine = createPolygonEngine({
481
+ getPolygonPoints: getParallelogramPoints,
482
+ getConnectorPoints: (rectangle) => {
483
+ const cornerPoints = getParallelogramPoints(rectangle);
484
+ return getCenterPointsOnPolygon(cornerPoints);
501
485
  },
502
- getConnectorPoints(rectangle) {
503
- return getPentagonPoints(rectangle);
486
+ getTextRectangle(element) {
487
+ const rectangle = getTextRectangle(element);
488
+ const width = rectangle.width;
489
+ rectangle.width = rectangle.width / 2;
490
+ rectangle.x += width / 4;
491
+ return rectangle;
504
492
  }
505
- };
493
+ });
494
+
506
495
  const getPentagonPoints = (rectangle) => {
507
496
  return [
508
497
  [rectangle.x + rectangle.width / 2, rectangle.y],
@@ -512,34 +501,23 @@ const getPentagonPoints = (rectangle) => {
512
501
  [rectangle.x, rectangle.y + (rectangle.height * 2) / 5]
513
502
  ];
514
503
  };
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);
504
+ const PentagonEngine = createPolygonEngine({
505
+ getPolygonPoints: getPentagonPoints,
506
+ getTextRectangle(element) {
507
+ const elementRectangle = getRectangleByPoints(element.points);
508
+ const strokeWidth = getStrokeWidthByElement(element);
509
+ const height = element.textHeight;
510
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
511
+ const width = (originWidth * 3) / 5;
512
+ return {
513
+ height,
514
+ width: width > 0 ? width : 0,
515
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 5,
516
+ y: elementRectangle.y + elementRectangle.height / 5 + ((elementRectangle.height * 4) / 5 - height) / 2
517
+ };
541
518
  }
542
- };
519
+ });
520
+
543
521
  const getPentagonArrowPoints = (rectangle) => {
544
522
  return [
545
523
  [rectangle.x, rectangle.y],
@@ -549,34 +527,18 @@ const getPentagonArrowPoints = (rectangle) => {
549
527
  [rectangle.x, rectangle.y + rectangle.height]
550
528
  ];
551
529
  };
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
- },
530
+ const PentagonArrowEngine = createPolygonEngine({
531
+ getPolygonPoints: getPentagonArrowPoints,
576
532
  getConnectorPoints(rectangle) {
577
- return getProcessArrowPoints(rectangle);
533
+ return RectangleClient.getEdgeCenterPoints(rectangle);
534
+ },
535
+ getTextRectangle(element) {
536
+ const rectangle = getTextRectangle(element);
537
+ rectangle.width = (rectangle.width * 3) / 5;
538
+ return rectangle;
578
539
  }
579
- };
540
+ });
541
+
580
542
  const getProcessArrowPoints = (rectangle) => {
581
543
  const wider = rectangle.width > rectangle.height / 2;
582
544
  return [
@@ -588,6 +550,17 @@ const getProcessArrowPoints = (rectangle) => {
588
550
  [rectangle.x + (wider ? rectangle.height / 2 : rectangle.width), rectangle.y + rectangle.height / 2]
589
551
  ];
590
552
  };
553
+ const ProcessArrowEngine = createPolygonEngine({
554
+ getPolygonPoints: getProcessArrowPoints,
555
+ getTextRectangle(element) {
556
+ const rectangle = getTextRectangle(element);
557
+ const elementRectangle = getRectangleByPoints(element.points);
558
+ const width = rectangle.width;
559
+ rectangle.width = elementRectangle.height / 2;
560
+ rectangle.x += elementRectangle.height / 2;
561
+ return rectangle;
562
+ }
563
+ });
591
564
 
592
565
  const RectangleEngine = {
593
566
  draw(board, rectangle, options) {
@@ -613,48 +586,31 @@ const RectangleEngine = {
613
586
  }
614
587
  };
615
588
 
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;
589
+ const getRightArrowPoints = (rectangle) => {
590
+ return [
591
+ [rectangle.x, rectangle.y + rectangle.height * 0.2],
592
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.2],
593
+ [rectangle.x + rectangle.width * 0.68, rectangle.y],
594
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
595
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height],
596
+ [rectangle.x + rectangle.width * 0.68, rectangle.y + rectangle.height * 0.8],
597
+ [rectangle.x, rectangle.y + rectangle.height * 0.8]
598
+ ];
599
+ };
600
+ const RightArrowEngine = createPolygonEngine({
601
+ getPolygonPoints: getRightArrowPoints,
602
+ getConnectorPoints: (rectangle) => {
603
+ return [
604
+ [rectangle.x, rectangle.y + rectangle.height / 2],
605
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
606
+ ];
623
607
  },
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
- ];
608
+ getTextRectangle(element) {
609
+ const rectangle = getTextRectangle(element);
610
+ rectangle.width = rectangle.width * 0.68;
611
+ return rectangle;
645
612
  }
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
- };
613
+ });
658
614
 
659
615
  const RoundRectangleEngine = {
660
616
  draw(board, rectangle, options) {
@@ -667,7 +623,7 @@ const RoundRectangleEngine = {
667
623
  return RectangleClient.getCornerPoints(rectangle);
668
624
  },
669
625
  getNearestPoint(rectangle, point) {
670
- return getNearestPointBetweenPointAndRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
626
+ return getNearestPointBetweenPointAndRoundRectangle$1(point, rectangle, getRoundRectangleRadius(rectangle));
671
627
  },
672
628
  getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
673
629
  const corners = RectangleEngine.getCornerPoints(rectangle);
@@ -681,7 +637,7 @@ const RoundRectangleEngine = {
681
637
  const getRoundRectangleRadius = (rectangle) => {
682
638
  return Math.min(rectangle.width * 0.1, rectangle.height * 0.1);
683
639
  };
684
- function getNearestPointBetweenPointAndRoundRectangle(point, rectangle, radius) {
640
+ function getNearestPointBetweenPointAndRoundRectangle$1(point, rectangle, radius) {
685
641
  const { x: rectX, y: rectY, width, height } = rectangle;
686
642
  const cornerPoints = RectangleClient.getCornerPoints(rectangle);
687
643
  let result = getNearestPointBetweenPointAndSegments(point, cornerPoints);
@@ -731,7 +687,7 @@ const RoundCommentEngine = {
731
687
  const point9 = [x1 + rectangle.width / 4, y2];
732
688
  const point10 = [x1 + rectangle.width / 4, rectangle.y + rectangle.height];
733
689
  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);
690
+ return rs.path(`M${point2[0]} ${point2[1]} A ${radius} ${radius}, 0, 0, 1, ${point3[0]} ${point3[1]} L ${point4[0]} ${point4[1]} A ${radius} ${radius}, 0, 0, 1, ${point5[0]} ${point5[1]} L ${point11[0]} ${point11[1]} ${point10[0]} ${point10[1]} ${point9[0]} ${point9[1]} ${point6[0]} ${point6[1]} A ${radius} ${radius}, 0, 0, 1, ${point7[0]} ${point7[1]} L ${point8[0]} ${point8[1]} A ${radius} ${radius}, 0, 0, 1, ${point1[0]} ${point1[1]} Z`, { ...options, fillStyle: 'solid' });
735
691
  },
736
692
  isHit(rectangle, point) {
737
693
  const points = [
@@ -786,34 +742,82 @@ const getRoundCommentPoints = (rectangle) => {
786
742
  ];
787
743
  };
788
744
 
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);
745
+ const getTrapezoidPoints = (rectangle) => {
746
+ return [
747
+ [rectangle.x + rectangle.width * 0.15, rectangle.y],
748
+ [rectangle.x + rectangle.width * 0.85, rectangle.y],
749
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
750
+ [rectangle.x, rectangle.y + rectangle.height]
751
+ ];
752
+ };
753
+ const TrapezoidEngine = createPolygonEngine({
754
+ getPolygonPoints: getTrapezoidPoints,
755
+ getConnectorPoints(rectangle) {
756
+ const points = getTrapezoidPoints(rectangle);
757
+ return getCenterPointsOnPolygon(points);
811
758
  },
759
+ getTextRectangle(element) {
760
+ const rectangle = getTextRectangle(element);
761
+ const width = rectangle.width;
762
+ rectangle.width = (rectangle.width * 3) / 4;
763
+ rectangle.x += width / 8;
764
+ return rectangle;
765
+ }
766
+ });
767
+
768
+ const getTrianglePoints = (rectangle) => {
769
+ return [
770
+ [rectangle.x + rectangle.width / 2, rectangle.y],
771
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
772
+ [rectangle.x, rectangle.y + rectangle.height]
773
+ ];
774
+ };
775
+ const TriangleEngine = createPolygonEngine({
776
+ getPolygonPoints: getTrianglePoints,
812
777
  getConnectorPoints(rectangle) {
813
- const points = getStarPoints(rectangle);
814
- return [points[1], points[3], points[5], points[7], points[9]];
778
+ const cornerPoints = getTrianglePoints(rectangle);
779
+ const lineCenterPoints = getCenterPointsOnPolygon(cornerPoints);
780
+ return [...lineCenterPoints, ...cornerPoints];
781
+ },
782
+ getTextRectangle(element) {
783
+ const elementRectangle = getRectangleByPoints(element.points);
784
+ const strokeWidth = getStrokeWidthByElement(element);
785
+ const height = element.textHeight;
786
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
787
+ const width = (originWidth * 2) / 3;
788
+ return {
789
+ height,
790
+ width: width > 0 ? width : 0,
791
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 6,
792
+ y: elementRectangle.y + (elementRectangle.height * 3) / 5 + ((elementRectangle.height * 2) / 5 - height) / 2
793
+ };
815
794
  }
795
+ });
796
+
797
+ const getTwoWayArrowPoints = (rectangle) => {
798
+ return [
799
+ [rectangle.x, rectangle.y + rectangle.height / 2],
800
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y],
801
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + rectangle.height / 5],
802
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + rectangle.height / 5],
803
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y],
804
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
805
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + rectangle.height],
806
+ [rectangle.x + (rectangle.width * 17) / 25, rectangle.y + (rectangle.height * 4) / 5],
807
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + (rectangle.height * 4) / 5],
808
+ [rectangle.x + (rectangle.width * 8) / 25, rectangle.y + rectangle.height]
809
+ ];
816
810
  };
811
+ const TwoWayArrowEngine = createPolygonEngine({
812
+ getPolygonPoints: getTwoWayArrowPoints,
813
+ getConnectorPoints: (rectangle) => {
814
+ return [
815
+ [rectangle.x, rectangle.y + rectangle.height / 2],
816
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2]
817
+ ];
818
+ }
819
+ });
820
+
817
821
  const getStarPoints = (rectangle) => {
818
822
  return [
819
823
  [rectangle.x + rectangle.width / 2, rectangle.y + (rectangle.height * 75) / 91],
@@ -828,169 +832,679 @@ const getStarPoints = (rectangle) => {
828
832
  [rectangle.x + (rectangle.width * 77.3892626) / 96, rectangle.y + rectangle.height]
829
833
  ];
830
834
  };
835
+ const StarEngine = createPolygonEngine({
836
+ getPolygonPoints: getStarPoints,
837
+ getConnectorPoints: (rectangle) => {
838
+ const points = getStarPoints(rectangle);
839
+ return [points[1], points[3], points[5], points[7], points[9]];
840
+ },
841
+ getTextRectangle(element) {
842
+ const elementRectangle = getRectangleByPoints(element.points);
843
+ const strokeWidth = getStrokeWidthByElement(element);
844
+ const height = element.textHeight;
845
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
846
+ const width = originWidth / 2;
847
+ return {
848
+ height,
849
+ width: width > 0 ? width : 0,
850
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 4,
851
+ y: elementRectangle.y + (elementRectangle.height * 1) / 5 + ((elementRectangle.height * 4) / 5 - height) / 2
852
+ };
853
+ }
854
+ });
831
855
 
832
- const TrapezoidEngine = {
856
+ const TerminalEngine = {
833
857
  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;
858
+ return drawRoundRectangle(PlaitBoard.getRoughSVG(board), rectangle.x, rectangle.y, rectangle.x + rectangle.width, rectangle.y + rectangle.height, { ...options, fillStyle: 'solid' }, false, getStartEndRadius(rectangle));
839
859
  },
840
860
  isHit(rectangle, point) {
841
- const points = getTrapezoidPoints(rectangle);
842
- return isPointInPolygon(point, points);
861
+ return isPointInRoundRectangle(point, rectangle, getStartEndRadius(rectangle));
843
862
  },
844
- getNearestPoint(rectangle, point) {
845
- const cornerPoints = getTrapezoidPoints(rectangle);
846
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
863
+ getCornerPoints(rectangle) {
864
+ return RectangleClient.getCornerPoints(rectangle);
847
865
  },
848
- getConnectorPoints(rectangle) {
849
- const points = getTrapezoidPoints(rectangle);
850
- return getCenterPointsOnPolygon(points);
866
+ getNearestPoint(rectangle, point) {
867
+ return getNearestPointBetweenPointAndRoundRectangle(point, rectangle, getStartEndRadius(rectangle));
851
868
  },
852
869
  getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
853
- const corners = getTrapezoidPoints(rectangle);
870
+ const corners = RectangleEngine.getCornerPoints(rectangle);
854
871
  const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
855
872
  return getEdgeOnPolygonByPoint(corners, point);
856
873
  },
857
- getCornerPoints(rectangle) {
858
- return getTrapezoidPoints(rectangle);
874
+ getConnectorPoints(rectangle) {
875
+ return RectangleClient.getEdgeCenterPoints(rectangle);
859
876
  }
860
877
  };
861
- const getTrapezoidPoints = (rectangle) => {
878
+ const getStartEndRadius = (rectangle) => {
879
+ return Math.min(rectangle.width / 2, rectangle.height / 2);
880
+ };
881
+ function getNearestPointBetweenPointAndRoundRectangle(point, rectangle, radius) {
882
+ const { x: rectX, y: rectY, width, height } = rectangle;
883
+ const cornerPoints = RectangleClient.getCornerPoints(rectangle);
884
+ let result = getNearestPointBetweenPointAndSegments(point, cornerPoints);
885
+ let circleCenter = null;
886
+ const inLeftTop = point[0] >= rectX && point[0] <= rectX + radius && point[1] >= rectY && point[1] <= rectY + radius;
887
+ if (inLeftTop) {
888
+ circleCenter = [rectX + radius, rectY + radius];
889
+ }
890
+ const inLeftBottom = point[0] >= rectX && point[0] <= rectX + radius && point[1] >= rectY + height && point[1] <= rectY + height - radius;
891
+ if (inLeftBottom) {
892
+ circleCenter = [rectX + radius, rectY + height - radius];
893
+ }
894
+ const inRightTop = point[0] >= rectX + width - radius && point[0] <= rectX + width && point[1] >= rectY && point[1] <= rectY + radius;
895
+ if (inRightTop) {
896
+ circleCenter = [rectX + width - radius, rectY + radius];
897
+ }
898
+ const inRightBottom = point[0] >= rectX + width - radius &&
899
+ point[0] <= rectX + width &&
900
+ point[1] >= rectY + height - radius &&
901
+ point[1] <= rectY + height;
902
+ if (inRightBottom) {
903
+ circleCenter = [rectX + width - radius, rectY + height - radius];
904
+ }
905
+ if (circleCenter) {
906
+ result = getNearestPointBetweenPointAndEllipse(point, circleCenter, radius, radius);
907
+ }
908
+ return result;
909
+ }
910
+
911
+ const getManualInputPoints = (rectangle) => {
862
912
  return [
863
- [rectangle.x + rectangle.width * 0.15, rectangle.y],
864
- [rectangle.x + rectangle.width * 0.85, rectangle.y],
913
+ [rectangle.x, rectangle.y + rectangle.height / 4],
914
+ [rectangle.x + rectangle.width, rectangle.y],
865
915
  [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
866
916
  [rectangle.x, rectangle.y + rectangle.height]
867
917
  ];
868
918
  };
919
+ const ManualInputEngine = createPolygonEngine({
920
+ getPolygonPoints: getManualInputPoints,
921
+ getConnectorPoints: (rectangle) => {
922
+ const cornerPoints = getManualInputPoints(rectangle);
923
+ return getCenterPointsOnPolygon(cornerPoints);
924
+ },
925
+ getTextRectangle: (element) => {
926
+ const elementRectangle = getRectangleByPoints(element.points);
927
+ const strokeWidth = getStrokeWidthByElement(element);
928
+ const height = element.textHeight;
929
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
930
+ return {
931
+ height,
932
+ width: width > 0 ? width : 0,
933
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
934
+ y: elementRectangle.y + elementRectangle.height / 4 + ((elementRectangle.height * 3) / 4 - height) / 2
935
+ };
936
+ }
937
+ });
938
+
939
+ const getPreparationPoints = (rectangle) => {
940
+ return [
941
+ [rectangle.x, rectangle.y + rectangle.height / 2],
942
+ [rectangle.x + rectangle.width / 6, rectangle.y],
943
+ [rectangle.x + (rectangle.width * 5) / 6, rectangle.y],
944
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
945
+ [rectangle.x + (rectangle.width * 5) / 6, rectangle.y + rectangle.height],
946
+ [rectangle.x + rectangle.width / 6, rectangle.y + rectangle.height]
947
+ ];
948
+ };
949
+ const PreparationEngine = createPolygonEngine({
950
+ getPolygonPoints: getPreparationPoints,
951
+ getConnectorPoints: (rectangle) => {
952
+ return RectangleClient.getEdgeCenterPoints(rectangle);
953
+ },
954
+ getTextRectangle(element) {
955
+ const rectangle = getTextRectangle(element);
956
+ const width = rectangle.width;
957
+ rectangle.width = (rectangle.width * 2) / 3;
958
+ rectangle.x += width / 6;
959
+ return rectangle;
960
+ }
961
+ });
962
+
963
+ const getManualLoopPoints = (rectangle) => {
964
+ return [
965
+ [rectangle.x, rectangle.y],
966
+ [rectangle.x + rectangle.width, rectangle.y],
967
+ [rectangle.x + (rectangle.width * 7) / 8, rectangle.y + rectangle.height],
968
+ [rectangle.x + rectangle.width / 8, rectangle.y + rectangle.height]
969
+ ];
970
+ };
971
+ const ManualLoopEngine = createPolygonEngine({
972
+ getPolygonPoints: getManualLoopPoints,
973
+ getConnectorPoints: (rectangle) => {
974
+ const cornerPoints = getManualLoopPoints(rectangle);
975
+ return getCenterPointsOnPolygon(cornerPoints);
976
+ },
977
+ getTextRectangle(element) {
978
+ const rectangle = getTextRectangle(element);
979
+ const width = rectangle.width;
980
+ rectangle.width = (rectangle.width * 3) / 4;
981
+ rectangle.x += width / 8;
982
+ return rectangle;
983
+ }
984
+ });
985
+
986
+ const getMergePoints = (rectangle) => {
987
+ return [
988
+ [rectangle.x, rectangle.y],
989
+ [rectangle.x + rectangle.width, rectangle.y],
990
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height]
991
+ ];
992
+ };
993
+ const MergeEngine = createPolygonEngine({
994
+ getPolygonPoints: getMergePoints,
995
+ getConnectorPoints: (rectangle) => {
996
+ const cornerPoints = getMergePoints(rectangle);
997
+ const lineCenterPoints = getCenterPointsOnPolygon(cornerPoints);
998
+ return [...lineCenterPoints, ...cornerPoints];
999
+ },
1000
+ getTextRectangle(element) {
1001
+ const elementRectangle = getRectangleByPoints(element.points);
1002
+ const strokeWidth = getStrokeWidthByElement(element);
1003
+ const height = element.textHeight;
1004
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
1005
+ const width = (originWidth * 2) / 3;
1006
+ return {
1007
+ height,
1008
+ width: width > 0 ? width : 0,
1009
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 6,
1010
+ y: elementRectangle.y + ((elementRectangle.height * 2) / 3 - height) / 2
1011
+ };
1012
+ }
1013
+ });
869
1014
 
870
- const TriangleEngine = {
1015
+ const DelayEngine = {
871
1016
  draw(board, rectangle, options) {
872
- const points = getTrianglePoints(rectangle);
873
1017
  const rs = PlaitBoard.getRoughSVG(board);
874
- const polygon = rs.polygon(points, { ...options, fillStyle: 'solid' });
875
- setStrokeLinecap(polygon, 'round');
876
- return polygon;
1018
+ const shape = rs.path(`M${rectangle.x} ${rectangle.y} L${rectangle.x + (rectangle.width * 3) / 4} ${rectangle.y} A ${rectangle.width /
1019
+ 4} ${rectangle.height / 2}, 0, 0, 1,${rectangle.x + (rectangle.width * 3) / 4} ${rectangle.y + rectangle.height} L${rectangle.x} ${rectangle.y + rectangle.height} Z`, { ...options, fillStyle: 'solid' });
1020
+ setStrokeLinecap(shape, 'round');
1021
+ return shape;
877
1022
  },
878
1023
  isHit(rectangle, point) {
879
- const points = getTrianglePoints(rectangle);
880
- return isPointInPolygon(point, points);
1024
+ //split shape to rectangle and a half ellipse
1025
+ const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
1026
+ const isInRectangle = RectangleClient.isHit({
1027
+ ...rectangle,
1028
+ width: (rectangle.width * 3) / 4
1029
+ }, rangeRectangle);
1030
+ const isInEllipse = isPointInEllipse(point, [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 2], rectangle.width / 4, rectangle.height / 2);
1031
+ return isInRectangle || isInEllipse;
1032
+ },
1033
+ getCornerPoints(rectangle) {
1034
+ return RectangleClient.getCornerPoints(rectangle);
881
1035
  },
882
1036
  getNearestPoint(rectangle, point) {
883
- const cornerPoints = getTrianglePoints(rectangle);
884
- return getNearestPointBetweenPointAndSegments(point, cornerPoints);
1037
+ const nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
1038
+ if (nearestPoint[0] > rectangle.x + (rectangle.width * 3) / 4) {
1039
+ return getNearestPointBetweenPointAndEllipse(point, [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 2], rectangle.width / 4, rectangle.height / 2);
1040
+ }
1041
+ return nearestPoint;
1042
+ },
1043
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
1044
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1045
+ const centerPoint = [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height / 2];
1046
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
1047
+ const a = rectangle.width / 4;
1048
+ const b = rectangle.height / 2;
1049
+ const slope = getTangentSlope(point[0], point[1], a, b);
1050
+ return getVectorBySlope(point[0], point[1], slope);
885
1051
  },
886
1052
  getConnectorPoints(rectangle) {
887
- const cornerPoints = getTrianglePoints(rectangle);
888
- const lineCenterPoints = getCenterPointsOnPolygon(cornerPoints);
889
- return [...lineCenterPoints, ...cornerPoints];
1053
+ return RectangleClient.getEdgeCenterPoints(rectangle);
1054
+ }
1055
+ };
1056
+
1057
+ const StoredDataEngine = {
1058
+ draw(board, rectangle, options) {
1059
+ const rs = PlaitBoard.getRoughSVG(board);
1060
+ const shape = rs.path(`M${rectangle.x + rectangle.width / 10} ${rectangle.y} L${rectangle.x + rectangle.width} ${rectangle.y} A ${rectangle.width /
1061
+ 10} ${rectangle.height / 2}, 1, 0, 0,${rectangle.x + rectangle.width} ${rectangle.y + rectangle.height} L${rectangle.x +
1062
+ rectangle.width / 10} ${rectangle.y + rectangle.height}A ${rectangle.width / 10} ${rectangle.height /
1063
+ 2}, 0, 0, 1,${rectangle.x + rectangle.width / 10} ${rectangle.y}`, { ...options, fillStyle: 'solid' });
1064
+ setStrokeLinecap(shape, 'round');
1065
+ return shape;
890
1066
  },
891
- getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
892
- const corners = getTrianglePoints(rectangle);
893
- const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
894
- return getEdgeOnPolygonByPoint(corners, point);
1067
+ isHit(rectangle, point) {
1068
+ //split shape to rectangle and a half ellipse
1069
+ const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
1070
+ const isInRectangle = RectangleClient.isHit({
1071
+ ...rectangle,
1072
+ x: rectangle.x + rectangle.width / 10,
1073
+ width: (rectangle.width * 9) / 10
1074
+ }, rangeRectangle);
1075
+ const isInFrontEllipse = isPointInEllipse(point, [rectangle.x + rectangle.width / 10, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1076
+ const notInBackEllipse = !isPointInEllipse(point, [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1077
+ return (isInRectangle && notInBackEllipse) || isInFrontEllipse;
895
1078
  },
896
1079
  getCornerPoints(rectangle) {
897
- return getTrianglePoints(rectangle);
898
- }
1080
+ return RectangleClient.getCornerPoints(rectangle);
1081
+ },
1082
+ getNearestPoint(rectangle, point) {
1083
+ const nearestPoint = getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
1084
+ if (nearestPoint[0] < rectangle.x + rectangle.width / 10) {
1085
+ const nearestPoint = getNearestPointBetweenPointAndEllipse(point, [rectangle.x + rectangle.width / 10, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1086
+ if (nearestPoint[0] > rectangle.x + rectangle.width / 10) {
1087
+ nearestPoint[0] = (rectangle.x + rectangle.width / 10) * 2 - nearestPoint[0];
1088
+ }
1089
+ return nearestPoint;
1090
+ }
1091
+ if (nearestPoint[0] > rectangle.x + (rectangle.width * 9) / 10) {
1092
+ return getNearestPointBetweenPointAndEllipse(point, [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2], rectangle.width / 10, rectangle.height / 2);
1093
+ }
1094
+ return nearestPoint;
1095
+ },
1096
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
1097
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1098
+ let centerPoint = [rectangle.x + rectangle.width / 10, rectangle.y + rectangle.height / 2];
1099
+ let a = rectangle.width / 10;
1100
+ let b = rectangle.height / 2;
1101
+ const isBackEllipse = connectionPoint[0] > rectangle.x + (rectangle.width * 9) / 10 && connectionPoint[1] > rectangle.y;
1102
+ if (isBackEllipse) {
1103
+ centerPoint = [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2];
1104
+ }
1105
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
1106
+ const slope = getTangentSlope(point[0], point[1], a, b);
1107
+ const vector = getVectorBySlope(point[0], point[1], slope);
1108
+ return isBackEllipse ? vector.map(num => -num) : vector;
1109
+ },
1110
+ getConnectorPoints(rectangle) {
1111
+ return [
1112
+ [rectangle.x + rectangle.width / 2, rectangle.y],
1113
+ [rectangle.x + (rectangle.width * 9) / 10, rectangle.y + rectangle.height / 2],
1114
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
1115
+ [rectangle.x, rectangle.y + rectangle.height / 2]
1116
+ ];
1117
+ },
1118
+ getTextRectangle(element) {
1119
+ const rectangle = getTextRectangle(element);
1120
+ const width = rectangle.width;
1121
+ rectangle.width = (rectangle.width * 3) / 4;
1122
+ rectangle.x += width / 8;
1123
+ return rectangle;
1124
+ }
1125
+ };
1126
+
1127
+ const ShapeEngineMap = {
1128
+ [BasicShapes.rectangle]: RectangleEngine,
1129
+ [BasicShapes.diamond]: DiamondEngine,
1130
+ [BasicShapes.ellipse]: EllipseEngine,
1131
+ [BasicShapes.parallelogram]: ParallelogramEngine,
1132
+ [BasicShapes.roundRectangle]: RoundRectangleEngine,
1133
+ [BasicShapes.text]: RectangleEngine,
1134
+ [BasicShapes.triangle]: TriangleEngine,
1135
+ [BasicShapes.leftArrow]: LeftArrowEngine,
1136
+ [BasicShapes.trapezoid]: TrapezoidEngine,
1137
+ [BasicShapes.rightArrow]: RightArrowEngine,
1138
+ [BasicShapes.cross]: CrossEngine,
1139
+ [BasicShapes.star]: StarEngine,
1140
+ [BasicShapes.pentagon]: PentagonEngine,
1141
+ [BasicShapes.hexagon]: HexagonEngine,
1142
+ [BasicShapes.octagon]: OctagonEngine,
1143
+ [BasicShapes.pentagonArrow]: PentagonArrowEngine,
1144
+ [BasicShapes.processArrow]: ProcessArrowEngine,
1145
+ [BasicShapes.twoWayArrow]: TwoWayArrowEngine,
1146
+ [BasicShapes.comment]: CommentEngine,
1147
+ [BasicShapes.roundComment]: RoundCommentEngine,
1148
+ [FlowchartSymbols.process]: RectangleEngine,
1149
+ [FlowchartSymbols.decision]: DiamondEngine,
1150
+ [FlowchartSymbols.connector]: EllipseEngine,
1151
+ [FlowchartSymbols.data]: ParallelogramEngine,
1152
+ [FlowchartSymbols.terminal]: TerminalEngine,
1153
+ [FlowchartSymbols.manualInput]: ManualInputEngine,
1154
+ [FlowchartSymbols.preparation]: PreparationEngine,
1155
+ [FlowchartSymbols.manualLoop]: ManualLoopEngine,
1156
+ [FlowchartSymbols.merge]: MergeEngine,
1157
+ [FlowchartSymbols.delay]: DelayEngine,
1158
+ [FlowchartSymbols.storedData]: StoredDataEngine
1159
+ };
1160
+ const getEngine = (shape) => {
1161
+ return ShapeEngineMap[shape];
1162
+ };
1163
+
1164
+ const getShape = (value) => {
1165
+ if (PlaitDrawElement.isImage(value)) {
1166
+ return BasicShapes.rectangle;
1167
+ }
1168
+ return value.shape;
1169
+ };
1170
+
1171
+ class GeometryShapeGenerator extends Generator {
1172
+ canDraw(element, data) {
1173
+ return true;
1174
+ }
1175
+ baseDraw(element, data) {
1176
+ const rectangle = getRectangleByPoints(element.points);
1177
+ const shape = element.shape;
1178
+ if (shape === BasicShapes.text) {
1179
+ return;
1180
+ }
1181
+ const strokeWidth = getStrokeWidthByElement(element);
1182
+ const strokeColor = getStrokeColorByElement(element);
1183
+ const fill = getFillByElement(element);
1184
+ const strokeLineDash = getLineDashByElement(element);
1185
+ return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
1186
+ stroke: strokeColor,
1187
+ strokeWidth,
1188
+ fill,
1189
+ strokeLineDash
1190
+ });
1191
+ }
1192
+ }
1193
+
1194
+ const insertGeometry = (board, points, shape) => {
1195
+ let newElement = createGeometryElement(shape, points, '', {
1196
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1197
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1198
+ });
1199
+ Transforms.insertNode(board, newElement, [board.children.length]);
1200
+ clearSelectedElement(board);
1201
+ addSelectedElement(board, newElement);
1202
+ };
1203
+ const insertText = (board, points, text = '文本') => {
1204
+ let newElement = createGeometryElement(BasicShapes.text, points, text);
1205
+ Transforms.insertNode(board, newElement, [board.children.length]);
1206
+ clearSelectedElement(board);
1207
+ addSelectedElement(board, newElement);
1208
+ };
1209
+ const resizeGeometry = (board, points, textHeight, path) => {
1210
+ const normalizePoints = normalizeShapePoints(points);
1211
+ const element = PlaitNode.get(board, path);
1212
+ const newHeight = textHeight / board.viewport.zoom;
1213
+ const newProperties = { points: normalizePoints, textHeight: newHeight };
1214
+ if (PlaitDrawElement.isText(element) && element.autoSize) {
1215
+ newProperties.autoSize = false;
1216
+ }
1217
+ Transforms.setNode(board, newProperties, path);
1218
+ };
1219
+
1220
+ const normalizePoints = (board, element, width, textHeight) => {
1221
+ let points = element.points;
1222
+ let autoSize = element.autoSize;
1223
+ const defaultSpace = ShapeDefaultSpace.rectangleAndText;
1224
+ if (autoSize) {
1225
+ const editor = PlaitGeometry.getTextEditor(element);
1226
+ if (AlignEditor.isActive(editor, Alignment.right)) {
1227
+ points = [
1228
+ [points[1][0] - (width + defaultSpace * 2), points[0][1]],
1229
+ [points[1][0], points[0][1] + textHeight]
1230
+ ];
1231
+ }
1232
+ else if (AlignEditor.isActive(editor, Alignment.center)) {
1233
+ const oldWidth = Math.abs(points[0][0] - points[1][0]);
1234
+ const offset = (width - oldWidth) / 2;
1235
+ points = [
1236
+ [points[0][0] - offset - defaultSpace, points[0][1]],
1237
+ [points[1][0] + offset + defaultSpace, points[0][1] + textHeight]
1238
+ ];
1239
+ }
1240
+ else {
1241
+ points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
1242
+ }
1243
+ }
1244
+ return { points };
1245
+ };
1246
+ const setText = (board, element, text, width, textHeight) => {
1247
+ const newElement = {
1248
+ text,
1249
+ textHeight,
1250
+ ...normalizePoints(board, element, width, textHeight)
1251
+ };
1252
+ const path = board.children.findIndex(child => child === element);
1253
+ Transforms.setNode(board, newElement, [path]);
1254
+ };
1255
+ const setTextSize = (board, element, textWidth, textHeight) => {
1256
+ if (element.autoSize) {
1257
+ const newElement = {
1258
+ textHeight,
1259
+ ...normalizePoints(board, element, textWidth, textHeight)
1260
+ };
1261
+ const isPointsEqual = Point.isEquals(element.points[0], newElement.points[0]) && Point.isEquals(element.points[1], newElement.points[1]);
1262
+ const isTextHeightEqual = Math.round(textHeight) === Math.round(element.textHeight);
1263
+ if (!isPointsEqual || !isTextHeightEqual) {
1264
+ const path = board.children.findIndex(child => child === element);
1265
+ Transforms.setNode(board, newElement, [path]);
1266
+ }
1267
+ }
1268
+ };
1269
+
1270
+ const insertImage = (board, imageItem, startPoint) => {
1271
+ const { width, height, url } = imageItem;
1272
+ const host = BOARD_TO_HOST.get(board);
1273
+ const viewportWidth = PlaitBoard.getComponent(board).nativeElement.clientWidth;
1274
+ const viewportHeight = PlaitBoard.getComponent(board).nativeElement.clientHeight;
1275
+ const point = transformPoint(board, toPoint(viewportWidth / 2, viewportHeight / 2, host));
1276
+ const points = startPoint
1277
+ ? [startPoint, [startPoint[0] + width, startPoint[1] + height]]
1278
+ : [
1279
+ [point[0] - width / 2, point[1] - height / 2],
1280
+ [point[0] + width / 2, point[1] + height / 2]
1281
+ ];
1282
+ const imageElement = {
1283
+ id: idCreator(),
1284
+ type: 'image',
1285
+ points,
1286
+ url
1287
+ };
1288
+ Transforms.insertNode(board, imageElement, [board.children.length]);
1289
+ Transforms.addSelectionWithTemporaryElements(board, [imageElement]);
1290
+ };
1291
+
1292
+ const resizeLine = (board, options, path) => {
1293
+ Transforms.setNode(board, options, path);
1294
+ };
1295
+ const setLineTexts = (board, element, texts) => {
1296
+ const path = PlaitBoard.findPath(board, element);
1297
+ Transforms.setNode(board, { texts }, path);
1298
+ };
1299
+ const removeLineText = (board, element, index) => {
1300
+ const path = PlaitBoard.findPath(board, element);
1301
+ const texts = element.texts?.length ? [...element.texts] : [];
1302
+ const newTexts = [...texts];
1303
+ newTexts.splice(index, 1);
1304
+ Transforms.setNode(board, { texts: newTexts }, path);
1305
+ };
1306
+ const setLineMark = (board, element, handleKey, marker) => {
1307
+ const path = PlaitBoard.findPath(board, element);
1308
+ let handle = handleKey === LineHandleKey.source ? element.source : element.target;
1309
+ handle = { ...handle, marker };
1310
+ Transforms.setNode(board, { [handleKey]: handle }, path);
1311
+ };
1312
+
1313
+ const DrawTransforms = {
1314
+ setText,
1315
+ insertGeometry,
1316
+ resizeGeometry,
1317
+ insertText,
1318
+ setTextSize,
1319
+ resizeLine,
1320
+ setLineTexts,
1321
+ removeLineText,
1322
+ setLineMark,
1323
+ insertImage
1324
+ };
1325
+
1326
+ const withGeometryCreateByDrag = (board) => {
1327
+ const { pointerMove, pointerUp } = board;
1328
+ let geometryShapeG = null;
1329
+ board.pointerMove = (event) => {
1330
+ geometryShapeG?.remove();
1331
+ geometryShapeG = createG();
1332
+ const geometryGenerator = new GeometryShapeGenerator(board);
1333
+ const geometryPointers = getGeometryPointers();
1334
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1335
+ const dragMode = isGeometryPointer && isDndMode(board);
1336
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1337
+ const pointer = PlaitBoard.getPointer(board);
1338
+ if (dragMode) {
1339
+ const points = getDefaultGeometryPoints(pointer, movingPoint);
1340
+ if (pointer === BasicShapes.text) {
1341
+ const textG = getTemporaryTextG(movingPoint);
1342
+ geometryShapeG.appendChild(textG);
1343
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1344
+ }
1345
+ else {
1346
+ const temporaryElement = createGeometryElement(pointer, points, '', {
1347
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1348
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1349
+ });
1350
+ geometryGenerator.draw(temporaryElement, geometryShapeG);
1351
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1352
+ }
1353
+ }
1354
+ pointerMove(event);
1355
+ };
1356
+ board.pointerUp = (event) => {
1357
+ const pointer = PlaitBoard.getPointer(board);
1358
+ const geometryPointers = getGeometryPointers();
1359
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1360
+ const dragMode = isGeometryPointer && isDndMode(board);
1361
+ if (dragMode) {
1362
+ const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1363
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
1364
+ if (pointer === BasicShapes.text) {
1365
+ DrawTransforms.insertText(board, points);
1366
+ }
1367
+ else {
1368
+ DrawTransforms.insertGeometry(board, points, pointer);
1369
+ }
1370
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1371
+ }
1372
+ geometryShapeG?.remove();
1373
+ geometryShapeG = null;
1374
+ preventTouchMove(board, event, false);
1375
+ pointerUp(event);
1376
+ };
1377
+ return board;
1378
+ };
1379
+ const withGeometryCreateByDrawing = (board) => {
1380
+ const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
1381
+ let start = null;
1382
+ let geometryShapeG = null;
1383
+ let temporaryElement = null;
1384
+ let isShift = false;
1385
+ board.keydown = (event) => {
1386
+ isShift = isKeyHotkey('shift', event);
1387
+ keydown(event);
1388
+ };
1389
+ board.keyup = (event) => {
1390
+ isShift = false;
1391
+ keyup(event);
1392
+ };
1393
+ board.pointerDown = (event) => {
1394
+ const geometryPointers = getGeometryPointers();
1395
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
1396
+ if (isGeometryPointer && isDrawingMode(board)) {
1397
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1398
+ start = point;
1399
+ const pointer = PlaitBoard.getPointer(board);
1400
+ preventTouchMove(board, event, true);
1401
+ if (pointer === BasicShapes.text) {
1402
+ const points = getDefaultGeometryPoints(pointer, point);
1403
+ const textElement = createGeometryElement(BasicShapes.text, points, DefaultTextProperty.text);
1404
+ Transforms.insertNode(board, textElement, [board.children.length]);
1405
+ clearSelectedElement(board);
1406
+ addSelectedElement(board, textElement);
1407
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1408
+ start = null;
1409
+ }
1410
+ }
1411
+ pointerDown(event);
1412
+ };
1413
+ board.pointerMove = (event) => {
1414
+ geometryShapeG?.remove();
1415
+ geometryShapeG = createG();
1416
+ const geometryGenerator = new GeometryShapeGenerator(board);
1417
+ const drawMode = !!start;
1418
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1419
+ const pointer = PlaitBoard.getPointer(board);
1420
+ if (drawMode && pointer !== BasicShapes.text) {
1421
+ const points = normalizeShapePoints([start, movingPoint], isShift);
1422
+ temporaryElement = createGeometryElement(pointer, points, '', {
1423
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1424
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1425
+ });
1426
+ geometryGenerator.draw(temporaryElement, geometryShapeG);
1427
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1428
+ }
1429
+ pointerMove(event);
1430
+ };
1431
+ board.pointerUp = (event) => {
1432
+ const isDrawMode = !!start;
1433
+ if (isDrawMode) {
1434
+ const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1435
+ const { width, height } = RectangleClient.toRectangleClient([start, targetPoint]);
1436
+ if (Math.hypot(width, height) === 0) {
1437
+ const pointer = PlaitBoard.getPointer(board);
1438
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
1439
+ if (pointer !== BasicShapes.text) {
1440
+ temporaryElement = createGeometryElement(pointer, points, '', {
1441
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1442
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1443
+ });
1444
+ }
1445
+ }
1446
+ }
1447
+ if (temporaryElement) {
1448
+ Transforms.insertNode(board, temporaryElement, [board.children.length]);
1449
+ clearSelectedElement(board);
1450
+ addSelectedElement(board, temporaryElement);
1451
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1452
+ }
1453
+ geometryShapeG?.remove();
1454
+ geometryShapeG = null;
1455
+ start = null;
1456
+ temporaryElement = null;
1457
+ preventTouchMove(board, event, false);
1458
+ pointerUp(event);
1459
+ };
1460
+ return board;
899
1461
  };
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
- ];
1462
+ const getDefaultGeometryPoints = (pointer, targetPoint) => {
1463
+ const defaultProperty = getGeometryDefaultProperty(pointer);
1464
+ return getPointsByCenterPoint(targetPoint, defaultProperty.width, defaultProperty.height);
906
1465
  };
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
- ];
1466
+ const getGeometryDefaultProperty = (pointer) => {
1467
+ const isText = pointer === BasicShapes.text;
1468
+ const isFlowChart = getFlowchartPointers().includes(pointer);
1469
+ if (isText) {
1470
+ return DefaultTextProperty;
1471
+ }
1472
+ else if (isFlowChart) {
1473
+ return getDefaultFlowchartProperty(pointer);
1474
+ }
1475
+ else {
1476
+ return DefaultBasicShapeProperty;
937
1477
  }
938
1478
  };
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
- };
953
-
954
- const ShapeEngineMap = {
955
- [GeometryShape.rectangle]: RectangleEngine,
956
- [GeometryShape.diamond]: DiamondEngine,
957
- [GeometryShape.ellipse]: EllipseEngine,
958
- [GeometryShape.parallelogram]: ParallelogramEngine,
959
- [GeometryShape.roundRectangle]: RoundRectangleEngine,
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
975
- };
976
- const getEngine = (shape) => {
977
- return ShapeEngineMap[shape];
1479
+ const getTemporaryTextG = (movingPoint) => {
1480
+ const textG = createG();
1481
+ const width = DefaultTextProperty.width - ShapeDefaultSpace.rectangleAndText * 2;
1482
+ const foreignObject = createForeignObject(movingPoint[0] - width / 2, movingPoint[1] - DefaultTextProperty.height / 2, width, DefaultTextProperty.height);
1483
+ const richtext = document.createElement('div');
1484
+ richtext.textContent = DefaultTextProperty.text;
1485
+ richtext.style.fontSize = `${DEFAULT_FONT_SIZE}px`;
1486
+ richtext.style.cursor = 'default';
1487
+ foreignObject.appendChild(richtext);
1488
+ textG.appendChild(foreignObject);
1489
+ return textG;
978
1490
  };
979
1491
 
980
- const getShape = (value) => {
981
- if (PlaitDrawElement.isImage(value)) {
982
- return GeometryShape.rectangle;
983
- }
984
- return value.shape;
1492
+ const DefaultLineStyle = {
1493
+ strokeWidth: 2,
1494
+ strokeColor: '#000'
985
1495
  };
986
1496
 
987
1497
  const createGeometryElement = (shape, points, text, options) => {
988
1498
  let textOptions = {};
989
1499
  let alignment = Alignment.center;
990
- if (shape === GeometryShape.text) {
1500
+ if (shape === BasicShapes.text) {
991
1501
  textOptions = { autoSize: true };
992
1502
  alignment = undefined;
993
1503
  }
1504
+ let flowchartOptions = {};
1505
+ if (getFlowchartPointers().includes(shape)) {
1506
+ flowchartOptions = { fill: '#ffffff' };
1507
+ }
994
1508
  return {
995
1509
  id: idCreator(),
996
1510
  type: 'geometry',
@@ -1001,7 +1515,8 @@ const createGeometryElement = (shape, points, text, options) => {
1001
1515
  text: buildText(text, alignment),
1002
1516
  points,
1003
1517
  ...textOptions,
1004
- ...options
1518
+ ...options,
1519
+ ...flowchartOptions
1005
1520
  };
1006
1521
  };
1007
1522
  const getPointsByCenterPoint = (point, width, height) => {
@@ -1073,6 +1588,66 @@ const getEdgeOnPolygonByPoint = (corners, point) => {
1073
1588
  }
1074
1589
  return null;
1075
1590
  };
1591
+ const getDefaultFlowchartProperty = (symbol) => {
1592
+ return DefaultFlowchartPropertyMap[symbol];
1593
+ };
1594
+ const createDefaultFlowchart = (point) => {
1595
+ const decisionProperty = getDefaultFlowchartProperty(FlowchartSymbols.decision);
1596
+ const processProperty = getDefaultFlowchartProperty(FlowchartSymbols.process);
1597
+ const terminalProperty = getDefaultFlowchartProperty(FlowchartSymbols.terminal);
1598
+ const options = {
1599
+ strokeColor: DefaultBasicShapeProperty.strokeColor,
1600
+ strokeWidth: DefaultBasicShapeProperty.strokeWidth
1601
+ };
1602
+ const lineOptions = {
1603
+ strokeColor: DefaultLineStyle.strokeColor,
1604
+ strokeWidth: DefaultLineStyle.strokeWidth
1605
+ };
1606
+ const startElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, point), '开始', options);
1607
+ const processPoint1 = [point[0], point[1] + terminalProperty.height / 2 + 55 + processProperty.height / 2];
1608
+ const processElement1 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint1), '过程', options);
1609
+ const decisionPoint = [processPoint1[0], processPoint1[1] + processProperty.height / 2 + 55 + decisionProperty.height / 2];
1610
+ const decisionElement = createGeometryElement(FlowchartSymbols.decision, getDefaultGeometryPoints(FlowchartSymbols.decision, decisionPoint), '过程', options);
1611
+ const processPoint2 = [decisionPoint[0] + decisionProperty.width / 2 + 75 + processProperty.width / 2, decisionPoint[1]];
1612
+ const processElement2 = createGeometryElement(FlowchartSymbols.process, getDefaultGeometryPoints(FlowchartSymbols.process, processPoint2), '过程', options);
1613
+ const endPoint = [decisionPoint[0], decisionPoint[1] + decisionProperty.height / 2 + 95 + terminalProperty.height / 2];
1614
+ const endElement = createGeometryElement(FlowchartSymbols.terminal, getDefaultGeometryPoints(FlowchartSymbols.terminal, endPoint), '结束', options);
1615
+ const line1 = createLineElement(LineShape.elbow, [
1616
+ [0, 0],
1617
+ [0, 0]
1618
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: startElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: processElement1.id }, [], lineOptions);
1619
+ const line2 = createLineElement(LineShape.elbow, [
1620
+ [0, 0],
1621
+ [0, 0]
1622
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement1.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: decisionElement.id }, [], lineOptions);
1623
+ const line3 = createLineElement(LineShape.elbow, [
1624
+ [0, 0],
1625
+ [0, 0]
1626
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0.5, 0], boundId: endElement.id }, [
1627
+ {
1628
+ text: buildText('是'),
1629
+ position: 0.5,
1630
+ width: 14,
1631
+ height: 20
1632
+ }
1633
+ ], lineOptions);
1634
+ const line4 = createLineElement(LineShape.elbow, [
1635
+ [0, 0],
1636
+ [0, 0]
1637
+ ], { marker: LineMarkerType.none, connection: [1, 0.5], boundId: decisionElement.id }, { marker: LineMarkerType.arrow, connection: [0, 0.5], boundId: processElement2.id }, [
1638
+ {
1639
+ text: buildText('否'),
1640
+ position: 0.5,
1641
+ width: 14,
1642
+ height: 20
1643
+ }
1644
+ ], lineOptions);
1645
+ const line5 = createLineElement(LineShape.elbow, [
1646
+ [0, 0],
1647
+ [0, 0]
1648
+ ], { marker: LineMarkerType.none, connection: [0.5, 1], boundId: processElement2.id }, { marker: LineMarkerType.arrow, connection: [1, 0.5], boundId: endElement.id }, [], lineOptions);
1649
+ return [startElement, processElement1, decisionElement, processElement2, endElement, line1, line2, line3, line4, line5];
1650
+ };
1076
1651
 
1077
1652
  const drawLineArrow = (element, points, options) => {
1078
1653
  const arrowG = createG();
@@ -1112,11 +1687,11 @@ const getArrow = (element, arrowOptions, options) => {
1112
1687
  break;
1113
1688
  }
1114
1689
  case LineMarkerType.oneSideUp: {
1115
- targetArrow = drawOneSideArrow(source, target, 'up', options);
1690
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'down' : 'up', options);
1116
1691
  break;
1117
1692
  }
1118
1693
  case LineMarkerType.oneSideDown: {
1119
- targetArrow = drawOneSideArrow(source, target, 'down', options);
1694
+ targetArrow = drawOneSideArrow(source, target, isSource ? 'up' : 'down', options);
1120
1695
  break;
1121
1696
  }
1122
1697
  case LineMarkerType.hollowTriangle: {
@@ -1183,13 +1758,13 @@ const drawHollowTriangleArrow = (source, target, options) => {
1183
1758
  return drawLinearPath([pointLeft, pointRight, target], { ...options, fill: 'white' }, true);
1184
1759
  };
1185
1760
 
1186
- const createLineElement = (shape, points, source, target, options) => {
1761
+ const createLineElement = (shape, points, source, target, texts, options) => {
1187
1762
  return {
1188
1763
  id: idCreator(),
1189
1764
  type: 'line',
1190
1765
  shape,
1191
1766
  source,
1192
- texts: [],
1767
+ texts: texts ? texts : [],
1193
1768
  target,
1194
1769
  opacity: 1,
1195
1770
  points,
@@ -1260,8 +1835,41 @@ const getLineHandleRefPair = (board, element) => {
1260
1835
  const getElbowPoints = (board, element) => {
1261
1836
  if (element.points.length === 2) {
1262
1837
  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);
1838
+ const offset = element.source.boundId || element.target.boundId ? DEFAULT_ROUTE_MARGIN : 0;
1839
+ const sourceElement = element.source.boundId && getElementById(board, element.source.boundId);
1840
+ const targetElement = element.target.boundId && getElementById(board, element.target.boundId);
1841
+ const isBound = sourceElement && targetElement;
1842
+ let points = [];
1843
+ if (isBound) {
1844
+ const targetRectangle = RectangleClient.inflate(getRectangleByPoints(targetElement.points), getStrokeWidthByElement(targetElement) * 2);
1845
+ const sourceRectangle = RectangleClient.inflate(getRectangleByPoints(sourceElement.points), getStrokeWidthByElement(sourceElement) * 2);
1846
+ const sourcePoint = handleRefPair.source.point;
1847
+ const targetPoint = handleRefPair.target.point;
1848
+ const { sourceOffset, targetOffset } = reduceRouteMargin(sourceRectangle, targetRectangle);
1849
+ const sourceOuterRectangle = RectangleClient.expand(sourceRectangle, sourceOffset[3], sourceOffset[0], sourceOffset[1], sourceOffset[2]);
1850
+ const targetOuterRectangle = RectangleClient.expand(targetRectangle, targetOffset[3], targetOffset[0], targetOffset[1], targetOffset[2]);
1851
+ const nextSourcePoint = getNextPoint(sourcePoint, sourceOuterRectangle, handleRefPair.source.direction);
1852
+ const nextTargetPoint = getNextPoint(targetPoint, targetOuterRectangle, handleRefPair.target.direction);
1853
+ const isIntersect = RectangleClient.isPointInRectangle(targetRectangle, sourcePoint) ||
1854
+ RectangleClient.isPointInRectangle(targetOuterRectangle, nextSourcePoint) ||
1855
+ RectangleClient.isPointInRectangle(sourceOuterRectangle, nextTargetPoint) ||
1856
+ RectangleClient.isPointInRectangle(sourceRectangle, targetPoint);
1857
+ if (!isIntersect) {
1858
+ points = generateElbowLineRoute({
1859
+ sourcePoint,
1860
+ nextSourcePoint,
1861
+ sourceRectangle,
1862
+ sourceOuterRectangle,
1863
+ targetPoint,
1864
+ nextTargetPoint,
1865
+ targetRectangle,
1866
+ targetOuterRectangle
1867
+ });
1868
+ }
1869
+ }
1870
+ if (!points.length) {
1871
+ points = getPoints(handleRefPair.source.point, handleRefPair.source.direction, handleRefPair.target.point, handleRefPair.target.direction, offset);
1872
+ }
1265
1873
  points = removeDuplicatePoints(points);
1266
1874
  return points;
1267
1875
  }
@@ -1434,17 +2042,6 @@ const getBoardLines = (board) => {
1434
2042
  recursion: (element) => PlaitDrawElement.isDrawElement(element)
1435
2043
  });
1436
2044
  };
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
2045
  const getExtendPoint = (source, target, extendDistance) => {
1449
2046
  const distance = distanceBetweenPointAndPoint(...source, ...target);
1450
2047
  const sin = (target[1] - source[1]) / distance;
@@ -1510,6 +2107,55 @@ const getSelectedImageElements = (board) => {
1510
2107
  return selectedElements;
1511
2108
  };
1512
2109
 
2110
+ const isRectangleHitDrawElement = (board, element, selection) => {
2111
+ if (PlaitDrawElement.isGeometry(element)) {
2112
+ const client = getRectangleByPoints(element.points);
2113
+ const rangeRectangle = RectangleClient.toRectangleClient([selection.anchor, selection.focus]);
2114
+ if (element.textHeight > client.height) {
2115
+ const textClient = getTextRectangle(element);
2116
+ return RectangleClient.isHit(rangeRectangle, client) || RectangleClient.isHit(rangeRectangle, textClient);
2117
+ }
2118
+ return RectangleClient.isHit(rangeRectangle, client);
2119
+ }
2120
+ if (PlaitDrawElement.isImage(element)) {
2121
+ const client = getRectangleByPoints(element.points);
2122
+ const rangeRectangle = RectangleClient.toRectangleClient([selection.anchor, selection.focus]);
2123
+ return RectangleClient.isHit(rangeRectangle, client);
2124
+ }
2125
+ if (PlaitDrawElement.isLine(element)) {
2126
+ const points = getLinePoints(board, element);
2127
+ const strokeWidth = getStrokeWidthByElement(element);
2128
+ const isHitText = isHitLineText(board, element, selection.focus);
2129
+ const isHit = isHitPolyLine(points, selection.focus, strokeWidth, 3) || isHitText;
2130
+ const rangeRectangle = RectangleClient.toRectangleClient([selection.anchor, selection.focus]);
2131
+ const isContainPolyLinePoint = points.some(point => {
2132
+ return RectangleClient.isHit(rangeRectangle, RectangleClient.toRectangleClient([point, point]));
2133
+ });
2134
+ const isIntersect = Point.isEquals(selection.anchor, selection.focus) ? isHit : isPolylineHitRectangle(points, rangeRectangle);
2135
+ return isContainPolyLinePoint || isIntersect;
2136
+ }
2137
+ return null;
2138
+ };
2139
+ const isHitDrawElement = (board, element, point) => {
2140
+ if (PlaitDrawElement.isGeometry(element)) {
2141
+ const fill = getFillByElement(element);
2142
+ if (fill !== DefaultGeometryStyle.fill) {
2143
+ return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
2144
+ }
2145
+ else {
2146
+ const strokeWidth = getStrokeWidthByElement(element);
2147
+ const engine = getEngine(getShape(element));
2148
+ const corners = engine.getCornerPoints(getRectangleByPoints(element.points));
2149
+ const isHit = isHitPolyLine(corners, point, strokeWidth, 3);
2150
+ return isHit;
2151
+ }
2152
+ }
2153
+ if (PlaitDrawElement.isImage(element) || PlaitDrawElement.isLine(element)) {
2154
+ return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
2155
+ }
2156
+ return null;
2157
+ };
2158
+
1513
2159
  var LineMarkerType;
1514
2160
  (function (LineMarkerType) {
1515
2161
  LineMarkerType["arrow"] = "arrow";
@@ -1562,208 +2208,59 @@ const PlaitLine = {
1562
2208
  return PlaitLine.isSourceMarkOrTargetMark(line, markType, LineHandleKey.target);
1563
2209
  },
1564
2210
  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
- };
1613
-
1614
- class GeometryShapeGenerator extends Generator {
1615
- canDraw(element, data) {
1616
- return true;
1617
- }
1618
- baseDraw(element, data) {
1619
- const rectangle = getRectangleByPoints(element.points);
1620
- const shape = element.shape;
1621
- if (shape === GeometryShape.text) {
1622
- return;
1623
- }
1624
- const strokeWidth = getStrokeWidthByElement(element);
1625
- const strokeColor = getStrokeColorByElement(element);
1626
- const fill = getFillByElement(element);
1627
- const strokeLineDash = getLineDashByElement(element);
1628
- return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
1629
- stroke: strokeColor,
1630
- strokeWidth,
1631
- fill,
1632
- strokeLineDash
1633
- });
1634
- }
1635
- }
1636
-
1637
- const insertGeometry = (board, points, shape) => {
1638
- let newElement = createGeometryElement(shape, points, '', {
1639
- strokeColor: DefaultGeometryProperty.strokeColor,
1640
- strokeWidth: DefaultGeometryProperty.strokeWidth
1641
- });
1642
- Transforms.insertNode(board, newElement, [board.children.length]);
1643
- clearSelectedElement(board);
1644
- addSelectedElement(board, newElement);
1645
- };
1646
- const insertText = (board, points, text = '文本') => {
1647
- let newElement = createGeometryElement(GeometryShape.text, points, text);
1648
- Transforms.insertNode(board, newElement, [board.children.length]);
1649
- clearSelectedElement(board);
1650
- addSelectedElement(board, newElement);
1651
- };
1652
- const resizeGeometry = (board, points, textHeight, path) => {
1653
- const normalizePoints = normalizeShapePoints(points);
1654
- const element = PlaitNode.get(board, path);
1655
- const newHeight = textHeight / board.viewport.zoom;
1656
- const newProperties = { points: normalizePoints, textHeight: newHeight };
1657
- if (PlaitDrawElement.isText(element) && element.autoSize) {
1658
- newProperties.autoSize = false;
1659
- }
1660
- Transforms.setNode(board, newProperties, path);
1661
- };
1662
-
1663
- const normalizePoints = (board, element, width, textHeight) => {
1664
- let points = element.points;
1665
- let autoSize = element.autoSize;
1666
- const defaultSpace = ShapeDefaultSpace.rectangleAndText;
1667
- if (autoSize) {
1668
- const editor = PlaitGeometry.getTextEditor(element);
1669
- if (AlignEditor.isActive(editor, Alignment.right)) {
1670
- points = [
1671
- [points[1][0] - (width + defaultSpace * 2), points[0][1]],
1672
- [points[1][0], points[0][1] + textHeight]
1673
- ];
1674
- }
1675
- else if (AlignEditor.isActive(editor, Alignment.center)) {
1676
- const oldWidth = Math.abs(points[0][0] - points[1][0]);
1677
- const offset = (width - oldWidth) / 2;
1678
- points = [
1679
- [points[0][0] - offset - defaultSpace, points[0][1]],
1680
- [points[1][0] + offset + defaultSpace, points[0][1] + textHeight]
1681
- ];
1682
- }
1683
- else {
1684
- points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
1685
- }
1686
- }
1687
- return { points };
1688
- };
1689
- const setText = (board, element, text, width, textHeight) => {
1690
- const newElement = {
1691
- text,
1692
- textHeight,
1693
- ...normalizePoints(board, element, width, textHeight)
1694
- };
1695
- const path = board.children.findIndex(child => child === element);
1696
- Transforms.setNode(board, newElement, [path]);
1697
- };
1698
- const setTextSize = (board, element, textWidth, textHeight) => {
1699
- if (element.autoSize) {
1700
- const newElement = {
1701
- textHeight,
1702
- ...normalizePoints(board, element, textWidth, textHeight)
1703
- };
1704
- const isPointsEqual = Point.isEquals(element.points[0], newElement.points[0]) && Point.isEquals(element.points[1], newElement.points[1]);
1705
- const isTextHeightEqual = Math.round(textHeight) === Math.round(element.textHeight);
1706
- if (!isPointsEqual || !isTextHeightEqual) {
1707
- const path = board.children.findIndex(child => child === element);
1708
- Transforms.setNode(board, newElement, [path]);
1709
- }
2211
+ return line.source.boundId === element.id;
2212
+ },
2213
+ isBoundElementOfTarget(line, element) {
2214
+ return line.target.boundId === element.id;
2215
+ },
2216
+ getPoints(board, line) {
2217
+ let sourcePoint = line.source.boundId
2218
+ ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
2219
+ : line.points[0];
2220
+ let targetPoint = line.target.boundId
2221
+ ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
2222
+ : line.points[line.points.length - 1];
2223
+ const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
2224
+ return [sourcePoint, ...restPoints, targetPoint];
1710
2225
  }
1711
2226
  };
1712
2227
 
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
-
1735
- const resizeLine = (board, options, path) => {
1736
- Transforms.setNode(board, options, path);
1737
- };
1738
- const setLineTexts = (board, element, texts) => {
1739
- const path = PlaitBoard.findPath(board, element);
1740
- Transforms.setNode(board, { texts }, path);
1741
- };
1742
- const removeLineText = (board, element, index) => {
1743
- const path = PlaitBoard.findPath(board, element);
1744
- const texts = element.texts?.length ? [...element.texts] : [];
1745
- const newTexts = [...texts];
1746
- newTexts.splice(index, 1);
1747
- Transforms.setNode(board, { texts: newTexts }, path);
1748
- };
1749
- const setLineMark = (board, element, handleKey, marker) => {
1750
- const path = PlaitBoard.findPath(board, element);
1751
- let handle = handleKey === LineHandleKey.source ? element.source : element.target;
1752
- handle = { ...handle, marker };
1753
- Transforms.setNode(board, { [handleKey]: handle }, path);
1754
- };
2228
+ var StrokeStyle;
2229
+ (function (StrokeStyle) {
2230
+ StrokeStyle["solid"] = "solid";
2231
+ StrokeStyle["dashed"] = "dashed";
2232
+ })(StrokeStyle || (StrokeStyle = {}));
1755
2233
 
1756
- const DrawTransforms = {
1757
- setText,
1758
- insertGeometry,
1759
- resizeGeometry,
1760
- insertText,
1761
- setTextSize,
1762
- resizeLine,
1763
- setLineTexts,
1764
- removeLineText,
1765
- setLineMark,
1766
- insertImage
2234
+ const PlaitDrawElement = {
2235
+ isGeometry: (value) => {
2236
+ return value.type === 'geometry';
2237
+ },
2238
+ isLine: (value) => {
2239
+ return value.type === 'line';
2240
+ },
2241
+ isText: (value) => {
2242
+ return value.type === 'geometry' && value.shape === BasicShapes.text;
2243
+ },
2244
+ isImage: (value) => {
2245
+ return value.type === 'image';
2246
+ },
2247
+ isDrawElement: (value) => {
2248
+ if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value) || PlaitDrawElement.isImage(value)) {
2249
+ return true;
2250
+ }
2251
+ else {
2252
+ return false;
2253
+ }
2254
+ },
2255
+ isShape: (value) => {
2256
+ return PlaitDrawElement.isImage(value) || PlaitDrawElement.isGeometry(value);
2257
+ },
2258
+ isBaseShape: (value) => {
2259
+ return Object.keys(BasicShapes).includes(value.type);
2260
+ },
2261
+ isFlowchart: (value) => {
2262
+ return Object.keys(FlowchartSymbols).includes(value.type);
2263
+ }
1767
2264
  };
1768
2265
 
1769
2266
  class GeometryComponent extends CommonPluginElement {
@@ -1864,7 +2361,11 @@ class GeometryComponent extends CommonPluginElement {
1864
2361
  }
1865
2362
  },
1866
2363
  getMaxWidth: () => {
1867
- const width = getTextRectangle(this.element).width;
2364
+ let width = getTextRectangle(this.element).width;
2365
+ const getRectangle = getEngine(this.element.shape).getTextRectangle;
2366
+ if (getRectangle) {
2367
+ width = getRectangle(this.element).width;
2368
+ }
1868
2369
  return this.element?.autoSize ? GeometryThreshold.defaultTextMaxWidth : width;
1869
2370
  },
1870
2371
  textPlugins: plugins
@@ -1877,10 +2378,10 @@ class GeometryComponent extends CommonPluginElement {
1877
2378
  this.destroy$.next();
1878
2379
  this.destroy$.complete();
1879
2380
  }
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 }); }
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 }); }
2381
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GeometryComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2382
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: GeometryComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1882
2383
  }
1883
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: GeometryComponent, decorators: [{
2384
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GeometryComponent, decorators: [{
1884
2385
  type: Component,
1885
2386
  args: [{
1886
2387
  selector: 'plait-draw-geometry',
@@ -2118,10 +2619,10 @@ class LineComponent extends PlaitPluginElementComponent {
2118
2619
  this.destroy$.next();
2119
2620
  this.destroy$.complete();
2120
2621
  }
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 }); }
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 }); }
2622
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LineComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2623
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LineComponent, isStandalone: true, selector: "plait-draw-line", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2123
2624
  }
2124
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: LineComponent, decorators: [{
2625
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LineComponent, decorators: [{
2125
2626
  type: Component,
2126
2627
  args: [{
2127
2628
  selector: 'plait-draw-line',
@@ -2160,160 +2661,6 @@ const withDrawHotkey = (board) => {
2160
2661
  return board;
2161
2662
  };
2162
2663
 
2163
- const withGeometryCreateByDrag = (board) => {
2164
- const { pointerMove, pointerUp } = board;
2165
- let geometryShapeG = null;
2166
- board.pointerMove = (event) => {
2167
- geometryShapeG?.remove();
2168
- geometryShapeG = createG();
2169
- const geometryGenerator = new GeometryShapeGenerator(board);
2170
- const geometryPointers = getGeometryPointers();
2171
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2172
- const dragMode = isGeometryPointer && isDndMode(board);
2173
- const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2174
- const pointer = PlaitBoard.getPointer(board);
2175
- if (dragMode) {
2176
- const points = getDefaultGeometryPoints(pointer, movingPoint);
2177
- if (pointer === GeometryShape.text) {
2178
- const textG = getTemporaryTextG(movingPoint);
2179
- geometryShapeG.appendChild(textG);
2180
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2181
- }
2182
- else {
2183
- const temporaryElement = createGeometryElement(pointer, points, '', {
2184
- strokeColor: DefaultGeometryProperty.strokeColor,
2185
- strokeWidth: DefaultGeometryProperty.strokeWidth
2186
- });
2187
- geometryGenerator.draw(temporaryElement, geometryShapeG);
2188
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2189
- }
2190
- }
2191
- pointerMove(event);
2192
- };
2193
- board.pointerUp = (event) => {
2194
- const pointer = PlaitBoard.getPointer(board);
2195
- const geometryPointers = getGeometryPointers();
2196
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2197
- const dragMode = isGeometryPointer && isDndMode(board);
2198
- if (dragMode) {
2199
- const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2200
- const points = getDefaultGeometryPoints(pointer, targetPoint);
2201
- if (pointer === GeometryShape.text) {
2202
- DrawTransforms.insertText(board, points);
2203
- }
2204
- else {
2205
- DrawTransforms.insertGeometry(board, points, pointer);
2206
- }
2207
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2208
- }
2209
- geometryShapeG?.remove();
2210
- geometryShapeG = null;
2211
- preventTouchMove(board, event, false);
2212
- pointerUp(event);
2213
- };
2214
- return board;
2215
- };
2216
- const withGeometryCreateByDrawing = (board) => {
2217
- const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
2218
- let start = null;
2219
- let geometryShapeG = null;
2220
- let temporaryElement = null;
2221
- let isShift = false;
2222
- board.keydown = (event) => {
2223
- isShift = isKeyHotkey('shift', event);
2224
- keydown(event);
2225
- };
2226
- board.keyup = (event) => {
2227
- isShift = false;
2228
- keyup(event);
2229
- };
2230
- board.pointerDown = (event) => {
2231
- const geometryPointers = getGeometryPointers();
2232
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
2233
- if (isGeometryPointer && isDrawingMode(board)) {
2234
- const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2235
- start = point;
2236
- const pointer = PlaitBoard.getPointer(board);
2237
- preventTouchMove(board, event, true);
2238
- if (pointer === GeometryShape.text) {
2239
- const points = getDefaultGeometryPoints(pointer, point);
2240
- const textElement = createGeometryElement(GeometryShape.text, points, DefaultTextProperty.text);
2241
- Transforms.insertNode(board, textElement, [board.children.length]);
2242
- clearSelectedElement(board);
2243
- addSelectedElement(board, textElement);
2244
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2245
- start = null;
2246
- }
2247
- }
2248
- pointerDown(event);
2249
- };
2250
- board.pointerMove = (event) => {
2251
- geometryShapeG?.remove();
2252
- geometryShapeG = createG();
2253
- const geometryGenerator = new GeometryShapeGenerator(board);
2254
- const drawMode = !!start;
2255
- const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2256
- const pointer = PlaitBoard.getPointer(board);
2257
- if (drawMode && pointer !== GeometryShape.text) {
2258
- const points = normalizeShapePoints([start, movingPoint], isShift);
2259
- temporaryElement = createGeometryElement(pointer, points, '', {
2260
- strokeColor: DefaultGeometryProperty.strokeColor,
2261
- strokeWidth: DefaultGeometryProperty.strokeWidth
2262
- });
2263
- geometryGenerator.draw(temporaryElement, geometryShapeG);
2264
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
2265
- }
2266
- pointerMove(event);
2267
- };
2268
- board.pointerUp = (event) => {
2269
- const isDrawMode = !!start;
2270
- if (isDrawMode) {
2271
- const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2272
- const { width, height } = RectangleClient.toRectangleClient([start, targetPoint]);
2273
- if (Math.hypot(width, height) === 0) {
2274
- const pointer = PlaitBoard.getPointer(board);
2275
- const points = getDefaultGeometryPoints(pointer, targetPoint);
2276
- if (pointer !== GeometryShape.text) {
2277
- temporaryElement = createGeometryElement(pointer, points, '', {
2278
- strokeColor: DefaultGeometryProperty.strokeColor,
2279
- strokeWidth: DefaultGeometryProperty.strokeWidth
2280
- });
2281
- }
2282
- }
2283
- }
2284
- if (temporaryElement) {
2285
- Transforms.insertNode(board, temporaryElement, [board.children.length]);
2286
- clearSelectedElement(board);
2287
- addSelectedElement(board, temporaryElement);
2288
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
2289
- }
2290
- geometryShapeG?.remove();
2291
- geometryShapeG = null;
2292
- start = null;
2293
- temporaryElement = null;
2294
- preventTouchMove(board, event, false);
2295
- pointerUp(event);
2296
- };
2297
- return board;
2298
- };
2299
- const getDefaultGeometryPoints = (pointer, targetPoint) => {
2300
- return pointer === GeometryShape.text
2301
- ? getPointsByCenterPoint(targetPoint, DefaultTextProperty.width, DefaultTextProperty.height)
2302
- : getPointsByCenterPoint(targetPoint, DefaultGeometryProperty.width, DefaultGeometryProperty.height);
2303
- };
2304
- const getTemporaryTextG = (movingPoint) => {
2305
- const textG = createG();
2306
- const width = DefaultTextProperty.width - ShapeDefaultSpace.rectangleAndText * 2;
2307
- const foreignObject = createForeignObject(movingPoint[0] - width / 2, movingPoint[1] - DefaultTextProperty.height / 2, width, DefaultTextProperty.height);
2308
- const richtext = document.createElement('div');
2309
- richtext.textContent = DefaultTextProperty.text;
2310
- richtext.style.fontSize = `${DEFAULT_FONT_SIZE}px`;
2311
- richtext.style.cursor = 'default';
2312
- foreignObject.appendChild(richtext);
2313
- textG.appendChild(foreignObject);
2314
- return textG;
2315
- };
2316
-
2317
2664
  const buildClipboardData = (board, elements, startPoint) => {
2318
2665
  return elements.map(element => {
2319
2666
  if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
@@ -2404,13 +2751,13 @@ const withDrawFragment = (baseBoard) => {
2404
2751
  };
2405
2752
  board.insertFragment = (data, targetPoint) => {
2406
2753
  const elements = getDataFromClipboard(data);
2754
+ const selectedElements = getSelectedElements(board);
2407
2755
  const drawElements = elements.filter(value => PlaitDrawElement.isDrawElement(value));
2408
2756
  if (elements.length > 0 && drawElements.length > 0) {
2409
2757
  insertClipboardData(board, drawElements, targetPoint);
2410
2758
  }
2411
2759
  else if (elements.length === 0) {
2412
2760
  const text = getTextFromClipboard(data);
2413
- const selectedElements = getSelectedElements(board);
2414
2761
  // (* ̄︶ ̄)
2415
2762
  const insertAsChildren = selectedElements.length === 1 && selectedElements[0].children;
2416
2763
  const insertAsFreeText = !insertAsChildren;
@@ -2422,7 +2769,8 @@ const withDrawFragment = (baseBoard) => {
2422
2769
  }
2423
2770
  if (data?.files.length) {
2424
2771
  const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
2425
- if (acceptImageArray.includes(data?.files[0].type)) {
2772
+ const canInsertionImage = !getElementOfFocusedImage(board) && !(selectedElements.length === 1 && board.isImageBindingAllowed(selectedElements[0]));
2773
+ if (acceptImageArray.includes(data?.files[0].type) && canInsertionImage) {
2426
2774
  const imageFile = data.files[0];
2427
2775
  buildImage(board, imageFile, DEFAULT_IMAGE_WIDTH, imageItem => {
2428
2776
  DrawTransforms.insertImage(board, imageItem, targetPoint);
@@ -2439,11 +2787,6 @@ const getBoundedLineElements = (board, plaitShapes) => {
2439
2787
  return lines.filter(line => plaitShapes.find(shape => PlaitLine.isBoundElementOfSource(line, shape) || PlaitLine.isBoundElementOfTarget(line, shape)));
2440
2788
  };
2441
2789
 
2442
- const DefaultLineStyle = {
2443
- strokeWidth: 2,
2444
- strokeColor: '#000'
2445
- };
2446
-
2447
2790
  const getHitGeometryResizeHandleRef = (board, element, point) => {
2448
2791
  const rectangle = getRectangleByPoints(element.points);
2449
2792
  const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER);
@@ -2500,7 +2843,7 @@ const withLineCreateByDraw = (board) => {
2500
2843
  targetRef.boundId = hitElement ? hitElement.id : undefined;
2501
2844
  const lineGenerator = new LineShapeGenerator(board);
2502
2845
  const lineShape = PlaitBoard.getPointer(board);
2503
- temporaryElement = createLineElement(lineShape, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, {
2846
+ temporaryElement = createLineElement(lineShape, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, [], {
2504
2847
  strokeColor: DefaultLineStyle.strokeColor,
2505
2848
  strokeWidth: DefaultLineStyle.strokeWidth
2506
2849
  });
@@ -2739,9 +3082,9 @@ const withLineText = (board) => {
2739
3082
  const { dblclick } = board;
2740
3083
  board.dblclick = (event) => {
2741
3084
  const clickPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2742
- const hitTarget = getHitElements(board, { ranges: [{ anchor: clickPoint, focus: clickPoint }] }, (element) => {
3085
+ const hitTarget = getHitElementByPoint(board, clickPoint, (element) => {
2743
3086
  return PlaitDrawElement.isLine(element);
2744
- })[0];
3087
+ });
2745
3088
  if (hitTarget) {
2746
3089
  const points = getLinePoints(board, hitTarget);
2747
3090
  const point = getNearestPointBetweenPointAndSegments(clickPoint, points);
@@ -2836,10 +3179,10 @@ class ImageComponent extends CommonPluginElement {
2836
3179
  this.destroy$.complete();
2837
3180
  this.imageGenerator.destroy();
2838
3181
  }
2839
- 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 }); }
2840
- 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 }); }
3182
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3183
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ImageComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2841
3184
  }
2842
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: ImageComponent, decorators: [{
3185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageComponent, decorators: [{
2843
3186
  type: Component,
2844
3187
  args: [{
2845
3188
  selector: 'plait-draw-geometry',
@@ -2850,7 +3193,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
2850
3193
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
2851
3194
 
2852
3195
  const withDraw = (board) => {
2853
- const { drawElement, getRectangle, isHitSelection, isMovable, isAlign } = board;
3196
+ const { drawElement, getRectangle, isRectangleHit, isHit, isMovable, isAlign } = board;
2854
3197
  board.drawElement = (context) => {
2855
3198
  if (PlaitDrawElement.isGeometry(context.element)) {
2856
3199
  return GeometryComponent;
@@ -2876,34 +3219,19 @@ const withDraw = (board) => {
2876
3219
  }
2877
3220
  return getRectangle(element);
2878
3221
  };
2879
- board.isHitSelection = (element, range) => {
2880
- if (PlaitDrawElement.isGeometry(element)) {
2881
- const client = getRectangleByPoints(element.points);
2882
- const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
2883
- if (element.textHeight > client.height) {
2884
- const textClient = getTextRectangle(element);
2885
- return RectangleClient.isHit(rangeRectangle, client) || RectangleClient.isHit(rangeRectangle, textClient);
2886
- }
2887
- return RectangleClient.isHit(rangeRectangle, client);
2888
- }
2889
- if (PlaitDrawElement.isImage(element)) {
2890
- const client = getRectangleByPoints(element.points);
2891
- const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
2892
- return RectangleClient.isHit(rangeRectangle, client);
3222
+ board.isRectangleHit = (element, selection) => {
3223
+ const result = isRectangleHitDrawElement(board, element, selection);
3224
+ if (result !== null) {
3225
+ return result;
2893
3226
  }
2894
- if (PlaitDrawElement.isLine(element)) {
2895
- const points = getLinePoints(board, element);
2896
- const strokeWidth = getStrokeWidthByElement(element);
2897
- const isHitText = isHitLineText(board, element, range.focus);
2898
- const isHit = isHitPolyLine(points, range.focus, strokeWidth, 3) || isHitText;
2899
- const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
2900
- const isContainPolyLinePoint = points.some(point => {
2901
- return RectangleClient.isHit(rangeRectangle, RectangleClient.toRectangleClient([point, point]));
2902
- });
2903
- const isIntersect = range.anchor === range.focus ? isHit : isPolylineHitRectangle(points, rangeRectangle);
2904
- return isContainPolyLinePoint || isIntersect;
3227
+ return isRectangleHit(element, selection);
3228
+ };
3229
+ board.isHit = (element, point) => {
3230
+ const result = isHitDrawElement(board, element, point);
3231
+ if (result !== null) {
3232
+ return result;
2905
3233
  }
2906
- return isHitSelection(element, range);
3234
+ return isHit(element, point);
2907
3235
  };
2908
3236
  board.isMovable = (element) => {
2909
3237
  if (PlaitDrawElement.isGeometry(element)) {
@@ -2938,5 +3266,5 @@ const withDraw = (board) => {
2938
3266
  * Generated bundle index. Do not edit.
2939
3267
  */
2940
3268
 
2941
- 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 };
3269
+ export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LineComponent, LineHandleKey, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, createDefaultFlowchart, createGeometryElement, createLineElement, drawBoundMask, drawGeometry, drawLine, getBasicPointers, getBoardLines, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getEdgeOnPolygonByPoint, getElbowPoints, getExtendPoint, getFillByElement, getFlowchartPointers, getGeometryPointers, getHitConnectorPoint, getHitLineTextIndex, getLineDashByElement, getLineHandleRefPair, getLinePointers, getLinePoints, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getVectorByConnection, isHitDrawElement, isHitLineText, isHitPolyLine, isRectangleHitDrawElement, transformOpsToPoints, transformPointToConnection, withDraw };
2942
3270
  //# sourceMappingURL=plait-draw.mjs.map