@plait/draw 0.52.0 → 0.53.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.
@@ -1,5 +1,5 @@
1
- import { ACTIVE_STROKE_WIDTH, ThemeColorMode, Point, RectangleClient, getElementById, createG, arrowPoints, createPath, distanceBetweenPointAndPoint, drawLinearPath, rotate, depthFirstRecursion, getIsRecursionFunc, idCreator, catmullRomFitting, PlaitBoard, findElements, createMask, createRect, getSelectedElements, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPolylineHitRectangle, setStrokeLinecap, isPointInPolygon, getNearestPointBetweenPointAndSegments, isPointInEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, drawCircle, Transforms, clearSelectedElement, addSelectedElement, BoardTransforms, PlaitPointerType, Direction, Path, PlaitNode, toViewBoxPoint, toHostPoint, isSelectionMoving, RgbaToHEX, PlaitElement, preventTouchMove, createClipboardContext, WritableClipboardType, addClipboardContext, getRectangleByElements, getHitElementByPoint, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER, getRectangleByGroup, getElementsInGroup, isSelectedElementOrGroup, PlaitGroupElement } from '@plait/core';
2
- import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator, getRectangleResizeHandleRefs, RESIZE_HANDLE_DIAMETER, getMemorizedLatest, memorizeLatest, getPointOnPolyline, rotatePoints, TRANSPARENT, getCrossingPointsBetweenPointAndSegment, isPointOnSegment, getDirectionByVector, getOppositeDirection, getDirectionFactor, getDirectionByPointOfRectangle, rotateVectorAnti90, getSourceAndTargetOuterRectangle, getNextPoint, normalizeShapePoints, getFirstTextEditor, PRIMARY_COLOR, CommonPluginElement, ActiveGenerator, WithTextPluginKey, drawPrimaryHandle, drawFillPrimaryHandle, isVirtualKey, isDelete, isSpaceHotkey, isDndMode, isDrawingMode, getElementsText, acceptImageTypes, getElementOfFocusedImage, buildImage, 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, rotatePoints, depthFirstRecursion, rotateAntiPointsByElement, getIsRecursionFunc, idCreator, catmullRomFitting, PlaitBoard, findElements, createMask, createRect, getSelectedElements, distanceBetweenPointAndSegments, HIT_DISTANCE_BUFFER, isPolylineHitRectangle, isPointInPolygon, setStrokeLinecap, getNearestPointBetweenPointAndSegments, isPointInEllipse, getEllipseTangentSlope, getVectorFromPointAndSlope, drawRectangle, drawRoundRectangle, isPointInRoundRectangle, 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, getRectangleByElements, getSelectionAngle, rotatedDataPoints, setAngleForG, CursorClass, temporaryDisableSelection, PRESS_AND_MOVE_BUFFER } from '@plait/core';
2
+ import { removeDuplicatePoints, generateElbowLineRoute, simplifyOrthogonalPoints, isSourceAndTargetIntersect, getPoints, getPointByVectorComponent, getExtendPoint, getUnitVectorByPointAndPoint, Generator, getRectangleResizeHandleRefs, RESIZE_HANDLE_DIAMETER, getMemorizedLatest, memorizeLatest, getPointOnPolyline, TRANSPARENT, 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, getDirectionFactorByDirectionComponent, isCornerHandle, resetPointsAfterResize, getFirstTextManage, withResize, drawHandle, getIndexByResizeHandle, getSymmetricHandleIndex, getResizeHandlePointByIndex, isResizingByCondition, getRatioByPoint, ImageGenerator, ResizeHandle } 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';
@@ -166,6 +166,8 @@ const LINE_AUTO_COMPLETE_HOVERED_OPACITY = 0.8;
166
166
  const LINE_AUTO_COMPLETE_HOVERED_DIAMETER = 10;
167
167
  const LINE_ALIGN_TOLERANCE = 3;
168
168
 
