@plait/common 0.50.1 → 0.51.1

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 (37) hide show
  1. package/README.md +7 -6
  2. package/constants/default.d.ts +1 -1
  3. package/constants/resize.d.ts +8 -8
  4. package/esm2022/constants/default.mjs +2 -2
  5. package/esm2022/constants/resize.mjs +9 -9
  6. package/esm2022/core/image-base.component.mjs +4 -4
  7. package/esm2022/generators/active.generator.mjs +9 -10
  8. package/esm2022/generators/generator.mjs +6 -1
  9. package/esm2022/plugins/with-resize.mjs +53 -44
  10. package/esm2022/public-api.mjs +2 -1
  11. package/esm2022/types/resize.mjs +2 -0
  12. package/esm2022/utils/direction.mjs +5 -25
  13. package/esm2022/utils/drawing/index.mjs +2 -0
  14. package/esm2022/utils/drawing/resize-handle.mjs +23 -0
  15. package/esm2022/utils/elbow-line-route.mjs +38 -36
  16. package/esm2022/utils/index.mjs +4 -2
  17. package/esm2022/utils/line-path.mjs +23 -12
  18. package/esm2022/utils/math.mjs +24 -0
  19. package/esm2022/utils/resize.mjs +36 -23
  20. package/esm2022/utils/vector.mjs +33 -0
  21. package/fesm2022/plait-common.mjs +242 -165
  22. package/fesm2022/plait-common.mjs.map +1 -1
  23. package/package.json +1 -1
  24. package/plugins/with-resize.d.ts +3 -21
  25. package/public-api.d.ts +1 -0
  26. package/types/resize.d.ts +30 -0
  27. package/utils/direction.d.ts +2 -7
  28. package/utils/drawing/index.d.ts +1 -0
  29. package/utils/drawing/resize-handle.d.ts +4 -0
  30. package/utils/elbow-line-route.d.ts +17 -2
  31. package/utils/index.d.ts +3 -1
  32. package/utils/line-path.d.ts +1 -1
  33. package/utils/math.d.ts +3 -0
  34. package/utils/resize.d.ts +10 -8
  35. package/utils/vector.d.ts +5 -0
  36. package/esm2022/utils/rectangle.mjs +0 -16
  37. package/utils/rectangle.d.ts +0 -7
@@ -1,4 +1,4 @@
1
- import { createG, RectangleClient, drawRectangle, drawCircle, PlaitBoard, createForeignObject, updateForeignObject, ResizeCursorClass, setDragging, Direction, distanceBetweenPointAndPoint, Point, hotkeys, PlaitElement, PlaitContextService, downScale, getSelectedElements, Transforms, getRectangleByElements, MERGING, PlaitPointerType, isMainPointer, toViewBoxPoint, toHostPoint, preventTouchMove, PRESS_AND_MOVE_BUFFER, throttleRAF, handleTouchTarget, PlaitPluginElementComponent, isSelectionMoving, ACTIVE_STROKE_WIDTH } from '@plait/core';
1
+ import { setTransformRotate, drawCircle, PlaitBoard, createG, RectangleClient, drawRectangle, createForeignObject, updateForeignObject, ResizeCursorClass, setDragging, Direction, distanceBetweenPointAndPoint, Point, hotkeys, PlaitElement, PlaitContextService, getSelectedElements, Transforms, getRectangleByElements, MERGING, PlaitPointerType, isMainPointer, toViewBoxPoint, toHostPoint, preventTouchMove, PRESS_AND_MOVE_BUFFER, isDragging, throttleRAF, handleTouchTarget, PlaitPluginElementComponent, isSelectionMoving, ACTIVE_STROKE_WIDTH } from '@plait/core';
2
2
  import { isKeyHotkey } from 'is-hotkey';
3
3
  import { PlaitMarkEditor, MarkTypes, AlignEditor } from '@plait/text';
4
4
  import { Node, Transforms as Transforms$1, Editor } from 'slate';
@@ -7,7 +7,7 @@ import { Directive, Input } from '@angular/core';
7
7
 
8
8
  const BASE = 4;
9
9
  const PRIMARY_COLOR = '#6698FF';
10
- const RESIZE_HANDLE_DIAMETER = 8;
10
+ const RESIZE_HANDLE_DIAMETER = 9;
11
11
  const WithTextPluginKey = 'plait-text-plugin-key';
12
12
  const DEFAULT_ROUTE_MARGIN = 30;
13
13
  const TRANSPARENT = 'transparent';
@@ -22,14 +22,14 @@ const WithCommonPluginKey = 'plait-common-plugin-key';
22
22
 
23
23
  var ResizeHandle;
24
24
  (function (ResizeHandle) {
25
- ResizeHandle["ne"] = "ne";
26
- ResizeHandle["n"] = "n";
27
- ResizeHandle["nw"] = "nw";
28
- ResizeHandle["e"] = "e";
29
- ResizeHandle["se"] = "se";
30
- ResizeHandle["s"] = "s";
31
- ResizeHandle["sw"] = "sw";
32
- ResizeHandle["w"] = "w";
25
+ ResizeHandle["nw"] = "0";
26
+ ResizeHandle["n"] = "4";
27
+ ResizeHandle["ne"] = "1";
28
+ ResizeHandle["e"] = "5";
29
+ ResizeHandle["se"] = "2";
30
+ ResizeHandle["s"] = "6";
31
+ ResizeHandle["sw"] = "3";
32
+ ResizeHandle["w"] = "7";
33
33
  })(ResizeHandle || (ResizeHandle = {}));
