@plait/draw 0.1.0-next.3

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 (91) hide show
  1. package/README.md +3 -0
  2. package/constants/geometry.d.ts +27 -0
  3. package/constants/index.d.ts +2 -0
  4. package/constants/line.d.ts +4 -0
  5. package/constants/pointer.d.ts +10 -0
  6. package/esm2022/constants/geometry.mjs +28 -0
  7. package/esm2022/constants/index.mjs +3 -0
  8. package/esm2022/constants/line.mjs +5 -0
  9. package/esm2022/constants/pointer.mjs +19 -0
  10. package/esm2022/generator/geometry-shape.generator.mjs +22 -0
  11. package/esm2022/generator/line-active.generator.mjs +36 -0
  12. package/esm2022/generator/line.generator.mjs +43 -0
  13. package/esm2022/geometry.component.mjs +118 -0
  14. package/esm2022/interfaces/geometry.mjs +20 -0
  15. package/esm2022/interfaces/index.mjs +24 -0
  16. package/esm2022/interfaces/line.mjs +12 -0
  17. package/esm2022/interfaces/text.mjs +2 -0
  18. package/esm2022/line.component.mjs +152 -0
  19. package/esm2022/plait-draw.mjs +5 -0
  20. package/esm2022/plugins/with-draw-fragment.mjs +51 -0
  21. package/esm2022/plugins/with-draw-hotkey.mjs +19 -0
  22. package/esm2022/plugins/with-draw.mjs +76 -0
  23. package/esm2022/plugins/with-geometry-create.mjs +164 -0
  24. package/esm2022/plugins/with-geometry-resize.mjs +71 -0
  25. package/esm2022/plugins/with-line-bound-reaction.mjs +45 -0
  26. package/esm2022/plugins/with-line-create.mjs +66 -0
  27. package/esm2022/plugins/with-line-resize.mjs +52 -0
  28. package/esm2022/plugins/with-line-text.mjs +55 -0
  29. package/esm2022/public-api.mjs +5 -0
  30. package/esm2022/transforms/geometry-text.mjs +54 -0
  31. package/esm2022/transforms/geometry.mjs +31 -0
  32. package/esm2022/transforms/index.mjs +14 -0
  33. package/esm2022/transforms/line.mjs +16 -0
  34. package/esm2022/utils/clipboard.mjs +23 -0
  35. package/esm2022/utils/create-mode.mjs +13 -0
  36. package/esm2022/utils/engine/diamond.mjs +20 -0
  37. package/esm2022/utils/engine/ellipse.mjs +55 -0
  38. package/esm2022/utils/engine/index.mjs +18 -0
  39. package/esm2022/utils/engine/parallelogram.mjs +30 -0
  40. package/esm2022/utils/engine/rectangle.mjs +18 -0
  41. package/esm2022/utils/engine/round-rectangle.mjs +49 -0
  42. package/esm2022/utils/geometry-style/stroke.mjs +17 -0
  43. package/esm2022/utils/geometry.mjs +84 -0
  44. package/esm2022/utils/index.mjs +5 -0
  45. package/esm2022/utils/line.mjs +145 -0
  46. package/esm2022/utils/position/geometry.mjs +28 -0
  47. package/esm2022/utils/position/line.mjs +34 -0
  48. package/esm2022/utils/selected.mjs +15 -0
  49. package/fesm2022/plait-draw.mjs +1602 -0
  50. package/fesm2022/plait-draw.mjs.map +1 -0
  51. package/generator/geometry-shape.generator.d.ts +8 -0
  52. package/generator/line-active.generator.d.ts +9 -0
  53. package/generator/line.generator.d.ts +8 -0
  54. package/geometry.component.d.ts +27 -0
  55. package/index.d.ts +5 -0
  56. package/interfaces/geometry.d.ts +43 -0
  57. package/interfaces/index.d.ts +13 -0
  58. package/interfaces/line.d.ts +44 -0
  59. package/interfaces/text.d.ts +5 -0
  60. package/line.component.d.ts +36 -0
  61. package/package.json +25 -0
  62. package/plugins/with-draw-fragment.d.ts +2 -0
  63. package/plugins/with-draw-hotkey.d.ts +2 -0
  64. package/plugins/with-draw.d.ts +2 -0
  65. package/plugins/with-geometry-create.d.ts +3 -0
  66. package/plugins/with-geometry-resize.d.ts +2 -0
  67. package/plugins/with-line-bound-reaction.d.ts +2 -0
  68. package/plugins/with-line-create.d.ts +2 -0
  69. package/plugins/with-line-resize.d.ts +2 -0
  70. package/plugins/with-line-text.d.ts +2 -0
  71. package/public-api.d.ts +4 -0
  72. package/styles/styles.scss +16 -0
  73. package/transforms/geometry-text.d.ts +5 -0
  74. package/transforms/geometry.d.ts +6 -0
  75. package/transforms/index.d.ts +10 -0
  76. package/transforms/line.d.ts +5 -0
  77. package/utils/clipboard.d.ts +4 -0
  78. package/utils/create-mode.d.ts +7 -0
  79. package/utils/engine/diamond.d.ts +2 -0
  80. package/utils/engine/ellipse.d.ts +4 -0
  81. package/utils/engine/index.d.ts +3 -0
  82. package/utils/engine/parallelogram.d.ts +4 -0
  83. package/utils/engine/rectangle.d.ts +2 -0
  84. package/utils/engine/round-rectangle.d.ts +5 -0
  85. package/utils/geometry-style/stroke.d.ts +5 -0
  86. package/utils/geometry.d.ts +16 -0
  87. package/utils/index.d.ts +4 -0
  88. package/utils/line.d.ts +16 -0
  89. package/utils/position/geometry.d.ts +13 -0
  90. package/utils/position/line.d.ts +10 -0
  91. package/utils/selected.d.ts +5 -0