169
+ const debugKey$2 = 'debug:plait:line-mirror';
170
+ const debugGenerator$2 = createDebugGenerator(debugKey$2);
169
171
  const alignPoints = (basePoint, movingPoint) => {
170
172
  const newPoint = [...movingPoint];
171
173
  if (Point.isVertical(newPoint, basePoint, LINE_ALIGN_TOLERANCE)) {
@@ -429,6 +431,7 @@ function findOrthogonalParallelSegments(segment, keyPoints) {
429
431
  return parallelSegments;
430
432
  }
431
433
  function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, targetRectangle) {
434
+ debugGenerator$2.isDebug() && debugGenerator$2.clear();
432
435
  const mirrorSegments = [];
433
436
  for (let index = 0; index < parallelSegments.length; index++) {
434
437
  const parallelPath = parallelSegments[index];
@@ -442,14 +445,7 @@ function findMirrorSegments(board, segment, parallelSegments, sourceRectangle, t
442
445
  const isValid = !RectangleClient.isHit(fakeRectangle, sourceRectangle) && !RectangleClient.isHit(fakeRectangle, targetRectangle);
443
446
  if (isValid) {
444
447
  mirrorSegments.push([startPoint, endPoint]);
445
- // const fakeRectangleG = PlaitBoard.getRoughSVG(board).rectangle(
446
- // fakeRectangle.x,
447
- // fakeRectangle.y,
448
- // fakeRectangle.width,
449
- // fakeRectangle.height,
450
- // { stroke: 'blue' }
451
- // );
452
- // PlaitBoard.getElementActiveHost(board).append(fakeRectangleG);
448
+ debugGenerator$2.isDebug() && debugGenerator$2.drawPolygon(board, RectangleClient.getCornerPoints(fakeRectangle));
453
449
  }
454
450
  }
455
451
  return mirrorSegments;
@@ -549,8 +545,16 @@ const getSourceAndTargetRectangle = (board, element, handleRefPair) => {
549
545
  const target = handleRefPair.target;
550
546
  targetElement = createFakeElement(target.point, target.vector);
551
547
  }
552
- const sourceRectangle = RectangleClient.inflate(RectangleClient.getRectangleByPoints(sourceElement.points), getStrokeWidthByElement(sourceElement) * 2);
553
- const targetRectangle = RectangleClient.inflate(RectangleClient.getRectangleByPoints(targetElement.points), getStrokeWidthByElement(targetElement) * 2);
548
+ let sourceRectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
549
+ const rotatedSourceCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(sourceRectangle), sourceElement) ||
550
+ RectangleClient.getCornerPoints(sourceRectangle);
551
+ sourceRectangle = RectangleClient.getRectangleByPoints(rotatedSourceCornerPoints);
552
+ sourceRectangle = RectangleClient.inflate(sourceRectangle, getStrokeWidthByElement(sourceElement) * 2);
553
+ let targetRectangle = RectangleClient.getRectangleByPoints(targetElement.points);
554
+ const rotatedTargetCornerPoints = rotatePointsByElement(RectangleClient.getCornerPoints(targetRectangle), targetElement) ||
555
+ RectangleClient.getCornerPoints(targetRectangle);
556
+ targetRectangle = RectangleClient.getRectangleByPoints(rotatedTargetCornerPoints);
557
+ targetRectangle = RectangleClient.inflate(targetRectangle, getStrokeWidthByElement(targetElement) * 2);
554
558
  return {
555
559
  sourceRectangle,
556
560
  targetRectangle
@@ -706,10 +710,12 @@ class LineShapeGenerator extends Generator {
706
710
  }
707
711
  }
708
712
 
709
- const getHitRectangleResizeHandleRef = (board, rectangle, point) => {
710
- const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER);
713
+ const getHitRectangleResizeHandleRef = (board, rectangle, point, angle = 0) => {
714
+ const centerPoint = RectangleClient.getCenterPoint(rectangle);
715
+ const rotatedPoint = rotatePoints([point], centerPoint, -angle)[0];
716
+ const resizeHandleRefs = getRectangleResizeHandleRefs(rectangle, RESIZE_HANDLE_DIAMETER, angle);
711
717
  const result = resizeHandleRefs.find(resizeHandleRef => {
712
- return RectangleClient.isHit(RectangleClient.getRectangleByPoints([point, point]), resizeHandleRef.rectangle);
718
+ return RectangleClient.isHit(RectangleClient.getRectangleByPoints([rotatedPoint, rotatedPoint]), resizeHandleRef.rectangle);
713
719
  });
714
720
  return result;
715
721
  };
@@ -720,7 +726,7 @@ const getHitOutlineGeometry = (board, point, offset = 0) => {
720
726
  let client = RectangleClient.getRectangleByPoints(node.points);
721
727
  client = RectangleClient.getOutlineRectangle(client, offset);
722
728
  const shape = getShape(node);
723
- const isHit = getEngine(shape).isInsidePoint(client, point);
729
+ const isHit = getEngine(shape).isInsidePoint(client, rotateAntiPointsByElement(point, node) || point);
724
730
  if (isHit) {
725
731
  geometry = node;
726
732
  }
@@ -996,8 +1002,12 @@ const Q2C = (points) => {
996
1002
  };
997
1003
  const handleLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceElement, lineShapeG) => {
998
1004
  const hitElement = getHitOutlineGeometry(board, movingPoint, REACTION_MARGIN);
999
- const targetConnection = hitElement ? getConnectionByNearestPoint(board, movingPoint, hitElement) : undefined;
1000
- const connection = sourceElement ? getConnectionByNearestPoint(board, sourcePoint, sourceElement) : undefined;
1005
+ const targetConnection = hitElement
1006
+ ? getConnectionByNearestPoint(board, rotateAntiPointsByElement(movingPoint, hitElement) || movingPoint, hitElement)
1007
+ : undefined;
1008
+ const sourceConnection = sourceElement
1009
+ ? getConnectionByNearestPoint(board, rotateAntiPointsByElement(sourcePoint, sourceElement) || sourcePoint, sourceElement)
1010
+ : undefined;
1001
1011
  const targetBoundId = hitElement ? hitElement.id : undefined;
1002
1012
  const lineGenerator = new LineShapeGenerator(board);
1003
1013
  const memorizedLatest = getLineMemorizedLatest();
@@ -1006,7 +1016,7 @@ const handleLineCreating = (board, lineShape, sourcePoint, movingPoint, sourceEl
1006
1016
  targetMarker = memorizedLatest.target;
1007
1017
  sourceMarker && delete memorizedLatest.source;
1008
1018
  targetMarker && delete memorizedLatest.target;
1009
- const temporaryLineElement = createLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || LineMarkerType.none, connection: connection, boundId: sourceElement?.id }, { marker: targetMarker || LineMarkerType.arrow, connection: targetConnection, boundId: targetBoundId }, [], {
1019
+ const temporaryLineElement = createLineElement(lineShape, [sourcePoint, movingPoint], { marker: sourceMarker || LineMarkerType.none, connection: sourceConnection, boundId: sourceElement?.id }, { marker: targetMarker || LineMarkerType.arrow, connection: targetConnection, boundId: targetBoundId }, [], {
1010
1020
  strokeWidth: DefaultLineStyle.strokeWidth,
1011
1021
  ...memorizedLatest
1012
1022
  });
@@ -1157,7 +1167,7 @@ const isRectangleHitDrawElement = (board, element, selection) => {
1157
1167
  if (PlaitDrawElement.isImage(element)) {
1158
1168
  const client = RectangleClient.getRectangleByPoints(element.points);
1159
1169
  const rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), RectangleClient.getCenterPoint(client), element.angle);
1160
- return isPolylineHitRectangle(rotatedCornerPoints, client);
1170
+ return isPolylineHitRectangle(rotatedCornerPoints, rangeRectangle);
1161
1171
  }
1162
1172
  if (PlaitDrawElement.isLine(element)) {
1163
1173
  const points = getLinePoints(board, element);
@@ -1203,7 +1213,9 @@ const isHitDrawElement = (board, element, point) => {
1203
1213
  }
1204
1214
  }
1205
1215
  if (PlaitDrawElement.isImage(element)) {
1206
- return isRectangleHitDrawElement(board, element, { anchor: point, focus: point });
1216
+ const client = RectangleClient.getRectangleByPoints(element.points);
1217
+ const rotatedCornerPoints = rotatePoints(RectangleClient.getCornerPoints(client), RectangleClient.getCenterPoint(client), element.angle);
1218
+ return isPointInPolygon(point, rotatedCornerPoints);
1207
1219
  }
1208
1220
  if (PlaitDrawElement.isLine(element)) {
1209
1221
  return isHitLine(board, element, point);
@@ -2537,24 +2549,36 @@ const getLineHandleRefPair = (board, element) => {
2537
2549
  if (sourceBoundElement) {
2538
2550
  const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.source) ? 0 : strokeWidth;
2539
2551
  const sourceVector = getVectorByConnection(sourceBoundElement, element.source.connection);
2540
- const direction = getDirectionByVector(sourceVector);
2541
- sourceDirection = direction ? direction : sourceDirection;
2542
- sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
2552
+ sourceHandleRef.vector = sourceVector;
2543
2553
  sourceHandleRef.boundElement = sourceBoundElement;
2554
+ if (hasValidAngle(sourceBoundElement)) {
2555
+ const direction = getDirectionByVector(rotateVector(sourceVector, sourceBoundElement.angle));
2556
+ sourceDirection = direction ? direction : sourceDirection;
2557
+ }
2558
+ else {
2559
+ const direction = getDirectionByVector(sourceVector);
2560
+ sourceDirection = direction ? direction : sourceDirection;
2561
+ }
2544
2562
  sourceHandleRef.direction = sourceDirection;
2545
- sourceHandleRef.point = sourcePoint;
2546
- sourceHandleRef.vector = sourceVector;
2563
+ sourcePoint = getConnectionPoint(sourceBoundElement, element.source.connection, sourceDirection, connectionOffset);
2564
+ sourceHandleRef.point = rotatePointsByElement(sourcePoint, sourceBoundElement) || sourcePoint;
2547
2565
  }
2548
2566
  if (targetBoundElement) {
2549
2567
  const connectionOffset = PlaitLine.isSourceMarkOrTargetMark(element, LineMarkerType.none, LineHandleKey.target) ? 0 : strokeWidth;
2550
2568
  const targetVector = getVectorByConnection(targetBoundElement, element.target.connection);
2551
- const direction = getDirectionByVector(targetVector);
2552
- targetDirection = direction ? direction : targetDirection;
2553
- targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
2569
+ targetHandleRef.vector = targetVector;
2554
2570
  targetHandleRef.boundElement = targetBoundElement;
2571
+ if (hasValidAngle(targetBoundElement)) {
2572
+ const direction = getDirectionByVector(rotateVector(targetVector, targetBoundElement.angle));
2573
+ targetDirection = direction ? direction : targetDirection;
2574
+ }
2575
+ else {
2576
+ const direction = getDirectionByVector(targetVector);
2577
+ targetDirection = direction ? direction : targetDirection;
2578
+ }
2555
2579
  targetHandleRef.direction = targetDirection;
2556
- targetHandleRef.point = targetPoint;
2557
- targetHandleRef.vector = targetVector;
2580
+ targetPoint = getConnectionPoint(targetBoundElement, element.target.connection, targetDirection, connectionOffset);
2581
+ targetHandleRef.point = rotatePointsByElement(targetPoint, targetBoundElement) || targetPoint;
2558
2582
  }
2559
2583
  return { source: sourceHandleRef, target: targetHandleRef };
2560
2584
  };
@@ -2659,12 +2683,24 @@ const PlaitLine = {
2659
2683
  return line.target.boundId === element.id;
2660
2684
  },
2661
2685
  getPoints(board, line) {
2662
- let sourcePoint = line.source.boundId
2663
- ? getConnectionPoint(getElementById(board, line.source.boundId), line.source.connection)
2664
- : line.points[0];
2665
- let targetPoint = line.target.boundId
2666
- ? getConnectionPoint(getElementById(board, line.target.boundId), line.target.connection)
2667
- : line.points[line.points.length - 1];
2686
+ let sourcePoint;
2687
+ if (line.source.boundId) {
2688
+ const sourceElement = getElementById(board, line.source.boundId);
2689
+ const sourceConnectionPoint = getConnectionPoint(sourceElement, line.source.connection);
2690
+ sourcePoint = rotatePointsByElement(sourceConnectionPoint, sourceElement) || sourceConnectionPoint;
2691
+ }
2692
+ else {
2693
+ sourcePoint = line.points[0];
2694
+ }
2695
+ let targetPoint;
2696
+ if (line.target.boundId) {
2697
+ const targetElement = getElementById(board, line.target.boundId);
2698
+ const targetConnectionPoint = getConnectionPoint(targetElement, line.target.connection);
2699
+ targetPoint = rotatePointsByElement(targetConnectionPoint, targetElement) || targetConnectionPoint;
2700
+ }
2701
+ else {
2702
+ targetPoint = line.points[line.points.length - 1];
2703
+ }
2668
2704
  const restPoints = line.points.length > 2 ? line.points.slice(1, line.points.length - 1) : [];
2669
2705
  return [sourcePoint, ...restPoints, targetPoint];
2670
2706
  }
@@ -3235,6 +3271,8 @@ class LineActiveGenerator extends Generator {
3235
3271
  }
3236
3272
  }
3237
3273
 
3274
+ const debugKey$1 = 'debug:plait:line-turning';
3275
+ const debugGenerator$1 = createDebugGenerator(debugKey$1);
3238
3276
  class LineComponent extends CommonPluginElement {
3239
3277
  constructor(viewContainerRef, cdr) {
3240
3278
  super(cdr);
@@ -3259,21 +3297,7 @@ class LineComponent extends CommonPluginElement {
3259
3297
  super.ngOnInit();
3260
3298
  this.boundedElements = this.getBoundedElements();
3261
3299
  this.drawText();
3262
- // const points = this.element.points;
3263
- // points.forEach((p, index) => {
3264
- // if (index === 0) {
3265
- // return;
3266
- // }
3267
- // if (index === points.length - 1) {
3268
- // return;
3269
- // }
3270
- // const dataPointG = PlaitBoard.getRoughSVG(this.board).circle(p[0], p[1], 8 * index, {
3271
- // stroke: '#f08c02',
3272
- // fill: '#f08c02',
3273
- // fillStyle: 'solid'
3274
- // });
3275
- // PlaitBoard.getElementActiveHost(this.board).append(dataPointG);
3276
- // });
3300
+ debugGenerator$1.isDebug() && debugGenerator$1.drawCircles(this.board, this.element.points.slice(1, -1), 4, true);
3277
3301
  }
3278
3302
  getBoundedElements() {
3279
3303
  const boundedElements = {};
@@ -3429,10 +3453,13 @@ const withDrawHotkey = (board) => {
3429
3453
  };
3430
3454
  board.dblClick = (event) => {
3431
3455
  event.preventDefault();
3432
- const geometries = getSelectedGeometryElements(board);
3433
- if (!PlaitBoard.isReadonly(board) && geometries.length === 1) {
3434
- const component = PlaitElement.getComponent(geometries[0]);
3435
- component.editText();
3456
+ if (!PlaitBoard.isReadonly(board)) {
3457
+ const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3458
+ const hitElement = getHitElementByPoint(board, point);
3459
+ if (hitElement && PlaitDrawElement.isGeometry(hitElement)) {
3460
+ const component = PlaitElement.getComponent(hitElement);
3461
+ component.editText();
3462
+ }
3436
3463
  }
3437
3464
  dblClick(event);
3438
3465
  };
@@ -4122,6 +4149,8 @@ function getResizeAlignRef(board, resizeRef, resizeState, resizeOriginPointAndHa
4122
4149
  });
4123
4150
  }
4124
4151
 
4152
+ const debugKey = 'debug:plait:resize-for-rotation';
4153
+ const debugGenerator = createDebugGenerator(debugKey);
4125
4154
  function withDrawResize(board) {
4126
4155
  const { afterChange } = board;
4127
4156
  let alignG;
@@ -4136,7 +4165,8 @@ function withDrawResize(board) {
4136
4165
  hitTest: (point) => {
4137
4166
  const elements = getSelectedElements(board);
4138
4167
  const boundingRectangle = getRectangleByElements(board, elements, false);
4139
- const handleRef = getHitRectangleResizeHandleRef(board, boundingRectangle, point);
4168
+ const angle = getSelectionAngle(elements);
4169
+ const handleRef = getHitRectangleResizeHandleRef(board, boundingRectangle, point, angle);
4140
4170
  if (handleRef) {
4141
4171
  return {
4142
4172
  element: elements,
@@ -4149,20 +4179,66 @@ function withDrawResize(board) {
4149
4179
  },
4150
4180
  onResize: (resizeRef, resizeState) => {
4151
4181
  alignG?.remove();
4182
+ debugGenerator.isDebug() && debugGenerator.clear();
4152
4183
  const isFromCorner = isCornerHandle(board, resizeRef.handle);
4153
4184
  const isAspectRatio = resizeState.isShift || isFromCorner;
4185
+ const centerPoint = RectangleClient.getCenterPoint(resizeRef.rectangle);
4154
4186
  const { originPoint, handlePoint } = getResizeOriginPointAndHandlePoint(board, resizeRef);
4187
+ const angle = getSelectionAngle(resizeRef.element);
4188
+ let bulkRotationRef;
4189
+ if (angle) {
4190
+ bulkRotationRef = {
4191
+ angle: angle,
4192
+ offsetX: 0,
4193
+ offsetY: 0,
4194
+ newCenterPoint: [0, 0]
4195
+ };
4196
+ const [rotatedStartPoint, rotateEndPoint] = rotatePoints([resizeState.startPoint, resizeState.endPoint], centerPoint, -bulkRotationRef.angle);
4197
+ resizeState.startPoint = rotatedStartPoint;
4198
+ resizeState.endPoint = rotateEndPoint;
4199
+ }
4155
4200
  const resizeAlignRef = getResizeAlignRef(board, resizeRef, resizeState, {
4156
4201
  originPoint,
4157
4202
  handlePoint
4158
4203
  }, isAspectRatio, isFromCorner);
4159
4204
  alignG = resizeAlignRef.alignG;
4160
4205
  PlaitBoard.getElementActiveHost(board).append(alignG);
4161
- resizeRef.element.forEach(target => {
4162
- const path = PlaitBoard.findPath(board, target);
4163
- let points = target.points.map(p => {
4206
+ if (bulkRotationRef) {
4207
+ const boundingBoxCornerPoints = RectangleClient.getPoints(resizeRef.rectangle);
4208
+ const resizedBoundingBoxCornerPoints = boundingBoxCornerPoints.map(p => {
4164
4209
  return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4165
4210
  });
4211
+ const newBoundingBox = RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints);
4212
+ debugGenerator.isDebug() && debugGenerator.drawRectangle(board, newBoundingBox, { stroke: 'blue' });
4213
+ const newBoundingBoxCenter = RectangleClient.getCenterPoint(newBoundingBox);
4214
+ const adjustedNewBoundingBoxPoints = resetPointsAfterResize(RectangleClient.getRectangleByPoints(boundingBoxCornerPoints), RectangleClient.getRectangleByPoints(resizedBoundingBoxCornerPoints), centerPoint, newBoundingBoxCenter, bulkRotationRef.angle);
4215
+ const newCenter = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(adjustedNewBoundingBoxPoints));
4216
+ bulkRotationRef = Object.assign(bulkRotationRef, {
4217
+ offsetX: newCenter[0] - newBoundingBoxCenter[0],
4218
+ offsetY: newCenter[1] - newBoundingBoxCenter[1],
4219
+ newCenterPoint: newCenter
4220
+ });
4221
+ debugGenerator.isDebug() && debugGenerator.drawRectangle(board, adjustedNewBoundingBoxPoints);
4222
+ }
4223
+ resizeRef.element.forEach(target => {
4224
+ const path = PlaitBoard.findPath(board, target);
4225
+ let points;
4226
+ if (bulkRotationRef) {
4227
+ const reversedPoints = rotatedDataPoints(target.points, centerPoint, -bulkRotationRef.angle);
4228
+ points = reversedPoints.map((p) => {
4229
+ return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4230
+ });
4231
+ const adjustTargetPoints = points.map(p => [
4232
+ p[0] + bulkRotationRef.offsetX,
4233
+ p[1] + bulkRotationRef.offsetY
4234
+ ]);
4235
+ points = rotatedDataPoints(adjustTargetPoints, bulkRotationRef.newCenterPoint, bulkRotationRef.angle);
4236
+ }
4237
+ else {
4238
+ points = target.points.map(p => {
4239
+ return movePointByZoomAndOriginPoint(p, originPoint, resizeAlignRef.xZoom, resizeAlignRef.yZoom);
4240
+ });
4241
+ }
4166
4242
  if (PlaitDrawElement.isGeometry(target)) {
4167
4243
  const { height: textHeight } = getFirstTextManage(target).getSize();
4168
4244
  DrawTransforms.resizeGeometry(board, points, textHeight, path);
@@ -4201,8 +4277,13 @@ function withDrawResize(board) {
4201
4277
  handleG = createG();
4202
4278
  const elements = getSelectedElements(board);
4203
4279
  const boundingRectangle = getRectangleByElements(board, elements, false);
4204
- const corners = RectangleClient.getCornerPoints(boundingRectangle);
4205
- corners.forEach((corner) => {
4280
+ let corners = RectangleClient.getCornerPoints(boundingRectangle);
4281
+ const angle = getSelectionAngle(elements);
4282
+ if (angle) {
4283
+ const centerPoint = RectangleClient.getCenterPoint(boundingRectangle);
4284
+ corners = rotatePoints(corners, centerPoint, angle);
4285
+ }
4286
+ corners.forEach(corner => {
4206
4287
  const g = drawHandle(board, corner);
4207
4288
  handleG && handleG.append(g);
4208
4289
  });
@@ -4281,7 +4362,7 @@ const withGeometryResize = (board) => {
4281
4362
  const targetComponent = PlaitElement.getComponent(selectedElements[0]);
4282
4363
  if (targetComponent.activeGenerator.hasResizeHandle) {
4283
4364
  const rectangle = board.getRectangle(target);
4284
- const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point);
4365
+ const handleRef = getHitRectangleResizeHandleRef(board, rectangle, point, target.angle);
4285
4366
  if (handleRef) {
4286
4367
  return {
4287
4368
  element: target,
@@ -4294,6 +4375,13 @@ const withGeometryResize = (board) => {
4294
4375
  return null;
4295
4376
  },
4296
4377
  onResize: (resizeRef, resizeState) => {
4378
+ const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(resizeRef.element.points));
4379
+ const angle = resizeRef.element.angle;
4380
+ if (angle) {
4381
+ const [rotatedStartPoint, rotateEndPoint] = rotatePoints([resizeState.startPoint, resizeState.endPoint], centerPoint, -resizeRef.element.angle);
4382
+ resizeState.startPoint = rotatedStartPoint;
4383
+ resizeState.endPoint = rotateEndPoint;
4384
+ }
4297
4385
  alignG?.remove();
4298
4386
  const isFromCorner = isCornerHandle(board, resizeRef.handle);
4299
4387
  const isAspectRatio = resizeState.isShift || PlaitDrawElement.isImage(resizeRef.element);
@@ -4305,6 +4393,9 @@ const withGeometryResize = (board) => {
4305
4393
  alignG = resizeAlignRef.alignG;
4306
4394
  PlaitBoard.getElementActiveHost(board).append(alignG);
4307
4395
  let points = resizeAlignRef.activePoints;
4396
+ if (angle) {
4397
+ points = resetPointsAfterResize(resizeRef.rectangle, RectangleClient.getRectangleByPoints(points), centerPoint, RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(points)), angle);
4398
+ }
4308
4399
  if (PlaitDrawElement.isGeometry(resizeRef.element)) {
4309
4400
  const { height: textHeight } = getFirstTextManage(resizeRef.element).getSize();
4310
4401
  DrawTransforms.resizeGeometry(board, points, textHeight, resizeRef.path);
@@ -4382,7 +4473,7 @@ const withLineResize = (board) => {
4382
4473
  const object = resizeRef.handle === LineResizeHandle.source ? source : target;
4383
4474
  points[handleIndex] = resizeState.endPoint;
4384
4475
  if (hitElement) {
4385
- object.connection = getConnectionByNearestPoint(board, resizeState.endPoint, hitElement);
4476
+ object.connection = getConnectionByNearestPoint(board, rotateAntiPointsByElement(resizeState.endPoint, hitElement) || resizeState.endPoint, hitElement);
4386
4477
  object.boundId = hitElement.id;
4387
4478
  }
4388
4479
  else {
@@ -4490,9 +4581,9 @@ const withLineBoundReaction = (board) => {
4490
4581
  if (isLinePointer || isLineResizing) {
4491
4582
  const hitElement = getHitOutlineGeometry(board, movingPoint, -4);
4492
4583
  if (hitElement) {
4493
- boundShapeG = drawBoundMask(board, hitElement);
4494
- let nearestPoint = getNearestPoint(hitElement, movingPoint);
4495
4584
  const rectangle = RectangleClient.getRectangleByPoints(hitElement.points);
4585
+ boundShapeG = drawBoundMask(board, hitElement);
4586
+ let nearestPoint = getNearestPoint(hitElement, rotateAntiPointsByElement(movingPoint, hitElement) || movingPoint);
4496
4587
  const activeRectangle = RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH);
4497
4588
  const hitConnector = getHitConnectorPoint(nearestPoint, hitElement, activeRectangle);
4498
4589
  nearestPoint = hitConnector ? hitConnector : nearestPoint;
@@ -4504,6 +4595,9 @@ const withLineBoundReaction = (board) => {
4504
4595
  });
4505
4596
  boundShapeG.appendChild(circleG);
4506
4597
  PlaitBoard.getElementActiveHost(board).append(boundShapeG);
4598
+ if (hasValidAngle(hitElement)) {
4599
+ setAngleForG(boundShapeG, RectangleClient.getCenterPoint(rectangle), hitElement.angle);
4600
+ }
4507
4601
  }
4508
4602
  }
4509
4603
  pointerMove(event);
@@ -4654,7 +4748,7 @@ const withLineAutoCompleteReaction = (board) => {
4654
4748
  const movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4655
4749
  if (!PlaitBoard.isReadonly(board) && !isSelectionMoving(board) && targetElement && PlaitDrawElement.isShape(targetElement)) {
4656
4750
  const points = getAutoCompletePoints(targetElement);
4657
- const hitIndex = getHitIndexOfAutoCompletePoint(movingPoint, points);
4751
+ const hitIndex = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(movingPoint, targetElement) || movingPoint, points);
4658
4752
  const hitPoint = points[hitIndex];
4659
4753
  const component = PlaitElement.getComponent(targetElement);
4660
4754
  component.lineAutoCompleteGenerator.recoverAutoCompleteG();
@@ -4667,6 +4761,9 @@ const withLineAutoCompleteReaction = (board) => {
4667
4761
  });
4668
4762
  PlaitBoard.getElementActiveHost(board).append(reactionG);
4669
4763
  PlaitBoard.getBoardContainer(board).classList.add(CursorClass.crosshair);
4764
+ if (hasValidAngle(targetElement)) {
4765
+ setAngleForG(reactionG, RectangleClient.getCenterPoint(board.getRectangle(targetElement)), targetElement.angle);
4766
+ }
4670
4767
  }
4671
4768
  }
4672
4769
  pointerMove(event);
@@ -4687,7 +4784,7 @@ const withLineAutoComplete = (board) => {
4687
4784
  const clickPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4688
4785
  if (!PlaitBoard.isReadonly(board) && targetElement && PlaitDrawElement.isShape(targetElement)) {
4689
4786
  const points = getAutoCompletePoints(targetElement);
4690
- const index = getHitIndexOfAutoCompletePoint(clickPoint, points);
4787
+ const index = getHitIndexOfAutoCompletePoint(rotateAntiPointsByElement(clickPoint, targetElement) || clickPoint, points);
4691
4788
  const hitPoint = points[index];
4692
4789
  if (hitPoint) {
4693
4790
  temporaryDisableSelection(board);
@@ -4703,7 +4800,7 @@ const withLineAutoComplete = (board) => {
4703
4800
  lineShapeG = createG();
4704
4801
  let movingPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4705
4802
  if (startPoint && sourceElement) {
4706
- const distance = distanceBetweenPointAndPoint(...movingPoint, ...startPoint);
4803
+ const distance = distanceBetweenPointAndPoint(...movingPoint, ...(rotatePointsByElement(startPoint, sourceElement) || startPoint));
4707
4804
  if (distance > PRESS_AND_MOVE_BUFFER) {
4708
4805
  const rectangle = RectangleClient.getRectangleByPoints(sourceElement.points);
4709
4806
  const shape = getShape(sourceElement);
@@ -4713,7 +4810,7 @@ const withLineAutoComplete = (board) => {
4713
4810
  const crossingPoint = engine.getNearestCrossingPoint(rectangle, startPoint);
4714
4811
  sourcePoint = crossingPoint;
4715
4812
  }
4716
- temporaryElement = handleLineCreating(board, LineShape.elbow, sourcePoint, movingPoint, sourceElement, lineShapeG);
4813
+ temporaryElement = handleLineCreating(board, LineShape.elbow, rotatePointsByElement(sourcePoint, sourceElement) || sourcePoint, movingPoint, sourceElement, lineShapeG);
4717
4814
  }
4718
4815
  }
4719
4816
  pointerMove(event);
@@ -4787,66 +4884,6 @@ const withLineTextMove = (board) => {
4787
4884
  return board;
4788
4885
  };
4789
4886
 
4790
- class GroupGenerator extends Generator {
4791
- canDraw(element) {
4792
- return true;
4793
- }
4794
- draw(element, partialSelected) {
4795
- const options = {
4796
- stroke: '',
4797
- strokeWidth: ACTIVE_STROKE_WIDTH,
4798
- strokeLineDash: [5]
4799
- };
4800
- if (partialSelected) {
4801
- options.stroke = '#999';
4802
- }
4803
- const rectangle = getRectangleByGroup(this.board, element, true);
4804
- return drawRectangle(this.board, rectangle, options);
4805
- }
4806
- }
4807
-
4808
- class GroupComponent extends CommonPluginElement {
4809
- constructor(viewContainerRef, cdr) {
4810
- super(cdr);
4811
- this.viewContainerRef = viewContainerRef;
4812
- this.cdr = cdr;
4813
- }
4814
- initializeGenerator() {
4815
- this.activeGenerator = new ActiveGenerator(this.board, {
4816
- getRectangle: (element) => {
4817
- return getRectangleByGroup(this.board, element);
4818
- },
4819
- getStrokeWidth: () => 0,
4820
- getStrokeOpacity: () => 0,
4821
- hasResizeHandle: () => {
4822
- return !isSelectionMoving(this.board);
4823
- }
4824
- });
4825
- this.groupGenerator = new GroupGenerator(this.board);
4826
- }
4827
- ngOnInit() {
4828
- super.ngOnInit();
4829
- this.initializeGenerator();
4830
- }
4831
- onContextChanged(value, previous) {
4832
- const elementsInGroup = getElementsInGroup(this.board, value.element, false, true);
4833
- const isPartialSelectGroup = elementsInGroup.some(item => isSelectedElementOrGroup(this.board, item)) &&
4834
- !elementsInGroup.every(item => isSelectedElementOrGroup(this.board, item));
4835
- this.groupGenerator.processDrawing(value.element, this.g, isPartialSelectGroup);
4836
- }
4837
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GroupComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
4838
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.2.4", type: GroupComponent, isStandalone: true, selector: "plait-group", usesInheritance: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4839
- }
4840
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: GroupComponent, decorators: [{
4841
- type: Component,
4842
- args: [{
4843
- selector: 'plait-group',
4844
- template: ``,
4845
- changeDetection: ChangeDetectionStrategy.OnPush,
4846
- standalone: true
4847
- }]
4848
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }] });
4849
-
4850
4887
  const withDraw = (board) => {
4851
4888
  const { drawElement, getRectangle, isRectangleHit, isHit, isInsidePoint, isMovable, isAlign, getRelatedFragment } = board;
4852
4889
  board.drawElement = (context) => {
@@ -4859,9 +4896,6 @@ const withDraw = (board) => {
4859
4896
  else if (PlaitDrawElement.isImage(context.element)) {
4860
4897
  return ImageComponent;
4861
4898
  }
4862
- else if (PlaitGroupElement.isGroup(context.element)) {
4863
- return GroupComponent;
4864
- }
4865
4899
  return drawElement(context);
4866
4900
  };
4867
4901
  board.getRectangle = (element) => {
@@ -4880,9 +4914,6 @@ const withDraw = (board) => {
4880
4914
  if (PlaitDrawElement.isImage(element)) {
4881
4915
  return RectangleClient.getRectangleByPoints(element.points);
4882
4916
  }
4883
- if (PlaitGroupElement.isGroup(element)) {
4884
- return getRectangleByGroup(board, element);
4885
- }
4886
4917
  return getRectangle(element);
4887
4918
  };
4888
4919
  board.isRectangleHit = (element, selection) => {