@plait/draw 0.54.0 → 0.55.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 (48) hide show
  1. package/constants/geometry.d.ts +22 -0
  2. package/engines/basic-shapes/circle.d.ts +8 -0
  3. package/engines/basic-shapes/cloud.d.ts +2 -0
  4. package/engines/flowchart/off-page.d.ts +4 -0
  5. package/engines/flowchart/or.d.ts +2 -0
  6. package/engines/flowchart/predefined-process.d.ts +2 -0
  7. package/engines/flowchart/summing-junction.d.ts +2 -0
  8. package/esm2022/constants/geometry.mjs +12 -2
  9. package/esm2022/engines/basic-shapes/circle.mjs +51 -0
  10. package/esm2022/engines/basic-shapes/cloud.mjs +57 -0
  11. package/esm2022/engines/basic-shapes/ellipse.mjs +3 -41
  12. package/esm2022/engines/flowchart/off-page.mjs +32 -0
  13. package/esm2022/engines/flowchart/or.mjs +25 -0
  14. package/esm2022/engines/flowchart/predefined-process.mjs +47 -0
  15. package/esm2022/engines/flowchart/summing-junction.mjs +28 -0
  16. package/esm2022/engines/index.mjs +12 -2
  17. package/esm2022/geometry.component.mjs +7 -8
  18. package/esm2022/image.component.mjs +6 -7
  19. package/esm2022/interfaces/element.mjs +2 -1
  20. package/esm2022/interfaces/geometry.mjs +6 -1
  21. package/esm2022/line.component.mjs +8 -9
  22. package/esm2022/plugins/with-draw-fragment.mjs +7 -7
  23. package/esm2022/plugins/with-draw-hotkey.mjs +1 -1
  24. package/esm2022/plugins/with-draw-resize.mjs +23 -23
  25. package/esm2022/plugins/with-draw-rotate.mjs +127 -0
  26. package/esm2022/plugins/with-draw.mjs +3 -2
  27. package/esm2022/plugins/with-geometry-create.mjs +21 -5
  28. package/esm2022/plugins/with-geometry-resize.mjs +15 -14
  29. package/esm2022/plugins/with-line-auto-complete.mjs +4 -3
  30. package/esm2022/utils/geometry.mjs +5 -2
  31. package/esm2022/utils/line/line-basic.mjs +6 -3
  32. package/esm2022/utils/position/geometry.mjs +10 -2
  33. package/esm2022/utils/snap-resizing.mjs +185 -0
  34. package/esm2022/utils/style/stroke.mjs +9 -2
  35. package/fesm2022/plait-draw.mjs +1126 -942
  36. package/fesm2022/plait-draw.mjs.map +1 -1
  37. package/geometry.component.d.ts +2 -3
  38. package/image.component.d.ts +2 -3
  39. package/interfaces/element.d.ts +2 -1
  40. package/interfaces/geometry.d.ts +7 -2
  41. package/line.component.d.ts +2 -3
  42. package/package.json +1 -1
  43. package/plugins/with-draw-resize.d.ts +3 -5
  44. package/plugins/with-draw-rotate.d.ts +2 -0
  45. package/utils/position/geometry.d.ts +6 -0
  46. package/utils/snap-resizing.d.ts +25 -0
  47. package/esm2022/utils/resize-snap.mjs +0 -361
  48. package/utils/resize-snap.d.ts +0 -49
@@ -1,5 +1,5 @@
1
- import { ACTIVE_STROKE_WIDTH, ThemeColorMode, createDebugGenerator, Point, RectangleClient, getElementById, rotatePointsByElement, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPolylineHitRectangle, rotateAntiPointsByElement, rotatePoints, depthFirstRecursion, PlaitBoard, getIsRecursionFunc, idCreator, catmullRomFitting, findElements, createMask, createRect, getSelectedElements, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, Direction, hasValidAngle, Path, PlaitNode, toViewBoxPoint, toHostPoint, isSelectionMoving, RgbaToHEX, PlaitElement, getHitElementByPoint, preventTouchMove, createClipboardContext, WritableClipboardType, addClipboardContext, getSelectionAngle, getRectangleByAngle, getRectangleByElements, rotatedDataPoints, isAxisChangedByAngle, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER } from '@plait/core';
2
- import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, DEFAULT_ROUTE_MARGIN, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator, RESIZE_HANDLE_DIAMETER, getPointOnPolyline, TRANSPARENT, getRectangleResizeHandleRefs, getRotatedResizeCursorClassByAngle, getMemorizedLatest, memorizeLatest, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getDirectionByVector, getOppositeDirection, getDirectionFactor, rotateVector, getDirectionByPointOfRectangle, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, normalizeShapePoints, getFirstTextEditor, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, resetPointsAfterResize, getDirectionFactorByDirectionComponent, isCornerHandle, getFirstTextManage, withResize, drawHandle, getIndexByResizeHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, isResizingByCondition, getRatioByPoint, ImageGenerator, ResizeHandle } from '@plait/common';
1
+ import { ACTIVE_STROKE_WIDTH, ThemeColorMode, createDebugGenerator, Point, RectangleClient, getElementById, rotatePointsByElement, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPolylineHitRectangle, rotateAntiPointsByElement, rotatePoints, depthFirstRecursion, PlaitBoard, getIsRecursionFunc, idCreator, catmullRomFitting, setStrokeLinecap, findElements, createMask, createRect, getSelectedElements, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, setPathStrokeLinecap, getCrossingPointsBetweenEllipseAndSegment, SNAPPING_STROKE_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, Direction, hasValidAngle, Path, PlaitNode, toViewBoxPoint, toHostPoint, isSelectionMoving, RgbaToHEX, PlaitElement, getHitElementByPoint, getRectangleByElements, getSelectionAngle, rotatedDataPoints, isAxisChangedByAngle, getRectangleByAngle, getSnapRectangles, getTripleAxis, getMinPointDelta, SNAP_TOLERANCE, drawPointSnapLines, drawSolidLines, preventTouchMove, createClipboardContext, WritableClipboardType, addClipboardContext, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER, isMainPointer, throttleRAF, getAngleBetweenPoints, degreesToRadians, normalizeAngle, rotateElements, MERGING, ROTATE_HANDLE_CLASS_NAME, SELECTION_RECTANGLE_CLASS_NAME } from '@plait/core';
2
+ import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, DEFAULT_ROUTE_MARGIN, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator, RESIZE_HANDLE_DIAMETER, getPointOnPolyline, TRANSPARENT, getRectangleResizeHandleRefs, getRotatedResizeCursorClassByAngle, ROTATE_HANDLE_DISTANCE_TO_ELEMENT, ROTATE_HANDLE_SIZE, getMemorizedLatest, memorizeLatest, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getDirectionByVector, getOppositeDirection, getDirectionFactor, rotateVector, getDirectionByPointOfRectangle, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, normalizeShapePoints, getFirstTextEditor, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isCornerHandle, getIndexByResizeHandle, resetPointsAfterResize, getFirstTextManage, withResize, drawHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, getDirectionFactorByDirectionComponent, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, isResizingByCondition, getRatioByPoint, ImageGenerator, ResizeHandle, addRotating, removeRotating, drawRotateHandle } from '@plait/common';
3
3
  import { Alignment, buildText, DEFAULT_FONT_SIZE, getTextSize, AlignEditor, TextManage } from '@plait/text';
4
4
  import { pointsOnBezierCurves } from 'points-on-curve';
5
5
  import * as i0 from '@angular/core';
@@ -30,6 +30,7 @@ var BasicShapes;
30
30
  BasicShapes["twoWayArrow"] = "twoWayArrow";
31
31
  BasicShapes["comment"] = "comment";
32
32
  BasicShapes["roundComment"] = "roundComment";
33
+ BasicShapes["cloud"] = "cloud";
33
34
  })(BasicShapes || (BasicShapes = {}));
34
35
  var FlowchartSymbols;
35
36
  (function (FlowchartSymbols) {
@@ -44,6 +45,10 @@ var FlowchartSymbols;
44
45
  FlowchartSymbols["merge"] = "merge";
45
46
  FlowchartSymbols["delay"] = "delay";
46
47
  FlowchartSymbols["storedData"] = "storedData";
48
+ FlowchartSymbols["or"] = "or";
49
+ FlowchartSymbols["summingJunction"] = "summingJunction";
50
+ FlowchartSymbols["predefinedProcess"] = "predefinedProcess";
51
+ FlowchartSymbols["offPage"] = "offPage";
47
52
  })(FlowchartSymbols || (FlowchartSymbols = {}));
48
53
  const PlaitGeometry = {};
49
54
 
@@ -66,6 +71,12 @@ const DefaultBasicShapeProperty = {
66
71
  strokeColor: '#333',
67
72
  strokeWidth: 2
68
73
  };
74
+ const DefaultCloudShapeProperty = {
75
+ width: 120,
76
+ height: 100,
77
+ strokeColor: '#333',
78
+ strokeWidth: 2
79
+ };
69
80
  const DefaultTextProperty = {
70
81
  width: 36,
71
82
  height: 20,
@@ -109,7 +120,11 @@ const DefaultFlowchartPropertyMap = {
109
120
  [FlowchartSymbols.manualLoop]: DefaultFlowchartProperty,
110
121
  [FlowchartSymbols.merge]: DefaultMergeProperty,
111
122
  [FlowchartSymbols.delay]: DefaultFlowchartProperty,
112
- [FlowchartSymbols.storedData]: DefaultFlowchartProperty
123
+ [FlowchartSymbols.storedData]: DefaultFlowchartProperty,
124
+ [FlowchartSymbols.or]: DefaultConnectorProperty,
125
+ [FlowchartSymbols.summingJunction]: DefaultConnectorProperty,
126
+ [FlowchartSymbols.predefinedProcess]: DefaultFlowchartProperty,
127
+ [FlowchartSymbols.offPage]: DefaultFlowchartProperty
113
128
  };
114
129
  const LINE_HIT_GEOMETRY_BUFFER = 10;
115
130
  const LINE_SNAPPING_BUFFER = 6;
@@ -950,6 +965,14 @@ const traverseDrawShapes = (board, callback) => {
950
965
  }
951
966
  }, getIsRecursionFunc(board), true);
952
967
  };
968
+ const getRotateHandleRectangle = (rectangle) => {
969
+ return {
970
+ x: rectangle.x - ROTATE_HANDLE_DISTANCE_TO_ELEMENT - ROTATE_HANDLE_SIZE,
971
+ y: rectangle.y + rectangle.height + ROTATE_HANDLE_DISTANCE_TO_ELEMENT,
972
+ width: ROTATE_HANDLE_SIZE,
973
+ height: ROTATE_HANDLE_SIZE
974
+ };
975
+ };
953
976
 
954
977
  const SHAPE_MAX_LENGTH = 6;
955
978
  const memorizedShape = new WeakMap();
@@ -1158,6 +1181,9 @@ const drawLine = (board, element) => {
1158
1181
  }
1159
1182
  const id = idCreator();
1160
1183
  line.setAttribute('mask', `url(#${id})`);
1184
+ if (element.strokeStyle === StrokeStyle.dotted) {
1185
+ setStrokeLinecap(line, 'round');
1186
+ }
1161
1187
  lineG.appendChild(line);
1162
1188
  const { mask, maskTargetFillRect } = drawMask(board, element, id);
1163
1189
  lineG.appendChild(mask);
@@ -1457,44 +1483,55 @@ const DiamondEngine = createPolygonEngine({
1457
1483
  }
1458
1484
  });
1459
1485
 