@@ -0,0 +1,1602 @@
1
+ import { PlaitElement, RectangleClient, PlaitBoard, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, idCreator, createG, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, distanceBetweenPointAndSegments, arrowPoints, drawLinearPath, getElementById, getSelectedElements, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Point, PlaitPluginElementComponent, isSelectionMoving, createMask, createRect, transformPoint, toPoint, BoardTransforms, PlaitPointerType, preventTouchMove, createForeignObject, setClipboardData, getDataFromClipboard, depthFirstRecursion, getIsRecursionFunc, getHitElements, isPolylineHitRectangle } from '@plait/core';
2
+ import * as i0 from '@angular/core';
3
+ import { Component, ChangeDetectionStrategy } from '@angular/core';
4
+ import { Subject } from 'rxjs';
5
+ import { getRectangleByPoints, Direction, getDirectionByPoint, getPoints, getPointOnPolyline, Generator, normalizeShapePoints, ActiveGenerator, RESIZE_HANDLE_DIAMETER, isVirtualKey, isSpaceHotkey, CommonTransforms, getRectangleResizeHandleRefs, ResizeHandle, withResize, isResizingByCondition, getRatioByPoint } from '@plait/common';
6
+ import { Alignment, buildText, AlignEditor, TextManage, DEFAULT_FONT_SIZE, getTextFromClipboard, getTextSize } from '@plait/text';
7
+ import { isKeyHotkey } from 'is-hotkey';
8
+ import { Node } from 'slate';
9
+
10
+ var GeometryShape;
11
+ (function (GeometryShape) {
12
+ GeometryShape["rectangle"] = "rectangle";
13
+ GeometryShape["ellipse"] = "ellipse";
14
+ GeometryShape["diamond"] = "diamond";
15
+ GeometryShape["roundRectangle"] = "roundRectangle";
16
+ GeometryShape["parallelogram"] = "parallelogram";
17
+ GeometryShape["text"] = "text";
18
+ })(GeometryShape || (GeometryShape = {}));
19
+ const PlaitGeometry = {
20
+ getTextEditor(element) {
21
+ const component = PlaitElement.getComponent(element);
22
+ if (component) {
23
+ return component.textManage.componentRef.instance.editor;
24
+ }
25
+ throw new Error('can not get correctly component in get text editor');
26
+ }
27
+ };
28
+
29
+ var LineMarkerType;
30
+ (function (LineMarkerType) {
31
+ LineMarkerType["arrow"] = "arrow";
32
+ LineMarkerType["none"] = "none";
33
+ })(LineMarkerType || (LineMarkerType = {}));
34
+ var LineShape;
35
+ (function (LineShape) {
36
+ LineShape["straight"] = "straight";
37
+ LineShape["curve"] = "curve";
38
+ LineShape["elbow"] = "elbow";
39
+ })(LineShape || (LineShape = {}));
40
+
41
+ const PlaitDrawElement = {
42
+ isGeometry: (value) => {
43
+ return value.type === 'geometry';
44
+ },
45
+ isLine: (value) => {
46
+ return value.type === 'line';
47
+ },
48
+ isText: (value) => {
49
+ return value.type === 'geometry' && value.shape === GeometryShape.text;
50
+ },
51
+ isDrawElement: (value) => {
52
+ if (PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isLine(value)) {
53
+ return true;
54
+ }
55
+ else {
56
+ return false;
57
+ }
58
+ }
59
+ };
60
+
61
+ const ShapeDefaultSpace = {
62
+ rectangleAndText: 4
63
+ };
64
+ const DefaultGeometryStyle = {
65
+ strokeWidth: 2,
66
+ defaultRadius: 4,
67
+ strokeColor: '#000',
68
+ fill: 'none'
69
+ };
70
+ const DefaultGeometryActiveStyle = {
71
+ strokeWidth: 2,
72
+ selectionStrokeWidth: 1
73
+ };
74
+ const DefaultGeometryProperty = {
75
+ width: 100,
76
+ height: 100,
77
+ strokeColor: '#333',
78
+ strokeWidth: 2
79
+ };
80
+ const DefaultTextProperty = {
81
+ width: 36,
82
+ height: 20,
83
+ text: '文本'
84
+ };
85
+ const GeometryThreshold = {
86
+ defaultTextMaxWidth: 34 * 14,
87
+ };
88
+
89
+ var DrawPointerType;
90
+ (function (DrawPointerType) {
91
+ DrawPointerType["text"] = "text";
92
+ DrawPointerType["rectangle"] = "rectangle";
93
+ DrawPointerType["line"] = "line";
94
+ DrawPointerType["diamond"] = "diamond";
95
+ DrawPointerType["roundRectangle"] = "roundRectangle";
96
+ DrawPointerType["parallelogram"] = "parallelogram";
97
+ DrawPointerType["ellipse"] = "ellipse";
98
+ })(DrawPointerType || (DrawPointerType = {}));
99
+ const GeometryPointer = [
100
+ DrawPointerType.rectangle,
101
+ DrawPointerType.text,
102
+ DrawPointerType.diamond,
103
+ DrawPointerType.ellipse,
104
+ DrawPointerType.parallelogram,
105
+ DrawPointerType.roundRectangle
106
+ ];
107
+
108
+ const getStrokeWidthByElement = (element) => {
109
+ const strokeWidth = element.strokeWidth || DefaultGeometryStyle.strokeWidth;
110
+ return strokeWidth;
111
+ };
112
+ const getStrokeColorByElement = (element) => {
113
+ const strokeColor = element.strokeColor || DefaultGeometryStyle.strokeColor;
114
+ return strokeColor;
115
+ };
116
+ const getFillByElement = (element) => {
117
+ const fill = element.fill || DefaultGeometryStyle.fill;
118
+ return fill;
119
+ };
120
+ const getLineDashByElement = (element) => {
121
+ return element.strokeStyle === 'dashed' ? [8, 8 + getStrokeWidthByElement(element)] : undefined;
122
+ };
123
+
124
+ const DiamondEngine = {
125
+ draw(board, rectangle, options) {
126
+ const points = RectangleClient.getEdgeCenterPoints(rectangle);
127
+ const rs = PlaitBoard.getRoughSVG(board);
128
+ return rs.polygon(points, { ...options, fillStyle: 'solid' });
129
+ },
130
+ isHit(rectangle, point) {
131
+ const controlPoints = RectangleClient.getEdgeCenterPoints(rectangle);
132
+ return isPointInPolygon(point, controlPoints);
133
+ },
134
+ getNearestPoint(rectangle, point) {
135
+ const connectorPoints = RectangleClient.getEdgeCenterPoints(rectangle);
136
+ return getNearestPointBetweenPointAndSegments(point, connectorPoints);
137
+ },
138
+ getConnectorPoints(rectangle) {
139
+ return RectangleClient.getEdgeCenterPoints(rectangle);
140
+ }
141
+ };
142
+
143
+ const EllipseEngine = {
144
+ draw(board, rectangle, options) {
145
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
146
+ const rs = PlaitBoard.getRoughSVG(board);
147
+ return rs.ellipse(centerPoint[0], centerPoint[1], rectangle.width, rectangle.height, { ...options, fillStyle: 'solid' });
148
+ },
149
+ isHit(rectangle, point) {
150
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
151
+ return isPointInEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
152
+ },
153
+ getNearestPoint(rectangle, point) {
154
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
155
+ return getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
156
+ },
157
+ getConnectorPoints(rectangle) {
158
+ return RectangleClient.getEdgeCenterPoints(rectangle);
159
+ }
160
+ };
161
+ function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation = 0) {
162
+ const rectangleClient = {
163
+ x: center[0] - rx,
164
+ y: center[1] - ry,
165
+ height: ry * 2,
166
+ width: rx * 2
167
+ };
168
+ // https://stackoverflow.com/a/46007540/232122
169
+ const px = Math.abs(point[0] - rectangleClient.x - rectangleClient.width / 2);
170
+ const py = Math.abs(point[1] - rectangleClient.y - rectangleClient.height / 2);
171
+ let tx = 0.707;
172
+ let ty = 0.707;
173
+ const a = Math.abs(rectangleClient.width) / 2;
174
+ const b = Math.abs(rectangleClient.height) / 2;
175
+ [0, 1, 2, 3].forEach(x => {
176
+ const xx = a * tx;
177
+ const yy = b * ty;
178
+ const ex = ((a * a - b * b) * tx ** 3) / a;
179
+ const ey = ((b * b - a * a) * ty ** 3) / b;
180
+ const rx = xx - ex;
181
+ const ry = yy - ey;
182
+ const qx = px - ex;
183
+ const qy = py - ey;
184
+ const r = Math.hypot(ry, rx);
185
+ const q = Math.hypot(qy, qx);
186
+ tx = Math.min(1, Math.max(0, ((qx * r) / q + ex) / a));
187
+ ty = Math.min(1, Math.max(0, ((qy * r) / q + ey) / b));
188
+ const t = Math.hypot(ty, tx);
189
+ tx /= t;
190
+ ty /= t;
191
+ });
192
+ const signX = point[0] > center[0] ? 1 : -1;
193
+ const signY = point[1] > center[1] ? 1 : -1;
194
+ return [center[0] + a * tx * signX, center[1] + b * ty * signY];
195
+ }
196
+
197
+ const ParallelogramEngine = {
198
+ draw(board, rectangle, options) {
199
+ const points = getParallelogramPoints(rectangle);
200
+ const rs = PlaitBoard.getRoughSVG(board);
201
+ return rs.polygon(points, { ...options, fillStyle: 'solid' });
202
+ },
203
+ isHit(rectangle, point) {
204
+ const parallelogramPoints = getParallelogramPoints(rectangle);
205
+ return isPointInPolygon(point, parallelogramPoints);
206
+ },
207
+ getNearestPoint(rectangle, point) {
208
+ const cornerPoints = getParallelogramPoints(rectangle);
209
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
210
+ },
211
+ getConnectorPoints(rectangle) {
212
+ const cornerPoints = getParallelogramPoints(rectangle);
213
+ return getCenterPointsOnPolygon(cornerPoints);
214
+ }
215
+ };
216
+ const getParallelogramPoints = (rectangle) => {
217
+ return [
218
+ [rectangle.x + rectangle.width / 4, rectangle.y],
219
+ [rectangle.x + rectangle.width, rectangle.y],
220
+ [rectangle.x + (rectangle.width * 3) / 4, rectangle.y + rectangle.height],
221
+ [rectangle.x, rectangle.y + rectangle.height]
222
+ ];
223
+ };
224
+
225
+ const RectangleEngine = {
226
+ draw(board, rectangle, options) {
227
+ return drawRectangle(board, rectangle, { ...options, fillStyle: 'solid' });
228
+ },
229
+ isHit(rectangle, point) {
230
+ const rangeRectangle = RectangleClient.toRectangleClient([point, point]);
231
+ return RectangleClient.isHit(rectangle, rangeRectangle);
232
+ },
233
+ getNearestPoint(rectangle, point) {
234
+ const cornerPoints = RectangleClient.getCornerPoints(rectangle);
235
+ return getNearestPointBetweenPointAndSegments(point, cornerPoints);
236
+ },
237
+ getConnectorPoints(rectangle) {
238
+ return RectangleClient.getEdgeCenterPoints(rectangle);
239
+ }
240
+ };
241
+
242
+ const RoundRectangleEngine = {
243
+ draw(board, rectangle, options) {
244
+ return drawRoundRectangle(PlaitBoard.getRoughSVG(board), rectangle.x, rectangle.y, rectangle.x + rectangle.width, rectangle.y + rectangle.height, { ...options, fillStyle: 'solid' }, false, getRoundRectangleRadius(rectangle));
245
+ },
246
+ isHit(rectangle, point) {
247
+ return isPointInRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
248
+ },
249
+ getNearestPoint(rectangle, point) {
250
+ return getNearestPointBetweenPointAndRoundRectangle(point, rectangle, getRoundRectangleRadius(rectangle));
251
+ },
252
+ getConnectorPoints(rectangle) {
253
+ return RectangleClient.getEdgeCenterPoints(rectangle);
254
+ }
255
+ };
256
+ const getRoundRectangleRadius = (rectangle) => {
257
+ return Math.min(rectangle.width * 0.1, rectangle.height * 0.1);
258
+ };
259
+ function getNearestPointBetweenPointAndRoundRectangle(point, rectangle, radius) {
260
+ const { x: rectX, y: rectY, width, height } = rectangle;
261
+ const cornerPoints = RectangleClient.getCornerPoints(rectangle);
262
+ let result = getNearestPointBetweenPointAndSegments(point, cornerPoints);
263
+ let circleCenter = null;
264
+ const inLeftTop = point[0] >= rectX && point[0] <= rectX + radius && point[1] >= rectY && point[1] <= rectY + radius;
265
+ if (inLeftTop) {
266
+ circleCenter = [rectX + radius, rectY + radius];
267
+ }
268
+ const inLeftBottom = point[0] >= rectX && point[0] <= rectX + radius && point[1] >= rectY + height && point[1] <= rectY + height - radius;
269
+ if (inLeftBottom) {
270
+ circleCenter = [rectX + radius, rectY + height - radius];
271
+ }
272
+ const inRightTop = point[0] >= rectX + width - radius && point[0] <= rectX + width && point[1] >= rectY && point[1] <= rectY + radius;
273
+ if (inRightTop) {
274
+ circleCenter = [rectX + width - radius, rectY + radius];
275
+ }
276
+ const inRightBottom = point[0] >= rectX + width - radius &&
277
+ point[0] <= rectX + width &&
278
+ point[1] >= rectY + height - radius &&
279
+ point[1] <= rectY + height;
280
+ if (inRightBottom) {
281
+ circleCenter = [rectX + width - radius, rectY + height - radius];
282
+ }
283
+ if (circleCenter) {
284
+ result = getNearestPointBetweenPointAndEllipse(point, circleCenter, radius, radius);
285
+ }
286
+ return result;
287
+ }
288
+
289
+ const ShapeEngineMap = {
290
+ [GeometryShape.rectangle]: RectangleEngine,
291
+ [GeometryShape.diamond]: DiamondEngine,
292
+ [GeometryShape.ellipse]: EllipseEngine,
293
+ [GeometryShape.parallelogram]: ParallelogramEngine,
294
+ [GeometryShape.roundRectangle]: RoundRectangleEngine,
295
+ [GeometryShape.text]: RectangleEngine
296
+ };
297
+ const getEngine = (shape) => {
298
+ return ShapeEngineMap[shape];
299
+ };
300
+
301
+ const createGeometryElement = (shape, points, text, options) => {
302
+ let textOptions = {};
303
+ let alignment = Alignment.center;
304
+ if (shape === GeometryShape.text) {
305
+ textOptions = { autoSize: true };
306
+ alignment = undefined;
307
+ }
308
+ return {
309
+ id: idCreator(),
310
+ type: 'geometry',
311
+ shape,
312
+ angle: 0,
313
+ opacity: 1,
314
+ textHeight: DefaultTextProperty.height,
315
+ text: buildText(text, alignment),
316
+ points,
317
+ ...textOptions,
318
+ ...options
319
+ };
320
+ };
321
+ const getPointsByCenterPoint = (point, width, height) => {
322
+ const leftTopPoint = [point[0] - width / 2, point[1] - height / 2];
323
+ const rightBottomPoint = [point[0] + width / 2, point[1] + height / 2];
324
+ return [leftTopPoint, rightBottomPoint];
325
+ };
326
+ const getTextRectangle = (element) => {
327
+ const elementRectangle = getRectangleByPoints(element.points);
328
+ const height = element.textHeight;
329
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2;
330
+ return {
331
+ height,
332
+ width: width > 0 ? width : 0,
333
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText,
334
+ y: elementRectangle.y + (elementRectangle.height - height) / 2
335
+ };
336
+ };
337
+ const drawBoundMask = (board, element) => {
338
+ const G = createG();
339
+ const rectangle = getRectangleByPoints(element.points);
340
+ const offset = (getStrokeWidthByElement(element) + 1) / 2 - 0.1;
341
+ const activeRectangle = RectangleClient.getOutlineRectangle(rectangle, -offset);
342
+ const maskG = drawGeometry(board, activeRectangle, element.shape, {
343
+ stroke: SELECTION_BORDER_COLOR,
344
+ strokeWidth: 1,
345
+ fill: SELECTION_FILL_COLOR,
346
+ fillStyle: 'solid'
347
+ });
348
+ G.appendChild(maskG);
349
+ const connectorPoints = getEngine(element.shape).getConnectorPoints(activeRectangle);
350
+ connectorPoints.forEach(point => {
351
+ const circleG = drawCircle(PlaitBoard.getRoughSVG(board), point, 6, {
352
+ stroke: '#999999',
353
+ strokeWidth: 1,
354
+ fill: '#FFF',
355
+ fillStyle: 'solid'
356
+ });
357
+ G.appendChild(circleG);
358
+ });
359
+ return G;
360
+ };
361
+ const drawGeometry = (board, outerRectangle, shape, options) => {
362
+ return getEngine(shape).draw(board, outerRectangle, options);
363
+ };
364
+ const getNearestPoint = (element, point, offset = 0) => {
365
+ const rectangle = getRectangleByPoints(element.points);
366
+ const activeRectangle = RectangleClient.getOutlineRectangle(rectangle, -offset);
367
+ return getEngine(element.shape).getNearestPoint(activeRectangle, point);
368
+ };
369
+ const getCenterPointsOnPolygon = (points) => {
370
+ const centerPoint = [];
371
+ for (let i = 0; i < points.length; i++) {
372
+ let j = i == points.length - 1 ? 0 : i + 1;
373
+ centerPoint.push([(points[i][0] + points[j][0]) / 2, (points[i][1] + points[j][1]) / 2]);
374
+ }
375
+ return centerPoint;
376
+ };
377
+
378
+ const createLineElement = (shape, points, source, target, options) => {
379
+ return {
380
+ id: idCreator(),
381
+ type: 'line',
382
+ shape,
383
+ source,
384
+ texts: [],
385
+ target,
386
+ opacity: 1,
387
+ points,
388
+ ...options
389
+ };
390
+ };
391
+ const getElbowPoints = (board, element) => {
392
+ if (element.points.length === 2) {
393
+ const source = getSourcePoint(board, element);
394
+ const target = getTargetPoint(board, element);
395
+ let sourceDirection = source[0] < target[0] ? Direction.right : Direction.left;
396
+ let targetDirection = source[0] < target[0] ? Direction.left : Direction.right;
397
+ if (element.source.connection) {
398
+ sourceDirection = getDirectionByPoint(element.source.connection, sourceDirection);
399
+ }
400
+ if (element.target.connection) {
401
+ targetDirection = getDirectionByPoint(element.target.connection, targetDirection);
402
+ }
403
+ const points = getPoints(source, sourceDirection, target, targetDirection, 30);
404
+ return points;
405
+ }
406
+ return element.points;
407
+ };
408
+ const isHitPolyLine = (pathPoints, point, strokeWidth, expand = 0) => {
409
+ const distance = distanceBetweenPointAndSegments(pathPoints, point);
410
+ return distance <= strokeWidth + expand;
411
+ };
412
+ const getHitLineTextIndex = (board, element, point) => {
413
+ const texts = element.texts;
414
+ if (!texts.length)
415
+ return -1;
416
+ const points = getElbowPoints(board, element);
417
+ return texts.findIndex(text => {
418
+ const center = getPointOnPolyline(points, text.position);
419
+ const rectangle = {
420
+ x: center[0] - text.width / 2,
421
+ y: center[1] - text.height / 2,
422
+ width: text.width,
423
+ height: text.height
424
+ };
425
+ return RectangleClient.isHit(rectangle, RectangleClient.toRectangleClient([point, point]));
426
+ });
427
+ };
428
+ const isHitLineText = (board, element, point) => {
429
+ return getHitLineTextIndex(board, element, point) !== -1;
430
+ };
431
+ const drawElbowLine = (board, element) => {
432
+ const strokeWidth = getStrokeWidthByElement(element);
433
+ const strokeColor = getStrokeColorByElement(element);
434
+ const strokeLineDash = getLineDashByElement(element);
435
+ const options = { stroke: strokeColor, strokeWidth, strokeLineDash };
436
+ const lineG = createG();
437
+ const points = getElbowPoints(board, element);
438
+ const elbowLine = PlaitBoard.getRoughSVG(board).linearPath(points, options);
439
+ const path = elbowLine.querySelector('path');
440
+ path?.setAttribute('mask', `url(#${element.id})`);
441
+ lineG.appendChild(elbowLine);
442
+ const arrow = drawLineArrow(element, points, options);
443
+ arrow && lineG.appendChild(arrow);
444
+ return lineG;
445
+ };
446
+ const drawLineArrow = (element, points, options) => {
447
+ const sourceMarker = element.source.marker;
448
+ const targetMarker = element.target.marker;
449
+ const arrowG = createG();
450
+ if (sourceMarker === LineMarkerType.none && targetMarker === LineMarkerType.none)
451
+ return null;
452
+ if (sourceMarker === LineMarkerType.arrow) {
453
+ const sourcePoint = points[0];
454
+ const { pointLeft, pointRight } = arrowPoints(points[1], sourcePoint, 10, 20);
455
+ const sourceArrow = drawLinearPath([pointLeft, sourcePoint, pointRight], options);
456
+ arrowG.appendChild(sourceArrow);
457
+ }
458
+ if (targetMarker === LineMarkerType.arrow) {
459
+ const endPoint = points[points.length - 1];
460
+ const { pointLeft, pointRight } = arrowPoints(points[points.length - 2], endPoint, 10, 20);
461
+ const targetArrow = drawLinearPath([pointLeft, endPoint, pointRight], options);
462
+ arrowG.appendChild(targetArrow);
463
+ }
464
+ return arrowG;
465
+ };
466
+ const getSourcePoint = (board, element) => {
467
+ if (element.source.boundId) {
468
+ const boundElement = getElementById(board, element.source.boundId);
469
+ return boundElement ? normalizeConnection(boundElement, element.source.connection) : element.points[0];
470
+ }
471
+ return element.points[0];
472
+ };
473
+ const getTargetPoint = (board, element) => {
474
+ if (element.target.boundId) {
475
+ const boundElement = getElementById(board, element.target.boundId);
476
+ return boundElement ? normalizeConnection(boundElement, element.target.connection) : element.points[element.points.length - 1];
477
+ }
478
+ return element.points[element.points.length - 1];
479
+ };
480
+ const normalizeConnection = (geometry, connection) => {
481
+ const rectangle = getRectangleByPoints(geometry.points);
482
+ const strokeWidth = getStrokeWidthByElement(geometry);
483
+ return [
484
+ rectangle.x - strokeWidth / 2 + (rectangle.width + strokeWidth) * connection[0],
485
+ rectangle.y - strokeWidth / 2 + (rectangle.height + strokeWidth) * connection[1]
486
+ ];
487
+ };
488
+ const transformPointToConnection = (board, point, hitElement) => {
489
+ const offset = (getStrokeWidthByElement(hitElement) + 1) / 2;
490
+ let rectangle = getRectangleByPoints(hitElement.points);
491
+ rectangle = RectangleClient.getOutlineRectangle(rectangle, -offset);
492
+ let nearestPoint = getNearestPoint(hitElement, point, offset);
493
+ const hitConnector = getHitConnectorPoint(nearestPoint, hitElement, rectangle);
494
+ nearestPoint = hitConnector ? hitConnector : nearestPoint;
495
+ return [(nearestPoint[0] - rectangle.x) / rectangle.width, (nearestPoint[1] - rectangle.y) / rectangle.height];
496
+ };
497
+ const getHitConnectorPoint = (movingPoint, hitElement, rectangle) => {
498
+ const connector = getEngine(hitElement.shape).getConnectorPoints(rectangle);
499
+ const points = getPointsByCenterPoint(movingPoint, 5, 5);
500
+ const pointRectangle = getRectangleByPoints(points);
501
+ return connector.find(point => {
502
+ return RectangleClient.isHit(pointRectangle, RectangleClient.toRectangleClient([point, point]));
503
+ });
504
+ };
505
+ const getLineTextRectangle = (board, element, index) => {
506
+ const text = element.texts[index];
507
+ const elbowPoints = getElbowPoints(board, element);
508
+ const point = getPointOnPolyline(elbowPoints, text.position);
509
+ return {
510
+ x: point[0] - text.width / 2,
511
+ y: point[1] - text.height / 2,
512
+ width: text.width,
513
+ height: text.height
514
+ };
515
+ };
516
+
517
+ var DrawCreateMode;
518
+ (function (DrawCreateMode) {
519
+ DrawCreateMode["drag"] = "drag";
520
+ DrawCreateMode["draw"] = "draw";
521
+ })(DrawCreateMode || (DrawCreateMode = {}));
522
+ const BOARD_TO_CREATE_MODE = new WeakMap();
523
+ const getCreateMode = (board) => {
524
+ return BOARD_TO_CREATE_MODE.get(board);
525
+ };
526
+ const setCreateMode = (board, mode) => {
527
+ BOARD_TO_CREATE_MODE.set(board, mode);
528
+ };
529
+
530
+ const getSelectedDrawElements = (board) => {
531
+ const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isDrawElement(value));
532
+ return selectedElements;
533
+ };
534
+ const getSelectedGeometryElements = (board) => {
535
+ const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isGeometry(value));
536
+ return selectedElements;
537
+ };
538
+ const getSelectedLineElements = (board) => {
539
+ const selectedElements = getSelectedElements(board).filter(value => PlaitDrawElement.isLine(value));
540
+ return selectedElements;
541
+ };
542
+
543
+ class GeometryShapeGenerator extends Generator {
544
+ canDraw(element, data) {
545
+ return true;
546
+ }
547
+ baseDraw(element, data) {
548
+ const outerRectangle = getRectangleByPoints(element.points);
549
+ const shape = element.shape;
550
+ if (shape === GeometryShape.text) {
551
+ return;
552
+ }
553
+ const strokeWidth = getStrokeWidthByElement(element);
554
+ const strokeColor = getStrokeColorByElement(element);
555
+ const fill = getFillByElement(element);
556
+ const strokeLineDash = getLineDashByElement(element);
557
+ return drawGeometry(this.board, outerRectangle, shape, { stroke: strokeColor, strokeWidth, fill, strokeLineDash });
558
+ }
559
+ }
560
+
561
+ const insertGeometry = (board, points, shape) => {
562
+ let newElement = createGeometryElement(shape, points, '', {
563
+ strokeColor: DefaultGeometryProperty.strokeColor,
564
+ strokeWidth: DefaultGeometryProperty.strokeWidth
565
+ });
566
+ Transforms.insertNode(board, newElement, [board.children.length]);
567
+ clearSelectedElement(board);
568
+ addSelectedElement(board, newElement);
569
+ };
570
+ const insertText = (board, points, text = '文本') => {
571
+ let newElement = createGeometryElement(GeometryShape.text, points, text);
572
+ Transforms.insertNode(board, newElement, [board.children.length]);
573
+ clearSelectedElement(board);
574
+ addSelectedElement(board, newElement);
575
+ };
576
+ const resizeGeometry = (board, points, textHeight, path) => {
577
+ const normalizePoints = normalizeShapePoints(points);
578
+ const element = PlaitNode.get(board, path);
579
+ const newHeight = textHeight / board.viewport.zoom;
580
+ const newProperties = { points: normalizePoints, textHeight: newHeight };
581
+ if (PlaitDrawElement.isText(element) && element.autoSize) {
582
+ newProperties.autoSize = false;
583
+ }
584
+ Transforms.setNode(board, newProperties, path);
585
+ };
586
+
587
+ const normalizePoints = (board, element, width, textHeight) => {
588
+ let points = element.points;
589
+ let autoSize = element.autoSize;
590
+ const defaultSpace = ShapeDefaultSpace.rectangleAndText;
591
+ if (autoSize) {
592
+ const editor = PlaitGeometry.getTextEditor(element);
593
+ if (AlignEditor.isActive(editor, Alignment.right)) {
594
+ points = [
595
+ [points[1][0] - (width + defaultSpace * 2), points[0][1]],
596
+ [points[1][0], points[0][1] + textHeight]
597
+ ];
598
+ }
599
+ else if (AlignEditor.isActive(editor, Alignment.center)) {
600
+ const oldWidth = Math.abs(points[0][0] - points[1][0]);
601
+ const offset = (width - oldWidth) / 2;
602
+ points = [
603
+ [points[0][0] - offset - defaultSpace, points[0][1]],
604
+ [points[1][0] + offset + defaultSpace, points[0][1] + textHeight]
605
+ ];
606
+ }
607
+ else {
608
+ points = [points[0], [points[0][0] + width + defaultSpace * 2, points[0][1] + textHeight]];
609
+ }
610
+ }
611
+ return { points };
612
+ };
613
+ const setText = (board, element, text, width, textHeight) => {
614
+ const newElement = {
615
+ text,
616
+ textHeight,
617
+ ...normalizePoints(board, element, width, textHeight)
618
+ };
619
+ const path = board.children.findIndex(child => child === element);
620
+ Transforms.setNode(board, newElement, [path]);
621
+ };
622
+ const setTextSize = (board, element, textWidth, textHeight) => {
623
+ if (element.autoSize) {
624
+ const newElement = {
625
+ textHeight,
626
+ ...normalizePoints(board, element, textWidth, textHeight)
627
+ };
628
+ const isPointsEqual = Point.isEquals(element.points[0], newElement.points[0]) && Point.isEquals(element.points[1], newElement.points[1]);
629
+ const isTextHeightEqual = Math.round(textHeight) === Math.round(element.textHeight);
630
+ if (!isPointsEqual || !isTextHeightEqual) {
631
+ const path = board.children.findIndex(child => child === element);
632
+ Transforms.setNode(board, newElement, [path]);
633
+ }
634
+ }
635
+ };
636
+
637
+ const resizeLine = (board, options, path) => {
638
+ Transforms.setNode(board, options, path);
639
+ };
640
+ const setLineTexts = (board, element, texts) => {
641
+ const path = PlaitBoard.findPath(board, element);
642
+ Transforms.setNode(board, { texts }, path);
643
+ };
644
+ const removeLineText = (board, element, index) => {
645
+ const path = PlaitBoard.findPath(board, element);
646
+ const texts = element.texts?.length ? [...element.texts] : [];
647
+ const newTexts = [...texts];
648
+ newTexts.splice(index, 1);
649
+ Transforms.setNode(board, { texts: newTexts }, path);
650
+ };
651
+
652
+ const DrawTransforms = {
653
+ setText,
654
+ insertGeometry,
655
+ resizeGeometry,
656
+ insertText,
657
+ setTextSize,
658
+ resizeLine,
659
+ setLineTexts,
660
+ removeLineText
661
+ };
662
+
663
+ class GeometryComponent extends PlaitPluginElementComponent {
664
+ constructor(viewContainerRef, cdr) {
665
+ super(cdr);
666
+ this.viewContainerRef = viewContainerRef;
667
+ this.cdr = cdr;
668
+ this.destroy$ = new Subject();
669
+ }
670
+ initializeGenerator() {
671
+ this.activeGenerator = new ActiveGenerator(this.board, {
672
+ getStrokeWidth: () => {
673
+ const selectedElements = getSelectedElements(this.board);
674
+ if (selectedElements.length === 1 && !isSelectionMoving(this.board)) {
675
+ return DefaultGeometryActiveStyle.strokeWidth;
676
+ }
677
+ else {
678
+ return DefaultGeometryActiveStyle.selectionStrokeWidth;
679
+ }
680
+ },
681
+ getRectangle: (element) => {
682
+ return getRectangleByPoints(element.points);
683
+ },
684
+ getStrokeWidthByElement: (element) => {
685
+ return getStrokeWidthByElement(element);
686
+ },
687
+ hasResizeHandle: () => {
688
+ const selectedElements = getSelectedElements(this.board);
689
+ if (PlaitBoard.hasBeenTextEditing(this.board)) {
690
+ return false;
691
+ }
692
+ return selectedElements.length === 1 && !isSelectionMoving(this.board);
693
+ }
694
+ });
695
+ this.shapeGenerator = new GeometryShapeGenerator(this.board);
696
+ this.initializeTextManage();
697
+ }
698
+ ngOnInit() {
699
+ super.ngOnInit();
700
+ this.initializeGenerator();
701
+ this.shapeGenerator.draw(this.element, this.g);
702
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected });
703
+ this.drawText();
704
+ }
705
+ onContextChanged(value, previous) {
706
+ if (value.element !== previous.element) {
707
+ this.shapeGenerator.draw(this.element, this.g);
708
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected });
709
+ this.updateText();
710
+ }
711
+ else {
712
+ const hasSameSelected = value.selected === previous.selected;
713
+ const hasSameHandleState = this.activeGenerator.options.hasResizeHandle() === this.activeGenerator.hasResizeHandle;
714
+ if (!hasSameSelected || !hasSameHandleState) {
715
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected });
716
+ }
717
+ }
718
+ }
719
+ editText() {
720
+ this.textManage.edit();
721
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected });
722
+ }
723
+ drawText() {
724
+ this.textManage.draw(this.element.text);
725
+ this.g.append(this.textManage.g);
726
+ }
727
+ updateText() {
728
+ this.textManage.updateText(this.element.text);
729
+ this.textManage.updateRectangle();
730
+ }
731
+ initializeTextManage() {
732
+ this.textManage = new TextManage(this.board, this.viewContainerRef, {
733
+ getRectangle: () => {
734
+ return getTextRectangle(this.element);
735
+ },
736
+ onValueChangeHandle: (textManageRef) => {
737
+ const height = textManageRef.height / this.board.viewport.zoom;
738
+ const width = textManageRef.width / this.board.viewport.zoom;
739
+ if (textManageRef.newValue) {
740
+ DrawTransforms.setText(this.board, this.element, textManageRef.newValue, width, height);
741
+ }
742
+ else {
743
+ DrawTransforms.setTextSize(this.board, this.element, width, height);
744
+ }
745
+ },
746
+ getMaxWidth: () => {
747
+ const width = getTextRectangle(this.element).width;
748
+ return this.element?.autoSize ? GeometryThreshold.defaultTextMaxWidth : width;
749
+ }
750
+ });
751
+ }
752
+ ngOnDestroy() {
753
+ super.ngOnDestroy();
754
+ this.textManage.destroy();
755
+ this.destroy$.next();
756
+ this.destroy$.complete();
757
+ }
758
+ 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 }); }
759
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: GeometryComponent, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
760
+ }
761
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: GeometryComponent, decorators: [{
762
+ type: Component,
763
+ args: [{
764
+ selector: 'plait-draw-geometry',
765
+ template: ``,
766
+ changeDetection: ChangeDetectionStrategy.OnPush
767
+ }]
768
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
769
+
770
+ class LineShapeGenerator extends Generator {
771
+ canDraw(element, data) {
772
+ return true;
773
+ }
774
+ baseDraw(element, data) {
775
+ const shape = element.shape;
776
+ let lineG;
777
+ switch (shape) {
778
+ case LineShape.elbow:
779
+ lineG = drawElbowLine(this.board, element);
780
+ drawMask(this.board, lineG, element);
781
+ break;
782
+ default:
783
+ break;
784
+ }
785
+ return lineG;
786
+ }
787
+ }
788
+ function drawMask(board, g, element) {
789
+ const mask = createMask();
790
+ mask.setAttribute('id', element.id);
791
+ const points = getElbowPoints(board, element);
792
+ let rectangle = getRectangleByPoints(points);
793
+ rectangle = RectangleClient.getOutlineRectangle(rectangle, -3);
794
+ const maskRect = createRect(rectangle, {
795
+ fill: 'white'
796
+ });
797
+ mask.appendChild(maskRect);
798
+ const texts = element.texts;
799
+ texts.forEach((text, index) => {
800
+ const textRectangle = getLineTextRectangle(board, element, index);
801
+ const rect = createRect(textRectangle, {
802
+ fill: 'black'
803
+ });
804
+ mask.appendChild(rect);
805
+ });
806
+ g.appendChild(mask);
807
+ }
808
+
809
+ class LineActiveGenerator extends Generator {
810
+ canDraw(element, data) {
811
+ if (data.selected) {
812
+ return true;
813
+ }
814
+ else {
815
+ return false;
816
+ }
817
+ }
818
+ baseDraw(element, data) {
819
+ const activeG = createG();
820
+ activeG.classList.add('active');
821
+ activeG.classList.add('line-handle');
822
+ const sourcePoint = getSourcePoint(this.board, element);
823
+ const targetPoint = getTargetPoint(this.board, element);
824
+ const sourceCircle = drawCircle(PlaitBoard.getRoughSVG(this.board), sourcePoint, RESIZE_HANDLE_DIAMETER, {
825
+ stroke: '#999999',
826
+ strokeWidth: 1,
827
+ fill: '#FFF',
828
+ fillStyle: 'solid'
829
+ });
830
+ const targetCircle = drawCircle(PlaitBoard.getRoughSVG(this.board), targetPoint, RESIZE_HANDLE_DIAMETER, {
831
+ stroke: '#999999',
832
+ strokeWidth: 1,
833
+ fill: '#FFF',
834
+ fillStyle: 'solid'
835
+ });
836
+ activeG.appendChild(targetCircle);
837
+ activeG.appendChild(sourceCircle);
838
+ return activeG;
839
+ }
840
+ }
841
+
842
+ class LineComponent extends PlaitPluginElementComponent {
843
+ constructor(viewContainerRef, cdr) {
844
+ super(cdr);
845
+ this.viewContainerRef = viewContainerRef;
846
+ this.cdr = cdr;
847
+ this.destroy$ = new Subject();
848
+ this.textManages = [];
849
+ this.boundedElements = {};
850
+ }
851
+ initializeGenerator() {
852
+ this.shapeGenerator = new LineShapeGenerator(this.board);
853
+ this.activeGenerator = new LineActiveGenerator(this.board);
854
+ this.initializeTextManages();
855
+ }
856
+ ngOnInit() {
857
+ this.initializeGenerator();
858
+ this.shapeGenerator.draw(this.element, this.g);
859
+ this.activeGenerator.draw(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
860
+ super.ngOnInit();
861
+ this.boundedElements = this.getBoundedElements();
862
+ this.drawText();
863
+ }
864
+ getBoundedElements() {
865
+ const boundedElements = {};
866
+ if (this.element.source.boundId) {
867
+ const boundElement = getElementById(this.board, this.element.source.boundId);
868
+ if (boundElement) {
869
+ boundedElements.source = boundElement;
870
+ }
871
+ }
872
+ if (this.element.target.boundId) {
873
+ const boundElement = getElementById(this.board, this.element.target.boundId);
874
+ if (boundElement) {
875
+ boundedElements.target = boundElement;
876
+ }
877
+ }
878
+ return boundedElements;
879
+ }
880
+ onContextChanged(value, previous) {
881
+ const boundedElements = this.getBoundedElements();
882
+ const isBoundedElementsChanged = boundedElements.source !== this.boundedElements.source || boundedElements.target !== this.boundedElements.target;
883
+ this.boundedElements = boundedElements;
884
+ if (value.element !== previous.element) {
885
+ this.shapeGenerator.draw(this.element, this.g);
886
+ this.activeGenerator.draw(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
887
+ this.updateText(previous.element.texts, value.element.texts);
888
+ this.updateTextRectangle();
889
+ }
890
+ if (isBoundedElementsChanged) {
891
+ this.shapeGenerator.draw(this.element, this.g);
892
+ this.activeGenerator.draw(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
893
+ this.updateTextRectangle();
894
+ return;
895
+ }
896
+ const hasSameSelected = value.selected === previous.selected;
897
+ if (!hasSameSelected) {
898
+ this.activeGenerator.draw(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
899
+ }
900
+ }
901
+ initializeTextManages() {
902
+ if (this.element.texts?.length) {
903
+ this.element.texts.forEach((text, index) => {
904
+ const manage = this.createTextManage(text, index);
905
+ this.textManages.push(manage);
906
+ });
907
+ }
908
+ }
909
+ destroyTextManages() {
910
+ this.textManages.forEach(manage => {
911
+ manage.destroy();
912
+ });
913
+ }
914
+ drawText() {
915
+ if (this.element.texts?.length) {
916
+ this.textManages.forEach((manage, index) => {
917
+ manage.draw(this.element.texts[index].text);
918
+ this.g.append(manage.g);
919
+ });
920
+ }
921
+ }
922
+ createTextManage(text, index) {
923
+ return new TextManage(this.board, this.viewContainerRef, {
924
+ getRectangle: () => {
925
+ return getLineTextRectangle(this.board, this.element, index);
926
+ },
927
+ onValueChangeHandle: (textManageRef) => {
928
+ const height = textManageRef.height / this.board.viewport.zoom;
929
+ const width = textManageRef.width / this.board.viewport.zoom;
930
+ const texts = [...this.element.texts];
931
+ texts.splice(index, 1, {
932
+ text: textManageRef.newValue ? textManageRef.newValue : this.element.texts[index].text,
933
+ position: this.element.texts[index].position,
934
+ width,
935
+ height
936
+ });
937
+ DrawTransforms.setLineTexts(this.board, this.element, texts);
938
+ },
939
+ getMaxWidth: () => GeometryThreshold.defaultTextMaxWidth
940
+ });
941
+ }
942
+ updateText(previousTexts, currentTexts) {
943
+ if (previousTexts === currentTexts)
944
+ return;
945
+ const previousTextsLength = previousTexts.length;
946
+ const currentTextsLength = currentTexts.length;
947
+ if (currentTextsLength === previousTextsLength) {
948
+ for (let i = 0; i < previousTextsLength; i++) {
949
+ if (previousTexts[i].text !== currentTexts[i].text) {
950
+ this.textManages[i].updateText(currentTexts[i].text);
951
+ }
952
+ }
953
+ }
954
+ else {
955
+ this.destroyTextManages();
956
+ this.textManages = [];
957
+ this.initializeTextManages();
958
+ this.drawText();
959
+ }
960
+ }
961
+ updateTextRectangle() {
962
+ this.textManages.forEach(manage => {
963
+ manage.updateRectangle();
964
+ });
965
+ }
966
+ ngOnDestroy() {
967
+ super.ngOnDestroy();
968
+ this.activeGenerator.destroy();
969
+ this.destroy$.next();
970
+ this.destroy$.complete();
971
+ }
972
+ 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 }); }
973
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: LineComponent, selector: "plait-draw-line", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
974
+ }
975
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: LineComponent, decorators: [{
976
+ type: Component,
977
+ args: [{
978
+ selector: 'plait-draw-line',
979
+ template: ``,
980
+ changeDetection: ChangeDetectionStrategy.OnPush
981
+ }]
982
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
983
+
984
+ const withDrawHotkey = (board) => {
985
+ const { keydown } = board;
986
+ board.keydown = (event) => {
987
+ const selectedElements = getSelectedElements(board);
988
+ const isSingleSelection = selectedElements.length === 1;
989
+ const targetElement = selectedElements[0];
990
+ if (!isVirtualKey(event) && !isSpaceHotkey(event) && isSingleSelection && PlaitDrawElement.isDrawElement(targetElement)) {
991
+ event.preventDefault();
992
+ PlaitElement.getComponent(targetElement).editText();
993
+ return;
994
+ }
995
+ keydown(event);
996
+ };
997
+ return board;
998
+ };
999
+
1000
+ const withGeometryCreateByDrag = (board) => {
1001
+ const { pointerMove, pointerUp } = board;
1002
+ let createMode = undefined;
1003
+ let geometryShapeG = null;
1004
+ board.pointerMove = (event) => {
1005
+ geometryShapeG?.remove();
1006
+ geometryShapeG = createG();
1007
+ createMode = getCreateMode(board);
1008
+ const geometryGenerator = new GeometryShapeGenerator(board);
1009
+ const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
1010
+ const dragMode = isGeometryPointer && createMode === DrawCreateMode.drag;
1011
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1012
+ const pointer = PlaitBoard.getPointer(board);
1013
+ if (dragMode) {
1014
+ const points = getDefaultGeometryPoints(pointer, movingPoint);
1015
+ if (pointer === DrawPointerType.text) {
1016
+ const textG = getTemporaryTextG(movingPoint);
1017
+ geometryShapeG.appendChild(textG);
1018
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1019
+ }
1020
+ else {
1021
+ const temporaryElement = createGeometryElement(pointer, points, '', {
1022
+ strokeColor: DefaultGeometryProperty.strokeColor,
1023
+ strokeWidth: DefaultGeometryProperty.strokeWidth
1024
+ });
1025
+ geometryGenerator.draw(temporaryElement, geometryShapeG);
1026
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1027
+ }
1028
+ }
1029
+ pointerMove(event);
1030
+ };
1031
+ board.pointerUp = (event) => {
1032
+ const pointer = PlaitBoard.getPointer(board);
1033
+ const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
1034
+ const dragMode = isGeometryPointer && createMode === DrawCreateMode.drag;
1035
+ if (dragMode) {
1036
+ const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1037
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
1038
+ if (pointer === DrawPointerType.text) {
1039
+ DrawTransforms.insertText(board, points);
1040
+ }
1041
+ else {
1042
+ DrawTransforms.insertGeometry(board, points, pointer);
1043
+ }
1044
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1045
+ }
1046
+ geometryShapeG?.remove();
1047
+ geometryShapeG = null;
1048
+ preventTouchMove(board, false);
1049
+ pointerUp(event);
1050
+ };
1051
+ return board;
1052
+ };
1053
+ const withGeometryCreateByDraw = (board) => {
1054
+ const { pointerDown, pointerMove, pointerUp, keydown, keyup } = board;
1055
+ let start = null;
1056
+ let geometryShapeG = null;
1057
+ let temporaryElement = null;
1058
+ let isShift = false;
1059
+ board.keydown = (event) => {
1060
+ isShift = isKeyHotkey('shift', event);
1061
+ keydown(event);
1062
+ };
1063
+ board.keyup = (event) => {
1064
+ isShift = false;
1065
+ keyup(event);
1066
+ };
1067
+ board.pointerDown = (event) => {
1068
+ const createMode = getCreateMode(board);
1069
+ const isGeometryPointer = PlaitBoard.isInPointer(board, GeometryPointer);
1070
+ if (isGeometryPointer && createMode === DrawCreateMode.draw) {
1071
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1072
+ start = point;
1073
+ preventTouchMove(board, true);
1074
+ const pointer = PlaitBoard.getPointer(board);
1075
+ if (pointer === DrawPointerType.text) {
1076
+ const points = getDefaultGeometryPoints(pointer, point);
1077
+ const textElement = createGeometryElement(GeometryShape.text, points, DefaultTextProperty.text);
1078
+ Transforms.insertNode(board, textElement, [board.children.length]);
1079
+ clearSelectedElement(board);
1080
+ addSelectedElement(board, textElement);
1081
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1082
+ start = null;
1083
+ preventTouchMove(board, false);
1084
+ }
1085
+ }
1086
+ pointerDown(event);
1087
+ };
1088
+ board.pointerMove = (event) => {
1089
+ geometryShapeG?.remove();
1090
+ geometryShapeG = createG();
1091
+ const geometryGenerator = new GeometryShapeGenerator(board);
1092
+ const drawMode = !!start;
1093
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1094
+ const pointer = PlaitBoard.getPointer(board);
1095
+ if (drawMode && pointer !== DrawPointerType.text) {
1096
+ const points = normalizeShapePoints([start, movingPoint], isShift);
1097
+ temporaryElement = createGeometryElement(pointer, points, '', {
1098
+ strokeColor: DefaultGeometryProperty.strokeColor,
1099
+ strokeWidth: DefaultGeometryProperty.strokeWidth
1100
+ });
1101
+ geometryGenerator.draw(temporaryElement, geometryShapeG);
1102
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
1103
+ }
1104
+ pointerMove(event);
1105
+ };
1106
+ board.pointerUp = (event) => {
1107
+ const isDrawMode = !!start;
1108
+ if (isDrawMode) {
1109
+ const targetPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1110
+ const { width, height } = RectangleClient.toRectangleClient([start, targetPoint]);
1111
+ if (Math.hypot(width, height) === 0) {
1112
+ const pointer = PlaitBoard.getPointer(board);
1113
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
1114
+ if (pointer !== DrawPointerType.text) {
1115
+ temporaryElement = createGeometryElement(pointer, points, '', {
1116
+ strokeColor: DefaultGeometryProperty.strokeColor,
1117
+ strokeWidth: DefaultGeometryProperty.strokeWidth
1118
+ });
1119
+ }
1120
+ }
1121
+ }
1122
+ if (temporaryElement) {
1123
+ Transforms.insertNode(board, temporaryElement, [board.children.length]);
1124
+ clearSelectedElement(board);
1125
+ addSelectedElement(board, temporaryElement);
1126
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1127
+ }
1128
+ geometryShapeG?.remove();
1129
+ geometryShapeG = null;
1130
+ start = null;
1131
+ temporaryElement = null;
1132
+ preventTouchMove(board, false);
1133
+ pointerUp(event);
1134
+ };
1135
+ return board;
1136
+ };
1137
+ const getDefaultGeometryPoints = (pointer, targetPoint) => {
1138
+ return pointer === DrawPointerType.text
1139
+ ? getPointsByCenterPoint(targetPoint, DefaultTextProperty.width, DefaultTextProperty.height)
1140
+ : getPointsByCenterPoint(targetPoint, DefaultGeometryProperty.width, DefaultGeometryProperty.height);
1141
+ };
1142
+ const getTemporaryTextG = (movingPoint) => {
1143
+ const textG = createG();
1144
+ const width = DefaultTextProperty.width - ShapeDefaultSpace.rectangleAndText * 2;
1145
+ const foreignObject = createForeignObject(movingPoint[0] - width / 2, movingPoint[1] - DefaultTextProperty.height / 2, width, DefaultTextProperty.height);
1146
+ const richtext = document.createElement('div');
1147
+ richtext.textContent = DefaultTextProperty.text;
1148
+ richtext.style.fontSize = `${DEFAULT_FONT_SIZE}px`;
1149
+ richtext.style.cursor = 'default';
1150
+ foreignObject.appendChild(richtext);
1151
+ textG.appendChild(foreignObject);
1152
+ return textG;
1153
+ };
1154
+
1155
+ const buildClipboardData = (board, elements, startPoint) => {
1156
+ return elements.map(element => {
1157
+ if (PlaitDrawElement.isGeometry(element)) {
1158
+ const points = element.points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
1159
+ return { ...element, points };
1160
+ }
1161
+ if (PlaitDrawElement.isLine(element)) {
1162
+ const points = element.points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
1163
+ return { ...element, points };
1164
+ }
1165
+ return element;
1166
+ });
1167
+ };
1168
+ const insertClipboardData = (board, elements, startPoint) => {
1169
+ elements.forEach(element => {
1170
+ element.id = idCreator();
1171
+ element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
1172
+ Transforms.insertNode(board, element, [board.children.length]);
1173
+ });
1174
+ };
1175
+
1176
+ const withDrawFragment = (baseBoard) => {
1177
+ const board = baseBoard;
1178
+ const { deleteFragment, setFragment, insertFragment } = board;
1179
+ board.deleteFragment = (data) => {
1180
+ const drawElements = getSelectedDrawElements(board);
1181
+ if (drawElements.length) {
1182
+ const geometryElements = drawElements.filter(value => PlaitDrawElement.isDrawElement(value));
1183
+ // query bound lines
1184
+ const boundLineElements = [];
1185
+ CommonTransforms.removeElements(board, [...geometryElements, ...boundLineElements]);
1186
+ }
1187
+ deleteFragment(data);
1188
+ };
1189
+ board.setFragment = (data, rectangle) => {
1190
+ const targetDrawElements = getSelectedDrawElements(board);
1191
+ if (targetDrawElements.length) {
1192
+ const elements = buildClipboardData(board, targetDrawElements, rectangle ? [rectangle.x, rectangle.y] : [0, 0]);
1193
+ setClipboardData(data, elements);
1194
+ }
1195
+ setFragment(data, rectangle);
1196
+ };
1197
+ board.insertFragment = (data, targetPoint) => {
1198
+ const elements = getDataFromClipboard(data);
1199
+ const drawElements = elements.filter(value => PlaitDrawElement.isDrawElement(value));
1200
+ if (elements.length > 0 && drawElements.length > 0) {
1201
+ insertClipboardData(board, drawElements, targetPoint);
1202
+ }
1203
+ else if (elements.length === 0) {
1204
+ const text = getTextFromClipboard(data);
1205
+ const selectedElements = getSelectedElements(board);
1206
+ // (* ̄︶ ̄)
1207
+ const insertAsChildren = selectedElements.length === 1 && selectedElements[0].children;
1208
+ const insertAsFreeText = !insertAsChildren;
1209
+ if (text && insertAsFreeText) {
1210
+ const { width, height } = getTextSize(board, text);
1211
+ DrawTransforms.insertText(board, [targetPoint, [targetPoint[0] + width, targetPoint[1] + height]], text);
1212
+ return;
1213
+ }
1214
+ }
1215
+ insertFragment(data, targetPoint);
1216
+ };
1217
+ return board;
1218
+ };
1219
+
1220
+ const DefaultLineStyle = {
1221
+ strokeWidth: 2,
1222
+ strokeColor: '#000'
1223
+ };
1224
+
1225
+ const getHitGeometryResizeHandleRef = (board, element, point) => {
1226
+ const rectangle = getRectangleByPoints(element.points);
1227
+ const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER);
1228
+ const result = resizeHandleRefs.find(resizeHandleRef => {
1229
+ return RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), resizeHandleRef.rectangle);
1230
+ });
1231
+ return result;
1232
+ };
1233
+ const getHitOutlineGeometry = (board, point, offset = 0) => {
1234
+ let geometry = null;
1235
+ depthFirstRecursion(board, node => {
1236
+ if (PlaitDrawElement.isGeometry(node)) {
1237
+ const shape = node.shape;
1238
+ let client = getRectangleByPoints(node.points);
1239
+ client = RectangleClient.getOutlineRectangle(client, offset);
1240
+ const isHit = getEngine(shape).isHit(client, point);
1241
+ if (isHit) {
1242
+ geometry = node;
1243
+ }
1244
+ }
1245
+ }, getIsRecursionFunc(board), true);
1246
+ return geometry;
1247
+ };
1248
+
1249
+ const withLineCreateByDraw = (board) => {
1250
+ const { pointerDown, pointerMove, pointerUp } = board;
1251
+ let start = null;
1252
+ let sourceRef = {};
1253
+ let targetRef = {};
1254
+ let lineShapeG = null;
1255
+ let temporaryElement = null;
1256
+ board.pointerDown = (event) => {
1257
+ const createMode = getCreateMode(board);
1258
+ const isLinePointer = PlaitBoard.isPointer(board, DrawPointerType.line);
1259
+ if (isLinePointer && createMode === DrawCreateMode.draw) {
1260
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1261
+ start = point;
1262
+ const hitElement = getHitOutlineGeometry(board, point, -4);
1263
+ if (hitElement) {
1264
+ sourceRef.connection = transformPointToConnection(board, point, hitElement);
1265
+ sourceRef.boundId = hitElement.id;
1266
+ }
1267
+ preventTouchMove(board, true);
1268
+ }
1269
+ pointerDown(event);
1270
+ };
1271
+ board.pointerMove = (event) => {
1272
+ lineShapeG?.remove();
1273
+ lineShapeG = createG();
1274
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1275
+ if (start) {
1276
+ const hitElement = getHitOutlineGeometry(board, movingPoint, -4);
1277
+ targetRef.connection = hitElement ? transformPointToConnection(board, movingPoint, hitElement) : undefined;
1278
+ targetRef.boundId = hitElement ? hitElement.id : undefined;
1279
+ const lineGenerator = new LineShapeGenerator(board);
1280
+ temporaryElement = createLineElement(LineShape.elbow, [start, movingPoint], { marker: LineMarkerType.none, connection: sourceRef.connection, boundId: sourceRef?.boundId }, { marker: LineMarkerType.arrow, connection: targetRef.connection, boundId: targetRef?.boundId }, {
1281
+ strokeColor: DefaultLineStyle.strokeColor,
1282
+ strokeWidth: DefaultLineStyle.strokeWidth
1283
+ });
1284
+ lineGenerator.draw(temporaryElement, lineShapeG);
1285
+ PlaitBoard.getElementActiveHost(board).append(lineShapeG);
1286
+ }
1287
+ pointerMove(event);
1288
+ };
1289
+ board.pointerUp = (event) => {
1290
+ if (temporaryElement) {
1291
+ Transforms.insertNode(board, temporaryElement, [board.children.length]);
1292
+ clearSelectedElement(board);
1293
+ addSelectedElement(board, temporaryElement);
1294
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
1295
+ }
1296
+ lineShapeG?.remove();
1297
+ lineShapeG = null;
1298
+ start = null;
1299
+ sourceRef = {};
1300
+ targetRef = {};
1301
+ temporaryElement = null;
1302
+ preventTouchMove(board, false);
1303
+ pointerUp(event);
1304
+ };
1305
+ return board;
1306
+ };
1307
+
1308
+ const withGeometryResize = (board) => {
1309
+ const { keydown, keyup } = board;
1310
+ let isShift = false;
1311
+ board.keydown = (event) => {
1312
+ isShift = isKeyHotkey('shift', event);
1313
+ keydown(event);
1314
+ };
1315
+ board.keyup = (event) => {
1316
+ isShift = false;
1317
+ keyup(event);
1318
+ };
1319
+ const options = {
1320
+ key: 'draw-geometry',
1321
+ canResize: () => {
1322
+ return true;
1323
+ },
1324
+ detect: (point) => {
1325
+ const selectedGeometryElements = getSelectedGeometryElements(board);
1326
+ if (selectedGeometryElements.length !== 1) {
1327
+ return null;
1328
+ }
1329
+ const target = selectedGeometryElements[0];
1330
+ const targetComponent = PlaitElement.getComponent(selectedGeometryElements[0]);
1331
+ if (targetComponent.activeGenerator.hasResizeHandle) {
1332
+ const handleRef = getHitGeometryResizeHandleRef(board, target, point);
1333
+ if (handleRef) {
1334
+ return {
1335
+ element: target,
1336
+ handle: handleRef.handle,
1337
+ cursorClass: handleRef.cursorClass
1338
+ };
1339
+ }
1340
+ }
1341
+ return null;
1342
+ },
1343
+ onResize: (resizeRef, resizeState) => {
1344
+ let points = [...resizeRef.element.points];
1345
+ if (resizeRef.handle === ResizeHandle.nw) {
1346
+ points = [resizeState.endTransformPoint, resizeRef.element.points[1]];
1347
+ }
1348
+ if (resizeRef.handle === ResizeHandle.ne) {
1349
+ points = [
1350
+ [resizeRef.element.points[0][0], resizeState.endTransformPoint[1]],
1351
+ [resizeState.endTransformPoint[0], resizeRef.element.points[1][1]]
1352
+ ];
1353
+ }
1354
+ if (resizeRef.handle === ResizeHandle.se) {
1355
+ points = [resizeRef.element.points[0], resizeState.endTransformPoint];
1356
+ }
1357
+ if (resizeRef.handle === ResizeHandle.sw) {
1358
+ points = [
1359
+ [resizeState.endTransformPoint[0], resizeRef.element.points[0][1]],
1360
+ [resizeRef.element.points[1][0], resizeState.endTransformPoint[1]]
1361
+ ];
1362
+ }
1363
+ points = normalizeShapePoints(points, isShift);
1364
+ const component = PlaitElement.getComponent(resizeRef.element);
1365
+ const { height: textHeight } = component.textManage.getSize();
1366
+ DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
1367
+ }
1368
+ };
1369
+ withResize(board, options);
1370
+ return board;
1371
+ };
1372
+
1373
+ var LineResizeHandle;
1374
+ (function (LineResizeHandle) {
1375
+ LineResizeHandle["source"] = "source";
1376
+ LineResizeHandle["target"] = "target";
1377
+ })(LineResizeHandle || (LineResizeHandle = {}));
1378
+ const getHitLineResizeHandleRef = (board, element, point) => {
1379
+ const sourcePoint = getSourcePoint(board, element);
1380
+ const targetPoint = getTargetPoint(board, element);
1381
+ const sourceRectangle = {
1382
+ x: sourcePoint[0] - RESIZE_HANDLE_DIAMETER / 2,
1383
+ y: sourcePoint[1] - RESIZE_HANDLE_DIAMETER / 2,
1384
+ width: RESIZE_HANDLE_DIAMETER,
1385
+ height: RESIZE_HANDLE_DIAMETER
1386
+ };
1387
+ const targetRectangle = {
1388
+ x: targetPoint[0] - RESIZE_HANDLE_DIAMETER / 2,
1389
+ y: targetPoint[1] - RESIZE_HANDLE_DIAMETER / 2,
1390
+ width: RESIZE_HANDLE_DIAMETER,
1391
+ height: RESIZE_HANDLE_DIAMETER
1392
+ };
1393
+ const isHitSourceRectangle = RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), sourceRectangle);
1394
+ const isHitTargetRectangle = RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), targetRectangle);
1395
+ if (isHitSourceRectangle) {
1396
+ return { rectangle: sourceRectangle, handle: LineResizeHandle.source };
1397
+ }
1398
+ if (isHitTargetRectangle) {
1399
+ return { rectangle: targetRectangle, handle: LineResizeHandle.target };
1400
+ }
1401
+ return undefined;
1402
+ };
1403
+
1404
+ const withLineResize = (board) => {
1405
+ const options = {
1406
+ key: 'draw-line',
1407
+ canResize: () => {
1408
+ return true;
1409
+ },
1410
+ detect: (point) => {
1411
+ const selectedLineElements = getSelectedLineElements(board);
1412
+ if (selectedLineElements.length > 0) {
1413
+ let result = null;
1414
+ selectedLineElements.forEach(value => {
1415
+ const handleRef = getHitLineResizeHandleRef(board, value, point);
1416
+ if (handleRef) {
1417
+ result = {
1418
+ element: value,
1419
+ handle: handleRef.handle
1420
+ };
1421
+ }
1422
+ });
1423
+ return result;
1424
+ }
1425
+ return null;
1426
+ },
1427
+ onResize: (resizeRef, resizeState) => {
1428
+ let points = [...resizeRef.element.points];
1429
+ let source = { ...resizeRef.element.source };
1430
+ let target = { ...resizeRef.element.target };
1431
+ if (resizeRef.handle === LineResizeHandle.source) {
1432
+ points[0] = resizeState.endTransformPoint;
1433
+ const hitElement = getHitOutlineGeometry(board, resizeState.endTransformPoint, -4);
1434
+ source.connection = hitElement ? transformPointToConnection(board, resizeState.endTransformPoint, hitElement) : undefined;
1435
+ source.boundId = hitElement ? hitElement.id : undefined;
1436
+ }
1437
+ if (resizeRef.handle === LineResizeHandle.target) {
1438
+ points[1] = resizeState.endTransformPoint;
1439
+ const hitElement = getHitOutlineGeometry(board, resizeState.endTransformPoint, -4);
1440
+ target.connection = hitElement ? transformPointToConnection(board, resizeState.endTransformPoint, hitElement) : undefined;
1441
+ target.boundId = hitElement ? hitElement.id : undefined;
1442
+ }
1443
+ DrawTransforms.resizeLine(board, { points, source, target }, resizeRef.path);
1444
+ }
1445
+ };
1446
+ withResize(board, options);
1447
+ return board;
1448
+ };
1449
+
1450
+ const withLineBoundReaction = (board) => {
1451
+ const { pointerMove, pointerUp } = board;
1452
+ let boundShapeG = null;
1453
+ board.pointerMove = (event) => {
1454
+ boundShapeG?.remove();
1455
+ const isLinePointer = PlaitBoard.isPointer(board, DrawPointerType.line);
1456
+ const movingPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1457
+ const isLineResizing = isResizingByCondition(board, element => PlaitDrawElement.isLine(element));
1458
+ if (isLinePointer || isLineResizing) {
1459
+ const hitElement = getHitOutlineGeometry(board, movingPoint, -4);
1460
+ if (hitElement) {
1461
+ boundShapeG = drawBoundMask(board, hitElement);
1462
+ const offset = (getStrokeWidthByElement(hitElement) + 1) / 2;
1463
+ let nearestPoint = getNearestPoint(hitElement, movingPoint, offset);
1464
+ const rectangle = getRectangleByPoints(hitElement.points);
1465
+ const activeRectangle = RectangleClient.getOutlineRectangle(rectangle, -offset);
1466
+ const hitConnector = getHitConnectorPoint(nearestPoint, hitElement, activeRectangle);
1467
+ nearestPoint = hitConnector ? hitConnector : nearestPoint;
1468
+ const circleG = drawCircle(PlaitBoard.getRoughSVG(board), nearestPoint, 6, {
1469
+ stroke: SELECTION_BORDER_COLOR,
1470
+ strokeWidth: 1,
1471
+ fill: SELECTION_BORDER_COLOR,
1472
+ fillStyle: 'solid'
1473
+ });
1474
+ boundShapeG.appendChild(circleG);
1475
+ PlaitBoard.getElementActiveHost(board).append(boundShapeG);
1476
+ }
1477
+ }
1478
+ pointerMove(event);
1479
+ };
1480
+ board.pointerUp = event => {
1481
+ boundShapeG?.remove();
1482
+ boundShapeG = null;
1483
+ pointerUp(event);
1484
+ };
1485
+ return board;
1486
+ };
1487
+
1488
+ const withLineText = (board) => {
1489
+ const { dblclick } = board;
1490
+ board.dblclick = (event) => {
1491
+ const clickPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1492
+ const hitTarget = getHitElements(board, { ranges: [{ anchor: clickPoint, focus: clickPoint }] }, (element) => {
1493
+ return PlaitDrawElement.isLine(element);
1494
+ })[0];
1495
+ if (hitTarget) {
1496
+ const points = getElbowPoints(board, hitTarget);
1497
+ const point = getNearestPointBetweenPointAndSegments(clickPoint, points);
1498
+ const texts = hitTarget.texts?.length ? [...hitTarget.texts] : [];
1499
+ const textIndex = getHitLineTextIndex(board, hitTarget, clickPoint);
1500
+ const isHitText = isHitLineText(board, hitTarget, clickPoint);
1501
+ if (isHitText) {
1502
+ editHandle(board, hitTarget, textIndex);
1503
+ }
1504
+ else {
1505
+ const ratio = getRatioByPoint(points, point);
1506
+ texts.push({
1507
+ text: buildText('文本'),
1508
+ position: ratio,
1509
+ width: 28,
1510
+ height: 20
1511
+ });
1512
+ DrawTransforms.setLineTexts(board, hitTarget, texts);
1513
+ setTimeout(() => {
1514
+ const hitComponent = PlaitElement.getComponent(hitTarget);
1515
+ editHandle(board, hitTarget, hitComponent.textManages.length - 1, true);
1516
+ });
1517
+ }
1518
+ }
1519
+ dblclick(event);
1520
+ };
1521
+ return board;
1522
+ };
1523
+ function editHandle(board, element, manageIndex, isFirstEdit = false) {
1524
+ const hitComponent = PlaitElement.getComponent(element);
1525
+ const textManage = hitComponent.textManages[manageIndex];
1526
+ const originText = textManage.componentRef.instance.children;
1527
+ textManage.edit((origin, descendant) => {
1528
+ const text = Node.string(descendant[0]);
1529
+ const shouldRemove = (isFirstEdit && originText === descendant) || !text;
1530
+ if (shouldRemove) {
1531
+ DrawTransforms.removeLineText(board, element, manageIndex);
1532
+ }
1533
+ });
1534
+ }
1535
+
1536
+ const withDraw = (board) => {
1537
+ const { drawElement, getRectangle, isHitSelection, isMovable, dblclick } = board;
1538
+ board.drawElement = (context) => {
1539
+ if (PlaitDrawElement.isGeometry(context.element)) {
1540
+ return GeometryComponent;
1541
+ }
1542
+ else if (PlaitDrawElement.isLine(context.element)) {
1543
+ return LineComponent;
1544
+ }
1545
+ return drawElement(context);
1546
+ };
1547
+ board.getRectangle = (element) => {
1548
+ if (PlaitDrawElement.isGeometry(element)) {
1549
+ return getRectangleByPoints(element.points);
1550
+ }
1551
+ return getRectangle(element);
1552
+ };
1553
+ board.isHitSelection = (element, range) => {
1554
+ if (PlaitDrawElement.isGeometry(element)) {
1555
+ const client = getRectangleByPoints(element.points);
1556
+ const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
1557
+ if (element.textHeight > client.height) {
1558
+ const textClient = getTextRectangle(element);
1559
+ return RectangleClient.isHit(rangeRectangle, client) || RectangleClient.isHit(rangeRectangle, textClient);
1560
+ }
1561
+ return RectangleClient.isHit(rangeRectangle, client);
1562
+ }
1563
+ if (PlaitDrawElement.isLine(element)) {
1564
+ const points = getElbowPoints(board, element);
1565
+ const strokeWidth = getStrokeWidthByElement(element);
1566
+ const isHitText = isHitLineText(board, element, range.focus);
1567
+ const isHit = isHitPolyLine(points, range.focus, strokeWidth, 3) || isHitText;
1568
+ const rangeRectangle = RectangleClient.toRectangleClient([range.anchor, range.focus]);
1569
+ const isContainPolyLinePoint = points.some(point => {
1570
+ return RectangleClient.isHit(rangeRectangle, RectangleClient.toRectangleClient([point, point]));
1571
+ });
1572
+ const isIntersect = range.anchor === range.focus ? isHit : isPolylineHitRectangle(points, rangeRectangle);
1573
+ return isContainPolyLinePoint || isIntersect;
1574
+ }
1575
+ return isHitSelection(element, range);
1576
+ };
1577
+ board.isMovable = (element) => {
1578
+ if (PlaitDrawElement.isGeometry(element)) {
1579
+ return true;
1580
+ }
1581
+ if (PlaitDrawElement.isLine(element)) {
1582
+ return !element.source.boundId && !element.source.boundId;
1583
+ }
1584
+ return isMovable(element);
1585
+ };
1586
+ board.dblclick = (event) => {
1587
+ const element = getSelectedElements(board)[0];
1588
+ if (element && PlaitDrawElement.isGeometry(element)) {
1589
+ const component = PlaitElement.getComponent(element);
1590
+ component.editText();
1591
+ }
1592
+ dblclick(event);
1593
+ };
1594
+ return withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withGeometryCreateByDrag(withGeometryCreateByDraw(withDrawFragment(withDrawHotkey(board)))))))));
1595
+ };
1596
+
1597
+ /**
1598
+ * Generated bundle index. Do not edit.
1599
+ */
1600
+
1601
+ export { DefaultGeometryActiveStyle, DefaultGeometryProperty, DefaultGeometryStyle, DefaultTextProperty, DrawCreateMode, DrawPointerType, GeometryPointer, GeometryShape, GeometryThreshold, LineMarkerType, LineShape, PlaitDrawElement, PlaitGeometry, ShapeDefaultSpace, createGeometryElement, createLineElement, drawBoundMask, drawElbowLine, drawGeometry, drawLineArrow, getCenterPointsOnPolygon, getCreateMode, getElbowPoints, getHitConnectorPoint, getHitLineTextIndex, getLineTextRectangle, getNearestPoint, getPointsByCenterPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedLineElements, getSourcePoint, getTargetPoint, getTextRectangle, isHitLineText, isHitPolyLine, normalizeConnection, setCreateMode, transformPointToConnection, withDraw };
1602
+ //# sourceMappingURL=plait-draw.mjs.map