@plait/mind 0.27.0-next.7 → 0.27.0-next.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, ChangeDetectionStrategy, NgModule, NgZone, Directive, Input, HostListener } from '@angular/core';
3
3
  import * as i2 from '@plait/core';
4
- import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, PlaitPluginKey, getSelectedElements, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitBoard, Path, PlaitNode, PlaitContextService, depthFirstRecursion, getIsRecursionFunc, drawLinearPath, drawBezierPath, createG, updateForeignObject, drawRoundRectangle, getRectangleByElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, setStrokeLinecap, createText, PlaitPointerType, NODE_TO_INDEX, PlaitModule, isMainPointer, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CoreTransforms, BOARD_TO_HOST, BoardTransforms, throttleRAF, removeSelectedElement, PlaitHistoryBoard, hotkeys, setClipboardDataByMedia, getClipboardDataByMedia, ResizeCursorClass, preventTouchMove, PRESS_AND_MOVE_BUFFER, MERGING, setClipboardData, setClipboardDataByText, getDataFromClipboard } from '@plait/core';
5
- import { MindLayoutType, isIndentedLayout, isHorizontalLayout, isHorizontalLogicLayout, ConnectingPosition, AbstractNode, isStandardLayout, isVerticalLogicLayout, getNonAbstractChildren, isLeftLayout, isRightLayout, isTopLayout, isBottomLayout, getCorrectStartEnd, getAbstractLayout, GlobalLayout } from '@plait/layouts';
4
+ import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, PlaitElement, PlaitNode, Path, isNullOrUndefined, PlaitBoard, distanceBetweenPointAndRectangle, RectangleClient, PlaitPluginKey, getSelectedElements, idCreator, Transforms, clearSelectedElement, addSelectedElement, PlaitContextService, depthFirstRecursion, getIsRecursionFunc, drawRoundRectangle, drawLinearPath, drawBezierPath, createG, updateForeignObject, getRectangleByElements, NODE_TO_PARENT, createForeignObject, setStrokeLinecap, ACTIVE_STROKE_WIDTH, createText, PlaitPointerType, NODE_TO_INDEX, PlaitModule, isMainPointer, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CoreTransforms, BOARD_TO_HOST, BoardTransforms, throttleRAF, removeSelectedElement, PlaitHistoryBoard, hotkeys, setClipboardDataByMedia, getClipboardDataByMedia, ResizeCursorClass, preventTouchMove, PRESS_AND_MOVE_BUFFER, MERGING, setClipboardData, setClipboardDataByText, getDataFromClipboard } from '@plait/core';
5
+ import { MindLayoutType, AbstractNode, isIndentedLayout, isHorizontalLayout, isHorizontalLogicLayout, ConnectingPosition, isStandardLayout, isVerticalLogicLayout, getNonAbstractChildren, isLeftLayout, isRightLayout, isTopLayout, isBottomLayout, getCorrectStartEnd, getAbstractLayout, GlobalLayout } from '@plait/layouts';
6
6
  import { PlaitMarkEditor, MarkTypes, DEFAULT_FONT_SIZE, TEXT_DEFAULT_HEIGHT, buildText, getTextSize, TextManage, ExitOrigin, TextModule, getTextFromClipboard } from '@plait/text';
7
7
  import { fromEvent, Subject } from 'rxjs';
8
- import { RESIZE_HANDLE_DIAMETER, getRectangleResizeHandleRefs, CommonPluginElement, WithTextPluginKey, isDrawingMode, isDndMode, setCreationMode, BoardCreationMode, isExpandHotkey, isTabHotkey, isEnterHotkey, isVirtualKey, isDelete, isSpaceHotkey, MediaKeys, ResizeHandle, withResize, ActiveGenerator } from '@plait/common';
8
+ import { RESIZE_HANDLE_DIAMETER, getRectangleResizeHandleRefs, Generator, CommonPluginElement, WithTextPluginKey, isDrawingMode, isDndMode, setCreationMode, BoardCreationMode, isExpandHotkey, isTabHotkey, isEnterHotkey, isVirtualKey, isDelete, isSpaceHotkey, MediaKeys, ResizeHandle, withResize, ActiveGenerator } from '@plait/common';
9
9
  import { Node as Node$1, Path as Path$1 } from 'slate';
10
10
  import { pointsOnBezierCurves } from 'points-on-curve';
11
11
  import { take, filter } from 'rxjs/operators';
@@ -222,6 +222,277 @@ const NodeTopicThreshold = {
222
222
  defaultTextMaxWidth: 34 * 14,
223
223
  };
224
224
 
