@plait/core 0.52.0 → 0.54.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 (56) hide show
  1. package/constants/cursor.d.ts +1 -0
  2. package/constants/selection.d.ts +1 -0
  3. package/esm2022/board/board.component.mjs +8 -6
  4. package/esm2022/constants/cursor.mjs +2 -1
  5. package/esm2022/constants/selection.mjs +2 -1
  6. package/esm2022/interfaces/board.mjs +5 -1
  7. package/esm2022/interfaces/path.mjs +2 -2
  8. package/esm2022/interfaces/rectangle-client.mjs +4 -1
  9. package/esm2022/interfaces/selection.mjs +2 -2
  10. package/esm2022/plugins/create-board.mjs +9 -6
  11. package/esm2022/plugins/with-hotkey.mjs +3 -3
  12. package/esm2022/plugins/with-moving.mjs +41 -21
  13. package/esm2022/plugins/with-related-fragment.mjs +20 -0
  14. package/esm2022/plugins/with-selection.mjs +37 -101
  15. package/esm2022/public-api.mjs +2 -1
  16. package/esm2022/transforms/element.mjs +2 -2
  17. package/esm2022/transforms/group.mjs +47 -0
  18. package/esm2022/transforms/index.mjs +2 -1
  19. package/esm2022/utils/angle.mjs +114 -0
  20. package/esm2022/utils/common.mjs +3 -2
  21. package/esm2022/utils/debug.mjs +91 -0
  22. package/esm2022/utils/element.mjs +17 -5
  23. package/esm2022/utils/fragment.mjs +5 -0
  24. package/esm2022/utils/group.mjs +88 -87
  25. package/esm2022/utils/helper.mjs +10 -1
  26. package/esm2022/utils/index.mjs +3 -1
  27. package/esm2022/utils/math.mjs +11 -1
  28. package/esm2022/utils/moving-snap.mjs +372 -0
  29. package/esm2022/utils/selection.mjs +90 -5
  30. package/esm2022/utils/touch.mjs +15 -4
  31. package/esm2022/utils/weak-maps.mjs +2 -1
  32. package/fesm2022/plait-core.mjs +587 -251
  33. package/fesm2022/plait-core.mjs.map +1 -1
  34. package/interfaces/board.d.ts +5 -2
  35. package/interfaces/rectangle-client.d.ts +1 -0
  36. package/interfaces/selection.d.ts +1 -1
  37. package/package.json +1 -1
  38. package/plugins/with-moving.d.ts +1 -1
  39. package/plugins/with-related-fragment.d.ts +2 -0
  40. package/public-api.d.ts +1 -0
  41. package/transforms/group.d.ts +7 -0
  42. package/transforms/index.d.ts +1 -0
  43. package/utils/angle.d.ts +18 -0
  44. package/utils/debug.d.ts +14 -0
  45. package/utils/fragment.d.ts +2 -0
  46. package/utils/group.d.ts +16 -16
  47. package/utils/helper.d.ts +2 -0
  48. package/utils/index.d.ts +2 -0
  49. package/utils/math.d.ts +8 -0
  50. package/utils/{reaction-manager.d.ts → moving-snap.d.ts} +3 -3
  51. package/utils/selection.d.ts +7 -4
  52. package/utils/touch.d.ts +1 -1
  53. package/utils/weak-maps.d.ts +1 -0
  54. package/esm2022/plugins/with-group.mjs +0 -27
  55. package/esm2022/utils/reaction-manager.mjs +0 -371
  56. package/plugins/with-group.d.ts +0 -2
@@ -4,7 +4,7 @@ import rough from 'roughjs/bin/rough';
4
4
  import { timer, Subject, fromEvent } from 'rxjs';
5
5
  import { takeUntil, filter, tap } from 'rxjs/operators';
6
6
  import { isKeyHotkey, isHotkey } from 'is-hotkey';
7
- import produce, { createDraft, finishDraft, isDraft } from 'immer';
7
+ import { produce, createDraft, finishDraft, isDraft } from 'immer';
8
8
  import { NgFor } from '@angular/common';
9
9
 
10
10
  // record richtext type status
@@ -18,6 +18,7 @@ const BOARD_TO_AFTER_CHANGE = new WeakMap();
18
18
  const BOARD_TO_COMPONENT = new WeakMap();
19
19
  const BOARD_TO_ROUGH_SVG = new WeakMap();
20
20
  const BOARD_TO_HOST = new WeakMap();
21
+ const IS_BOARD_ALIVE = new WeakMap();
21
22
  const BOARD_TO_ELEMENT_HOST = new WeakMap();
22
23
  const BOARD_TO_SELECTED_ELEMENT = new WeakMap();
23
24
  const BOARD_TO_MOVING_POINT_IN_BOARD = new WeakMap();
@@ -64,7 +65,7 @@ const getIsRecursionFunc = (board) => {
64
65
  };
65
66
 
66
67
  const SELECTION_BORDER_COLOR = '#6698FF';
