@plait/mind 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/{drawer/base/base.d.ts → base/base.drawer.d.ts} +1 -1
  2. package/{plugins/emoji → base}/emoji-base.component.d.ts +2 -2
  3. package/{plugins/emoji → base}/index.d.ts +1 -1
  4. package/draw/abstract.d.ts +2 -1
  5. package/draw/indented-link.d.ts +1 -1
  6. package/draw/link/logic-link.d.ts +1 -1
  7. package/draw/node.d.ts +5 -0
  8. package/draw/topic.d.ts +16 -0
  9. package/{plugins/emoji → drawer}/emoji.drawer.d.ts +3 -3
  10. package/drawer/quick-insert.drawer.d.ts +1 -1
  11. package/esm2020/base/base.drawer.mjs +17 -0
  12. package/esm2020/base/emoji-base.component.mjs +33 -0
  13. package/esm2020/base/index.mjs +3 -0
  14. package/esm2020/draw/abstract.mjs +8 -7
  15. package/esm2020/draw/indented-link.mjs +3 -3
  16. package/esm2020/draw/link/abstract-link.mjs +9 -15
  17. package/esm2020/draw/link/logic-link.mjs +9 -9
  18. package/esm2020/draw/node.mjs +21 -0
  19. package/esm2020/draw/topic.mjs +32 -0
  20. package/esm2020/drawer/emoji.drawer.mjs +73 -0
  21. package/esm2020/drawer/quick-insert.drawer.mjs +3 -3
  22. package/esm2020/interfaces/index.mjs +2 -2
  23. package/esm2020/interfaces/pointer.mjs +5 -0
  24. package/esm2020/mind.component.mjs +2 -2
  25. package/esm2020/mind.module.mjs +5 -5
  26. package/esm2020/node.component.mjs +11 -10
  27. package/esm2020/plugins/with-abstract-resize.board.mjs +12 -0
  28. package/esm2020/plugins/with-abstract-resize.mjs +107 -0
  29. package/esm2020/plugins/with-mind-create.mjs +85 -0
  30. package/esm2020/plugins/with-mind-extend.mjs +11 -0
  31. package/esm2020/plugins/with-mind.board.mjs +2 -0
  32. package/esm2020/plugins/with-mind.mjs +30 -16
  33. package/esm2020/plugins/with-node-dnd.mjs +162 -0
  34. package/esm2020/public-api.mjs +5 -3
  35. package/esm2020/transforms/abstract-node.mjs +3 -2
  36. package/esm2020/transforms/emoji.mjs +37 -0
  37. package/esm2020/transforms/index.mjs +7 -3
  38. package/esm2020/transforms/node.mjs +40 -33
  39. package/esm2020/utils/abstract/common.mjs +64 -31
  40. package/esm2020/utils/abstract/resize.mjs +3 -2
  41. package/esm2020/utils/clipboard.mjs +16 -18
  42. package/esm2020/utils/dnd/common.mjs +35 -0
  43. package/esm2020/utils/dnd/detector.mjs +268 -0
  44. package/esm2020/utils/dnd/draw.mjs +161 -0
  45. package/esm2020/utils/index.mjs +6 -6
  46. package/esm2020/utils/mind.mjs +6 -129
  47. package/esm2020/utils/node/adjust-node.mjs +49 -0
  48. package/esm2020/utils/node/common.mjs +6 -0
  49. package/esm2020/utils/node/create-node.mjs +61 -0
  50. package/esm2020/utils/node/index.mjs +4 -0
  51. package/esm2020/utils/point-placement.mjs +22 -2
  52. package/esm2020/utils/position/emoji.mjs +31 -0
  53. package/esm2020/utils/position/index.mjs +4 -0
  54. package/esm2020/utils/position/node.mjs +34 -0
  55. package/esm2020/utils/position/topic.mjs +14 -0
  56. package/esm2020/utils/space/emoji.mjs +19 -0
  57. package/esm2020/utils/space/layout-options.mjs +72 -0
  58. package/esm2020/utils/space/node-space.mjs +77 -0
  59. package/fesm2015/plait-mind.mjs +1464 -1631
  60. package/fesm2015/plait-mind.mjs.map +1 -1
  61. package/fesm2020/plait-mind.mjs +1486 -1642
  62. package/fesm2020/plait-mind.mjs.map +1 -1
  63. package/interfaces/index.d.ts +1 -1
  64. package/interfaces/pointer.d.ts +3 -0
  65. package/mind.module.d.ts +2 -2
  66. package/node.component.d.ts +3 -3
  67. package/package.json +3 -3
  68. package/{interfaces/abstract.d.ts → plugins/with-abstract-resize.board.d.ts} +2 -2
  69. package/plugins/with-mind-create.d.ts +11 -0
  70. package/plugins/with-mind-extend.d.ts +3 -0
  71. package/plugins/{with-extend-mind.d.ts → with-mind.board.d.ts} +4 -4
  72. package/plugins/with-mind.d.ts +1 -1
  73. package/public-api.d.ts +4 -2
  74. package/styles/styles.scss +5 -2
  75. package/transforms/abstract-node.d.ts +1 -1
  76. package/transforms/emoji.d.ts +6 -0
  77. package/transforms/index.d.ts +3 -0
  78. package/transforms/node.d.ts +5 -5
  79. package/utils/abstract/common.d.ts +19 -4
  80. package/utils/abstract/resize.d.ts +2 -1
  81. package/utils/dnd/common.d.ts +7 -0
  82. package/utils/dnd/detector.d.ts +31 -0
  83. package/utils/dnd/draw.d.ts +9 -0
  84. package/utils/index.d.ts +5 -5
  85. package/utils/mind.d.ts +3 -22
  86. package/utils/node/adjust-node.d.ts +5 -0
  87. package/utils/{node.d.ts → node/common.d.ts} +1 -1
  88. package/utils/node/create-node.d.ts +14 -0
  89. package/utils/node/index.d.ts +3 -0
  90. package/utils/point-placement.d.ts +8 -1
  91. package/utils/position/emoji.d.ts +7 -0
  92. package/utils/position/index.d.ts +3 -0
  93. package/utils/position/node.d.ts +12 -0
  94. package/utils/position/topic.d.ts +16 -0
  95. package/utils/space/emoji.d.ts +7 -0
  96. package/{layout-option.d.ts → utils/space/layout-options.d.ts} +1 -1
  97. package/utils/{node-space.d.ts → space/node-space.d.ts} +4 -4
  98. package/draw/link.d.ts +0 -3
  99. package/draw/richtext.d.ts +0 -15
  100. package/draw/shape.d.ts +0 -3
  101. package/esm2020/draw/link.mjs +0 -160
  102. package/esm2020/draw/richtext.mjs +0 -39
  103. package/esm2020/draw/shape.mjs +0 -18
  104. package/esm2020/drawer/base/base.mjs +0 -17
  105. package/esm2020/interfaces/abstract.mjs +0 -12
  106. package/esm2020/layout-option.mjs +0 -72
  107. package/esm2020/plugins/emoji/emoji-base.component.mjs +0 -33
  108. package/esm2020/plugins/emoji/emoji.drawer.mjs +0 -72
  109. package/esm2020/plugins/emoji/emoji.mjs +0 -47
  110. package/esm2020/plugins/emoji/index.mjs +0 -3
  111. package/esm2020/plugins/with-abstract.mjs +0 -106
  112. package/esm2020/plugins/with-dnd.mjs +0 -179
  113. package/esm2020/plugins/with-extend-mind.mjs +0 -11
  114. package/esm2020/utils/direction-corrector.mjs +0 -54
  115. package/esm2020/utils/direction-detector.mjs +0 -56
  116. package/esm2020/utils/dnd.mjs +0 -122
  117. package/esm2020/utils/draw-placeholder.mjs +0 -313
  118. package/esm2020/utils/drop-target-corrector.mjs +0 -87
  119. package/esm2020/utils/graph.mjs +0 -24
  120. package/esm2020/utils/node-space.mjs +0 -77
  121. package/esm2020/utils/node.mjs +0 -6
  122. package/plugins/emoji/emoji.d.ts +0 -11
  123. package/utils/direction-corrector.d.ts +0 -4
  124. package/utils/direction-detector.d.ts +0 -9
  125. package/utils/dnd.d.ts +0 -16
  126. package/utils/draw-placeholder.d.ts +0 -42
  127. package/utils/drop-target-corrector.d.ts +0 -9
  128. package/utils/graph.d.ts +0 -5
  129. /package/plugins/{with-abstract.d.ts → with-abstract-resize.d.ts} +0 -0
  130. /package/plugins/{with-dnd.d.ts → with-node-dnd.d.ts} +0 -0
@@ -1,16 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, ChangeDetectionStrategy, NgModule, Directive, Input } from '@angular/core';
3
3
  import * as i2 from '@plait/core';
