@plait/core 0.50.1 → 0.51.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 (53) hide show
  1. package/README.md +30 -28
  2. package/board/board.component.interface.d.ts +0 -5
  3. package/esm2022/board/board.component.interface.mjs +1 -1
  4. package/esm2022/board/board.component.mjs +9 -6
  5. package/esm2022/interfaces/board.mjs +3 -3
  6. package/esm2022/interfaces/direction.mjs +1 -1
  7. package/esm2022/interfaces/point.mjs +20 -5
  8. package/esm2022/interfaces/rectangle-client.mjs +57 -2
  9. package/esm2022/plugins/create-board.mjs +5 -5
  10. package/esm2022/plugins/with-hand.mjs +6 -6
  11. package/esm2022/plugins/with-history.mjs +4 -4
  12. package/esm2022/plugins/with-hotkey.mjs +10 -56
  13. package/esm2022/plugins/with-moving.mjs +97 -37
  14. package/esm2022/plugins/with-selection.mjs +36 -19
  15. package/esm2022/utils/common.mjs +18 -6
  16. package/esm2022/utils/dom/common.mjs +17 -1
  17. package/esm2022/utils/drawing/arrow.mjs +23 -0
  18. package/esm2022/utils/drawing/circle.mjs +4 -0
  19. package/esm2022/utils/drawing/line.mjs +47 -0
  20. package/esm2022/utils/drawing/rectangle.mjs +34 -0
  21. package/esm2022/utils/element.mjs +11 -22
  22. package/esm2022/utils/helper.mjs +2 -2
  23. package/esm2022/utils/id-creator.mjs +2 -2
  24. package/esm2022/utils/index.mjs +5 -5
  25. package/esm2022/utils/math.mjs +37 -4
  26. package/esm2022/utils/moving-element.mjs +2 -7
  27. package/esm2022/utils/selected-element.mjs +15 -2
  28. package/esm2022/utils/weak-maps.mjs +1 -1
  29. package/fesm2022/plait-core.mjs +426 -267
  30. package/fesm2022/plait-core.mjs.map +1 -1
  31. package/interfaces/board.d.ts +4 -4
  32. package/interfaces/direction.d.ts +2 -0
  33. package/interfaces/point.d.ts +7 -2
  34. package/interfaces/rectangle-client.d.ts +7 -6
  35. package/package.json +1 -1
  36. package/plugins/with-moving.d.ts +4 -0
  37. package/styles/styles.scss +4 -0
  38. package/utils/common.d.ts +2 -1
  39. package/utils/dom/common.d.ts +1 -0
  40. package/utils/helper.d.ts +1 -1
  41. package/utils/index.d.ts +4 -4
  42. package/utils/math.d.ts +14 -1
  43. package/utils/moving-element.d.ts +0 -1
  44. package/utils/selected-element.d.ts +2 -1
  45. package/utils/weak-maps.d.ts +8 -2
  46. package/esm2022/utils/draw/arrow.mjs +0 -23
  47. package/esm2022/utils/draw/circle.mjs +0 -4
  48. package/esm2022/utils/draw/line.mjs +0 -47
  49. package/esm2022/utils/draw/rectangle.mjs +0 -34
  50. /package/utils/{draw → drawing}/arrow.d.ts +0 -0
  51. /package/utils/{draw → drawing}/circle.d.ts +0 -0
  52. /package/utils/{draw → drawing}/line.d.ts +0 -0
  53. /package/utils/{draw → drawing}/rectangle.d.ts +0 -0
@@ -84,6 +84,165 @@ const sortElements = (board, elements) => {
84
84
  });
85
85
  };
86
86
 