1460
- const EllipseEngine = {
1461
- draw(board, rectangle, options) {
1462
- const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1463
- const rs = PlaitBoard.getRoughSVG(board);
1464
- return rs.ellipse(centerPoint[0], centerPoint[1], rectangle.width, rectangle.height, { ...options, fillStyle: 'solid' });
1465
- },
1466
- isInsidePoint(rectangle, point) {
1467
- const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1468
- return isPointInEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
1469
- },
1470
- getCornerPoints(rectangle) {
1471
- return RectangleClient.getEdgeCenterPoints(rectangle);
1472
- },
1473
- getNearestPoint(rectangle, point) {
1474
- const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1475
- return getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
1476
- },
1477
- getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
1478
- const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1479
- const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1480
- const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
1481
- const a = rectangle.width / 2;
1482
- const b = rectangle.height / 2;
1483
- const slope = getEllipseTangentSlope(point[0], point[1], a, b);
1484
- const vector = getVectorFromPointAndSlope(point[0], point[1], slope);
1485
- return vector;
1486
- },
1487
- getConnectorPoints(rectangle) {
1488
- return RectangleClient.getEdgeCenterPoints(rectangle);
1489
- },
1490
- getTextRectangle(element) {
1491
- const rectangle = getTextRectangle(element);
1492
- const width = rectangle.width;
1493
- rectangle.width = (rectangle.width * 3) / 4;
1494
- rectangle.x += width / 8;
1495
- return rectangle;
1486
+ function createEllipseEngine(createOptions) {
1487
+ const engine = {
1488
+ draw(board, rectangle, options) {
1489
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1490
+ const rs = PlaitBoard.getRoughSVG(board);
1491
+ return rs.ellipse(centerPoint[0], centerPoint[1], rectangle.width, rectangle.height, { ...options, fillStyle: 'solid' });
1492
+ },
1493
+ isInsidePoint(rectangle, point) {
1494
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1495
+ return isPointInEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
1496
+ },
1497
+ getCornerPoints(rectangle) {
1498
+ return RectangleClient.getEdgeCenterPoints(rectangle);
1499
+ },
1500
+ getNearestPoint(rectangle, point) {
1501
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1502
+ return getNearestPointBetweenPointAndEllipse(point, centerPoint, rectangle.width / 2, rectangle.height / 2);
1503
+ },
1504
+ getTangentVectorByConnectionPoint(rectangle, pointOfRectangle) {
1505
+ const connectionPoint = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
1506
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
1507
+ const point = [connectionPoint[0] - centerPoint[0], -(connectionPoint[1] - centerPoint[1])];
1508
+ const a = rectangle.width / 2;
1509
+ const b = rectangle.height / 2;
1510
+ const slope = getEllipseTangentSlope(point[0], point[1], a, b);
1511
+ const vector = getVectorFromPointAndSlope(point[0], point[1], slope);
1512
+ return vector;
1513
+ },
1514
+ getConnectorPoints(rectangle) {
1515
+ return RectangleClient.getEdgeCenterPoints(rectangle);
1516
+ },
1517
+ getTextRectangle(element) {
1518
+ const rectangle = getTextRectangle(element);
1519
+ const width = rectangle.width;
1520
+ rectangle.width = (rectangle.width * 3) / 4;
1521
+ rectangle.x += width / 8;
1522
+ return rectangle;
1523
+ }
1524
+ };
1525
+ if (createOptions?.draw) {
1526
+ engine.draw = createOptions.draw;
1496
1527
  }
1497
- };
1528
+ if (createOptions?.getTextRectangle) {
1529
+ engine.getTextRectangle = createOptions.getTextRectangle;
1530
+ }
1531
+ return engine;
1532
+ }
1533
+
1534
+ const EllipseEngine = createEllipseEngine();
1498
1535
  function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation = 0) {
1499
1536
  const rectangleClient = {
1500
1537
  x: center[0] - rx,
@@ -2282,6 +2319,176 @@ const StoredDataEngine = {
2282
2319
  }
2283
2320
  };
2284
2321
 
2322
+ const PredefinedProcessEngine = {
2323
+ draw(board, rectangle, options) {
2324
+ const rs = PlaitBoard.getRoughSVG(board);
2325
+ const shape = rs.path(`M${rectangle.x} ${rectangle.y} H${rectangle.x + rectangle.width} V${rectangle.y + rectangle.height} H${rectangle.x} Z M${rectangle.x + rectangle.width * 0.06} ${rectangle.y} L${rectangle.x + rectangle.width * 0.06} ${rectangle.y +
2326
+ rectangle.height} M${rectangle.x + rectangle.width - rectangle.width * 0.06} ${rectangle.y} L${rectangle.x +
2327
+ rectangle.width -
2328
+ rectangle.width * 0.06} ${rectangle.y + rectangle.height}`, { ...options, fillStyle: 'solid' });
2329
+ setStrokeLinecap(shape, 'round');
2330
+ return shape;
2331
+ },
2332
+ isInsidePoint(rectangle, point) {
2333
+ const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
2334
+ return RectangleClient.isHit(rectangle, rangeRectangle);
2335
+ },
2336
+ getCornerPoints(rectangle) {
2337
+ return RectangleClient.getCornerPoints(rectangle);
2338
+ },
2339
+ getNearestPoint(rectangle, point) {
2340
+ return getNearestPointBetweenPointAndSegments(point, RectangleEngine.getCornerPoints(rectangle));
2341
+ },
2342
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
2343
+ const corners = RectangleEngine.getCornerPoints(rectangle);
2344
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
2345
+ return getPolygonEdgeByConnectionPoint(corners, point);
2346
+ },
2347
+ getConnectorPoints(rectangle) {
2348
+ return RectangleClient.getEdgeCenterPoints(rectangle);
2349
+ },
2350
+ getTextRectangle: (element) => {
2351
+ const elementRectangle = RectangleClient.getRectangleByPoints(element.points);
2352
+ const strokeWidth = getStrokeWidthByElement(element);
2353
+ const height = element.textHeight;
2354
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2 - elementRectangle.width * 0.06 * 2;
2355
+ return {
2356
+ height,
2357
+ width: width > 0 ? width : 0,
2358
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + elementRectangle.width * 0.06,
2359
+ y: elementRectangle.y + (elementRectangle.height - height) / 2
2360
+ };
2361
+ }
2362
+ };
2363
+
2364
+ const getOffPagePoints = (rectangle) => {
2365
+ return [
2366
+ [rectangle.x, rectangle.y],
2367
+ [rectangle.x + rectangle.width, rectangle.y],
2368
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
2369
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
2370
+ [rectangle.x, rectangle.y + rectangle.height / 2]
2371
+ ];
2372
+ };
2373
+ const OffPageEngine = createPolygonEngine({
2374
+ getPolygonPoints: getOffPagePoints,
2375
+ getConnectorPoints: (rectangle) => {
2376
+ return RectangleClient.getEdgeCenterPoints(rectangle);
2377
+ },
2378
+ getTextRectangle: (element) => {
2379
+ const elementRectangle = RectangleClient.getRectangleByPoints(element.points);
2380
+ const strokeWidth = getStrokeWidthByElement(element);
2381
+ const height = element.textHeight;
2382
+ const width = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
2383
+ return {
2384
+ width: width > 0 ? width : 0,
2385
+ height: height,
2386
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth,
2387
+ y: elementRectangle.y + (elementRectangle.height - elementRectangle.height / 2 - height) / 2
2388
+ };
2389
+ }
2390
+ });
2391
+
2392
+ const CloudEngine = {
2393
+ draw(board, rectangle, options) {
2394
+ const rs = PlaitBoard.getRoughSVG(board);
2395
+ const divisionWidth = rectangle.width / 7;
2396
+ const divisionHeight = rectangle.height / 3.2;
2397
+ const xRadius = divisionWidth / 8.5;
2398
+ const yRadius = divisionHeight / 20;
2399
+ const svgElement = rs.path(`M ${rectangle.x + divisionWidth} ${rectangle.y + divisionHeight}
2400
+ A ${xRadius} ${yRadius * 1.2} 0 1 1 ${rectangle.x + divisionWidth * 2} ${rectangle.y + divisionHeight / 2}
2401
+ A ${xRadius} ${yRadius} 0 1 1 ${rectangle.x + divisionWidth * 4.2} ${rectangle.y + divisionHeight / 2.2}
2402
+ A ${xRadius} ${yRadius} 0 1 1 ${rectangle.x + divisionWidth * 5.8} ${rectangle.y + divisionHeight}
2403
+ A ${xRadius} ${yRadius * 1.3} 0 1 1 ${rectangle.x + divisionWidth * 6} ${rectangle.y + divisionHeight * 2.2}
2404
+ A ${xRadius} ${yRadius * 1.2} 0 1 1 ${rectangle.x + divisionWidth * 5} ${rectangle.y + divisionHeight * 2.8}
2405
+ A ${xRadius} ${yRadius / 1.2} 0 1 1 ${rectangle.x + divisionWidth * 2.8} ${rectangle.y + divisionHeight * 2.8}
2406
+ A ${xRadius} ${yRadius} 0 1 1 ${rectangle.x + divisionWidth} ${rectangle.y + divisionHeight * 2.2}
2407
+ A ${xRadius} ${yRadius * 1.42} 0 1 1 ${rectangle.x + divisionWidth} ${rectangle.y + divisionHeight}
2408
+ Z`, { ...options, fillStyle: 'solid' });
2409
+ setPathStrokeLinecap(svgElement, 'round');
2410
+ return svgElement;
2411
+ },
2412
+ isInsidePoint(rectangle, point) {
2413
+ const rangeRectangle = RectangleClient.getRectangleByPoints([point, point]);
2414
+ return RectangleClient.isHit(rectangle, rangeRectangle);
2415
+ },
2416
+ getCornerPoints(rectangle) {
2417
+ return RectangleClient.getCornerPoints(rectangle);
2418
+ },
2419
+ getNearestPoint(rectangle, point) {
2420
+ return getNearestPointBetweenPointAndSegments(point, CloudEngine.getCornerPoints(rectangle));
2421
+ },
2422
+ getEdgeByConnectionPoint(rectangle, pointOfRectangle) {
2423
+ const corners = CloudEngine.getCornerPoints(rectangle);
2424
+ const point = RectangleClient.getConnectionPoint(rectangle, pointOfRectangle);
2425
+ return getPolygonEdgeByConnectionPoint(corners, point);
2426
+ },
2427
+ getConnectorPoints(rectangle) {
2428
+ return RectangleClient.getEdgeCenterPoints(rectangle);
2429
+ },
2430
+ getTextRectangle(element) {
2431
+ const elementRectangle = RectangleClient.getRectangleByPoints(element.points);
2432
+ const strokeWidth = getStrokeWidthByElement(element);
2433
+ const height = element.textHeight;
2434
+ const originWidth = elementRectangle.width - ShapeDefaultSpace.rectangleAndText * 2 - strokeWidth * 2;
2435
+ const width = originWidth / 1.5;
2436
+ return {
2437
+ height,
2438
+ width: width > 0 ? width : 0,
2439
+ x: elementRectangle.x + ShapeDefaultSpace.rectangleAndText + strokeWidth + originWidth / 6,
2440
+ y: elementRectangle.y + elementRectangle.height / 6 + ((elementRectangle.height * 4) / 6 - height) / 2
2441
+ };
2442
+ }
2443
+ };
2444
+
2445
+ const OrEngine = createEllipseEngine({
2446
+ draw(board, rectangle, options) {
2447
+ const rs = PlaitBoard.getRoughSVG(board);
2448
+ const rx = rectangle.width / 2;
2449
+ const ry = rectangle.height / 2;
2450
+ const startPoint = [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2];
2451
+ return rs.path(`M${startPoint[0]} ${startPoint[1]}
2452
+ A${rx},${ry} 0 1,1 ${startPoint[0]} ${startPoint[1] - 0.01}
2453
+ M${rectangle.x} ${rectangle.y + rectangle.height / 2}
2454
+ L${rectangle.x + rectangle.width} ${rectangle.y + rectangle.height / 2}
2455
+ M${rectangle.x + rectangle.width / 2} ${rectangle.y}
2456
+ L${rectangle.x + rectangle.width / 2} ${rectangle.y + rectangle.height}
2457
+ `, { ...options, fillStyle: 'solid' });
2458
+ },
2459
+ getTextRectangle(element) {
2460
+ const rectangle = getTextRectangle(element);
2461
+ rectangle.width = 0;
2462
+ rectangle.height = 0;
2463
+ return rectangle;
2464
+ }
2465
+ });
2466
+
2467
+ const SummingJunctionEngine = createEllipseEngine({
2468
+ draw(board, rectangle, options) {
2469
+ const rs = PlaitBoard.getRoughSVG(board);
2470
+ const rx = rectangle.width / 2;
2471
+ const ry = rectangle.height / 2;
2472
+ const startPoint = [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2];
2473
+ const centerPoint = [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
2474
+ const line1Points = getCrossingPointsBetweenEllipseAndSegment([rectangle.x, rectangle.y], [rectangle.x + rectangle.width, rectangle.y + rectangle.height], centerPoint[0], centerPoint[1], rx, ry);
2475
+ const line2Points = getCrossingPointsBetweenEllipseAndSegment([rectangle.x + rectangle.width, rectangle.y], [rectangle.x, rectangle.y + rectangle.height], centerPoint[0], centerPoint[1], rx, ry);
2476
+ return rs.path(`M${startPoint[0]} ${startPoint[1]}
2477
+ A${rx},${ry} 0 1,1 ${startPoint[0]} ${startPoint[1] - 0.01}
2478
+ M${line1Points[0][0]} ${line1Points[0][1]}
2479
+ L${line1Points[1][0]} ${line1Points[1][1]}
2480
+ M${line2Points[0][0]} ${line2Points[0][1]}
2481
+ L${line2Points[1][0]} ${line2Points[1][1]}
2482
+ `, { ...options, fillStyle: 'solid' });
2483
+ },
2484
+ getTextRectangle(element) {
2485
+ const rectangle = getTextRectangle(element);
2486
+ rectangle.width = 0;
2487
+ rectangle.height = 0;
2488
+ return rectangle;
2489
+ }
2490
+ });
2491
+
2285
2492
  const ShapeEngineMap = {
2286
2493
  [BasicShapes.rectangle]: RectangleEngine,
2287
2494
  [BasicShapes.diamond]: DiamondEngine,
@@ -2303,6 +2510,7 @@ const ShapeEngineMap = {
2303
2510
  [BasicShapes.twoWayArrow]: TwoWayArrowEngine,
2304
2511
  [BasicShapes.comment]: CommentEngine,
2305
2512
  [BasicShapes.roundComment]: RoundCommentEngine,
2513
+ [BasicShapes.cloud]: CloudEngine,
2306
2514
  [FlowchartSymbols.process]: RectangleEngine,
2307
2515
  [FlowchartSymbols.decision]: DiamondEngine,
2308
2516
  [FlowchartSymbols.connector]: EllipseEngine,
@@ -2313,7 +2521,11 @@ const ShapeEngineMap = {
2313
2521
  [FlowchartSymbols.manualLoop]: ManualLoopEngine,
2314
2522
  [FlowchartSymbols.merge]: MergeEngine,
2315
2523
  [FlowchartSymbols.delay]: DelayEngine,
2316
- [FlowchartSymbols.storedData]: StoredDataEngine
2524
+ [FlowchartSymbols.storedData]: StoredDataEngine,
2525
+ [FlowchartSymbols.or]: OrEngine,
2526
+ [FlowchartSymbols.summingJunction]: SummingJunctionEngine,
2527
+ [FlowchartSymbols.predefinedProcess]: PredefinedProcessEngine,
2528
+ [FlowchartSymbols.offPage]: OffPageEngine
2317
2529
  };
2318
2530
  const getEngine = (shape) => {
2319
2531
  return ShapeEngineMap[shape];
@@ -2502,6 +2714,9 @@ const getDefaultGeometryProperty = (pointer) => {
2502
2714
  return getDefaultFlowchartProperty(pointer);
2503
2715
  }
2504
2716
  else {
2717
+ if (pointer === BasicShapes.cloud) {
2718
+ return DefaultCloudShapeProperty;
2719
+ }
2505
2720
  return DefaultBasicShapeProperty;
2506
2721
  }
2507
2722
  };
@@ -2553,7 +2768,14 @@ const getFillByElement = (board, element) => {
2553
2768
  return fill;
2554
2769
  };
2555
2770
  const getLineDashByElement = (element) => {
2556
- return element.strokeStyle === 'dashed' ? [8, 8 + getStrokeWidthByElement(element)] : undefined;
2771
+ switch (element.strokeStyle) {
2772
+ case StrokeStyle.dashed:
2773
+ return [8, 8 + getStrokeWidthByElement(element)];
2774
+ case StrokeStyle.dotted:
2775
+ return [0, 4 + getStrokeWidthByElement(element)];
2776
+ default:
2777
+ return undefined;
2778
+ }
2557
2779
  };
2558
2780
  const getStrokeStyleByElement = (element) => {
2559
2781
  return element.strokeStyle || StrokeStyle.solid;
@@ -2747,6 +2969,7 @@ var StrokeStyle;
2747
2969
  (function (StrokeStyle) {
2748
2970
  StrokeStyle["solid"] = "solid";
2749
2971
  StrokeStyle["dashed"] = "dashed";
2972
+ StrokeStyle["dotted"] = "dotted";
2750
2973
  })(StrokeStyle || (StrokeStyle = {}));
2751
2974
  var MemorizeKey;
2752
2975
  (function (MemorizeKey) {
@@ -3095,9 +3318,8 @@ class GeometryComponent extends CommonPluginElement {
3095
3318
  get textManage() {
3096
3319
  return this.getTextManages()[0];
3097
3320
  }
3098
- constructor(viewContainerRef, cdr) {
3321
+ constructor(cdr) {
3099
3322
  super(cdr);
3100
- this.viewContainerRef = viewContainerRef;
3101
3323
  this.cdr = cdr;
3102
3324
  this.destroy$ = new Subject();
3103
3325
  }
@@ -3139,7 +3361,7 @@ class GeometryComponent extends CommonPluginElement {
3139
3361
  ngOnInit() {
3140
3362
  super.ngOnInit();
3141
3363
  this.initializeGenerator();
3142
- this.shapeGenerator.processDrawing(this.element, this.g);
3364
+ this.shapeGenerator.processDrawing(this.element, this.getElementG());
3143
3365
  this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
3144
3366
  this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3145
3367
  selected: this.selected
@@ -3149,7 +3371,7 @@ class GeometryComponent extends CommonPluginElement {
3149
3371
  onContextChanged(value, previous) {
3150
3372
  const isChangeTheme = this.board.operations.find(op => op.type === 'set_theme');
3151
3373
  if (value.element !== previous.element || isChangeTheme) {
3152
- this.shapeGenerator.processDrawing(this.element, this.g);
3374
+ this.shapeGenerator.processDrawing(this.element, this.getElementG());
3153
3375
  this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), { selected: this.selected });
3154
3376
  this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3155
3377
  selected: this.selected
@@ -3173,7 +3395,7 @@ class GeometryComponent extends CommonPluginElement {
3173
3395
  }
3174
3396
  drawText() {
3175
3397
  this.textManage.draw(this.element.text);
3176
- this.g.append(this.textManage.g);
3398
+ this.getElementG().append(this.textManage.g);
3177
3399
  const centerPoint = RectangleClient.getCenterPoint(this.board.getRectangle(this.element));
3178
3400
  this.textManage.updateAngle(centerPoint, this.element.angle);
3179
3401
  }
@@ -3224,7 +3446,7 @@ class GeometryComponent extends CommonPluginElement {
3224
3446
  this.activeGenerator.destroy();
3225
3447
  this.lineAutoCompleteGenerator.destroy();
3226
3448
  }
3227
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GeometryComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3449
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GeometryComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3228
3450
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.2.4", type: GeometryComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3229
3451
  }
3230
3452
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GeometryComponent, decorators: [{
@@ -3235,7 +3457,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
3235
3457
  changeDetection: ChangeDetectionStrategy.OnPush,
3236
3458
  standalone: true
3237
3459
  }]
3238
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }] });
3460
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
3239
3461
 
3240
3462
  class LineActiveGenerator extends Generator {
3241
3463
  constructor() {
@@ -3311,9 +3533,8 @@ class LineActiveGenerator extends Generator {
3311
3533
  const debugKey$2 = 'debug:plait:line-turning';
3312
3534
  const debugGenerator$2 = createDebugGenerator(debugKey$2);
3313
3535
  class LineComponent extends CommonPluginElement {
3314
- constructor(viewContainerRef, cdr) {
3536
+ constructor(cdr) {
3315
3537
  super(cdr);
3316
- this.viewContainerRef = viewContainerRef;
3317
3538
  this.cdr = cdr;
3318
3539
  this.destroy$ = new Subject();
3319
3540
  this.boundedElements = {};
@@ -3325,7 +3546,7 @@ class LineComponent extends CommonPluginElement {
3325
3546
  }
3326
3547
  ngOnInit() {
3327
3548
  this.initializeGenerator();
3328
- this.shapeGenerator.processDrawing(this.element, this.g);
3549
+ this.shapeGenerator.processDrawing(this.element, this.getElementG());
3329
3550
  const linePoints = getLinePoints(this.board, this.element);
3330
3551
  this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3331
3552
  selected: this.selected,
@@ -3359,7 +3580,7 @@ class LineComponent extends CommonPluginElement {
3359
3580
  const isChangeTheme = this.board.operations.find(op => op.type === 'set_theme');
3360
3581
  const linePoints = getLinePoints(this.board, this.element);
3361
3582
  if (value.element !== previous.element || isChangeTheme) {
3362
- this.shapeGenerator.processDrawing(this.element, this.g);
3583
+ this.shapeGenerator.processDrawing(this.element, this.getElementG());
3363
3584
  this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3364
3585
  selected: this.selected,
3365
3586
  linePoints
@@ -3377,7 +3598,7 @@ class LineComponent extends CommonPluginElement {
3377
3598
  }
3378
3599
  }
3379
3600
  if (isBoundedElementsChanged) {
3380
- this.shapeGenerator.processDrawing(this.element, this.g);
3601
+ this.shapeGenerator.processDrawing(this.element, this.getElementG());
3381
3602
  this.activeGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
3382
3603
  selected: this.selected,
3383
3604
  linePoints
@@ -3400,7 +3621,7 @@ class LineComponent extends CommonPluginElement {
3400
3621
  if (this.element.texts?.length) {
3401
3622
  this.getTextManages().forEach((manage, index) => {
3402
3623
  manage.draw(this.element.texts[index].text);
3403
- this.g.append(manage.g);
3624
+ this.getElementG().append(manage.g);
3404
3625
  });
3405
3626
  }
3406
3627
  }
@@ -3457,7 +3678,7 @@ class LineComponent extends CommonPluginElement {
3457
3678
  this.destroy$.complete();
3458
3679
  this.destroyTextManages();
3459
3680
  }
3460
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: LineComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3681
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: LineComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3461
3682
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.2.4", type: LineComponent, isStandalone: true, selector: "plait-draw-line", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3462
3683
  }
3463
3684
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: LineComponent, decorators: [{
@@ -3468,7 +3689,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
3468
3689
  changeDetection: ChangeDetectionStrategy.OnPush,
3469
3690
  standalone: true
3470
3691
  }]
3471
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }] });
3692
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
3472
3693
 
3473
3694
  const withDrawHotkey = (board) => {
3474
3695
  const { keyDown, dblClick } = board;
@@ -3503,583 +3724,388 @@ const withDrawHotkey = (board) => {
3503
3724
  return board;
3504
3725
  };
3505
3726
 
3506
- const withGeometryCreateByDrag = (board) => {
3507
- const { pointerMove, globalPointerUp } = board;
3508
- let geometryShapeG = null;
3509
- let temporaryElement = null;
3510
- let fakeCreateTextRef = null;
3511
- board.pointerMove = (event) => {
3512
- geometryShapeG?.remove();
3513
- geometryShapeG = createG();
3514
- const geometryGenerator = new GeometryShapeGenerator(board);
3515
- const geometryPointers = getGeometryPointers();
3516
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
3517
- const dragMode = isGeometryPointer && isDndMode(board);
3518
- const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3519
- const pointer = PlaitBoard.getPointer(board);
3520
- if (dragMode) {
3521
- const memorizedLatest = getMemorizedLatestByPointer(pointer);
3522
- if (pointer === BasicShapes.text) {
3523
- const property = getTextShapeProperty(board, DefaultTextProperty.text, memorizedLatest.textProperties['font-size']);
3524
- const points = RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(movingPoint, property.width, property.height));
3525
- temporaryElement = createTextElement(board, points);
3526
- if (!fakeCreateTextRef) {
3527
- const textManage = new TextManage(board, PlaitBoard.getComponent(board).viewContainerRef, {
3528
- getRectangle: () => {
3529
- return getTextRectangle(temporaryElement);
3530
- }
3531
- });
3532
- PlaitBoard.getComponent(board)
3533
- .viewContainerRef.injector.get(NgZone)
3534
- .run(() => {
3535
- textManage.draw(temporaryElement.text);
3536
- });
3537
- fakeCreateTextRef = {
3538
- g: createG(),
3539
- textManage
3540
- };
3541
- PlaitBoard.getHost(board).append(fakeCreateTextRef.g);
3542
- fakeCreateTextRef.g.append(textManage.g);
3543
- }
3544
- else {
3545
- fakeCreateTextRef.textManage.updateRectangle();
3546
- fakeCreateTextRef.g.append(fakeCreateTextRef.textManage.g);
3547
- }
3548
- }
3549
- else {
3550
- const points = getDefaultGeometryPoints(pointer, movingPoint);
3551
- temporaryElement = createDefaultGeometry(board, points, pointer);
3552
- geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
3553
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
3554
- }
3555
- }
3556
- pointerMove(event);
3557
- };
3558
- board.globalPointerUp = (event) => {
3559
- const geometryPointers = getGeometryPointers();
3560
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
3561
- const dragMode = isGeometryPointer && isDndMode(board);
3562
- if (dragMode && temporaryElement) {
3563
- insertElement(board, temporaryElement);
3564
- fakeCreateTextRef?.textManage.destroy();
3565
- fakeCreateTextRef?.g.remove();
3566
- fakeCreateTextRef = null;
3567
- }
3568
- geometryShapeG?.remove();
3569
- geometryShapeG = null;
3570
- preventTouchMove(board, event, false);
3571
- globalPointerUp(event);
3727
+ const debugKey$1 = 'debug:plait:resize-for-rotation';
3728
+ const debugGenerator$1 = createDebugGenerator(debugKey$1);
3729
+ function withDrawResize(board) {
3730
+ const { afterChange, drawActiveRectangle } = board;
3731
+ let snapG;
3732
+ let handleG;
3733
+ let needCustomActiveRectangle = false;
3734
+ let resizeActivePoints = null;
3735
+ const canResize = () => {
3736
+ const elements = getSelectedElements(board);
3737
+ return elements.length > 1 && elements.every(el => PlaitDrawElement.isDrawElement(el));
3572
3738
  };
3573
- return board;
3574
- };
3575
- const withGeometryCreateByDrawing = (board) => {
3576
- const { pointerDown, pointerMove, pointerUp, keyDown, keyUp } = board;
3577
- let start = null;
3578
- let geometryShapeG = null;
3579
- let temporaryElement = null;
3580
- let isShift = false;
3581
- board.keyDown = (event) => {
3582
- isShift = isKeyHotkey('shift', event);
3583
- keyDown(event);
3584
- };
3585
- board.keyUp = (event) => {
3586
- isShift = false;
3587
- keyUp(event);
3588
- };
3589
- board.pointerDown = (event) => {
3590
- const geometryPointers = getGeometryPointers();
3591
- const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
3592
- if (!PlaitBoard.isReadonly(board) && isGeometryPointer && isDrawingMode(board)) {
3593
- const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3594
- start = point;
3595
- const pointer = PlaitBoard.getPointer(board);
3596
- preventTouchMove(board, event, true);
3597
- if (pointer === BasicShapes.text) {
3598
- const memorizedLatest = getMemorizedLatestByPointer(pointer);
3599
- const property = getTextShapeProperty(board, DefaultTextProperty.text, memorizedLatest.textProperties['font-size']);
3600
- const points = RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(point, property.width, property.height));
3601
- const textElement = createTextElement(board, points);
3602
- insertElement(board, textElement);
3603
- start = null;
3739
+ const options = {
3740
+ key: 'draw-elements',
3741
+ canResize,
3742
+ hitTest: (point) => {
3743
+ const elements = getSelectedElements(board);
3744
+ const boundingRectangle = getRectangleByElements(board, elements, false);
3745
+ const angle = getSelectionAngle(elements);
3746
+ const handleRef = getHitRectangleResizeHandleRef(board, boundingRectangle, point, angle);
3747
+ if (handleRef) {
3748
+ return {
3749
+ element: elements,
3750
+ rectangle: boundingRectangle,
3751
+ handle: handleRef.handle,
3752
+ cursorClass: handleRef.cursorClass
3753
+ };
3754
+ }
3755
+ return null;
3756
+ },
3757
+ onResize: (resizeRef, resizeState) => {
3758
+ snapG?.remove();
3759
+ debugGenerator$1.isDebug() && debugGenerator$1.clear();
3760
+ const isFromCorner = isCornerHandle(board, resizeRef.handle);
3761
+ const isAspectRatio = resizeState.isShift || isFromCorner;
3762
+ const centerPoint = RectangleClient.getCenterPoint(resizeRef.rectangle);
3763
+ const handleIndex = getIndexByResizeHandle(resizeRef.handle);
3764
+ const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, handleIndex, resizeRef.rectangle);
3765
+ const angle = getSelectionAngle(resizeRef.element);
3766
+ let bulkRotationRef;
3767
+ if (angle) {
3768
+ bulkRotationRef = {
3769
+ angle: angle,
3770
+ offsetX: 0,
3771
+ offsetY: 0,
3772
+ newCenterPoint: [0, 0]
3773
+ };
3774
+ const [rotatedStartPoint, rotateEndPoint] = rotatePoints([resizeState.startPoint, resizeState.endPoint], centerPoint, -bulkRotationRef.angle);
3775
+ resizeState.startPoint = rotatedStartPoint;
3776
+ resizeState.endPoint = rotateEndPoint;
3777
+ }
3778
+ const resizeSnapRefOptions = getSnapResizingRefOptions(board, resizeRef, resizeState, {
3779
+ originPoint,
3780
+ handlePoint
3781
+ }, isAspectRatio, isFromCorner);
3782
+ const resizeSnapRef = getSnapResizingRef(board, resizeRef.element, resizeSnapRefOptions);
3783
+ resizeActivePoints = resizeSnapRef.activePoints;
3784
+ snapG = resizeSnapRef.snapG;
3785
+ PlaitBoard.getElementActiveHost(board).append(snapG);
3786
+ if (bulkRotationRef) {
3787
+ const boundingBoxCornerPoints = RectangleClient.getPoints(resizeRef.rectangle);
3788
+ const resizedBoundingBoxCornerPoints = boundingBoxCornerPoints.map(p => {
3789
+ return movePointByZoomAndOriginPoint(p, originPoint, resizeSnapRef.xZoom, resizeSnapRef.yZoom);
3790
+ });
3791
+ const newBoundingBox = RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints);
3792
+ debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(board, newBoundingBox, { stroke: 'blue' });
3793
+ const newBoundingBoxCenter = RectangleClient.getCenterPoint(newBoundingBox);
3794
+ const adjustedNewBoundingBoxPoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(boundingBoxCornerPoints), RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints), centerPoint, newBoundingBoxCenter, bulkRotationRef.angle);
3795
+ const newCenter = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(adjustedNewBoundingBoxPoints));
3796
+ bulkRotationRef = Object.assign(bulkRotationRef, {
3797
+ offsetX: newCenter[0] - newBoundingBoxCenter[0],
3798
+ offsetY: newCenter[1] - newBoundingBoxCenter[1],
3799
+ newCenterPoint: newCenter
3800
+ });
3801
+ debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(board, adjustedNewBoundingBoxPoints);
3802
+ }
3803
+ resizeRef.element.forEach(target => {
3804
+ const path = PlaitBoard.findPath(board, target);
3805
+ let points;
3806
+ if (bulkRotationRef) {
3807
+ const reversedPoints = rotatedDataPoints(target.points, centerPoint, -bulkRotationRef.angle);
3808
+ points = reversedPoints.map((p) => {
3809
+ return movePointByZoomAndOriginPoint(p, originPoint, resizeSnapRef.xZoom, resizeSnapRef.yZoom);
3810
+ });
3811
+ const adjustTargetPoints = points.map(p => [
3812
+ p[0] + bulkRotationRef.offsetX,
3813
+ p[1] + bulkRotationRef.offsetY
3814
+ ]);
3815
+ points = rotatedDataPoints(adjustTargetPoints, bulkRotationRef.newCenterPoint, bulkRotationRef.angle);
3816
+ }
3817
+ else {
3818
+ if (hasValidAngle(target)) {
3819
+ needCustomActiveRectangle = true;
3820
+ }
3821
+ if (hasValidAngle(target) && isAxisChangedByAngle(target.angle)) {
3822
+ points = getResizePointsByOtherwiseAxis(board, target.points, originPoint, resizeSnapRef.xZoom, resizeSnapRef.yZoom);
3823
+ }
3824
+ else {
3825
+ points = target.points.map(p => {
3826
+ return movePointByZoomAndOriginPoint(p, originPoint, resizeSnapRef.xZoom, resizeSnapRef.yZoom);
3827
+ });
3828
+ }
3829
+ }
3830
+ if (PlaitDrawElement.isGeometry(target)) {
3831
+ const { height: textHeight } = getFirstTextManage(target).getSize();
3832
+ DrawTransforms.resizeGeometry(board, points, textHeight, path);
3833
+ }
3834
+ else if (PlaitDrawElement.isLine(target)) {
3835
+ Transforms.setNode(board, { points }, path);
3836
+ }
3837
+ else if (PlaitDrawElement.isImage(target)) {
3838
+ if (isAspectRatio) {
3839
+ Transforms.setNode(board, { points }, path);
3840
+ }
3841
+ else {
3842
+ // The image element does not follow the resize, but moves based on the center point.
3843
+ const targetRectangle = RectangleClient.getRectangleByPoints(target.points);
3844
+ const centerPoint = RectangleClient.getCenterPoint(targetRectangle);
3845
+ const newCenterPoint = movePointByZoomAndOriginPoint(centerPoint, originPoint, resizeSnapRef.xZoom, resizeSnapRef.yZoom);
3846
+ const newTargetRectangle = RectangleClient.getRectangleByCenterPoint(newCenterPoint, targetRectangle.width, targetRectangle.height);
3847
+ Transforms.setNode(board, { points: RectangleClient.getPoints(newTargetRectangle) }, path);
3848
+ }
3849
+ }
3850
+ });
3851
+ },
3852
+ afterResize: (resizeRef) => {
3853
+ snapG?.remove();
3854
+ snapG = null;
3855
+ if (needCustomActiveRectangle) {
3856
+ needCustomActiveRectangle = false;
3857
+ resizeActivePoints = null;
3858
+ const selectedElements = getSelectedElements(board);
3859
+ Transforms.addSelectionWithTemporaryElements(board, selectedElements);
3604
3860
  }
3605
3861
  }
3606
- pointerDown(event);
3607
3862
  };
3608
- board.pointerMove = (event) => {
3609
- geometryShapeG?.remove();
3610
- geometryShapeG = createG();
3611
- const geometryGenerator = new GeometryShapeGenerator(board);
3612
- const drawMode = !!start;
3613
- const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3614
- const pointer = PlaitBoard.getPointer(board);
3615
- if (drawMode && pointer !== BasicShapes.text) {
3616
- const points = normalizeShapePoints([start, movingPoint], isShift);
3617
- temporaryElement = createDefaultGeometry(board, points, pointer);
3618
- geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
3619
- PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
3863
+ withResize(board, options);
3864
+ board.afterChange = () => {
3865
+ afterChange();
3866
+ if (handleG) {
3867
+ handleG.remove();
3868
+ handleG = null;
3620
3869
  }
3621
- pointerMove(event);
3622
- };
3623
- board.pointerUp = (event) => {
3624
- const isDrawMode = !!start;
3625
- if (isDrawMode) {
3626
- const targetPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3627
- const { width, height } = RectangleClient.getRectangleByPoints([start, targetPoint]);
3628
- if (Math.hypot(width, height) === 0) {
3629
- const pointer = PlaitBoard.getPointer(board);
3630
- if (pointer !== BasicShapes.text) {
3631
- const points = getDefaultGeometryPoints(pointer, targetPoint);
3632
- temporaryElement = createDefaultGeometry(board, points, pointer);
3633
- }
3870
+ if (canResize() && !isSelectionMoving(board)) {
3871
+ handleG = createG();
3872
+ const elements = getSelectedElements(board);
3873
+ const boundingRectangle = needCustomActiveRectangle
3874
+ ? RectangleClient.getRectangleByPoints(resizeActivePoints)
3875
+ : getRectangleByElements(board, elements, false);
3876
+ let corners = RectangleClient.getCornerPoints(boundingRectangle);
3877
+ const angle = getSelectionAngle(elements);
3878
+ if (angle) {
3879
+ const centerPoint = RectangleClient.getCenterPoint(boundingRectangle);
3880
+ corners = rotatePoints(corners, centerPoint, angle);
3634
3881
  }
3882
+ corners.forEach(corner => {
3883
+ const g = drawHandle(board, corner);
3884
+ handleG && handleG.append(g);
3885
+ });
3886
+ PlaitBoard.getElementActiveHost(board).append(handleG);
3635
3887
  }
3636
- if (temporaryElement) {
3637
- insertElement(board, temporaryElement);
3888
+ };
3889
+ board.drawActiveRectangle = () => {
3890
+ if (needCustomActiveRectangle) {
3891
+ const rectangle = RectangleClient.getRectangleByPoints(resizeActivePoints);
3892
+ return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
3893
+ stroke: SELECTION_BORDER_COLOR,
3894
+ strokeWidth: ACTIVE_STROKE_WIDTH
3895
+ });
3638
3896
  }
3639
- geometryShapeG?.remove();
3640
- geometryShapeG = null;
3641
- start = null;
3642
- temporaryElement = null;
3643
- preventTouchMove(board, event, false);
3644
- pointerUp(event);
3897
+ return drawActiveRectangle();
3645
3898
  };
3646
3899
  return board;
3900
+ }
3901
+ const getResizeOriginPointAndHandlePoint = (board, handleIndex, rectangle) => {
3902
+ const symmetricHandleIndex = getSymmetricHandleIndex(board, handleIndex);
3903
+ const originPoint = getResizeHandlePointByIndex(rectangle, symmetricHandleIndex);
3904
+ const handlePoint = getResizeHandlePointByIndex(rectangle, handleIndex);
3905
+ return {
3906
+ originPoint,
3907
+ handlePoint
3908
+ };
3647
3909
  };
3648
-
3649
- const buildClipboardData = (board, elements, startPoint) => {
3650
- return elements.map(element => {
3651
- if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
3652
- const points = element.points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
3653
- return { ...element, points };
3910
+ const getResizeZoom = (resizeStartAndEnd, resizeOriginPoint, resizeHandlePoint, isFromCorner, isAspectRatio) => {
3911
+ const [startPoint, endPoint] = resizeStartAndEnd;
3912
+ let xZoom = 0;
3913
+ let yZoom = 0;
3914
+ if (isFromCorner) {
3915
+ if (isAspectRatio) {
3916
+ let normalizedOffsetX = Point.getOffsetX(startPoint, endPoint);
3917
+ xZoom = normalizedOffsetX / (resizeHandlePoint[0] - resizeOriginPoint[0]);
3918
+ yZoom = xZoom;
3654
3919
  }
3655
- if (PlaitDrawElement.isLine(element)) {
3656
- let source = { ...element.source };
3657
- let target = { ...element.target };
3658
- let points = [...element.points];
3659
- if (element.source.boundId) {
3660
- points[0] = getConnectionPoint(getElementById(board, element.source.boundId), element.source.connection);
3661
- if (!getElementById(board, element.source.boundId, elements)) {
3662
- delete source.boundId;
3663
- delete source.connection;
3664
- }
3920
+ else {
3921
+ let normalizedOffsetX = Point.getOffsetX(startPoint, endPoint);
3922
+ let normalizedOffsetY = Point.getOffsetY(startPoint, endPoint);
3923
+ xZoom = normalizedOffsetX / (resizeHandlePoint[0] - resizeOriginPoint[0]);
3924
+ yZoom = normalizedOffsetY / (resizeHandlePoint[1] - resizeOriginPoint[1]);
3925
+ }
3926
+ }
3927
+ else {
3928
+ const isHorizontal = Point.isHorizontal(resizeOriginPoint, resizeHandlePoint, 0.1) || false;
3929
+ let normalizedOffset = isHorizontal ? Point.getOffsetX(startPoint, endPoint) : Point.getOffsetY(startPoint, endPoint);
3930
+ let benchmarkOffset = isHorizontal ? resizeHandlePoint[0] - resizeOriginPoint[0] : resizeHandlePoint[1] - resizeOriginPoint[1];
3931
+ const zoom = normalizedOffset / benchmarkOffset;
3932
+ if (isAspectRatio) {
3933
+ xZoom = zoom;
3934
+ yZoom = zoom;
3935
+ }
3936
+ else {
3937
+ if (isHorizontal) {
3938
+ xZoom = zoom;
3665
3939
  }
3666
- if (element.target.boundId) {
3667
- points[points.length - 1] = getConnectionPoint(getElementById(board, element.target.boundId), element.target.connection);
3668
- if (!getElementById(board, element.target.boundId, elements)) {
3669
- delete target.boundId;
3670
- delete target.connection;
3671
- }
3940
+ else {
3941
+ yZoom = zoom;
3672
3942
  }
3673
- points = points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
3674
- return { ...element, points, source, target };
3675
3943
  }
3676
- return element;
3677
- });
3944
+ }
3945
+ return { xZoom, yZoom };
3678
3946
  };
3679
- const insertClipboardData = (board, elements, startPoint) => {
3680
- const lines = elements.filter(value => PlaitDrawElement.isLine(value));
3681
- const geometries = elements.filter(value => PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isImage(value));
3682
- geometries.forEach(element => {
3683
- const sourceLines = [];
3684
- const targetLines = [];
3685
- lines.forEach(line => {
3686
- if (PlaitLine.isBoundElementOfSource(line, element)) {
3687
- sourceLines.push(line);
3688
- }
3689
- if (PlaitLine.isBoundElementOfTarget(line, element)) {
3690
- targetLines.push(line);
3691
- }
3692
- });
3693
- element.id = idCreator();
3694
- // update lines
3695
- sourceLines.forEach(sourceLine => (sourceLine.source.boundId = element.id));
3696
- targetLines.forEach(targetLine => (targetLine.target.boundId = element.id));
3697
- element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
3698
- Transforms.insertNode(board, element, [board.children.length]);
3699
- });
3700
- lines.forEach(element => {
3701
- element.id = idCreator();
3702
- element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
3703
- Transforms.insertNode(board, element, [board.children.length]);
3947
+ const movePointByZoomAndOriginPoint = (p, resizeOriginPoint, xZoom, yZoom) => {
3948
+ const offsetX = (p[0] - resizeOriginPoint[0]) * xZoom;
3949
+ const offsetY = (p[1] - resizeOriginPoint[1]) * yZoom;
3950
+ return [p[0] + offsetX, p[1] + offsetY];
3951
+ };
3952
+ /**
3953
+ * 1. Rotate 90°
3954
+ * 2. Scale based on the rotated points
3955
+ * 3. Reverse rotate the scaled points by 90°
3956
+ */
3957
+ const getResizePointsByOtherwiseAxis = (board, points, resizeOriginPoint, xZoom, yZoom) => {
3958
+ const currentRectangle = RectangleClient.getRectangleByPoints(points);
3959
+ debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(board, currentRectangle, { stroke: 'black' });
3960
+ let resultPoints = points;
3961
+ resultPoints = rotatePoints(resultPoints, RectangleClient.getCenterPoint(currentRectangle), (1 / 2) * Math.PI);
3962
+ debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(board, resultPoints, { stroke: 'blue' });
3963
+ resultPoints = resultPoints.map(p => {
3964
+ return movePointByZoomAndOriginPoint(p, resizeOriginPoint, xZoom, yZoom);
3704
3965
  });
3705
- Transforms.addSelectionWithTemporaryElements(board, elements);
3966
+ debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(board, resultPoints);
3967
+ const newRectangle = RectangleClient.getRectangleByPoints(resultPoints);
3968
+ return rotatePoints(resultPoints, RectangleClient.getCenterPoint(newRectangle), -(1 / 2) * Math.PI);
3706
3969
  };
3707
3970
 
3708
- const withDrawFragment = (baseBoard) => {
3709
- const board = baseBoard;
3710
- const { getDeletedFragment, setFragment, insertFragment } = board;
3711
- board.getDeletedFragment = (data) => {
3712
- const drawElements = getSelectedDrawElements(board);
3713
- if (drawElements.length) {
3714
- const geometryElements = drawElements.filter(value => PlaitDrawElement.isGeometry(value));
3715
- const lineElements = drawElements.filter(value => PlaitDrawElement.isLine(value));
3716
- const imageElements = drawElements.filter(value => PlaitDrawElement.isImage(value));
3717
- const boundLineElements = [
3718
- ...getBoundedLineElements(board, geometryElements),
3719
- ...getBoundedLineElements(board, imageElements)
3720
- ].filter(line => !lineElements.includes(line));
3721
- data.push(...[
3722
- ...geometryElements,
3723
- ...lineElements,
3724
- ...imageElements,
3725
- ...boundLineElements.filter(line => !lineElements.includes(line))
3726
- ]);
3727
- }
3728
- return getDeletedFragment(data);
3971
+ const debugKey = 'debug:plait:point-for-geometry';
3972
+ const debugGenerator = createDebugGenerator(debugKey);
3973
+ const EQUAL_SPACING = 10;
3974
+ function getSnapResizingRefOptions(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
3975
+ const { originPoint, handlePoint } = resizeOriginPointAndHandlePoint;
3976
+ const resizePoints = [resizeState.startPoint, resizeState.endPoint];
3977
+ const { xZoom, yZoom } = getResizeZoom(resizePoints, originPoint, handlePoint, isFromCorner, isAspectRatio);
3978
+ let activeElements;
3979
+ let resizeOriginPoint = [];
3980
+ if (Array.isArray(resizeRef.element)) {
3981
+ activeElements = resizeRef.element;
3982
+ const rectangle = getRectangleByElements(board, resizeRef.element, false);
3983
+ resizeOriginPoint = RectangleClient.getPoints(rectangle);
3984
+ }
3985
+ else {
3986
+ activeElements = [resizeRef.element];
3987
+ resizeOriginPoint = resizeRef.element.points;
3988
+ }
3989
+ const points = resizeOriginPoint.map(p => {
3990
+ return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
3991
+ });
3992
+ const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(points), getSelectionAngle(activeElements)) ||
3993
+ RectangleClient.getRectangleByPoints(points);
3994
+ const resizeHandlePoint = movePointByZoomAndOriginPoint(handlePoint, originPoint, xZoom, yZoom);
3995
+ const [x, y] = getUnitVectorByPointAndPoint(originPoint, resizeHandlePoint);
3996
+ return {
3997
+ resizePoints,
3998
+ resizeOriginPoint,
3999
+ activeRectangle,
4000
+ originPoint,
4001
+ handlePoint,
4002
+ directionFactors: [getDirectionFactorByDirectionComponent(x), getDirectionFactorByDirectionComponent(y)],
4003
+ isAspectRatio,
4004
+ isFromCorner
3729
4005
  };
3730
- board.setFragment = (data, clipboardContext, rectangle, type) => {
3731
- const targetDrawElements = getSelectedDrawElements(board);
3732
- let boundLineElements = [];
3733
- if (targetDrawElements.length) {
3734
- if (type === 'cut') {
3735
- const geometryElements = targetDrawElements.filter(value => PlaitDrawElement.isGeometry(value));
3736
- const lineElements = targetDrawElements.filter(value => PlaitDrawElement.isLine(value));
3737
- boundLineElements = getBoundedLineElements(board, geometryElements).filter(line => !lineElements.includes(line));
3738
- }
3739
- const selectedElements = [...targetDrawElements, ...boundLineElements];
3740
- const elements = buildClipboardData(board, selectedElements, rectangle ? [rectangle.x, rectangle.y] : [0, 0]);
3741
- const text = getElementsText(selectedElements);
3742
- if (!clipboardContext) {
3743
- clipboardContext = createClipboardContext(WritableClipboardType.elements, elements, text);
3744
- }
3745
- else {
3746
- clipboardContext = addClipboardContext(clipboardContext, {
3747
- text,
3748
- type: WritableClipboardType.elements,
3749
- data: elements
3750
- });
3751
- }
3752
- }
3753
- setFragment(data, clipboardContext, rectangle, type);
4006
+ }
4007
+ function getSnapResizingRef(board, activeElements, resizeSnapOptions) {
4008
+ const snapG = createG();
4009
+ const snapRectangles = getSnapRectangles(board, activeElements);
4010
+ let snapLineDelta = getIsometricLineDelta(snapRectangles, resizeSnapOptions);
4011
+ if (snapLineDelta.deltaX === 0 && snapLineDelta.deltaY === 0) {
4012
+ snapLineDelta = getSnapPointDelta(snapRectangles, resizeSnapOptions);
4013
+ }
4014
+ const angle = getSelectionAngle(activeElements);
4015
+ const activePointAndZoom = getActivePointAndZoom(snapLineDelta, resizeSnapOptions, angle);
4016
+ const isometricLinesG = drawIsometricSnapLines(board, activePointAndZoom.activePoints, snapRectangles, resizeSnapOptions, angle);
4017
+ const pointLinesG = drawResizingPointSnapLines(board, activePointAndZoom.activePoints, snapRectangles, resizeSnapOptions, angle);
4018
+ snapG.append(isometricLinesG, pointLinesG);
4019
+ return { ...activePointAndZoom, ...snapLineDelta, snapG };
4020
+ }
4021
+ function getSnapPointDelta(snapRectangles, resizeSnapOptions) {
4022
+ let pointLineDelta = {
4023
+ deltaX: 0,
4024
+ deltaY: 0
3754
4025
  };
3755
- board.insertFragment = (data, clipboardData, targetPoint) => {
3756
- const selectedElements = getSelectedElements(board);
3757
- if (clipboardData?.files?.length) {
3758
- const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
3759
- const canInsertionImage = !getElementOfFocusedImage(board) && !(selectedElements.length === 1 && board.isImageBindingAllowed(selectedElements[0]));
3760
- if (acceptImageArray.includes(clipboardData.files[0].type) && canInsertionImage) {
3761
- const imageFile = clipboardData.files[0];
3762
- buildImage(board, imageFile, DEFAULT_IMAGE_WIDTH, imageItem => {
3763
- DrawTransforms.insertImage(board, imageItem, targetPoint);
3764
- });
3765
- return;
3766
- }
3767
- }
3768
- if (clipboardData?.elements?.length) {
3769
- const drawElements = clipboardData.elements?.filter(value => PlaitDrawElement.isDrawElement(value));
3770
- if (clipboardData.elements && clipboardData.elements.length > 0 && drawElements.length > 0) {
3771
- insertClipboardData(board, drawElements, targetPoint);
3772
- }
3773
- }
3774
- if (clipboardData?.text) {
3775
- if (!clipboardData.elements || clipboardData.elements.length === 0) {
3776
- // (* ̄︶ ̄)
3777
- const insertAsChildren = selectedElements.length === 1 && selectedElements[0].children;
3778
- const insertAsFreeText = !insertAsChildren;
3779
- if (insertAsFreeText) {
3780
- DrawTransforms.insertText(board, targetPoint, clipboardData.text);
3781
- return;
3782
- }
4026
+ const { isAspectRatio, activeRectangle, directionFactors } = resizeSnapOptions;
4027
+ const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
4028
+ const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
4029
+ if (drawHorizontal) {
4030
+ const xSnapAxis = getTripleAxis(activeRectangle, true);
4031
+ const pointX = directionFactors[0] === -1 ? xSnapAxis[0] : xSnapAxis[2];
4032
+ const deltaX = getMinPointDelta(snapRectangles, pointX, true);
4033
+ if (Math.abs(deltaX) < SNAP_TOLERANCE) {
4034
+ pointLineDelta.deltaX = deltaX;
4035
+ if (pointLineDelta.deltaX !== 0 && isAspectRatio) {
4036
+ pointLineDelta.deltaY = pointLineDelta.deltaX / (activeRectangle.width / activeRectangle.height);
4037
+ return pointLineDelta;
3783
4038
  }
3784
4039
  }
3785
- insertFragment(data, clipboardData, targetPoint);
3786
- };
3787
- return board;
3788
- };
3789
- const getBoundedLineElements = (board, plaitShapes) => {
3790
- const lines = getLines(board);
3791
- return lines.filter(line => plaitShapes.find(shape => PlaitLine.isBoundElementOfSource(line, shape) || PlaitLine.isBoundElementOfTarget(line, shape)));
3792
- };
3793
-
3794
- const withLineCreateByDraw = (board) => {
3795
- const { pointerDown, pointerMove, globalPointerUp } = board;
3796
- let start = null;
3797
- let sourceElement;
3798
- let lineShapeG = null;
3799
- let temporaryElement = null;
3800
- board.pointerDown = (event) => {
3801
- const linePointers = getLinePointers();
3802
- const isLinePointer = PlaitBoard.isInPointer(board, linePointers);
3803
- if (!PlaitBoard.isReadonly(board) && isLinePointer && isDrawingMode(board)) {
3804
- const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3805
- start = point;
3806
- const hitElement = getSnappingGeometry(board, point);
3807
- if (hitElement) {
3808
- sourceElement = hitElement;
4040
+ }
4041
+ if (drawVertical) {
4042
+ const ySnapAxis = getTripleAxis(activeRectangle, false);
4043
+ const pointY = directionFactors[1] === -1 ? ySnapAxis[0] : ySnapAxis[2];
4044
+ const deltaY = getMinPointDelta(snapRectangles, pointY, false);
4045
+ if (Math.abs(deltaY) < SNAP_TOLERANCE) {
4046
+ pointLineDelta.deltaY = deltaY;
4047
+ if (pointLineDelta.deltaY !== 0 && isAspectRatio) {
4048
+ pointLineDelta.deltaX = pointLineDelta.deltaY * (activeRectangle.width / activeRectangle.height);
4049
+ return pointLineDelta;
3809
4050
  }
3810
- preventTouchMove(board, event, true);
3811
- }
3812
- pointerDown(event);
3813
- };
3814
- board.pointerMove = (event) => {
3815
- lineShapeG?.remove();
3816
- lineShapeG = createG();
3817
- let movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3818
- if (start) {
3819
- const lineShape = PlaitBoard.getPointer(board);
3820
- temporaryElement = handleLineCreating(board, lineShape, start, movingPoint, sourceElement, lineShapeG);
3821
- }
3822
- pointerMove(event);
3823
- };
3824
- board.globalPointerUp = (event) => {
3825
- if (temporaryElement) {
3826
- Transforms.insertNode(board, temporaryElement, [board.children.length]);
3827
- clearSelectedElement(board);
3828
- addSelectedElement(board, temporaryElement);
3829
- BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
3830
4051
  }
3831
- lineShapeG?.remove();
3832
- lineShapeG = null;
3833
- sourceElement = null;
3834
- start = null;
3835
- temporaryElement = null;
3836
- preventTouchMove(board, event, false);
3837
- globalPointerUp(event);
3838
- };
3839
- return board;
3840
- };
3841
-
3842
- const debugKey$1 = 'debug:plait:align-for-geometry';
3843
- const debugGenerator$1 = createDebugGenerator(debugKey$1);
3844
- const ALIGN_TOLERANCE = 2;
3845
- const EQUAL_SPACING = 10;
3846
- const ALIGN_SPACING = 24;
3847
- class ResizeSnapReaction {
3848
- constructor(board, activeElements) {
3849
- this.board = board;
3850
- this.activeElements = activeElements;
3851
- this.alignRectangles = this.getAlignRectangle();
3852
- this.angle = getSelectionAngle(activeElements);
3853
- }
3854
- getAlignRectangle() {
3855
- const elements = findElements(this.board, {
3856
- match: element => this.board.isAlign(element) && !this.activeElements.some(item => item.id === element.id),
3857
- recursion: () => false,
3858
- isReverse: false
3859
- });
3860
- return elements.map(item => getRectangleByAngle(this.board.getRectangle(item), item.angle) || this.board.getRectangle(item));
3861
- }
3862
- getSnapRef(resizeAlignDelta, resizeSnapOptions) {
3863
- const { deltaX, deltaY } = resizeAlignDelta;
3864
- const { resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoints } = resizeSnapOptions;
3865
- const newResizeState = {
3866
- ...resizeState,
3867
- endPoint: [resizeState.endPoint[0] + deltaX, resizeState.endPoint[1] + deltaY]
3868
- };
3869
- const { xZoom, yZoom } = getResizeZoom(newResizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
3870
- let activePoints = resizeOriginPoints.map(p => {
4052
+ }
4053
+ return pointLineDelta;
4054
+ }
4055
+ function getActivePointAndZoom(resizeSnapDelta, resizeSnapOptions, angle) {
4056
+ const { deltaX, deltaY } = resizeSnapDelta;
4057
+ const { resizePoints, isCreate } = resizeSnapOptions;
4058
+ const newResizePoints = [resizePoints[0], [resizePoints[1][0] + deltaX, resizePoints[1][1] + deltaY]];
4059
+ let activePoints = newResizePoints;
4060
+ let xZoom = 0;
4061
+ let yZoom = 0;
4062
+ if (!isCreate) {
4063
+ const { originPoint, handlePoint, isFromCorner, isAspectRatio, resizeOriginPoint } = resizeSnapOptions;
4064
+ const resizeZoom = getResizeZoom(newResizePoints, originPoint, handlePoint, isFromCorner, isAspectRatio);
4065
+ xZoom = resizeZoom.xZoom;
4066
+ yZoom = resizeZoom.yZoom;
4067
+ activePoints = resizeOriginPoint.map(p => {
3871
4068
  return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
3872
4069
  });
3873
- if (this.angle) {
3874
- activePoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(resizeOriginPoints), RectangleClient.getRectangleByPoints(activePoints), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeOriginPoints)), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(activePoints)), this.angle);
4070
+ if (angle) {
4071
+ activePoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(resizeOriginPoint), RectangleClient.getRectangleByPoints(activePoints), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeOriginPoint)), RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(activePoints)), angle);
3875
4072
  }
3876
- return {
3877
- deltaX,
3878
- deltaY,
3879
- xZoom,
3880
- yZoom,
3881
- activePoints
3882
- };
3883
4073
  }
3884
- getEqualLineDelta(resizeSnapOptions) {
3885
- let equalLineDelta = {
3886
- deltaX: 0,
3887
- deltaY: 0
3888
- };
3889
- const { isAspectRatio, activeRectangle } = resizeSnapOptions;
3890
- const widthAlignRectangle = this.alignRectangles.find(item => Math.abs(item.width - activeRectangle.width) < ALIGN_TOLERANCE);
3891
- if (widthAlignRectangle) {
3892
- const deltaWidth = widthAlignRectangle.width - activeRectangle.width;
3893
- equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
3894
- if (isAspectRatio) {
3895
- const deltaHeight = deltaWidth / (activeRectangle.width / activeRectangle.height);
3896
- equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
3897
- return equalLineDelta;
3898
- }
3899
- }
3900
- const heightAlignRectangle = this.alignRectangles.find(item => Math.abs(item.height - activeRectangle.height) < ALIGN_TOLERANCE);
3901
- if (heightAlignRectangle) {
3902
- const deltaHeight = heightAlignRectangle.height - activeRectangle.height;
3903
- equalLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
3904
- if (isAspectRatio) {
3905
- const deltaWidth = deltaHeight * (activeRectangle.width / activeRectangle.height);
3906
- equalLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
3907
- return equalLineDelta;
3908
- }
3909
- }
3910
- return equalLineDelta;
3911
- }
3912
- drawEqualLines(activePoints, resizeSnapOptions) {
3913
- let widthEqualPoints = [];
3914
- let heightEqualPoints = [];
3915
- const drawHorizontalLine = resizeSnapOptions.directionFactors[0] !== 0 || resizeSnapOptions.isAspectRatio;
3916
- const drawVerticalLine = resizeSnapOptions.directionFactors[1] !== 0 || resizeSnapOptions.isAspectRatio;
3917
- const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), this.angle) ||
3918
- RectangleClient.getRectangleByPoints(activePoints);
3919
- for (let alignRectangle of this.alignRectangles) {
3920
- if (activeRectangle.width === alignRectangle.width && drawHorizontalLine) {
3921
- widthEqualPoints.push(getEqualLinePoints(alignRectangle, true));
3922
- }
3923
- if (activeRectangle.height === alignRectangle.height && drawVerticalLine) {
3924
- heightEqualPoints.push(getEqualLinePoints(alignRectangle, false));
3925
- }
3926
- }
3927
- if (widthEqualPoints.length && drawHorizontalLine) {
3928
- widthEqualPoints.push(getEqualLinePoints(activeRectangle, true));
3929
- }
3930
- if (heightEqualPoints.length && drawVerticalLine) {
3931
- heightEqualPoints.push(getEqualLinePoints(activeRectangle, false));
4074
+ return {
4075
+ xZoom,
4076
+ yZoom,
4077
+ activePoints
4078
+ };
4079
+ }
4080
+ function getIsometricLineDelta(snapRectangles, resizeSnapOptions) {
4081
+ let isometricLineDelta = {
4082
+ deltaX: 0,
4083
+ deltaY: 0
4084
+ };
4085
+ const { isAspectRatio, activeRectangle } = resizeSnapOptions;
4086
+ const widthSnapRectangle = snapRectangles.find(item => Math.abs(item.width - activeRectangle.width) < SNAP_TOLERANCE);
4087
+ if (widthSnapRectangle) {
4088
+ const deltaWidth = widthSnapRectangle.width - activeRectangle.width;
4089
+ isometricLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
4090
+ if (isAspectRatio) {
4091
+ const deltaHeight = deltaWidth / (activeRectangle.width / activeRectangle.height);
4092
+ isometricLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
4093
+ return isometricLineDelta;
3932
4094
  }
3933
- const equalLinePoints = [...widthEqualPoints, ...heightEqualPoints];
3934
- return drawEqualLines(this.board, equalLinePoints);
3935
4095
  }
3936
- getAlignLineDelta(resizeSnapOptions) {
3937
- let alignLineDelta = {
3938
- deltaX: 0,
3939
- deltaY: 0
3940
- };
3941
- const { isAspectRatio, activeRectangle, directionFactors } = resizeSnapOptions;
3942
- const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
3943
- const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
3944
- if (drawHorizontal) {
3945
- const xAlignAxis = getTripleAlignAxis(activeRectangle, true);
3946
- const alignX = directionFactors[0] === -1 ? xAlignAxis[0] : xAlignAxis[2];
3947
- const deltaX = getMinAlignDelta(this.alignRectangles, alignX, true);
3948
- if (Math.abs(deltaX) < ALIGN_TOLERANCE) {
3949
- alignLineDelta.deltaX = deltaX;
3950
- if (alignLineDelta.deltaX !== 0 && isAspectRatio) {
3951
- alignLineDelta.deltaY = alignLineDelta.deltaX / (activeRectangle.width / activeRectangle.height);
3952
- return alignLineDelta;
3953
- }
3954
- }
3955
- }
3956
- if (drawVertical) {
3957
- const yAlignAxis = getTripleAlignAxis(activeRectangle, false);
3958
- const alignY = directionFactors[1] === -1 ? yAlignAxis[0] : yAlignAxis[2];
3959
- const deltaY = getMinAlignDelta(this.alignRectangles, alignY, false);
3960
- if (Math.abs(deltaY) < ALIGN_TOLERANCE) {
3961
- alignLineDelta.deltaY = deltaY;
3962
- if (alignLineDelta.deltaY !== 0 && isAspectRatio) {
3963
- alignLineDelta.deltaX = alignLineDelta.deltaY * (activeRectangle.width / activeRectangle.height);
3964
- return alignLineDelta;
3965
- }
3966
- }
3967
- }
3968
- return alignLineDelta;
3969
- }
3970
- drawAlignLines(activePoints, resizeSnapOptions) {
3971
- debugGenerator$1.isDebug() && debugGenerator$1.clear();
3972
- let alignLinePoints = [];
3973
- const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), this.angle) ||
3974
- RectangleClient.getRectangleByPoints(activePoints);
3975
- debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(this.board, activeRectangle, { stroke: 'green' });
3976
- const alignAxisX = getTripleAlignAxis(activeRectangle, true);
3977
- const alignAxisY = getTripleAlignAxis(activeRectangle, false);
3978
- const alignLineRefs = [
3979
- {
3980
- axis: alignAxisX[0],
3981
- isHorizontal: true,
3982
- alignRectangles: []
3983
- },
3984
- {
3985
- axis: alignAxisX[2],
3986
- isHorizontal: true,
3987
- alignRectangles: []
3988
- },
3989
- {
3990
- axis: alignAxisY[0],
3991
- isHorizontal: false,
3992
- alignRectangles: []
3993
- },
3994
- {
3995
- axis: alignAxisY[2],
3996
- isHorizontal: false,
3997
- alignRectangles: []
3998
- }
3999
- ];
4000
- const setAlignLine = (axis, alignRectangle, isHorizontal) => {
4001
- const boundingRectangle = RectangleClient.inflate(RectangleClient.getBoundingRectangle([activeRectangle, alignRectangle]), ALIGN_SPACING);
4002
- if (isHorizontal) {
4003
- const pointStart = [axis, boundingRectangle.y];
4004
- const pointEnd = [axis, boundingRectangle.y + boundingRectangle.height];
4005
- alignLinePoints.push([pointStart, pointEnd]);
4006
- }
4007
- else {
4008
- const pointStart = [boundingRectangle.x, axis];
4009
- const pointEnd = [boundingRectangle.x + boundingRectangle.width, axis];
4010
- alignLinePoints.push([pointStart, pointEnd]);
4011
- }
4012
- };
4013
- const { isAspectRatio, directionFactors } = resizeSnapOptions;
4014
- const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
4015
- const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
4016
- for (let index = 0; index < this.alignRectangles.length; index++) {
4017
- const element = this.alignRectangles[index];
4018
- debugGenerator$1.isDebug() && debugGenerator$1.drawRectangle(this.board, element);
4019
- if (isAlign(alignLineRefs[0].axis, element, alignLineRefs[0].isHorizontal)) {
4020
- alignLineRefs[0].alignRectangles.push(element);
4021
- }
4022
- if (isAlign(alignLineRefs[1].axis, element, alignLineRefs[1].isHorizontal)) {
4023
- alignLineRefs[1].alignRectangles.push(element);
4024
- }
4025
- if (isAlign(alignLineRefs[2].axis, element, alignLineRefs[2].isHorizontal)) {
4026
- alignLineRefs[2].alignRectangles.push(element);
4027
- }
4028
- if (isAlign(alignLineRefs[3].axis, element, alignLineRefs[3].isHorizontal)) {
4029
- alignLineRefs[3].alignRectangles.push(element);
4030
- }
4096
+ const heightSnapRectangle = snapRectangles.find(item => Math.abs(item.height - activeRectangle.height) < SNAP_TOLERANCE);
4097
+ if (heightSnapRectangle) {
4098
+ const deltaHeight = heightSnapRectangle.height - activeRectangle.height;
4099
+ isometricLineDelta.deltaY = deltaHeight * resizeSnapOptions.directionFactors[1];
4100
+ if (isAspectRatio) {
4101
+ const deltaWidth = deltaHeight * (activeRectangle.width / activeRectangle.height);
4102
+ isometricLineDelta.deltaX = deltaWidth * resizeSnapOptions.directionFactors[0];
4103
+ return isometricLineDelta;
4031
4104
  }
4032
- if (drawHorizontal && alignLineRefs[0].alignRectangles.length) {
4033
- const leftRectangle = alignLineRefs[0].alignRectangles.length === 1
4034
- ? alignLineRefs[0].alignRectangles[0]
4035
- : getNearestAlignRectangle(alignLineRefs[0].alignRectangles, activeRectangle);
4036
- setAlignLine(alignLineRefs[0].axis, leftRectangle, alignLineRefs[0].isHorizontal);
4037
- }
4038
- if (drawHorizontal && alignLineRefs[1].alignRectangles.length) {
4039
- const rightRectangle = alignLineRefs[1].alignRectangles.length === 1
4040
- ? alignLineRefs[1].alignRectangles[0]
4041
- : getNearestAlignRectangle(alignLineRefs[1].alignRectangles, activeRectangle);
4042
- setAlignLine(alignLineRefs[1].axis, rightRectangle, alignLineRefs[1].isHorizontal);
4043
- }
4044
- if (drawVertical && alignLineRefs[2].alignRectangles.length) {
4045
- const topRectangle = alignLineRefs[2].alignRectangles.length === 1
4046
- ? alignLineRefs[2].alignRectangles[0]
4047
- : getNearestAlignRectangle(alignLineRefs[2].alignRectangles, activeRectangle);
4048
- setAlignLine(alignLineRefs[2].axis, topRectangle, alignLineRefs[2].isHorizontal);
4049
- }
4050
- if (drawVertical && alignLineRefs[3].alignRectangles.length) {
4051
- const bottomRectangle = alignLineRefs[3].alignRectangles.length === 1
4052
- ? alignLineRefs[3].alignRectangles[0]
4053
- : getNearestAlignRectangle(alignLineRefs[3].alignRectangles, activeRectangle);
4054
- setAlignLine(alignLineRefs[3].axis, bottomRectangle, alignLineRefs[3].isHorizontal);
4055
- }
4056
- return drawAlignLines(this.board, alignLinePoints);
4057
- }
4058
- handleResizeSnap(resizeSnapOptions) {
4059
- const alignG = createG();
4060
- let alignLineDelta = this.getEqualLineDelta(resizeSnapOptions);
4061
- if (alignLineDelta.deltaX === 0 && alignLineDelta.deltaY === 0) {
4062
- alignLineDelta = this.getAlignLineDelta(resizeSnapOptions);
4063
- }
4064
- const equalLineRef = this.getSnapRef(alignLineDelta, resizeSnapOptions);
4065
- const equalLinesG = this.drawEqualLines(equalLineRef.activePoints, resizeSnapOptions);
4066
- const alignLinesG = this.drawAlignLines(equalLineRef.activePoints, resizeSnapOptions);
4067
- alignG.append(equalLinesG, alignLinesG);
4068
- return { ...equalLineRef, alignG };
4069
4105
  }
4106
+ return isometricLineDelta;
4070
4107
  }
4071
- function getBarPoint(point, isHorizontal) {
4072
- return isHorizontal
4073
- ? [
4074
- [point[0], point[1] - 4],
4075
- [point[0], point[1] + 4]
4076
- ]
4077
- : [
4078
- [point[0] - 4, point[1]],
4079
- [point[0] + 4, point[1]]
4080
- ];
4081
- }
4082
- function getEqualLinePoints(rectangle, isHorizontal) {
4108
+ function getIsometricLinePoints(rectangle, isHorizontal) {
4083
4109
  return isHorizontal
4084
4110
  ? [
4085
4111
  [rectangle.x, rectangle.y - EQUAL_SPACING],
@@ -4090,359 +4116,393 @@ function getEqualLinePoints(rectangle, isHorizontal) {
4090
4116
  [rectangle.x - EQUAL_SPACING, rectangle.y + rectangle.height]
4091
4117
  ];
4092
4118
  }
4093
- function drawEqualLines(board, lines) {
4094
- const g = createG();
4095
- lines.forEach(line => {
4096
- if (!line.length)
4097
- return;
4098
- const yAlign = PlaitBoard.getRoughSVG(board).line(line[0][0], line[0][1], line[1][0], line[1][1], {
4099
- stroke: SELECTION_BORDER_COLOR,
4100
- strokeWidth: 1
4101
- });
4102
- g.appendChild(yAlign);
4103
- line.forEach(point => {
4104
- const barPoint = getBarPoint(point, !!Point.isHorizontal(line[0], line[1]));
4105
- const bar = PlaitBoard.getRoughSVG(board).line(barPoint[0][0], barPoint[0][1], barPoint[1][0], barPoint[1][1], {
4106
- stroke: SELECTION_BORDER_COLOR,
4107
- strokeWidth: 1
4108
- });
4109
- g.appendChild(bar);
4110
- });
4111
- });
4112
- return g;
4113
- }
4114
- function drawAlignLines(board, lines) {
4115
- const g = createG();
4116
- lines.forEach(points => {
4117
- if (!points.length)
4118
- return;
4119
- const xAlign = PlaitBoard.getRoughSVG(board).line(points[0][0], points[0][1], points[1][0], points[1][1], {
4120
- stroke: SELECTION_BORDER_COLOR,
4121
- strokeWidth: 1,
4122
- strokeLineDash: [4, 4]
4123
- });
4124
- g.appendChild(xAlign);
4125
- });
4126
- return g;
4119
+ function drawResizingPointSnapLines(board, activePoints, snapRectangles, resizeSnapOptions, angle) {
4120
+ debugGenerator.isDebug() && debugGenerator.clear();
4121
+ const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), angle) ||
4122
+ RectangleClient.getRectangleByPoints(activePoints);
4123
+ const { isAspectRatio, directionFactors } = resizeSnapOptions;
4124
+ const drawHorizontal = directionFactors[0] !== 0 || isAspectRatio;
4125
+ const drawVertical = directionFactors[1] !== 0 || isAspectRatio;
4126
+ return drawPointSnapLines(board, activeRectangle, snapRectangles, drawHorizontal, drawVertical);
4127
4127
  }
4128
- const getTripleAlignAxis = (rectangle, isHorizontal) => {
4129
- const axis = isHorizontal ? 'x' : 'y';
4130
- const side = isHorizontal ? 'width' : 'height';
4131
- return [rectangle[axis], rectangle[axis] + rectangle[side] / 2, rectangle[axis] + rectangle[side]];
4132
- };
4133
- const isAlign = (axis, rectangle, isHorizontal) => {
4134
- const alignAxis = getTripleAlignAxis(rectangle, isHorizontal);
4135
- return alignAxis.includes(axis);
4136
- };
4137
- const getClosestDelta = (axis, rectangle, isHorizontal) => {
4138
- const alignAxis = getTripleAlignAxis(rectangle, isHorizontal);
4139
- const deltas = alignAxis.map(item => item - axis);
4140
- const absDeltas = deltas.map(item => Math.abs(item));
4141
- const index = absDeltas.indexOf(Math.min(...absDeltas));
4142
- return deltas[index];
4143
- };
4144
- function getMinAlignDelta(alignRectangles, axis, isHorizontal) {
4145
- let delta = ALIGN_TOLERANCE;
4146
- alignRectangles.forEach(item => {
4147
- const distance = getClosestDelta(axis, item, isHorizontal);
4148
- if (Math.abs(distance) < Math.abs(delta)) {
4149
- delta = distance;
4128
+ function drawIsometricSnapLines(board, activePoints, snapRectangles, resizeSnapOptions, angle) {
4129
+ let widthIsometricPoints = [];
4130
+ let heightIsometricPoints = [];
4131
+ const drawHorizontalLine = resizeSnapOptions.directionFactors[0] !== 0 || resizeSnapOptions.isAspectRatio;
4132
+ const drawVerticalLine = resizeSnapOptions.directionFactors[1] !== 0 || resizeSnapOptions.isAspectRatio;
4133
+ const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(activePoints), angle) ||
4134
+ RectangleClient.getRectangleByPoints(activePoints);
4135
+ for (let snapRectangle of snapRectangles) {
4136
+ if (activeRectangle.width === snapRectangle.width && drawHorizontalLine) {
4137
+ widthIsometricPoints.push(getIsometricLinePoints(snapRectangle, true));
4150
4138
  }
4151
- });
4152
- return delta;
4153
- }
4154
- function getNearestAlignRectangle(alignRectangles, activeRectangle) {
4155
- let minDistance = Infinity;
4156
- let nearestRectangle = alignRectangles[0];
4157
- alignRectangles.forEach(item => {
4158
- const distance = Math.sqrt(Math.pow(activeRectangle.x - item.x, 2) + Math.pow(activeRectangle.y - item.y, 2));
4159
- if (distance < minDistance) {
4160
- minDistance = distance;
4161
- nearestRectangle = item;
4139
+ if (activeRectangle.height === snapRectangle.height && drawVerticalLine) {
4140
+ heightIsometricPoints.push(getIsometricLinePoints(snapRectangle, false));
4162
4141
  }
4163
- });
4164
- return nearestRectangle;
4165
- }
4166
- function getResizeSnapRef(board, resizeRef, resizeState, resizeOriginPointAndHandlePoint, isAspectRatio, isFromCorner) {
4167
- const { originPoint, handlePoint } = resizeOriginPointAndHandlePoint;
4168
- const { xZoom, yZoom } = getResizeZoom(resizeState, originPoint, handlePoint, isFromCorner, isAspectRatio);
4169
- let activeElements;
4170
- let resizeOriginPoints = [];
4171
- if (Array.isArray(resizeRef.element)) {
4172
- activeElements = resizeRef.element;
4173
- const rectangle = getRectangleByElements(board, resizeRef.element, false);
4174
- resizeOriginPoints = RectangleClient.getPoints(rectangle);
4175
4142
  }
4176
- else {
4177
- activeElements = [resizeRef.element];
4178
- resizeOriginPoints = resizeRef.element.points;
4143
+ if (widthIsometricPoints.length && drawHorizontalLine) {
4144
+ widthIsometricPoints.push(getIsometricLinePoints(activeRectangle, true));
4179
4145
  }
4180
- const points = resizeOriginPoints.map(p => {
4181
- return movePointByZoomAndOriginPoint(p, originPoint, xZoom, yZoom);
4182
- });
4183
- const activeRectangle = getRectangleByAngle(RectangleClient.getRectangleByPoints(points), getSelectionAngle(activeElements)) ||
4184
- RectangleClient.getRectangleByPoints(points);
4185
- const resizeSnapReaction = new ResizeSnapReaction(board, activeElements);
4186
- const resizeHandlePoint = movePointByZoomAndOriginPoint(handlePoint, originPoint, xZoom, yZoom);
4187
- const [x, y] = getUnitVectorByPointAndPoint(originPoint, resizeHandlePoint);
4188
- return resizeSnapReaction.handleResizeSnap({
4189
- resizeState,
4190
- resizeOriginPoints,
4191
- activeRectangle,
4192
- originPoint,
4193
- handlePoint,
4194
- directionFactors: [getDirectionFactorByDirectionComponent(x), getDirectionFactorByDirectionComponent(y)],
4195
- isAspectRatio,
4196
- isFromCorner
4197
- });
4146
+ if (heightIsometricPoints.length && drawVerticalLine) {
4147
+ heightIsometricPoints.push(getIsometricLinePoints(activeRectangle, false));
4148
+ }
4149
+ const isometricLines = [...widthIsometricPoints, ...heightIsometricPoints];
4150
+ return drawSolidLines(board, isometricLines);
4198
4151
  }
4199
4152
 
4200
- const debugKey = 'debug:plait:resize-for-rotation';
4201
- const debugGenerator = createDebugGenerator(debugKey);
4202
- function withDrawResize(board) {
4203
- const { afterChange, drawActiveRectangle } = board;
4204
- let alignG;
4205
- let handleG;
4206
- let needCustomActiveRectangle = false;
4207
- let resizeActivePoints = null;
4208
- const canResize = () => {
4209
- const elements = getSelectedElements(board);
4210
- return elements.length > 1 && elements.every(el => PlaitDrawElement.isDrawElement(el));
4211
- };
4212
- const options = {
4213
- key: 'draw-elements',
4214
- canResize,
4215
- hitTest: (point) => {
4216
- const elements = getSelectedElements(board);
4217
- const boundingRectangle = getRectangleByElements(board, elements, false);
4218
- const angle = getSelectionAngle(elements);
4219
- const handleRef = getHitRectangleResizeHandleRef(board, boundingRectangle, point, angle);
4220
- if (handleRef) {
4221
- return {
4222
- element: elements,
4223
- rectangle: boundingRectangle,
4224
- handle: handleRef.handle,
4225
- cursorClass: handleRef.cursorClass
4226
- };
4227
- }
4228
- return null;
4229
- },
4230
- onResize: (resizeRef, resizeState) => {
4231
- alignG?.remove();
4232
- debugGenerator.isDebug() && debugGenerator.clear();
4233
- const isFromCorner = isCornerHandle(board, resizeRef.handle);
4234
- const isAspectRatio = resizeState.isShift || isFromCorner;
4235
- const centerPoint = RectangleClient.getCenterPoint(resizeRef.rectangle);
4236
- const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
4237
- const angle = getSelectionAngle(resizeRef.element);
4238
- let bulkRotationRef;
4239
- if (angle) {
4240
- bulkRotationRef = {
4241
- angle: angle,
4242
- offsetX: 0,
4243
- offsetY: 0,
4244
- newCenterPoint: [0, 0]
4245
- };
4246
- const [rotatedStartPoint, rotateEndPoint] = rotatePoints([resizeState.startPoint, resizeState.endPoint], centerPoint, -bulkRotationRef.angle);
4247
- resizeState.startPoint = rotatedStartPoint;
4248
- resizeState.endPoint = rotateEndPoint;
4249
- }
4250
- const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
4251
- originPoint,
4252
- handlePoint
4253
- }, isAspectRatio, isFromCorner);
4254
- resizeActivePoints = resizeAlignRef.activePoints;
4255
- alignG = resizeAlignRef.alignG;
4256
- PlaitBoard.getElementActiveHost(board).append(alignG);
4257
- if (bulkRotationRef) {
4258
- const boundingBoxCornerPoints = RectangleClient.getPoints(resizeRef.rectangle);
4259
- const resizedBoundingBoxCornerPoints = boundingBoxCornerPoints.map(p => {
4260
- return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4261
- });
4262
- const newBoundingBox = RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints);
4263
- debugGenerator.isDebug() && debugGenerator.drawRectangle(board, newBoundingBox, { stroke: 'blue' });
4264
- const newBoundingBoxCenter = RectangleClient.getCenterPoint(newBoundingBox);
4265
- const adjustedNewBoundingBoxPoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(boundingBoxCornerPoints), RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints), centerPoint, newBoundingBoxCenter, bulkRotationRef.angle);
4266
- const newCenter = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(adjustedNewBoundingBoxPoints));
4267
- bulkRotationRef = Object.assign(bulkRotationRef, {
4268
- offsetX: newCenter[0] - newBoundingBoxCenter[0],
4269
- offsetY: newCenter[1] - newBoundingBoxCenter[1],
4270
- newCenterPoint: newCenter
4271
- });
4272
- debugGenerator.isDebug() && debugGenerator.drawRectangle(board, adjustedNewBoundingBoxPoints);
4273
- }
4274
- resizeRef.element.forEach(target => {
4275
- const path = PlaitBoard.findPath(board, target);
4276
- let points;
4277
- if (bulkRotationRef) {
4278
- const reversedPoints = rotatedDataPoints(target.points, centerPoint, -bulkRotationRef.angle);
4279
- points = reversedPoints.map((p) => {
4280
- return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4153
+ const withGeometryCreateByDrag = (board) => {
4154
+ const { pointerMove, globalPointerUp } = board;
4155
+ let geometryShapeG = null;
4156
+ let temporaryElement = null;
4157
+ let fakeCreateTextRef = null;
4158
+ board.pointerMove = (event) => {
4159
+ geometryShapeG?.remove();
4160
+ geometryShapeG = createG();
4161
+ const geometryGenerator = new GeometryShapeGenerator(board);
4162
+ const geometryPointers = getGeometryPointers();
4163
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
4164
+ const dragMode = isGeometryPointer && isDndMode(board);
4165
+ const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4166
+ const pointer = PlaitBoard.getPointer(board);
4167
+ if (dragMode) {
4168
+ const memorizedLatest = getMemorizedLatestByPointer(pointer);
4169
+ if (pointer === BasicShapes.text) {
4170
+ const property = getTextShapeProperty(board, DefaultTextProperty.text, memorizedLatest.textProperties['font-size']);
4171
+ const points = RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(movingPoint, property.width, property.height));
4172
+ temporaryElement = createTextElement(board, points);
4173
+ if (!fakeCreateTextRef) {
4174
+ const textManage = new TextManage(board, PlaitBoard.getComponent(board).viewContainerRef, {
4175
+ getRectangle: () => {
4176
+ return getTextRectangle(temporaryElement);
4177
+ }
4281
4178
  });
4282
- const adjustTargetPoints = points.map(p => [
4283
- p[0] + bulkRotationRef.offsetX,
4284
- p[1] + bulkRotationRef.offsetY
4285
- ]);
4286
- points = rotatedDataPoints(adjustTargetPoints, bulkRotationRef.newCenterPoint, bulkRotationRef.angle);
4179
+ PlaitBoard.getComponent(board)
4180
+ .viewContainerRef.injector.get(NgZone)
4181
+ .run(() => {
4182
+ textManage.draw(temporaryElement.text);
4183
+ });
4184
+ fakeCreateTextRef = {
4185
+ g: createG(),
4186
+ textManage
4187
+ };
4188
+ PlaitBoard.getHost(board).append(fakeCreateTextRef.g);
4189
+ fakeCreateTextRef.g.append(textManage.g);
4287
4190
  }
4288
4191
  else {
4289
- if (hasValidAngle(target)) {
4290
- needCustomActiveRectangle = true;
4291
- }
4292
- if (hasValidAngle(target) && isAxisChangedByAngle(target.angle)) {
4293
- points = getResizePointsByOtherwiseAxis(board, target.points, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4294
- }
4295
- else {
4296
- points = target.points.map(p => {
4297
- return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4298
- });
4299
- }
4192
+ fakeCreateTextRef.textManage.updateRectangle();
4193
+ fakeCreateTextRef.g.append(fakeCreateTextRef.textManage.g);
4300
4194
  }
4301
- if (PlaitDrawElement.isGeometry(target)) {
4302
- const { height: textHeight } = getFirstTextManage(target).getSize();
4303
- DrawTransforms.resizeGeometry(board, points, textHeight, path);
4195
+ }
4196
+ else {
4197
+ const points = getDefaultGeometryPoints(pointer, movingPoint);
4198
+ temporaryElement = createDefaultGeometry(board, points, pointer);
4199
+ geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
4200
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
4201
+ }
4202
+ }
4203
+ pointerMove(event);
4204
+ };
4205
+ board.globalPointerUp = (event) => {
4206
+ const geometryPointers = getGeometryPointers();
4207
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
4208
+ const dragMode = isGeometryPointer && isDndMode(board);
4209
+ if (dragMode && temporaryElement) {
4210
+ insertElement(board, temporaryElement);
4211
+ fakeCreateTextRef?.textManage.destroy();
4212
+ fakeCreateTextRef?.g.remove();
4213
+ fakeCreateTextRef = null;
4214
+ }
4215
+ geometryShapeG?.remove();
4216
+ geometryShapeG = null;
4217
+ preventTouchMove(board, event, false);
4218
+ globalPointerUp(event);
4219
+ };
4220
+ return board;
4221
+ };
4222
+ const withGeometryCreateByDrawing = (board) => {
4223
+ const { pointerDown, pointerMove, pointerUp, keyDown, keyUp } = board;
4224
+ let start = null;
4225
+ let geometryShapeG = null;
4226
+ let temporaryElement = null;
4227
+ let isShift = false;
4228
+ let snapG;
4229
+ board.keyDown = (event) => {
4230
+ isShift = isKeyHotkey('shift', event);
4231
+ keyDown(event);
4232
+ };
4233
+ board.keyUp = (event) => {
4234
+ isShift = false;
4235
+ keyUp(event);
4236
+ };
4237
+ board.pointerDown = (event) => {
4238
+ const geometryPointers = getGeometryPointers();
4239
+ const isGeometryPointer = PlaitBoard.isInPointer(board, geometryPointers);
4240
+ if (!PlaitBoard.isReadonly(board) && isGeometryPointer && isDrawingMode(board)) {
4241
+ const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4242
+ start = point;
4243
+ const pointer = PlaitBoard.getPointer(board);
4244
+ preventTouchMove(board, event, true);
4245
+ if (pointer === BasicShapes.text) {
4246
+ const memorizedLatest = getMemorizedLatestByPointer(pointer);
4247
+ const property = getTextShapeProperty(board, DefaultTextProperty.text, memorizedLatest.textProperties['font-size']);
4248
+ const points = RectangleClient.getPoints(RectangleClient.getRectangleByCenterPoint(point, property.width, property.height));
4249
+ const textElement = createTextElement(board, points);
4250
+ insertElement(board, textElement);
4251
+ start = null;
4252
+ }
4253
+ }
4254
+ pointerDown(event);
4255
+ };
4256
+ board.pointerMove = (event) => {
4257
+ geometryShapeG?.remove();
4258
+ geometryShapeG = createG();
4259
+ const geometryGenerator = new GeometryShapeGenerator(board);
4260
+ const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4261
+ const pointer = PlaitBoard.getPointer(board);
4262
+ snapG?.remove();
4263
+ if (start && pointer !== BasicShapes.text) {
4264
+ let points = normalizeShapePoints([start, movingPoint], isShift);
4265
+ const activeRectangle = RectangleClient.getRectangleByPoints(points);
4266
+ const [x, y] = getUnitVectorByPointAndPoint(start, movingPoint);
4267
+ const resizeSnapRef = getSnapResizingRef(board, [], {
4268
+ resizePoints: points,
4269
+ activeRectangle,
4270
+ directionFactors: [getDirectionFactorByDirectionComponent(x), getDirectionFactorByDirectionComponent(y)],
4271
+ isAspectRatio: isShift,
4272
+ isFromCorner: true,
4273
+ isCreate: true
4274
+ });
4275
+ snapG = resizeSnapRef.snapG;
4276
+ PlaitBoard.getElementActiveHost(board).append(snapG);
4277
+ points = normalizeShapePoints(resizeSnapRef.activePoints, isShift);
4278
+ temporaryElement = createDefaultGeometry(board, points, pointer);
4279
+ geometryGenerator.processDrawing(temporaryElement, geometryShapeG);
4280
+ PlaitBoard.getElementActiveHost(board).append(geometryShapeG);
4281
+ }
4282
+ pointerMove(event);
4283
+ };
4284
+ board.pointerUp = (event) => {
4285
+ const isDrawMode = !!start;
4286
+ if (isDrawMode) {
4287
+ const targetPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4288
+ const { width, height } = RectangleClient.getRectangleByPoints([start, targetPoint]);
4289
+ if (Math.hypot(width, height) === 0) {
4290
+ const pointer = PlaitBoard.getPointer(board);
4291
+ if (pointer !== BasicShapes.text) {
4292
+ const points = getDefaultGeometryPoints(pointer, targetPoint);
4293
+ temporaryElement = createDefaultGeometry(board, points, pointer);
4304
4294
  }
4305
- else if (PlaitDrawElement.isLine(target)) {
4306
- Transforms.setNode(board, { points }, path);
4295
+ }
4296
+ }
4297
+ if (temporaryElement) {
4298
+ insertElement(board, temporaryElement);
4299
+ }
4300
+ snapG?.remove();
4301
+ geometryShapeG?.remove();
4302
+ geometryShapeG = null;
4303
+ start = null;
4304
+ temporaryElement = null;
4305
+ preventTouchMove(board, event, false);
4306
+ pointerUp(event);
4307
+ };
4308
+ return board;
4309
+ };
4310
+
4311
+ const buildClipboardData = (board, elements, startPoint) => {
4312
+ return elements.map(element => {
4313
+ if (PlaitDrawElement.isGeometry(element) || PlaitDrawElement.isImage(element)) {
4314
+ const points = element.points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
4315
+ return { ...element, points };
4316
+ }
4317
+ if (PlaitDrawElement.isLine(element)) {
4318
+ let source = { ...element.source };
4319
+ let target = { ...element.target };
4320
+ let points = [...element.points];
4321
+ if (element.source.boundId) {
4322
+ points[0] = getConnectionPoint(getElementById(board, element.source.boundId), element.source.connection);
4323
+ if (!getElementById(board, element.source.boundId, elements)) {
4324
+ delete source.boundId;
4325
+ delete source.connection;
4307
4326
  }
4308
- else if (PlaitDrawElement.isImage(target)) {
4309
- if (isAspectRatio) {
4310
- Transforms.setNode(board, { points }, path);
4311
- }
4312
- else {
4313
- // The image element does not follow the resize, but moves based on the center point.
4314
- const targetRectangle = RectangleClient.getRectangleByPoints(target.points);
4315
- const centerPoint = RectangleClient.getCenterPoint(targetRectangle);
4316
- const newCenterPoint = movePointByZoomAndOriginPoint(centerPoint, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4317
- const newTargetRectangle = RectangleClient.getRectangleByCenterPoint(newCenterPoint, targetRectangle.width, targetRectangle.height);
4318
- Transforms.setNode(board, { points: RectangleClient.getPoints(newTargetRectangle) }, path);
4319
- }
4327
+ }
4328
+ if (element.target.boundId) {
4329
+ points[points.length - 1] = getConnectionPoint(getElementById(board, element.target.boundId), element.target.connection);
4330
+ if (!getElementById(board, element.target.boundId, elements)) {
4331
+ delete target.boundId;
4332
+ delete target.connection;
4320
4333
  }
4321
- });
4322
- },
4323
- afterResize: (resizeRef) => {
4324
- alignG?.remove();
4325
- alignG = null;
4326
- if (needCustomActiveRectangle) {
4327
- needCustomActiveRectangle = false;
4328
- resizeActivePoints = null;
4329
- const selectedElements = getSelectedElements(board);
4330
- Transforms.addSelectionWithTemporaryElements(board, selectedElements);
4334
+ }
4335
+ points = points.map(point => [point[0] - startPoint[0], point[1] - startPoint[1]]);
4336
+ return { ...element, points, source, target };
4337
+ }
4338
+ return element;
4339
+ });
4340
+ };
4341
+ const insertClipboardData = (board, elements, startPoint) => {
4342
+ const lines = elements.filter(value => PlaitDrawElement.isLine(value));
4343
+ const geometries = elements.filter(value => PlaitDrawElement.isGeometry(value) || PlaitDrawElement.isImage(value));
4344
+ geometries.forEach(element => {
4345
+ const sourceLines = [];
4346
+ const targetLines = [];
4347
+ lines.forEach(line => {
4348
+ if (PlaitLine.isBoundElementOfSource(line, element)) {
4349
+ sourceLines.push(line);
4350
+ }
4351
+ if (PlaitLine.isBoundElementOfTarget(line, element)) {
4352
+ targetLines.push(line);
4353
+ }
4354
+ });
4355
+ element.id = idCreator();
4356
+ // update lines
4357
+ sourceLines.forEach(sourceLine => (sourceLine.source.boundId = element.id));
4358
+ targetLines.forEach(targetLine => (targetLine.target.boundId = element.id));
4359
+ element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
4360
+ Transforms.insertNode(board, element, [board.children.length]);
4361
+ });
4362
+ lines.forEach(element => {
4363
+ element.id = idCreator();
4364
+ element.points = element.points.map(point => [startPoint[0] + point[0], startPoint[1] + point[1]]);
4365
+ Transforms.insertNode(board, element, [board.children.length]);
4366
+ });
4367
+ Transforms.addSelectionWithTemporaryElements(board, elements);
4368
+ };
4369
+
4370
+ const withDrawFragment = (baseBoard) => {
4371
+ const board = baseBoard;
4372
+ const { getDeletedFragment, buildFragment, insertFragment } = board;
4373
+ board.getDeletedFragment = (data) => {
4374
+ const drawElements = getSelectedDrawElements(board);
4375
+ if (drawElements.length) {
4376
+ const geometryElements = drawElements.filter(value => PlaitDrawElement.isGeometry(value));
4377
+ const lineElements = drawElements.filter(value => PlaitDrawElement.isLine(value));
4378
+ const imageElements = drawElements.filter(value => PlaitDrawElement.isImage(value));
4379
+ const boundLineElements = [
4380
+ ...getBoundedLineElements(board, geometryElements),
4381
+ ...getBoundedLineElements(board, imageElements)
4382
+ ].filter(line => !lineElements.includes(line));
4383
+ data.push(...[
4384
+ ...geometryElements,
4385
+ ...lineElements,
4386
+ ...imageElements,
4387
+ ...boundLineElements.filter(line => !lineElements.includes(line))
4388
+ ]);
4389
+ }
4390
+ return getDeletedFragment(data);
4391
+ };
4392
+ board.buildFragment = (clipboardContext, rectangle, type) => {
4393
+ const targetDrawElements = getSelectedDrawElements(board);
4394
+ let boundLineElements = [];
4395
+ if (targetDrawElements.length) {
4396
+ if (type === 'cut') {
4397
+ const geometryElements = targetDrawElements.filter(value => PlaitDrawElement.isGeometry(value));
4398
+ const lineElements = targetDrawElements.filter(value => PlaitDrawElement.isLine(value));
4399
+ boundLineElements = getBoundedLineElements(board, geometryElements).filter(line => !lineElements.includes(line));
4400
+ }
4401
+ const selectedElements = [...targetDrawElements, ...boundLineElements];
4402
+ const elements = buildClipboardData(board, selectedElements, rectangle ? [rectangle.x, rectangle.y] : [0, 0]);
4403
+ const text = getElementsText(selectedElements);
4404
+ if (!clipboardContext) {
4405
+ clipboardContext = createClipboardContext(WritableClipboardType.elements, elements, text);
4406
+ }
4407
+ else {
4408
+ clipboardContext = addClipboardContext(clipboardContext, {
4409
+ text,
4410
+ type: WritableClipboardType.elements,
4411
+ elements
4412
+ });
4331
4413
  }
4332
4414
  }
4415
+ return buildFragment(clipboardContext, rectangle, type);
4333
4416
  };
4334
- withResize(board, options);
4335
- board.afterChange = () => {
4336
- afterChange();
4337
- if (handleG) {
4338
- handleG.remove();
4339
- handleG = null;
4417
+ board.insertFragment = (clipboardData, targetPoint) => {
4418
+ const selectedElements = getSelectedElements(board);
4419
+ if (clipboardData?.files?.length) {
4420
+ const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
4421
+ const canInsertionImage = !getElementOfFocusedImage(board) && !(selectedElements.length === 1 && board.isImageBindingAllowed(selectedElements[0]));
4422
+ if (acceptImageArray.includes(clipboardData.files[0].type) && canInsertionImage) {
4423
+ const imageFile = clipboardData.files[0];
4424
+ buildImage(board, imageFile, DEFAULT_IMAGE_WIDTH, imageItem => {
4425
+ DrawTransforms.insertImage(board, imageItem, targetPoint);
4426
+ });
4427
+ return;
4428
+ }
4340
4429
  }
4341
- if (canResize() && !isSelectionMoving(board)) {
4342
- handleG = createG();
4343
- const elements = getSelectedElements(board);
4344
- const boundingRectangle = needCustomActiveRectangle
4345
- ? RectangleClient.getRectangleByPoints(resizeActivePoints)
4346
- : getRectangleByElements(board, elements, false);
4347
- let corners = RectangleClient.getCornerPoints(boundingRectangle);
4348
- const angle = getSelectionAngle(elements);
4349
- if (angle) {
4350
- const centerPoint = RectangleClient.getCenterPoint(boundingRectangle);
4351
- corners = rotatePoints(corners, centerPoint, angle);
4430
+ if (clipboardData?.elements?.length) {
4431
+ const drawElements = clipboardData.elements?.filter(value => PlaitDrawElement.isDrawElement(value));
4432
+ if (clipboardData.elements && clipboardData.elements.length > 0 && drawElements.length > 0) {
4433
+ insertClipboardData(board, drawElements, targetPoint);
4352
4434
  }
4353
- corners.forEach(corner => {
4354
- const g = drawHandle(board, corner);
4355
- handleG && handleG.append(g);
4356
- });
4357
- PlaitBoard.getElementActiveHost(board).append(handleG);
4358
4435
  }
4359
- };
4360
- board.drawActiveRectangle = () => {
4361
- if (needCustomActiveRectangle) {
4362
- const rectangle = RectangleClient.getRectangleByPoints(resizeActivePoints);
4363
- return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
4364
- stroke: SELECTION_BORDER_COLOR,
4365
- strokeWidth: ACTIVE_STROKE_WIDTH
4366
- });
4436
+ if (clipboardData?.text) {
4437
+ if (!clipboardData.elements || clipboardData.elements.length === 0) {
4438
+ // (* ̄︶ ̄)
4439
+ const insertAsChildren = selectedElements.length === 1 && selectedElements[0].children;
4440
+ const insertAsFreeText = !insertAsChildren;
4441
+ if (insertAsFreeText) {
4442
+ DrawTransforms.insertText(board, targetPoint, clipboardData.text);
4443
+ return;
4444
+ }
4445
+ }
4367
4446
  }
4368
- return drawActiveRectangle();
4447
+ insertFragment(clipboardData, targetPoint);
4369
4448
  };
4370
4449
  return board;
4371
- }
4372
- const getResizeOriginPointAndHandlePoint = (board, resizeRef) => {
4373
- const handleIndex = getIndexByResizeHandle(resizeRef.handle);
4374
- const symmetricHandleIndex = getSymmetricHandleIndex(board, handleIndex);
4375
- const originPoint = getResizeHandlePointByIndex(resizeRef.rectangle, symmetricHandleIndex);
4376
- const handlePoint = getResizeHandlePointByIndex(resizeRef.rectangle, handleIndex);
4377
- return {
4378
- originPoint,
4379
- handlePoint
4380
- };
4381
4450
  };
4382
- const getResizeZoom = (resizeState, resizeOriginPoint, resizeHandlePoint, isFromCorner, isAspectRatio) => {
4383
- const startPoint = resizeState.startPoint;
4384
- const endPoint = resizeState.endPoint;
4385
- let xZoom = 0;
4386
- let yZoom = 0;
4387
- if (isFromCorner) {
4388
- if (isAspectRatio) {
4389
- let normalizedOffsetX = Point.getOffsetX(startPoint, endPoint);
4390
- xZoom = normalizedOffsetX / (resizeHandlePoint[0] - resizeOriginPoint[0]);
4391
- yZoom = xZoom;
4392
- }
4393
- else {
4394
- let normalizedOffsetX = Point.getOffsetX(startPoint, endPoint);
4395
- let normalizedOffsetY = Point.getOffsetY(startPoint, endPoint);
4396
- xZoom = normalizedOffsetX / (resizeHandlePoint[0] - resizeOriginPoint[0]);
4397
- yZoom = normalizedOffsetY / (resizeHandlePoint[1] - resizeOriginPoint[1]);
4451
+ const getBoundedLineElements = (board, plaitShapes) => {
4452
+ const lines = getLines(board);
4453
+ return lines.filter(line => plaitShapes.find(shape => PlaitLine.isBoundElementOfSource(line, shape) || PlaitLine.isBoundElementOfTarget(line, shape)));
4454
+ };
4455
+
4456
+ const withLineCreateByDraw = (board) => {
4457
+ const { pointerDown, pointerMove, globalPointerUp } = board;
4458
+ let start = null;
4459
+ let sourceElement;
4460
+ let lineShapeG = null;
4461
+ let temporaryElement = null;
4462
+ board.pointerDown = (event) => {
4463
+ const linePointers = getLinePointers();
4464
+ const isLinePointer = PlaitBoard.isInPointer(board, linePointers);
4465
+ if (!PlaitBoard.isReadonly(board) && isLinePointer && isDrawingMode(board)) {
4466
+ const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4467
+ start = point;
4468
+ const hitElement = getSnappingGeometry(board, point);
4469
+ if (hitElement) {
4470
+ sourceElement = hitElement;
4471
+ }
4472
+ preventTouchMove(board, event, true);
4398
4473
  }
4399
- }
4400
- else {
4401
- const isHorizontal = Point.isHorizontal(resizeOriginPoint, resizeHandlePoint, 0.1) || false;
4402
- let normalizedOffset = isHorizontal ? Point.getOffsetX(startPoint, endPoint) : Point.getOffsetY(startPoint, endPoint);
4403
- let benchmarkOffset = isHorizontal ? resizeHandlePoint[0] - resizeOriginPoint[0] : resizeHandlePoint[1] - resizeOriginPoint[1];
4404
- const zoom = normalizedOffset / benchmarkOffset;
4405
- if (isAspectRatio) {
4406
- xZoom = zoom;
4407
- yZoom = zoom;
4474
+ pointerDown(event);
4475
+ };
4476
+ board.pointerMove = (event) => {
4477
+ lineShapeG?.remove();
4478
+ lineShapeG = createG();
4479
+ let movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4480
+ if (start) {
4481
+ const lineShape = PlaitBoard.getPointer(board);
4482
+ temporaryElement = handleLineCreating(board, lineShape, start, movingPoint, sourceElement, lineShapeG);
4408
4483
  }
4409
- else {
4410
- if (isHorizontal) {
4411
- xZoom = zoom;
4412
- }
4413
- else {
4414
- yZoom = zoom;
4415
- }
4484
+ pointerMove(event);
4485
+ };
4486
+ board.globalPointerUp = (event) => {
4487
+ if (temporaryElement) {
4488
+ Transforms.insertNode(board, temporaryElement, [board.children.length]);
4489
+ clearSelectedElement(board);
4490
+ addSelectedElement(board, temporaryElement);
4491
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
4416
4492
  }
4417
- }
4418
- return { xZoom, yZoom };
4419
- };
4420
- const movePointByZoomAndOriginPoint = (p, resizeOriginPoint, xZoom, yZoom) => {
4421
- const offsetX = (p[0] - resizeOriginPoint[0]) * xZoom;
4422
- const offsetY = (p[1] - resizeOriginPoint[1]) * yZoom;
4423
- return [p[0] + offsetX, p[1] + offsetY];
4424
- };
4425
- /**
4426
- * 1. Rotate 90°
4427
- * 2. Scale based on the rotated points
4428
- * 3. Reverse rotate the scaled points by 90°
4429
- */
4430
- const getResizePointsByOtherwiseAxis = (board, points, resizeOriginPoint, xZoom, yZoom) => {
4431
- const currentRectangle = RectangleClient.getRectangleByPoints(points);
4432
- debugGenerator.isDebug() && debugGenerator.drawRectangle(board, currentRectangle, { stroke: 'black' });
4433
- let resultPoints = points;
4434
- resultPoints = rotatePoints(resultPoints, RectangleClient.getCenterPoint(currentRectangle), (1 / 2) * Math.PI);
4435
- debugGenerator.isDebug() && debugGenerator.drawRectangle(board, resultPoints, { stroke: 'blue' });
4436
- resultPoints = resultPoints.map(p => {
4437
- return movePointByZoomAndOriginPoint(p, resizeOriginPoint, xZoom, yZoom);
4438
- });
4439
- debugGenerator.isDebug() && debugGenerator.drawRectangle(board, resultPoints);
4440
- const newRectangle = RectangleClient.getRectangleByPoints(resultPoints);
4441
- return rotatePoints(resultPoints, RectangleClient.getCenterPoint(newRectangle), -(1 / 2) * Math.PI);
4493
+ lineShapeG?.remove();
4494
+ lineShapeG = null;
4495
+ sourceElement = null;
4496
+ start = null;
4497
+ temporaryElement = null;
4498
+ preventTouchMove(board, event, false);
4499
+ globalPointerUp(event);
4500
+ };
4501
+ return board;
4442
4502
  };
4443
4503
 
4444
4504
  const withGeometryResize = (board) => {
4445
- let alignG;
4505
+ let snapG;
4446
4506
  const options = {
4447
4507
  key: 'draw-geometry',
4448
4508
  canResize: () => {
@@ -4470,20 +4530,21 @@ const withGeometryResize = (board) => {
4470
4530
  return null;
4471
4531
  },
4472
4532
  onResize: (resizeRef, resizeState) => {
4473
- const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeRef.element.points));
4474
4533
  resizeState.startPoint = rotateAntiPointsByElement(resizeState.startPoint, resizeRef.element) || resizeState.startPoint;
4475
4534
  resizeState.endPoint = rotateAntiPointsByElement(resizeState.endPoint, resizeRef.element) || resizeState.endPoint;
4476
- alignG?.remove();
4535
+ snapG?.remove();
4477
4536
  const isFromCorner = isCornerHandle(board, resizeRef.handle);
4478
4537
  const isAspectRatio = resizeState.isShift || PlaitDrawElement.isImage(resizeRef.element);
4479
- const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
4480
- const resizeAlignRef = getResizeSnapRef(board, resizeRef, resizeState, {
4538
+ const handleIndex = getIndexByResizeHandle(resizeRef.handle);
4539
+ const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, handleIndex, resizeRef.rectangle);
4540
+ const resizeSnapRefOptions = getSnapResizingRefOptions(board, resizeRef, resizeState, {
4481
4541
  originPoint,
4482
4542
  handlePoint
4483
4543
  }, isAspectRatio, isFromCorner);
4484
- alignG = resizeAlignRef.alignG;
4485
- PlaitBoard.getElementActiveHost(board).append(alignG);
4486
- let points = resizeAlignRef.activePoints;
4544
+ const resizeSnapRef = getSnapResizingRef(board, [resizeRef.element], resizeSnapRefOptions);
4545
+ snapG = resizeSnapRef.snapG;
4546
+ PlaitBoard.getElementActiveHost(board).append(snapG);
4547
+ let points = resizeSnapRef.activePoints;
4487
4548
  if (PlaitDrawElement.isGeometry(resizeRef.element)) {
4488
4549
  const { height: textHeight } = getFirstTextManage(resizeRef.element).getSize();
4489
4550
  DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
@@ -4494,8 +4555,8 @@ const withGeometryResize = (board) => {
4494
4555
  }
4495
4556
  },
4496
4557
  afterResize: (resizeRef) => {
4497
- alignG?.remove();
4498
- alignG = null;
4558
+ snapG?.remove();
4559
+ snapG = null;
4499
4560
  }
4500
4561
  };
4501
4562
  withResize(board, options);
@@ -4751,9 +4812,8 @@ class ImageComponent extends CommonPluginElement {
4751
4812
  get activeGenerator() {
4752
4813
  return this.imageGenerator.componentRef.instance.activeGenerator;
4753
4814
  }
4754
- constructor(viewContainerRef, cdr) {
4815
+ constructor(cdr) {
4755
4816
  super(cdr);
4756
- this.viewContainerRef = viewContainerRef;
4757
4817
  this.cdr = cdr;
4758
4818
  this.destroy$ = new Subject();
4759
4819
  }
@@ -4780,14 +4840,14 @@ class ImageComponent extends CommonPluginElement {
4780
4840
  ngOnInit() {
4781
4841
  super.ngOnInit();
4782
4842
  this.initializeGenerator();
4783
- this.imageGenerator.processDrawing(this.element, this.g, this.viewContainerRef);
4843
+ this.imageGenerator.processDrawing(this.element, this.getElementG(), this.viewContainerRef);
4784
4844
  this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
4785
4845
  selected: this.selected
4786
4846
  });
4787
4847
  }
4788
4848
  onContextChanged(value, previous) {
4789
4849
  if (value.element !== previous.element) {
4790
- this.imageGenerator.updateImage(this.g, previous.element, value.element);
4850
+ this.imageGenerator.updateImage(this.getElementG(), previous.element, value.element);
4791
4851
  this.imageGenerator.componentRef.instance.isFocus = this.selected;
4792
4852
  this.lineAutoCompleteGenerator.processDrawing(this.element, PlaitBoard.getElementActiveHost(this.board), {
4793
4853
  selected: this.selected
@@ -4811,7 +4871,7 @@ class ImageComponent extends CommonPluginElement {
4811
4871
  this.imageGenerator.destroy();
4812
4872
  this.lineAutoCompleteGenerator.destroy();
4813
4873
  }
4814
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
4874
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
4815
4875
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.2.4", type: ImageComponent, isStandalone: true, selector: "plait-draw-geometry", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4816
4876
  }
4817
4877
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: ImageComponent, decorators: [{
@@ -4822,7 +4882,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
4822
4882
  changeDetection: ChangeDetectionStrategy.OnPush,
4823
4883
  standalone: true
4824
4884
  }]
4825
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }] });
4885
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
4826
4886
 
4827
4887
  const withLineAutoCompleteReaction = (board) => {
4828
4888
  const { pointerMove } = board;
@@ -4892,12 +4952,13 @@ const withLineAutoComplete = (board) => {
4892
4952
  const rectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
4893
4953
  const shape = getElementShape(sourceElement);
4894
4954
  const engine = getEngine(shape);
4955
+ let sourcePoint = autoCompletePoint;
4895
4956
  if (engine.getNearestCrossingPoint) {
4896
4957
  const crossingPoint = engine.getNearestCrossingPoint(rectangle, autoCompletePoint);
4897
- autoCompletePoint = crossingPoint;
4958
+ sourcePoint = crossingPoint;
4898
4959
  }
4899
4960
  // source point must be click point
4900
- const rotatedSourcePoint = rotatePointsByElement(autoCompletePoint, sourceElement) || autoCompletePoint;
4961
+ const rotatedSourcePoint = rotatePointsByElement(sourcePoint, sourceElement) || sourcePoint;
4901
4962
  temporaryElement = handleLineCreating(board, LineShape.elbow, rotatedSourcePoint, movingPoint, sourceElement, lineShapeG);
4902
4963
  }
4903
4964
  }
@@ -4972,6 +5033,129 @@ const withLineTextMove = (board) => {
4972
5033
  return board;
4973
5034
  };
4974
5035
 
5036
+ const withDrawRotate = (board) => {
5037
+ const { pointerDown, pointerMove, globalPointerUp, afterChange, drawActiveRectangle } = board;
5038
+ let rotateRef = null;
5039
+ let rotateHandleG;
5040
+ let needCustomActiveRectangle = false;
5041
+ const canRotate = () => {
5042
+ const elements = getSelectedElements(board);
5043
+ return elements.length > 0 && elements.every(el => PlaitDrawElement.isGeometry(el) || PlaitDrawElement.isImage(el));
5044
+ };
5045
+ board.pointerDown = (event) => {
5046
+ if (!canRotate() || PlaitBoard.isReadonly(board) || PlaitBoard.hasBeenTextEditing(board) || !isMainPointer(event)) {
5047
+ pointerDown(event);
5048
+ return;
5049
+ }
5050
+ const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
5051
+ const elements = getSelectedElements(board);
5052
+ const boundingRectangle = getRectangleByElements(board, elements, false);
5053
+ const handleRectangle = getRotateHandleRectangle(boundingRectangle);
5054
+ const angle = getSelectionAngle(elements);
5055
+ const rotatedPoint = angle ? rotatePoints(point, RectangleClient.getCenterPoint(boundingRectangle), -angle) : point;
5056
+ if (handleRectangle && RectangleClient.isHit(RectangleClient.getRectangleByPoints([rotatedPoint, rotatedPoint]), handleRectangle)) {
5057
+ rotateRef = {
5058
+ elements: elements,
5059
+ startPoint: point
5060
+ };
5061
+ }
5062
+ pointerDown(event);
5063
+ };
5064
+ board.pointerMove = (event) => {
5065
+ if (rotateRef) {
5066
+ event.preventDefault();
5067
+ const isShift = !!event.shiftKey;
5068
+ addRotating(board, rotateRef);
5069
+ const endPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
5070
+ const selectionRectangle = getRectangleByElements(board, rotateRef.elements, false);
5071
+ const selectionCenterPoint = RectangleClient.getCenterPoint(selectionRectangle);
5072
+ if (!getSelectionAngle(rotateRef.elements) && rotateRef.elements.length > 1) {
5073
+ needCustomActiveRectangle = true;
5074
+ }
5075
+ throttleRAF(board, 'with-common-rotate', () => {
5076
+ if (rotateRef && rotateRef.startPoint) {
5077
+ let angle = getAngleBetweenPoints(rotateRef.startPoint, endPoint, selectionCenterPoint);
5078
+ if (isShift) {
5079
+ angle += Math.PI / 12 / 2;
5080
+ angle -= angle % (Math.PI / 12);
5081
+ }
5082
+ const selectionAngle = getSelectionAngle(rotateRef.elements);
5083
+ let remainder = (selectionAngle + angle) % (Math.PI / 2);
5084
+ if (Math.PI / 2 - remainder <= degreesToRadians(5)) {
5085
+ const snapAngle = Math.PI / 2 - remainder;
5086
+ angle += snapAngle;
5087
+ }
5088
+ if (remainder <= degreesToRadians(5)) {
5089
+ const snapAngle = -remainder;
5090
+ angle += snapAngle;
5091
+ }
5092
+ rotateRef.angle = normalizeAngle(angle);
5093
+ if (rotateRef.angle) {
5094
+ rotateElements(board, rotateRef.elements, rotateRef.angle);
5095
+ }
5096
+ PlaitBoard.getBoardContainer(board).classList.add('element-rotating');
5097
+ }
5098
+ });
5099
+ return;
5100
+ }
5101
+ pointerMove(event);
5102
+ };
5103
+ board.globalPointerUp = (event) => {
5104
+ globalPointerUp(event);
5105
+ if (needCustomActiveRectangle) {
5106
+ needCustomActiveRectangle = false;
5107
+ const selectedElements = getSelectedElements(board);
5108
+ Transforms.addSelectionWithTemporaryElements(board, selectedElements);
5109
+ }
5110
+ PlaitBoard.getBoardContainer(board).classList.remove('element-rotating');
5111
+ removeRotating(board);
5112
+ rotateRef = null;
5113
+ MERGING.set(board, false);
5114
+ preventTouchMove(board, event, false);
5115
+ };
5116
+ board.afterChange = () => {
5117
+ afterChange();
5118
+ if (rotateHandleG) {
5119
+ rotateHandleG.remove();
5120
+ rotateHandleG = null;
5121
+ }
5122
+ if (canRotate() && !isSelectionMoving(board)) {
5123
+ if (needCustomActiveRectangle && rotateRef) {
5124
+ const boundingRectangle = getRectangleByElements(board, rotateRef.elements, false);
5125
+ rotateHandleG = drawRotateHandle(board, boundingRectangle);
5126
+ rotateHandleG.classList.add(ROTATE_HANDLE_CLASS_NAME);
5127
+ if (rotateRef.angle) {
5128
+ setAngleForG(rotateHandleG, RectangleClient.getCenterPoint(boundingRectangle), rotateRef.angle);
5129
+ }
5130
+ }
5131
+ else {
5132
+ const elements = getSelectedElements(board);
5133
+ const boundingRectangle = getRectangleByElements(board, elements, false);
5134
+ rotateHandleG = drawRotateHandle(board, boundingRectangle);
5135
+ rotateHandleG.classList.add(ROTATE_HANDLE_CLASS_NAME);
5136
+ setAngleForG(rotateHandleG, RectangleClient.getCenterPoint(boundingRectangle), getSelectionAngle(elements));
5137
+ }
5138
+ PlaitBoard.getElementActiveHost(board).append(rotateHandleG);
5139
+ }
5140
+ };
5141
+ board.drawActiveRectangle = () => {
5142
+ if (needCustomActiveRectangle && rotateRef) {
5143
+ const rectangle = getRectangleByElements(board, rotateRef.elements, false);
5144
+ const rectangleG = drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
5145
+ stroke: SELECTION_BORDER_COLOR,
5146
+ strokeWidth: ACTIVE_STROKE_WIDTH
5147
+ });
5148
+ rectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
5149
+ if (rotateRef.angle) {
5150
+ setAngleForG(rectangleG, RectangleClient.getCenterPoint(rectangle), rotateRef.angle);
5151
+ }
5152
+ return rectangleG;
5153
+ }
5154
+ return drawActiveRectangle();
5155
+ };
5156
+ return board;
5157
+ };
5158
+
4975
5159
  const withDraw = (board) => {
4976
5160
  const { drawElement, getRectangle, isRectangleHit, isHit, isInsidePoint, isMovable, isAlign, getRelatedFragment } = board;
4977
5161
  board.drawElement = (context) => {
@@ -5067,12 +5251,12 @@ const withDraw = (board) => {
5067
5251
  });
5068
5252
  return getRelatedFragment([...elements, ...activeLines], originData);
5069
5253
  };
5070
- return withDrawResize(withLineTextMove(withLineAutoCompleteReaction(withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withLineCreateByDraw(withLineAutoComplete(withGeometryCreateByDrag(withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board)))))))))))));
5254
+ return withDrawResize(withLineTextMove(withLineAutoCompleteReaction(withLineText(withLineBoundReaction(withLineResize(withGeometryResize(withDrawRotate(withLineCreateByDraw(withLineAutoComplete(withGeometryCreateByDrag(withGeometryCreateByDrawing(withDrawFragment(withDrawHotkey(board))))))))))))));
5071
5255
  };
5072
5256
 
5073
5257
  /**
5074
5258
  * Generated bundle index. Do not edit.
5075
5259
  */
5076
5260
 
5077
- export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LINE_HIT_GEOMETRY_BUFFER, LINE_SNAPPING_BUFFER, LINE_SNAPPING_CONNECTOR_BUFFER, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, WithLineAutoCompletePluginKey, alignElbowSegment, alignPoints, createDefaultFlowchart, createDefaultGeometry, createGeometryElement, createLineElement, createTextElement, drawBoundReaction, drawGeometry, drawLine, drawLineArrow, getAutoCompletePoints, getBasicPointers, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultTextPoints, getDrawDefaultStrokeColor, getElbowLineRouteOptions, getElbowPoints, getFillByElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryPointers, getHitConnection, getHitConnectorPoint, getHitIndexOfAutoCompletePoint, getIndexAndDeleteCountByKeyPoint, getLineDashByElement, getLineHandleRefPair, getLineMemorizedLatest, getLinePointers, getLinePoints, getLineTextRectangle, getLines, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getMidKeyPoints, getMiddlePoints, getMirrorDataPoints, getNearestPoint, getNextRenderPoints, getNextSourceAndTargetPoints, getResizedPreviousAndNextPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getSourceAndTargetRectangle, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getTextShapeProperty, getVectorByConnection, handleLineCreating, hasIllegalElbowPoint, insertElement, isHitDrawElement, isHitEdgeOfShape, isHitElementInside, isHitLine, isHitLineText, isHitPolyLine, isInsideOfShape, isRectangleHitDrawElement, isSelfLoop, isTextExceedingBounds, isUpdatedHandleIndex, isUseDefaultOrthogonalRoute, memorizeLatestShape, memorizeLatestText, withDraw, withLineAutoComplete };
5261
+ export { BasicShapes, DEFAULT_IMAGE_WIDTH, DefaultBasicShapeProperty, DefaultCloudShapeProperty, DefaultConnectorProperty, DefaultDataProperty, DefaultDecisionProperty, DefaultFlowchartProperty, DefaultFlowchartPropertyMap, DefaultGeometryActiveStyle, DefaultGeometryStyle, DefaultManualInputProperty, DefaultMergeProperty, DefaultTextProperty, DrawThemeColors, DrawTransforms, FlowchartSymbols, GeometryComponent, GeometryThreshold, LINE_HIT_GEOMETRY_BUFFER, LINE_SNAPPING_BUFFER, LINE_SNAPPING_CONNECTOR_BUFFER, LineComponent, LineHandleKey, LineMarkerType, LineShape, MemorizeKey, PlaitDrawElement, PlaitGeometry, PlaitLine, Q2C, ShapeDefaultSpace, StrokeStyle, WithLineAutoCompletePluginKey, alignElbowSegment, alignPoints, createDefaultFlowchart, createDefaultGeometry, createGeometryElement, createLineElement, createTextElement, drawBoundReaction, drawGeometry, drawLine, drawLineArrow, getAutoCompletePoints, getBasicPointers, getCenterPointsOnPolygon, getConnectionPoint, getCurvePoints, getDefaultFlowchartProperty, getDefaultGeometryPoints, getDefaultGeometryProperty, getDefaultTextPoints, getDrawDefaultStrokeColor, getElbowLineRouteOptions, getElbowPoints, getFillByElement, getFlowchartDefaultFill, getFlowchartPointers, getGeometryPointers, getHitConnection, getHitConnectorPoint, getHitIndexOfAutoCompletePoint, getIndexAndDeleteCountByKeyPoint, getLineDashByElement, getLineHandleRefPair, getLineMemorizedLatest, getLinePointers, getLinePoints, getLineTextRectangle, getLines, getMemorizeKey, getMemorizedLatestByPointer, getMemorizedLatestShape, getMidKeyPoints, getMiddlePoints, getMirrorDataPoints, getNearestPoint, getNextRenderPoints, getNextSourceAndTargetPoints, getResizedPreviousAndNextPoint, getSelectedDrawElements, getSelectedGeometryElements, getSelectedImageElements, getSelectedLineElements, getSourceAndTargetRectangle, getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement, getTextRectangle, getTextShapeProperty, getVectorByConnection, handleLineCreating, hasIllegalElbowPoint, insertElement, isHitDrawElement, isHitEdgeOfShape, isHitElementInside, isHitLine, isHitLineText, isHitPolyLine, isInsideOfShape, isRectangleHitDrawElement, isSelfLoop, isTextExceedingBounds, isUpdatedHandleIndex, isUseDefaultOrthogonalRoute, memorizeLatestShape, memorizeLatestText, withDraw, withLineAutoComplete };
5078
5262
  //# sourceMappingURL=plait-draw.mjs.map