225
+ const getAvailableProperty = (board, element, propertyKey) => {
226
+ return element[propertyKey];
227
+ };
228
+
229
+ const DefaultAbstractNodeStyle = {
230
+ branch: { color: GRAY_COLOR, width: 2 },
231
+ shape: {
232
+ strokeColor: GRAY_COLOR,
233
+ strokeWidth: 2
234
+ }
235
+ };
236
+ const DefaultNodeStyle = {
237
+ branch: {
238
+ width: 3
239
+ },
240
+ shape: {
241
+ rectangleRadius: 4,
242
+ strokeWidth: 3,
243
+ fill: 'none'
244
+ }
245
+ };
246
+
247
+ const separateChildren = (parentElement) => {
248
+ const rightNodeCount = parentElement.rightNodeCount;
249
+ const children = parentElement.children;
250
+ let rightChildren = [], leftChildren = [];
251
+ for (let i = 0; i < children.length; i++) {
252
+ const child = children[i];
253
+ if (AbstractNode.isAbstract(child) && child.end < rightNodeCount) {
254
+ rightChildren.push(child);
255
+ continue;
256
+ }
257
+ if (AbstractNode.isAbstract(child) && child.start >= rightNodeCount) {
258
+ leftChildren.push(child);
259
+ continue;
260
+ }
261
+ if (i < rightNodeCount) {
262
+ rightChildren.push(child);
263
+ }
264
+ else {
265
+ leftChildren.push(child);
266
+ }
267
+ }
268
+ return { leftChildren, rightChildren };
269
+ };
270
+ const isSetAbstract = (element) => {
271
+ return !!getCorrespondingAbstract(element);
272
+ };
273
+ const canSetAbstract = (element) => {
274
+ return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
275
+ };
276
+ const getCorrespondingAbstract = (element) => {
277
+ const parent = MindElement.findParent(element);
278
+ if (!parent)
279
+ return undefined;
280
+ const elementIndex = parent.children.indexOf(element);
281
+ return parent.children.find(child => {
282
+ return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
283
+ });
284
+ };
285
+ const getBehindAbstracts = (element) => {
286
+ const parent = MindElement.findParent(element);
287
+ if (!parent)
288
+ return [];
289
+ const index = parent.children.indexOf(element);
290
+ return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
291
+ };
292
+ /**
293
+ * return corresponding abstract that is not child of elements
294
+ */
295
+ const getOverallAbstracts = (board, elements) => {
296
+ const overallAbstracts = [];
297
+ elements
298
+ .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
299
+ .forEach(value => {
300
+ const abstract = getCorrespondingAbstract(value);
301
+ if (abstract && elements.indexOf(abstract) === -1 && overallAbstracts.indexOf(abstract) === -1) {
302
+ const { start, end } = abstract;
303
+ const parent = MindElement.getParent(value);
304
+ const isOverall = parent.children.slice(start, end + 1).every(includedElement => elements.indexOf(includedElement) > -1);
305
+ if (isOverall) {
306
+ overallAbstracts.push(abstract);
307
+ }
308
+ }
309
+ });
310
+ return overallAbstracts;
311
+ };
312
+ /**
313
+ * abstract node is valid when elements contains at least one element it is referenced with
314
+ */
315
+ const getValidAbstractRefs = (board, elements) => {
316
+ const validAbstractRefs = [];
317
+ elements
318
+ .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
319
+ .forEach(value => {
320
+ const abstract = getCorrespondingAbstract(value);
321
+ if (abstract && elements.indexOf(abstract) > 0) {
322
+ const index = validAbstractRefs.findIndex(value => value.abstract === abstract);
323
+ if (index === -1) {
324
+ validAbstractRefs.push({
325
+ abstract: abstract,
326
+ references: [value]
327
+ });
328
+ }
329
+ else {
330
+ validAbstractRefs[index].references.push(value);
331
+ }
332
+ }
333
+ });
334
+ return validAbstractRefs;
335
+ };
336
+ function getRelativeStartEndByAbstractRef(abstractRef, elements) {
337
+ const start = elements.indexOf(abstractRef.references[0]);
338
+ const end = elements.indexOf(abstractRef.references[abstractRef.references.length - 1]);
339
+ return { start, end };
340
+ }
341
+ const insertElementHandleAbstract = (board, path, step = 1,
342
+ //由此区分拖拽和新增到概要概括最后一个节点
343
+ isExtendPreviousNode = true, effectedAbstracts = new Map()) => {
344
+ const parent = PlaitNode.parent(board, path);
345
+ const hasPreviousNode = path[path.length - 1] !== 0;
346
+ let behindAbstracts;
347
+ if (!hasPreviousNode) {
348
+ behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));
349
+ }
350
+ else {
351
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
352
+ behindAbstracts = getBehindAbstracts(selectedElement);
353
+ }
354
+ if (behindAbstracts.length) {
355
+ behindAbstracts.forEach(abstract => {
356
+ let newProperties = effectedAbstracts.get(abstract);
357
+ if (!newProperties) {
358
+ newProperties = { start: 0, end: 0 };
359
+ effectedAbstracts.set(abstract, newProperties);
360
+ }
361
+ newProperties.start = newProperties.start + step;
362
+ newProperties.end = newProperties.end + step;
363
+ });
364
+ }
365
+ if (!hasPreviousNode) {
366
+ return effectedAbstracts;
367
+ }
368
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
369
+ const correspondingAbstract = getCorrespondingAbstract(selectedElement);
370
+ const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;
371
+ if (correspondingAbstract && !isDragToLast) {
372
+ let newProperties = effectedAbstracts.get(correspondingAbstract);
373
+ if (!newProperties) {
374
+ newProperties = { start: 0, end: 0 };
375
+ effectedAbstracts.set(correspondingAbstract, newProperties);
376
+ }
377
+ newProperties.end = newProperties.end + step;
378
+ }
379
+ return effectedAbstracts;
380
+ };
381
+ const deleteElementHandleAbstract = (board, deletableElements, effectedAbstracts = new Map()) => {
382
+ deletableElements.forEach(node => {
383
+ if (!PlaitMind.isMind(node)) {
384
+ const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));
385
+ if (behindAbstracts.length) {
386
+ behindAbstracts.forEach(abstract => {
387
+ let newProperties = effectedAbstracts.get(abstract);
388
+ if (!newProperties) {
389
+ newProperties = { start: 0, end: 0 };
390
+ effectedAbstracts.set(abstract, newProperties);
391
+ }
392
+ newProperties.start = newProperties.start - 1;
393
+ newProperties.end = newProperties.end - 1;
394
+ });
395
+ }
396
+ const correspondingAbstract = getCorrespondingAbstract(node);
397
+ if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
398
+ let newProperties = effectedAbstracts.get(correspondingAbstract);
399
+ if (!newProperties) {
400
+ newProperties = { start: 0, end: 0 };
401
+ effectedAbstracts.set(correspondingAbstract, newProperties);
402
+ }
403
+ newProperties.end = newProperties.end - 1;
404
+ }
405
+ }
406
+ });
407
+ return effectedAbstracts;
408
+ };
409
+ const isChildOfAbstract = (board, element) => {
410
+ const ancestors = MindElement.getAncestors(board, element);
411
+ return !!ancestors.find((value) => AbstractNode.isAbstract(value));
412
+ };
413
+
414
+ /**
415
+ * Processing of branch color, width, style, etc. of the mind node
416
+ */
417
+ const getBranchColorByMindElement = (board, element) => {
418
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
419
+ return getAbstractBranchColor(board, element);
420
+ }
421
+ const branchColor = getAvailableProperty(board, element, 'branchColor');
422
+ return branchColor || getDefaultBranchColor(board, element);
423
+ };
424
+ const getBranchShapeByMindElement = (board, element) => {
425
+ const branchShape = getAvailableProperty(board, element, 'branchShape');
426
+ return branchShape || BranchShape.bight;
427
+ };
428
+ const getBranchWidthByMindElement = (board, element) => {
429
+ const branchWidth = getAvailableProperty(board, element, 'branchWidth');
430
+ return branchWidth || BRANCH_WIDTH;
431
+ };
432
+ const getAbstractBranchWidth = (board, element) => {
433
+ if (!isNullOrUndefined(element.branchWidth)) {
434
+ return element.branchWidth;
435
+ }
436
+ return DefaultAbstractNodeStyle.branch.width;
437
+ };
438
+ const getAbstractBranchColor = (board, element) => {
439
+ if (element.branchColor) {
440
+ return element.branchColor;
441
+ }
442
+ return DefaultAbstractNodeStyle.branch.color;
443
+ };
444
+ const getNextBranchColor = (board, root) => {
445
+ const index = root.children.length;
446
+ return getDefaultBranchColorByIndex(board, index);
447
+ };
448
+ const getDefaultBranchColor = (board, element) => {
449
+ const path = PlaitBoard.findPath(board, element);
450
+ return getDefaultBranchColorByIndex(board, path[1]);
451
+ };
452
+ const getDefaultBranchColorByIndex = (board, index) => {
453
+ const themeColor = getMindThemeColor(board);
454
+ const length = themeColor.branchColors.length;
455
+ const remainder = index % length;
456
+ return themeColor.branchColors[remainder];
457
+ };
458
+ const getMindThemeColor = (board) => {
459
+ const themeColors = PlaitBoard.getThemeColors(board);
460
+ const themeColor = themeColors.find(val => val.mode === board.theme.themeColorMode);
461
+ if (themeColor && MindThemeColor.isMindThemeColor(themeColor)) {
462
+ return themeColor;
463
+ }
464
+ else {
465
+ return MindDefaultThemeColor;
466
+ }
467
+ };
468
+
469
+ const getStrokeByMindElement = (board, element) => {
470
+ if (PlaitMind.isMind(element)) {
471
+ const defaultRootStroke = getMindThemeColor(board).rootFill;
472
+ return element.strokeColor || defaultRootStroke;
473
+ }
474
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
475
+ return element.strokeColor || DefaultAbstractNodeStyle.shape.strokeColor;
476
+ }
477
+ return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);
478
+ };
479
+ const getStrokeWidthByElement = (board, element) => {
480
+ const strokeWidth = element.strokeWidth ||
481
+ (AbstractNode.isAbstract(element) ? DefaultAbstractNodeStyle.shape.strokeWidth : DefaultNodeStyle.shape.strokeWidth);
482
+ return strokeWidth;
483
+ };
484
+ const getFillByElement = (board, element) => {
485
+ if (element.fill) {
486
+ return element.fill;
487
+ }
488
+ const defaultRootFill = getMindThemeColor(board).rootFill;
489
+ return element.isRoot ? defaultRootFill : DefaultNodeStyle.shape.fill;
490
+ };
491
+ const getShapeByElement = (board, element) => {
492
+ const shape = getAvailableProperty(board, element, 'shape');
493
+ return shape || MindElementShape.roundRectangle;
494
+ };
495
+
225
496
  const NodeDefaultSpace = {
226
497
  horizontal: {
227
498
  nodeAndText: BASE * 2.5,
@@ -246,13 +517,13 @@ const getHorizontalSpaceBetweenNodeAndText = (board, element) => {
246
517
  const isMind = PlaitMind.isMind(element);
247
518
  const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;
248
519
  const strokeWidth = getStrokeWidthByElement(board, element);
249
- return nodeAndText + strokeWidth / 2;
520
+ return nodeAndText + strokeWidth;
250
521
  };
251
522
  const getVerticalSpaceBetweenNodeAndText = (board, element) => {
252
523
  const isMind = PlaitMind.isMind(element);
253
524
  const strokeWidth = getStrokeWidthByElement(board, element);
254
525
  const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;
255
- return nodeAndText + strokeWidth / 2;
526
+ return nodeAndText + strokeWidth;
256
527
  };
257
528
  const getSpaceEmojiAndText = (element) => {
258
529
  const isMind = PlaitMind.isMind(element);
@@ -284,11 +555,7 @@ const NodeSpace = {
284
555
  return Math.max(width, imageWidth);
285
556
  },
286
557
  /**
287
- * use this when upload image first or resize image
288
- * @param board
289
- * @param element
290
- * @param imageWidth
291
- * @returns
558
+ * use it when upload image first or resize image
292
559
  */
293
560
  getNodeNewDynamicWidth(board, element, imageWidth) {
294
561
  const width = element.manualWidth || element.width;
@@ -330,13 +597,12 @@ const NodeSpace = {
330
597
  },
331
598
  getImageTopSpace(board, element) {
332
599
  const strokeWidth = getStrokeWidthByElement(board, element);
333
- return strokeWidth / 2 + NodeDefaultSpace.vertical.nodeAndImage;
600
+ return strokeWidth + NodeDefaultSpace.vertical.nodeAndImage;
334
601
  },
335
602
  getEmojiLeftSpace(board, element) {
336
603
  const options = board.getPluginOptions(WithMindPluginKey);
337
604
  const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
338
- const strokeWidth = getStrokeWidthByElement(board, element);
339
- return strokeWidth / 2 + nodeAndText - options.emojiPadding;
605
+ return nodeAndText - options.emojiPadding;
340
606
  },
341
607
  getEmojiTopSpace(board, element) {
342
608
  const nodeAndText = getVerticalSpaceBetweenNodeAndText(board, element);
@@ -357,6 +623,39 @@ const getNodeDefaultFontSize = (isRoot = false) => {
357
623
  return defaultFontSize;
358
624
  };
359
625
 
626
+ function getRectangleByNode(node) {
627
+ const x = node.x + node.hGap;
628
+ let y = node.y + node.vGap;
629
+ const width = node.width - node.hGap * 2;
630
+ const height = node.height - node.vGap * 2;
631
+ return {
632
+ x,
633
+ y,
634
+ width,
635
+ height
636
+ };
637
+ }
638
+ function getRectangleByElement(board, element) {
639
+ const width = NodeSpace.getNodeWidth(board, element);
640
+ const height = NodeSpace.getNodeHeight(board, element);
641
+ const nodeRectangle = {
642
+ x: element.points[0][0],
643
+ y: element.points[0][1],
644
+ width,
645
+ height
646
+ };
647
+ return nodeRectangle;
648
+ }
649
+ function isHitMindElement(board, point, element) {
650
+ const node = MindElement.getNode(element);
651
+ if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
652
+ return true;
653
+ }
654
+ else {
655
+ return false;
656
+ }
657
+ }
658
+
360
659
  function getEmojiRectangle(board, element) {
361
660
  let { x, y } = getRectangleByNode(MindElement.getNode(element));
362
661
  x = x + NodeSpace.getEmojiLeftSpace(board, element);
@@ -551,21 +850,19 @@ const getRootLayout = (root) => {
551
850
 
552
851
  const getLayoutOptions = (board) => {
553
852
  function getMainAxle(element, parent) {
554
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
555
853
  if (element.isRoot) {
556
854
  return BASE * 12;
557
855
  }
558
856
  if (parent && parent.isRoot()) {
559
- return BASE * 3 + strokeWidth / 2;
857
+ return BASE * 3;
560
858
  }
561
- return BASE * 3 + strokeWidth / 2;
859
+ return BASE * 3;
562
860
  }
563
861
  function getSecondAxle(element, parent) {
564
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
565
862
  if (element.isRoot) {
566
- return BASE * 10 + strokeWidth / 2;
863
+ return BASE * 10;
567
864
  }
568
- return BASE * 6 + strokeWidth / 2;
865
+ return BASE * 6;
569
866
  }
570
867
  return {
571
868
  getHeight(element) {
@@ -577,9 +874,8 @@ const getLayoutOptions = (board) => {
577
874
  getHorizontalGap(element, parent) {
578
875
  const _layout = (parent && parent.layout) || getRootLayout(element);
579
876
  const isHorizontal = isHorizontalLayout(_layout);
580
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
581
877
  if (isIndentedLayout(_layout)) {
582
- return BASE * 4 + strokeWidth;
878
+ return BASE * 4;
583
879
  }
584
880
  if (!isHorizontal) {
585
881
  return getMainAxle(element, parent);
@@ -800,24 +1096,6 @@ const adjustNodeToRoot = (board, node) => {
800
1096
  };
801
1097
  };
802
1098
 
803
- const DefaultAbstractNodeStyle = {
804
- branch: { color: GRAY_COLOR, width: 2 },
805
- shape: {
806
- strokeColor: GRAY_COLOR,
807
- strokeWidth: 2
808
- }
809
- };
810
- const DefaultNodeStyle = {
811
- branch: {
812
- width: 3
813
- },
814
- shape: {
815
- rectangleRadius: 4,
816
- strokeWidth: 3,
817
- fill: 'none'
818
- }
819
- };
820
-
821
1099
  const setAbstractsByRefs = (board, abstractRefs) => {
822
1100
  abstractRefs.forEach((newProperty, element) => {
823
1101
  const start = element.start + newProperty.start;
@@ -861,216 +1139,49 @@ const setAbstractByElements = (board, groupParent, group) => {
861
1139
  const path = [...PlaitBoard.findPath(board, groupParent), childrenLength];
862
1140
  const leftChildren = indexArray.filter(index => index >= rightNodeCount);
863
1141
  const rightChildren = indexArray.filter(index => index < rightNodeCount);
864
- insertAbstractNode(board, path, rightChildren[0], rightChildren[rightChildren.length - 1]);
865
- insertAbstractNode(board, Path.next(path), leftChildren[0], leftChildren[leftChildren.length - 1]);
866
- }
867
- else {
868
- const path = [...PlaitBoard.findPath(board, groupParent), groupParent.children.length];
869
- insertAbstractNode(board, path, start, end);
870
- }
871
- };
872
- const insertAbstractNode = (board, path, start, end) => {
873
- const mindElement = createMindElement('概要', 28, 20, {
874
- strokeWidth: DefaultAbstractNodeStyle.branch.width,
875
- branchWidth: DefaultAbstractNodeStyle.branch.width
876
- });
877
- mindElement.start = start;
878
- mindElement.end = end;
879
- Transforms.insertNode(board, mindElement, path);
880
- clearSelectedElement(board);
881
- addSelectedElement(board, mindElement);
882
- };
883
-
884
- const setLayout = (board, layout, path) => {
885
- correctLogicLayoutNode(board, layout, path);
886
- const element = PlaitNode.get(board, path);
887
- if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
888
- MindTransforms.setAbstractByStandardLayout(board, element);
889
- }
890
- Transforms.setNode(board, { layout }, path);
891
- };
892
- const correctLogicLayoutNode = (board, layout, path) => {
893
- const node = PlaitNode.get(board, path);
894
- if (node && layout) {
895
- node.children?.forEach((value, index) => {
896
- if (value.layout) {
897
- if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
898
- (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
899
- Transforms.setNode(board, { layout: null }, [...path, index]);
900
- }
901
- if (value.children?.length) {
902
- correctLogicLayoutNode(board, layout, [...path, index]);
903
- }
904
- }
905
- });
906
- }
907
- };
908
-
909
- const separateChildren = (parentElement) => {
910
- const rightNodeCount = parentElement.rightNodeCount;
911
- const children = parentElement.children;
912
- let rightChildren = [], leftChildren = [];
913
- for (let i = 0; i < children.length; i++) {
914
- const child = children[i];
915
- if (AbstractNode.isAbstract(child) && child.end < rightNodeCount) {
916
- rightChildren.push(child);
917
- continue;
918
- }
919
- if (AbstractNode.isAbstract(child) && child.start >= rightNodeCount) {
920
- leftChildren.push(child);
921
- continue;
922
- }
923
- if (i < rightNodeCount) {
924
- rightChildren.push(child);
925
- }
926
- else {
927
- leftChildren.push(child);
928
- }
929
- }
930
- return { leftChildren, rightChildren };
931
- };
932
- const isSetAbstract = (element) => {
933
- return !!getCorrespondingAbstract(element);
934
- };
935
- const canSetAbstract = (element) => {
936
- return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
937
- };
938
- const getCorrespondingAbstract = (element) => {
939
- const parent = MindElement.findParent(element);
940
- if (!parent)
941
- return undefined;
942
- const elementIndex = parent.children.indexOf(element);
943
- return parent.children.find(child => {
944
- return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
945
- });
946
- };
947
- const getBehindAbstracts = (element) => {
948
- const parent = MindElement.findParent(element);
949
- if (!parent)
950
- return [];
951
- const index = parent.children.indexOf(element);
952
- return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
953
- };
954
- /**
955
- * return corresponding abstract that is not child of elements
956
- */
957
- const getOverallAbstracts = (board, elements) => {
958
- const overallAbstracts = [];
959
- elements
960
- .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
961
- .forEach(value => {
962
- const abstract = getCorrespondingAbstract(value);
963
- if (abstract && elements.indexOf(abstract) === -1 && overallAbstracts.indexOf(abstract) === -1) {
964
- const { start, end } = abstract;
965
- const parent = MindElement.getParent(value);
966
- const isOverall = parent.children.slice(start, end + 1).every(includedElement => elements.indexOf(includedElement) > -1);
967
- if (isOverall) {
968
- overallAbstracts.push(abstract);
969
- }
970
- }
971
- });
972
- return overallAbstracts;
973
- };
974
- /**
975
- * abstract node is valid when elements contains at least one element it is referenced with
976
- */
977
- const getValidAbstractRefs = (board, elements) => {
978
- const validAbstractRefs = [];
979
- elements
980
- .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
981
- .forEach(value => {
982
- const abstract = getCorrespondingAbstract(value);
983
- if (abstract && elements.indexOf(abstract) > 0) {
984
- const index = validAbstractRefs.findIndex(value => value.abstract === abstract);
985
- if (index === -1) {
986
- validAbstractRefs.push({
987
- abstract: abstract,
988
- references: [value]
989
- });
990
- }
991
- else {
992
- validAbstractRefs[index].references.push(value);
993
- }
994
- }
995
- });
996
- return validAbstractRefs;
997
- };
998
- function getRelativeStartEndByAbstractRef(abstractRef, elements) {
999
- const start = elements.indexOf(abstractRef.references[0]);
1000
- const end = elements.indexOf(abstractRef.references[abstractRef.references.length - 1]);
1001
- return { start, end };
1002
- }
1003
- const insertElementHandleAbstract = (board, path, step = 1,
1004
- //由此区分拖拽和新增到概要概括最后一个节点
1005
- isExtendPreviousNode = true, effectedAbstracts = new Map()) => {
1006
- const parent = PlaitNode.parent(board, path);
1007
- const hasPreviousNode = path[path.length - 1] !== 0;
1008
- let behindAbstracts;
1009
- if (!hasPreviousNode) {
1010
- behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));
1142
+ insertAbstractNode(board, path, rightChildren[0], rightChildren[rightChildren.length - 1]);
1143
+ insertAbstractNode(board, Path.next(path), leftChildren[0], leftChildren[leftChildren.length - 1]);
1011
1144
  }
1012
1145
  else {
1013
- const selectedElement = PlaitNode.get(board, Path.previous(path));
1014
- behindAbstracts = getBehindAbstracts(selectedElement);
1015
- }
1016
- if (behindAbstracts.length) {
1017
- behindAbstracts.forEach(abstract => {
1018
- let newProperties = effectedAbstracts.get(abstract);
1019
- if (!newProperties) {
1020
- newProperties = { start: 0, end: 0 };
1021
- effectedAbstracts.set(abstract, newProperties);
1022
- }
1023
- newProperties.start = newProperties.start + step;
1024
- newProperties.end = newProperties.end + step;
1025
- });
1026
- }
1027
- if (!hasPreviousNode) {
1028
- return effectedAbstracts;
1146
+ const path = [...PlaitBoard.findPath(board, groupParent), groupParent.children.length];
1147
+ insertAbstractNode(board, path, start, end);
1029
1148
  }
1030
- const selectedElement = PlaitNode.get(board, Path.previous(path));
1031
- const correspondingAbstract = getCorrespondingAbstract(selectedElement);
1032
- const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;
1033
- if (correspondingAbstract && !isDragToLast) {
1034
- let newProperties = effectedAbstracts.get(correspondingAbstract);
1035
- if (!newProperties) {
1036
- newProperties = { start: 0, end: 0 };
1037
- effectedAbstracts.set(correspondingAbstract, newProperties);
1038
- }
1039
- newProperties.end = newProperties.end + step;
1149
+ };
1150
+ const insertAbstractNode = (board, path, start, end) => {
1151
+ const mindElement = createMindElement('概要', 28, 20, {
1152
+ strokeWidth: DefaultAbstractNodeStyle.branch.width,
1153
+ branchWidth: DefaultAbstractNodeStyle.branch.width
1154
+ });
1155
+ mindElement.start = start;
1156
+ mindElement.end = end;
1157
+ Transforms.insertNode(board, mindElement, path);
1158
+ clearSelectedElement(board);
1159
+ addSelectedElement(board, mindElement);
1160
+ };
1161
+
1162
+ const setLayout = (board, layout, path) => {
1163
+ correctLogicLayoutNode(board, layout, path);
1164
+ const element = PlaitNode.get(board, path);
1165
+ if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
1166
+ MindTransforms.setAbstractByStandardLayout(board, element);
1040
1167
  }
1041
- return effectedAbstracts;
1168
+ Transforms.setNode(board, { layout }, path);
1042
1169
  };
1043
- const deleteElementHandleAbstract = (board, deletableElements, effectedAbstracts = new Map()) => {
1044
- deletableElements.forEach(node => {
1045
- if (!PlaitMind.isMind(node)) {
1046
- const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));
1047
- if (behindAbstracts.length) {
1048
- behindAbstracts.forEach(abstract => {
1049
- let newProperties = effectedAbstracts.get(abstract);
1050
- if (!newProperties) {
1051
- newProperties = { start: 0, end: 0 };
1052
- effectedAbstracts.set(abstract, newProperties);
1053
- }
1054
- newProperties.start = newProperties.start - 1;
1055
- newProperties.end = newProperties.end - 1;
1056
- });
1057
- }
1058
- const correspondingAbstract = getCorrespondingAbstract(node);
1059
- if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
1060
- let newProperties = effectedAbstracts.get(correspondingAbstract);
1061
- if (!newProperties) {
1062
- newProperties = { start: 0, end: 0 };
1063
- effectedAbstracts.set(correspondingAbstract, newProperties);
1170
+ const correctLogicLayoutNode = (board, layout, path) => {
1171
+ const node = PlaitNode.get(board, path);
1172
+ if (node && layout) {
1173
+ node.children?.forEach((value, index) => {
1174
+ if (value.layout) {
1175
+ if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
1176
+ (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
1177
+ Transforms.setNode(board, { layout: null }, [...path, index]);
1178
+ }
1179
+ if (value.children?.length) {
1180
+ correctLogicLayoutNode(board, layout, [...path, index]);
1064
1181
  }
1065
- newProperties.end = newProperties.end - 1;
1066
1182
  }
1067
- }
1068
- });
1069
- return effectedAbstracts;
1070
- };
1071
- const isChildOfAbstract = (board, element) => {
1072
- const ancestors = MindElement.getAncestors(board, element);
1073
- return !!ancestors.find((value) => AbstractNode.isAbstract(value));
1183
+ });
1184
+ }
1074
1185
  };
1075
1186
 
1076
1187
  const normalizeWidthAndHeight = (board, element, width, height) => {
@@ -1301,92 +1412,6 @@ function getImageSize(file, defaultImageWidth = DEFAULT_IMAGE_WIDTH) {
1301
1412
  });
1302
1413
  }
1303
1414
 
1304
- const getAvailableProperty = (board, element, propertyKey) => {
1305
- return element[propertyKey];
1306
- };
1307
-
1308
- /**
1309
- * Processing of branch color, width, style, etc. of the mind node
1310
- */
1311
- const getBranchColorByMindElement = (board, element) => {
1312
- if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
1313
- return getAbstractBranchColor(board, element);
1314
- }
1315
- const branchColor = getAvailableProperty(board, element, 'branchColor');
1316
- return branchColor || getDefaultBranchColor(board, element);
1317
- };
1318
- const getBranchShapeByMindElement = (board, element) => {
1319
- const branchShape = getAvailableProperty(board, element, 'branchShape');
1320
- return branchShape || BranchShape.bight;
1321
- };
1322
- const getBranchWidthByMindElement = (board, element) => {
1323
- const branchWidth = getAvailableProperty(board, element, 'branchWidth');
1324
- return branchWidth || BRANCH_WIDTH;
1325
- };
1326
- const getAbstractBranchWidth = (board, element) => {
1327
- if (!isNullOrUndefined(element.branchWidth)) {
1328
- return element.branchWidth;
1329
- }
1330
- return DefaultAbstractNodeStyle.branch.width;
1331
- };
1332
- const getAbstractBranchColor = (board, element) => {
1333
- if (element.branchColor) {
1334
- return element.branchColor;
1335
- }
1336
- return DefaultAbstractNodeStyle.branch.color;
1337
- };
1338
- const getNextBranchColor = (board, root) => {
1339
- const index = root.children.length;
1340
- return getDefaultBranchColorByIndex(board, index);
1341
- };
1342
- const getDefaultBranchColor = (board, element) => {
1343
- const path = PlaitBoard.findPath(board, element);
1344
- return getDefaultBranchColorByIndex(board, path[1]);
1345
- };
1346
- const getDefaultBranchColorByIndex = (board, index) => {
1347
- const themeColor = getMindThemeColor(board);
1348
- const length = themeColor.branchColors.length;
1349
- const remainder = index % length;
1350
- return themeColor.branchColors[remainder];
1351
- };
1352
- const getMindThemeColor = (board) => {
1353
- const themeColors = PlaitBoard.getThemeColors(board);
1354
- const themeColor = themeColors.find(val => val.mode === board.theme.themeColorMode);
1355
- if (themeColor && MindThemeColor.isMindThemeColor(themeColor)) {
1356
- return themeColor;
1357
- }
1358
- else {
1359
- return MindDefaultThemeColor;
1360
- }
1361
- };
1362
-
1363
- const getStrokeByMindElement = (board, element) => {
1364
- if (PlaitMind.isMind(element)) {
1365
- const defaultRootStroke = getMindThemeColor(board).rootFill;
1366
- return element.strokeColor || defaultRootStroke;
1367
- }
1368
- if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
1369
- return element.strokeColor || DefaultAbstractNodeStyle.shape.strokeColor;
1370
- }
1371
- return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);
1372
- };
1373
- const getStrokeWidthByElement = (board, element) => {
1374
- const strokeWidth = element.strokeWidth ||
1375
- (AbstractNode.isAbstract(element) ? DefaultAbstractNodeStyle.shape.strokeWidth : DefaultNodeStyle.shape.strokeWidth);
1376
- return strokeWidth;
1377
- };
1378
- const getFillByElement = (board, element) => {
1379
- if (element.fill) {
1380
- return element.fill;
1381
- }
1382
- const defaultRootFill = getMindThemeColor(board).rootFill;
1383
- return element.isRoot ? defaultRootFill : DefaultNodeStyle.shape.fill;
1384
- };
1385
- const getShapeByElement = (board, element) => {
1386
- const shape = getAvailableProperty(board, element, 'shape');
1387
- return shape || MindElementShape.roundRectangle;
1388
- };
1389
-
1390
1415
  const IS_DRAGGING = new WeakMap();
1391
1416
  const addActiveOnDragOrigin = (activeElement) => {
1392
1417
  const activeComponent = PlaitElement.getComponent(activeElement);
@@ -1621,6 +1646,24 @@ const getPathByDropTarget = (board, dropTarget) => {
1621
1646
  return targetPath;
1622
1647
  };
1623
1648
 
1649
+ function drawRoundRectangleByNode(board, node) {
1650
+ const rectangle = getRectangleByNode(node);
1651
+ return drawRoundRectangleByElement(board, rectangle, node.origin);
1652
+ }
1653
+ function drawRoundRectangleByElement(board, nodeRectangle, element) {
1654
+ const fill = getFillByElement(board, element);
1655
+ const stroke = getStrokeByMindElement(board, element);
1656
+ const strokeWidth = getStrokeWidthByElement(board, element);
1657
+ const newNodeRectangle = RectangleClient.inflate(nodeRectangle, -strokeWidth);
1658
+ const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), newNodeRectangle.x, newNodeRectangle.y, newNodeRectangle.x + newNodeRectangle.width, newNodeRectangle.y + newNodeRectangle.height, {
1659
+ stroke,
1660
+ strokeWidth,
1661
+ fill,
1662
+ fillStyle: 'solid'
1663
+ }, false, DefaultNodeStyle.shape.rectangleRadius);
1664
+ return nodeG;
1665
+ }
1666
+
1624
1667
  const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //primary color 50% opacity
1625
1668
  const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;
1626
1669
  const ABSTRACT_HANDLE_LENGTH = 10;
@@ -2191,13 +2234,13 @@ function handleTouchedAbstract(board, touchedAbstract, endPoint) {
2191
2234
  }
2192
2235
  if (touchedAbstract) {
2193
2236
  const component = PlaitElement.getComponent(touchedAbstract);
2194
- component.activeDrawer.updateAbstractOutline(touchedAbstract);
2237
+ component.activeGenerator.updateAbstractOutline(touchedAbstract);
2195
2238
  touchedAbstract = undefined;
2196
2239
  }
2197
2240
  if (abstract) {
2198
2241
  touchedAbstract = abstract;
2199
2242
  const component = PlaitElement.getComponent(touchedAbstract);
2200
- component.activeDrawer.updateAbstractOutline(touchedAbstract, touchedHandle);
2243
+ component.activeGenerator.updateAbstractOutline(touchedAbstract, touchedHandle);
2201
2244
  }
2202
2245
  return touchedAbstract;
2203
2246
  }
@@ -2459,56 +2502,6 @@ var BranchShape;
2459
2502
  BranchShape["polyline"] = "polyline";
2460
2503
  })(BranchShape || (BranchShape = {}));
2461
2504
 
2462
- function getRectangleByNode(node) {
2463
- const x = node.x + node.hGap;
2464
- let y = node.y + node.vGap;
2465
- const width = node.width - node.hGap * 2;
2466
- const height = node.height - node.vGap * 2;
2467
- return {
2468
- x,
2469
- y,
2470
- width,
2471
- height
2472
- };
2473
- }
2474
- function getRectangleByElement(board, element) {
2475
- const width = NodeSpace.getNodeWidth(board, element);
2476
- const height = NodeSpace.getNodeHeight(board, element);
2477
- const nodeRectangle = {
2478
- x: element.points[0][0],
2479
- y: element.points[0][1],
2480
- width,
2481
- height
2482
- };
2483
- return nodeRectangle;
2484
- }
2485
- function isHitMindElement(board, point, element) {
2486
- const node = MindElement.getNode(element);
2487
- if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
2488
- return true;
2489
- }
2490
- else {
2491
- return false;
2492
- }
2493
- }
2494
-
2495
- function drawRoundRectangleByNode(board, node) {
2496
- const rectangle = getRectangleByNode(node);
2497
- return drawRoundRectangleByElement(board, rectangle, node.origin);
2498
- }
2499
- function drawRoundRectangleByElement(board, nodeRectangle, element) {
2500
- const fill = getFillByElement(board, element);
2501
- const stroke = getStrokeByMindElement(board, element);
2502
- const strokeWidth = getStrokeWidthByElement(board, element);
2503
- const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), nodeRectangle.x, nodeRectangle.y, nodeRectangle.x + nodeRectangle.width, nodeRectangle.y + nodeRectangle.height, {
2504
- stroke,
2505
- strokeWidth,
2506
- fill,
2507
- fillStyle: 'solid'
2508
- }, false, DefaultNodeStyle.shape.rectangleRadius);
2509
- return nodeG;
2510
- }
2511
-
2512
2505
  function drawAbstractLink(board, node, isHorizontal) {
2513
2506
  const linkPadding = 15;
2514
2507
  const branchWidth = getAbstractBranchWidth(board, node.origin);
@@ -2853,7 +2846,7 @@ function drawAbstractRoundRectangle(rs, x1, y1, x2, y2, isHorizontal, options) {
2853
2846
  }
2854
2847
  }