87
+ const RectangleClient = {
88
+ isHit: (origin, target) => {
89
+ return RectangleClient.isHitX(origin, target) && RectangleClient.isHitY(origin, target);
90
+ },
91
+ isHitX: (origin, target) => {
92
+ const minX = origin.x < target.x ? origin.x : target.x;
93
+ const maxX = origin.x + origin.width > target.x + target.width ? origin.x + origin.width : target.x + target.width;
94
+ // float calculate error( eg: 1.4210854715202004e-14 > 0)
95
+ if (Math.floor(maxX - minX - origin.width - target.width) <= 0) {
96
+ return true;
97
+ }
98
+ else {
99
+ return false;
100
+ }
101
+ },
102
+ isHitY: (origin, target) => {
103
+ const minY = origin.y < target.y ? origin.y : target.y;
104
+ const maxY = origin.y + origin.height > target.y + target.height ? origin.y + origin.height : target.y + target.height;
105
+ // float calculate error( eg: 1.4210854715202004e-14 > 0)
106
+ if (Math.floor(maxY - minY - origin.height - target.height) <= 0) {
107
+ return true;
108
+ }
109
+ else {
110
+ return false;
111
+ }
112
+ },
113
+ getPoints(rectangle) {
114
+ return [
115
+ [rectangle.x, rectangle.y],
116
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height]
117
+ ];
118
+ },
119
+ getRectangleByCenterPoint(point, width, height) {
120
+ return RectangleClient.getRectangleByPoint([point[0] - width / 2, point[1] - height / 2], width, height);
121
+ },
122
+ getRectangleByPoint(point, width, height) {
123
+ return {
124
+ x: point[0],
125
+ y: point[1],
126
+ width,
127
+ height
128
+ };
129
+ },
130
+ getRectangleByPoints(points) {
131
+ const xArray = points.map(ele => ele[0]);
132
+ const yArray = points.map(ele => ele[1]);
133
+ const xMin = Math.min(...xArray);
134
+ const xMax = Math.max(...xArray);
135
+ const yMin = Math.min(...yArray);
136
+ const yMax = Math.max(...yArray);
137
+ const rect = { x: xMin, y: yMin, width: xMax - xMin, height: yMax - yMin };
138
+ return rect;
139
+ },
140
+ getCornerPointsByPoints(points) {
141
+ const xArray = points.map(ele => ele[0]);
142
+ const yArray = points.map(ele => ele[1]);
143
+ const xMin = Math.min(...xArray);
144
+ const xMax = Math.max(...xArray);
145
+ const yMin = Math.min(...yArray);
146
+ const yMax = Math.max(...yArray);
147
+ return [
148
+ [xMin, yMin],
149
+ [xMax, yMin],
150
+ [xMax, yMax],
151
+ [xMin, yMax]
152
+ ];
153
+ },
154
+ getOutlineRectangle: (rectangle, offset) => {
155
+ return {
156
+ x: rectangle.x + offset,
157
+ y: rectangle.y + offset,
158
+ width: rectangle.width - offset * 2,
159
+ height: rectangle.height - offset * 2
160
+ };
161
+ },
162
+ inflate: (rectangle, delta) => {
163
+ const half = delta / 2;
164
+ return {
165
+ x: rectangle.x - half,
166
+ y: rectangle.y - half,
167
+ width: rectangle.width + half * 2,
168
+ height: rectangle.height + half * 2
169
+ };
170
+ },
171
+ isEqual: (rectangle, otherRectangle) => {
172
+ return (rectangle.x === otherRectangle.x &&
173
+ rectangle.y === otherRectangle.y &&
174
+ rectangle.width === otherRectangle.width &&
175
+ rectangle.height === otherRectangle.height);
176
+ },
177
+ getCornerPoints: (rectangle) => {
178
+ return [
179
+ [rectangle.x, rectangle.y],
180
+ [rectangle.x + rectangle.width, rectangle.y],
181
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
182
+ [rectangle.x, rectangle.y + rectangle.height]
183
+ ];
184
+ },
185
+ getCenterPoint: (rectangle) => {
186
+ return [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
187
+ },
188
+ getEdgeCenterPoints: (rectangle) => {
189
+ return [
190
+ [rectangle.x + rectangle.width / 2, rectangle.y],
191
+ [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
192
+ [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
193
+ [rectangle.x, rectangle.y + rectangle.height / 2]
194
+ ];
195
+ },
196
+ getConnectionPoint: (rectangle, point) => {
197
+ return [rectangle.x + rectangle.width * point[0], rectangle.y + rectangle.height * point[1]];
198
+ },
199
+ expand(rectangle, left, top = left, right = left, bottom = top) {
200
+ return {
201
+ x: rectangle.x - left,
202
+ y: rectangle.y - top,
203
+ width: rectangle.width + left + right,
204
+ height: rectangle.height + top + bottom
205
+ };
206
+ },
207
+ getGapCenter(rectangle1, rectangle2, isHorizontal) {
208
+ const axis = isHorizontal ? 'x' : 'y';
209
+ const side = isHorizontal ? 'width' : 'height';
210
+ const align = [rectangle1[axis], rectangle1[axis] + rectangle1[side], rectangle2[axis], rectangle2[axis] + rectangle2[side]];
211
+ const sortArr = align.sort((a, b) => a - b);
212
+ return (sortArr[1] + sortArr[2]) / 2;
213
+ },
214
+ isPointInRectangle(rectangle, point) {
215
+ const x = point[0], y = point[1];
216
+ return x > rectangle.x && x < rectangle.x + rectangle.width && y > rectangle.y && y < rectangle.y + rectangle.height;
217
+ },
218
+ getBoundingRectangle(rectangles) {
219
+ if (rectangles.length === 0) {
220
+ throw new Error('rectangles can not be empty array');
221
+ }
222
+ let minX = Number.MAX_VALUE;
223
+ let minY = Number.MAX_VALUE;
224
+ let maxX = Number.NEGATIVE_INFINITY;
225
+ let maxY = Number.NEGATIVE_INFINITY;
226
+ rectangles.forEach(rect => {
227
+ minX = Math.min(minX, rect.x);
228
+ minY = Math.min(minY, rect.y);
229
+ maxX = Math.max(maxX, rect.x + rect.width);
230
+ maxY = Math.max(maxY, rect.y + rect.height);
231
+ });
232
+ return {
233
+ x: minX,
234
+ y: minY,
235
+ width: maxX - minX,
236
+ height: maxY - minY
237
+ };
238
+ }
239
+ };
240
+
241
+ var PlaitPluginKey;
242
+ (function (PlaitPluginKey) {
243
+ PlaitPluginKey["withSelection"] = "withSelection";
244
+ })(PlaitPluginKey || (PlaitPluginKey = {}));
245
+
87
246
  const getHitElementsBySelection = (board, selection, match = () => true) => {
88
247
  const newSelection = selection || board.selection;
89
248
  const rectangleHitElements = [];
@@ -127,6 +286,17 @@ const getHitElementByPoint = (board, point, match = () => true) => {
127
286
  }, getIsRecursionFunc(board), true);
128
287
  return hitElement || rectangleHitElement;
129
288
  };
289
+ const getHitSelectedElements = (board, point) => {
290
+ const selectedElements = getSelectedElements(board);
291
+ const targetRectangle = selectedElements.length > 0 && getRectangleByElements(board, selectedElements, false);
292
+ const isInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
293
+ if (isInTargetRectangle) {
294
+ return selectedElements;
295
+ }
296
+ else {
297
+ return [];
298
+ }
299
+ };
130
300
  const cacheSelectedElements = (board, selectedElements) => {
131
301
  const sortedElements = sortElements(board, selectedElements);
132
302
  BOARD_TO_SELECTED_ELEMENT.set(board, sortedElements);
@@ -357,6 +527,22 @@ function createRect(rectangle, options) {
357
527
  const setStrokeLinecap = (g, value) => {
358
528
  g.setAttribute('stroke-linecap', value);
359
529
  };
530
+ const setTransformRotate = (g, rectangle, angle) => {
531
+ var centerX = rectangle.x + rectangle.width / 2;
532
+ var centerY = rectangle.y + rectangle.height / 2;
533
+ let cosTheta = Math.cos(angle);
534
+ let sinTheta = Math.sin(angle);
535
+ let transformMatrix = [
536
+ cosTheta,
537
+ sinTheta,
538
+ -sinTheta,
539
+ cosTheta,
540
+ centerX * (1 - cosTheta) + centerY * sinTheta,
541
+ centerY * (1 - cosTheta) - centerX * sinTheta
542
+ ];
543
+ let matrix = 'matrix(' + transformMatrix.join(',') + ')';
544
+ g.setAttribute('transform', `${matrix}`);
545
+ };
360
546
  const setPathStrokeLinecap = (g, value) => {
361
547
  g.querySelectorAll('path').forEach(path => {
362
548
  path.setAttribute('stroke-linecap', value);
@@ -486,105 +672,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
486
672
  }] } });
487
673
  const ELEMENT_TO_COMPONENT = new WeakMap();
488
674
 
489
- const RectangleClient = {
490
- isHit: (origin, target) => {
491
- return RectangleClient.isHitX(origin, target) && RectangleClient.isHitY(origin, target);
492
- },
493
- isHitX: (origin, target) => {
494
- const minX = origin.x < target.x ? origin.x : target.x;
495
- const maxX = origin.x + origin.width > target.x + target.width ? origin.x + origin.width : target.x + target.width;
496
- // float calculate error( eg: 1.4210854715202004e-14 > 0)
497
- if (Math.floor(maxX - minX - origin.width - target.width) <= 0) {
498
- return true;
499
- }
500
- else {
501
- return false;
502
- }
503
- },
504
- isHitY: (origin, target) => {
505
- const minY = origin.y < target.y ? origin.y : target.y;
506
- const maxY = origin.y + origin.height > target.y + target.height ? origin.y + origin.height : target.y + target.height;
507
- // float calculate error( eg: 1.4210854715202004e-14 > 0)
508
- if (Math.floor(maxY - minY - origin.height - target.height) <= 0) {
509
- return true;
510
- }
511
- else {
512
- return false;
513
- }
514
- },
515
- toRectangleClient: (points) => {
516
- const xArray = points.map(ele => ele[0]);
517
- const yArray = points.map(ele => ele[1]);
518
- const xMin = Math.min(...xArray);
519
- const xMax = Math.max(...xArray);
520
- const yMin = Math.min(...yArray);
521
- const yMax = Math.max(...yArray);
522
- const rect = { x: xMin, y: yMin, width: xMax - xMin, height: yMax - yMin };
523
- return rect;
524
- },
525
- getOutlineRectangle: (rectangle, offset) => {
526
- return {
527
- x: rectangle.x + offset,
528
- y: rectangle.y + offset,
529
- width: rectangle.width - offset * 2,
530
- height: rectangle.height - offset * 2
531
- };
532
- },
533
- inflate: (rectangle, delta) => {
534
- const half = delta / 2;
535
- return {
536
- x: rectangle.x - half,
537
- y: rectangle.y - half,
538
- width: rectangle.width + half * 2,
539
- height: rectangle.height + half * 2
540
- };
541
- },
542
- isEqual: (rectangle, otherRectangle) => {
543
- return (rectangle.x === otherRectangle.x &&
544
- rectangle.y === otherRectangle.y &&
545
- rectangle.width === otherRectangle.width &&
546
- rectangle.height === otherRectangle.height);
547
- },
548
- getCornerPoints: (rectangle) => {
549
- return [
550
- [rectangle.x, rectangle.y],
551
- [rectangle.x + rectangle.width, rectangle.y],
552
- [rectangle.x + rectangle.width, rectangle.y + rectangle.height],
553
- [rectangle.x, rectangle.y + rectangle.height]
554
- ];
555
- },
556
- getEdgeCenterPoints: (rectangle) => {
557
- return [
558
- [rectangle.x + rectangle.width / 2, rectangle.y],
559
- [rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2],
560
- [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
561
- [rectangle.x, rectangle.y + rectangle.height / 2]
562
- ];
563
- },
564
- getConnectionPoint: (rectangle, point) => {
565
- return [rectangle.x + rectangle.width * point[0], rectangle.y + rectangle.height * point[1]];
566
- },
567
- expand(rectangle, left, top = left, right = left, bottom = top) {
568
- return {
569
- x: rectangle.x - left,
570
- y: rectangle.y - top,
571
- width: rectangle.width + left + right,
572
- height: rectangle.height + top + bottom
573
- };
574
- },
575
- getGapCenter(rectangle1, rectangle2, isHorizontal) {
576
- const axis = isHorizontal ? 'x' : 'y';
577
- const side = isHorizontal ? 'width' : 'height';
578
- const align = [rectangle1[axis], rectangle1[axis] + rectangle1[side], rectangle2[axis], rectangle2[axis] + rectangle2[side]];
579
- const sortArr = align.sort((a, b) => a - b);
580
- return (sortArr[1] + sortArr[2]) / 2;
581
- },
582
- isPointInRectangle(rectangle, point) {
583
- const x = point[0], y = point[1];
584
- return x > rectangle.x && x < rectangle.x + rectangle.width && y > rectangle.y && y < rectangle.y + rectangle.height;
585
- }
586
- };
587
-
588
675
  // https://stackoverflow.com/a/6853926/232122
589
676
  function distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) {
590
677
  const A = x - x1;
@@ -761,9 +848,6 @@ const isPointInRoundRectangle = (point, rectangle, radius) => {
761
848
  const isInCorner = handleLeftTop || handleLeftBottom || handleRightTop || handleRightBottom;
762
849
  return isInRectangle && !isInCorner;
763
850
  };
764
- const downScale = (number) => {
765
- return Number(number.toFixed(2));
766
- };
767
851
  // https://gist.github.com/nicholaswmin/c2661eb11cad5671d816
768
852
  const catmullRomFitting = function (points) {
769
853
  const alpha = 0.5;
@@ -815,6 +899,42 @@ const catmullRomFitting = function (points) {
815
899
  }
816
900
  return result;
817
901
  };
902
+ /**
903
+ * the result of slope is based on Cartesian coordinate system
904
+ * x, y are based on the position in the Cartesian coordinate system
905
+ */
906
+ function getEllipseTangentSlope(x, y, a, b) {
907
+ if (Math.abs(y) === 0) {
908
+ return x > 0 ? -Infinity : Infinity;
909
+ }
910
+ const k = (-b * b * x) / (a * a * y);
911
+ return k;
912
+ }
913
+ /**
914
+ * x, y are based on the position in the Cartesian coordinate system
915
+ */
916
+ function getVectorFromPointAndSlope(x, y, slope) {
917
+ if (slope === Infinity) {
918
+ return [0, -1];
919
+ }
920
+ else if (slope === -Infinity) {
921
+ return [0, 1];
922
+ }
923
+ let vector = [1, -slope];
924
+ if (y < 0) {
925
+ vector = [-vector[0], -vector[1]];
926
+ }
927
+ return vector;
928
+ }
929
+ /**
930
+ * The DOM likes values to be fixed to 3 decimal places
931
+ */
932
+ function toDomPrecision(v) {
933
+ return +v.toFixed(4);
934
+ }
935
+ function toFixed(v) {
936
+ return +v.toFixed(2);
937
+ }
818
938
 
819
939
  function isInPlaitBoard(board, x, y) {
820
940
  const plaitBoardElement = PlaitBoard.getBoardContainer(board);
@@ -875,7 +995,7 @@ function isNullOrUndefined(value) {
875
995
  return value === null || value === undefined;
876
996
  }
877
997
  /**
878
- * 规范 point
998
+ * get {x,y} point
879
999
  * @param point
880
1000
  * @returns point
881
1001
  */
@@ -1063,7 +1183,7 @@ const hotkeys = {
1063
1183
 
1064
1184
  function idCreator(length = 5) {
1065
1185
  // remove numeral
1066
- const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
1186
+ const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'; /**** Easily confusing characters are removed by default oOLl,9gq,Vv,Uu,I1****/
1067
1187
  const maxPosition = $chars.length;
1068
1188
  let key = '';
1069
1189
  for (let i = 0; i < length; i++) {
@@ -1532,17 +1652,29 @@ const setIsFromViewportChange = (board, state) => {
1532
1652
  };
1533
1653
  function scrollToRectangle(board, client) { }
1534
1654
 
1535
- let timerId = null;
1536
- const throttleRAF = (fn) => {
1655
+ const BOARD_TO_RAF = new WeakMap();
1656
+ const getTimerId = (board, key) => {
1657
+ const state = getRAFState(board);
1658
+ return state[key] || null;
1659
+ };
1660
+ const getRAFState = (board) => {
1661
+ return BOARD_TO_RAF.get(board) || {};
1662
+ };
1663
+ const throttleRAF = (board, key, fn) => {
1537
1664
  const scheduleFunc = () => {
1538
- timerId = requestAnimationFrame(() => {
1539
- timerId = null;
1665
+ let timerId = requestAnimationFrame(() => {
1666
+ const value = BOARD_TO_RAF.get(board) || {};
1667
+ value[key] = null;
1668
+ BOARD_TO_RAF.set(board, value);
1540
1669
  fn();
1541
1670
  });
1671
+ const state = getRAFState(board);
1672
+ state[key] = timerId;
1673
+ BOARD_TO_RAF.set(board, state);
1542
1674
  };
1675
+ let timerId = getTimerId(board, key);
1543
1676
  if (timerId !== null) {
1544
1677
  cancelAnimationFrame(timerId);
1545
- timerId = null;
1546
1678
  }
1547
1679
  scheduleFunc();
1548
1680
  };
@@ -1580,18 +1712,13 @@ const getMovingElements = (board) => {
1580
1712
  const isMovingElements = (board) => {
1581
1713
  return (BOARD_TO_MOVING_ELEMENT.get(board) || []).length > 0;
1582
1714
  };
1583
- const addMovingElements = (board, elements) => {
1584
- const movingElements = getMovingElements(board);
1585
- const newElements = elements.filter(item => !movingElements.find(movingElement => movingElement.key === item.key));
1586
- cacheMovingElements(board, [...movingElements, ...newElements]);
1587
- setDragging(board, true);
1588
- };
1589
1715
  const removeMovingElements = (board) => {
1590
1716
  BOARD_TO_MOVING_ELEMENT.delete(board);
1591
1717
  setDragging(board, false);
1592
1718
  };
1593
1719
  const cacheMovingElements = (board, elements) => {
1594
1720
  BOARD_TO_MOVING_ELEMENT.set(board, elements);
1721
+ setDragging(board, true);
1595
1722
  };
1596
1723
 
1597
1724
  const IMAGE_CONTAINER = 'plait-image-container';
@@ -2364,11 +2491,26 @@ const Point = {
2364
2491
  isEquals(point, otherPoint) {
2365
2492
  return point && otherPoint && point[0] === otherPoint[0] && point[1] === otherPoint[1];
2366
2493
  },
2367
- isHorizontalAlign(point, otherPoint, tolerance = 0) {
2368
- return point && otherPoint && Math.abs(point[1] - otherPoint[1]) <= tolerance;
2494
+ isHorizontal(point, otherPoint, tolerance = 0) {
2495
+ return point && otherPoint && Point.isOverHorizontal([point, otherPoint], tolerance);
2496
+ },
2497
+ isOverHorizontal(points, tolerance = 0) {
2498
+ return points.every(point => Math.abs(point[1] - points[0][1]) <= tolerance);
2499
+ },
2500
+ isVertical(point, otherPoint, tolerance = 0) {
2501
+ return point && otherPoint && Point.isOverVertical([point, otherPoint], tolerance);
2502
+ },
2503
+ isOverVertical(points, tolerance = 0) {
2504
+ return points.every(point => Math.abs(point[0] - points[0][0]) <= tolerance);
2505
+ },
2506
+ isAlign(points, tolerance = 0) {
2507
+ return Point.isOverHorizontal(points, tolerance) || Point.isOverVertical(points, tolerance);
2369
2508
  },
2370
- isVerticalAlign(point, otherPoint, tolerance = 0) {
2371
- return point && otherPoint && Math.abs(point[0] - otherPoint[0]) <= tolerance;
2509
+ getOffsetX(point1, point2) {
2510
+ return point2[0] - point1[0];
2511
+ },
2512
+ getOffsetY(point1, point2) {
2513
+ return point2[1] - point1[1];
2372
2514
  }
2373
2515
  };
2374
2516
 
@@ -2381,11 +2523,6 @@ const Viewport = {
2381
2523
  const SAVING = new WeakMap();
2382
2524
  const MERGING = new WeakMap();
2383
2525
 
2384
- var PlaitPluginKey;
2385
- (function (PlaitPluginKey) {
2386
- PlaitPluginKey["withSelection"] = "withSelection";
2387
- })(PlaitPluginKey || (PlaitPluginKey = {}));
2388
-
2389
2526
  var ThemeColorMode;
2390
2527
  (function (ThemeColorMode) {
2391
2528
  ThemeColorMode["default"] = "default";
@@ -2443,19 +2580,11 @@ var Direction;
2443
2580
  })(Direction || (Direction = {}));
2444
2581
 
2445
2582
  function getRectangleByElements(board, elements, recursion) {
2446
- const boundaryBox = {
2447
- left: Number.MAX_VALUE,
2448
- top: Number.MAX_VALUE,
2449
- right: Number.NEGATIVE_INFINITY,
2450
- bottom: Number.NEGATIVE_INFINITY
2451
- };
2452
- const calcRectangleClient = (node) => {
2583
+ const rectangles = [];
2584
+ const callback = (node) => {
2453
2585
  const nodeRectangle = board.getRectangle(node);
2454
2586
  if (nodeRectangle) {
2455
- boundaryBox.left = Math.min(boundaryBox.left, nodeRectangle.x);
2456
- boundaryBox.top = Math.min(boundaryBox.top, nodeRectangle.y);
2457
- boundaryBox.right = Math.max(boundaryBox.right, nodeRectangle.x + nodeRectangle.width);
2458
- boundaryBox.bottom = Math.max(boundaryBox.bottom, nodeRectangle.y + nodeRectangle.height);
2587
+ rectangles.push(nodeRectangle);
2459
2588
  }
2460
2589
  else {
2461
2590
  console.error(`can not get rectangle of element:`, node);
@@ -2463,13 +2592,16 @@ function getRectangleByElements(board, elements, recursion) {
2463
2592
  };
2464
2593
  elements.forEach(element => {
2465
2594
  if (recursion) {
2466
- depthFirstRecursion(element, node => calcRectangleClient(node), node => board.isRecursion(node));
2595
+ depthFirstRecursion(element, node => callback(node), node => board.isRecursion(node));
2467
2596
  }
2468
2597
  else {
2469
- calcRectangleClient(element);
2598
+ callback(element);
2470
2599
  }
2471
2600
  });
2472
- if (boundaryBox.left === Number.MAX_VALUE) {
2601
+ if (rectangles.length > 0) {
2602
+ return RectangleClient.getBoundingRectangle(rectangles);
2603
+ }
2604
+ else {
2473
2605
  return {
2474
2606
  x: 0,
2475
2607
  y: 0,
@@ -2477,12 +2609,6 @@ function getRectangleByElements(board, elements, recursion) {
2477
2609
  height: 0
2478
2610
  };
2479
2611
  }
2480
- return {
2481
- x: boundaryBox.left,
2482
- y: boundaryBox.top,
2483
- width: boundaryBox.right - boundaryBox.left,
2484
- height: boundaryBox.bottom - boundaryBox.top
2485
- };
2486
2612
  }
2487
2613
  function getBoardRectangle(board) {
2488
2614
  return getRectangleByElements(board, board.children, true);
@@ -2563,13 +2689,13 @@ const PlaitBoard = {
2563
2689
  return BOARD_TO_COMPONENT.get(board);
2564
2690
  },
2565
2691
  getBoardContainer(board) {
2566
- return PlaitBoard.getComponent(board).nativeElement;
2692
+ return BOARD_TO_ELEMENT_HOST.get(board)?.container;
2567
2693
  },
2568
2694
  getRectangle(board) {
2569
2695
  return getRectangleByElements(board, board.children, true);
2570
2696
  },
2571
2697
  getViewportContainer(board) {
2572
- return PlaitBoard.getHost(board).parentElement;
2698
+ return BOARD_TO_ELEMENT_HOST.get(board)?.viewportContainer;
2573
2699
  },
2574
2700
  isFocus(board) {
2575
2701
  return !!board.selection;
@@ -2785,7 +2911,7 @@ const NodeTransforms = {
2785
2911
  };
2786
2912
 
2787
2913
  function withSelection(board) {
2788
- const { pointerDown, pointerUp, pointerMove, globalPointerUp, keydown, keyup, onChange, afterChange } = board;
2914
+ const { pointerDown, pointerUp, pointerMove, globalPointerUp, onChange, afterChange } = board;
2789
2915
  let start = null;
2790
2916
  let end = null;
2791
2917
  let selectionMovingG;
@@ -2807,9 +2933,12 @@ function withSelection(board) {
2807
2933
  event.preventDefault();
2808
2934
  }
2809
2935
  const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
2936
+ const selectedElements = getSelectedElements(board);
2810
2937
  const hitElement = getHitElementByPoint(board, point);
2938
+ const hitSelectedElements = selectedElements.length > 1 ? getHitSelectedElements(board, point) : [];
2939
+ const isHitTarget = hitElement || hitSelectedElements.length > 0;
2811
2940
  const options = board.getPluginOptions(PlaitPluginKey.withSelection);
2812
- if (PlaitBoard.isPointer(board, PlaitPointerType.selection) && !hitElement && options.isMultiple && !options.isDisabledSelect) {
2941
+ if (PlaitBoard.isPointer(board, PlaitPointerType.selection) && !isHitTarget && options.isMultiple && !options.isDisabledSelect) {
2813
2942
  preventTouchMove(board, event, true);
2814
2943
  // start rectangle selection
2815
2944
  start = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
@@ -2823,11 +2952,11 @@ function withSelection(board) {
2823
2952
  }
2824
2953
  if (start && PlaitBoard.isPointer(board, PlaitPointerType.selection)) {
2825
2954
  const movedTarget = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
2826
- const rectangle = RectangleClient.toRectangleClient([start, movedTarget]);
2955
+ const rectangle = RectangleClient.getRectangleByPoints([start, movedTarget]);
2827
2956
  selectionMovingG?.remove();
2828
2957
  if (Math.hypot(rectangle.width, rectangle.height) > PRESS_AND_MOVE_BUFFER || isSelectionMoving(board)) {
2829
2958
  end = movedTarget;
2830
- throttleRAF(() => {
2959
+ throttleRAF(board, 'with-selection', () => {
2831
2960
  if (start && end) {
2832
2961
  Transforms.setSelection(board, { anchor: start, focus: end });
2833
2962
  }
@@ -2849,7 +2978,7 @@ function withSelection(board) {
2849
2978
  const isSetSelectionPointer = PlaitBoard.isPointer(board, PlaitPointerType.selection) || PlaitBoard.isPointer(board, PlaitPointerType.hand);
2850
2979
  const isSkip = !isMainPointer(event) || isDragging(board) || !isSetSelectionPointer;
2851
2980
  if (isSkip) {
2852
- pointerDown(event);
2981
+ pointerUp(event);
2853
2982
  return;
2854
2983
  }
2855
2984
  const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
@@ -2892,23 +3021,36 @@ function withSelection(board) {
2892
3021
  });
2893
3022
  if (isHandleSelection(board) && isSetSelectionOperation(board)) {
2894
3023
  try {
2895
- selectionRectangleG?.remove();
3024
+ if (!isShift) {
3025
+ selectionRectangleG?.remove();
3026
+ }
2896
3027
  const temporaryElements = getTemporaryElements(board);
2897
3028
  let elements = temporaryElements ? temporaryElements : getHitElementsBySelection(board);
2898
3029
  if (!options.isMultiple && elements.length > 1) {
2899
3030
  elements = [elements[0]];
2900
3031
  }
2901
- if (isShift && board.selection && Selection.isCollapsed(board.selection)) {
2902
- const newSelectedElements = [...getSelectedElements(board)];
2903
- elements.forEach(element => {
2904
- if (newSelectedElements.includes(element)) {
2905
- newSelectedElements.splice(newSelectedElements.indexOf(element), 1);
2906
- }
2907
- else {
2908
- newSelectedElements.push(element);
2909
- }
2910
- });
2911
- cacheSelectedElements(board, newSelectedElements);
3032
+ if (isShift) {
3033
+ if (board.selection && Selection.isCollapsed(board.selection)) {
3034
+ const newSelectedElements = [...getSelectedElements(board)];
3035
+ elements.forEach(element => {
3036
+ if (newSelectedElements.includes(element)) {
3037
+ newSelectedElements.splice(newSelectedElements.indexOf(element), 1);
3038
+ }
3039
+ else {
3040
+ newSelectedElements.push(element);
3041
+ }
3042
+ });
3043
+ cacheSelectedElements(board, newSelectedElements);
3044
+ }
3045
+ else {
3046
+ const newSelectedElements = [...getSelectedElements(board)];
3047
+ elements.forEach(element => {
3048
+ if (!newSelectedElements.includes(element)) {
3049
+ newSelectedElements.push(element);
3050
+ }
3051
+ });
3052
+ cacheSelectedElements(board, newSelectedElements);
3053
+ }
2912
3054
  }
2913
3055
  else {
2914
3056
  const newSelectedElements = [...elements];
@@ -2918,6 +3060,7 @@ function withSelection(board) {
2918
3060
  previousSelectedElements = newElements;
2919
3061
  deleteTemporaryElements(board);
2920
3062
  if (!isSelectionMoving(board) && newElements.length > 1) {
3063
+ selectionRectangleG?.remove();
2921
3064
  selectionRectangleG = createSelectionRectangleG(board);
2922
3065
  }
2923
3066
  }
@@ -3140,10 +3283,10 @@ function createBoard(children, options) {
3140
3283
  globalMousemove: (event) => { },
3141
3284
  mouseup: (event) => { },
3142
3285
  globalMouseup: (event) => { },
3143
- keydown: (event) => { },
3144
- globalKeydown: (event) => { },
3145
- keyup: (event) => { },
3146
- dblclick: (event) => { },
3286
+ keyDown: (event) => { },
3287
+ globalKeyDown: (event) => { },
3288
+ keyUp: (event) => { },
3289
+ dblClick: (event) => { },
3147
3290
  setFragment: (data, clipboardContext) => {
3148
3291
  setClipboardData(data, clipboardContext);
3149
3292
  },
@@ -3198,7 +3341,7 @@ function withBoard(board) {
3198
3341
  }
3199
3342
 
3200
3343
  function withHistory(board) {
3201
- const { apply, keydown } = board;
3344
+ const { apply, keyDown } = board;
3202
3345
  board.history = { undos: [], redos: [] };
3203
3346
  board.redo = () => {
3204
3347
  const { history } = board;
@@ -3267,7 +3410,7 @@ function withHistory(board) {
3267
3410
  }
3268
3411
  apply(op);
3269
3412
  };
3270
- board.keydown = (event) => {
3413
+ board.keyDown = (event) => {
3271
3414
  if (isHotkey('mod+z', event)) {
3272
3415
  board.undo();
3273
3416
  return;
@@ -3276,13 +3419,13 @@ function withHistory(board) {
3276
3419
  board.redo();
3277
3420
  return;
3278
3421
  }
3279
- keydown(event);
3422
+ keyDown(event);
3280
3423
  };
3281
3424
  return board;
3282
3425
  }
3283
3426
 
3284
3427
  function withHandPointer(board) {
3285
- const { pointerDown, pointerMove, globalPointerUp, keydown, keyup } = board;
3428
+ const { pointerDown, pointerMove, globalPointerUp, keyDown, keyUp } = board;
3286
3429
  let isMoving = false;
3287
3430
  const plaitBoardMove = {
3288
3431
  x: 0,
@@ -3317,20 +3460,20 @@ function withHandPointer(board) {
3317
3460
  }
3318
3461
  globalPointerUp(event);
3319
3462
  };
3320
- board.keydown = (event) => {
3463
+ board.keyDown = (event) => {
3321
3464
  if (event.code === 'Space') {
3322
3465
  if (!PlaitBoard.isPointer(board, PlaitPointerType.hand)) {
3323
3466
  BoardTransforms.updatePointerType(board, PlaitPointerType.hand);
3324
3467
  }
3325
3468
  event.preventDefault();
3326
3469
  }
3327
- keydown(event);
3470
+ keyDown(event);
3328
3471
  };
3329
- board.keyup = (event) => {
3472
+ board.keyUp = (event) => {
3330
3473
  if (!board.options.readonly && event.code === 'Space') {
3331
3474
  BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
3332
3475
  }
3333
- keyup(event);
3476
+ keyUp(event);
3334
3477
  };
3335
3478
  return board;
3336
3479
  }
@@ -3740,29 +3883,32 @@ function withMoving(board) {
3740
3883
  let alignG = null;
3741
3884
  let activeElementsRectangle = null;
3742
3885
  board.pointerDown = (event) => {
3886
+ if (PlaitBoard.isReadonly(board) ||
3887
+ !PlaitBoard.isPointer(board, PlaitPointerType.selection) ||
3888
+ isPreventTouchMove(board) ||
3889
+ !isMainPointer(event)) {
3890
+ pointerDown(event);
3891
+ }
3743
3892
  const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
3744
- let movableElements = board.children.filter(item => board.isMovable(item));
3745
- if (!PlaitBoard.isReadonly(board) &&
3746
- PlaitBoard.isPointer(board, PlaitPointerType.selection) &&
3747
- movableElements.length &&
3748
- !isPreventTouchMove(board) &&
3749
- isMainPointer(event)) {
3893
+ const targetElements = getTargetElements(board);
3894
+ const targetRectangle = targetElements.length > 0 && getRectangleByElements(board, targetElements, false);
3895
+ const isInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
3896
+ if (isInTargetRectangle) {
3750
3897
  startPoint = point;
3751
- const selectedMovableElements = getSelectedElements(board).filter(item => movableElements.includes(item));
3752
- const hitElement = getHitElementByPoint(board, point);
3753
- if (hitElement && movableElements.includes(hitElement)) {
3754
- if (selectedMovableElements.includes(hitElement)) {
3755
- const relatedElements = board.getRelatedFragment([]);
3756
- activeElements = [...selectedMovableElements, ...relatedElements];
3757
- }
3758
- else {
3759
- activeElements = [hitElement];
3898
+ activeElements = targetElements;
3899
+ preventTouchMove(board, event, true);
3900
+ activeElementsRectangle = getRectangleByElements(board, activeElements, true);
3901
+ }
3902
+ else {
3903
+ const targetElement = getHitElementByPoint(board, point, el => board.isMovable(el));
3904
+ if (targetElement) {
3905
+ startPoint = point;
3906
+ activeElements = [targetElement];
3907
+ if (targetElements.length > 0) {
3908
+ addSelectionWithTemporaryElements(board, []);
3760
3909
  }
3910
+ activeElementsRectangle = getRectangleByElements(board, activeElements, true);
3761
3911
  }
3762
- if (activeElements.length > 0) {
3763
- preventTouchMove(board, event, true);
3764
- }
3765
- activeElementsRectangle = getRectangleByElements(board, activeElements, true);
3766
3912
  }
3767
3913
  pointerDown(event);
3768
3914
  };
@@ -3777,7 +3923,7 @@ function withMoving(board) {
3777
3923
  offsetY = endPoint[1] - startPoint[1];
3778
3924
  const distance = distanceBetweenPointAndPoint(...endPoint, ...startPoint);
3779
3925
  if (distance > PRESS_AND_MOVE_BUFFER || getMovingElements(board).length > 0) {
3780
- throttleRAF(() => {
3926
+ throttleRAF(board, 'with-moving', () => {
3781
3927
  if (!activeElementsRectangle) {
3782
3928
  return;
3783
3929
  }
@@ -3794,19 +3940,9 @@ function withMoving(board) {
3794
3940
  alignG.classList.add(ACTIVE_MOVING_CLASS_NAME);
3795
3941
  PlaitBoard.getElementActiveHost(board).append(alignG);
3796
3942
  handleTouchTarget(board);
3797
- const currentElements = activeElements.map(activeElement => {
3798
- const points = activeElement.points || [];
3799
- const [x, y] = activeElement.points[0];
3800
- const newPoints = points.map(p => [p[0] + offsetX, p[1] + offsetY]);
3801
- const index = board.children.findIndex(item => item.id === activeElement.id);
3802
- Transforms.setNode(board, {
3803
- points: newPoints
3804
- }, [index]);
3805
- MERGING.set(board, true);
3806
- return PlaitNode.get(board, [index]);
3807
- });
3943
+ const currentElements = updatePoints(board, activeElements, offsetX, offsetY);
3808
3944
  PlaitBoard.getBoardContainer(board).classList.add('element-moving');
3809
- addMovingElements(board, currentElements);
3945
+ cacheMovingElements(board, currentElements);
3810
3946
  });
3811
3947
  }
3812
3948
  }
@@ -3840,12 +3976,78 @@ function withMoving(board) {
3840
3976
  offsetX = 0;
3841
3977
  offsetY = 0;
3842
3978
  activeElements = [];
3843
- removeMovingElements(board);
3979
+ if (isMovingElements(board)) {
3980
+ removeMovingElements(board);
3981
+ }
3844
3982
  MERGING.set(board, false);
3845
3983
  PlaitBoard.getBoardContainer(board).classList.remove('element-moving');
3846
3984
  }
3985
+ return withArrowMoving(board);
3986
+ }
3987
+ function withArrowMoving(board) {
3988
+ const { keyDown, keyUp } = board;
3989
+ board.keyDown = (event) => {
3990
+ const selectedElements = getSelectedElements(board);
3991
+ if (!PlaitBoard.isReadonly(board) && selectedElements.length > 0 && (hotkeys.isArrow(event) || hotkeys.isExtendArrow(event))) {
3992
+ event.preventDefault();
3993
+ const isShift = event.shiftKey ? true : false;
3994
+ const offset = [0, 0];
3995
+ const buffer = isShift ? 10 : 1;
3996
+ switch (true) {
3997
+ case hotkeys.isMoveUp(event) || hotkeys.isExtendUp(event): {
3998
+ offset[1] = -buffer;
3999
+ break;
4000
+ }
4001
+ case hotkeys.isMoveDown(event) || hotkeys.isExtendDown(event): {
4002
+ offset[1] = buffer;
4003
+ break;
4004
+ }
4005
+ case hotkeys.isMoveBackward(event) || hotkeys.isExtendBackward(event): {
4006
+ offset[0] = -buffer;
4007
+ break;
4008
+ }
4009
+ case hotkeys.isMoveForward(event) || hotkeys.isExtendForward(event): {
4010
+ offset[0] = buffer;
4011
+ break;
4012
+ }
4013
+ }
4014
+ const targetElements = getTargetElements(board);
4015
+ throttleRAF(board, 'with-arrow-moving', () => {
4016
+ updatePoints(board, targetElements, offset[0], offset[1]);
4017
+ });
4018
+ }
4019
+ keyDown(event);
4020
+ };
4021
+ board.keyUp = (event) => {
4022
+ MERGING.set(board, false);
4023
+ keyUp(event);
4024
+ };
3847
4025
  return board;
3848
4026
  }
4027
+ function getTargetElements(board) {
4028
+ const selectedElements = getSelectedElements(board);
4029
+ const movableElements = board.children.filter(item => board.isMovable(item));
4030
+ const targetElements = selectedElements.filter(element => {
4031
+ return movableElements.includes(element);
4032
+ });
4033
+ const relatedElements = board.getRelatedFragment([]);
4034
+ targetElements.push(...relatedElements);
4035
+ return targetElements;
4036
+ }
4037
+ function updatePoints(board, targetElements, offsetX, offsetY) {
4038
+ const validElements = targetElements.filter(element => board.children.findIndex(item => item.id === element.id) > -1);
4039
+ const currentElements = validElements.map(element => {
4040
+ const points = element.points || [];
4041
+ const newPoints = points.map(p => [p[0] + offsetX, p[1] + offsetY]);
4042
+ const index = board.children.findIndex(item => item.id === element.id);
4043
+ Transforms.setNode(board, {
4044
+ points: newPoints
4045
+ }, [index]);
4046
+ MERGING.set(board, true);
4047
+ return PlaitNode.get(board, [index]);
4048
+ });
4049
+ return currentElements;
4050
+ }
3849
4051
 
3850
4052
  const withOptions = (board) => {
3851
4053
  const pluginOptions = new Map();
@@ -3930,13 +4132,9 @@ const hasOnBoardChange = (value) => {
3930
4132
  };
3931
4133
 
3932
4134
  const withHotkey = (board) => {
3933
- const { keydown, keyup, globalKeydown } = board;
3934
- let isShift = false;
3935
- board.keydown = (event) => {
4135
+ const { keyDown, keyUp, globalKeyDown } = board;
4136
+ board.keyDown = (event) => {
3936
4137
  const options = board.getPluginOptions(PlaitPluginKey.withSelection);
3937
- if (hotkeys.isShift(event)) {
3938
- isShift = true;
3939
- }
3940
4138
  if (!PlaitBoard.isReadonly(board) && options.isMultiple && isHotkey('mod+a', event)) {
3941
4139
  event.preventDefault();
3942
4140
  let elements = [];
@@ -3963,54 +4161,12 @@ const withHotkey = (board) => {
3963
4161
  event.preventDefault();
3964
4162
  board.deleteFragment(null);
3965
4163
  }
3966
- if (!PlaitBoard.isReadonly(board) && selectedElements.length > 0 && (hotkeys.isArrow(event) || hotkeys.isExtendArrow(event))) {
3967
- event.preventDefault();
3968
- const offset = [0, 0];
3969
- const buffer = isShift ? 10 : 1;
3970
- switch (true) {
3971
- case hotkeys.isMoveUp(event) || hotkeys.isExtendUp(event): {
3972
- offset[1] = -buffer;
3973
- break;
3974
- }
3975
- case hotkeys.isMoveDown(event) || hotkeys.isExtendDown(event): {
3976
- offset[1] = buffer;
3977
- break;
3978
- }
3979
- case hotkeys.isMoveBackward(event) || hotkeys.isExtendBackward(event): {
3980
- offset[0] = -buffer;
3981
- break;
3982
- }
3983
- case hotkeys.isMoveForward(event) || hotkeys.isExtendForward(event): {
3984
- offset[0] = buffer;
3985
- break;
3986
- }
3987
- }
3988
- const selectedElements = getSelectedElements(board);
3989
- const relatedElements = board.getRelatedFragment([]);
3990
- const movableElements = board.children.filter(item => board.isMovable(item));
3991
- throttleRAF(() => {
3992
- [...selectedElements, ...relatedElements]
3993
- .filter(element => movableElements.includes(element))
3994
- .forEach(element => {
3995
- const points = element.points || [];
3996
- const newPoints = points.map(p => [p[0] + offset[0], p[1] + offset[1]]);
3997
- Transforms.setNode(board, {
3998
- points: newPoints
3999
- }, PlaitBoard.findPath(board, element));
4000
- MERGING.set(board, true);
4001
- });
4002
- });
4003
- }
4004
- keydown(event);
4164
+ keyDown(event);
4005
4165
  };
4006
- board.keyup = (event) => {
4007
- if (event.key === 'Shift') {
4008
- isShift = false;
4009
- }
4010
- MERGING.set(board, false);
4011
- keyup(event);
4166
+ board.keyUp = (event) => {
4167
+ keyUp(event);
4012
4168
  };
4013
- board.globalKeydown = (event) => {
4169
+ board.globalKeyDown = (event) => {
4014
4170
  if (PlaitBoard.getMovingPointInBoard(board) || PlaitBoard.isMovingPointInBoard(board)) {
4015
4171
  if (isHotkey(['mod+=', 'mod++'], { byKey: true })(event)) {
4016
4172
  event.preventDefault();
@@ -4033,7 +4189,7 @@ const withHotkey = (board) => {
4033
4189
  return;
4034
4190
  }
4035
4191
  }
4036
- globalKeydown(event);
4192
+ globalKeyDown(event);
4037
4193
  };
4038
4194
  return board;
4039
4195
  };
@@ -4287,7 +4443,9 @@ class PlaitBoardComponent {
4287
4443
  BOARD_TO_ELEMENT_HOST.set(this.board, {
4288
4444
  host: elementHost,
4289
4445
  upperHost: elementUpperHost,
4290
- activeHost: elementActiveHost
4446
+ activeHost: elementActiveHost,
4447
+ container: this.elementRef.nativeElement,
4448
+ viewportContainer: this.viewportContainer.nativeElement
4291
4449
  });
4292
4450
  BOARD_TO_ON_CHANGE.set(this.board, () => {
4293
4451
  this.ngZone.run(() => {
@@ -4416,19 +4574,19 @@ class PlaitBoardComponent {
4416
4574
  fromEvent(this.host, 'dblclick')
4417
4575
  .pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
4418
4576
  .subscribe((event) => {
4419
- this.board.dblclick(event);
4577
+ this.board.dblClick(event);
4420
4578
  });
4421
4579
  fromEvent(document, 'keydown')
4422
4580
  .pipe(takeUntil(this.destroy$), tap(event => {
4423
- this.board.globalKeydown(event);
4581
+ this.board.globalKeyDown(event);
4424
4582
  }), filter(event => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board) && !hasInputOrTextareaTarget(event.target)))
4425
4583
  .subscribe((event) => {
4426
- this.board.keydown(event);
4584
+ this.board.keyDown(event);
4427
4585
  });
4428
4586
  fromEvent(document, 'keyup')
4429
4587
  .pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
4430
4588
  .subscribe((event) => {
4431
- this.board?.keyup(event);
4589
+ this.board?.keyUp(event);
4432
4590
  });
4433
4591
  fromEvent(document, 'copy')
4434
4592
  .pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.hasBeenTextEditing(this.board)))
@@ -4538,6 +4696,7 @@ class PlaitBoardComponent {
4538
4696
  BOARD_TO_HOST.delete(this.board);
4539
4697
  BOARD_TO_ELEMENT_HOST.delete(this.board);
4540
4698
  BOARD_TO_ON_CHANGE.delete(this.board);
4699
+ BOARD_TO_AFTER_CHANGE.set(this.board, () => { });
4541
4700
  }
4542
4701
  markForCheck() {
4543
4702
  this.cdr.markForCheck();
@@ -4783,5 +4942,5 @@ function createModModifierKeys() {
4783
4942
  * Generated bundle index. Do not edit.
4784
4943
  */
4785
4944
 
4786
- export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_IS_SELECTION_MOVING, BOARD_TO_MOVING_ELEMENT, BOARD_TO_MOVING_POINT, BOARD_TO_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_COMPONENT, END, ENTER, EQUALS, ESCAPE, F, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, FF_EQUALS, FF_MINUS, FF_MUTE, FF_SEMICOLON, FF_VOLUME_DOWN, FF_VOLUME_UP, FIRST_MEDIA, FIVE, FLUSHING, FOUR, G, H, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_MAC, IS_SAFARI, IS_TEXT_EDITABLE, J, K, L, LAST_MEDIA, LEFT_ARROW, M, MAC_ENTER, MAC_META, MAC_WK_CMD_LEFT, MAC_WK_CMD_RIGHT, MAX_RADIUS, MERGING, META, MUTE, N, NINE, NODE_TO_INDEX, NODE_TO_PARENT, NS, NUMPAD_DIVIDE, NUMPAD_EIGHT, NUMPAD_FIVE, NUMPAD_FOUR, NUMPAD_MINUS, NUMPAD_MULTIPLY, NUMPAD_NINE, NUMPAD_ONE, NUMPAD_PERIOD, NUMPAD_PLUS, NUMPAD_SEVEN, NUMPAD_SIX, NUMPAD_THREE, NUMPAD_TWO, NUMPAD_ZERO, NUM_CENTER, NUM_LOCK, O, ONE, OPEN_SQUARE_BRACKET, P, PAGE_DOWN, PAGE_UP, PATH_REFS, PAUSE, PERIOD, PLUS_SIGN, POINTER_BUTTON, PRESS_AND_MOVE_BUFFER, PRINT_SCREEN, Path, PlaitBoard, PlaitBoardComponent, PlaitChildrenElementComponent, PlaitContextService, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RIGHT_ARROW, RectangleClient, ResizeCursorClass, RetroThemeColor, RgbaToHEX, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addMovingElements, addSelectedElement, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, calcNewViewBox, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createFakeEvent, createForeignObject, createG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createSelectionRectangleG, createTestingBoard, createText, createTouchEvent, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downScale, downloadImage, drawArrow, drawBezierPath, drawCircle, drawLine, drawLinearPath, drawRectangle, drawRoundRectangle, fakeNodeWeakMap, findElements, getBoardRectangle, getClipboardData, getClipboardFromHtml, getDataTransferClipboard, getDataTransferClipboardText, getElementById, getElementHostBBox, getHitElementByPoint, getHitElementsBySelection, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByElements, getSelectedElements, getTemporaryElements, getTemporaryRef, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isContextmenu, isDOMElement, isDOMNode, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedElement, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, normalizePoint, preventTouchMove, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, stripHtml, temporaryDisableSelection, throttleRAF, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, updateForeignObject, updateForeignObjectWidth, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withMoving, withOptions, withSelection };
4945
+ export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_IS_SELECTION_MOVING, BOARD_TO_MOVING_ELEMENT, BOARD_TO_MOVING_POINT, BOARD_TO_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_COMPONENT, END, ENTER, EQUALS, ESCAPE, F, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, FF_EQUALS, FF_MINUS, FF_MUTE, FF_SEMICOLON, FF_VOLUME_DOWN, FF_VOLUME_UP, FIRST_MEDIA, FIVE, FLUSHING, FOUR, G, H, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_MAC, IS_SAFARI, IS_TEXT_EDITABLE, J, K, L, LAST_MEDIA, LEFT_ARROW, M, MAC_ENTER, MAC_META, MAC_WK_CMD_LEFT, MAC_WK_CMD_RIGHT, MAX_RADIUS, MERGING, META, MUTE, N, NINE, NODE_TO_INDEX, NODE_TO_PARENT, NS, NUMPAD_DIVIDE, NUMPAD_EIGHT, NUMPAD_FIVE, NUMPAD_FOUR, NUMPAD_MINUS, NUMPAD_MULTIPLY, NUMPAD_NINE, NUMPAD_ONE, NUMPAD_PERIOD, NUMPAD_PLUS, NUMPAD_SEVEN, NUMPAD_SIX, NUMPAD_THREE, NUMPAD_TWO, NUMPAD_ZERO, NUM_CENTER, NUM_LOCK, O, ONE, OPEN_SQUARE_BRACKET, P, PAGE_DOWN, PAGE_UP, PATH_REFS, PAUSE, PERIOD, PLUS_SIGN, POINTER_BUTTON, PRESS_AND_MOVE_BUFFER, PRINT_SCREEN, Path, PlaitBoard, PlaitBoardComponent, PlaitChildrenElementComponent, PlaitContextService, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RIGHT_ARROW, RectangleClient, ResizeCursorClass, RetroThemeColor, RgbaToHEX, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, calcNewViewBox, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createFakeEvent, createForeignObject, createG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createSelectionRectangleG, createTestingBoard, createText, createTouchEvent, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawLine, drawLinearPath, drawRectangle, drawRoundRectangle, fakeNodeWeakMap, findElements, getBoardRectangle, getClipboardData, getClipboardFromHtml, getDataTransferClipboard, getDataTransferClipboardText, getElementById, getElementHostBBox, getEllipseTangentSlope, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByElements, getSelectedElements, getTargetElements, getTemporaryElements, getTemporaryRef, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isContextmenu, isDOMElement, isDOMNode, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedElement, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, normalizePoint, preventTouchMove, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectionMoving, setStrokeLinecap, setTransformRotate, shouldClear, shouldMerge, shouldSave, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
4787
4946
  //# sourceMappingURL=plait-core.mjs.map