34
34
 
35
35
  class Generator {
@@ -53,6 +53,10 @@ class Generator {
53
53
  }
54
54
  }
55
55
  this.g = g;
56
+ const rect = this.board.getRectangle(element);
57
+ if (rect && element.angle) {
58
+ setTransformRotate(g, rect, element.angle);
59
+ }
56
60
  }
57
61
  else {
58
62
  this.destroy();
@@ -79,6 +83,27 @@ function hasAfterDraw(value) {
79
83
  return false;
80
84
  }
81
85
 
86
+ const drawHandle = (board, centerPoint) => {
87
+ const options = { stroke: '#99999995', strokeWidth: 2, fill: '#FFF', fillStyle: 'solid' };
88
+ return drawCircle(PlaitBoard.getRoughSVG(board), centerPoint, RESIZE_HANDLE_DIAMETER, options);
89
+ };
90
+ function drawFillPrimaryHandle(board, point) {
91
+ return drawCircle(PlaitBoard.getRoughSVG(board), point, RESIZE_HANDLE_DIAMETER, {
92
+ stroke: '#FFFFFF',
93
+ strokeWidth: 1,
94
+ fill: `${PRIMARY_COLOR}`,
95
+ fillStyle: 'solid'
96
+ });
97
+ }
98
+ function drawPrimaryHandle(board, point) {
99
+ return drawCircle(PlaitBoard.getRoughSVG(board), point, RESIZE_HANDLE_DIAMETER, {
100
+ stroke: `${PRIMARY_COLOR}`,
101
+ strokeWidth: 2,
102
+ fill: `#FFFFFF`,
103
+ fillStyle: 'solid'
104
+ });
105
+ }
106
+
82
107
  class ActiveGenerator extends Generator {
83
108
  constructor(board, options) {
84
109
  super(board, options);
@@ -107,13 +132,11 @@ class ActiveGenerator extends Generator {
107
132
  strokeG.style.opacity = `${this.options.getStrokeOpacity()}`;
108
133
  if (this.options.hasResizeHandle()) {
109
134
  this.hasResizeHandle = true;
110
- // resize handle
111
- const options = { stroke: '#999999', strokeWidth: 1, fill: '#FFF', fillStyle: 'solid' };
112
- const leftTopHandleG = drawCircle(PlaitBoard.getRoughSVG(this.board), [activeRectangle.x, activeRectangle.y], RESIZE_HANDLE_DIAMETER, options);
113
- const rightTopHandleG = drawCircle(PlaitBoard.getRoughSVG(this.board), [activeRectangle.x + activeRectangle.width, activeRectangle.y], RESIZE_HANDLE_DIAMETER, options);
114
- const rightBottomHandleG = drawCircle(PlaitBoard.getRoughSVG(this.board), [activeRectangle.x + activeRectangle.width, activeRectangle.y + activeRectangle.height], RESIZE_HANDLE_DIAMETER, options);
115
- const leftBottomHandleG = drawCircle(PlaitBoard.getRoughSVG(this.board), [activeRectangle.x, activeRectangle.y + activeRectangle.height], RESIZE_HANDLE_DIAMETER, options);
116
- activeG.append(...[leftTopHandleG, rightTopHandleG, rightBottomHandleG, leftBottomHandleG]);
135
+ // draw resize handle
136
+ RectangleClient.getCornerPoints(activeRectangle).forEach(corner => {
137
+ const cornerHandleG = drawHandle(this.board, corner);
138
+ activeG.append(cornerHandleG);
139
+ });
117
140
  }
118
141
  else {
119
142
  this.hasResizeHandle = false;
@@ -174,26 +197,18 @@ class ImageGenerator extends Generator {
174
197
  }
175
198
 
176
199
  const getResizeHandleByIndex = (index) => {
177
- switch (index) {
178
- case 0:
179
- return ResizeHandle.nw;
180
- case 1:
181
- return ResizeHandle.ne;
182
- case 2:
183
- return ResizeHandle.se;
184
- case 3:
185
- return ResizeHandle.sw;
186
- case 4:
187
- return ResizeHandle.n;
188
- case 5:
189
- return ResizeHandle.e;
190
- case 6:
191
- return ResizeHandle.s;
192
- case 7:
193
- return ResizeHandle.w;
194
- default:
195
- return null;
200
+ return `${index}`;
201
+ };
202
+ const getIndexByResizeHandle = (resizeHandle) => {
203
+ return Number(resizeHandle);
204
+ };
205
+ const getSymmetricHandleIndex = (board, index) => {
206
+ const originIndex = isEdgeHandle(board, getResizeHandleByIndex(index)) ? index - 4 : index;
207
+ let originSymmetricHandleIndex = originIndex + 2;
208
+ if (originSymmetricHandleIndex >= 4) {
209
+ originSymmetricHandleIndex = originSymmetricHandleIndex - 4;
196
210
  }
211
+ return isEdgeHandle(board, getResizeHandleByIndex(index)) ? originSymmetricHandleIndex + 4 : originSymmetricHandleIndex;
197
212
  };
198
213
  const getResizeCursorClassByIndex = (index) => {
199
214
  switch (index) {
@@ -237,10 +252,20 @@ const getRectangleResizeHandleRefs = (rectangle, diameter) => {
237
252
  }));
238
253
  return refs;
239
254
  };
255
+ const getResizeHandlePointByIndex = (rectangle, index) => {
256
+ if (index <= 3) {
257
+ const corners = RectangleClient.getCornerPoints(rectangle);
258
+ return corners[index];
259
+ }
260
+ else {
261
+ const edgeCenterPoints = RectangleClient.getEdgeCenterPoints(rectangle);
262
+ return edgeCenterPoints[index - 4];
263
+ }
264
+ };
240
265
  const getResizeSideRectangles = (cornerPoints, offset) => {
241
266
  const result = [];
242
267
  for (let i = 0; i < cornerPoints.length; i++) {
243
- let rectangle = RectangleClient.toRectangleClient([cornerPoints[i], cornerPoints[(i + 1) % 4]]);
268
+ let rectangle = RectangleClient.getRectangleByPoints([cornerPoints[i], cornerPoints[(i + 1) % 4]]);
244
269
  const arr = new Array(2).fill(0);
245
270
  arr[(i + 1) % 2] = offset / 2;
246
271
  rectangle = RectangleClient.expand(rectangle, arr[0], arr[1]);
@@ -265,6 +290,18 @@ const removeResizing = (board, key) => {
265
290
  IS_RESIZING.delete(board);
266
291
  setDragging(board, false);
267
292
  };
293
+ const isEdgeHandle = (board, handle) => {
294
+ const index = getIndexByResizeHandle(handle);
295
+ if (index >= 4) {
296
+ return true;
297
+ }
298
+ else {
299
+ return false;
300
+ }
301
+ };
302
+ const isCornerHandle = (board, handle) => {
303
+ return !isEdgeHandle(board, handle);
304
+ };
268
305
 
269
306
  const handleDirectionFactors = {
270
307
  [Direction.left]: { x: -1, y: 0 },
@@ -319,17 +356,6 @@ function getDirectionByVector(vector) {
319
356
  return Direction.left;
320
357
  }
321
358
  }
322
- function getPointByVector(point, vector, offset) {
323
- const distance = Math.hypot(vector[0], vector[1]);
324
- return [point[0] + (vector[0] / distance) * offset, point[1] + (vector[1] / distance) * offset];
325
- }
326
- function rotateVectorAnti90(vector) {
327
- const x = vector[0];
328
- const y = vector[1];
329
- const rotatedX = y;
330
- const rotatedY = -x;
331
- return [rotatedX, rotatedY];
332
- }
333
359
  function getDirectionBetweenPointAndPoint(source, target) {
334
360
  if (source[0] === target[0]) {
335
361
  if (source[1] >= target[1]) {
@@ -352,19 +378,65 @@ function getDirectionBetweenPointAndPoint(source, target) {
352
378
  function getDirectionFactor(direction) {
353
379
  return handleDirectionFactors[direction];
354
380
  }
355
- function getFactorByPoints(source, target) {
356
- const distance = distanceBetweenPointAndPoint(...source, ...target);
357
- if (Point.isEquals(source, target)) {
358
- return {
359
- x: 1,
360
- y: 1
361
- };
381
+ function getDirectionFactorByVectorComponent(vectorComponent) {
382
+ const directionFactor = vectorComponent === 0 ? vectorComponent : vectorComponent / Math.abs(vectorComponent);
383
+ return directionFactor;
384
+ }
385
+
386
+ function getUnitVectorByPointAndPoint(point1, point2) {
387
+ const deltaX = point2[0] - point1[0];
388
+ const deltaY = point2[1] - point1[1];
389
+ const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
390
+ // Avoid division by zero if the points are the same
391
+ if (distance === 0) {
392
+ throw new Error('Points must not be the same for a unit vector calculation.');
393
+ }
394
+ // Calculate the unit vector components
395
+ const unitX = deltaX / distance;
396
+ const unitY = deltaY / distance;
397
+ return [unitX, unitY];
398
+ }
399
+ function getPointByVector(point, vector, component) {
400
+ const distance = Math.hypot(vector[0], vector[1]);
401
+ return [point[0] + (vector[0] / distance) * component, point[1] + (vector[1] / distance) * component];
402
+ }
403
+ function getPointByUnitVectorAndVectorComponent(point, unitVector, vectorComponent, isHorizontal) {
404
+ if (isHorizontal) {
405
+ return [point[0] + vectorComponent, point[1] + (vectorComponent / unitVector[0]) * unitVector[1]];
406
+ }
407
+ else {
408
+ return [point[0] + (vectorComponent / unitVector[1]) * unitVector[0], point[1] + vectorComponent];
362
409
  }
363
- return {
364
- x: (target[0] - source[0]) / distance,
365
- y: (target[1] - source[1]) / distance
366
- };
367
410
  }
411
+ function rotateVectorAnti90(vector) {
412
+ const x = vector[0];
413
+ const y = vector[1];
414
+ const rotatedX = y;
415
+ const rotatedY = -x;
416
+ return [rotatedX, rotatedY];
417
+ }
418
+
419
+ function isPointOnSegment(point, startPoint, endPoint) {
420
+ const distanceToStart = distanceBetweenPointAndPoint(point[0], point[1], startPoint[0], startPoint[1]);
421
+ const distanceToEnd = distanceBetweenPointAndPoint(point[0], point[1], endPoint[0], endPoint[1]);
422
+ const segmentLength = distanceBetweenPointAndPoint(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
423
+ return Math.abs(distanceToStart + distanceToEnd - segmentLength) < 0.1;
424
+ }
425
+ const getCrossingPointsBetweenPointAndSegment = (point, startPoint, endPoint) => {
426
+ const result = [];
427
+ const xRange = [Math.min(startPoint[0], endPoint[0]), Math.max(startPoint[0], endPoint[0])];
428
+ const yRange = [Math.min(startPoint[1], endPoint[1]), Math.max(startPoint[1], endPoint[1])];
429
+ const unitVector = getUnitVectorByPointAndPoint(startPoint, endPoint);
430
+ if (point[0] >= xRange[0] && point[0] <= xRange[1]) {
431
+ const crossingPoint = getPointByUnitVectorAndVectorComponent(startPoint, unitVector, point[0] - startPoint[0], true);
432
+ result.push(crossingPoint);
433
+ }
434
+ else if (point[1] >= yRange[0] && point[1] <= yRange[1]) {
435
+ const crossingPoint = getPointByUnitVectorAndVectorComponent(startPoint, unitVector, point[1] - startPoint[1], false);
436
+ result.push(crossingPoint);
437
+ }
438
+ return result;
439
+ };
368
440
 
369
441
  function getOppositeDirection(direction) {
370
442
  switch (direction) {
@@ -435,11 +507,11 @@ const getPoints = (source, sourcePosition, target, targetPosition, offset) => {
435
507
  if (sourcePosition !== targetPosition) {
436
508
  const dirAccessorOpposite = dirAccessor === 'x' ? 1 : 0;
437
509
  const isSameDir = sourceDir[dirAccessor] === targetDir[dirAccessor === 'x' ? 'y' : 'x'];
438
- const sourceGtTargetOppo = sourceGapped[dirAccessorOpposite] > targetGapped[dirAccessorOpposite];
439
- const sourceLtTargetOppo = sourceGapped[dirAccessorOpposite] < targetGapped[dirAccessorOpposite];
510
+ const sourceGtTarget = sourceGapped[dirAccessorOpposite] > targetGapped[dirAccessorOpposite];
511
+ const sourceLtTarget = sourceGapped[dirAccessorOpposite] < targetGapped[dirAccessorOpposite];
440
512
  flipSourceTarget =
441
- (sourceDir[dirAccessor] === 1 && ((!isSameDir && sourceGtTargetOppo) || (isSameDir && sourceLtTargetOppo))) ||
442
- (sourceDir[dirAccessor] !== 1 && ((!isSameDir && sourceLtTargetOppo) || (isSameDir && sourceGtTargetOppo)));
513
+ (sourceDir[dirAccessor] === 1 && ((!isSameDir && sourceGtTarget) || (isSameDir && sourceLtTarget))) ||
514
+ (sourceDir[dirAccessor] !== 1 && ((!isSameDir && sourceLtTarget) || (isSameDir && sourceGtTarget)));
443
515
  if (flipSourceTarget) {
444
516
  points = dirAccessor === 'x' ? sourceTarget : targetSource;
445
517
  }
@@ -492,7 +564,7 @@ function getRatioByPoint(points, point) {
492
564
  const totalLength = calculatePolylineLength(points);
493
565
  let distance = 0;
494
566
  for (let i = 0; i < points.length - 1; i++) {
495
- const isOverlap = isPointOnLineSegment(point, points[i], points[i + 1]);
567
+ const isOverlap = isPointOnSegment(point, points[i], points[i + 1]);
496
568
  if (isOverlap) {
497
569
  distance += distanceBetweenPointAndPoint(point[0], point[1], points[i][0], points[i][1]);
498
570
  return distance / totalLength;
@@ -503,12 +575,6 @@ function getRatioByPoint(points, point) {
503
575
  }
504
576
  throw new Error('Cannot get ratio by point');
505
577
  }
506
- function isPointOnLineSegment(point, startPoint, endPoint) {
507
- const distanceToStart = distanceBetweenPointAndPoint(point[0], point[1], startPoint[0], startPoint[1]);
508
- const distanceToEnd = distanceBetweenPointAndPoint(point[0], point[1], endPoint[0], endPoint[1]);
509
- const segmentLength = distanceBetweenPointAndPoint(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
510
- return Math.abs(distanceToStart + distanceToEnd - segmentLength) < 0.1;
511
- }
512
578
  const removeDuplicatePoints = (points) => {
513
579
  const newArray = [];
514
580
  points.forEach(point => {
@@ -520,6 +586,22 @@ const removeDuplicatePoints = (points) => {
520
586
  });
521
587
  return newArray;
522
588
  };
589
+ function simplifyOrthogonalPoints(points) {
590
+ if (points.length <= 2)
591
+ return points;
592
+ let simplifiedPoints = [points[0]];
593
+ for (let i = 1; i < points.length - 1; i++) {
594
+ const previous = points[i - 1];
595
+ const current = points[i];
596
+ const next = points[i + 1];
597
+ const isTurn = !(Point.isOverHorizontal([previous, current, next]) || Point.isOverVertical([previous, current, next]));
598
+ if (isTurn) {
599
+ simplifiedPoints.push(current);
600
+ }
601
+ }
602
+ simplifiedPoints.push(points[points.length - 1]);
603
+ return simplifiedPoints;
604
+ }
523
605
  const getExtendPoint = (source, target, extendDistance) => {
524
606
  const distance = distanceBetweenPointAndPoint(...source, ...target);
525
607
  const isEqual = Point.isEquals(source, target);
@@ -555,22 +637,6 @@ const isDelete = (event) => {
555
637
  return hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event);
556
638
  };
557
639
 
558
- const getRectangleByPoints = (points) => {
559
- let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
560
- points.forEach(point => {
561
- minX = Math.min(point[0], minX);
562
- maxX = Math.max(point[0], maxX);
563
- minY = Math.min(point[1], minY);
564
- maxY = Math.max(point[1], maxY);
565
- });
566
- return {
567
- x: minX,
568
- y: minY,
569
- width: maxX - minX,
570
- height: maxY - minY
571
- };
572
- };
573
-
574
640
  var BoardCreationMode;
575
641
  (function (BoardCreationMode) {
576
642
  BoardCreationMode["dnd"] = "dnd";
@@ -825,30 +891,30 @@ const generateElbowLineRoute = (options) => {
825
891
  let route = aStar.getRoute(nextSourcePoint, nextTargetPoint);
826
892
  route = [options.sourcePoint, ...route, nextTargetPoint, options.targetPoint];
827
893
  // Centerline correction: Correct the shortest path route based on the horizontal centerline/vertical centerline
828
- // 1. Find the horizontal center line (xAxis)/vertical center line (yAxis)
829
- // 2. Find the point that intersects xAxis/yAxis in route, and find the line segment parallel to xAxis/yAxis in route
894
+ // 1. Find the horizontal center line (centerX)/vertical center line (centerY)
895
+ // 2. Find the point that intersects centerX/centerY in route, and find the line segment parallel to centerX/centerY in route
830
896
  // 3. Construct a rectangle based on the intersection points and parallel lines found in the previous step.
831
897
  // 4. Determine whether the rectangle intersects with the element. If it does not intersect, the center line can be mapped based on the rectangle constructed in the previous step.
832
898
  // 5. Determine whether the path after mapping the center line meets the constraints (inflection point cannot be increased)
833
899
  const isHitX = RectangleClient.isHitX(options.sourceOuterRectangle, options.targetOuterRectangle);
834
900
  const isHitY = RectangleClient.isHitY(options.sourceOuterRectangle, options.targetOuterRectangle);
835
- const xAxis = isHitX ? undefined : RectangleClient.getGapCenter(options.sourceOuterRectangle, options.targetOuterRectangle, true);
836
- const yAxis = isHitY ? undefined : RectangleClient.getGapCenter(options.sourceOuterRectangle, options.targetOuterRectangle, false);
837
- route = routeAdjust(route, { xAxis, yAxis, sourceRectangle: options.sourceRectangle, targetRectangle: options.targetRectangle });
901
+ const centerX = isHitX ? undefined : RectangleClient.getGapCenter(options.sourceOuterRectangle, options.targetOuterRectangle, true);
902
+ const centerY = isHitY ? undefined : RectangleClient.getGapCenter(options.sourceOuterRectangle, options.targetOuterRectangle, false);
903
+ route = routeAdjust(route, { centerX, centerY, sourceRectangle: options.sourceRectangle, targetRectangle: options.targetRectangle });
838
904
  return route;
839
905
  };
840
906
  const routeAdjust = (path, options) => {
841
- const { sourceRectangle, targetRectangle, xAxis, yAxis } = options;
842
- if (xAxis !== undefined) {
843
- const optionsX = getAdjustOptions(path, xAxis, true);
907
+ const { sourceRectangle, targetRectangle, centerX, centerY } = options;
908
+ if (centerX !== undefined) {
909
+ const optionsX = getAdjustOptions(path, centerX, true);
844
910
  const resultX = optionsX.pointOfHit &&
845
911
  adjust(path, { parallelPaths: optionsX.parallelPaths, pointOfHit: optionsX.pointOfHit, sourceRectangle, targetRectangle });
846
912
  if (resultX) {
847
913
  path = resultX;
848
914
  }
849
915
  }
850
- if (yAxis !== undefined) {
851
- const optionsY = getAdjustOptions(path, yAxis, false);
916
+ if (centerY !== undefined) {
917
+ const optionsY = getAdjustOptions(path, centerY, false);
852
918
  const resultY = optionsY.pointOfHit &&
853
919
  adjust(path, { parallelPaths: optionsY.parallelPaths, pointOfHit: optionsY.pointOfHit, sourceRectangle, targetRectangle });
854
920
  if (resultY) {
@@ -862,29 +928,15 @@ const adjust = (route, options) => {
862
928
  let result = null;
863
929
  parallelPaths.forEach(parallelPath => {
864
930
  // Construct a rectangle
865
- const tempRect = RectangleClient.toRectangleClient([pointOfHit, parallelPath[0], parallelPath[1]]);
931
+ const tempRectPoints = [pointOfHit, parallelPath[0], parallelPath[1]];
932
+ // directly use getCornerPoints will bring the precision issue (eg: 263.6923375175286 - 57.130859375)
933
+ const tempRect = RectangleClient.getRectangleByPoints(tempRectPoints);
866
934
  if (!RectangleClient.isHit(tempRect, sourceRectangle) && !RectangleClient.isHit(tempRect, targetRectangle)) {
867
- const getCornerCount = (path) => {
868
- let cornerCount = 0;
869
- for (let index = 1; index < path.length - 1; index++) {
870
- const pre = path[index - 1];
871
- const current = path[index];
872
- const next = path[index + 1];
873
- if (pre &&
874
- current &&
875
- next &&
876
- !((downScale(current[0]) === downScale(pre[0]) && downScale(current[0]) === downScale(next[0])) ||
877
- (downScale(current[1]) === downScale(pre[1]) && downScale(current[1]) === downScale(next[1])))) {
878
- cornerCount++;
879
- }
880
- }
881
- return cornerCount;
882
- };
883
935
  const tempCorners = RectangleClient.getCornerPoints(tempRect);
884
936
  const indexRangeInPath = [];
885
937
  const indexRangeInCorner = [];
886
938
  route.forEach((point, index) => {
887
- const cornerResult = tempCorners.findIndex(corner => Math.floor(corner[0]) === Math.floor(point[0]) && Math.floor(corner[1]) === Math.floor(point[1]));
939
+ const cornerResult = tempCorners.findIndex(corner => Point.isEquals(point, corner));
888
940
  if (cornerResult !== -1) {
889
941
  indexRangeInPath.push(index);
890
942
  indexRangeInCorner.push(cornerResult);
@@ -894,9 +946,9 @@ const adjust = (route, options) => {
894
946
  const missCorner = tempCorners.find((c, index) => !indexRangeInCorner.includes(index));
895
947
  const removeLength = Math.abs(indexRangeInPath[0] - indexRangeInPath[indexRangeInPath.length - 1]) + 1;
896
948
  newPath.splice(indexRangeInPath[0] + 1, removeLength - 2, missCorner);
897
- const cornerCount = getCornerCount([...route]);
898
- const newCornerCount = getCornerCount([...newPath]);
899
- if (newCornerCount <= cornerCount) {
949
+ const turnCount = simplifyOrthogonalPoints([...route]).length - 1;
950
+ const newTurnCount = simplifyOrthogonalPoints([...newPath]).length - 1;
951
+ if (newTurnCount <= turnCount) {
900
952
  result = newPath;
901
953
  }
902
954
  }
@@ -904,7 +956,7 @@ const adjust = (route, options) => {
904
956
  });
905
957
  return result;
906
958
  };
907
- const getAdjustOptions = (path, middle, isHorizontal) => {
959
+ const getAdjustOptions = (path, centerOfAxis, isHorizontal) => {
908
960
  const parallelPaths = [];
909
961
  let start = null;
910
962
  let pointOfHit = null;
@@ -921,7 +973,7 @@ const getAdjustOptions = (path, middle, isHorizontal) => {
921
973
  start = null;
922
974
  }
923
975
  }
924
- if (current[axis] === middle) {
976
+ if (current[axis] === centerOfAxis) {
925
977
  pointOfHit = current;
926
978
  }
927
979
  }
@@ -1054,6 +1106,22 @@ const getNextPoint = (point, outerRectangle, direction) => {
1054
1106
  }
1055
1107
  }
1056
1108
  };
1109
+ const getSourceAndTargetOuterRectangle = (sourceRectangle, targetRectangle) => {
1110
+ const { sourceOffset, targetOffset } = reduceRouteMargin(sourceRectangle, targetRectangle);
1111
+ const sourceOuterRectangle = RectangleClient.expand(sourceRectangle, sourceOffset[3], sourceOffset[0], sourceOffset[1], sourceOffset[2]);
1112
+ const targetOuterRectangle = RectangleClient.expand(targetRectangle, targetOffset[3], targetOffset[0], targetOffset[1], targetOffset[2]);
1113
+ return {
1114
+ sourceOuterRectangle,
1115
+ targetOuterRectangle
1116
+ };
1117
+ };
1118
+ const isSourceAndTargetIntersect = (options) => {
1119
+ const { sourcePoint, nextSourcePoint, sourceRectangle, sourceOuterRectangle, targetPoint, nextTargetPoint, targetRectangle, targetOuterRectangle } = options;
1120
+ return (RectangleClient.isPointInRectangle(targetRectangle, sourcePoint) ||
1121
+ RectangleClient.isPointInRectangle(targetOuterRectangle, nextSourcePoint) ||
1122
+ RectangleClient.isPointInRectangle(sourceOuterRectangle, nextTargetPoint) ||
1123
+ RectangleClient.isPointInRectangle(sourceRectangle, targetPoint));
1124
+ };
1057
1125
 
1058
1126
  const map = new Map();
1059
1127
  const memorizeLatest = (memorizedKey, propertyKey, propertyValue) => {
@@ -1287,26 +1355,31 @@ const generalCanResize = (board, event) => {
1287
1355
  };
1288
1356
  const withResize = (board, options) => {
1289
1357
  const { pointerDown, pointerMove, globalPointerUp } = board;
1290
- let resizeDetectResult = null;
1358
+ let resizeHitTestRef = null;
1291
1359
  let resizeRef = null;
1292
1360
  let startPoint = null;
1293
- let hoveDetectResult = null;
1361
+ let hoverHitTestRef = null;
1294
1362
  board.pointerDown = (event) => {
1295
1363
  if (!options.canResize() || !generalCanResize(board, event) || !isMainPointer(event)) {
1296
1364
  pointerDown(event);
1297
1365
  return;
1298
1366
  }
1299
1367
  const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
1300
- resizeDetectResult = options.detect(point);
1301
- if (resizeDetectResult) {
1302
- if (resizeDetectResult.cursorClass) {
1303
- PlaitBoard.getBoardContainer(board).classList.add(`${resizeDetectResult.cursorClass}`);
1368
+ resizeHitTestRef = options.hitTest(point);
1369
+ if (resizeHitTestRef) {
1370
+ if (resizeHitTestRef.cursorClass) {
1371
+ PlaitBoard.getBoardContainer(board).classList.add(`${resizeHitTestRef.cursorClass}`);
1304
1372
  }
1305
1373
  startPoint = [event.x, event.y];
1374
+ const path = Array.isArray(resizeHitTestRef.element)
1375
+ ? resizeHitTestRef.element.map(el => PlaitBoard.findPath(board, el))
1376
+ : PlaitBoard.findPath(board, resizeHitTestRef.element);
1306
1377
  resizeRef = {
1307
- path: PlaitBoard.findPath(board, resizeDetectResult.element),
1308
- element: resizeDetectResult.element,
1309
- handle: resizeDetectResult.handle
1378
+ path,
1379
+ element: resizeHitTestRef.element,
1380
+ handle: resizeHitTestRef.handle,
1381
+ handleIndex: resizeHitTestRef.handleIndex,
1382
+ rectangle: resizeHitTestRef.rectangle
1310
1383
  };
1311
1384
  preventTouchMove(board, event, true);
1312
1385
  // prevent text from being selected when user pressed shift and pointer down
@@ -1320,7 +1393,7 @@ const withResize = (board, options) => {
1320
1393
  pointerMove(event);
1321
1394
  return;
1322
1395
  }
1323
- if (startPoint && resizeDetectResult && !isResizing(board)) {
1396
+ if (startPoint && resizeHitTestRef && !isResizing(board)) {
1324
1397
  // prevent text from being selected
1325
1398
  event.preventDefault();
1326
1399
  const endPoint = [event.x, event.y];
@@ -1331,51 +1404,55 @@ const withResize = (board, options) => {
1331
1404
  options.beforeResize && options.beforeResize(resizeRef);
1332
1405
  }
1333
1406
  }
1334
- if (isResizing(board) && startPoint) {
1335
- // prevent text from being selected
1336
- event.preventDefault();
1337
- const endTransformPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
1338
- throttleRAF(() => {
1339
- const endPoint = [event.x, event.y];
1340
- if (startPoint && resizeRef) {
1341
- handleTouchTarget(board);
1342
- const offsetX = endPoint[0] - startPoint[0];
1343
- const offsetY = endPoint[1] - startPoint[1];
1344
- options.onResize(resizeRef, { offsetX, offsetY, endTransformPoint });
1407
+ if (!isResizing(board) && !isDragging(board)) {
1408
+ const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
1409
+ throttleRAF(board, options.key + '-common-resize-hit-test', () => {
1410
+ const hitTestRef = options.hitTest(point);
1411
+ if (hitTestRef) {
1412
+ if (hoverHitTestRef && hitTestRef.cursorClass !== hoverHitTestRef.cursorClass) {
1413
+ PlaitBoard.getBoardContainer(board).classList.remove(`${hoverHitTestRef.cursorClass}`);
1414
+ }
1415
+ hoverHitTestRef = hitTestRef;
1416
+ if (hoverHitTestRef.cursorClass) {
1417
+ PlaitBoard.getBoardContainer(board).classList.add(`${hoverHitTestRef.cursorClass}`);
1418
+ }
1419
+ }
1420
+ else {
1421
+ if (hoverHitTestRef) {
1422
+ if (hoverHitTestRef.cursorClass) {
1423
+ PlaitBoard.getBoardContainer(board).classList.remove(`${hoverHitTestRef.cursorClass}`);
1424
+ }
1425
+ hoverHitTestRef = null;
1426
+ }
1345
1427
  }
1346
1428
  });
1347
- return;
1348
1429
  }
1349
1430
  else {
1350
- const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
1351
- const resizeDetectResult = options.detect(point);
1352
- if (resizeDetectResult) {
1353
- if (hoveDetectResult && resizeDetectResult.cursorClass !== hoveDetectResult.cursorClass) {
1354
- PlaitBoard.getBoardContainer(board).classList.remove(`${hoveDetectResult.cursorClass}`);
1355
- }
1356
- hoveDetectResult = resizeDetectResult;
1357
- if (hoveDetectResult.cursorClass) {
1358
- PlaitBoard.getBoardContainer(board).classList.add(`${hoveDetectResult.cursorClass}`);
1359
- }
1360
- }
1361
- else {
1362
- if (hoveDetectResult) {
1363
- if (hoveDetectResult.cursorClass) {
1364
- PlaitBoard.getBoardContainer(board).classList.remove(`${hoveDetectResult.cursorClass}`);
1431
+ if (startPoint && isResizing(board)) {
1432
+ event.preventDefault();
1433
+ const endPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
1434
+ throttleRAF(board, 'with-common-resize', () => {
1435
+ if (startPoint && resizeRef) {
1436
+ handleTouchTarget(board);
1437
+ options.onResize(resizeRef, {
1438
+ startPoint: toViewBoxPoint(board, toHostPoint(board, startPoint[0], startPoint[1])),
1439
+ endPoint,
1440
+ isShift: !!event.shiftKey
1441
+ });
1365
1442
  }
1366
- hoveDetectResult = null;
1367
- }
1443
+ });
1444
+ return;
1368
1445
  }
1369
1446
  }
1370
1447
  pointerMove(event);
1371
1448
  };
1372
1449
  board.globalPointerUp = (event) => {
1373
1450
  globalPointerUp(event);
1374
- if (isResizing(board) || resizeDetectResult) {
1375
- options.beforeResize && options.beforeResize(resizeRef);
1451
+ if (isResizing(board) || resizeHitTestRef) {
1452
+ options.afterResize && options.afterResize(resizeRef);
1376
1453
  removeResizing(board, options.key);
1377
1454
  startPoint = null;
1378
- resizeDetectResult = null;
1455
+ resizeHitTestRef = null;
1379
1456
  resizeRef = null;
1380
1457
  MERGING.set(board, false);
1381
1458
  preventTouchMove(board, event, false);
@@ -1471,10 +1548,10 @@ class ImageBaseComponent {
1471
1548
  this.activeGenerator.destroy();
1472
1549
  }
1473
1550
  }
1474
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageBaseComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1475
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ImageBaseComponent, inputs: { element: "element", imageItem: "imageItem", board: "board", isFocus: "isFocus", getRectangle: "getRectangle", hasResizeHandle: "hasResizeHandle" }, host: { classAttribute: "plait-image-container" }, ngImport: i0 }); }
1551
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.8", ngImport: i0, type: ImageBaseComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1552
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.8", type: ImageBaseComponent, inputs: { element: "element", imageItem: "imageItem", board: "board", isFocus: "isFocus", getRectangle: "getRectangle", hasResizeHandle: "hasResizeHandle" }, host: { classAttribute: "plait-image-container" }, ngImport: i0 }); }
1476
1553
  }
1477
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageBaseComponent, decorators: [{
1554
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.8", ngImport: i0, type: ImageBaseComponent, decorators: [{
1478
1555
  type: Directive,
1479
1556
  args: [{
1480
1557
  host: {
@@ -1503,5 +1580,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1503
1580
  * Generated bundle index. Do not edit.
1504
1581
  */
1505
1582
 
1506
- export { AStar, ActiveGenerator, AlignTransform, BASE, BoardCreationMode, CommonPluginElement, DEFAULT_ROUTE_MARGIN, Generator, IS_RESIZING, ImageBaseComponent, ImageGenerator, MediaKeys, PICTURE_ACCEPTED_UPLOAD_SIZE, PRIMARY_COLOR, PointGraph, PointNode, PriorityQueue, PropertyTransforms, RESIZE_HANDLE_DIAMETER, ResizeHandle, TRANSPARENT, TextTransforms, WithCommonPluginKey, WithTextPluginKey, acceptImageTypes, addElementOfFocusedImage, addResizing, alignBottom, alignHorizontalCenter, alignLeft, alignRight, alignTop, alignVerticalCenter, buildImage, calculatePolylineLength, createGraph, distributeHorizontal, distributeVertical, generateElbowLineRoute, getCreationMode, getDirection, getDirectionBetweenPointAndPoint, getDirectionByPointOfRectangle, getDirectionByVector, getDirectionFactor, getEdgeCenter, getElementOfFocusedImage, getElementsText, getExtendPoint, getFactorByPoints, getFirstTextEditor, getFirstTextManage, getGraphPoints, getMemorizedLatest, getNextPoint, getOppositeDirection, getPointByVector, getPointOnPolyline, getPoints, getRatioByPoint, getRectangleByPoints, getRectangleResizeHandleRefs, getTextEditors, getTextManages, getTextMarksByElement, hasAfterDraw, isDelete, isDndMode, isDrawingMode, isEnterHotkey, isExpandHotkey, isPointOnLineSegment, isResizing, isResizingByCondition, isSpaceHotkey, isTabHotkey, isVirtualKey, memorizeLatest, normalizeShapePoints, reduceRouteMargin, removeDuplicatePoints, removeElementOfFocusedImage, removeResizing, rotateVectorAnti90, routeAdjust, selectImage, setCreationMode, setProperty, withResize };
1583
+ export { AStar, ActiveGenerator, AlignTransform, BASE, BoardCreationMode, CommonPluginElement, DEFAULT_ROUTE_MARGIN, Generator, IS_RESIZING, ImageBaseComponent, ImageGenerator, MediaKeys, PICTURE_ACCEPTED_UPLOAD_SIZE, PRIMARY_COLOR, PointGraph, PointNode, PriorityQueue, PropertyTransforms, RESIZE_HANDLE_DIAMETER, ResizeHandle, TRANSPARENT, TextTransforms, WithCommonPluginKey, WithTextPluginKey, acceptImageTypes, addElementOfFocusedImage, addResizing, alignBottom, alignHorizontalCenter, alignLeft, alignRight, alignTop, alignVerticalCenter, buildImage, calculatePolylineLength, createGraph, distributeHorizontal, distributeVertical, drawFillPrimaryHandle, drawHandle, drawPrimaryHandle, generateElbowLineRoute, getCreationMode, getCrossingPointsBetweenPointAndSegment, getDirection, getDirectionBetweenPointAndPoint, getDirectionByPointOfRectangle, getDirectionByVector, getDirectionFactor, getDirectionFactorByVectorComponent, getEdgeCenter, getElementOfFocusedImage, getElementsText, getExtendPoint, getFirstTextEditor, getFirstTextManage, getGraphPoints, getIndexByResizeHandle, getMemorizedLatest, getNextPoint, getOppositeDirection, getPointByUnitVectorAndVectorComponent, getPointByVector, getPointOnPolyline, getPoints, getRatioByPoint, getRectangleResizeHandleRefs, getResizeHandleByIndex, getResizeHandlePointByIndex, getSourceAndTargetOuterRectangle, getSymmetricHandleIndex, getTextEditors, getTextManages, getTextMarksByElement, getUnitVectorByPointAndPoint, hasAfterDraw, isCornerHandle, isDelete, isDndMode, isDrawingMode, isEdgeHandle, isEnterHotkey, isExpandHotkey, isPointOnSegment, isResizing, isResizingByCondition, isSourceAndTargetIntersect, isSpaceHotkey, isTabHotkey, isVirtualKey, memorizeLatest, normalizeShapePoints, reduceRouteMargin, removeDuplicatePoints, removeElementOfFocusedImage, removeResizing, rotateVectorAnti90, routeAdjust, selectImage, setCreationMode, setProperty, simplifyOrthogonalPoints, withResize };
1507
1584
  //# sourceMappingURL=plait-common.mjs.map