4
- import { distanceBetweenPointAndRectangle, PlaitBoard, PlaitNode, NODE_TO_PARENT, Path, ELEMENT_TO_COMPONENT, PlaitElement, Transforms, idCreator, isNullOrUndefined, clearSelectedElement, addSelectedElement, drawRoundRectangle, getRectangleByElements, RectangleClient, getSelectedElements, createG, drawAbstractRoundRectangle, PlaitPluginElementComponent, PlaitPointerType, NODE_TO_INDEX, createText, IS_TEXT_EDITABLE, MERGING, transformPoint, toPoint, depthFirstRecursion, PlaitModule, distanceBetweenPointAndPoint, updateForeignObject as updateForeignObject$1, CLIP_BOARD_FORMAT_KEY, BOARD_TO_HOST, Selection, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
- import { MindLayoutType, AbstractNode, getAbstractLayout, isIndentedLayout, isStandardLayout, isHorizontalLogicLayout, isVerticalLogicLayout, isTopLayout, isLeftLayout, isBottomLayout, isRightLayout, isHorizontalLayout, getNonAbstractChildren, getCorrectStartEnd, ConnectingPosition, GlobalLayout } from '@plait/layouts';
6
- import { getSizeByText, ROOT_DEFAULT_HEIGHT, TEXT_DEFAULT_HEIGHT, drawRichtext, updateForeignObject, createForeignObject, updateRichText, setFullSelectionAndFocus, getRichtextContentSize, hasEditableTarget, RichtextModule } from '@plait/richtext';
4
+ import { PlaitBoard, PlaitNode, NODE_TO_PARENT, Path, distanceBetweenPointAndRectangle, RectangleClient, PlaitElement, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, depthFirstRecursion, drawRoundRectangle, createG, getRectangleByElements, getSelectedElements, drawAbstractRoundRectangle, PlaitPluginElementComponent, PlaitPointerType, NODE_TO_INDEX, createText, IS_TEXT_EDITABLE, MERGING, transformPoint, toPoint, PlaitModule, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, BOARD_TO_HOST, throttleRAF, updateForeignObject as updateForeignObject$1, BoardTransforms, Selection, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
+ import { MindLayoutType, AbstractNode, getAbstractLayout, isIndentedLayout, isStandardLayout, isLeftLayout, isRightLayout, getNonAbstractChildren, isTopLayout, isVerticalLogicLayout, isHorizontalLogicLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, ConnectingPosition, GlobalLayout } from '@plait/layouts';
6
+ import { getSizeByText, ROOT_DEFAULT_HEIGHT, TEXT_DEFAULT_HEIGHT, updateForeignObject, drawRichtext, createForeignObject, updateRichText, setFullSelectionAndFocus, getRichtextContentSize, hasEditableTarget, RichtextModule } from '@plait/richtext';
7
7
  import { fromEvent, Subject, timer } from 'rxjs';
8
8
  import { take, takeUntil, filter, debounceTime } from 'rxjs/operators';
9
9
  import { Node, Path as Path$1, Editor, Operation } from 'slate';
10
10
  import { pointsOnBezierCurves } from 'points-on-curve';
11
11
  import { isKeyHotkey } from 'is-hotkey';
12
12
  import * as i1 from '@angular/common';
13
- import { BrowserModule } from '@angular/platform-browser';
13
+ import { CommonModule } from '@angular/common';
14
14
 
15
15
  const ELEMENT_TO_NODE = new WeakMap();
16
16
 
@@ -56,27 +56,42 @@ const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;
56
56
  const ABSTRACT_HANDLE_LENGTH = 10;
57
57
  const ABSTRACT_HANDLE_MASK_WIDTH = 8;
58
58
 
59
- function getRectangleByNode(node) {
60
- const x = node.x + node.hGap;
61
- let y = node.y + node.vGap;
62
- const width = node.width - node.hGap * 2;
63
- const height = node.height - node.vGap * 2;
64
- return {
65
- x,
66
- y,
67
- width,
68
- height
69
- };
70
- }
71
- function hitMindElement(board, point, element) {
72
- const node = ELEMENT_TO_NODE.get(element);
73
- if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
74
- return true;
75
- }
76
- else {
77
- return false;
59
+ const MindNode = {
60
+ get(root, path) {
61
+ let node = root;
62
+ for (let i = 0; i < path.length; i++) {
63
+ const p = path[i];
64
+ if (!node || !node.children || !node.children[p]) {
65
+ throw new Error(`Cannot find a descendant at path [${path}]`);
66
+ }
67
+ node = node.children[p];
68
+ }
69
+ return node;
78
70
  }
79
- }
71
+ };
72
+
73
+ var LayoutDirection;
74
+ (function (LayoutDirection) {
75
+ LayoutDirection["top"] = "top";
76
+ LayoutDirection["right"] = "right";
77
+ LayoutDirection["bottom"] = "bottom";
78
+ LayoutDirection["left"] = "left";
79
+ })(LayoutDirection || (LayoutDirection = {}));
80
+ const LayoutDirectionsMap = {
81
+ [MindLayoutType.right]: [LayoutDirection.right],
82
+ [MindLayoutType.left]: [LayoutDirection.left],
83
+ [MindLayoutType.upward]: [LayoutDirection.top],
84
+ [MindLayoutType.downward]: [LayoutDirection.bottom],
85
+ [MindLayoutType.rightBottomIndented]: [LayoutDirection.right, LayoutDirection.bottom],
86
+ [MindLayoutType.rightTopIndented]: [LayoutDirection.right, LayoutDirection.top],
87
+ [MindLayoutType.leftBottomIndented]: [LayoutDirection.left, LayoutDirection.bottom],
88
+ [MindLayoutType.leftTopIndented]: [LayoutDirection.left, LayoutDirection.top]
89
+ };
90
+
91
+ var MindPointerType;
92
+ (function (MindPointerType) {
93
+ MindPointerType["mind"] = "mind";
94
+ })(MindPointerType || (MindPointerType = {}));
80
95
 
81
96
  /**
82
97
  * get correctly layout:
@@ -368,396 +383,172 @@ var MindElementShape;
368
383
  MindElementShape["underline"] = "underline";
369
384
  })(MindElementShape || (MindElementShape = {}));
370
385
 
371
- const MindNode = {
372
- get(root, path) {
373
- let node = root;
374
- for (let i = 0; i < path.length; i++) {
375
- const p = path[i];
376
- if (!node || !node.children || !node.children[p]) {
377
- throw new Error(`Cannot find a descendant at path [${path}]`);
378
- }
379
- node = node.children[p];
380
- }
381
- return node;
386
+ function getEmojisWidthHeight(board, element) {
387
+ const options = board.getMindOptions();
388
+ const count = element.data.emojis.length;
389
+ const fontSize = getEmojiFontSize(element);
390
+ return {
391
+ width: fontSize * count + count * 2 * options.emojiPadding + (count - 1) * options.spaceBetweenEmojis,
392
+ height: element.height
393
+ };
394
+ }
395
+ function getEmojiFontSize(element) {
396
+ if (PlaitMind.isMind(element)) {
397
+ return 18 + 2;
398
+ }
399
+ else {
400
+ return 14 + 2;
382
401
  }
383
- };
384
-
385
- var LayoutDirection;
386
- (function (LayoutDirection) {
387
- LayoutDirection["top"] = "top";
388
- LayoutDirection["right"] = "right";
389
- LayoutDirection["bottom"] = "bottom";
390
- LayoutDirection["left"] = "left";
391
- })(LayoutDirection || (LayoutDirection = {}));
392
- const LayoutDirectionsMap = {
393
- [MindLayoutType.right]: [LayoutDirection.right],
394
- [MindLayoutType.left]: [LayoutDirection.left],
395
- [MindLayoutType.upward]: [LayoutDirection.top],
396
- [MindLayoutType.downward]: [LayoutDirection.bottom],
397
- [MindLayoutType.rightBottomIndented]: [LayoutDirection.right, LayoutDirection.bottom],
398
- [MindLayoutType.rightTopIndented]: [LayoutDirection.right, LayoutDirection.top],
399
- [MindLayoutType.leftBottomIndented]: [LayoutDirection.left, LayoutDirection.bottom],
400
- [MindLayoutType.leftTopIndented]: [LayoutDirection.left, LayoutDirection.top]
401
- };
402
-
403
- var AbstractHandlePosition;
404
- (function (AbstractHandlePosition) {
405
- AbstractHandlePosition["start"] = "start";
406
- AbstractHandlePosition["end"] = "end";
407
- })(AbstractHandlePosition || (AbstractHandlePosition = {}));
408
- var AbstractResizeState;
409
- (function (AbstractResizeState) {
410
- AbstractResizeState["start"] = "start";
411
- AbstractResizeState["resizing"] = "resizing";
412
- AbstractResizeState["end"] = "end";
413
- })(AbstractResizeState || (AbstractResizeState = {}));
414
-
415
- function enterNodeEditing(element) {
416
- const component = ELEMENT_TO_COMPONENT.get(element);
417
- component.startEditText(false, false);
418
402
  }
419
403
 
420
- const separateChildren = (parentElement) => {
421
- const rightNodeCount = parentElement.rightNodeCount;
422
- const children = parentElement.children;
423
- let rightChildren = [], leftChildren = [];
424
- for (let i = 0; i < children.length; i++) {
425
- const child = children[i];
426
- if (AbstractNode.isAbstract(child) && child.end < rightNodeCount) {
427
- rightChildren.push(child);
428
- continue;
429
- }
430
- if (AbstractNode.isAbstract(child) && child.start >= rightNodeCount) {
431
- leftChildren.push(child);
432
- continue;
433
- }
434
- if (i < rightNodeCount) {
435
- rightChildren.push(child);
436
- }
437
- else {
438
- leftChildren.push(child);
439
- }
404
+ const NodeDefaultSpace = {
405
+ horizontal: {
406
+ nodeAndText: BASE * 3,
407
+ emojiAndText: BASE * 1.5
408
+ },
409
+ vertical: {
410
+ nodeAndText: BASE * 1.5
440
411
  }
441
- return { leftChildren, rightChildren };
442
412
  };
443
- const isSetAbstract = (element) => {
444
- const parent = MindElement.getParent(element);
445
- return !!getCorrespondingAbstract(parent, element);
413
+ const RootDefaultSpace = {
414
+ horizontal: {
415
+ nodeAndText: BASE * 4,
416
+ emojiAndText: BASE * 2
417
+ },
418
+ vertical: {
419
+ nodeAndText: BASE * 2
420
+ }
446
421
  };
447
- const canSetAbstract = (element) => {
448
- return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
422
+ const getHorizontalSpaceBetweenNodeAndText = (board, element) => {
423
+ const isMind = PlaitMind.isMind(element);
424
+ const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;
425
+ return nodeAndText;
449
426
  };
450
- const getCorrespondingAbstract = (parent, element) => {
451
- if (!parent)
452
- return undefined;
453
- const elementIndex = parent.children.indexOf(element);
454
- return parent.children.find(child => {
455
- return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
456
- });
427
+ const getVerticalSpaceBetweenNodeAndText = (element) => {
428
+ const isMind = PlaitMind.isMind(element);
429
+ const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;
430
+ return nodeAndText;
457
431
  };
458
- const getBehindAbstracts = (parent, element) => {
459
- const index = parent.children.indexOf(element);
460
- return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
432
+ const getSpaceEmojiAndText = (element) => {
433
+ const isMind = PlaitMind.isMind(element);
434
+ const emojiAndText = isMind ? RootDefaultSpace.horizontal.emojiAndText : NodeDefaultSpace.horizontal.emojiAndText;
435
+ return emojiAndText;
461
436
  };
462
- const getOverallAbstracts = (board, elements) => {
463
- const overallAbstracts = [];
464
- elements
465
- .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
466
- .forEach(value => {
467
- const parent = MindElement.getParent(value);
468
- const abstract = getCorrespondingAbstract(parent, value);
469
- if (abstract && overallAbstracts.indexOf(abstract) === -1) {
470
- const { start, end } = abstract;
471
- const parent = MindElement.getParent(value);
472
- const isOverall = parent.children.slice(start, end + 1).every(includedElement => elements.indexOf(includedElement) > -1);
473
- if (isOverall) {
474
- overallAbstracts.push(abstract);
475
- }
437
+ const NodeSpace = {
438
+ getNodeWidth(board, element) {
439
+ const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
440
+ if (MindElement.hasEmojis(element)) {
441
+ return (NodeSpace.getEmojiLeftSpace(board, element) +
442
+ getEmojisWidthHeight(board, element).width +
443
+ getSpaceEmojiAndText(element) +
444
+ element.width +
445
+ nodeAndText);
476
446
  }
477
- });
478
- return overallAbstracts;
447
+ return nodeAndText + element.width + nodeAndText;
448
+ },
449
+ getNodeHeight(board, element) {
450
+ const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
451
+ return nodeAndText + element.height + nodeAndText;
452
+ },
453
+ getTextLeftSpace(board, element) {
454
+ const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
455
+ if (MindElement.hasEmojis(element)) {
456
+ return NodeSpace.getEmojiLeftSpace(board, element) + getEmojisWidthHeight(board, element).width + getSpaceEmojiAndText(element);
457
+ }
458
+ else {
459
+ return nodeAndText;
460
+ }
461
+ },
462
+ getTextTopSpace(element) {
463
+ const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
464
+ return nodeAndText;
465
+ },
466
+ getEmojiLeftSpace(board, element) {
467
+ const options = board.getMindOptions();
468
+ const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
469
+ return nodeAndText - options.emojiPadding;
470
+ },
471
+ getEmojiTopSpace(element) {
472
+ const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
473
+ return nodeAndText;
474
+ }
479
475
  };
480
- const insertElementHandleAbstract = (board, path,
481
- //由此区分拖拽和新增到概要概括最后一个节点
482
- isExtendPreviousNode = true, abstractRefs = new Map()) => {
483
- const parent = PlaitNode.parent(board, path);
484
- const hasPreviousNode = path[path.length - 1] !== 0;
485
- let behindAbstracts;
486
- if (!hasPreviousNode) {
487
- behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));
476
+
477
+ function getRectangleByNode(node) {
478
+ const x = node.x + node.hGap;
479
+ let y = node.y + node.vGap;
480
+ const width = node.width - node.hGap * 2;
481
+ const height = node.height - node.vGap * 2;
482
+ return {
483
+ x,
484
+ y,
485
+ width,
486
+ height
487
+ };
488
+ }
489
+ function getRectangleByElement(board, originPoint, element) {
490
+ const nodeRectangle = {
491
+ x: originPoint[0],
492
+ y: originPoint[1],
493
+ width: NodeSpace.getNodeWidth(board, element),
494
+ height: NodeSpace.getNodeHeight(board, element)
495
+ };
496
+ return nodeRectangle;
497
+ }
498
+ function isHitMindElement(board, point, element) {
499
+ const node = MindElement.getNode(element);
500
+ if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
501
+ return true;
488
502
  }
489
503
  else {
490
- const selectedElement = PlaitNode.get(board, Path.previous(path));
491
- behindAbstracts = getBehindAbstracts(parent, selectedElement);
492
- }
493
- if (behindAbstracts.length) {
494
- behindAbstracts.forEach(abstract => {
495
- let newProperties = abstractRefs.get(abstract);
496
- if (!newProperties) {
497
- newProperties = { start: 0, end: 0 };
498
- abstractRefs.set(abstract, newProperties);
499
- }
500
- newProperties.start = newProperties.start + 1;
501
- newProperties.end = newProperties.end + 1;
502
- });
503
- }
504
- if (!hasPreviousNode) {
505
- return abstractRefs;
504
+ return false;
506
505
  }
507
- const selectedElement = PlaitNode.get(board, Path.previous(path));
508
- const correspondingAbstract = getCorrespondingAbstract(parent, selectedElement);
509
- const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;
510
- if (correspondingAbstract && !isDragToLast) {
511
- let newProperties = abstractRefs.get(correspondingAbstract);
512
- if (!newProperties) {
513
- newProperties = { start: 0, end: 0 };
514
- abstractRefs.set(correspondingAbstract, newProperties);
515
- }
516
- newProperties.end = newProperties.end + 1;
517
- }
518
- return abstractRefs;
519
- };
520
- const deleteElementHandleAbstract = (board, deletableElements, abstractRefs = new Map()) => {
521
- deletableElements.forEach(node => {
522
- if (!PlaitMind.isMind(node)) {
523
- const parent = PlaitNode.parent(board, PlaitBoard.findPath(board, node));
524
- const behindAbstracts = getBehindAbstracts(parent, node).filter(abstract => !deletableElements.includes(abstract));
525
- if (behindAbstracts.length) {
526
- behindAbstracts.forEach(abstract => {
527
- let newProperties = abstractRefs.get(abstract);
528
- if (!newProperties) {
529
- newProperties = { start: 0, end: 0 };
530
- abstractRefs.set(abstract, newProperties);
531
- }
532
- newProperties.start = newProperties.start - 1;
533
- newProperties.end = newProperties.end - 1;
534
- });
535
- }
536
- const correspondingAbstract = getCorrespondingAbstract(parent, node);
537
- if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
538
- let newProperties = abstractRefs.get(correspondingAbstract);
539
- if (!newProperties) {
540
- newProperties = { start: 0, end: 0 };
541
- abstractRefs.set(correspondingAbstract, newProperties);
542
- }
543
- newProperties.end = newProperties.end - 1;
544
- }
545
- }
546
- });
547
- return abstractRefs;
548
- };
549
-
550
- const setAbstractsByRefs = (board, abstractRefs) => {
551
- abstractRefs.forEach((newProperty, element) => {
552
- const start = element.start + newProperty.start;
553
- const end = element.end + newProperty.end;
554
- const path = PlaitBoard.findPath(board, element);
555
- if (start > end) {
556
- Transforms.removeNode(board, path);
557
- }
558
- else {
559
- Transforms.setNode(board, { start, end }, path);
560
- }
561
- });
562
- };
563
- const setAbstractByStandardLayout = (board, element) => {
564
- const rightNodeCount = element.rightNodeCount;
565
- const abstract = element.children.find(child => {
566
- return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
567
- });
568
- if (abstract) {
569
- const path = PlaitBoard.findPath(board, abstract);
570
- Transforms.setNode(board, { end: rightNodeCount - 1 }, path);
571
- }
572
- };
573
- const insertAbstract = (board, elements) => {
574
- let elementGroup = getFirstLevelElement(elements);
575
- const { parentElements, abstractIncludedGroups } = divideElementByParent(elementGroup);
576
- abstractIncludedGroups.forEach((group, index) => {
577
- const groupParent = parentElements[index];
578
- setAbstractByElements(board, groupParent, group);
579
- });
580
- };
581
- const setAbstractByElements = (board, groupParent, group) => {
582
- const indexArray = group.map(child => groupParent.children.indexOf(child)).sort((a, b) => a - b);
583
- const rightNodeCount = groupParent?.rightNodeCount;
584
- const start = indexArray[0], end = indexArray[indexArray.length - 1];
585
- if (isStandardLayout(MindQueries.getLayoutByElement(groupParent)) &&
586
- rightNodeCount &&
587
- start < rightNodeCount &&
588
- end >= rightNodeCount) {
589
- const childrenLength = groupParent.children.length;
590
- const path = [...PlaitBoard.findPath(board, groupParent), childrenLength];
591
- const leftChildren = indexArray.filter(index => index >= rightNodeCount);
592
- const rightChildren = indexArray.filter(index => index < rightNodeCount);
593
- insertAbstractNode(board, path, rightChildren[0], rightChildren[rightChildren.length - 1]);
594
- insertAbstractNode(board, Path.next(path), leftChildren[0], leftChildren[leftChildren.length - 1]);
595
- }
596
- else {
597
- const path = [...PlaitBoard.findPath(board, groupParent), groupParent.children.length];
598
- insertAbstractNode(board, path, start, end);
599
- }
600
- };
601
- const insertAbstractNode = (board, path, start, end) => {
602
- const mindElement = createMindElement('概要', 28, 20, {
603
- strokeColor: DefaultAbstractNodeStyle.strokeColor,
604
- strokeWidth: DefaultAbstractNodeStyle.branchWidth,
605
- branchColor: DefaultAbstractNodeStyle.branchColor,
606
- branchWidth: DefaultAbstractNodeStyle.branchWidth
607
- });
608
- mindElement.start = start;
609
- mindElement.end = end;
610
- Transforms.insertNode(board, mindElement, path);
611
- };
612
-
613
- const setLayout = (board, layout, path) => {
614
- correctLogicLayoutNode(board, layout, path);
615
- const element = PlaitNode.get(board, path);
616
- if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
617
- MindTransforms.setAbstractByStandardLayout(board, element);
618
- }
619
- Transforms.setNode(board, { layout }, path);
620
- };
621
- const correctLogicLayoutNode = (board, layout, path) => {
622
- const node = PlaitNode.get(board, path);
623
- if (node && layout) {
624
- node.children?.forEach((value, index) => {
625
- if (value.layout) {
626
- if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
627
- (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
628
- Transforms.setNode(board, { layout: null }, [...path, index]);
629
- }
630
- if (value.children?.length) {
631
- correctLogicLayoutNode(board, layout, [...path, index]);
632
- }
633
- }
634
- });
635
- }
636
- };
506
+ }
637
507
 
638
- const setTopic = (board, element, topic, width, height) => {
639
- const newElement = {
640
- data: { topic },
641
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
642
- height: height / board.viewport.zoom
643
- };
644
- if (MindElement.hasEmojis(element)) {
645
- newElement.data.emojis = element.data.emojis;
646
- }
647
- const path = PlaitBoard.findPath(board, element);
648
- Transforms.setNode(board, newElement, path);
649
- };
650
- const setTopicSize = (board, element, width, height) => {
651
- const newElement = {
652
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
653
- height: height / board.viewport.zoom
654
- };
655
- const path = PlaitBoard.findPath(board, element);
656
- Transforms.setNode(board, newElement, path);
657
- };
658
- const addEmoji = (board, element, emojiItem) => {
659
- const emojis = element.data.emojis || [];
660
- const newEmojis = [...emojis];
661
- newEmojis.push(emojiItem);
662
- const newElement = {
663
- data: { topic: element.data.topic, emojis: newEmojis }
664
- };
665
- const path = PlaitBoard.findPath(board, element);
666
- Transforms.setNode(board, newElement, path);
667
- };
668
- const removeEmoji = (board, element, emojiItem) => {
669
- const emojis = element.data.emojis.filter(value => value !== emojiItem);
670
- const newElement = {
671
- data: { topic: element.data.topic }
508
+ function getEmojiRectangle(board, element) {
509
+ let { x, y } = getRectangleByNode(MindElement.getNode(element));
510
+ x = x + NodeSpace.getEmojiLeftSpace(board, element);
511
+ const { width, height } = getEmojisWidthHeight(board, element);
512
+ return {
513
+ x,
514
+ y,
515
+ width,
516
+ height
672
517
  };
673
- if (emojis.length > 0) {
674
- newElement.data.emojis = emojis;
675
- }
676
- const path = PlaitBoard.findPath(board, element);
677
- Transforms.setNode(board, newElement, path);
678
- };
679
- const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
680
- const newElement = {
681
- data: { topic: element.data.topic }
518
+ }
519
+ function getEmojiForeignRectangle(board, element) {
520
+ let { x, y } = getRectangleByNode(MindElement.getNode(element));
521
+ x = x + NodeSpace.getEmojiLeftSpace(board, element);
522
+ const { width, height } = getEmojisWidthHeight(board, element);
523
+ return {
524
+ x,
525
+ y,
526
+ width,
527
+ height: height + NodeSpace.getEmojiTopSpace(element) * 2
682
528
  };
683
- const newEmojis = element.data.emojis.map(value => {
684
- if (value === oldEmoji) {
685
- return newEmoji;
686
- }
687
- return value;
688
- });
689
- newElement.data.emojis = newEmojis;
690
- const path = PlaitBoard.findPath(board, element);
691
- Transforms.setNode(board, newElement, path);
529
+ }
530
+ const isHitEmojis = (board, element, point) => {
531
+ return RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), getEmojiRectangle(board, element));
692
532
  };
693
533
 
694
- const MindTransforms = {
695
- setLayout,
696
- setTopic,
697
- setTopicSize,
698
- addEmoji,
699
- removeEmoji,
700
- replaceEmoji,
701
- insertAbstract,
702
- setAbstractsByRefs,
703
- setAbstractByStandardLayout
704
- };
534
+ function getTopicRectangleByNode(board, node) {
535
+ let nodeRectangle = getRectangleByNode(node);
536
+ return getTopicRectangleByElement(board, nodeRectangle, node.origin);
537
+ }
538
+ function getTopicRectangleByElement(board, nodeRectangle, element) {
539
+ const x = nodeRectangle.x + NodeSpace.getTextLeftSpace(board, element);
540
+ const y = nodeRectangle.y + NodeSpace.getTextTopSpace(element);
541
+ const width = Math.ceil(element.width);
542
+ const height = Math.ceil(element.height);
543
+ return { height, width, x, y };
544
+ }
705
545
 
706
- function findUpElement(element) {
707
- let branch;
708
- let root = element;
709
- let parent = MindElement.findParent(element);
710
- while (parent) {
711
- branch = root;
712
- root = parent;
713
- parent = MindElement.findParent(parent);
714
- }
715
- return { root, branch };
546
+ function enterNodeEditing(element) {
547
+ const component = PlaitElement.getComponent(element);
548
+ component.startEditText(false, false);
716
549
  }
717
- const getChildrenCount = (element) => {
718
- const count = element.children.reduce((p, c) => {
719
- return p + getChildrenCount(c);
720
- }, 0);
721
- return count + element.children.length;
722
- };
723
- const isChildElement = (origin, child) => {
724
- let parent = MindElement.findParent(child);
725
- while (parent) {
726
- if (parent === origin) {
727
- return true;
728
- }
729
- parent = MindElement.findParent(parent);
730
- }
731
- return false;
732
- };
733
- const getFirstLevelElement = (elements) => {
734
- let result = [];
735
- elements.forEach(element => {
736
- const isChild = elements.some(node => {
737
- return isChildElement(node, element);
738
- });
739
- if (!isChild) {
740
- result.push(element);
741
- }
742
- });
743
- return result;
744
- };
745
- const isChildRight = (node, child) => {
746
- return node.x < child.x;
747
- };
748
- const isChildUp = (node, child) => {
749
- return node.y > child.y;
750
- };
751
- const copyNewNode = (node) => {
752
- const newNode = { ...node };
753
- newNode.id = idCreator();
754
- newNode.children = [];
755
- for (const childNode of node.children) {
756
- newNode.children.push(copyNewNode(childNode));
757
- }
758
- return newNode;
759
- };
760
- const transformRootToNode = (board, node) => {
550
+
551
+ const adjustRootToNode = (board, node) => {
761
552
  const newNode = { ...node };
762
553
  delete newNode.isRoot;
763
554
  delete newNode.rightNodeCount;
@@ -771,13 +562,13 @@ const transformRootToNode = (board, node) => {
771
562
  }
772
563
  return newNode;
773
564
  };
774
- const transformAbstractToNode = (node) => {
565
+ const adjustAbstractToNode = (node) => {
775
566
  const newNode = { ...node };
776
567
  delete newNode.start;
777
568
  delete newNode.end;
778
569
  return newNode;
779
570
  };
780
- const transformNodeToRoot = (board, node) => {
571
+ const adjustNodeToRoot = (board, node) => {
781
572
  const newElement = { ...node };
782
573
  let text = Node.string(newElement.data.topic);
783
574
  if (!text) {
@@ -799,40 +590,14 @@ const transformNodeToRoot = (board, node) => {
799
590
  type: 'mindmap'
800
591
  };
801
592
  };
802
- const extractNodesText = (node) => {
803
- let str = '';
804
- if (node) {
805
- str += Node.string(node.data.topic.children[0]) + ' ';
806
- for (const childNode of node.children) {
807
- str += extractNodesText(childNode);
808
- }
809
- }
810
- return str;
811
- };
812
- const changeRightNodeCount = (board, parentPath, changeNumber) => {
813
- const _rightNodeCount = board.children[parentPath[0]].rightNodeCount;
814
- Transforms.setNode(board, {
815
- rightNodeCount: changeNumber >= 0
816
- ? _rightNodeCount + changeNumber
817
- : _rightNodeCount + changeNumber < 0
818
- ? 0
819
- : _rightNodeCount + changeNumber
820
- }, parentPath);
821
- };
822
- const shouldChangeRightNodeCount = (selectedElement) => {
823
- const parentElement = MindElement.findParent(selectedElement);
824
- if (parentElement) {
825
- const nodeIndex = parentElement.children.findIndex(item => item.id === selectedElement.id);
826
- if (parentElement.isRoot &&
827
- getRootLayout(parentElement) === MindLayoutType.standard &&
828
- parentElement.rightNodeCount &&
829
- nodeIndex <= parentElement.rightNodeCount - 1) {
830
- return true;
831
- }
832
- }
833
- return false;
593
+
594
+ const createEmptyMind = (board, point) => {
595
+ const element = createMindElement('', 0, 0, { layout: MindLayoutType.right });
596
+ const rootElement = adjustNodeToRoot(board, element);
597
+ rootElement.points = [point];
598
+ return rootElement;
834
599
  };
835
- const createDefaultMindMapElement = (point, rightNodeCount, layout) => {
600
+ const createDefaultMind = (point, rightNodeCount, layout) => {
836
601
  const root = createMindElement('思维导图', 72, ROOT_DEFAULT_HEIGHT, { shape: MindElementShape.roundRectangle, layout });
837
602
  root.rightNodeCount = rightNodeCount;
838
603
  root.isRoot = true;
@@ -881,6 +646,83 @@ const createMindElement = (text, width, height, options) => {
881
646
  }
882
647
  return newElement;
883
648
  };
649
+
650
+ const getChildrenCount = (element) => {
651
+ const count = element.children.reduce((p, c) => {
652
+ return p + getChildrenCount(c);
653
+ }, 0);
654
+ return count + element.children.length;
655
+ };
656
+ const isChildElement = (origin, child) => {
657
+ let parent = MindElement.findParent(child);
658
+ while (parent) {
659
+ if (parent === origin) {
660
+ return true;
661
+ }
662
+ parent = MindElement.findParent(parent);
663
+ }
664
+ return false;
665
+ };
666
+ const getFirstLevelElement = (elements) => {
667
+ let result = [];
668
+ elements.forEach(element => {
669
+ const isChild = elements.some(node => {
670
+ return isChildElement(node, element);
671
+ });
672
+ if (!isChild) {
673
+ result.push(element);
674
+ }
675
+ });
676
+ return result;
677
+ };
678
+ const isChildRight = (node, child) => {
679
+ return node.x < child.x;
680
+ };
681
+ const isChildUp = (node, child) => {
682
+ return node.y > child.y;
683
+ };
684
+ const copyNewNode = (node) => {
685
+ const newNode = { ...node };
686
+ newNode.id = idCreator();
687
+ newNode.children = [];
688
+ for (const childNode of node.children) {
689
+ newNode.children.push(copyNewNode(childNode));
690
+ }
691
+ return newNode;
692
+ };
693
+ const extractNodesText = (node) => {
694
+ let str = '';
695
+ if (node) {
696
+ str += Node.string(node.data.topic.children[0]) + ' ';
697
+ for (const childNode of node.children) {
698
+ str += extractNodesText(childNode);
699
+ }
700
+ }
701
+ return str;
702
+ };
703
+ const changeRightNodeCount = (board, parentPath, changeNumber) => {
704
+ const _rightNodeCount = board.children[parentPath[0]].rightNodeCount;
705
+ Transforms.setNode(board, {
706
+ rightNodeCount: changeNumber >= 0
707
+ ? _rightNodeCount + changeNumber
708
+ : _rightNodeCount + changeNumber < 0
709
+ ? 0
710
+ : _rightNodeCount + changeNumber
711
+ }, parentPath);
712
+ };
713
+ const isInRightBranchOfStandardLayout = (selectedElement) => {
714
+ const parentElement = MindElement.findParent(selectedElement);
715
+ if (parentElement) {
716
+ const nodeIndex = parentElement.children.findIndex(item => item.id === selectedElement.id);
717
+ if (parentElement.isRoot &&
718
+ getRootLayout(parentElement) === MindLayoutType.standard &&
719
+ parentElement.rightNodeCount &&
720
+ nodeIndex <= parentElement.rightNodeCount - 1) {
721
+ return true;
722
+ }
723
+ }
724
+ return false;
725
+ };
884
726
  // layoutLevel 用来表示插入兄弟节点还是子节点
885
727
  const insertMindElement = (board, inheritNode, path) => {
886
728
  let fill, strokeColor, strokeWidth, shape = MindElementShape.roundRectangle;
@@ -905,25 +747,6 @@ const findLastChild = (child) => {
905
747
  }
906
748
  return result;
907
749
  };
908
- const deleteSelectedELements = (board, selectedElements) => {
909
- const deletableElements = getFirstLevelElement(selectedElements).reverse();
910
- const abstractRefs = deleteElementHandleAbstract(board, deletableElements);
911
- MindTransforms.setAbstractsByRefs(board, abstractRefs);
912
- //翻转,从下到上修改,防止找不到 path
913
- deletableElements
914
- .map(element => {
915
- const path = PlaitBoard.findPath(board, element);
916
- return () => {
917
- if (shouldChangeRightNodeCount(element)) {
918
- changeRightNodeCount(board, path.slice(0, 1), -1);
919
- }
920
- Transforms.removeNode(board, path);
921
- };
922
- })
923
- .forEach(action => {
924
- action();
925
- });
926
- };
927
750
  const divideElementByParent = (elements) => {
928
751
  const abstractIncludedGroups = [];
929
752
  const parentElements = [];
@@ -1019,466 +842,123 @@ function isVirtualKey(e) {
1019
842
  return isCapsLock || isMod || isAlt || isArrow || isShift || isTab || isEsc || isF;
1020
843
  }
1021
844
 
1022
- function drawLink(board, node, child, defaultStroke = null, isHorizontal = true, needDrawUnderline = true) {
1023
- let beginX, beginY, endX, endY, beginNode = node, endNode = child;
1024
- const layout = MindQueries.getCorrectLayoutByElement(board, node.origin);
1025
- if (isHorizontal) {
1026
- if (!isChildRight(node, child)) {
1027
- beginNode = child;
1028
- endNode = node;
1029
- }
1030
- beginX = beginNode.x + beginNode.width - beginNode.hGap;
1031
- beginY = beginNode.y + beginNode.height / 2;
1032
- endX = endNode.x + endNode.hGap;
1033
- endY = endNode.y + endNode.height / 2;
1034
- if (node.parent &&
1035
- isIndentedLayout(MindQueries.getLayoutByElement(node.parent?.origin)) &&
1036
- getShapeByElement(board, node.origin) === MindElementShape.underline) {
1037
- if (isChildRight(node, child)) {
1038
- beginY = node.y + node.height - node.vGap;
1039
- }
1040
- else {
1041
- endY = node.y + node.height - node.vGap;
1042
- }
1043
- }
845
+ const IS_DRAGGING = new WeakMap();
846
+ const addActiveOnDragOrigin = (activeElement, isOrigin = true) => {
847
+ const activeComponent = PlaitElement.getComponent(activeElement);
848
+ if (isOrigin) {
849
+ activeComponent.g.classList.add('dragging-origin');
1044
850
  }
1045
851
  else {
1046
- if (node.y > child.y) {
1047
- beginNode = child;
1048
- endNode = node;
1049
- }
1050
- beginX = beginNode.x + beginNode.width / 2;
1051
- beginY = beginNode.y + beginNode.height - beginNode.vGap;
1052
- endX = endNode.x + endNode.width / 2;
1053
- endY = endNode.y + endNode.vGap;
852
+ activeComponent.g.classList.add('dragging-child');
853
+ }
854
+ !activeElement.isCollapsed &&
855
+ activeElement.children.forEach(child => {
856
+ addActiveOnDragOrigin(child, false);
857
+ });
858
+ };
859
+ const removeActiveOnDragOrigin = (activeElement, isOrigin = true) => {
860
+ const activeComponent = PlaitElement.getComponent(activeElement);
861
+ if (isOrigin) {
862
+ activeComponent.g.classList.remove('dragging-origin');
1054
863
  }
1055
- const stroke = defaultStroke || getBranchColorByMindElement(board, child.origin);
1056
- const strokeWidth = child.origin.branchWidth ? child.origin.branchWidth : STROKE_WIDTH;
1057
- if (endNode.origin.isRoot) {
1058
- if (layout === MindLayoutType.left || isStandardLayout(layout)) {
1059
- endX -= strokeWidth;
864
+ else {
865
+ activeComponent.g.classList.remove('dragging-child');
866
+ }
867
+ !activeElement.isCollapsed &&
868
+ activeElement.children.forEach(child => {
869
+ removeActiveOnDragOrigin(child, false);
870
+ });
871
+ };
872
+ const isDragging = (board) => {
873
+ return !!IS_DRAGGING.get(board);
874
+ };
875
+ const setIsDragging = (board, state) => {
876
+ IS_DRAGGING.set(board, state);
877
+ };
878
+
879
+ /**
880
+ *
881
+ * @param targetNode
882
+ * @param centerPoint
883
+ * @returns DetectResult[] | null
884
+ */
885
+ const directionCorrector = (board, node, detectResults) => {
886
+ if (!node.origin.isRoot && !AbstractNode.isAbstract(node.origin)) {
887
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, node?.parent.origin);
888
+ if (isStandardLayout(parentLayout)) {
889
+ const idx = node.parent.children.findIndex(x => x === node);
890
+ const isLeft = idx >= (node.parent.origin.rightNodeCount || 0);
891
+ return getAllowedDirection(detectResults, [isLeft ? 'right' : 'left']);
1060
892
  }
1061
- if (layout === MindLayoutType.upward) {
1062
- endY -= strokeWidth;
893
+ if (isLeftLayout(parentLayout)) {
894
+ return getAllowedDirection(detectResults, ['right']);
1063
895
  }
1064
- }
1065
- if (beginNode.origin.isRoot) {
1066
- if (layout === MindLayoutType.right || isStandardLayout(layout)) {
1067
- beginX += strokeWidth;
896
+ if (isRightLayout(parentLayout)) {
897
+ return getAllowedDirection(detectResults, ['left']);
1068
898
  }
1069
- if (layout === MindLayoutType.downward) {
1070
- beginY += strokeWidth;
899
+ if (parentLayout === MindLayoutType.upward) {
900
+ return getAllowedDirection(detectResults, ['bottom']);
1071
901
  }
1072
- }
1073
- if (isHorizontal) {
1074
- let curve = [
1075
- [beginX, beginY],
1076
- [beginX + (beginNode.hGap + endNode.hGap) / 3, beginY],
1077
- [endX - (beginNode.hGap + endNode.hGap) / 2, endY],
1078
- [endX, endY]
1079
- ];
1080
- const shape = getShapeByElement(board, child.origin);
1081
- if (!node.origin.isRoot) {
1082
- if (node.x > child.x) {
1083
- curve = [
1084
- [beginX, beginY],
1085
- [beginX + (beginNode.hGap + endNode.hGap) / 3, beginY],
1086
- [endX - (beginNode.hGap + endNode.hGap) / 2, endY],
1087
- [endX - 12, endY]
1088
- ];
1089
- const line = [
1090
- [endX - 12, endY],
1091
- [endX - 12, endY],
1092
- [endX, endY]
1093
- ];
1094
- curve = [...curve, ...line];
1095
- }
1096
- else {
1097
- curve = [
1098
- [beginX + 12, beginY],
1099
- [beginX + (beginNode.hGap + endNode.hGap) / 2, beginY],
1100
- [endX - (beginNode.hGap + endNode.hGap) / 3, endY],
1101
- [endX, endY]
1102
- ];
1103
- const line = [
1104
- [beginX, beginY],
1105
- [beginX + 12, beginY],
1106
- [beginX + 12, beginY]
1107
- ];
1108
- curve = [...line, ...curve];
1109
- }
1110
- }
1111
- if (needDrawUnderline && shape === MindElementShape.underline) {
1112
- if (child.left) {
1113
- const underline = [
1114
- [beginX - (beginNode.width - beginNode.hGap * 2), beginY],
1115
- [beginX - (beginNode.width - beginNode.hGap * 2), beginY],
1116
- [beginX - (beginNode.width - beginNode.hGap * 2), beginY]
1117
- ];
1118
- curve = [...underline, ...curve];
1119
- }
1120
- else {
1121
- const underline = [
1122
- [endX + (endNode.width - endNode.hGap * 2), endY],
1123
- [endX + (endNode.width - endNode.hGap * 2), endY],
1124
- [endX + (endNode.width - endNode.hGap * 2), endY]
1125
- ];
1126
- curve = [...curve, ...underline];
1127
- }
902
+ if (parentLayout === MindLayoutType.downward) {
903
+ return getAllowedDirection(detectResults, ['top']);
1128
904
  }
1129
- const points = pointsOnBezierCurves(curve);
1130
- return PlaitBoard.getRoughSVG(board).curve(points, { stroke, strokeWidth });
1131
905
  }
1132
906
  else {
1133
- let curve = [
1134
- [beginX, beginY],
1135
- [beginX, beginY + (beginNode.vGap + endNode.vGap) / 2],
1136
- [endX, endY - (beginNode.vGap + endNode.vGap) / 2],
1137
- [endX, endY]
1138
- ];
1139
- if (!node.origin.isRoot) {
1140
- if (isTopLayout(layout)) {
1141
- curve = [
1142
- [beginX, beginY],
1143
- [beginX, beginY + (beginNode.vGap + endNode.vGap) / 2],
1144
- [endX, endY - (beginNode.vGap + endNode.vGap) / 2],
1145
- [endX, endY - 12]
1146
- ];
1147
- const line = [
1148
- [endX, endY - 12],
1149
- [endX, endY - 12],
1150
- [endX, endY]
1151
- ];
1152
- curve = [...curve, ...line];
1153
- }
1154
- else {
1155
- curve = [
1156
- [beginX, beginY + 12],
1157
- [beginX, beginY + (beginNode.vGap + endNode.vGap) / 2],
1158
- [endX, endY - (beginNode.vGap + endNode.vGap) / 2],
1159
- [endX, endY]
1160
- ];
1161
- const line = [
1162
- [beginX, beginY],
1163
- [beginX, beginY + 12],
1164
- [beginX, beginY + 12]
1165
- ];
1166
- curve = [...line, ...curve];
1167
- }
1168
- }
1169
- const points = pointsOnBezierCurves(curve);
1170
- return PlaitBoard.getRoughSVG(board).curve(points, { stroke, strokeWidth });
1171
- }
1172
- }
1173
-
1174
- const drawPlaceholderDropNodeG = (board, dropTarget, fakeDropNodeG) => {
1175
- const targetComponent = PlaitElement.getComponent(dropTarget.target);
1176
- const targetRect = getRectangleByNode(targetComponent.node);
1177
- if (dropTarget.detectResult && ['right', 'left'].includes(dropTarget.detectResult)) {
1178
- drawStraightDropNodeG(board, targetRect, dropTarget.detectResult, targetComponent, fakeDropNodeG);
1179
- }
1180
- const targetParent = MindElement.findParent(targetComponent.element);
1181
- if (targetParent && dropTarget.detectResult && ['top', 'bottom'].includes(dropTarget.detectResult)) {
1182
- const parentComponent = PlaitElement.getComponent(targetParent);
1183
- const targetIndex = parentComponent.node.origin.children.indexOf(targetComponent.node.origin);
1184
- drawCurvePlaceholderDropNodeG(board, targetRect, dropTarget.detectResult, targetIndex, targetComponent, parentComponent, fakeDropNodeG);
1185
- }
1186
- };
1187
- const drawCurvePlaceholderDropNodeG = (board, targetRect, detectResult, targetIndex, targetComponent, parentComponent, fakeDropNodeG) => {
1188
- const parentNodeLayout = MindQueries.getCorrectLayoutByElement(board, parentComponent.node.origin);
1189
- const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.parent.origin);
1190
- const strokeWidth = targetComponent.node.origin.branchWidth ? targetComponent.node.origin.branchWidth : STROKE_WIDTH;
1191
- let fakeX = targetComponent.node.x, fakeY = targetRect.y - 30, fakeRectangleStartX = targetRect.x, fakeRectangleEndX = targetRect.x + 30, fakeRectangleStartY = fakeY, fakeRectangleEndY = fakeRectangleStartY + 12, width = 30;
1192
- if (isLeftLayout(layout)) {
1193
- fakeX = targetComponent.node.x + targetComponent.node.width - 30;
1194
- fakeRectangleStartX = targetRect.x + targetRect.width - 30;
1195
- fakeRectangleEndX = targetRect.x + targetRect.width;
1196
- }
1197
- if (isHorizontalLogicLayout(parentNodeLayout)) {
1198
- fakeY = getHorizontalFakeY(detectResult, targetIndex, parentComponent.node, targetRect, layout, fakeY);
1199
- if (isStandardLayout(parentNodeLayout)) {
1200
- const rightNodeCount = parentComponent.node.origin.rightNodeCount || 0;
1201
- const idx = parentComponent.node.children.findIndex(x => x === targetComponent.node);
1202
- const isLeft = idx >= rightNodeCount;
1203
- // 标准布局的左,需要调整 x
1204
- if (isLeft) {
1205
- fakeX = targetComponent.node.x + targetComponent.node.width - 30;
1206
- fakeRectangleStartX = targetRect.x + targetRect.width - 30;
1207
- fakeRectangleEndX = targetRect.x + targetRect.width;
1208
- }
1209
- const isLeftFirst = idx === rightNodeCount;
1210
- const isRightLast = idx === rightNodeCount - 1;
1211
- // 拖拽至左第一个节点的情况
1212
- if (detectResult === 'top' && isLeftFirst) {
1213
- fakeY = targetRect.y - targetRect.height;
1214
- }
1215
- if (detectResult === 'bottom' && isRightLast) {
1216
- fakeY = targetRect.y + targetRect.height + 30;
1217
- }
1218
- }
1219
- fakeRectangleStartY = fakeY;
1220
- fakeRectangleEndY = fakeRectangleStartY + 12;
1221
- }
1222
- if (isVerticalLogicLayout(layout)) {
1223
- parentComponent = targetComponent;
1224
- targetComponent = PlaitElement.getComponent(MindElement.getParent(targetComponent.element));
1225
- fakeX = parentComponent.node.x;
1226
- width = parentComponent.node.width;
1227
- const vGap = BASE * 6 + strokeWidth;
1228
- if (isTopLayout(layout) && detectResult === 'top') {
1229
- fakeY = targetRect.y - vGap;
1230
- fakeRectangleStartY = fakeY - vGap + strokeWidth;
1231
- }
1232
- if (isBottomLayout(layout) && detectResult === 'bottom') {
1233
- fakeY = targetRect.y + targetRect.height + vGap;
1234
- fakeRectangleStartY = fakeY + vGap - strokeWidth;
1235
- }
1236
- fakeRectangleStartX = fakeX + Math.ceil(parentComponent.node.width / 2) - parentComponent.node.hGap - Math.ceil(strokeWidth / 2);
1237
- fakeRectangleEndX = fakeRectangleStartX + 30;
1238
- fakeRectangleEndY = fakeRectangleStartY + 12;
1239
- }
1240
- if (isIndentedLayout(layout)) {
1241
- // 偏移一个 Gap
907
+ const layout = MindQueries.getCorrectLayoutByElement(board, node?.origin);
908
+ if (isStandardLayout(layout)) {
909
+ return getAllowedDirection(detectResults, ['top', 'bottom']);
910
+ }
911
+ if (layout === MindLayoutType.upward) {
912
+ return getAllowedDirection(detectResults, ['left', 'right', 'bottom']);
913
+ }
914
+ if (layout === MindLayoutType.downward) {
915
+ return getAllowedDirection(detectResults, ['left', 'right', 'top']);
916
+ }
1242
917
  if (isLeftLayout(layout)) {
1243
- fakeX -= BASE * 4;
918
+ return getAllowedDirection(detectResults, ['right', 'top', 'bottom']);
1244
919
  }
1245
920
  if (isRightLayout(layout)) {
1246
- fakeX += BASE * 4;
1247
- }
1248
- if (isTopLayout(layout)) {
1249
- if (detectResult === 'top') {
1250
- const isLastNode = targetIndex === parentComponent.node.origin.children.length - 1;
1251
- if (isLastNode) {
1252
- fakeY = targetRect.y - targetRect.height - BASE;
1253
- }
1254
- else {
1255
- const nextComponent = PlaitElement.getComponent(parentComponent.node.origin.children[targetIndex + 1]);
1256
- const nextRect = getRectangleByNode(nextComponent.node);
1257
- fakeY = targetRect.y - Math.abs((nextRect.y + nextRect.height - targetRect.y) / 2);
1258
- }
1259
- }
1260
- if (detectResult === 'bottom') {
1261
- const isFirstNode = targetIndex === 0;
1262
- if (isFirstNode) {
1263
- const parentRect = getRectangleByNode(parentComponent.node);
1264
- fakeY = parentRect.y - parentRect.height / 2 - BASE;
1265
- }
1266
- else {
1267
- const previousComponent = PlaitElement.getComponent(parentComponent.node.origin.children[targetIndex + 1]);
1268
- const previousRect = getRectangleByNode(previousComponent.node);
1269
- fakeY = previousRect.y - Math.abs((targetRect.y + targetRect.height - previousRect.y) / 2);
1270
- }
1271
- }
921
+ return getAllowedDirection(detectResults, ['left', 'top', 'bottom']);
1272
922
  }
1273
- fakeRectangleStartX = fakeX;
1274
- fakeRectangleEndX = fakeRectangleStartX + 30;
1275
- fakeRectangleStartY = fakeY;
1276
- fakeRectangleEndY = fakeRectangleStartY + 12;
1277
923
  }
1278
- // 构造一条曲线
1279
- const fakeNode = { ...targetComponent.node, x: fakeX, y: fakeY, width, height: 12 };
1280
- const linkSVGG = isIndentedLayout(layout)
1281
- ? drawIndentedLink(board, parentComponent.node, fakeNode, PRIMARY_COLOR, false)
1282
- : drawLink(board, parentComponent.node, fakeNode, PRIMARY_COLOR, isHorizontalLayout(layout), false);
1283
- // 构造一个矩形框坐标
1284
- const fakeRectangleG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), fakeRectangleStartX, fakeRectangleStartY, fakeRectangleEndX, fakeRectangleEndY, {
1285
- stroke: PRIMARY_COLOR,
1286
- strokeWidth: 2,
1287
- fill: PRIMARY_COLOR,
1288
- fillStyle: 'solid'
924
+ return null;
925
+ };
926
+ const getAllowedDirection = (detectResults, illegalDirections) => {
927
+ const directions = detectResults;
928
+ illegalDirections.forEach(item => {
929
+ const bottomDirectionIndex = directions.findIndex(direction => direction === item);
930
+ if (bottomDirectionIndex !== -1) {
931
+ directions.splice(bottomDirectionIndex, 1);
932
+ }
1289
933
  });
1290
- fakeDropNodeG?.appendChild(linkSVGG);
1291
- fakeDropNodeG?.appendChild(fakeRectangleG);
934
+ return directions.length ? directions : null;
1292
935
  };
1293
- const drawStraightDropNodeG = (board, targetRect, detectResult, targetComponent, fakeDropNodeG) => {
1294
- const { x, y, width, height } = targetRect;
1295
- const lineLength = 40;
1296
- let startLinePoint = x + width;
1297
- let endLinePoint = x + width + lineLength;
1298
- let startRectanglePointX = x + width + lineLength;
1299
- let endRectanglePointX = x + lineLength + width + 30;
1300
- let startRectanglePointY = y + height / 2 - 6;
1301
- let endRectanglePointY = y + height / 2 - 6 + 12;
1302
- if (detectResult === 'left') {
1303
- startLinePoint = x - lineLength;
1304
- endLinePoint = x;
1305
- startRectanglePointX = x - lineLength - 30;
1306
- endRectanglePointX = x - lineLength;
1307
- }
1308
- let fakeY = targetComponent.node.y;
1309
- let fakeX = targetRect.x;
1310
- const strokeWidth = targetComponent.node.origin.branchWidth ? targetComponent.node.origin.branchWidth : STROKE_WIDTH;
1311
- const pointOptions = {
1312
- fakeX,
1313
- fakeY,
1314
- x,
1315
- y,
1316
- width,
1317
- height,
1318
- strokeWidth
1319
- };
1320
- const parentLayout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1321
- const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1322
- if (!isMixedLayout(parentLayout, layout)) {
1323
- // 构造一条直线
1324
- let linePoints = [
1325
- [startLinePoint, y + height / 2],
1326
- [endLinePoint, y + height / 2]
1327
- ];
1328
- if (isIndentedLayout(parentLayout)) {
1329
- const fakePoint = getIndentedFakePoint(parentLayout, pointOptions);
1330
- drawIndentNodeG(board, fakeDropNodeG, fakePoint, targetComponent.node);
936
+ const detectDropTarget = (board, detectPoint, dropTarget, activeElements) => {
937
+ let detectResult = null;
938
+ depthFirstRecursion(board, element => {
939
+ if (!MindElement.isMindElement(board, element) || detectResult) {
1331
940
  return;
1332
941
  }
1333
- else if (isVerticalLogicLayout(parentLayout)) {
1334
- if (!targetComponent.node.origin.isRoot) {
1335
- /**
1336
- * 计算逻辑:
1337
- * 1. 移动到左侧:当前节点 startX - 偏移值,偏移值计算如下:
1338
- * a. 第一个节点: 固定值(来源于 getMainAxle,第二级节点:BASE * 8,其他 BASE * 3 + strokeWidth / 2);
1339
- * b. 第二个节点到最后一个节点之间:上一个节点到当前节点间距的一半((当前节点 startX - 上一个节点的 endX) / 2),endX = 当前节点的 startX + width;
1340
- * 2. 移动到右侧:当前节点 x + width + 偏移值,偏移值计算如下:
1341
- * a. 第二个节点到最后一个节点之间的右侧:当前节点到下一个节点间距的一半((下一个节点 startX - 当前节点的 endX) / 2),endX = 当前节点的 startX + width;
1342
- * b. 最后一个节点的右侧:固定值(来源于 getMainAxle,第二级节点:BASE * 8,其他 BASE * 3 + strokeWidth / 2);
1343
- */
1344
- fakeY = targetComponent.node.y;
1345
- const parentComponent = PlaitElement.getComponent(MindElement.getParent(targetComponent.element));
1346
- const targetIndex = parentComponent.node.origin.children.indexOf(targetComponent.node.origin);
1347
- if (detectResult === 'left') {
1348
- let offsetX = 0;
1349
- const isFirstNode = targetIndex === 0;
1350
- if (isFirstNode) {
1351
- offsetX = parentComponent.node.origin.isRoot ? BASE * 8 : BASE * 3 + strokeWidth / 2;
1352
- }
1353
- else {
1354
- const previousComponent = PlaitElement.getComponent(parentComponent.node.origin.children[targetIndex - 1]);
1355
- const previousRect = getRectangleByNode(previousComponent.node);
1356
- const space = targetRect.x - (previousRect.x + previousRect.width);
1357
- offsetX = space / 2;
1358
- }
1359
- fakeX = targetRect.x - offsetX - width / 2 - Math.ceil(strokeWidth / 2);
1360
- }
1361
- if (detectResult === 'right') {
1362
- let offsetX = 0;
1363
- const isLastNode = targetIndex === parentComponent.node.origin.children.length - 1;
1364
- if (isLastNode) {
1365
- offsetX = parentComponent.node.origin.isRoot ? BASE * 8 : BASE * 3 + strokeWidth / 2;
1366
- }
1367
- else {
1368
- const nextComponent = PlaitElement.getComponent(parentComponent.node.origin.children[targetIndex + 1]);
1369
- const nextRect = getRectangleByNode(nextComponent.node);
1370
- const space = nextRect.x - (targetRect.x + targetRect.width);
1371
- offsetX = space / 2;
1372
- }
1373
- fakeX = targetRect.x + width + offsetX - width / 2 - Math.ceil(strokeWidth / 2);
1374
- }
1375
- startRectanglePointX = fakeX;
1376
- if (isTopLayout(parentLayout)) {
1377
- // 因为矩形是从左上角为起点向下画的,所以需要向上偏移一个矩形的高度(-12)
1378
- startRectanglePointY = fakeY + height + targetComponent.node.vGap - 12;
1379
- }
1380
- if (isBottomLayout(parentLayout)) {
1381
- startRectanglePointY = fakeY + targetComponent.node.vGap;
1382
- }
1383
- endRectanglePointX = startRectanglePointX + 30;
1384
- endRectanglePointY = startRectanglePointY + 12;
1385
- const fakeNode = { ...targetComponent.node, x: fakeX, y: fakeY, width: 30 };
1386
- const linkSVGG = drawLink(board, parentComponent.node, fakeNode, PRIMARY_COLOR, false, false);
1387
- fakeDropNodeG?.appendChild(linkSVGG);
1388
- }
942
+ const node = MindElement.getNode(element);
943
+ const directions = directionDetector(node, detectPoint);
944
+ if (directions) {
945
+ detectResult = directionCorrector(board, node, directions);
946
+ }
947
+ dropTarget = null;
948
+ const isValid = activeElements.every(element => isValidTarget(element, node.origin));
949
+ if (detectResult && isValid) {
950
+ dropTarget = { target: node.origin, detectResult: detectResult[0] };
951
+ }
952
+ }, node => {
953
+ if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
954
+ return true;
1389
955
  }
1390
956
  else {
1391
- let linkSVGG = PlaitBoard.getRoughSVG(board).linearPath(linePoints, { stroke: PRIMARY_COLOR, strokeWidth });
1392
- fakeDropNodeG?.appendChild(linkSVGG);
957
+ return false;
1393
958
  }
1394
- // 构造一个矩形框坐标
1395
- let fakeRectangleG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), startRectanglePointX, startRectanglePointY, endRectanglePointX, endRectanglePointY, {
1396
- stroke: PRIMARY_COLOR,
1397
- strokeWidth: 2,
1398
- fill: PRIMARY_COLOR,
1399
- fillStyle: 'solid'
1400
- });
1401
- fakeDropNodeG?.appendChild(fakeRectangleG);
1402
- }
1403
- else {
1404
- // 混合布局画线逻辑
1405
- if (isHorizontalLogicLayout(parentLayout)) {
1406
- if (isIndentedLayout(layout)) {
1407
- const fakePoint = getIndentedFakePoint(layout, pointOptions);
1408
- drawIndentNodeG(board, fakeDropNodeG, fakePoint, targetComponent.node);
1409
- return;
1410
- }
1411
- }
1412
- }
1413
- };
1414
- const getHorizontalFakeY = (detectResult, targetIndex, parentNode, targetRect, layout, fakeY) => {
1415
- const childrenLength = getNonAbstractChildren(parentNode).length;
1416
- if (detectResult === 'top') {
1417
- if (targetIndex === 0 && isTopLayout(layout)) {
1418
- fakeY = targetRect.y + targetRect.height;
1419
- }
1420
- if (targetIndex > 0) {
1421
- const previousComponent = PlaitElement.getComponent(parentNode.origin.children[targetIndex - 1]);
1422
- const previousRect = getRectangleByNode(previousComponent.node);
1423
- const topY = previousRect.y + previousRect.height;
1424
- fakeY = topY + (targetRect.y - topY) / 5;
1425
- }
1426
- }
1427
- if (detectResult === 'bottom') {
1428
- fakeY = targetRect.y + targetRect.height + 30;
1429
- if (targetIndex < childrenLength - 1) {
1430
- const nextComponent = PlaitElement.getComponent(parentNode.origin.children[targetIndex + 1]);
1431
- const nextRect = getRectangleByNode(nextComponent.node);
1432
- const topY = targetRect.y + targetRect.height;
1433
- fakeY = topY + (nextRect.y - topY) / 5;
1434
- }
1435
- if (targetIndex === childrenLength - 1) {
1436
- fakeY = targetRect.y + targetRect.height + 30;
1437
- }
1438
- }
1439
- return fakeY;
1440
- };
1441
- const getIndentedFakePoint = (layout, pointOptions) => {
1442
- let { fakeX, fakeY, x, y, width, height, strokeWidth } = pointOptions;
1443
- const hGap = BASE * 4;
1444
- const vGap = BASE * 6;
1445
- const offsetX = hGap + width / 2 + strokeWidth;
1446
- const offsetY = vGap + height / 2 + strokeWidth;
1447
- if (isLeftLayout(layout)) {
1448
- fakeX = x - offsetX;
1449
- }
1450
- if (isRightLayout(layout)) {
1451
- fakeX = x + offsetX;
1452
- }
1453
- if (isTopLayout(layout)) {
1454
- fakeY = y - offsetY;
1455
- }
1456
- if (isBottomLayout(layout)) {
1457
- fakeY = y + height + offsetY;
1458
- }
1459
- return { fakeX, fakeY };
1460
- };
1461
- const drawIndentNodeG = (board, fakeDropNodeG, fakePoint, node) => {
1462
- const { fakeX, fakeY } = fakePoint;
1463
- const fakeNode = { ...node, x: fakeX, y: fakeY, width: 30, height: 12 };
1464
- const linkSVGG = drawIndentedLink(board, node, fakeNode, PRIMARY_COLOR, false);
1465
- const startRectanglePointX = fakeX, startRectanglePointY = fakeY, endRectanglePointX = fakeX + 30, endRectanglePointY = fakeY + 12;
1466
- const fakeRectangleG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), startRectanglePointX, startRectanglePointY, endRectanglePointX, endRectanglePointY, {
1467
- stroke: PRIMARY_COLOR,
1468
- strokeWidth: 2,
1469
- fill: PRIMARY_COLOR,
1470
- fillStyle: 'solid'
1471
959
  });
1472
- fakeDropNodeG?.appendChild(linkSVGG);
1473
- fakeDropNodeG?.appendChild(fakeRectangleG);
960
+ return dropTarget;
1474
961
  };
1475
-
1476
- /**
1477
- *
1478
- * @param targetNode
1479
- * @param centerPoint
1480
- * @returns DetectResult[] | null
1481
- */
1482
962
  const directionDetector = (targetNode, centerPoint) => {
1483
963
  const { x, y, width, height } = getRectangleByNode(targetNode);
1484
964
  const yCenter = y + height / 2;
@@ -1527,59 +1007,6 @@ const directionDetector = (targetNode, centerPoint) => {
1527
1007
  }
1528
1008
  return null;
1529
1009
  };
1530
-
1531
- const directionCorrector = (board, node, detectResults) => {
1532
- if (!node.origin.isRoot && !AbstractNode.isAbstract(node.origin)) {
1533
- const parentLayout = MindQueries.getCorrectLayoutByElement(board, node?.parent.origin);
1534
- if (isStandardLayout(parentLayout)) {
1535
- const idx = node.parent.children.findIndex(x => x === node);
1536
- const isLeft = idx >= (node.parent.origin.rightNodeCount || 0);
1537
- return getAllowedDirection(detectResults, [isLeft ? 'right' : 'left']);
1538
- }
1539
- if (isLeftLayout(parentLayout)) {
1540
- return getAllowedDirection(detectResults, ['right']);
1541
- }
1542
- if (isRightLayout(parentLayout)) {
1543
- return getAllowedDirection(detectResults, ['left']);
1544
- }
1545
- if (parentLayout === MindLayoutType.upward) {
1546
- return getAllowedDirection(detectResults, ['bottom']);
1547
- }
1548
- if (parentLayout === MindLayoutType.downward) {
1549
- return getAllowedDirection(detectResults, ['top']);
1550
- }
1551
- }
1552
- else {
1553
- const layout = MindQueries.getCorrectLayoutByElement(board, node?.origin);
1554
- if (isStandardLayout(layout)) {
1555
- return getAllowedDirection(detectResults, ['top', 'bottom']);
1556
- }
1557
- if (isTopLayout(layout)) {
1558
- return getAllowedDirection(detectResults, ['left', 'right', 'bottom']);
1559
- }
1560
- if (isBottomLayout(layout)) {
1561
- return getAllowedDirection(detectResults, ['left', 'right', 'top']);
1562
- }
1563
- if (layout === MindLayoutType.left) {
1564
- return getAllowedDirection(detectResults, ['right', 'top', 'bottom']);
1565
- }
1566
- if (layout === MindLayoutType.right) {
1567
- return getAllowedDirection(detectResults, ['left', 'top', 'bottom']);
1568
- }
1569
- }
1570
- return null;
1571
- };
1572
- const getAllowedDirection = (detectResults, illegalDirections) => {
1573
- const directions = detectResults;
1574
- illegalDirections.forEach(item => {
1575
- const bottomDirectionIndex = directions.findIndex(direction => direction === item);
1576
- if (bottomDirectionIndex !== -1) {
1577
- directions.splice(bottomDirectionIndex, 1);
1578
- }
1579
- });
1580
- return directions.length ? directions : null;
1581
- };
1582
-
1583
1010
  /* 根据布局调整 target 以及 direction */
1584
1011
  const readjustmentDropTarget = (board, dropTarget) => {
1585
1012
  const { target, detectResult } = dropTarget;
@@ -1662,276 +1089,126 @@ const readjustmentDropTarget = (board, dropTarget) => {
1662
1089
  }
1663
1090
  return dropTarget;
1664
1091
  };
1665
-
1666
- const getRectangleByResizingLocation = (abstractRectangle, location, activeHandlePosition, isHorizontal) => {
1667
- if (isHorizontal) {
1668
- if (activeHandlePosition === AbstractHandlePosition.start) {
1669
- return {
1670
- ...abstractRectangle,
1671
- y: location,
1672
- height: abstractRectangle.height + abstractRectangle.y - location
1673
- };
1092
+ const isValidTarget = (origin, target) => {
1093
+ return origin !== target && !isChildElement(origin, target);
1094
+ };
1095
+ const getPathByDropTarget = (board, dropTarget) => {
1096
+ let targetPath = PlaitBoard.findPath(board, dropTarget?.target);
1097
+ const layout = PlaitMind.isMind(dropTarget?.target)
1098
+ ? getRootLayout(dropTarget?.target)
1099
+ : MindQueries.getCorrectLayoutByElement(board, MindElement.getParent(dropTarget?.target));
1100
+ const children = getNonAbstractChildren(dropTarget.target);
1101
+ // 上下布局:左右是兄弟节点,上下是子节点
1102
+ if (isVerticalLogicLayout(layout)) {
1103
+ if (dropTarget.detectResult === 'top' || dropTarget.detectResult === 'bottom') {
1104
+ targetPath.push(children.length);
1674
1105
  }
1675
- else {
1676
- return {
1677
- ...abstractRectangle,
1678
- height: location - abstractRectangle.y
1679
- };
1106
+ // 如果是左,位置不变,右则插入到下一个兄弟节点
1107
+ if (dropTarget.detectResult === 'right') {
1108
+ targetPath = Path.next(targetPath);
1680
1109
  }
1681
1110
  }
1682
- else {
1683
- if (activeHandlePosition === AbstractHandlePosition.start) {
1684
- return {
1685
- ...abstractRectangle,
1686
- x: location,
1687
- width: abstractRectangle.width + abstractRectangle.x - location
1688
- };
1111
+ // 水平布局/标准布局:上下是兄弟节点,左右是子节点
1112
+ if (isHorizontalLogicLayout(layout)) {
1113
+ if (dropTarget.detectResult === 'right' || dropTarget.detectResult === 'left') {
1114
+ targetPath.push(children.length);
1689
1115
  }
1690
- else {
1691
- return {
1692
- ...abstractRectangle,
1693
- width: location - abstractRectangle.x
1694
- };
1116
+ // 如果是上,位置不变,下插入到下一个兄弟节点
1117
+ if (dropTarget.detectResult === 'bottom') {
1118
+ targetPath = Path.next(targetPath);
1695
1119
  }
1696
1120
  }
1697
- };
1698
- const getLocationScope = (board, handlePosition, parentChildren, element, parent, isHorizontal) => {
1699
- const node = MindElement.getNode(element);
1700
- const { start, end } = getCorrectStartEnd(node.origin, parent);
1701
- const startNode = parentChildren[start];
1702
- const endNode = parentChildren[end];
1703
- if (handlePosition === AbstractHandlePosition.start) {
1704
- const abstractNode = parentChildren.filter(child => AbstractNode.isAbstract(child) && child.end < element.start);
1705
- let minNode;
1706
- if (abstractNode.length) {
1707
- const index = abstractNode
1708
- .map(node => {
1709
- const { end } = getCorrectStartEnd(node, parent);
1710
- return end;
1711
- })
1712
- .sort((a, b) => b - a)[0];
1713
- minNode = parentChildren[index + 1];
1121
+ // 缩进布局:上下是兄弟节点,左右是子节点,但上(左上/右上),探测到上是子节点,下则位置不变,反之同理。
1122
+ if (isIndentedLayout(layout)) {
1123
+ if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
1124
+ targetPath = Path.next(targetPath);
1714
1125
  }
1715
- else {
1716
- minNode = parentChildren[0];
1126
+ if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
1127
+ targetPath = Path.next(targetPath);
1717
1128
  }
1718
- const minNodeRectangle = getRectangleByElements(board, [minNode], true);
1719
- const endNodeRectangle = getRectangleByElements(board, [endNode], false);
1720
- if (isHorizontal) {
1721
- return {
1722
- max: endNodeRectangle.y - ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1723
- min: minNodeRectangle.y - ABSTRACT_INCLUDED_OUTLINE_OFFSET
1724
- };
1129
+ if (isLeftLayout(layout) && dropTarget.detectResult === 'left') {
1130
+ targetPath.push(children.length);
1725
1131
  }
1726
- else {
1727
- return {
1728
- max: endNodeRectangle.x - ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1729
- min: minNodeRectangle.x - ABSTRACT_INCLUDED_OUTLINE_OFFSET
1730
- };
1132
+ if (isRightLayout(layout) && dropTarget.detectResult === 'right') {
1133
+ targetPath.push(children.length);
1731
1134
  }
1732
1135
  }
1136
+ return targetPath;
1137
+ };
1138
+
1139
+ function drawRoundRectangleByNode(board, node) {
1140
+ const rectangle = getRectangleByNode(node);
1141
+ return drawRoundRectangleByElement(board, rectangle, node.origin);
1142
+ }
1143
+ function drawRoundRectangleByElement(board, nodeRectangle, element) {
1144
+ const fill = element.fill ? element.fill : element.isRoot ? DefaultRootStyle.fill : DefaultNodeStyle.fill;
1145
+ const stroke = getStrokeByMindElement(board, element);
1146
+ const strokeWidth = element.strokeWidth ? element.strokeWidth : DefaultNodeStyle.strokeWidth;
1147
+ const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), nodeRectangle.x, nodeRectangle.y, nodeRectangle.x + nodeRectangle.width, nodeRectangle.y + nodeRectangle.height, {
1148
+ stroke,
1149
+ strokeWidth,
1150
+ fill,
1151
+ fillStyle: 'solid'
1152
+ });
1153
+ return nodeG;
1154
+ }
1155
+
1156
+ var HorizontalPlacement;
1157
+ (function (HorizontalPlacement) {
1158
+ HorizontalPlacement["left"] = "left";
1159
+ HorizontalPlacement["center"] = "center";
1160
+ HorizontalPlacement["right"] = "right";
1161
+ })(HorizontalPlacement || (HorizontalPlacement = {}));
1162
+ var VerticalPlacement;
1163
+ (function (VerticalPlacement) {
1164
+ VerticalPlacement["top"] = "top";
1165
+ VerticalPlacement["middle"] = "middle";
1166
+ VerticalPlacement["bottom"] = "bottom";
1167
+ })(VerticalPlacement || (VerticalPlacement = {}));
1168
+
1169
+ const getPointByPlacement = (client, placement) => {
1170
+ let x = client.x;
1171
+ let y = client.y;
1172
+ if (placement[0] === HorizontalPlacement.center) {
1173
+ x = client.x + client.width / 2;
1174
+ }
1175
+ if (placement[0] === HorizontalPlacement.right) {
1176
+ x = client.x + client.width;
1177
+ }
1178
+ if (placement[1] === VerticalPlacement.middle) {
1179
+ y = client.y + client.height / 2;
1180
+ }
1181
+ if (placement[1] === VerticalPlacement.bottom) {
1182
+ y = client.y + client.height;
1183
+ }
1184
+ return [x, y];
1185
+ };
1186
+ const getXDistanceBetweenPoint = (point1, point2, isHorizontalLayout) => {
1187
+ if (isHorizontalLayout) {
1188
+ return Math.abs(point1[0] - point2[0]);
1189
+ }
1733
1190
  else {
1734
- const abstractNode = parentChildren.filter(child => AbstractNode.isAbstract(child) && child.start > element.end);
1735
- let maxNode;
1736
- if (abstractNode.length) {
1737
- const index = abstractNode
1738
- .map(node => {
1739
- const { start } = getCorrectStartEnd(node, parent);
1740
- return start;
1741
- })
1742
- .sort((a, b) => a - b)[0];
1743
- maxNode = parentChildren[index - 1];
1191
+ return Math.abs(point1[1] - point2[1]);
1192
+ }
1193
+ };
1194
+ const getYDistanceBetweenPoint = (point1, point2, isHorizontalLayout) => {
1195
+ getXDistanceBetweenPoint(point1, point2, !isHorizontalLayout);
1196
+ };
1197
+ const getLayoutDirection = (node, isHorizontal) => {
1198
+ if (isHorizontal) {
1199
+ if (node.left) {
1200
+ return LayoutDirection.left;
1744
1201
  }
1745
1202
  else {
1746
- const children = parentChildren.filter(child => !AbstractNode.isAbstract(child));
1747
- maxNode = parentChildren[children.length - 1];
1203
+ return LayoutDirection.right;
1748
1204
  }
1749
- const maxNodeRectangle = getRectangleByElements(board, [maxNode], true);
1750
- const startNodeRectangle = getRectangleByElements(board, [startNode], false);
1751
- if (isHorizontal) {
1752
- return {
1753
- max: maxNodeRectangle.y + maxNodeRectangle.height + ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1754
- min: startNodeRectangle.y + startNodeRectangle.height + ABSTRACT_INCLUDED_OUTLINE_OFFSET
1755
- };
1205
+ }
1206
+ else {
1207
+ if (node.up) {
1208
+ return LayoutDirection.top;
1756
1209
  }
1757
1210
  else {
1758
- return {
1759
- max: maxNodeRectangle.x + maxNodeRectangle.width + ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1760
- min: startNodeRectangle.x + startNodeRectangle.width + ABSTRACT_INCLUDED_OUTLINE_OFFSET
1761
- };
1762
- }
1763
- }
1764
- };
1765
- const getHitAbstractHandle = (board, element, point) => {
1766
- const nodeLayout = MindQueries.getCorrectLayoutByElement(board, element);
1767
- const isHorizontal = isHorizontalLayout(nodeLayout);
1768
- const parentElement = MindElement.getParent(element);
1769
- const includedElements = parentElement.children.slice(element.start, element.end + 1);
1770
- let abstractRectangle = getRectangleByElements(board, includedElements, true);
1771
- abstractRectangle = RectangleClient.getOutlineRectangle(abstractRectangle, -ABSTRACT_INCLUDED_OUTLINE_OFFSET);
1772
- const startHandleRec = getAbstractHandleRectangle(abstractRectangle, isHorizontal, AbstractHandlePosition.start);
1773
- const endHandleRec = getAbstractHandleRectangle(abstractRectangle, isHorizontal, AbstractHandlePosition.end);
1774
- const pointRec = RectangleClient.toRectangleClient([point, point]);
1775
- if (RectangleClient.isHit(pointRec, startHandleRec))
1776
- return AbstractHandlePosition.start;
1777
- if (RectangleClient.isHit(pointRec, endHandleRec))
1778
- return AbstractHandlePosition.end;
1779
- return undefined;
1780
- };
1781
- const getAbstractHandleRectangle = (rectangle, isHorizontal, position) => {
1782
- let result;
1783
- if (position === AbstractHandlePosition.start) {
1784
- const location = isHorizontal ? rectangle.y : rectangle.x;
1785
- result = getRectangleByResizingLocation(rectangle, location + ABSTRACT_HANDLE_MASK_WIDTH / 2, AbstractHandlePosition.end, isHorizontal);
1786
- result = getRectangleByResizingLocation(result, location - ABSTRACT_HANDLE_MASK_WIDTH / 2, position, isHorizontal);
1787
- }
1788
- else {
1789
- const location = isHorizontal ? rectangle.y + rectangle.height : rectangle.x + rectangle.width;
1790
- result = getRectangleByResizingLocation(rectangle, location - ABSTRACT_HANDLE_MASK_WIDTH / 2, AbstractHandlePosition.start, isHorizontal);
1791
- result = getRectangleByResizingLocation(result, location + ABSTRACT_HANDLE_MASK_WIDTH / 2, position, isHorizontal);
1792
- }
1793
- return result;
1794
- };
1795
- function findLocationLeftIndex(board, parentChildren, location, isHorizontal) {
1796
- const children = parentChildren.filter(child => {
1797
- return !AbstractNode.isAbstract(child);
1798
- });
1799
- const recArray = children.map(child => {
1800
- return getRectangleByElements(board, [child], false);
1801
- });
1802
- const firstRec = getRectangleByElements(board, [children[0]], true);
1803
- const fakeLeftRec = {
1804
- x: firstRec.x - firstRec.width,
1805
- y: firstRec.y - firstRec.height,
1806
- width: firstRec.width,
1807
- height: firstRec.height
1808
- };
1809
- const lastRec = getRectangleByElements(board, [children[children.length - 1]], true);
1810
- const fakeRightRec = {
1811
- x: lastRec.x + lastRec.width,
1812
- y: lastRec.y + lastRec.height,
1813
- width: lastRec.width,
1814
- height: lastRec.height
1815
- };
1816
- recArray.push(fakeRightRec);
1817
- recArray.unshift(fakeLeftRec);
1818
- for (let i = 0; i < recArray.length - 1; i++) {
1819
- const recXOrY = isHorizontal ? recArray[i].y : recArray[i].x;
1820
- const recWidthOrHeight = isHorizontal ? recArray[i].height : recArray[i].width;
1821
- if (location >= recXOrY + recWidthOrHeight / 2 &&
1822
- location <= recArray[i + 1][isHorizontal ? 'y' : 'x'] + recArray[i + 1][isHorizontal ? 'height' : 'width'] / 2) {
1823
- return i - 1;
1824
- }
1825
- }
1826
- return 0;
1827
- }
1828
- function handleTouchedAbstract(board, touchedAbstract, endPoint) {
1829
- let touchedHandle;
1830
- const abstract = getSelectedElements(board)
1831
- .filter(element => AbstractNode.isAbstract(element))
1832
- .find(element => {
1833
- touchedHandle = getHitAbstractHandle(board, element, endPoint);
1834
- return touchedHandle;
1835
- });
1836
- if (touchedAbstract === abstract) {
1837
- return touchedAbstract;
1838
- }
1839
- if (touchedAbstract) {
1840
- const component = PlaitElement.getComponent(touchedAbstract);
1841
- component.updateAbstractIncludedOutline();
1842
- touchedAbstract = undefined;
1843
- }
1844
- if (abstract) {
1845
- touchedAbstract = abstract;
1846
- const component = PlaitElement.getComponent(touchedAbstract);
1847
- component.updateAbstractIncludedOutline(touchedHandle);
1848
- }
1849
- return touchedAbstract;
1850
- }
1851
-
1852
- function drawIndentedLink(board, node, child, defaultStroke = null, needDrawUnderline = true) {
1853
- const branchWidth = getBranchWidthByMindElement(board, child.origin);
1854
- const branchColor = defaultStroke || getBranchColorByMindElement(board, child.origin);
1855
- const isUnderlineShape = getShapeByElement(board, child.origin) === MindElementShape.underline;
1856
- let beginX, beginY, endX, endY, beginNode = node, endNode = child;
1857
- const beginRectangle = getRectangleByNode(beginNode);
1858
- const endRectangle = getRectangleByNode(endNode);
1859
- beginX = beginNode.x + beginNode.width / 2;
1860
- beginY = isChildUp(node, child) ? beginRectangle.y : beginRectangle.y + beginRectangle.height;
1861
- endX = node.left ? endNode.x + endNode.hGap + endRectangle.width : endNode.x + endNode.hGap;
1862
- endY = isUnderlineShape ? endNode.y + endNode.height - endNode.vGap : endNode.y + endNode.height / 2;
1863
- //根据位置,设置正负参数
1864
- let plusMinus = isChildUp(node, child) ? (node.left ? [-1, -1] : [1, -1]) : node.left ? [-1, 1] : [1, 1];
1865
- const layout = MindQueries.getCorrectLayoutByElement(board, node.origin);
1866
- if (beginNode.origin.isRoot) {
1867
- if (layout === MindLayoutType.leftBottomIndented || layout === MindLayoutType.rightBottomIndented) {
1868
- beginY += branchWidth;
1869
- }
1870
- if (layout === MindLayoutType.leftTopIndented || layout === MindLayoutType.rightTopIndented) {
1871
- beginY -= branchWidth;
1872
- }
1873
- }
1874
- let curve = [
1875
- [beginX, beginY],
1876
- [beginX, beginY],
1877
- [beginX, beginY],
1878
- [beginX, endY - (endNode.hGap * 3 * plusMinus[1]) / 5],
1879
- [beginX, endY - (endNode.hGap * plusMinus[1]) / 5],
1880
- [beginX + (endNode.hGap * plusMinus[0]) / 4, endY],
1881
- [beginX + (endNode.hGap * plusMinus[0] * 3) / 5, endY],
1882
- isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1883
- isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1884
- isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
1885
- ];
1886
- const points = pointsOnBezierCurves(curve);
1887
- return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth: branchWidth });
1888
- }
1889
-
1890
- var HorizontalPlacement;
1891
- (function (HorizontalPlacement) {
1892
- HorizontalPlacement["left"] = "left";
1893
- HorizontalPlacement["center"] = "center";
1894
- HorizontalPlacement["right"] = "right";
1895
- })(HorizontalPlacement || (HorizontalPlacement = {}));
1896
- var VerticalPlacement;
1897
- (function (VerticalPlacement) {
1898
- VerticalPlacement["top"] = "top";
1899
- VerticalPlacement["middle"] = "middle";
1900
- VerticalPlacement["bottom"] = "bottom";
1901
- })(VerticalPlacement || (VerticalPlacement = {}));
1902
-
1903
- const getPointByPlacement = (client, placement) => {
1904
- let x = client.x;
1905
- let y = client.y;
1906
- if (placement[0] === HorizontalPlacement.center) {
1907
- x = client.x + client.width / 2;
1908
- }
1909
- if (placement[0] === HorizontalPlacement.right) {
1910
- x = client.x + client.width;
1911
- }
1912
- if (placement[1] === VerticalPlacement.middle) {
1913
- y = client.y + client.height / 2;
1914
- }
1915
- if (placement[1] === VerticalPlacement.bottom) {
1916
- y = client.y + client.height;
1917
- }
1918
- return [x, y];
1919
- };
1920
- const getLayoutDirection = (node, isHorizontal) => {
1921
- if (isHorizontal) {
1922
- if (node.left) {
1923
- return LayoutDirection.left;
1924
- }
1925
- else {
1926
- return LayoutDirection.right;
1927
- }
1928
- }
1929
- else {
1930
- if (node.up) {
1931
- return LayoutDirection.top;
1932
- }
1933
- else {
1934
- return LayoutDirection.bottom;
1211
+ return LayoutDirection.bottom;
1935
1212
  }
1936
1213
  }
1937
1214
  };
@@ -1945,7 +1222,7 @@ const getLayoutDirection = (node, isHorizontal) => {
1945
1222
  // 下 -> 上:
1946
1223
  // 1. 终点 -> 起点/终点 -> 起点
1947
1224
  // 2. 加 -> 减
1948
- const movePoint = (point, distance, direction = LayoutDirection.right) => {
1225
+ const moveXOfPoint = (point, distance, direction = LayoutDirection.right) => {
1949
1226
  if (direction === LayoutDirection.left) {
1950
1227
  return [point[0] - distance, point[1]];
1951
1228
  }
@@ -1957,6 +1234,15 @@ const movePoint = (point, distance, direction = LayoutDirection.right) => {
1957
1234
  }
1958
1235
  return [point[0] + distance, point[1]];
1959
1236
  };
1237
+ const moveYOfPoint = (point, distance, direction = LayoutDirection.right) => {
1238
+ if (direction === LayoutDirection.bottom) {
1239
+ return [point[0] + distance, point[1]];
1240
+ }
1241
+ if (direction === LayoutDirection.top) {
1242
+ return [point[0] + distance, point[1]];
1243
+ }
1244
+ return [point[0], point[1] + distance];
1245
+ };
1960
1246
  const transformPlacement = (placement, direction) => {
1961
1247
  // to left
1962
1248
  if (direction === LayoutDirection.left) {
@@ -1997,9 +1283,9 @@ const transformPlacement = (placement, direction) => {
1997
1283
  }
1998
1284
  };
1999
1285
 
2000
- function drawLogicLink(board, node, parent, isHorizontal) {
2001
- const branchColor = getBranchColorByMindElement(board, node.origin);
2002
- const branchWidth = getBranchWidthByMindElement(board, node.origin);
1286
+ function drawLogicLink(board, node, parent, isHorizontal, defaultStroke = null, defaultStrokeWidth) {
1287
+ const branchColor = defaultStroke || getBranchColorByMindElement(board, node.origin);
1288
+ const branchWidth = defaultStrokeWidth || getBranchWidthByMindElement(board, node.origin);
2003
1289
  const hasStraightLine = !parent.origin.isRoot;
2004
1290
  const parentShape = getShapeByElement(board, parent.origin);
2005
1291
  const shape = node.origin.shape ? node.origin.shape : parentShape;
@@ -2026,158 +1312,589 @@ function drawLogicLink(board, node, parent, isHorizontal) {
2026
1312
  // ② 确定凸出直线,从起始点开始画一条直线,从直线的结束位置绘制曲线,保证收起图标可以完美覆盖起始连线,根节点不需要这条直线
2027
1313
  // 绘制贝塞尔曲线要求,需要增加三个点,正常两个点就可以确定这条直线
2028
1314
  const straightLineDistance = 8;
2029
- const beginPoint2 = hasStraightLine ? movePoint(beginPoint, straightLineDistance, linkDirection) : beginPoint;
1315
+ const beginPoint2 = hasStraightLine ? moveXOfPoint(beginPoint, straightLineDistance, linkDirection) : beginPoint;
2030
1316
  let straightLine = hasStraightLine ? [beginPoint, beginPoint2, beginPoint2] : [];
2031
1317
  // ③ 确定曲线
2032
1318
  const beginBufferDistance = (parent.hGap + node.hGap) / 3;
2033
1319
  const endBufferDistance = -(parent.hGap + node.hGap) / 2.4;
2034
1320
  let curve = [
2035
1321
  beginPoint2,
2036
- movePoint(beginPoint2, beginBufferDistance, linkDirection),
2037
- movePoint(endPoint, endBufferDistance, linkDirection),
1322
+ moveXOfPoint(beginPoint2, beginBufferDistance, linkDirection),
1323
+ moveXOfPoint(endPoint, endBufferDistance, linkDirection),
2038
1324
  endPoint
2039
1325
  ];
2040
1326
  // ④ 下划线绘制,underline shape and horizontal
2041
- const underlineEnd = movePoint(endPoint, nodeClient.width, linkDirection);
1327
+ const underlineEnd = moveXOfPoint(endPoint, nodeClient.width, linkDirection);
2042
1328
  const underline = hasUnderlineShape && isHorizontal ? [underlineEnd, underlineEnd, underlineEnd] : [];
2043
1329
  const points = pointsOnBezierCurves([...straightLine, ...curve, ...underline]);
2044
1330
  return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth: branchWidth });
2045
1331
  }
2046
1332
 
2047
- function getEmojisWidthHeight(board, element) {
2048
- const options = board.getMindOptions();
2049
- const count = element.data.emojis.length;
2050
- const fontSize = getEmojiFontSize(element);
2051
- return {
2052
- width: fontSize * count + count * 2 * options.emojiPadding + (count - 1) * options.spaceBetweenEmojis,
2053
- height: element.height
1333
+ const drawFakeDragNode = (board, activeComponent, offsetX, offsetY) => {
1334
+ const dragFakeNodeG = createG();
1335
+ dragFakeNodeG.classList.add('dragging', 'fake-node', 'plait-board-attached');
1336
+ const fakeDraggingNode = {
1337
+ ...activeComponent.node,
1338
+ children: [],
1339
+ x: activeComponent.node.x + offsetX,
1340
+ y: activeComponent.node.y + offsetY
2054
1341
  };
2055
- }
2056
- function getEmojiFontSize(element) {
2057
- if (PlaitMind.isMind(element)) {
2058
- return 18 + 2;
1342
+ const textRectangle = getTopicRectangleByNode(board, activeComponent.node);
1343
+ const fakeNodeG = drawRoundRectangleByNode(board, fakeDraggingNode);
1344
+ const richtextG = activeComponent.richtextG?.cloneNode(true);
1345
+ updateForeignObject(richtextG, textRectangle.width + BASE * 10, textRectangle.height, textRectangle.x + offsetX, textRectangle.y + offsetY);
1346
+ dragFakeNodeG?.append(fakeNodeG);
1347
+ dragFakeNodeG?.append(richtextG);
1348
+ return dragFakeNodeG;
1349
+ };
1350
+ const drawFakeDropNodeByPath = (board, target, path) => {
1351
+ const fakeDropNodeG = createG();
1352
+ const parent = PlaitNode.get(board, Path.parent(path));
1353
+ const layout = MindQueries.getLayoutByElement(parent);
1354
+ const isHorizontal = isHorizontalLayout(layout);
1355
+ const { hasNextNode, hasPreviousNode } = getPreviousAndNextByPath(parent, target, path);
1356
+ const width = 30;
1357
+ const height = 12;
1358
+ let fakeNode, centerPoint, basicNode, linkDirection;
1359
+ if (!hasPreviousNode && !hasNextNode) {
1360
+ const parentNode = MindElement.getNode(parent);
1361
+ const parentRect = getRectangleByNode(parentNode);
1362
+ linkDirection = getLayoutDirection(parentNode, isHorizontal);
1363
+ basicNode = parentNode;
1364
+ const placement = [HorizontalPlacement.right, VerticalPlacement.middle];
1365
+ transformPlacement(placement, linkDirection);
1366
+ const parentCenterPoint = getPointByPlacement(parentRect, placement);
1367
+ if (isIndentedLayout(layout)) {
1368
+ const placement = [
1369
+ HorizontalPlacement.center,
1370
+ isTopLayout(layout) ? VerticalPlacement.top : VerticalPlacement.bottom
1371
+ ];
1372
+ const parentCenterPoint = getPointByPlacement(parentRect, placement);
1373
+ centerPoint = moveXOfPoint(parentCenterPoint, height, linkDirection);
1374
+ centerPoint[1] = isTopLayout(layout) ? centerPoint[1] - height : centerPoint[1] + height;
1375
+ }
1376
+ else {
1377
+ centerPoint = moveXOfPoint(parentCenterPoint, width, linkDirection);
1378
+ }
1379
+ }
1380
+ else if (!hasPreviousNode && hasNextNode) {
1381
+ const nextElement = PlaitNode.get(board, path);
1382
+ basicNode = MindElement.getNode(nextElement);
1383
+ const nextRect = getRectangleByNode(basicNode);
1384
+ linkDirection = getLayoutDirection(basicNode, isHorizontal);
1385
+ const placement = [HorizontalPlacement.left, VerticalPlacement.top];
1386
+ transformPlacement(placement, linkDirection);
1387
+ let offset = -height;
1388
+ if (MindElement.isIndentedLayout(parent)) {
1389
+ offset = isTopLayout(layout) ? offset / 2 + basicNode.height - basicNode.vGap : 0;
1390
+ }
1391
+ centerPoint = getPointByPlacement(nextRect, placement);
1392
+ centerPoint = moveYOfPoint(centerPoint, offset, linkDirection);
1393
+ }
1394
+ else if (hasPreviousNode && !hasNextNode) {
1395
+ const previousElement = PlaitNode.get(board, Path.previous(path));
1396
+ basicNode = MindElement.getNode(previousElement);
1397
+ const previousRect = getRectangleByNode(basicNode);
1398
+ linkDirection = getLayoutDirection(basicNode, isHorizontal);
1399
+ const placement = [HorizontalPlacement.left, VerticalPlacement.bottom];
1400
+ transformPlacement(placement, linkDirection);
1401
+ let offset = height;
1402
+ if (MindElement.isIndentedLayout(parent)) {
1403
+ offset = isTopLayout(layout) ? -offset - (basicNode.height - basicNode.vGap) : offset;
1404
+ }
1405
+ centerPoint = getPointByPlacement(previousRect, placement);
1406
+ centerPoint = moveYOfPoint(centerPoint, offset, linkDirection);
2059
1407
  }
2060
1408
  else {
2061
- return 14 + 2;
2062
- }
2063
- }
2064
- function getEmojiRectangle(board, element) {
2065
- let { x, y } = getRectangleByNode(MindElement.getNode(element));
2066
- x = x + NodeSpace.getEmojiLeftSpace(board, element);
2067
- const { width, height } = getEmojisWidthHeight(board, element);
2068
- return {
1409
+ const previousElement = PlaitNode.get(board, Path.previous(path));
1410
+ basicNode = MindElement.getNode(previousElement);
1411
+ const previousRect = getRectangleByNode(basicNode);
1412
+ const nextElement = PlaitNode.get(board, path);
1413
+ const nextNode = MindElement.getNode(nextElement);
1414
+ const nextRect = getRectangleByNode(nextNode);
1415
+ const beginPlacement = [HorizontalPlacement.left, VerticalPlacement.bottom];
1416
+ const endPlacement = [HorizontalPlacement.left, VerticalPlacement.top];
1417
+ linkDirection = getLayoutDirection(basicNode, isHorizontal);
1418
+ transformPlacement(beginPlacement, linkDirection);
1419
+ transformPlacement(endPlacement, linkDirection);
1420
+ const previousPoint = getPointByPlacement(previousRect, beginPlacement);
1421
+ const nextPoint = getPointByPlacement(nextRect, endPlacement);
1422
+ centerPoint = [(previousPoint[0] + nextPoint[0]) / 2, (previousPoint[1] + nextPoint[1]) / 2];
1423
+ }
1424
+ let cornerPoint = centerPoint, oppositePoint = centerPoint;
1425
+ const offsetY = isHorizontal ? height : width;
1426
+ const offsetX = isHorizontal ? width : height;
1427
+ cornerPoint = moveYOfPoint(cornerPoint, -offsetY / 2, linkDirection);
1428
+ oppositePoint = moveYOfPoint(oppositePoint, offsetY / 2, linkDirection);
1429
+ oppositePoint = moveXOfPoint(oppositePoint, offsetX, linkDirection);
1430
+ const x = Math.min(cornerPoint[0], oppositePoint[0]);
1431
+ const y = Math.min(cornerPoint[1], oppositePoint[1]);
1432
+ fakeNode = {
1433
+ ...basicNode,
2069
1434
  x,
2070
1435
  y,
2071
1436
  width,
2072
- height
1437
+ height,
1438
+ hGap: MindElement.isIndentedLayout(parent) ? BASE * 4 + (basicNode.origin.strokeWidth || STROKE_WIDTH) : 0,
1439
+ vGap: MindElement.isIndentedLayout(parent) ? BASE : 0
2073
1440
  };
2074
- }
2075
- function getEmojiForeignRectangle(board, element) {
2076
- let { x, y } = getRectangleByNode(MindElement.getNode(element));
2077
- x = x + NodeSpace.getEmojiLeftSpace(board, element);
2078
- const { width, height } = getEmojisWidthHeight(board, element);
1441
+ const fakeRectangleG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), fakeNode.x, fakeNode.y, fakeNode.x + width, fakeNode.y + height, {
1442
+ stroke: PRIMARY_COLOR,
1443
+ strokeWidth: 2,
1444
+ fill: PRIMARY_COLOR,
1445
+ fillStyle: 'solid'
1446
+ });
1447
+ const link = MindElement.isIndentedLayout(parent)
1448
+ ? drawIndentedLink(board, MindElement.getNode(parent), fakeNode, PRIMARY_COLOR, false, STROKE_WIDTH)
1449
+ : drawLogicLink(board, fakeNode, MindElement.getNode(parent), isHorizontal, PRIMARY_COLOR, STROKE_WIDTH);
1450
+ fakeDropNodeG?.appendChild(link);
1451
+ fakeDropNodeG?.appendChild(fakeRectangleG);
1452
+ return fakeDropNodeG;
1453
+ };
1454
+ const getPreviousAndNextByPath = (parent, target, path) => {
1455
+ const children = getNonAbstractChildren(parent);
1456
+ let hasPreviousNode = path[path.length - 1] !== 0;
1457
+ let hasNextNode = path[path.length - 1] !== (children?.length || 0);
1458
+ if (PlaitMind.isMind(parent) && isStandardLayout(getRootLayout(parent))) {
1459
+ const dropStandardRightBottom = target === parent.children[parent.rightNodeCount - 1] && path[path.length - 1] === parent.rightNodeCount;
1460
+ const dropStandardLeftTop = target === parent.children[parent.rightNodeCount] && path[path.length - 1] === parent.rightNodeCount;
1461
+ if (dropStandardRightBottom) {
1462
+ hasPreviousNode = true;
1463
+ hasNextNode = false;
1464
+ }
1465
+ if (dropStandardLeftTop) {
1466
+ hasPreviousNode = false;
1467
+ hasNextNode = true;
1468
+ }
1469
+ }
1470
+ if (parent.isCollapsed) {
1471
+ hasNextNode = false;
1472
+ hasPreviousNode = false;
1473
+ }
2079
1474
  return {
2080
- x,
2081
- y,
2082
- width,
2083
- height: height + NodeSpace.getEmojiTopSpace(element) * 2
1475
+ hasPreviousNode,
1476
+ hasNextNode
2084
1477
  };
1478
+ };
1479
+
1480
+ const separateChildren = (parentElement) => {
1481
+ const rightNodeCount = parentElement.rightNodeCount;
1482
+ const children = parentElement.children;
1483
+ let rightChildren = [], leftChildren = [];
1484
+ for (let i = 0; i < children.length; i++) {
1485
+ const child = children[i];
1486
+ if (AbstractNode.isAbstract(child) && child.end < rightNodeCount) {
1487
+ rightChildren.push(child);
1488
+ continue;
1489
+ }
1490
+ if (AbstractNode.isAbstract(child) && child.start >= rightNodeCount) {
1491
+ leftChildren.push(child);
1492
+ continue;
1493
+ }
1494
+ if (i < rightNodeCount) {
1495
+ rightChildren.push(child);
1496
+ }
1497
+ else {
1498
+ leftChildren.push(child);
1499
+ }
1500
+ }
1501
+ return { leftChildren, rightChildren };
1502
+ };
1503
+ const isSetAbstract = (element) => {
1504
+ return !!getCorrespondingAbstract(element);
1505
+ };
1506
+ const canSetAbstract = (element) => {
1507
+ return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
1508
+ };
1509
+ const getCorrespondingAbstract = (element) => {
1510
+ const parent = MindElement.findParent(element);
1511
+ if (!parent)
1512
+ return undefined;
1513
+ const elementIndex = parent.children.indexOf(element);
1514
+ return parent.children.find(child => {
1515
+ return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
1516
+ });
1517
+ };
1518
+ const getBehindAbstracts = (element) => {
1519
+ const parent = MindElement.findParent(element);
1520
+ if (!parent)
1521
+ return [];
1522
+ const index = parent.children.indexOf(element);
1523
+ return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
1524
+ };
1525
+ /**
1526
+ * return corresponding abstract that is not child of elements
1527
+ */
1528
+ const getOverallAbstracts = (board, elements) => {
1529
+ const overallAbstracts = [];
1530
+ elements
1531
+ .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
1532
+ .forEach(value => {
1533
+ const abstract = getCorrespondingAbstract(value);
1534
+ if (abstract && elements.indexOf(abstract) === -1 && overallAbstracts.indexOf(abstract) === -1) {
1535
+ const { start, end } = abstract;
1536
+ const parent = MindElement.getParent(value);
1537
+ const isOverall = parent.children.slice(start, end + 1).every(includedElement => elements.indexOf(includedElement) > -1);
1538
+ if (isOverall) {
1539
+ overallAbstracts.push(abstract);
1540
+ }
1541
+ }
1542
+ });
1543
+ return overallAbstracts;
1544
+ };
1545
+ /**
1546
+ * abstract node is valid when elements contains at least one element it is referenced with
1547
+ */
1548
+ const getValidAbstractRefs = (board, elements) => {
1549
+ const validAbstractRefs = [];
1550
+ elements
1551
+ .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
1552
+ .forEach(value => {
1553
+ const abstract = getCorrespondingAbstract(value);
1554
+ if (abstract && elements.indexOf(abstract) > 0) {
1555
+ const index = validAbstractRefs.findIndex(value => value.abstract === abstract);
1556
+ if (index === -1) {
1557
+ validAbstractRefs.push({
1558
+ abstract: abstract,
1559
+ references: [value]
1560
+ });
1561
+ }
1562
+ else {
1563
+ validAbstractRefs[index].references.push(value);
1564
+ }
1565
+ }
1566
+ });
1567
+ return validAbstractRefs;
1568
+ };
1569
+ function getRelativeStartEndByAbstractRef(abstractRef, elements) {
1570
+ const start = elements.indexOf(abstractRef.references[0]);
1571
+ const end = elements.indexOf(abstractRef.references[abstractRef.references.length - 1]);
1572
+ return { start, end };
2085
1573
  }
2086
- const isHitEmojis = (board, element, point) => {
2087
- return RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), getEmojiRectangle(board, element));
1574
+ const insertElementHandleAbstract = (board, path, step = 1,
1575
+ //由此区分拖拽和新增到概要概括最后一个节点
1576
+ isExtendPreviousNode = true, effectedAbstracts = new Map()) => {
1577
+ const parent = PlaitNode.parent(board, path);
1578
+ const hasPreviousNode = path[path.length - 1] !== 0;
1579
+ let behindAbstracts;
1580
+ if (!hasPreviousNode) {
1581
+ behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));
1582
+ }
1583
+ else {
1584
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
1585
+ behindAbstracts = getBehindAbstracts(selectedElement);
1586
+ }
1587
+ if (behindAbstracts.length) {
1588
+ behindAbstracts.forEach(abstract => {
1589
+ let newProperties = effectedAbstracts.get(abstract);
1590
+ if (!newProperties) {
1591
+ newProperties = { start: 0, end: 0 };
1592
+ effectedAbstracts.set(abstract, newProperties);
1593
+ }
1594
+ newProperties.start = newProperties.start + step;
1595
+ newProperties.end = newProperties.end + step;
1596
+ });
1597
+ }
1598
+ if (!hasPreviousNode) {
1599
+ return effectedAbstracts;
1600
+ }
1601
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
1602
+ const correspondingAbstract = getCorrespondingAbstract(selectedElement);
1603
+ const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;
1604
+ if (correspondingAbstract && !isDragToLast) {
1605
+ let newProperties = effectedAbstracts.get(correspondingAbstract);
1606
+ if (!newProperties) {
1607
+ newProperties = { start: 0, end: 0 };
1608
+ effectedAbstracts.set(correspondingAbstract, newProperties);
1609
+ }
1610
+ newProperties.end = newProperties.end + step;
1611
+ }
1612
+ return effectedAbstracts;
1613
+ };
1614
+ const deleteElementHandleAbstract = (board, deletableElements, effectedAbstracts = new Map()) => {
1615
+ deletableElements.forEach(node => {
1616
+ if (!PlaitMind.isMind(node)) {
1617
+ const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));
1618
+ if (behindAbstracts.length) {
1619
+ behindAbstracts.forEach(abstract => {
1620
+ let newProperties = effectedAbstracts.get(abstract);
1621
+ if (!newProperties) {
1622
+ newProperties = { start: 0, end: 0 };
1623
+ effectedAbstracts.set(abstract, newProperties);
1624
+ }
1625
+ newProperties.start = newProperties.start - 1;
1626
+ newProperties.end = newProperties.end - 1;
1627
+ });
1628
+ }
1629
+ const correspondingAbstract = getCorrespondingAbstract(node);
1630
+ if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
1631
+ let newProperties = effectedAbstracts.get(correspondingAbstract);
1632
+ if (!newProperties) {
1633
+ newProperties = { start: 0, end: 0 };
1634
+ effectedAbstracts.set(correspondingAbstract, newProperties);
1635
+ }
1636
+ newProperties.end = newProperties.end - 1;
1637
+ }
1638
+ }
1639
+ });
1640
+ return effectedAbstracts;
2088
1641
  };
2089
1642
 
2090
- const NodeDefaultSpace = {
2091
- horizontal: {
2092
- nodeAndText: BASE * 3,
2093
- emojiAndText: BASE * 1.5
2094
- },
2095
- vertical: {
2096
- nodeAndText: BASE * 1.5
1643
+ var AbstractHandlePosition;
1644
+ (function (AbstractHandlePosition) {
1645
+ AbstractHandlePosition["start"] = "start";
1646
+ AbstractHandlePosition["end"] = "end";
1647
+ })(AbstractHandlePosition || (AbstractHandlePosition = {}));
1648
+ var AbstractResizeState;
1649
+ (function (AbstractResizeState) {
1650
+ AbstractResizeState["start"] = "start";
1651
+ AbstractResizeState["resizing"] = "resizing";
1652
+ AbstractResizeState["end"] = "end";
1653
+ })(AbstractResizeState || (AbstractResizeState = {}));
1654
+
1655
+ const getRectangleByResizingLocation = (abstractRectangle, location, activeHandlePosition, isHorizontal) => {
1656
+ if (isHorizontal) {
1657
+ if (activeHandlePosition === AbstractHandlePosition.start) {
1658
+ return {
1659
+ ...abstractRectangle,
1660
+ y: location,
1661
+ height: abstractRectangle.height + abstractRectangle.y - location
1662
+ };
1663
+ }
1664
+ else {
1665
+ return {
1666
+ ...abstractRectangle,
1667
+ height: location - abstractRectangle.y
1668
+ };
1669
+ }
1670
+ }
1671
+ else {
1672
+ if (activeHandlePosition === AbstractHandlePosition.start) {
1673
+ return {
1674
+ ...abstractRectangle,
1675
+ x: location,
1676
+ width: abstractRectangle.width + abstractRectangle.x - location
1677
+ };
1678
+ }
1679
+ else {
1680
+ return {
1681
+ ...abstractRectangle,
1682
+ width: location - abstractRectangle.x
1683
+ };
1684
+ }
1685
+ }
1686
+ };
1687
+ const getLocationScope = (board, handlePosition, parentChildren, element, parent, isHorizontal) => {
1688
+ const node = MindElement.getNode(element);
1689
+ const { start, end } = getCorrectStartEnd(node.origin, parent);
1690
+ const startNode = parentChildren[start];
1691
+ const endNode = parentChildren[end];
1692
+ if (handlePosition === AbstractHandlePosition.start) {
1693
+ const abstractNode = parentChildren.filter(child => AbstractNode.isAbstract(child) && child.end < element.start);
1694
+ let minNode;
1695
+ if (abstractNode.length) {
1696
+ const index = abstractNode
1697
+ .map(node => {
1698
+ const { end } = getCorrectStartEnd(node, parent);
1699
+ return end;
1700
+ })
1701
+ .sort((a, b) => b - a)[0];
1702
+ minNode = parentChildren[index + 1];
1703
+ }
1704
+ else {
1705
+ minNode = parentChildren[0];
1706
+ }
1707
+ const minNodeRectangle = getRectangleByElements(board, [minNode], true);
1708
+ const endNodeRectangle = getRectangleByElements(board, [endNode], false);
1709
+ if (isHorizontal) {
1710
+ return {
1711
+ max: endNodeRectangle.y - ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1712
+ min: minNodeRectangle.y - ABSTRACT_INCLUDED_OUTLINE_OFFSET
1713
+ };
1714
+ }
1715
+ else {
1716
+ return {
1717
+ max: endNodeRectangle.x - ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1718
+ min: minNodeRectangle.x - ABSTRACT_INCLUDED_OUTLINE_OFFSET
1719
+ };
1720
+ }
1721
+ }
1722
+ else {
1723
+ const abstractNode = parentChildren.filter(child => AbstractNode.isAbstract(child) && child.start > element.end);
1724
+ let maxNode;
1725
+ if (abstractNode.length) {
1726
+ const index = abstractNode
1727
+ .map(node => {
1728
+ const { start } = getCorrectStartEnd(node, parent);
1729
+ return start;
1730
+ })
1731
+ .sort((a, b) => a - b)[0];
1732
+ maxNode = parentChildren[index - 1];
1733
+ }
1734
+ else {
1735
+ const children = parentChildren.filter(child => !AbstractNode.isAbstract(child));
1736
+ maxNode = parentChildren[children.length - 1];
1737
+ }
1738
+ const maxNodeRectangle = getRectangleByElements(board, [maxNode], true);
1739
+ const startNodeRectangle = getRectangleByElements(board, [startNode], false);
1740
+ if (isHorizontal) {
1741
+ return {
1742
+ max: maxNodeRectangle.y + maxNodeRectangle.height + ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1743
+ min: startNodeRectangle.y + startNodeRectangle.height + ABSTRACT_INCLUDED_OUTLINE_OFFSET
1744
+ };
1745
+ }
1746
+ else {
1747
+ return {
1748
+ max: maxNodeRectangle.x + maxNodeRectangle.width + ABSTRACT_INCLUDED_OUTLINE_OFFSET,
1749
+ min: startNodeRectangle.x + startNodeRectangle.width + ABSTRACT_INCLUDED_OUTLINE_OFFSET
1750
+ };
1751
+ }
1752
+ }
1753
+ };
1754
+ const getHitAbstractHandle = (board, element, point) => {
1755
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(board, element);
1756
+ const isHorizontal = isHorizontalLayout(nodeLayout);
1757
+ const parentElement = MindElement.getParent(element);
1758
+ const includedElements = parentElement.children.slice(element.start, element.end + 1);
1759
+ let abstractRectangle = getRectangleByElements(board, includedElements, true);
1760
+ abstractRectangle = RectangleClient.getOutlineRectangle(abstractRectangle, -ABSTRACT_INCLUDED_OUTLINE_OFFSET);
1761
+ const startHandleRec = getAbstractHandleRectangle(abstractRectangle, isHorizontal, AbstractHandlePosition.start);
1762
+ const endHandleRec = getAbstractHandleRectangle(abstractRectangle, isHorizontal, AbstractHandlePosition.end);
1763
+ const pointRec = RectangleClient.toRectangleClient([point, point]);
1764
+ if (RectangleClient.isHit(pointRec, startHandleRec))
1765
+ return AbstractHandlePosition.start;
1766
+ if (RectangleClient.isHit(pointRec, endHandleRec))
1767
+ return AbstractHandlePosition.end;
1768
+ return undefined;
1769
+ };
1770
+ const getAbstractHandleRectangle = (rectangle, isHorizontal, position) => {
1771
+ let result;
1772
+ if (position === AbstractHandlePosition.start) {
1773
+ const location = isHorizontal ? rectangle.y : rectangle.x;
1774
+ result = getRectangleByResizingLocation(rectangle, location + ABSTRACT_HANDLE_MASK_WIDTH / 2, AbstractHandlePosition.end, isHorizontal);
1775
+ result = getRectangleByResizingLocation(result, location - ABSTRACT_HANDLE_MASK_WIDTH / 2, position, isHorizontal);
1776
+ }
1777
+ else {
1778
+ const location = isHorizontal ? rectangle.y + rectangle.height : rectangle.x + rectangle.width;
1779
+ result = getRectangleByResizingLocation(rectangle, location - ABSTRACT_HANDLE_MASK_WIDTH / 2, AbstractHandlePosition.start, isHorizontal);
1780
+ result = getRectangleByResizingLocation(result, location + ABSTRACT_HANDLE_MASK_WIDTH / 2, position, isHorizontal);
1781
+ }
1782
+ return result;
1783
+ };
1784
+ function findLocationLeftIndex(board, parentChildren, location, isHorizontal) {
1785
+ const children = parentChildren.filter(child => {
1786
+ return !AbstractNode.isAbstract(child);
1787
+ });
1788
+ const recArray = children.map(child => {
1789
+ return getRectangleByElements(board, [child], false);
1790
+ });
1791
+ const firstRec = getRectangleByElements(board, [children[0]], true);
1792
+ const fakeLeftRec = {
1793
+ x: firstRec.x - firstRec.width,
1794
+ y: firstRec.y - firstRec.height,
1795
+ width: firstRec.width,
1796
+ height: firstRec.height
1797
+ };
1798
+ const lastRec = getRectangleByElements(board, [children[children.length - 1]], true);
1799
+ const fakeRightRec = {
1800
+ x: lastRec.x + lastRec.width,
1801
+ y: lastRec.y + lastRec.height,
1802
+ width: lastRec.width,
1803
+ height: lastRec.height
1804
+ };
1805
+ recArray.push(fakeRightRec);
1806
+ recArray.unshift(fakeLeftRec);
1807
+ for (let i = 0; i < recArray.length - 1; i++) {
1808
+ const recXOrY = isHorizontal ? recArray[i].y : recArray[i].x;
1809
+ const recWidthOrHeight = isHorizontal ? recArray[i].height : recArray[i].width;
1810
+ if (location >= recXOrY + recWidthOrHeight / 2 &&
1811
+ location <= recArray[i + 1][isHorizontal ? 'y' : 'x'] + recArray[i + 1][isHorizontal ? 'height' : 'width'] / 2) {
1812
+ return i - 1;
1813
+ }
2097
1814
  }
2098
- };
2099
- const RootDefaultSpace = {
2100
- horizontal: {
2101
- nodeAndText: BASE * 4,
2102
- emojiAndText: BASE * 2
2103
- },
2104
- vertical: {
2105
- nodeAndText: BASE * 2
1815
+ return 0;
1816
+ }
1817
+ function handleTouchedAbstract(board, touchedAbstract, endPoint) {
1818
+ let touchedHandle;
1819
+ const abstract = getSelectedElements(board)
1820
+ .filter(element => AbstractNode.isAbstract(element))
1821
+ .find(element => {
1822
+ touchedHandle = getHitAbstractHandle(board, element, endPoint);
1823
+ return touchedHandle;
1824
+ });
1825
+ if (touchedAbstract === abstract) {
1826
+ return touchedAbstract;
2106
1827
  }
2107
- };
2108
- const getHorizontalSpaceBetweenNodeAndText = (board, element) => {
2109
- const isMind = PlaitMind.isMind(element);
2110
- const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;
2111
- return nodeAndText;
2112
- };
2113
- const getVerticalSpaceBetweenNodeAndText = (element) => {
2114
- const isMind = PlaitMind.isMind(element);
2115
- const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;
2116
- return nodeAndText;
2117
- };
2118
- const getSpaceEmojiAndText = (element) => {
2119
- const isMind = PlaitMind.isMind(element);
2120
- const emojiAndText = isMind ? RootDefaultSpace.horizontal.emojiAndText : NodeDefaultSpace.horizontal.emojiAndText;
2121
- return emojiAndText;
2122
- };
2123
- const NodeSpace = {
2124
- getNodeWidth(board, element) {
2125
- const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
2126
- if (MindElement.hasEmojis(element)) {
2127
- return (NodeSpace.getEmojiLeftSpace(board, element) +
2128
- getEmojisWidthHeight(board, element).width +
2129
- getSpaceEmojiAndText(element) +
2130
- element.width +
2131
- nodeAndText);
2132
- }
2133
- return nodeAndText + element.width + nodeAndText;
2134
- },
2135
- getNodeHeight(element) {
2136
- const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
2137
- return nodeAndText + element.height + nodeAndText;
2138
- },
2139
- getTextLeftSpace(board, element) {
2140
- const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
2141
- if (MindElement.hasEmojis(element)) {
2142
- return NodeSpace.getEmojiLeftSpace(board, element) + getEmojisWidthHeight(board, element).width + getSpaceEmojiAndText(element);
1828
+ if (touchedAbstract) {
1829
+ const component = PlaitElement.getComponent(touchedAbstract);
1830
+ component.updateAbstractIncludedOutline();
1831
+ touchedAbstract = undefined;
1832
+ }
1833
+ if (abstract) {
1834
+ touchedAbstract = abstract;
1835
+ const component = PlaitElement.getComponent(touchedAbstract);
1836
+ component.updateAbstractIncludedOutline(touchedHandle);
1837
+ }
1838
+ return touchedAbstract;
1839
+ }
1840
+
1841
+ function drawIndentedLink(board, node, child, defaultStroke = null, needDrawUnderline = true, defaultStrokeWidth) {
1842
+ const branchWidth = defaultStrokeWidth || getBranchWidthByMindElement(board, child.origin);
1843
+ const branchColor = defaultStroke || getBranchColorByMindElement(board, child.origin);
1844
+ const isUnderlineShape = getShapeByElement(board, child.origin) === MindElementShape.underline;
1845
+ let beginX, beginY, endX, endY, beginNode = node, endNode = child;
1846
+ const beginRectangle = getRectangleByNode(beginNode);
1847
+ const endRectangle = getRectangleByNode(endNode);
1848
+ beginX = beginNode.x + beginNode.width / 2;
1849
+ beginY = isChildUp(node, child) ? beginRectangle.y : beginRectangle.y + beginRectangle.height;
1850
+ endX = node.left ? endNode.x + endNode.hGap + endRectangle.width : endNode.x + endNode.hGap;
1851
+ endY = isUnderlineShape ? endNode.y + endNode.height - endNode.vGap : endNode.y + endNode.height / 2;
1852
+ //根据位置,设置正负参数
1853
+ let plusMinus = isChildUp(node, child) ? (node.left ? [-1, -1] : [1, -1]) : node.left ? [-1, 1] : [1, 1];
1854
+ const layout = MindQueries.getCorrectLayoutByElement(board, node.origin);
1855
+ if (beginNode.origin.isRoot) {
1856
+ if (layout === MindLayoutType.leftBottomIndented || layout === MindLayoutType.rightBottomIndented) {
1857
+ beginY += branchWidth;
2143
1858
  }
2144
- else {
2145
- return nodeAndText;
1859
+ if (layout === MindLayoutType.leftTopIndented || layout === MindLayoutType.rightTopIndented) {
1860
+ beginY -= branchWidth;
2146
1861
  }
2147
- },
2148
- getTextTopSpace(element) {
2149
- const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
2150
- return nodeAndText;
2151
- },
2152
- getEmojiLeftSpace(board, element) {
2153
- const options = board.getMindOptions();
2154
- const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
2155
- return nodeAndText - options.emojiPadding;
2156
- },
2157
- getEmojiTopSpace(element) {
2158
- const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
2159
- return nodeAndText;
2160
1862
  }
2161
- };
1863
+ let curve = [
1864
+ [beginX, beginY],
1865
+ [beginX, beginY],
1866
+ [beginX, beginY],
1867
+ [beginX, endY - (endNode.hGap * 3 * plusMinus[1]) / 5],
1868
+ [beginX, endY - (endNode.hGap * plusMinus[1]) / 5],
1869
+ [beginX + (endNode.hGap * plusMinus[0]) / 4, endY],
1870
+ [beginX + (endNode.hGap * plusMinus[0] * 3) / 5, endY],
1871
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1872
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1873
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
1874
+ ];
1875
+ const points = pointsOnBezierCurves(curve);
1876
+ return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth: branchWidth });
1877
+ }
2162
1878
 
2163
- function drawMindNodeRichtext(board, node, viewContainerRef) {
2164
- const { x, y, width, height } = getRichtextRectangleByNode(board, node);
1879
+ function drawTopicByNode(board, node, viewContainerRef) {
1880
+ const rectangle = getTopicRectangleByNode(board, node);
1881
+ return drawTopicByElement(board, rectangle, node.origin, viewContainerRef);
1882
+ }
1883
+ function drawTopicByElement(board, rectangle, element, viewContainerRef) {
1884
+ const containerRef = viewContainerRef || PlaitBoard.getComponent(board).viewContainerRef;
2165
1885
  const classList = [];
2166
- if (node.origin.isRoot) {
1886
+ if (element.isRoot) {
2167
1887
  classList.push('root-node');
2168
1888
  classList.push('font-size-18');
2169
1889
  }
2170
- else if (node.parent?.origin?.isRoot) {
2171
- classList.push('root-child-node');
2172
- }
2173
1890
  else {
2174
1891
  classList.push('child-node');
2175
1892
  }
2176
1893
  // COMPAT: last character can not show in safari browser
2177
- return drawRichtext(x, y, width, height, node.origin.data.topic, viewContainerRef, classList);
1894
+ return drawRichtext(rectangle.x, rectangle.y, rectangle.width, rectangle.height, element.data.topic, containerRef, classList);
2178
1895
  }
2179
1896
  function updateMindNodeTopicSize(board, node, g, isEditable) {
2180
- const { x, y, width, height } = getRichtextRectangleByNode(board, node);
1897
+ const { x, y, width, height } = getTopicRectangleByNode(board, node);
2181
1898
  if (isEditable) {
2182
1899
  // add 999, avoid changing lines when paste more text
2183
1900
  updateForeignObject(g, width + 999, height + 999, x, y);
@@ -2187,28 +1904,6 @@ function updateMindNodeTopicSize(board, node, g, isEditable) {
2187
1904
  updateForeignObject(g, width, height, x, y);
2188
1905
  }
2189
1906
  }
2190
- function getRichtextRectangleByNode(board, node) {
2191
- let { x, y } = getRectangleByNode(node);
2192
- x = x + NodeSpace.getTextLeftSpace(board, node.origin);
2193
- y = y + NodeSpace.getTextTopSpace(node.origin);
2194
- const width = Math.ceil(node.origin.width);
2195
- const height = Math.ceil(node.origin.height);
2196
- return { height, width, x, y };
2197
- }
2198
-
2199
- function drawRectangleNode(board, node) {
2200
- const { x, y, width, height } = getRectangleByNode(node);
2201
- const fill = node.origin.fill ? node.origin.fill : node.origin.isRoot ? DefaultRootStyle.fill : DefaultNodeStyle.fill;
2202
- const stroke = getStrokeByMindElement(board, node.origin);
2203
- const strokeWidth = node.origin.strokeWidth ? node.origin.strokeWidth : DefaultNodeStyle.strokeWidth;
2204
- const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), x, y, x + width, y + height, {
2205
- stroke,
2206
- strokeWidth,
2207
- fill,
2208
- fillStyle: 'solid'
2209
- });
2210
- return nodeG;
2211
- }
2212
1907
 
2213
1908
  function drawAbstractLink(board, node, isHorizontal) {
2214
1909
  const linkPadding = 15;
@@ -2230,18 +1925,12 @@ function drawAbstractLink(board, node, isHorizontal) {
2230
1925
  let bezierBeginPoint = getPointByPlacement(includedElementsRectangle, bezierBeginPlacement);
2231
1926
  let bezierEndPoint = getPointByPlacement(includedElementsRectangle, bezierEndPlacement);
2232
1927
  let abstractConnectorPoint = getPointByPlacement(abstractRectangle, abstractConnectorPlacement);
2233
- let curveDistance = 0;
2234
- if (isHorizontal) {
2235
- curveDistance = Math.abs(abstractConnectorPoint[0] - bezierBeginPoint[0]) - linkPadding * 2;
2236
- }
2237
- else {
2238
- curveDistance = Math.abs(abstractConnectorPoint[1] - bezierBeginPoint[1]) - linkPadding * 2;
2239
- }
2240
- bezierBeginPoint = movePoint(bezierBeginPoint, linkPadding, linkDirection);
2241
- let c1 = movePoint(bezierBeginPoint, curveDistance, linkDirection);
2242
- bezierEndPoint = movePoint(bezierEndPoint, linkPadding, linkDirection);
2243
- let c2 = movePoint(bezierEndPoint, curveDistance, linkDirection);
2244
- let bezierConnectorPoint = movePoint(abstractConnectorPoint, -linkPadding, linkDirection);
1928
+ let curveDistance = getXDistanceBetweenPoint(abstractConnectorPoint, bezierBeginPoint, isHorizontal) - linkPadding * 2;
1929
+ bezierBeginPoint = moveXOfPoint(bezierBeginPoint, linkPadding, linkDirection);
1930
+ let c1 = moveXOfPoint(bezierBeginPoint, curveDistance, linkDirection);
1931
+ bezierEndPoint = moveXOfPoint(bezierEndPoint, linkPadding, linkDirection);
1932
+ let c2 = moveXOfPoint(bezierEndPoint, curveDistance, linkDirection);
1933
+ let bezierConnectorPoint = moveXOfPoint(abstractConnectorPoint, -linkPadding, linkDirection);
2245
1934
  const link = PlaitBoard.getRoughSVG(board).path(`M${bezierBeginPoint[0]},${bezierBeginPoint[1]} Q${c1[0]},${c1[1]} ${bezierConnectorPoint[0]},${bezierConnectorPoint[1]} Q${c2[0]},${c2[1]} ${bezierEndPoint[0]},${bezierEndPoint[1]} M${abstractConnectorPoint[0]},${abstractConnectorPoint[1]} L${bezierConnectorPoint[0]},${bezierConnectorPoint[1]}`, {
2246
1935
  stroke: branchColor,
2247
1936
  strokeWidth: branchWidth
@@ -2285,37 +1974,236 @@ class EmojisDrawer {
2285
1974
  this.viewContainerRef = viewContainerRef;
2286
1975
  this.emojiDrawers = [];
2287
1976
  }
2288
- drawEmojis(element) {
2289
- this.destroy();
2290
- if (MindElement.hasEmojis(element)) {
2291
- this.g = createG();
2292
- this.g.classList.add('emojis');
2293
- const foreignRectangle = getEmojiForeignRectangle(this.board, element);
2294
- const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2295
- this.g.append(foreignObject);
2296
- const container = document.createElement('div');
2297
- container.classList.add('node-emojis-container');
2298
- foreignObject.append(container);
2299
- this.emojiDrawers = element.data.emojis.map(emojiItem => {
2300
- const drawer = new EmojiDrawer(this.board, this.viewContainerRef);
2301
- drawer.draw(emojiItem, element);
2302
- return drawer;
2303
- });
2304
- this.emojiDrawers.forEach(drawer => {
2305
- container.append(drawer.nativeElement);
2306
- });
2307
- return this.g;
1977
+ drawEmojis(element) {
1978
+ this.destroy();
1979
+ if (MindElement.hasEmojis(element)) {
1980
+ this.g = createG();
1981
+ this.g.classList.add('emojis');
1982
+ const foreignRectangle = getEmojiForeignRectangle(this.board, element);
1983
+ const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
1984
+ this.g.append(foreignObject);
1985
+ const container = document.createElement('div');
1986
+ container.classList.add('node-emojis-container');
1987
+ foreignObject.append(container);
1988
+ this.emojiDrawers = element.data.emojis.map(emojiItem => {
1989
+ const drawer = new EmojiDrawer(this.board, this.viewContainerRef);
1990
+ drawer.draw(emojiItem, element);
1991
+ return drawer;
1992
+ });
1993
+ this.emojiDrawers.forEach(drawer => {
1994
+ container.append(drawer.nativeElement);
1995
+ });
1996
+ return this.g;
1997
+ }
1998
+ return undefined;
1999
+ }
2000
+ destroy() {
2001
+ if (this.g) {
2002
+ this.g.remove();
2003
+ }
2004
+ this.emojiDrawers.forEach(drawer => drawer.destroy());
2005
+ this.emojiDrawers = [];
2006
+ }
2007
+ }
2008
+
2009
+ const setAbstractsByRefs = (board, abstractRefs) => {
2010
+ abstractRefs.forEach((newProperty, element) => {
2011
+ const start = element.start + newProperty.start;
2012
+ const end = element.end + newProperty.end;
2013
+ const path = PlaitBoard.findPath(board, element);
2014
+ if (start > end) {
2015
+ Transforms.removeNode(board, path);
2016
+ }
2017
+ else {
2018
+ Transforms.setNode(board, { start, end }, path);
2019
+ }
2020
+ });
2021
+ };
2022
+ const setAbstractByStandardLayout = (board, element) => {
2023
+ const rightNodeCount = element.rightNodeCount;
2024
+ const abstract = element.children.find(child => {
2025
+ return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
2026
+ });
2027
+ if (abstract) {
2028
+ const path = PlaitBoard.findPath(board, abstract);
2029
+ Transforms.setNode(board, { end: rightNodeCount - 1 }, path);
2030
+ }
2031
+ };
2032
+ const insertAbstract = (board, elements) => {
2033
+ let elementGroup = getFirstLevelElement(elements);
2034
+ const { parentElements, abstractIncludedGroups } = divideElementByParent(elementGroup);
2035
+ abstractIncludedGroups.forEach((group, index) => {
2036
+ const groupParent = parentElements[index];
2037
+ setAbstractByElements(board, groupParent, group);
2038
+ });
2039
+ };
2040
+ const setAbstractByElements = (board, groupParent, group) => {
2041
+ const indexArray = group.map(child => groupParent.children.indexOf(child)).sort((a, b) => a - b);
2042
+ const rightNodeCount = groupParent?.rightNodeCount;
2043
+ const start = indexArray[0], end = indexArray[indexArray.length - 1];
2044
+ if (isStandardLayout(MindQueries.getLayoutByElement(groupParent)) &&
2045
+ rightNodeCount &&
2046
+ start < rightNodeCount &&
2047
+ end >= rightNodeCount) {
2048
+ const childrenLength = groupParent.children.length;
2049
+ const path = [...PlaitBoard.findPath(board, groupParent), childrenLength];
2050
+ const leftChildren = indexArray.filter(index => index >= rightNodeCount);
2051
+ const rightChildren = indexArray.filter(index => index < rightNodeCount);
2052
+ insertAbstractNode(board, path, rightChildren[0], rightChildren[rightChildren.length - 1]);
2053
+ insertAbstractNode(board, Path.next(path), leftChildren[0], leftChildren[leftChildren.length - 1]);
2054
+ }
2055
+ else {
2056
+ const path = [...PlaitBoard.findPath(board, groupParent), groupParent.children.length];
2057
+ insertAbstractNode(board, path, start, end);
2058
+ }
2059
+ };
2060
+ const insertAbstractNode = (board, path, start, end) => {
2061
+ const mindElement = createMindElement('概要', 28, 20, {
2062
+ strokeColor: DefaultAbstractNodeStyle.strokeColor,
2063
+ strokeWidth: DefaultAbstractNodeStyle.branchWidth,
2064
+ branchColor: DefaultAbstractNodeStyle.branchColor,
2065
+ branchWidth: DefaultAbstractNodeStyle.branchWidth
2066
+ });
2067
+ mindElement.start = start;
2068
+ mindElement.end = end;
2069
+ Transforms.insertNode(board, mindElement, path);
2070
+ };
2071
+
2072
+ const setLayout = (board, layout, path) => {
2073
+ correctLogicLayoutNode(board, layout, path);
2074
+ const element = PlaitNode.get(board, path);
2075
+ if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
2076
+ MindTransforms.setAbstractByStandardLayout(board, element);
2077
+ }
2078
+ Transforms.setNode(board, { layout }, path);
2079
+ };
2080
+ const correctLogicLayoutNode = (board, layout, path) => {
2081
+ const node = PlaitNode.get(board, path);
2082
+ if (node && layout) {
2083
+ node.children?.forEach((value, index) => {
2084
+ if (value.layout) {
2085
+ if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
2086
+ (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
2087
+ Transforms.setNode(board, { layout: null }, [...path, index]);
2088
+ }
2089
+ if (value.children?.length) {
2090
+ correctLogicLayoutNode(board, layout, [...path, index]);
2091
+ }
2092
+ }
2093
+ });
2094
+ }
2095
+ };
2096
+
2097
+ const setTopic = (board, element, topic, width, height) => {
2098
+ const newElement = {
2099
+ data: { topic },
2100
+ width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2101
+ height: height / board.viewport.zoom
2102
+ };
2103
+ if (MindElement.hasEmojis(element)) {
2104
+ newElement.data.emojis = element.data.emojis;
2105
+ }
2106
+ const path = PlaitBoard.findPath(board, element);
2107
+ Transforms.setNode(board, newElement, path);
2108
+ };
2109
+ const setTopicSize = (board, element, width, height) => {
2110
+ const newElement = {
2111
+ width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2112
+ height: height / board.viewport.zoom
2113
+ };
2114
+ const path = PlaitBoard.findPath(board, element);
2115
+ Transforms.setNode(board, newElement, path);
2116
+ };
2117
+ const removeElements = (board, elements) => {
2118
+ const deletableElements = getFirstLevelElement(elements).reverse();
2119
+ //翻转,从下到上修改,防止找不到 path
2120
+ deletableElements
2121
+ .map(element => {
2122
+ const path = PlaitBoard.findPath(board, element);
2123
+ return () => {
2124
+ if (isInRightBranchOfStandardLayout(element)) {
2125
+ changeRightNodeCount(board, path.slice(0, 1), -1);
2126
+ }
2127
+ Transforms.removeNode(board, path);
2128
+ };
2129
+ })
2130
+ .forEach(action => {
2131
+ action();
2132
+ });
2133
+ };
2134
+ const insertNodes = (board, elements, path) => {
2135
+ const pathRef = board.pathRef(path);
2136
+ elements.forEach(element => {
2137
+ if (pathRef.current) {
2138
+ Transforms.insertNode(board, element, pathRef.current);
2308
2139
  }
2309
- return undefined;
2140
+ });
2141
+ pathRef.unref();
2142
+ };
2143
+ const insertAbstractNodes = (board, validAbstractRefs, elements, path) => {
2144
+ const parent = PlaitNode.get(board, Path$1.parent(path));
2145
+ const abstractPath = [...Path$1.parent(path), parent.children?.length];
2146
+ const abstracts = validAbstractRefs.map(refs => {
2147
+ const { start, end } = getRelativeStartEndByAbstractRef(refs, elements);
2148
+ return {
2149
+ ...refs.abstract,
2150
+ start: start + path[path.length - 1],
2151
+ end: end + path[path.length - 1]
2152
+ };
2153
+ });
2154
+ insertNodes(board, abstracts, abstractPath);
2155
+ };
2156
+
2157
+ const addEmoji = (board, element, emojiItem) => {
2158
+ const emojis = element.data.emojis || [];
2159
+ const newEmojis = [...emojis];
2160
+ newEmojis.push(emojiItem);
2161
+ const newElement = {
2162
+ data: { topic: element.data.topic, emojis: newEmojis }
2163
+ };
2164
+ const path = PlaitBoard.findPath(board, element);
2165
+ Transforms.setNode(board, newElement, path);
2166
+ };
2167
+ const removeEmoji = (board, element, emojiItem) => {
2168
+ const emojis = element.data.emojis.filter(value => value !== emojiItem);
2169
+ const newElement = {
2170
+ data: { topic: element.data.topic }
2171
+ };
2172
+ if (emojis.length > 0) {
2173
+ newElement.data.emojis = emojis;
2310
2174
  }
2311
- destroy() {
2312
- if (this.g) {
2313
- this.g.remove();
2175
+ const path = PlaitBoard.findPath(board, element);
2176
+ Transforms.setNode(board, newElement, path);
2177
+ };
2178
+ const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2179
+ const newElement = {
2180
+ data: { topic: element.data.topic }
2181
+ };
2182
+ const newEmojis = element.data.emojis.map(value => {
2183
+ if (value === oldEmoji) {
2184
+ return newEmoji;
2314
2185
  }
2315
- this.emojiDrawers.forEach(drawer => drawer.destroy());
2316
- this.emojiDrawers = [];
2317
- }
2318
- }
2186
+ return value;
2187
+ });
2188
+ newElement.data.emojis = newEmojis;
2189
+ const path = PlaitBoard.findPath(board, element);
2190
+ Transforms.setNode(board, newElement, path);
2191
+ };
2192
+
2193
+ const MindTransforms = {
2194
+ setLayout,
2195
+ setTopic,
2196
+ setTopicSize,
2197
+ addEmoji,
2198
+ removeEmoji,
2199
+ replaceEmoji,
2200
+ insertAbstract,
2201
+ setAbstractsByRefs,
2202
+ setAbstractByStandardLayout,
2203
+ removeElements,
2204
+ insertNodes,
2205
+ insertAbstractNodes
2206
+ };
2319
2207
 
2320
2208
  function drawAbstractIncludedOutline(board, roughSVG, element, activeHandlePosition, resizingLocation) {
2321
2209
  const abstractIncludedG = createG();
@@ -2340,10 +2228,10 @@ function drawAbstractIncludedOutline(board, roughSVG, element, activeHandlePosit
2340
2228
  transformPlacement(endPlacement, linkDirection);
2341
2229
  let startCenterPoint = getPointByPlacement(abstractRectangle, startPlacement);
2342
2230
  let endCenterPoint = getPointByPlacement(abstractRectangle, endPlacement);
2343
- const startPoint1 = movePoint(startCenterPoint, -ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2344
- const startPoint2 = movePoint(startCenterPoint, ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2345
- const endPoint1 = movePoint(endCenterPoint, -ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2346
- const endPoint2 = movePoint(endCenterPoint, ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2231
+ const startPoint1 = moveXOfPoint(startCenterPoint, -ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2232
+ const startPoint2 = moveXOfPoint(startCenterPoint, ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2233
+ const endPoint1 = moveXOfPoint(endCenterPoint, -ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2234
+ const endPoint2 = moveXOfPoint(endCenterPoint, ABSTRACT_HANDLE_LENGTH / 2, linkDirection);
2347
2235
  const startHandle = roughSVG.line(startPoint1[0], startPoint1[1], startPoint2[0], startPoint2[1], getHandleOption(activeHandlePosition === AbstractHandlePosition.start));
2348
2236
  const endHandle = roughSVG.line(endPoint1[0], endPoint1[1], endPoint2[0], endPoint2[1], getHandleOption(activeHandlePosition === AbstractHandlePosition.end));
2349
2237
  changeBoardClass(board, activeHandlePosition, isHorizontal);
@@ -2694,7 +2582,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2694
2582
  const shape = getShapeByElement(this.board, this.node.origin);
2695
2583
  switch (shape) {
2696
2584
  case MindElementShape.roundRectangle:
2697
- this.shapeG = drawRectangleNode(this.board, this.node);
2585
+ this.shapeG = drawRoundRectangleByNode(this.board, this.node);
2698
2586
  this.g.prepend(this.shapeG);
2699
2587
  break;
2700
2588
  default:
@@ -2850,7 +2738,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2850
2738
  }
2851
2739
  }
2852
2740
  drawRichtext() {
2853
- const { richtextG, richtextComponentRef, foreignObject } = drawMindNodeRichtext(this.board, this.node, this.viewContainerRef);
2741
+ const { richtextG, richtextComponentRef, foreignObject } = drawTopicByNode(this.board, this.node, this.viewContainerRef);
2854
2742
  this.richtextComponentRef = richtextComponentRef;
2855
2743
  this.richtextG = richtextG;
2856
2744
  this.foreignObject = foreignObject;
@@ -2871,7 +2759,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2871
2759
  }
2872
2760
  // interactive
2873
2761
  fromEvent(collapseG, 'mouseup')
2874
- .pipe(filter(() => !this.handActive || this.board.options.readonly), take(1))
2762
+ .pipe(filter(() => !this.handActive || !PlaitBoard.isReadonly(this.board)), take(1))
2875
2763
  .subscribe(() => {
2876
2764
  const isCollapsed = !this.node.origin.isCollapsed;
2877
2765
  const newElement = { isCollapsed };
@@ -3052,7 +2940,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
3052
2940
  });
3053
2941
  const mousedown$ = fromEvent(document, 'mousedown').subscribe((event) => {
3054
2942
  const point = transformPoint(this.board, toPoint(event.x, event.y, PlaitBoard.getHost(this.board)));
3055
- const clickInNode = hitMindElement(this.board, point, this.element);
2943
+ const clickInNode = isHitMindElement(this.board, point, this.element);
3056
2944
  if (clickInNode && !hasEditableTarget(richtextInstance.editor, event.target)) {
3057
2945
  event.preventDefault();
3058
2946
  }
@@ -3115,6 +3003,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
3115
3003
  super.ngOnDestroy();
3116
3004
  this.abstractIncludedOutlineG?.remove();
3117
3005
  this.destroyRichtext();
3006
+ this.emojisDrawer.destroy();
3118
3007
  this.destroy$.next();
3119
3008
  this.destroy$.complete();
3120
3009
  if (ELEMENT_TO_NODE.get(this.element) === this.node) {
@@ -3169,7 +3058,7 @@ const getLayoutOptions = (board) => {
3169
3058
  }
3170
3059
  return {
3171
3060
  getHeight(element) {
3172
- return NodeSpace.getNodeHeight(element);
3061
+ return NodeSpace.getNodeHeight(board, element);
3173
3062
  },
3174
3063
  getWidth(element) {
3175
3064
  return NodeSpace.getNodeWidth(board, element);
@@ -3260,141 +3149,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3260
3149
  class MindModule {
3261
3150
  }
3262
3151
  MindModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3263
- MindModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: MindModule, declarations: [PlaitMindComponent, MindNodeComponent], imports: [BrowserModule, RichtextModule, PlaitModule], exports: [PlaitMindComponent, MindNodeComponent] });
3264
- MindModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, imports: [BrowserModule, RichtextModule, PlaitModule] });
3152
+ MindModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: MindModule, declarations: [PlaitMindComponent, MindNodeComponent], imports: [CommonModule, RichtextModule, PlaitModule], exports: [PlaitMindComponent, MindNodeComponent] });
3153
+ MindModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, imports: [CommonModule, RichtextModule, PlaitModule] });
3265
3154
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, decorators: [{
3266
3155
  type: NgModule,
3267
3156
  args: [{
3268
3157
  declarations: [PlaitMindComponent, MindNodeComponent],
3269
- imports: [BrowserModule, RichtextModule, PlaitModule],
3158
+ imports: [CommonModule, RichtextModule, PlaitModule],
3270
3159
  exports: [PlaitMindComponent, MindNodeComponent]
3271
3160
  }]
3272
3161
  }] });
3273
3162
 
3274
- const isValidTarget = (origin, target) => {
3275
- return origin !== target && !isChildElement(origin, target);
3276
- };
3277
- const addActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3278
- const activeComponent = PlaitElement.getComponent(activeElement);
3279
- if (isOrigin) {
3280
- activeComponent.g.classList.add('dragging-origin');
3281
- }
3282
- else {
3283
- activeComponent.g.classList.add('dragging-child');
3284
- }
3285
- !activeElement.isCollapsed &&
3286
- activeElement.children.forEach(child => {
3287
- addActiveOnDragOrigin(child, false);
3288
- });
3289
- };
3290
- const removeActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3291
- const activeComponent = PlaitElement.getComponent(activeElement);
3292
- if (isOrigin) {
3293
- activeComponent.g.classList.remove('dragging-origin');
3294
- }
3295
- else {
3296
- activeComponent.g.classList.remove('dragging-child');
3297
- }
3298
- !activeElement.isCollapsed &&
3299
- activeElement.children.forEach(child => {
3300
- removeActiveOnDragOrigin(child, false);
3301
- });
3302
- };
3303
- const updatePathByLayoutAndDropTarget = (targetPath, layout, dropTarget) => {
3304
- // 上下布局:左右是兄弟节点,上下是子节点
3305
- if (isVerticalLogicLayout(layout)) {
3306
- if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3307
- targetPath.push(dropTarget.target.children.length);
3308
- }
3309
- if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3310
- targetPath.push(dropTarget.target.children.length);
3311
- }
3312
- // 如果是左,位置不变,右则插入到下一个兄弟节点
3313
- if (dropTarget.detectResult === 'right') {
3314
- targetPath = Path.next(targetPath);
3315
- }
3316
- }
3317
- // 水平布局/标准布局:上下是兄弟节点,左右是子节点
3318
- if (isHorizontalLogicLayout(layout)) {
3319
- if (dropTarget.detectResult === 'right') {
3320
- targetPath.push(dropTarget.target.children.length);
3321
- }
3322
- if (dropTarget.detectResult === 'left') {
3323
- targetPath.push(dropTarget.target.children.length);
3324
- }
3325
- // 如果是上,位置不变,下插入到下一个兄弟节点
3326
- if (dropTarget.detectResult === 'bottom') {
3327
- targetPath = Path.next(targetPath);
3328
- }
3329
- }
3330
- // 缩进布局:上下是兄弟节点,左右是子节点,但上(左上/右上),探测到上是子节点,下则位置不变,反之同理。
3331
- if (isIndentedLayout(layout)) {
3332
- if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3333
- targetPath = Path.next(targetPath);
3334
- }
3335
- if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3336
- targetPath = Path.next(targetPath);
3337
- }
3338
- if (isLeftLayout(layout) && dropTarget.detectResult === 'left') {
3339
- targetPath.push(dropTarget.target.children.length);
3340
- }
3341
- if (isRightLayout(layout) && dropTarget.detectResult === 'right') {
3342
- targetPath.push(dropTarget.target.children.length);
3343
- }
3344
- }
3345
- return targetPath;
3346
- };
3347
- const updateRightNodeCount = (board, activeComponent, targetComponent, detectResult) => {
3348
- let rightNodeCount;
3349
- const mindElement = findUpElement(targetComponent.node.origin).root;
3350
- const mindComponent = ELEMENT_TO_COMPONENT.get(mindElement);
3351
- const activeIndex = mindComponent?.root.children.indexOf(activeComponent.node);
3352
- const targetIndex = mindComponent?.root.children.indexOf(targetComponent.node);
3353
- const activeParent = MindElement.getParent(activeComponent.element);
3354
- const targetParent = MindElement.findParent(targetComponent.element);
3355
- const isActiveOnRight = activeIndex !== -1 && activeIndex <= activeParent.rightNodeCount - 1;
3356
- const isTargetOnRight = targetParent && targetIndex !== -1 && targetIndex <= targetParent.rightNodeCount - 1;
3357
- const isBothOnRight = isActiveOnRight && isTargetOnRight;
3358
- const rootChildCount = mindComponent.root.children?.length;
3359
- const rootRightNodeCount = mindComponent?.root.origin.rightNodeCount;
3360
- if (!isBothOnRight) {
3361
- if (isActiveOnRight) {
3362
- rightNodeCount = rootChildCount < rootRightNodeCount ? rootChildCount - 1 : rootRightNodeCount - 1;
3363
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, activeParent));
3364
- }
3365
- if (isTargetOnRight && detectResult !== 'right') {
3366
- rightNodeCount = rootChildCount < rootRightNodeCount ? rootRightNodeCount : rootRightNodeCount + 1;
3367
- const parent = MindElement.getParent(targetComponent.element);
3368
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, parent));
3369
- }
3370
- //二级子节点拖动到根节点左侧
3371
- if (targetComponent.node.origin.isRoot && detectResult === 'left' && activeIndex === -1) {
3372
- rightNodeCount = rootChildCount;
3373
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.element));
3374
- }
3375
- }
3376
- };
3377
- const IS_DRAGGING = new WeakMap();
3378
- const isDragging = (board) => {
3379
- return !!IS_DRAGGING.get(board);
3380
- };
3381
- const setIsDragging = (board, state) => {
3382
- IS_DRAGGING.set(board, state);
3383
- };
3384
- const updateAbstractInDnd = (board, deletableElements, originPath) => {
3385
- const refs = insertElementHandleAbstract(board, originPath, false);
3386
- deleteElementHandleAbstract(board, deletableElements, refs);
3387
- MindTransforms.setAbstractsByRefs(board, refs);
3388
- };
3389
-
3390
3163
  const DRAG_MOVE_BUFFER = 5;
3391
3164
  const withDnd = (board) => {
3392
- const { mousedown, mousemove, globalMouseup, keydown } = board;
3393
- let activeElement;
3165
+ const { mousedown, mousemove, globalMouseup } = board;
3166
+ let activeElements = [];
3167
+ let correspondingElements = [];
3394
3168
  let startPoint;
3395
- let fakeDragNodeG;
3169
+ let dragFakeNodeG;
3396
3170
  let fakeDropNodeG;
3397
3171
  let dropTarget = null;
3172
+ let targetPath;
3398
3173
  board.mousedown = (event) => {
3399
3174
  if (board.options.readonly || IS_TEXT_EDITABLE.get(board) || event.button === 2) {
3400
3175
  mousedown(event);
@@ -3403,156 +3178,137 @@ const withDnd = (board) => {
3403
3178
  // 确认是否 hit 节点
3404
3179
  const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3405
3180
  const selectedElements = getSelectedElements(board);
3406
- board.children.forEach((value) => {
3407
- if (activeElement) {
3181
+ depthFirstRecursion(board, element => {
3182
+ if (activeElements.length || !MindElement.isMindElement(board, element)) {
3408
3183
  return;
3409
3184
  }
3410
- if (PlaitMind.isMind(value)) {
3411
- const mindComponent = ELEMENT_TO_COMPONENT.get(value);
3412
- const root = mindComponent.root;
3413
- root.eachNode((node) => {
3414
- if (activeElement) {
3415
- return;
3416
- }
3417
- const canDrag = hitMindElement(board, point, node.origin) &&
3418
- !node.origin.isRoot &&
3419
- !AbstractNode.isAbstract(node.origin) &&
3420
- selectedElements.length <= 1;
3421
- if (canDrag) {
3422
- activeElement = node.origin;
3423
- startPoint = point;
3424
- }
3425
- });
3185
+ const isHitElement = isHitMindElement(board, point, element) && !element.isRoot && !AbstractNode.isAbstract(element);
3186
+ const isAllMindElement = selectedElements.every(element => MindElement.isMindElement(board, element));
3187
+ const isMultiple = isHitElement && selectedElements.length > 1 && selectedElements.includes(element) && isAllMindElement;
3188
+ const isSingle = isHitElement && !(selectedElements.length > 1 && selectedElements.includes(element));
3189
+ if (isSingle) {
3190
+ activeElements = [element];
3191
+ startPoint = point;
3192
+ }
3193
+ else if (isMultiple) {
3194
+ activeElements = getFirstLevelElement(selectedElements);
3195
+ startPoint = point;
3196
+ }
3197
+ }, node => {
3198
+ if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
3199
+ return true;
3200
+ }
3201
+ else {
3202
+ return false;
3426
3203
  }
3427
3204
  });
3428
- if (activeElement) {
3429
- event.preventDefault();
3205
+ if (activeElements.length) {
3206
+ correspondingElements = getOverallAbstracts(board, activeElements);
3430
3207
  }
3431
3208
  mousedown(event);
3432
3209
  };
3433
3210
  board.mousemove = (event) => {
3434
- if (!board.options.readonly && activeElement && startPoint) {
3211
+ if (!board.options.readonly && activeElements?.length && startPoint) {
3435
3212
  const endPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3436
3213
  const distance = distanceBetweenPointAndPoint(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
3437
3214
  if (distance < DRAG_MOVE_BUFFER) {
3438
3215
  return;
3439
3216
  }
3440
- if (!isDragging(board)) {
3441
- setIsDragging(board, true);
3442
- fakeDragNodeG = createG();
3443
- fakeDragNodeG.classList.add('dragging', 'fake-node', 'plait-board-attached');
3444
- fakeDropNodeG = createG();
3445
- addActiveOnDragOrigin(activeElement);
3217
+ setIsDragging(board, true);
3218
+ fakeDropNodeG?.remove();
3219
+ const detectPoint = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3220
+ dropTarget = detectDropTarget(board, detectPoint, dropTarget, [...activeElements, ...correspondingElements]);
3221
+ if (dropTarget?.target) {
3222
+ targetPath = getPathByDropTarget(board, dropTarget);
3223
+ fakeDropNodeG = drawFakeDropNodeByPath(board, dropTarget.target, targetPath);
3446
3224
  PlaitBoard.getHost(board).appendChild(fakeDropNodeG);
3447
- PlaitBoard.getHost(board).appendChild(fakeDragNodeG);
3448
- }
3449
- else {
3450
- if (fakeDragNodeG) {
3451
- fakeDragNodeG.innerHTML = '';
3452
- }
3453
- fakeDropNodeG?.childNodes.forEach(node => {
3454
- node.remove();
3455
- });
3456
3225
  }
3457
- // fake dragging origin node
3458
3226
  const offsetX = endPoint[0] - startPoint[0];
3459
3227
  const offsetY = endPoint[1] - startPoint[1];
3460
- const activeComponent = PlaitElement.getComponent(activeElement);
3461
- const fakeDraggingNode = {
3462
- ...activeComponent.node,
3463
- children: [],
3464
- x: activeComponent.node.x + offsetX,
3465
- y: activeComponent.node.y + offsetY
3466
- };
3467
- const textRectangle = getRichtextRectangleByNode(board, activeComponent.node);
3468
- const fakeNodeG = drawRectangleNode(board, fakeDraggingNode);
3469
- const richtextG = activeComponent.richtextG?.cloneNode(true);
3470
- updateForeignObject$1(richtextG, textRectangle.width, textRectangle.height, textRectangle.x + offsetX, textRectangle.y + offsetY);
3471
- fakeDragNodeG?.append(fakeNodeG);
3472
- fakeDragNodeG?.append(richtextG);
3473
- // draw emojis
3474
- if (MindElement.hasEmojis(activeElement)) {
3475
- const fakeEmojisG = activeComponent.emojisDrawer.g.cloneNode(true);
3476
- const foreignRectangle = getEmojiForeignRectangle(board, activeElement);
3477
- updateForeignObject$1(fakeEmojisG, foreignRectangle.width, foreignRectangle.height, foreignRectangle.x + offsetX, foreignRectangle.y + offsetY);
3478
- fakeDragNodeG?.append(fakeEmojisG);
3479
- }
3480
- // drop position detect
3481
- const { x, y } = getRectangleByNode(fakeDraggingNode);
3482
- const detectCenterPoint = [x + textRectangle.width / 2, y + textRectangle.height / 2];
3483
- let detectResult = null;
3484
- board.children.forEach((value) => {
3485
- if (detectResult) {
3486
- return;
3487
- }
3488
- if (PlaitMind.isMind(value)) {
3489
- const mindmapComponent = ELEMENT_TO_COMPONENT.get(value);
3490
- const root = mindmapComponent?.root;
3491
- root.eachNode((node) => {
3492
- if (detectResult) {
3493
- return;
3494
- }
3495
- const directions = directionDetector(node, detectCenterPoint);
3496
- if (directions) {
3497
- detectResult = directionCorrector(board, node, directions);
3498
- }
3499
- dropTarget = null;
3500
- if (detectResult && isValidTarget(activeComponent.node.origin, node.origin)) {
3501
- dropTarget = { target: node.origin, detectResult: detectResult[0] };
3502
- }
3503
- });
3228
+ dragFakeNodeG?.remove();
3229
+ dragFakeNodeG = createG();
3230
+ [...activeElements, ...correspondingElements].forEach(element => {
3231
+ addActiveOnDragOrigin(element);
3232
+ if (activeElements.includes(element)) {
3233
+ const activeComponent = PlaitElement.getComponent(element);
3234
+ const nodeG = drawFakeDragNode(board, activeComponent, offsetX, offsetY);
3235
+ dragFakeNodeG?.appendChild(nodeG);
3504
3236
  }
3505
3237
  });
3506
- if (dropTarget?.target) {
3507
- dropTarget = readjustmentDropTarget(board, dropTarget);
3508
- drawPlaceholderDropNodeG(board, dropTarget, fakeDropNodeG);
3509
- }
3238
+ PlaitBoard.getHost(board).appendChild(dragFakeNodeG);
3510
3239
  }
3511
3240
  mousemove(event);
3512
3241
  };
3513
3242
  board.globalMouseup = (event) => {
3514
- if (!board.options.readonly && activeElement) {
3515
- if (dropTarget?.target) {
3516
- const activeComponent = PlaitElement.getComponent(activeElement);
3517
- const targetComponent = PlaitElement.getComponent(dropTarget.target);
3518
- let targetPath = PlaitBoard.findPath(board, targetComponent.element);
3519
- const mindElement = findUpElement(dropTarget.target).root;
3520
- const mindComponent = ELEMENT_TO_COMPONENT.get(mindElement);
3521
- const layout = MindQueries.getCorrectLayoutByElement(board, mindComponent?.root.origin);
3522
- targetPath = updatePathByLayoutAndDropTarget(targetPath, layout, dropTarget);
3523
- const originPath = PlaitBoard.findPath(board, activeComponent.element);
3524
- let newElement = { isCollapsed: false }, rightTargetPath = PlaitBoard.findPath(board, targetComponent.element);
3525
- updateAbstractInDnd(board, [activeElement], targetPath);
3526
- if (isStandardLayout(layout)) {
3527
- updateRightNodeCount(board, activeComponent, targetComponent, dropTarget.detectResult);
3528
- }
3529
- if (dropTarget.detectResult === 'right') {
3530
- if (targetComponent.node.origin.isRoot) {
3531
- targetPath = PlaitBoard.findPath(board, targetComponent.element);
3532
- targetPath.push(0);
3533
- const rightNodeCount = targetComponent.node.origin.rightNodeCount + 1;
3534
- newElement = { isCollapsed: false, rightNodeCount };
3243
+ if (!board.options.readonly && activeElements?.length) {
3244
+ const elements = [...activeElements, ...correspondingElements];
3245
+ if (isDragging(board)) {
3246
+ elements.forEach(element => removeActiveOnDragOrigin(element));
3247
+ }
3248
+ if (dropTarget) {
3249
+ const targetPathRef = board.pathRef(targetPath);
3250
+ const targetElementPathRef = board.pathRef(PlaitBoard.findPath(board, dropTarget.target));
3251
+ const abstractRefs = getValidAbstractRefs(board, elements);
3252
+ const normalElements = elements
3253
+ .filter(element => !abstractRefs.some(refs => refs.abstract === element))
3254
+ .map(element => {
3255
+ if (AbstractNode.isAbstract(element)) {
3256
+ return adjustAbstractToNode(element);
3257
+ }
3258
+ if (PlaitMind.isMind(element)) {
3259
+ return adjustRootToNode(board, element);
3535
3260
  }
3536
- Transforms.setNode(board, newElement, rightTargetPath);
3261
+ return element;
3262
+ });
3263
+ const effectedAbstracts = deleteElementHandleAbstract(board, elements);
3264
+ insertElementHandleAbstract(board, targetPath, normalElements.length, false, effectedAbstracts);
3265
+ MindTransforms.setAbstractsByRefs(board, effectedAbstracts);
3266
+ MindTransforms.removeElements(board, elements);
3267
+ let insertPath = targetPathRef.current;
3268
+ const parentPath = Path.parent(targetPathRef.current || targetPath);
3269
+ if (!insertPath) {
3270
+ const parent = PlaitNode.get(board, parentPath);
3271
+ const children = getNonAbstractChildren(parent);
3272
+ insertPath = [...parentPath, children.length || 0];
3537
3273
  }
3538
- Transforms.moveNode(board, originPath, targetPath);
3539
- }
3540
- if (isDragging(board)) {
3541
- removeActiveOnDragOrigin(activeElement);
3274
+ MindTransforms.insertNodes(board, normalElements, insertPath);
3275
+ if (abstractRefs.length) {
3276
+ MindTransforms.insertAbstractNodes(board, abstractRefs, normalElements, insertPath);
3277
+ }
3278
+ const shouldChangeRoot = isInRightBranchOfStandardLayout(dropTarget?.target) &&
3279
+ targetElementPathRef.current &&
3280
+ (Path.isSibling(targetPath, targetElementPathRef.current) || Path.equals(targetPath, targetElementPathRef.current));
3281
+ if (shouldChangeRoot && targetElementPathRef.current) {
3282
+ changeRightNodeCount(board, targetElementPathRef.current.slice(0, 1), normalElements.length);
3283
+ }
3284
+ if (targetElementPathRef.current &&
3285
+ targetPathRef.current &&
3286
+ Path.isAncestor(targetElementPathRef.current, targetPathRef.current) &&
3287
+ dropTarget.target.isCollapsed) {
3288
+ Transforms.setNode(board, { isCollapsed: false }, targetElementPathRef.current);
3289
+ }
3290
+ targetElementPathRef.unref();
3291
+ targetPathRef.unref();
3292
+ const selectedElements = getSelectedElements(board);
3293
+ let setActiveElements = [];
3294
+ depthFirstRecursion(board, node => {
3295
+ const isSelected = selectedElements.some(element => element.id === node.id);
3296
+ if (isSelected) {
3297
+ setActiveElements.push(node);
3298
+ }
3299
+ });
3300
+ Transforms.setSelectionWithTemporaryElements(board, setActiveElements);
3542
3301
  }
3543
3302
  setIsDragging(board, false);
3544
- activeElement = null;
3545
- fakeDragNodeG?.remove();
3546
- fakeDragNodeG = undefined;
3303
+ activeElements = [];
3304
+ dragFakeNodeG?.remove();
3305
+ dragFakeNodeG = undefined;
3547
3306
  fakeDropNodeG?.remove();
3548
3307
  fakeDropNodeG = undefined;
3549
3308
  dropTarget = null;
3550
3309
  }
3551
3310
  globalMouseup(event);
3552
3311
  };
3553
- board.keydown = (event) => {
3554
- keydown(event);
3555
- };
3556
3312
  return board;
3557
3313
  };
3558
3314
 
@@ -3560,16 +3316,11 @@ const buildClipboardData = (board, selectedElements) => {
3560
3316
  let result = [];
3561
3317
  // get overall abstract
3562
3318
  const overallAbstracts = getOverallAbstracts(board, selectedElements);
3319
+ // get valid abstract refs
3320
+ const validAbstractRefs = getValidAbstractRefs(board, [...selectedElements, ...overallAbstracts]);
3563
3321
  // keep correct order
3564
- const newSelectedElements = selectedElements.filter((value) => !overallAbstracts.includes(value));
3565
- newSelectedElements.push(...overallAbstracts);
3566
- // get correct start and end in selected elements
3567
- function getCorrectStartEnd(abstract) {
3568
- const parent = MindElement.getParent(abstract);
3569
- const startElement = parent.children[abstract.start];
3570
- const index = selectedElements.indexOf(startElement);
3571
- return { start: index, end: index + (abstract.end - abstract.start) };
3572
- }
3322
+ const newSelectedElements = selectedElements.filter(value => !validAbstractRefs.find(ref => ref.abstract === value));
3323
+ newSelectedElements.push(...validAbstractRefs.map(value => value.abstract));
3573
3324
  const selectedMindNodes = newSelectedElements.map(value => MindElement.getNode(value));
3574
3325
  const nodesRectangle = getRectangleByElements(board, newSelectedElements, true);
3575
3326
  newSelectedElements.forEach((element, index) => {
@@ -3577,8 +3328,9 @@ const buildClipboardData = (board, selectedElements) => {
3577
3328
  const nodeRectangle = getRectangleByNode(selectedMindNodes[index]);
3578
3329
  const points = [[nodeRectangle.x - nodesRectangle.x, nodeRectangle.y - nodesRectangle.y]];
3579
3330
  // handle invalid abstract
3580
- if (AbstractNode.isAbstract(element) && overallAbstracts.includes(element)) {
3581
- const { start, end } = getCorrectStartEnd(element);
3331
+ const abstractRef = validAbstractRefs.find(ref => ref.abstract === element);
3332
+ if (AbstractNode.isAbstract(element) && abstractRef) {
3333
+ const { start, end } = getRelativeStartEndByAbstractRef(abstractRef, newSelectedElements);
3582
3334
  result.push({
3583
3335
  ...element,
3584
3336
  points,
@@ -3633,7 +3385,7 @@ const insertClipboardData = (board, elements, targetPoint) => {
3633
3385
  newElement = copyNewNode(item);
3634
3386
  if (hasTargetParent) {
3635
3387
  if (item.isRoot) {
3636
- newElement = transformRootToNode(board, newElement);
3388
+ newElement = adjustRootToNode(board, newElement);
3637
3389
  }
3638
3390
  // handle abstract start and end
3639
3391
  if (AbstractNode.isAbstract(newElement)) {
@@ -3646,10 +3398,10 @@ const insertClipboardData = (board, elements, targetPoint) => {
3646
3398
  const point = [targetPoint[0] + item.points[0][0], targetPoint[1] + item.points[0][1]];
3647
3399
  newElement.points = [point];
3648
3400
  if (AbstractNode.isAbstract(item)) {
3649
- newElement = transformAbstractToNode(newElement);
3401
+ newElement = adjustAbstractToNode(newElement);
3650
3402
  }
3651
3403
  if (!item.isRoot) {
3652
- newElement = transformNodeToRoot(board, newElement);
3404
+ newElement = adjustNodeToRoot(board, newElement);
3653
3405
  }
3654
3406
  path = [board.children.length];
3655
3407
  }
@@ -3680,8 +3432,8 @@ const withAbstract = (board) => {
3680
3432
  const point = transformPoint(board, toPoint(event.x, event.y, host));
3681
3433
  activeAbstractElement = activeAbstractElements.find(element => {
3682
3434
  abstractHandlePosition = getHitAbstractHandle(board, element, point);
3683
- if (newBoard?.abstractResize) {
3684
- newBoard.abstractResize(AbstractResizeState.start);
3435
+ if (newBoard?.onAbstractResize) {
3436
+ newBoard.onAbstractResize(AbstractResizeState.start);
3685
3437
  }
3686
3438
  return abstractHandlePosition;
3687
3439
  });
@@ -3715,8 +3467,8 @@ const withAbstract = (board) => {
3715
3467
  children = leftChildren;
3716
3468
  }
3717
3469
  }
3718
- if (newBoard?.abstractResize) {
3719
- newBoard.abstractResize(AbstractResizeState.resizing);
3470
+ if (newBoard?.onAbstractResize) {
3471
+ newBoard.onAbstractResize(AbstractResizeState.resizing);
3720
3472
  }
3721
3473
  const resizingLocation = isHorizontal ? endPoint[1] : endPoint[0];
3722
3474
  const parent = MindElement.getNode(parentElement);
@@ -3748,8 +3500,8 @@ const withAbstract = (board) => {
3748
3500
  startPoint = undefined;
3749
3501
  abstractHandlePosition = undefined;
3750
3502
  if (activeAbstractElement) {
3751
- if (newBoard?.abstractResize) {
3752
- newBoard.abstractResize(AbstractResizeState.end);
3503
+ if (newBoard?.onAbstractResize) {
3504
+ newBoard.onAbstractResize(AbstractResizeState.end);
3753
3505
  }
3754
3506
  if (newProperty) {
3755
3507
  const path = PlaitBoard.findPath(board, activeAbstractElement);
@@ -3766,7 +3518,7 @@ const withAbstract = (board) => {
3766
3518
  return board;
3767
3519
  };
3768
3520
 
3769
- const withExtendMind = (board) => {
3521
+ const withMindExtend = (board) => {
3770
3522
  const newBoard = board;
3771
3523
  newBoard.drawEmoji = (emoji, element) => {
3772
3524
  throw new Error('Not implement drawEmoji method error.');
@@ -3777,6 +3529,85 @@ const withExtendMind = (board) => {
3777
3529
  return newBoard;
3778
3530
  };
3779
3531
 
3532
+ const DefaultHotkey = 'm';
3533
+ const withCreateMind = (board) => {
3534
+ const newBoard = board;
3535
+ const { keydown, mousemove, mouseup } = board;
3536
+ let fakeCreateNodeRef = null;
3537
+ newBoard.mousemove = (event) => {
3538
+ if (PlaitBoard.isReadonly(board)) {
3539
+ mousemove(event);
3540
+ return;
3541
+ }
3542
+ if (PlaitBoard.isPointer(board, MindPointerType.mind)) {
3543
+ throttleRAF(() => {
3544
+ const movingPoint = PlaitBoard.getMovingPoint(board);
3545
+ if (movingPoint) {
3546
+ const targetPoint = transformPoint(board, toPoint(movingPoint[0], movingPoint[1], PlaitBoard.getHost(board)));
3547
+ const emptyMind = createEmptyMind(board, targetPoint);
3548
+ const nodeRectangle = getRectangleByElement(newBoard, targetPoint, emptyMind);
3549
+ const nodeG = drawRoundRectangleByElement(board, nodeRectangle, emptyMind);
3550
+ const topicRectangle = getTopicRectangleByElement(newBoard, nodeRectangle, emptyMind);
3551
+ if (!fakeCreateNodeRef) {
3552
+ const { richtextComponentRef, richtextG, foreignObject } = drawTopicByElement(newBoard, topicRectangle, emptyMind);
3553
+ fakeCreateNodeRef = {
3554
+ instanceRef: richtextComponentRef,
3555
+ nodeG,
3556
+ foreignObject,
3557
+ topicG: richtextG
3558
+ };
3559
+ richtextComponentRef.changeDetectorRef.detectChanges();
3560
+ PlaitBoard.getHost(board).append(...[fakeCreateNodeRef.nodeG, fakeCreateNodeRef.topicG]);
3561
+ }
3562
+ else {
3563
+ fakeCreateNodeRef.nodeG.remove();
3564
+ fakeCreateNodeRef.nodeG = nodeG;
3565
+ PlaitBoard.getHost(board).append(nodeG);
3566
+ PlaitBoard.getHost(board).append(fakeCreateNodeRef.topicG);
3567
+ updateForeignObject$1(fakeCreateNodeRef.topicG, topicRectangle.width, topicRectangle.height, topicRectangle.x, topicRectangle.y);
3568
+ }
3569
+ }
3570
+ });
3571
+ }
3572
+ else {
3573
+ destroy();
3574
+ }
3575
+ mousemove(event);
3576
+ };
3577
+ newBoard.mouseup = (event) => {
3578
+ const movingPoint = PlaitBoard.getMovingPoint(board);
3579
+ if (movingPoint && fakeCreateNodeRef && PlaitBoard.isPointer(board, MindPointerType.mind)) {
3580
+ const targetPoint = transformPoint(board, toPoint(movingPoint[0], movingPoint[1], PlaitBoard.getHost(board)));
3581
+ const emptyMind = createEmptyMind(board, targetPoint);
3582
+ Transforms.insertNode(board, emptyMind, [board.children.length]);
3583
+ BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
3584
+ }
3585
+ destroy();
3586
+ mouseup(event);
3587
+ };
3588
+ board.keydown = (event) => {
3589
+ if (PlaitBoard.isReadonly(board) || getSelectedElements(board).length > 0) {
3590
+ keydown(event);
3591
+ return;
3592
+ }
3593
+ if (event.key === DefaultHotkey && !PlaitBoard.isPointer(board, MindPointerType.mind)) {
3594
+ BoardTransforms.updatePointerType(board, MindPointerType.mind);
3595
+ event.preventDefault();
3596
+ return;
3597
+ }
3598
+ keydown(event);
3599
+ };
3600
+ function destroy() {
3601
+ if (fakeCreateNodeRef) {
3602
+ fakeCreateNodeRef.instanceRef.destroy();
3603
+ fakeCreateNodeRef.nodeG.remove();
3604
+ fakeCreateNodeRef.topicG.remove();
3605
+ fakeCreateNodeRef = null;
3606
+ }
3607
+ }
3608
+ return newBoard;
3609
+ };
3610
+
3780
3611
  const withMind = (board) => {
3781
3612
  const { drawElement, dblclick, keydown, insertFragment, setFragment, deleteFragment, isHitSelection, getRectangle, isMovable, isRecursion } = board;
3782
3613
  board.drawElement = (context) => {
@@ -3818,7 +3649,7 @@ const withMind = (board) => {
3818
3649
  return isMovable(element);
3819
3650
  };
3820
3651
  board.keydown = (event) => {
3821
- if (board.options.readonly || IS_TEXT_EDITABLE.get(board)) {
3652
+ if (PlaitBoard.isReadonly(board)) {
3822
3653
  keydown(event);
3823
3654
  return;
3824
3655
  }
@@ -3841,7 +3672,7 @@ const withMind = (board) => {
3841
3672
  insertMindElement(board, selectedElement, findNewChildNodePath(board, selectedElement));
3842
3673
  }
3843
3674
  else {
3844
- if (shouldChangeRightNodeCount(selectedElement)) {
3675
+ if (isInRightBranchOfStandardLayout(selectedElement)) {
3845
3676
  changeRightNodeCount(board, selectedElementPath.slice(0, 1), 1);
3846
3677
  }
3847
3678
  const abstractRefs = insertElementHandleAbstract(board, Path.next(selectedElementPath));
@@ -3852,7 +3683,10 @@ const withMind = (board) => {
3852
3683
  }
3853
3684
  if (hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event)) {
3854
3685
  event.preventDefault();
3855
- deleteSelectedELements(board, selectedElements);
3686
+ const deletableElements = getFirstLevelElement(selectedElements).reverse();
3687
+ const abstractRefs = deleteElementHandleAbstract(board, deletableElements);
3688
+ MindTransforms.setAbstractsByRefs(board, abstractRefs);
3689
+ MindTransforms.removeElements(board, selectedElements);
3856
3690
  let activeElement;
3857
3691
  const firstLevelElements = getFirstLevelElement(selectedElements);
3858
3692
  if (AbstractNode.isAbstract(firstLevelElements[0])) {
@@ -3898,7 +3732,7 @@ const withMind = (board) => {
3898
3732
  keydown(event);
3899
3733
  };
3900
3734
  board.dblclick = (event) => {
3901
- if (board.options.readonly || IS_TEXT_EDITABLE.get(board)) {
3735
+ if (PlaitBoard.isReadonly(board)) {
3902
3736
  dblclick(event);
3903
3737
  return;
3904
3738
  }
@@ -3907,9 +3741,16 @@ const withMind = (board) => {
3907
3741
  .filter(value => PlaitMind.isMind(value))
3908
3742
  .forEach(mindMap => {
3909
3743
  depthFirstRecursion(mindMap, node => {
3910
- if (!PlaitBoard.hasBeenTextEditing(board) && hitMindElement(board, point, node)) {
3744
+ if (!PlaitBoard.hasBeenTextEditing(board) && isHitMindElement(board, point, node)) {
3911
3745
  enterNodeEditing(node);
3912
3746
  }
3747
+ }, node => {
3748
+ if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
3749
+ return true;
3750
+ }
3751
+ else {
3752
+ return false;
3753
+ }
3913
3754
  });
3914
3755
  });
3915
3756
  if (PlaitBoard.hasBeenTextEditing(board)) {
@@ -3947,10 +3788,13 @@ const withMind = (board) => {
3947
3788
  };
3948
3789
  board.deleteFragment = (data) => {
3949
3790
  const selectedElements = getSelectedElements(board);
3950
- deleteSelectedELements(board, selectedElements);
3791
+ const deletableElements = getFirstLevelElement(selectedElements).reverse();
3792
+ const abstractRefs = deleteElementHandleAbstract(board, deletableElements);
3793
+ MindTransforms.setAbstractsByRefs(board, abstractRefs);
3794
+ MindTransforms.removeElements(board, selectedElements);
3951
3795
  deleteFragment(data);
3952
3796
  };
3953
- return withExtendMind(withAbstract(withDnd(board)));
3797
+ return withMindExtend(withCreateMind(withAbstract(withDnd(board))));
3954
3798
  };
3955
3799
 
3956
3800
  class MindEmojiBaseComponent {
@@ -3992,5 +3836,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3992
3836
  * Generated bundle index. Do not edit.
3993
3837
  */
3994
3838
 
3995
- export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_COLORS, BRANCH_WIDTH, DefaultAbstractNodeStyle, DefaultNodeStyle, DefaultRootStyle, ELEMENT_TO_NODE, EXTEND_OFFSET, EXTEND_RADIUS, GRAY_COLOR, LayoutDirection, LayoutDirectionsMap, MindElement, MindElementShape, MindEmojiBaseComponent, MindModule, MindNode, MindNodeComponent, MindQueries, MindTransforms, NODE_MIN_WIDTH, PRIMARY_COLOR, PlaitMind, PlaitMindComponent, QUICK_INSERT_CIRCLE_COLOR, QUICK_INSERT_CIRCLE_OFFSET, QUICK_INSERT_INNER_CROSS_COLOR, ROOT_TOPIC_FONT_SIZE, STROKE_WIDTH, TOPIC_COLOR, TOPIC_DEFAULT_MAX_WORD_COUNT, TOPIC_FONT_SIZE, TRANSPARENT, canSetAbstract, changeRightNodeCount, copyNewNode, correctLayoutByDirection, createDefaultMindMapElement, createMindElement, deleteElementHandleAbstract, deleteSelectedELements, directionCorrector, directionDetector, divideElementByParent, drawCurvePlaceholderDropNodeG, drawIndentNodeG, drawPlaceholderDropNodeG, drawStraightDropNodeG, extractNodesText, findLastChild, findLocationLeftIndex, findUpElement, getAbstractBranchColor, getAbstractBranchWidth, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getBranchWidthByMindElement, getChildrenCount, getCorrespondingAbstract, getDefaultBranchColor, getDefaultBranchColorByIndex, getDefaultLayout, getEmojiFontSize, getEmojiForeignRectangle, getEmojiRectangle, getEmojisWidthHeight, getFirstLevelElement, getHitAbstractHandle, getHorizontalFakeY, getInCorrectLayoutDirection, getIndentedFakePoint, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getNextBranchColor, getOverallAbstracts, getRectangleByNode, getRectangleByResizingLocation, getRootLayout, getShapeByElement, getStrokeByMindElement, handleTouchedAbstract, hitMindElement, insertElementHandleAbstract, insertMindElement, isChildElement, isChildRight, isChildUp, isCorrectLayout, isHitEmojis, isMixedLayout, isSetAbstract, isVirtualKey, readjustmentDropTarget, separateChildren, shouldChangeRightNodeCount, transformAbstractToNode, transformNodeToRoot, transformRootToNode, withExtendMind, withMind };
3839
+ export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_COLORS, BRANCH_WIDTH, BaseDrawer, DefaultAbstractNodeStyle, DefaultNodeStyle, DefaultRootStyle, ELEMENT_TO_NODE, EXTEND_OFFSET, EXTEND_RADIUS, GRAY_COLOR, IS_DRAGGING, LayoutDirection, LayoutDirectionsMap, MindElement, MindElementShape, MindEmojiBaseComponent, MindModule, MindNode, MindNodeComponent, MindPointerType, MindQueries, MindTransforms, NODE_MIN_WIDTH, PRIMARY_COLOR, PlaitMind, PlaitMindComponent, QUICK_INSERT_CIRCLE_COLOR, QUICK_INSERT_CIRCLE_OFFSET, QUICK_INSERT_INNER_CROSS_COLOR, ROOT_TOPIC_FONT_SIZE, STROKE_WIDTH, TOPIC_COLOR, TOPIC_DEFAULT_MAX_WORD_COUNT, TOPIC_FONT_SIZE, TRANSPARENT, addActiveOnDragOrigin, adjustAbstractToNode, adjustNodeToRoot, adjustRootToNode, canSetAbstract, changeRightNodeCount, copyNewNode, correctLayoutByDirection, createDefaultMind, createEmptyMind, createMindElement, deleteElementHandleAbstract, detectDropTarget, directionCorrector, directionDetector, divideElementByParent, drawFakeDragNode, drawFakeDropNodeByPath, enterNodeEditing, extractNodesText, findLastChild, findLocationLeftIndex, getAbstractBranchColor, getAbstractBranchWidth, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getBranchWidthByMindElement, getChildrenCount, getCorrespondingAbstract, getDefaultBranchColor, getDefaultBranchColorByIndex, getDefaultLayout, getEmojiForeignRectangle, getEmojiRectangle, getFirstLevelElement, getHitAbstractHandle, getInCorrectLayoutDirection, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getNextBranchColor, getOverallAbstracts, getPathByDropTarget, getPreviousAndNextByPath, getRectangleByElement, getRectangleByNode, getRectangleByResizingLocation, getRelativeStartEndByAbstractRef, getRootLayout, getShapeByElement, getStrokeByMindElement, getTopicRectangleByElement, getTopicRectangleByNode, getValidAbstractRefs, handleTouchedAbstract, hasAfterDraw, insertElementHandleAbstract, insertMindElement, isChildElement, isChildRight, isChildUp, isCorrectLayout, isDragging, isHitEmojis, isHitMindElement, isInRightBranchOfStandardLayout, isMixedLayout, isSetAbstract, isValidTarget, isVirtualKey, readjustmentDropTarget, removeActiveOnDragOrigin, separateChildren, setIsDragging, withMind, withMindExtend };
3996
3840
  //# sourceMappingURL=plait-mind.mjs.map