2855
2848
 
2856
- class NodeActiveDrawer extends BaseDrawer {
2849
+ class NodeActiveGenerator extends Generator {
2857
2850
  canDraw(element, data) {
2858
2851
  if (data.selected) {
2859
2852
  return true;
@@ -2864,19 +2857,17 @@ class NodeActiveDrawer extends BaseDrawer {
2864
2857
  }
2865
2858
  baseDraw(element, data) {
2866
2859
  const activeG = createG();
2867
- this.g = activeG;
2868
2860
  if (AbstractNode.isAbstract(element)) {
2869
2861
  this.abstractOutlineG = drawAbstractIncludedOutline(this.board, PlaitBoard.getRoughSVG(this.board), element);
2870
2862
  activeG.append(this.abstractOutlineG);
2871
2863
  }
2872
2864
  const node = MindElement.getNode(element);
2873
2865
  const rectangle = getRectangleByNode(node);
2874
- const activeStrokeWidth = 2;
2875
- // add 0.1 to avoid white gap
2876
- const offset = (getStrokeWidthByElement(this.board, element) + activeStrokeWidth) / 2 - 0.1;
2877
- const activeRectangle = RectangleClient.getOutlineRectangle(rectangle, -offset);
2878
- const strokeG = drawRoundRectangle(PlaitBoard.getRoughSVG(this.board), activeRectangle.x, activeRectangle.y, activeRectangle.x + activeRectangle.width, activeRectangle.y + activeRectangle.height, { stroke: PRIMARY_COLOR, strokeWidth: activeStrokeWidth, fill: '' }, true, DefaultNodeStyle.shape.rectangleRadius + offset);
2879
- this.g.appendChild(strokeG);
2866
+ const strokeWidth = getStrokeWidthByElement(this.board, element);
2867
+ const activeStrokeWidth = ACTIVE_STROKE_WIDTH;
2868
+ const activeRectangle = RectangleClient.inflate(rectangle, activeStrokeWidth);
2869
+ const strokeG = drawRoundRectangle(PlaitBoard.getRoughSVG(this.board), activeRectangle.x, activeRectangle.y, activeRectangle.x + activeRectangle.width, activeRectangle.y + activeRectangle.height, { stroke: PRIMARY_COLOR, strokeWidth: activeStrokeWidth, fill: '' }, true, DefaultNodeStyle.shape.rectangleRadius + (activeStrokeWidth + strokeWidth) / 2);
2870
+ activeG.appendChild(strokeG);
2880
2871
  return activeG;
2881
2872
  }
2882
2873
  updateAbstractOutline(element, activeHandlePosition, resizingLocation) {
@@ -3037,6 +3028,20 @@ class NodeImageDrawer {
3037
3028
  }
3038
3029
  }
3039
3030
 
3031
+ class NodeShapeGenerator extends Generator {
3032
+ canDraw(element, data) {
3033
+ const shape = getShapeByElement(this.board, element);
3034
+ if (shape === MindElementShape.roundRectangle) {
3035
+ return true;
3036
+ }
3037
+ return false;
3038
+ }
3039
+ baseDraw(element, data) {
3040
+ const rectangle = getRectangleByNode(data.node);
3041
+ return drawRoundRectangleByElement(this.board, rectangle, data.node.origin);
3042
+ }
3043
+ }
3044
+
3040
3045
  class MindNodeComponent extends CommonPluginElement {
3041
3046
  get textManage() {
3042
3047
  return this.getTextManages()[0];
@@ -3052,9 +3057,10 @@ class MindNodeComponent extends CommonPluginElement {
3052
3057
  };
3053
3058
  }
3054
3059
  initializeDrawer() {
3060
+ this.nodeShapeGenerator = new NodeShapeGenerator(this.board);
3055
3061
  this.nodeEmojisDrawer = new NodeEmojisDrawer(this.board, this.viewContainerRef);
3056
3062
  this.nodeInsertDrawer = new NodeInsertDrawer(this.board);
3057
- this.activeDrawer = new NodeActiveDrawer(this.board);
3063
+ this.activeGenerator = new NodeActiveGenerator(this.board);
3058
3064
  this.collapseDrawer = new CollapseDrawer(this.board);
3059
3065
  this.imageDrawer = new NodeImageDrawer(this.board, this.viewContainerRef);
3060
3066
  const plugins = this.board.getPluginOptions(WithTextPluginKey).textPlugins;
@@ -3092,10 +3098,10 @@ class MindNodeComponent extends CommonPluginElement {
3092
3098
  this.index = NODE_TO_INDEX.get(this.element) || 0;
3093
3099
  this.roughSVG = PlaitBoard.getRoughSVG(this.board);
3094
3100
  this.parentG = PlaitElement.getComponent(MindElement.getRoot(this.board, this.element)).rootG;
3095
- this.drawShape();
3101
+ this.nodeShapeGenerator.draw(this.element, this.g, { node: this.node });
3096
3102
  this.drawLink();
3097
3103
  this.drawTopic();
3098
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
3104
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
3099
3105
  this.drawEmojis();
3100
3106
  this.drawExtend();
3101
3107
  this.imageDrawer.drawImage(this.g, this.element);
@@ -3109,8 +3115,8 @@ class MindNodeComponent extends CommonPluginElement {
3109
3115
  this.node = newNode;
3110
3116
  const isChangeTheme = this.board.operations.find(op => op.type === 'set_theme');
3111
3117
  if (!isEqualNode || value.element !== previous.element || isChangeTheme) {
3112
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
3113
- this.drawShape();
3118
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
3119
+ this.nodeShapeGenerator.draw(this.element, this.g, { node: this.node });
3114
3120
  this.drawLink();
3115
3121
  this.drawEmojis();
3116
3122
  this.drawExtend();
@@ -3121,7 +3127,7 @@ class MindNodeComponent extends CommonPluginElement {
3121
3127
  const hasSameSelected = value.selected === previous.selected;
3122
3128
  const hasSameParent = value.parent === previous.parent;
3123
3129
  if (!hasSameSelected) {
3124
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
3130
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
3125
3131
  }
3126
3132
  if (!hasSameParent) {
3127
3133
  this.drawLink();
@@ -3134,24 +3140,6 @@ class MindNodeComponent extends CommonPluginElement {
3134
3140
  this.g.append(g);
3135
3141
  }
3136
3142
  }
3137
- drawShape() {
3138
- this.destroyShape();
3139
- const shape = getShapeByElement(this.board, this.node.origin);
3140
- switch (shape) {
3141
- case MindElementShape.roundRectangle:
3142
- this.shapeG = drawRoundRectangleByNode(this.board, this.node);
3143
- this.g.prepend(this.shapeG);
3144
- break;
3145
- default:
3146
- break;
3147
- }
3148
- }
3149
- destroyShape() {
3150
- if (this.shapeG) {
3151
- this.shapeG.remove();
3152
- this.shapeG = null;
3153
- }
3154
- }
3155
3143
  drawLink() {
3156
3144
  if (PlaitMind.isMind(this.element)) {
3157
3145
  return;
@@ -3203,10 +3191,10 @@ class MindNodeComponent extends CommonPluginElement {
3203
3191
  this.textManage.updateRectangle();
3204
3192
  }
3205
3193
  editTopic() {
3206
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
3194
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected, isEditing: true });
3207
3195
  this.textManage.edit((origin) => {
3208
3196
  if (origin === ExitOrigin.default) {
3209
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
3197
+ this.activeGenerator.draw(this.element, this.g, { selected: this.selected, isEditing: false });
3210
3198
  }
3211
3199
  });
3212
3200
  }
@@ -3461,7 +3449,7 @@ const withNodeDnd = (board) => {
3461
3449
  setActiveElements.push(node);
3462
3450
  }
3463
3451
  });
3464
- Transforms.setSelectionWithTemporaryElements(board, setActiveElements);
3452
+ Transforms.addSelectionWithTemporaryElements(board, setActiveElements);
3465
3453
  }
3466
3454
  setIsDragging(board, false);
3467
3455
  activeElements = [];
@@ -3555,7 +3543,7 @@ const withAbstract = (board) => {
3555
3543
  newProperty =
3556
3544
  abstractHandlePosition === AbstractHandlePosition.start ? { start: locationIndex + 1 } : { end: locationIndex };
3557
3545
  }
3558
- abstractComponent.activeDrawer.updateAbstractOutline(activeAbstractElement, abstractHandlePosition, location);
3546
+ abstractComponent.activeGenerator.updateAbstractOutline(activeAbstractElement, abstractHandlePosition, location);
3559
3547
  }
3560
3548
  mousemove(event);
3561
3549
  };
@@ -3572,7 +3560,7 @@ const withAbstract = (board) => {
3572
3560
  }
3573
3561
  else {
3574
3562
  const abstractComponent = PlaitElement.getComponent(activeAbstractElement);
3575
- abstractComponent.activeDrawer.updateAbstractOutline(activeAbstractElement);
3563
+ abstractComponent.activeGenerator.updateAbstractOutline(activeAbstractElement);
3576
3564
  }
3577
3565
  activeAbstractElement = undefined;
3578
3566
  }
@@ -3867,13 +3855,13 @@ const withNodeImage = (board) => {
3867
3855
  }
3868
3856
  globalPointerUp(event);
3869
3857
  };
3870
- board.setFragment = (data, rectangle) => {
3858
+ board.setFragment = (data, rectangle, type) => {
3871
3859
  const selectedImageElement = getSelectedImageElement(board);
3872
3860
  if (selectedImageElement) {
3873
3861
  setClipboardDataByMedia(data, selectedImageElement.data.image, MediaKeys.image);
3874
3862
  return;
3875
3863
  }
3876
- setFragment(data, rectangle);
3864
+ setFragment(data, rectangle, type);
3877
3865
  };
3878
3866
  board.deleteFragment = (data) => {
3879
3867
  const selectedImageElement = getSelectedImageElement(board);
@@ -4167,14 +4155,14 @@ const insertClipboardData = (board, elements, targetPoint) => {
4167
4155
  Transforms.insertNode(board, newElement, path);
4168
4156
  return;
4169
4157
  });
4170
- Transforms.setSelectionWithTemporaryElements(board, newELements);
4158
+ Transforms.addSelectionWithTemporaryElements(board, newELements);
4171
4159
  };
4172
4160
  const insertClipboardText = (board, targetParent, text) => {
4173
4161
  const styles = PlaitMind.isMind(targetParent) ? { fontFamily: BRANCH_FONT_FAMILY } : { fontFamily: DEFAULT_FONT_FAMILY };
4174
4162
  const { width, height } = getTextSize(board, text, TOPIC_DEFAULT_MAX_WORD_COUNT, styles);
4175
4163
  const newElement = createMindElement(text, Math.max(width, getFontSizeBySlateElement(text)), height, {});
4176
4164
  Transforms.insertNode(board, newElement, findNewChildNodePath(board, targetParent));
4177
- return;
4165
+ Transforms.addSelectionWithTemporaryElements(board, [newElement]);
4178
4166
  };
4179
4167
 
4180
4168
  const withMindFragment = (baseBoard) => {
@@ -4197,14 +4185,14 @@ const withMindFragment = (baseBoard) => {
4197
4185
  }
4198
4186
  return getDeletedFragment(data);
4199
4187
  };
4200
- board.setFragment = (data, rectangle) => {
4188
+ board.setFragment = (data, rectangle, type) => {
4201
4189
  const targetMindElements = getSelectedMindElements(board);
4202
4190
  const firstLevelElements = getFirstLevelElement(targetMindElements);
4203
4191
  if (firstLevelElements.length) {
4204
4192
  const elements = buildClipboardData(board, firstLevelElements, rectangle ? [rectangle.x, rectangle.y] : [0, 0]);
4205
4193
  setMindClipboardData(data, elements);
4206
4194
  }
4207
- setFragment(data, rectangle);
4195
+ setFragment(data, rectangle, type);
4208
4196
  };
4209
4197
  board.insertFragment = (data, targetPoint) => {
4210
4198
  const elements = getDataFromClipboard(data);