67
- const SELECTION_FILL_COLOR = '#6698FF19'; // 主色 0.1 透明度
68
+ const SELECTION_FILL_COLOR = '#6698FF25'; // opacity 0.25
68
69
  const Selection = {
69
70
  isCollapsed(selection) {
70
71
  if (selection.anchor[0] == selection.focus[0] && selection.anchor[1] === selection.focus[1]) {
@@ -185,6 +186,9 @@ const RectangleClient = {
185
186
  getCenterPoint: (rectangle) => {
186
187
  return [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2];
187
188
  },
189
+ getCenterPointByPoints: (points) => {
190
+ return RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(points));
191
+ },
188
192
  getEdgeCenterPoints: (rectangle) => {
189
193
  return [
190
194
  [rectangle.x + rectangle.width / 2, rectangle.y],
@@ -493,9 +497,11 @@ var CursorClass;
493
497
  (function (CursorClass) {
494
498
  CursorClass["crosshair"] = "crosshair";
495
499
  })(CursorClass || (CursorClass = {}));
500
+ const RESIZE_CURSORS = [ResizeCursorClass.ns, ResizeCursorClass.nesw, ResizeCursorClass.ew, ResizeCursorClass.nwse];
496
501
 
497
502
  const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
498
503
  const ACTIVE_STROKE_WIDTH = 1;
504
+ const SNAPPING_STROKE_WIDTH = 2;
499
505
  const SELECTION_RECTANGLE_CLASS_NAME = 'selection-rectangle';
500
506
 
501
507
  const HOST_CLASS_NAME = 'plait-board-container';
@@ -952,6 +958,16 @@ function toDomPrecision(v) {
952
958
  function toFixed(v) {
953
959
  return +v.toFixed(2);
954
960
  }
961
+ /**
962
+ * Whether two numbers numbers a and b are approximately equal.
963
+ *
964
+ * @param a - The first point.
965
+ * @param b - The second point.
966
+ * @public
967
+ */
968
+ function approximately(a, b, precision = 0.000001) {
969
+ return Math.abs(a - b) <= precision;
970
+ }
955
971
 
956
972
  function isInPlaitBoard(board, x, y) {
957
973
  const plaitBoardElement = PlaitBoard.getBoardContainer(board);
@@ -1030,6 +1046,15 @@ const RgbaToHEX = (Rgb, opacity) => {
1030
1046
  function isContextmenu(event) {
1031
1047
  return event.button === 2;
1032
1048
  }
1049
+ function uniqueById(elements) {
1050
+ const uniqueMap = new Map();
1051
+ elements.forEach(item => {
1052
+ if (!uniqueMap.has(item.id)) {
1053
+ uniqueMap.set(item.id, item);
1054
+ }
1055
+ });
1056
+ return Array.from(uniqueMap.values());
1057
+ }
1033
1058
 
1034
1059
  /**
1035
1060
  * Check whether to merge an operation into the previous operation.
@@ -1683,7 +1708,7 @@ const throttleRAF = (board, key, fn) => {
1683
1708
  const value = BOARD_TO_RAF.get(board) || {};
1684
1709
  value[key] = null;
1685
1710
  BOARD_TO_RAF.set(board, value);
1686
- fn();
1711
+ PlaitBoard.isAlive(board) && fn();
1687
1712
  });
1688
1713
  const state = getRAFState(board);
1689
1714
  state[key] = timerId;
@@ -2151,8 +2176,16 @@ const isPreventTouchMove = (board) => {
2151
2176
  return !!BOARD_TO_TOUCH_REF.get(board);
2152
2177
  };
2153
2178
  const preventTouchMove = (board, event, state) => {
2154
- if (state && (event.target instanceof HTMLElement || event.target instanceof SVGElement)) {
2155
- BOARD_TO_TOUCH_REF.set(board, { state, target: event.target instanceof SVGElement ? event.target : undefined });
2179
+ const hostElement = PlaitBoard.getElementHost(board);
2180
+ const activeHostElement = PlaitBoard.getElementActiveHost(board);
2181
+ if (state) {
2182
+ if ((event.target instanceof HTMLElement || event.target instanceof SVGElement) &&
2183
+ (hostElement.contains(event.target) || activeHostElement.contains(event.target))) {
2184
+ BOARD_TO_TOUCH_REF.set(board, { state, target: event.target instanceof SVGElement ? event.target : undefined });
2185
+ }
2186
+ else {
2187
+ BOARD_TO_TOUCH_REF.set(board, { state, target: undefined });
2188
+ }
2156
2189
  }
2157
2190
  else {
2158
2191
  const ref = BOARD_TO_TOUCH_REF.get(board);
@@ -2170,7 +2203,10 @@ const preventTouchMove = (board, event, state) => {
2170
2203
  */
2171
2204
  const handleTouchTarget = (board) => {
2172
2205
  const touchRef = BOARD_TO_TOUCH_REF.get(board);
2173
- if (touchRef && touchRef.target && !touchRef.target.contains(PlaitBoard.getElementActiveHost(board))) {
2206
+ if (touchRef &&
2207
+ touchRef.target &&
2208
+ !PlaitBoard.getElementHost(board).contains(touchRef.target) &&
2209
+ !PlaitBoard.getElementActiveHost(board).contains(touchRef.target)) {
2174
2210
  touchRef.target.style.opacity = '0';
2175
2211
  const host = createG();
2176
2212
  host.appendChild(touchRef.target);
@@ -2180,12 +2216,6 @@ const handleTouchTarget = (board) => {
2180
2216
  }
2181
2217
  };
2182
2218
 
2183
- const PlaitGroupElement = {
2184
- isGroup: (value) => {
2185
- return value.type === 'group';
2186
- }
2187
- };
2188
-
2189
2219
  const Viewport = {
2190
2220
  isViewport: (value) => {
2191
2221
  return !isNullOrUndefined(value.zoom) && !isNullOrUndefined(value.viewBackgroundColor);
@@ -2622,7 +2652,7 @@ const removeElements = (board, elements) => {
2622
2652
  const path = PlaitBoard.findPath(board, element);
2623
2653
  const ref = board.pathRef(path);
2624
2654
  return () => {
2625
- removeNode(board, ref.current);
2655
+ ref.current && removeNode(board, ref.current);
2626
2656
  ref.unref();
2627
2657
  removeSelectedElement(board, element, true);
2628
2658
  };
@@ -2635,6 +2665,50 @@ const CoreTransforms = {
2635
2665
  removeElements
2636
2666
  };
2637
2667
 
2668
+ const addGroup = (board, elements) => {
2669
+ const selectedGroups = getHighestSelectedGroups(board, elements);
2670
+ const selectedIsolatedElements = getSelectedIsolatedElementsCanAddToGroup(board);
2671
+ const highestSelectedElements = [...selectedGroups, ...selectedIsolatedElements];
2672
+ const group = createGroup();
2673
+ if (canAddGroup(board)) {
2674
+ highestSelectedElements.forEach(item => {
2675
+ const path = PlaitBoard.findPath(board, item);
2676
+ NodeTransforms.setNode(board, { groupId: group.id }, path);
2677
+ });
2678
+ if (hasSelectedElementsInSameGroup(highestSelectedElements)) {
2679
+ const newGroupId = selectedIsolatedElements[0].groupId;
2680
+ NodeTransforms.insertNode(board, {
2681
+ ...group,
2682
+ groupId: newGroupId
2683
+ }, [board.children.length]);
2684
+ }
2685
+ else {
2686
+ NodeTransforms.insertNode(board, group, [board.children.length]);
2687
+ }
2688
+ }
2689
+ };
2690
+ const removeGroup = (board, elements) => {
2691
+ const selectedGroups = getHighestSelectedGroups(board, elements);
2692
+ if (canRemoveGroup(board)) {
2693
+ selectedGroups.map(group => {
2694
+ const elementsInGroup = findElements(board, {
2695
+ match: item => item.groupId === group.id,
2696
+ recursion: () => false
2697
+ });
2698
+ elementsInGroup.forEach(item => {
2699
+ const path = PlaitBoard.findPath(board, item);
2700
+ NodeTransforms.setNode(board, { groupId: group.groupId || undefined }, path);
2701
+ });
2702
+ const groupPath = PlaitBoard.findPath(board, group);
2703
+ NodeTransforms.removeNode(board, groupPath);
2704
+ });
2705
+ }
2706
+ };
2707
+ const GroupTransforms = {
2708
+ addGroup,
2709
+ removeGroup
2710
+ };
2711
+
2638
2712
  const Transforms = {
2639
2713
  ...GeneralTransforms,
2640
2714
  ...ViewportTransforms$1,
@@ -2642,6 +2716,116 @@ const Transforms = {
2642
2716
  ...NodeTransforms
2643
2717
  };
2644
2718
 
2719
+ const rotatePoints = (points, centerPoint, angle) => {
2720
+ if (!angle) {
2721
+ angle = 0;
2722
+ }
2723
+ if (Array.isArray(points) && typeof points[0] === 'number') {
2724
+ return rotate(points[0], points[1], centerPoint[0], centerPoint[1], angle);
2725
+ }
2726
+ else {
2727
+ return points.map(point => {
2728
+ return rotate(point[0], point[1], centerPoint[0], centerPoint[1], angle);
2729
+ });
2730
+ }
2731
+ };
2732
+ const getSelectionAngle = (elements) => {
2733
+ let angle = elements[0]?.angle || 0;
2734
+ elements.forEach(item => {
2735
+ if (item.angle !== angle && !approximately((item.angle % (Math.PI / 2)) - (angle % (Math.PI / 2)), 0)) {
2736
+ angle = 0;
2737
+ }
2738
+ });
2739
+ return angle;
2740
+ };
2741
+ const hasSameAngle = (elements) => {
2742
+ if (!elements.length) {
2743
+ return false;
2744
+ }
2745
+ const angle = elements[0].angle;
2746
+ if (angle === undefined) {
2747
+ return false;
2748
+ }
2749
+ return !elements.some(item => item.angle !== angle);
2750
+ };
2751
+ const getRotatedBoundingRectangle = (rectanglesCornerPoints, angle) => {
2752
+ let rectanglesFromOrigin = [];
2753
+ for (let i = 0; i < rectanglesCornerPoints.length; i++) {
2754
+ const cornerPoints = rectanglesCornerPoints[i];
2755
+ const invertCornerPointsFromOrigin = rotatePoints(cornerPoints, [0, 0], -angle);
2756
+ rectanglesFromOrigin.push(RectangleClient.getRectangleByPoints(invertCornerPointsFromOrigin));
2757
+ }
2758
+ const selectionRectangleFromOrigin = RectangleClient.getBoundingRectangle(rectanglesFromOrigin);
2759
+ const selectionCornerPoints = RectangleClient.getCornerPoints(selectionRectangleFromOrigin);
2760
+ const cornerPointsFromOrigin = rotatePoints(selectionCornerPoints, [0, 0], angle);
2761
+ const centerPoint = RectangleClient.getCenterPoint(RectangleClient.getRectangleByPoints(cornerPointsFromOrigin));
2762
+ return RectangleClient.getRectangleByPoints(rotatePoints(cornerPointsFromOrigin, centerPoint, -angle));
2763
+ };
2764
+ const getOffsetAfterRotate = (rectangle, rotateCenterPoint, angle) => {
2765
+ const targetCenterPoint = RectangleClient.getCenterPoint(rectangle);
2766
+ const [rotatedCenterPoint] = rotatePoints([targetCenterPoint], rotateCenterPoint, angle);
2767
+ const offsetX = rotatedCenterPoint[0] - targetCenterPoint[0];
2768
+ const offsetY = rotatedCenterPoint[1] - targetCenterPoint[1];
2769
+ return { offsetX, offsetY };
2770
+ };
2771
+ const rotatedDataPoints = (points, rotateCenterPoint, angle) => {
2772
+ const { offsetX, offsetY } = getOffsetAfterRotate(RectangleClient.getRectangleByPoints(points), rotateCenterPoint, angle);
2773
+ return points.map(p => [p[0] + offsetX, p[1] + offsetY]);
2774
+ };
2775
+ const hasValidAngle = (node) => {
2776
+ return node.angle && node.angle !== 0;
2777
+ };
2778
+ const rotatePointsByElement = (points, element) => {
2779
+ if (hasValidAngle(element)) {
2780
+ let rectangle = RectangleClient.getRectangleByPoints(element.points);
2781
+ const centerPoint = RectangleClient.getCenterPoint(rectangle);
2782
+ return rotatePoints(points, centerPoint, element.angle);
2783
+ }
2784
+ else {
2785
+ return null;
2786
+ }
2787
+ };
2788
+ const rotateAntiPointsByElement = (points, element) => {
2789
+ if (hasValidAngle(element)) {
2790
+ let rectangle = RectangleClient.getRectangleByPoints(element.points);
2791
+ const centerPoint = RectangleClient.getCenterPoint(rectangle);
2792
+ return rotatePoints(points, centerPoint, -element.angle);
2793
+ }
2794
+ else {
2795
+ return null;
2796
+ }
2797
+ };
2798
+ const getRectangleByAngle = (rectangle, angle) => {
2799
+ if (angle) {
2800
+ const cornerPoints = RectangleClient.getCornerPoints(rectangle);
2801
+ const centerPoint = RectangleClient.getCenterPoint(rectangle);
2802
+ return RectangleClient.getRectangleByPoints(rotatePoints(cornerPoints, centerPoint, angle));
2803
+ }
2804
+ else {
2805
+ return null;
2806
+ }
2807
+ };
2808
+ const isAxisChangedByAngle = (angle) => {
2809
+ const unitAngle = Math.abs(angle) % Math.PI;
2810
+ return unitAngle >= (1 / 4) * Math.PI && unitAngle <= (3 / 4) * Math.PI;
2811
+ };
2812
+ function degreesToRadians(d) {
2813
+ return (d / 180) * Math.PI;
2814
+ }
2815
+ function radiansToDegrees(r) {
2816
+ return (r / Math.PI) * 180;
2817
+ }
2818
+ function rotateElements(board, elements, angle) {
2819
+ const selectionRectangle = getRectangleByElements(board, elements, false);
2820
+ const selectionCenterPoint = RectangleClient.getCenterPoint(selectionRectangle);
2821
+ elements.forEach(item => {
2822
+ const originAngle = item.angle;
2823
+ const points = rotatedDataPoints(item.points, selectionCenterPoint, angle);
2824
+ const path = PlaitBoard.findPath(board, item);
2825
+ Transforms.setNode(board, { points, angle: originAngle + angle }, path);
2826
+ });
2827
+ }
2828
+
2645
2829
  function isSelectionMoving(board) {
2646
2830
  return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
2647
2831
  }
@@ -2677,7 +2861,7 @@ function getTemporaryRef(board) {
2677
2861
  function deleteTemporaryElements(board) {
2678
2862
  BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
2679
2863
  }
2680
- function createSelectionRectangleG(board) {
2864
+ function drawEntireActiveRectangleG(board) {
2681
2865
  const elements = getSelectedElements(board);
2682
2866
  const rectangle = getRectangleByElements(board, elements, false);
2683
2867
  if (rectangle.width > 0 && rectangle.height > 0 && elements.length > 1) {
@@ -2687,11 +2871,91 @@ function createSelectionRectangleG(board) {
2687
2871
  fillStyle: 'solid'
2688
2872
  });
2689
2873
  selectionRectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
2690
- PlaitBoard.getElementActiveHost(board).append(selectionRectangleG);
2874
+ const angle = getSelectionAngle(elements);
2875
+ if (angle) {
2876
+ setAngleForG(selectionRectangleG, RectangleClient.getCenterPoint(rectangle), angle);
2877
+ }
2691
2878
  return selectionRectangleG;
2692
2879
  }
2693
2880
  return null;
2694
2881
  }
2882
+ function setSelectedElementsWithGroup(board, elements, isShift) {
2883
+ if (!board.selection) {
2884
+ return;
2885
+ }
2886
+ const selectedElements = getSelectedElements(board);
2887
+ if (!Selection.isCollapsed(board.selection)) {
2888
+ let newElements = [...selectedElements];
2889
+ elements.forEach(item => {
2890
+ if (!item.groupId) {
2891
+ newElements.push(item);
2892
+ }
2893
+ else {
2894
+ newElements.push(...getElementsInGroupByElement(board, item));
2895
+ }
2896
+ });
2897
+ cacheSelectedElements(board, uniqueById(newElements));
2898
+ return;
2899
+ }
2900
+ if (Selection.isCollapsed(board.selection)) {
2901
+ const hitElement = elements[0];
2902
+ const hitElementGroups = getGroupByElement(board, hitElement, true);
2903
+ if (hitElementGroups.length) {
2904
+ const elementsInHighestGroup = getElementsInGroup(board, hitElementGroups[hitElementGroups.length - 1], true) || [];
2905
+ const isSelectGroupElement = selectedElements.some(element => elementsInHighestGroup.map(item => item.id).includes(element.id));
2906
+ if (isShift) {
2907
+ cacheSelectedElementsWithGroupOnShift(board, elements, isSelectGroupElement, elementsInHighestGroup);
2908
+ }
2909
+ else {
2910
+ cacheSelectedElementsWithGroup(board, elements, isSelectGroupElement, hitElementGroups);
2911
+ }
2912
+ }
2913
+ }
2914
+ }
2915
+ function cacheSelectedElementsWithGroupOnShift(board, elements, isSelectGroupElement, elementsInHighestGroup) {
2916
+ const selectedElements = getSelectedElements(board);
2917
+ let newElements = [...selectedElements];
2918
+ const hitElement = elements[0];
2919
+ let pendingElements = [];
2920
+ if (!isSelectGroupElement) {
2921
+ pendingElements = elementsInHighestGroup;
2922
+ }
2923
+ else {
2924
+ const isHitSelectedElement = selectedElements.some(item => item.id === hitElement.id);
2925
+ const selectedElementsInGroup = elementsInHighestGroup.filter(item => selectedElements.includes(item));
2926
+ if (isHitSelectedElement) {
2927
+ pendingElements = selectedElementsInGroup.filter(item => item.id !== hitElement.id);
2928
+ }
2929
+ else {
2930
+ pendingElements.push(...selectedElementsInGroup, ...elements);
2931
+ }
2932
+ }
2933
+ elementsInHighestGroup.forEach(element => {
2934
+ if (newElements.includes(element)) {
2935
+ newElements.splice(newElements.indexOf(element), 1);
2936
+ }
2937
+ });
2938
+ if (pendingElements.length) {
2939
+ newElements.push(...pendingElements);
2940
+ }
2941
+ cacheSelectedElements(board, uniqueById(newElements));
2942
+ }
2943
+ function cacheSelectedElementsWithGroup(board, elements, isSelectGroupElement, hitElementGroups) {
2944
+ let newElements = [...elements];
2945
+ const selectedGroups = filterSelectedGroups(board, hitElementGroups);
2946
+ if (selectedGroups.length > 0) {
2947
+ if (selectedGroups.length > 1) {
2948
+ newElements = getAllElementsInGroup(board, selectedGroups[selectedGroups.length - 2], true);
2949
+ }
2950
+ }
2951
+ else {
2952
+ const elementsInGroup = getAllElementsInGroup(board, hitElementGroups[hitElementGroups.length - 1], true);
2953
+ if (!isSelectGroupElement) {
2954
+ newElements = elementsInGroup;
2955
+ }
2956
+ }
2957
+ cacheSelectedElements(board, uniqueById(newElements));
2958
+ }
2695
2959
 
2696
2960
  const getElementsInGroup = (board, group, recursion, includeGroup) => {
2697
2961
  let result = [];
@@ -2702,7 +2966,7 @@ const getElementsInGroup = (board, group, recursion, includeGroup) => {
2702
2966
  if (includeGroup) {
2703
2967
  result.push(item);
2704
2968
  }
2705
- result.push(...getElementsInGroup(board, item, recursion));
2969
+ result.push(...getElementsInGroup(board, item, recursion, includeGroup));
2706
2970
  }
2707
2971
  else {
2708
2972
  result.push(item);
@@ -2714,18 +2978,28 @@ const getElementsInGroup = (board, group, recursion, includeGroup) => {
2714
2978
  }
2715
2979
  return result;
2716
2980
  };
2981
+ const getAllElementsInGroup = (board, group, recursion, includeGroup) => {
2982
+ const elementsInGroup = getElementsInGroup(board, group, recursion, includeGroup);
2983
+ const result = [];
2984
+ elementsInGroup.forEach(element => {
2985
+ depthFirstRecursion(element, node => {
2986
+ result.push(node);
2987
+ }, () => true);
2988
+ });
2989
+ return result;
2990
+ };
2717
2991
  const getRectangleByGroup = (board, group, recursion) => {
2718
- const elementsInGroup = getElementsInGroup(board, group, recursion);
2992
+ const elementsInGroup = getAllElementsInGroup(board, group, recursion);
2719
2993
  return getRectangleByElements(board, elementsInGroup, false);
2720
2994
  };
2721
- const getGroupByElement = (board, element, recursion) => {
2722
- const group = board.children.find(item => item.id === element?.groupId);
2995
+ const getGroupByElement = (board, element, recursion, source) => {
2996
+ const group = (source || board.children).find(item => item.id === element?.groupId);
2723
2997
  if (!group) {
2724
2998
  return recursion ? [] : null;
2725
2999
  }
2726
3000
  if (recursion) {
2727
3001
  const groups = [group];
2728
- const grandGroups = getGroupByElement(board, group, recursion);
3002
+ const grandGroups = getGroupByElement(board, group, recursion, source);
2729
3003
  if (grandGroups.length) {
2730
3004
  groups.push(...grandGroups);
2731
3005
  }
@@ -2736,56 +3010,66 @@ const getGroupByElement = (board, element, recursion) => {
2736
3010
  }
2737
3011
  };
2738
3012
  const getHighestGroup = (board, element) => {
2739
- const groups = getGroupByElement(board, element, true);
2740
- if (groups.length) {
2741
- return groups[groups.length - 1];
3013
+ const hitElementGroups = getGroupByElement(board, element, true);
3014
+ if (hitElementGroups.length) {
3015
+ return hitElementGroups[hitElementGroups.length - 1];
2742
3016
  }
2743
3017
  return null;
2744
3018
  };
2745
3019
  const getElementsInGroupByElement = (board, element) => {
2746
3020
  const highestGroup = getHighestGroup(board, element);
2747
3021
  if (highestGroup) {
2748
- return getElementsInGroup(board, highestGroup, true);
3022
+ return getAllElementsInGroup(board, highestGroup, true);
2749
3023
  }
2750
3024
  else {
2751
3025
  return [element];
2752
3026
  }
2753
3027
  };
2754
- const isSelectedElementOrGroup = (board, element) => {
2755
- const selectedElements = getSelectedElements(board);
3028
+ const isSelectedElementOrGroup = (board, element, elements) => {
3029
+ const selectedElements = elements || getSelectedElements(board);
2756
3030
  if (PlaitGroupElement.isGroup(element)) {
2757
- return isSelectedAllElementsInGroup(board, element);
3031
+ return isSelectedAllElementsInGroup(board, element, elements);
2758
3032
  }
2759
- return selectedElements.includes(element);
3033
+ return selectedElements.map(item => item.id).includes(element.id);
2760
3034
  };
2761
- const isSelectedAllElementsInGroup = (board, group) => {
2762
- const selectedElements = getSelectedElements(board);
3035
+ const isSelectedAllElementsInGroup = (board, group, elements) => {
3036
+ const selectedElements = elements || getSelectedElements(board);
2763
3037
  const elementsInGroup = getElementsInGroup(board, group, true);
2764
- return elementsInGroup.every(item => selectedElements.includes(item));
3038
+ return elementsInGroup.every(item => selectedElements.map(element => element.id).includes(item.id));
2765
3039
  };
2766
- const getSelectedGroups = (board, groups) => {
3040
+ const filterSelectedGroups = (board, groups, elements) => {
2767
3041
  const selectedGroups = [];
2768
3042
  groups.forEach(item => {
2769
- if (isSelectedElementOrGroup(board, item)) {
3043
+ if (isSelectedElementOrGroup(board, item, elements)) {
2770
3044
  selectedGroups.push(item);
2771
3045
  }
2772
3046
  });
2773
3047
  return selectedGroups;
2774
3048
  };
2775
- const getHighestSelectedGroup = (board, element) => {
2776
- const groups = getGroupByElement(board, element, true);
2777
- const selectedGroups = getSelectedGroups(board, groups);
3049
+ const getSelectedGroups = (board, elements) => {
3050
+ const highestSelectedGroups = getHighestSelectedGroups(board, elements);
3051
+ const groups = [];
3052
+ highestSelectedGroups.forEach(item => {
3053
+ groups.push(item);
3054
+ const elementsInGroup = getElementsInGroup(board, item, true, true);
3055
+ groups.push(...elementsInGroup.filter(item => PlaitGroupElement.isGroup(item)));
3056
+ });
3057
+ return groups;
3058
+ };
3059
+ const getHighestSelectedGroup = (board, element, elements) => {
3060
+ const hitElementGroups = getGroupByElement(board, element, true, elements);
3061
+ const selectedGroups = filterSelectedGroups(board, hitElementGroups, elements);
2778
3062
  if (selectedGroups.length) {
2779
3063
  return selectedGroups[selectedGroups.length - 1];
2780
3064
  }
2781
3065
  return null;
2782
3066
  };
2783
- const getHighestSelectedGroups = (board) => {
3067
+ const getHighestSelectedGroups = (board, elements) => {
2784
3068
  let result = [];
2785
- const selectedElements = getSelectedElements(board);
3069
+ const selectedElements = elements || getSelectedElements(board);
2786
3070
  selectedElements.forEach(item => {
2787
3071
  if (item.groupId) {
2788
- const group = getHighestSelectedGroup(board, item);
3072
+ const group = getHighestSelectedGroup(board, item, elements);
2789
3073
  if (group && !result.includes(group)) {
2790
3074
  result.push(group);
2791
3075
  }
@@ -2793,15 +3077,17 @@ const getHighestSelectedGroups = (board) => {
2793
3077
  });
2794
3078
  return result;
2795
3079
  };
2796
- const getSelectedIsolatedElements = (board) => {
3080
+ const getSelectedIsolatedElements = (board, elements) => {
2797
3081
  let result = [];
2798
- const selectedElements = getSelectedElements(board);
2799
- selectedElements.forEach(item => {
3082
+ const selectedElements = elements || getSelectedElements(board);
3083
+ selectedElements
3084
+ .filter(item => !PlaitGroupElement.isGroup(item))
3085
+ .forEach(item => {
2800
3086
  if (!item.groupId) {
2801
3087
  result.push(item);
2802
3088
  }
2803
3089
  else {
2804
- const group = getHighestSelectedGroup(board, item);
3090
+ const group = getHighestSelectedGroup(board, item, elements);
2805
3091
  if (!group) {
2806
3092
  result.push(item);
2807
3093
  }
@@ -2809,8 +3095,12 @@ const getSelectedIsolatedElements = (board) => {
2809
3095
  });
2810
3096
  return result;
2811
3097
  };
2812
- const getHighestSelectedElements = (board) => {
2813
- return [...getHighestSelectedGroups(board), ...getSelectedIsolatedElements(board)];
3098
+ const getSelectedIsolatedElementsCanAddToGroup = (board, elements) => {
3099
+ const selectedIsolatedElements = getSelectedIsolatedElements(board, elements);
3100
+ return selectedIsolatedElements.filter(item => board.canAddToGroup(item));
3101
+ };
3102
+ const getHighestSelectedElements = (board, elements) => {
3103
+ return [...getHighestSelectedGroups(board, elements), ...getSelectedIsolatedElements(board, elements)];
2814
3104
  };
2815
3105
  const createGroupRectangleG = (board, elements) => {
2816
3106
  const selectedElements = getSelectedElements(board);
@@ -2821,20 +3111,31 @@ const createGroupRectangleG = (board, elements) => {
2821
3111
  if (item.groupId && isRender) {
2822
3112
  const elements = getElementsInGroupByElement(board, item);
2823
3113
  const rectangle = getRectangleByElements(board, elements, false);
2824
- groupRectangleG.append(drawRectangle(board, rectangle, {
3114
+ const rectangleG = drawRectangle(board, rectangle, {
2825
3115
  stroke: SELECTION_BORDER_COLOR,
2826
3116
  strokeWidth: ACTIVE_STROKE_WIDTH,
2827
3117
  strokeLineDash: [5]
2828
- }));
3118
+ });
3119
+ const angle = getSelectionAngle(elements);
3120
+ if (angle) {
3121
+ setAngleForG(rectangleG, RectangleClient.getCenterPoint(rectangle), angle);
3122
+ }
3123
+ groupRectangleG.append(rectangleG);
2829
3124
  }
2830
3125
  });
2831
3126
  return groupRectangleG;
2832
3127
  };
2833
- const createGroup = () => {
2834
- return {
2835
- id: idCreator(),
2836
- type: 'group'
2837
- };
3128
+ const createGroup = (groupId) => {
3129
+ return groupId
3130
+ ? {
3131
+ id: idCreator(),
3132
+ type: 'group',
3133
+ groupId
3134
+ }
3135
+ : {
3136
+ id: idCreator(),
3137
+ type: 'group'
3138
+ };
2838
3139
  };
2839
3140
  const nonGroupInHighestSelectedElements = (elements) => {
2840
3141
  return elements.every(item => !item.groupId);
@@ -2842,54 +3143,23 @@ const nonGroupInHighestSelectedElements = (elements) => {
2842
3143
  const hasSelectedElementsInSameGroup = (elements) => {
2843
3144
  return elements.every(item => item.groupId && item.groupId === elements[0].groupId);
2844
3145
  };
2845
- const canAddGroup = (highestSelectedElements) => {
2846
- if (highestSelectedElements.length > 1) {
2847
- return nonGroupInHighestSelectedElements(highestSelectedElements) || hasSelectedElementsInSameGroup(highestSelectedElements);
3146
+ const canAddGroup = (board, elements) => {
3147
+ const highestSelectedElements = getHighestSelectedElements(board, elements);
3148
+ const rootElements = highestSelectedElements.filter(item => board.canAddToGroup(item));
3149
+ if (rootElements.length > 1) {
3150
+ return nonGroupInHighestSelectedElements(rootElements) || hasSelectedElementsInSameGroup(rootElements);
2848
3151
  }
2849
3152
  return false;
2850
3153
  };
2851
- const addGroup = (board) => {
2852
- const selectedGroups = getHighestSelectedGroups(board);
2853
- const selectedIsolatedElements = getSelectedIsolatedElements(board);
2854
- const highestSelectedElements = [...selectedGroups, ...selectedIsolatedElements];
2855
- const group = createGroup();
2856
- if (canAddGroup(highestSelectedElements)) {
2857
- highestSelectedElements.forEach(item => {
2858
- const path = PlaitBoard.findPath(board, item);
2859
- Transforms.setNode(board, { groupId: group.id }, path);
2860
- });
2861
- if (hasSelectedElementsInSameGroup(highestSelectedElements)) {
2862
- const newGroupId = selectedIsolatedElements[0].groupId;
2863
- Transforms.insertNode(board, {
2864
- ...group,
2865
- groupId: newGroupId
2866
- }, [board.children.length]);
2867
- }
2868
- else {
2869
- Transforms.insertNode(board, group, [board.children.length]);
2870
- }
2871
- }
2872
- };
2873
- const canRemoveGroup = (board, selectedGroups) => {
2874
- const selectedElements = getSelectedElements(board);
3154
+ const canRemoveGroup = (board, elements) => {
3155
+ const selectedGroups = getHighestSelectedGroups(board, elements);
3156
+ const selectedElements = elements || getSelectedElements(board);
2875
3157
  return selectedElements.length > 0 && selectedGroups.length > 0;
2876
3158
  };
2877
- const removeGroup = (board) => {
2878
- const selectedGroups = getHighestSelectedGroups(board);
2879
- if (canRemoveGroup(board, selectedGroups)) {
2880
- selectedGroups.map(group => {
2881
- const elementsInGroup = findElements(board, {
2882
- match: item => item.groupId === group.id,
2883
- recursion: () => false
2884
- });
2885
- elementsInGroup.forEach(item => {
2886
- const path = PlaitBoard.findPath(board, item);
2887
- Transforms.setNode(board, { groupId: group.groupId || undefined }, path);
2888
- });
2889
- const groupPath = PlaitBoard.findPath(board, group);
2890
- Transforms.removeNode(board, groupPath);
2891
- });
2892
- }
3159
+
3160
+ const deleteFragment = (board) => {
3161
+ const elements = board.getDeletedFragment([]);
3162
+ board.deleteFragment(elements);
2893
3163
  };
2894
3164
 
2895
3165
  const PlaitElement = {
@@ -3080,12 +3350,20 @@ var Direction;
3080
3350
  Direction["bottom"] = "bottom";
3081
3351
  })(Direction || (Direction = {}));
3082
3352
 
3353
+ const PlaitGroupElement = {
3354
+ isGroup: (value) => {
3355
+ return value.type === 'group';
3356
+ }
3357
+ };
3358
+
3083
3359
  function getRectangleByElements(board, elements, recursion) {
3084
- const rectangles = [];
3360
+ const rectanglesCornerPoints = [];
3085
3361
  const callback = (node) => {
3086
3362
  const nodeRectangle = board.getRectangle(node);
3087
3363
  if (nodeRectangle) {
3088
- rectangles.push(nodeRectangle);
3364
+ const cornerPoints = RectangleClient.getCornerPoints(nodeRectangle);
3365
+ const rotatedCornerPoints = rotatePointsByElement(cornerPoints, node) || cornerPoints;
3366
+ rectanglesCornerPoints.push(rotatedCornerPoints);
3089
3367
  }
3090
3368
  else {
3091
3369
  console.error(`can not get rectangle of element:`, node);
@@ -3099,8 +3377,17 @@ function getRectangleByElements(board, elements, recursion) {
3099
3377
  callback(element);
3100
3378
  }
3101
3379
  });
3102
- if (rectangles.length > 0) {
3103
- return RectangleClient.getBoundingRectangle(rectangles);
3380
+ if (rectanglesCornerPoints.length > 0) {
3381
+ if (hasSameAngle(elements)) {
3382
+ const angle = getSelectionAngle(elements);
3383
+ return getRotatedBoundingRectangle(rectanglesCornerPoints, angle);
3384
+ }
3385
+ else {
3386
+ const flatCornerPoints = rectanglesCornerPoints.reduce((acc, val) => {
3387
+ return acc.concat(val);
3388
+ }, []);
3389
+ return RectangleClient.getRectangleByPoints(flatCornerPoints);
3390
+ }
3104
3391
  }
3105
3392
  else {
3106
3393
  return {
@@ -3149,6 +3436,10 @@ const PlaitBoard = {
3149
3436
  IS_BOARD_CACHE.set(value, isBoard);
3150
3437
  return isBoard;
3151
3438
  },
3439
+ isAlive(board) {
3440
+ const isAlive = IS_BOARD_CACHE.get(board);
3441
+ return !!isAlive;
3442
+ },
3152
3443
  findPath(board, node) {
3153
3444
  const path = [];
3154
3445
  let child = node;
@@ -3311,6 +3602,9 @@ function createBoard(children, options) {
3311
3602
  },
3312
3603
  onChange: () => { },
3313
3604
  afterChange: () => { },
3605
+ drawActiveRectangle: () => {
3606
+ return drawEntireActiveRectangleG(board);
3607
+ },
3314
3608
  mousedown: (event) => { },
3315
3609
  mousemove: (event) => { },
3316
3610
  mouseleave: (event) => { },
@@ -3325,12 +3619,11 @@ function createBoard(children, options) {
3325
3619
  setClipboardData(data, clipboardContext);
3326
3620
  },
3327
3621
  insertFragment: (data) => { },
3328
- deleteFragment: (data) => {
3329
- const elements = board.getDeletedFragment([]);
3622
+ deleteFragment: (elements) => {
3330
3623
  CoreTransforms.removeElements(board, elements);
3331
3624
  },
3332
3625
  getDeletedFragment: (data) => data,
3333
- getRelatedFragment: (data) => data,
3626
+ getRelatedFragment: (data, originData) => data,
3334
3627
  drawElement: (context) => [],
3335
3628
  redrawElement: (context, previousContext) => { },
3336
3629
  destroyElement: (context) => { },
@@ -3351,7 +3644,8 @@ function createBoard(children, options) {
3351
3644
  pointerLeave: pointer => { },
3352
3645
  globalPointerMove: pointer => { },
3353
3646
  globalPointerUp: pointer => { },
3354
- isImageBindingAllowed: (element) => false
3647
+ isImageBindingAllowed: (element) => false,
3648
+ canAddToGroup: (element) => true
3355
3649
  };
3356
3650
  return board;
3357
3651
  }
@@ -3514,7 +3808,7 @@ function withHandPointer(board) {
3514
3808
  }
3515
3809
 
3516
3810
  function withSelection(board) {
3517
- const { pointerDown, pointerUp, pointerMove, globalPointerUp, onChange, afterChange } = board;
3811
+ const { pointerDown, pointerUp, pointerMove, globalPointerUp, onChange, afterChange, drawActiveRectangle } = board;
3518
3812
  let start = null;
3519
3813
  let end = null;
3520
3814
  let selectionMovingG;
@@ -3628,112 +3922,46 @@ function withSelection(board) {
3628
3922
  selectionRectangleG?.remove();
3629
3923
  }
3630
3924
  const temporaryElements = getTemporaryElements(board);
3631
- let elements = temporaryElements ? temporaryElements : getHitElementsBySelection(board);
3632
- if (!options.isMultiple && elements.length > 1) {
3633
- elements = [elements[0]];
3925
+ if (temporaryElements) {
3926
+ cacheSelectedElements(board, [...temporaryElements]);
3634
3927
  }
3635
- const isHitElementWithGroup = elements.some(item => item.groupId);
3636
- if (isShift) {
3637
- const newSelectedElements = [...getSelectedElements(board)];
3638
- if (board.selection && Selection.isCollapsed(board.selection)) {
3639
- if (isHitElementWithGroup) {
3640
- let pendingElements = [...elements];
3641
- const hitElement = elements[0];
3642
- const groups = getGroupByElement(board, hitElement, true);
3643
- const selectedGroups = getSelectedGroups(board, groups);
3644
- const elementsInHighestGroup = getElementsInGroup(board, groups[groups.length - 1], true);
3645
- if (selectedGroups.length > 0) {
3646
- if (selectedGroups.length > 1) {
3647
- pendingElements = getElementsInGroup(board, selectedGroups[selectedGroups.length - 2], true);
3648
- }
3649
- }
3650
- else {
3651
- if (!newSelectedElements.includes(hitElement)) {
3652
- const selectedElementsInGroup = elementsInHighestGroup.filter(item => newSelectedElements.includes(item));
3653
- // When partially selected elements belong to a group,
3654
- // only select those elements along with the hit elements.
3655
- if (selectedElementsInGroup.length) {
3656
- pendingElements.push(...selectedElementsInGroup);
3928
+ else {
3929
+ let elements = getHitElementsBySelection(board);
3930
+ if (!options.isMultiple && elements.length > 1) {
3931
+ elements = [elements[0]];
3932
+ }
3933
+ const isHitElementWithGroup = elements.some(item => item.groupId);
3934
+ const selectedElements = getSelectedElements(board);
3935
+ if (isHitElementWithGroup) {
3936
+ setSelectedElementsWithGroup(board, elements, isShift);
3937
+ }
3938
+ else {
3939
+ if (isShift) {
3940
+ const newElements = [...selectedElements];
3941
+ if (board.selection && Selection.isCollapsed(board.selection)) {
3942
+ elements.forEach(element => {
3943
+ if (newElements.includes(element)) {
3944
+ newElements.splice(newElements.indexOf(element), 1);
3657
3945
  }
3658
3946
  else {
3659
- pendingElements = elementsInHighestGroup;
3947
+ newElements.push(element);
3660
3948
  }
3661
- }
3662
- else {
3663
- pendingElements = [];
3664
- }
3949
+ });
3950
+ cacheSelectedElements(board, newElements);
3665
3951
  }
3666
- elementsInHighestGroup.forEach(element => {
3667
- if (newSelectedElements.includes(element)) {
3668
- newSelectedElements.splice(newSelectedElements.indexOf(element), 1);
3669
- }
3670
- });
3671
- if (pendingElements.length) {
3672
- newSelectedElements.push(...pendingElements);
3673
- }
3674
- }
3675
- else {
3676
- elements.forEach(element => {
3677
- if (newSelectedElements.includes(element)) {
3678
- newSelectedElements.splice(newSelectedElements.indexOf(element), 1);
3679
- }
3680
- else {
3681
- newSelectedElements.push(element);
3682
- }
3683
- });
3684
- }
3685
- cacheSelectedElements(board, newSelectedElements);
3686
- }
3687
- else {
3688
- let newElements = [...elements];
3689
- if (isHitElementWithGroup) {
3690
- elements.forEach(item => {
3691
- if (!item.groupId) {
3692
- newElements.push(item);
3693
- }
3694
- else {
3695
- newElements.push(...getElementsInGroupByElement(board, item));
3696
- }
3697
- });
3698
- }
3699
- newElements.forEach(element => {
3700
- if (!newSelectedElements.includes(element)) {
3701
- newSelectedElements.push(element);
3952
+ else {
3953
+ elements.forEach(element => {
3954
+ if (!newElements.includes(element)) {
3955
+ newElements.push(element);
3956
+ }
3957
+ });
3958
+ cacheSelectedElements(board, [...newElements]);
3702
3959
  }
3703
- });
3704
- cacheSelectedElements(board, newSelectedElements);
3705
- }
3706
- }
3707
- else {
3708
- let newSelectedElements = [...elements];
3709
- if (isHitElementWithGroup) {
3710
- const isCollapsed = Selection.isCollapsed(board.selection);
3711
- if (!isCollapsed) {
3712
- newSelectedElements = [];
3713
- elements.forEach(item => {
3714
- if (!item.groupId) {
3715
- newSelectedElements.push(item);
3716
- }
3717
- else {
3718
- newSelectedElements.push(...getElementsInGroupByElement(board, item));
3719
- }
3720
- });
3721
3960
  }
3722
3961
  else {
3723
- const hitElement = elements[0];
3724
- const groups = getGroupByElement(board, hitElement, true);
3725
- const selectedGroups = getSelectedGroups(board, groups);
3726
- if (selectedGroups.length > 0) {
3727
- if (selectedGroups.length > 1) {
3728
- newSelectedElements = getElementsInGroup(board, selectedGroups[selectedGroups.length - 2], true);
3729
- }
3730
- }
3731
- else {
3732
- newSelectedElements = getElementsInGroup(board, groups[groups.length - 1], true);
3733
- }
3962
+ cacheSelectedElements(board, [...elements]);
3734
3963
  }
3735
3964
  }
3736
- cacheSelectedElements(board, newSelectedElements);
3737
3965
  }
3738
3966
  const newElements = getSelectedElements(board);
3739
3967
  previousSelectedElements = newElements;
@@ -3741,7 +3969,8 @@ function withSelection(board) {
3741
3969
  if (!isSelectionMoving(board)) {
3742
3970
  selectionRectangleG?.remove();
3743
3971
  if (newElements.length > 1) {
3744
- selectionRectangleG = createSelectionRectangleG(board);
3972
+ selectionRectangleG = board.drawActiveRectangle();
3973
+ PlaitBoard.getElementActiveHost(board).append(selectionRectangleG);
3745
3974
  }
3746
3975
  }
3747
3976
  }
@@ -3760,7 +3989,8 @@ function withSelection(board) {
3760
3989
  (currentSelectedElements.length !== previousSelectedElements.length ||
3761
3990
  currentSelectedElements.some((c, index) => c !== previousSelectedElements[index]))) {
3762
3991
  selectionRectangleG?.remove();
3763
- selectionRectangleG = createSelectionRectangleG(board);
3992
+ selectionRectangleG = board.drawActiveRectangle();
3993
+ PlaitBoard.getElementActiveHost(board).append(selectionRectangleG);
3764
3994
  previousSelectedElements = currentSelectedElements;
3765
3995
  }
3766
3996
  }
@@ -3809,8 +4039,8 @@ function withViewport(board) {
3809
4039
  return board;
3810
4040
  }
3811
4041
 
3812
- const ALIGN_TOLERANCE = 2;
3813
- class AlignReaction {
4042
+ const SNAP_TOLERANCE = 2;
4043
+ class MovingSnapReaction {
3814
4044
  constructor(board, activeElements, activeRectangle) {
3815
4045
  this.board = board;
3816
4046
  this.activeElements = activeElements;
@@ -3824,7 +4054,7 @@ class AlignReaction {
3824
4054
  return;
3825
4055
  }
3826
4056
  const rectangle = this.board.getRectangle(node);
3827
- rectangle && result.push(rectangle);
4057
+ rectangle && result.push(getRectangleByAngle(rectangle, node.angle) || rectangle);
3828
4058
  }, node => {
3829
4059
  if (node && (PlaitBoard.isBoard(node) || this.board.isRecursion(node))) {
3830
4060
  return true;
@@ -3835,7 +4065,7 @@ class AlignReaction {
3835
4065
  }, true);
3836
4066
  return result;
3837
4067
  }
3838
- handleAlign() {
4068
+ handleSnapping() {
3839
4069
  const alignRectangles = this.getAlignRectangle();
3840
4070
  const g = createG();
3841
4071
  let alignLines = [];
@@ -3847,7 +4077,7 @@ class AlignReaction {
3847
4077
  for (let alignRectangle of alignRectangles) {
3848
4078
  const closestDistances = this.calculateClosestDistances(this.activeRectangle, alignRectangle);
3849
4079
  let canDrawHorizontal = false;
3850
- if (!isCorrectX && closestDistances.absXDistance < ALIGN_TOLERANCE) {
4080
+ if (!isCorrectX && closestDistances.absXDistance < SNAP_TOLERANCE) {
3851
4081
  deltaX = closestDistances.xDistance;
3852
4082
  this.activeRectangle.x -= deltaX;
3853
4083
  isCorrectX = true;
@@ -3897,7 +4127,7 @@ class AlignReaction {
3897
4127
  isCorrectX = true;
3898
4128
  }
3899
4129
  let canDrawVertical = false;
3900
- if (!isCorrectY && closestDistances.absYDistance < ALIGN_TOLERANCE) {
4130
+ if (!isCorrectY && closestDistances.absYDistance < SNAP_TOLERANCE) {
3901
4131
  deltaY = closestDistances.yDistance;
3902
4132
  this.activeRectangle.y -= deltaY;
3903
4133
  isCorrectY = true;
@@ -4044,7 +4274,7 @@ class AlignReaction {
4044
4274
  //middle
4045
4275
  let _center = (before[axis] + before[side] + after[axis]) / 2;
4046
4276
  dif = Math.abs(activeRectangleCenter - _center);
4047
- if (dif < ALIGN_TOLERANCE) {
4277
+ if (dif < SNAP_TOLERANCE) {
4048
4278
  distributeDistance = (after[axis] - (before[axis] + before[side]) - this.activeRectangle[side]) / 2;
4049
4279
  delta = activeRectangleCenter - _center;
4050
4280
  beforeIndex = i;
@@ -4054,7 +4284,7 @@ class AlignReaction {
4054
4284
  const distanceRight = after[axis] - (before[axis] + before[side]);
4055
4285
  _center = after[axis] + after[side] + distanceRight + this.activeRectangle[side] / 2;
4056
4286
  dif = Math.abs(activeRectangleCenter - _center);
4057
- if (!distributeDistance && dif < ALIGN_TOLERANCE) {
4287
+ if (!distributeDistance && dif < SNAP_TOLERANCE) {
4058
4288
  distributeDistance = distanceRight;
4059
4289
  beforeIndex = j;
4060
4290
  delta = activeRectangleCenter - _center;
@@ -4063,7 +4293,7 @@ class AlignReaction {
4063
4293
  const distanceBefore = after[axis] - (before[axis] + before[side]);
4064
4294
  _center = before[axis] - distanceBefore - this.activeRectangle[side] / 2;
4065
4295
  dif = Math.abs(activeRectangleCenter - _center);
4066
- if (!distributeDistance && dif < ALIGN_TOLERANCE) {
4296
+ if (!distributeDistance && dif < SNAP_TOLERANCE) {
4067
4297
  distributeDistance = distanceBefore;
4068
4298
  afterIndex = i;
4069
4299
  delta = activeRectangleCenter - _center;
@@ -4185,6 +4415,9 @@ function withMoving(board) {
4185
4415
  let activeElements = [];
4186
4416
  let alignG = null;
4187
4417
  let activeElementsRectangle = null;
4418
+ let selectedTargetElements = null;
4419
+ let hitTargetElement = undefined;
4420
+ let isHitSelectedTarget = undefined;
4188
4421
  board.pointerDown = (event) => {
4189
4422
  if (PlaitBoard.isReadonly(board) ||
4190
4423
  !PlaitBoard.isPointer(board, PlaitPointerType.selection) ||
@@ -4194,24 +4427,32 @@ function withMoving(board) {
4194
4427
  return;
4195
4428
  }
4196
4429
  const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4197
- const targetElements = getTargetElements(board);
4198
- const targetRectangle = targetElements.length > 0 && getRectangleByElements(board, targetElements, false);
4199
- const isInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
4200
- if (isInTargetRectangle) {
4430
+ hitTargetElement = getHitElementByPoint(board, point, el => board.isMovable(el));
4431
+ selectedTargetElements = getSelectedTargetElements(board);
4432
+ isHitSelectedTarget = hitTargetElement && selectedTargetElements.includes(hitTargetElement);
4433
+ if (hitTargetElement && isHitSelectedTarget) {
4201
4434
  startPoint = point;
4202
- activeElements = targetElements;
4435
+ activeElements = selectedTargetElements;
4436
+ activeElementsRectangle = getRectangleByElements(board, activeElements, true);
4203
4437
  preventTouchMove(board, event, true);
4438
+ }
4439
+ else if (hitTargetElement) {
4440
+ startPoint = point;
4441
+ const relatedElements = board.getRelatedFragment([], [hitTargetElement]);
4442
+ activeElements = [...getElementsInGroupByElement(board, hitTargetElement), ...relatedElements];
4204
4443
  activeElementsRectangle = getRectangleByElements(board, activeElements, true);
4444
+ preventTouchMove(board, event, true);
4205
4445
  }
4206
4446
  else {
4207
- const targetElement = getHitElementByPoint(board, point, el => board.isMovable(el));
4208
- if (targetElement) {
4447
+ // 只有判定用户未击中元素之后才可以验证用户是否击中了已选元素所在的空白区域
4448
+ // Only after it is determined that the user has not hit the element can it be verified whether the user hit the blank area where the selected element is located.
4449
+ const targetRectangle = selectedTargetElements.length > 0 && getRectangleByElements(board, selectedTargetElements, false);
4450
+ const isHitInTargetRectangle = targetRectangle && RectangleClient.isPointInRectangle(targetRectangle, point);
4451
+ if (isHitInTargetRectangle) {
4209
4452
  startPoint = point;
4210
- activeElements = getElementsInGroupByElement(board, targetElement);
4211
- if (targetElements.length > 0) {
4212
- addSelectionWithTemporaryElements(board, []);
4213
- }
4214
- activeElementsRectangle = getRectangleByElements(board, activeElements, true);
4453
+ activeElements = selectedTargetElements;
4454
+ activeElementsRectangle = targetRectangle;
4455
+ preventTouchMove(board, event, true);
4215
4456
  }
4216
4457
  }
4217
4458
  pointerDown(event);
@@ -4227,6 +4468,12 @@ function withMoving(board) {
4227
4468
  offsetY = endPoint[1] - startPoint[1];
4228
4469
  const distance = distanceBetweenPointAndPoint(...endPoint, ...startPoint);
4229
4470
  if (distance > PRESS_AND_MOVE_BUFFER || getMovingElements(board).length > 0) {
4471
+ if (hitTargetElement && !isHitSelectedTarget && selectedTargetElements && selectedTargetElements.length > 0) {
4472
+ addSelectionWithTemporaryElements(board, []);
4473
+ hitTargetElement = undefined;
4474
+ selectedTargetElements = null;
4475
+ isHitSelectedTarget = undefined;
4476
+ }
4230
4477
  throttleRAF(board, 'with-moving', () => {
4231
4478
  if (!activeElementsRectangle) {
4232
4479
  return;
@@ -4236,8 +4483,8 @@ function withMoving(board) {
4236
4483
  x: activeElementsRectangle.x + offsetX,
4237
4484
  y: activeElementsRectangle.y + offsetY
4238
4485
  };
4239
- const reactionManager = new AlignReaction(board, activeElements, newRectangle);
4240
- const ref = reactionManager.handleAlign();
4486
+ const movingSnapReaction = new MovingSnapReaction(board, activeElements, getRectangleByAngle(newRectangle, getSelectionAngle(activeElements)) || newRectangle);
4487
+ const ref = movingSnapReaction.handleSnapping();
4241
4488
  offsetX -= ref.deltaX;
4242
4489
  offsetY -= ref.deltaY;
4243
4490
  alignG = ref.g;
@@ -4267,6 +4514,9 @@ function withMoving(board) {
4267
4514
  };
4268
4515
  board.globalPointerUp = event => {
4269
4516
  isPreventDefault = false;
4517
+ hitTargetElement = undefined;
4518
+ selectedTargetElements = null;
4519
+ isHitSelectedTarget = undefined;
4270
4520
  if (startPoint) {
4271
4521
  cancelMove(board);
4272
4522
  }
@@ -4315,7 +4565,7 @@ function withArrowMoving(board) {
4315
4565
  break;
4316
4566
  }
4317
4567
  }
4318
- const targetElements = getTargetElements(board);
4568
+ const targetElements = getSelectedTargetElements(board);
4319
4569
  throttleRAF(board, 'with-arrow-moving', () => {
4320
4570
  updatePoints(board, targetElements, offset[0], offset[1]);
4321
4571
  });
@@ -4328,7 +4578,7 @@ function withArrowMoving(board) {
4328
4578
  };
4329
4579
  return board;
4330
4580
  }
4331
- function getTargetElements(board) {
4581
+ function getSelectedTargetElements(board) {
4332
4582
  const selectedElements = getSelectedElements(board);
4333
4583
  const movableElements = board.children.filter(item => board.isMovable(item));
4334
4584
  const targetElements = selectedElements.filter(element => {
@@ -4339,7 +4589,7 @@ function getTargetElements(board) {
4339
4589
  return targetElements;
4340
4590
  }
4341
4591
  function updatePoints(board, targetElements, offsetX, offsetY) {
4342
- const validElements = targetElements.filter(element => board.children.findIndex(item => item.id === element.id) > -1);
4592
+ const validElements = targetElements.filter(element => !PlaitGroupElement.isGroup(element) && board.children.findIndex(item => item.id === element.id) > -1);
4343
4593
  const currentElements = validElements.map(element => {
4344
4594
  const points = element.points || [];
4345
4595
  const newPoints = points.map(p => [p[0] + offsetX, p[1] + offsetY]);
@@ -4463,7 +4713,7 @@ const withHotkey = (board) => {
4463
4713
  selectedElements.length > 0 &&
4464
4714
  (hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
4465
4715
  event.preventDefault();
4466
- board.deleteFragment(null);
4716
+ deleteFragment(board);
4467
4717
  }
4468
4718
  keyDown(event);
4469
4719
  };
@@ -4671,27 +4921,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
4671
4921
  type: Input
4672
4922
  }] } });
4673
4923
 
4674
- function withGroup(board) {
4675
- const { pointerMove, globalPointerUp } = board;
4676
- let groupRectangleG;
4677
- board.pointerMove = (event) => {
4678
- groupRectangleG?.remove();
4679
- const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
4680
- let selection = { anchor: point, focus: point };
4681
- if (board.selection && !Selection.isCollapsed(board.selection)) {
4682
- selection = board.selection;
4924
+ function withRelatedFragment(board) {
4925
+ const { setFragment } = board;
4926
+ board.setFragment = (data, clipboardContext, rectangle, type) => {
4927
+ const relatedFragment = board.getRelatedFragment([]);
4928
+ if (!clipboardContext) {
4929
+ clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
4683
4930
  }
4684
- const hitElements = getHitElementsBySelection(board, selection);
4685
- if (hitElements.length) {
4686
- groupRectangleG = createGroupRectangleG(board, hitElements);
4687
- groupRectangleG && PlaitBoard.getElementActiveHost(board).append(groupRectangleG);
4931
+ else {
4932
+ clipboardContext = addClipboardContext(clipboardContext, {
4933
+ text: '',
4934
+ type: WritableClipboardType.elements,
4935
+ data: relatedFragment
4936
+ });
4688
4937
  }
4689
- pointerMove(event);
4690
- };
4691
- board.globalPointerUp = (event) => {
4692
- groupRectangleG?.remove();
4693
- groupRectangleG = null;
4694
- globalPointerUp(event);
4938
+ setFragment(data, clipboardContext, rectangle, type);
4695
4939
  };
4696
4940
  return board;
4697
4941
  }
@@ -4769,6 +5013,7 @@ class PlaitBoardComponent {
4769
5013
  BOARD_TO_COMPONENT.set(this.board, this);
4770
5014
  BOARD_TO_ROUGH_SVG.set(this.board, roughSVG);
4771
5015
  BOARD_TO_HOST.set(this.board, this.host);
5016
+ IS_BOARD_ALIVE.set(this.board, true);
4772
5017
  BOARD_TO_ELEMENT_HOST.set(this.board, {
4773
5018
  host: elementHost,
4774
5019
  upperHost: elementUpperHost,
@@ -4821,7 +5066,7 @@ class PlaitBoardComponent {
4821
5066
  initializeViewportOffset(this.board);
4822
5067
  }
4823
5068
  initializePlugins() {
4824
- let board = withHotkey(withHandPointer(withHistory(withSelection(withGroup(withMoving(withBoard(withViewport(withOptions(createBoard(this.plaitValue, this.plaitOptions))))))))));
5069
+ let board = withRelatedFragment(withHotkey(withHandPointer(withHistory(withSelection(withMoving(withBoard(withViewport(withOptions(createBoard(this.plaitValue, this.plaitOptions))))))))));
4825
5070
  this.plaitPlugins.forEach(plugin => {
4826
5071
  board = plugin(board);
4827
5072
  });
@@ -4942,7 +5187,7 @@ class PlaitBoardComponent {
4942
5187
  event.preventDefault();
4943
5188
  const rectangle = getRectangleByElements(this.board, selectedElements, false);
4944
5189
  this.board.setFragment(event.clipboardData, null, rectangle, 'cut');
4945
- this.board.deleteFragment(event.clipboardData);
5190
+ deleteFragment(this.board);
4946
5191
  });
4947
5192
  }
4948
5193
  viewportScrollListener() {
@@ -5024,6 +5269,7 @@ class PlaitBoardComponent {
5024
5269
  BOARD_TO_ROUGH_SVG.delete(this.board);
5025
5270
  BOARD_TO_HOST.delete(this.board);
5026
5271
  BOARD_TO_ELEMENT_HOST.delete(this.board);
5272
+ IS_BOARD_ALIVE.set(this.board, false);
5027
5273
  BOARD_TO_ON_CHANGE.delete(this.board);
5028
5274
  BOARD_TO_AFTER_CHANGE.set(this.board, () => { });
5029
5275
  }
@@ -5263,6 +5509,96 @@ function createModModifierKeys() {
5263
5509
  return modifiers;
5264
5510
  }
5265
5511
 
5512
+ const TEMPORARY_G = new Map();
5513
+ const getTemporaryGArray = (debugKey) => {
5514
+ return TEMPORARY_G.get(debugKey) || [];
5515
+ };
5516
+ const setTemporaryGArray = (debugKey, gArray) => {
5517
+ TEMPORARY_G.set(debugKey, gArray);
5518
+ };
5519
+ class DebugGenerator {
5520
+ constructor(debugKey) {
5521
+ this.debugKey = debugKey;
5522
+ }
5523
+ isDebug() {
5524
+ return isDebug(this.debugKey);
5525
+ }
5526
+ clear() {
5527
+ if (!this.isDebug()) {
5528
+ return;
5529
+ }
5530
+ const gArray = getTemporaryGArray(this.debugKey);
5531
+ setTemporaryGArray(this.debugKey, []);
5532
+ gArray.forEach(g => g.remove());
5533
+ }
5534
+ drawPolygon(board, points, options) {
5535
+ if (!isDebug(this.debugKey)) {
5536
+ return;
5537
+ }
5538
+ const polygonG = PlaitBoard.getRoughSVG(board).polygon(points, options || { stroke: 'red' });
5539
+ polygonG.classList.add(this.debugKey);
5540
+ PlaitBoard.getElementActiveHost(board).append(polygonG);
5541
+ const gArray = getTemporaryGArray(this.debugKey);
5542
+ gArray.push(polygonG);
5543
+ setTemporaryGArray(this.debugKey, gArray);
5544
+ return polygonG;
5545
+ }
5546
+ drawLine(board, points, options) {
5547
+ if (!isDebug(this.debugKey)) {
5548
+ return;
5549
+ }
5550
+ const lineG = PlaitBoard.getRoughSVG(board).linearPath(points, options || { stroke: 'red' });
5551
+ lineG.classList.add(this.debugKey);
5552
+ PlaitBoard.getElementActiveHost(board).append(lineG);
5553
+ const gArray = getTemporaryGArray(this.debugKey);
5554
+ gArray.push(lineG);
5555
+ setTemporaryGArray(this.debugKey, gArray);
5556
+ return lineG;
5557
+ }
5558
+ drawRectangle(board, data, options) {
5559
+ if (!isDebug(this.debugKey)) {
5560
+ return;
5561
+ }
5562
+ let rectangle;
5563
+ if (data instanceof Array) {
5564
+ rectangle = RectangleClient.getRectangleByPoints(data);
5565
+ }
5566
+ else {
5567
+ rectangle = data;
5568
+ }
5569
+ const rectangleG = PlaitBoard.getRoughSVG(board).rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height, options || { stroke: 'red' });
5570
+ rectangleG.classList.add(this.debugKey);
5571
+ PlaitBoard.getElementActiveHost(board).append(rectangleG);
5572
+ const gArray = getTemporaryGArray(this.debugKey);
5573
+ gArray.push(rectangleG);
5574
+ setTemporaryGArray(this.debugKey, gArray);
5575
+ return rectangleG;
5576
+ }
5577
+ drawCircles(board, points, diameter = 0, isCumulativeDiameter = false, options) {
5578
+ if (!isDebug(this.debugKey)) {
5579
+ return;
5580
+ }
5581
+ const result = [];
5582
+ points.forEach((p, i) => {
5583
+ const circle = PlaitBoard.getRoughSVG(board).circle(p[0], p[1], isCumulativeDiameter ? diameter * (i + 1) : diameter, Object.assign({}, { stroke: 'red', fill: 'red', fillStyle: 'solid' }, options || {}));
5584
+ circle.classList.add(this.debugKey);
5585
+ PlaitBoard.getElementActiveHost(board).append(circle);
5586
+ const gArray = getTemporaryGArray(this.debugKey);
5587
+ gArray.push(circle);
5588
+ result.push(circle);
5589
+ setTemporaryGArray(this.debugKey, gArray);
5590
+ });
5591
+ return result;
5592
+ }
5593
+ }
5594
+ const createDebugGenerator = (debugKey) => {
5595
+ return new DebugGenerator(debugKey);
5596
+ };
5597
+ const isDebug = (key) => {
5598
+ const defaultKey = 'debug:plait';
5599
+ return localStorage.getItem(key || defaultKey) === 'true';
5600
+ };
5601
+
5266
5602
  /*
5267
5603
  * Public API Surface of plait
5268
5604
  */
@@ -5271,5 +5607,5 @@ function createModModifierKeys() {
5271
5607
  * Generated bundle index. Do not edit.
5272
5608
  */
5273
5609
 
5274
- 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, HIT_DISTANCE_BUFFER, 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, PlaitGroupElement, 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, addGroup, addSelectedElement, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, calcNewViewBox, canAddGroup, canRemoveGroup, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, 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, getElementsInGroup, getElementsInGroupByElement, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByElements, getRectangleByGroup, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getTargetElements, getTemporaryElements, getTemporaryRef, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hasSelectedElementsInSameGroup, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isContextmenu, isDOMElement, isDOMNode, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, nonGroupInHighestSelectedElements, normalizePoint, preventTouchMove, removeGroup, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectionMoving, setStrokeLinecap, 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 };
5610
+ 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, DebugGenerator, 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, GroupTransforms, H, HIT_DISTANCE_BUFFER, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_ALIVE, 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, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, 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, SNAPPING_STROKE_WIDTH, 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, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createDebugGenerator, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createTestingBoard, createText, createTouchEvent, debounce, degreesToRadians, deleteFragment, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawEntireActiveRectangleG, drawLine, drawLinearPath, drawRectangle, drawRoundRectangle, fakeNodeWeakMap, filterSelectedGroups, findElements, getAllElementsInGroup, getBoardRectangle, getClipboardData, getClipboardFromHtml, getDataTransferClipboard, getDataTransferClipboardText, getElementById, getElementHostBBox, getElementsInGroup, getElementsInGroupByElement, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getOffsetAfterRotate, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByAngle, getRectangleByElements, getRectangleByGroup, getRotatedBoundingRectangle, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getSelectedIsolatedElementsCanAddToGroup, getSelectedTargetElements, getSelectionAngle, getTemporaryElements, getTemporaryRef, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hasSameAngle, hasSelectedElementsInSameGroup, hasValidAngle, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isAxisChangedByAngle, isContextmenu, isDOMElement, isDOMNode, isDebug, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, nonGroupInHighestSelectedElements, normalizePoint, preventTouchMove, radiansToDegrees, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, rotateElements, rotatePoints, rotatePointsByElement, rotatedDataPoints, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectedElementsWithGroup, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, uniqueById, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
5275
5611
  //# sourceMappingURL=plait-core.mjs.map