@plait/mind 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/base/image-base.component.d.ts +16 -0
  2. package/base/index.d.ts +1 -0
  3. package/constants/node-style.d.ts +9 -4
  4. package/drawer/node-image.drawer.d.ts +16 -0
  5. package/esm2020/base/image-base.component.mjs +28 -0
  6. package/esm2020/base/index.mjs +2 -1
  7. package/esm2020/constants/node-style.mjs +11 -6
  8. package/esm2020/drawer/node-active.drawer.mjs +10 -9
  9. package/esm2020/drawer/node-image.drawer.mjs +61 -0
  10. package/esm2020/interfaces/element-data.mjs +1 -1
  11. package/esm2020/interfaces/element.mjs +9 -1
  12. package/esm2020/interfaces/options.mjs +1 -1
  13. package/esm2020/node.component.mjs +12 -1
  14. package/esm2020/plugins/with-mind-image.mjs +49 -0
  15. package/esm2020/plugins/with-mind.mjs +4 -11
  16. package/esm2020/transforms/emoji.mjs +2 -2
  17. package/esm2020/transforms/image.mjs +10 -0
  18. package/esm2020/transforms/index.mjs +4 -2
  19. package/esm2020/transforms/node.mjs +2 -6
  20. package/esm2020/utils/draw/abstract-outline.mjs +44 -2
  21. package/esm2020/utils/draw/node-dnd.mjs +8 -1
  22. package/esm2020/utils/draw/node-link/logic-link.mjs +2 -2
  23. package/esm2020/utils/draw/node-shape.mjs +5 -5
  24. package/esm2020/utils/mind.mjs +2 -2
  25. package/esm2020/utils/node-style/shape.mjs +8 -4
  26. package/esm2020/utils/position/emoji.mjs +8 -8
  27. package/esm2020/utils/position/image.mjs +21 -0
  28. package/esm2020/utils/position/index.mjs +2 -1
  29. package/esm2020/utils/space/node-space.mjs +23 -5
  30. package/fesm2015/plait-mind.mjs +283 -42
  31. package/fesm2015/plait-mind.mjs.map +1 -1
  32. package/fesm2020/plait-mind.mjs +280 -42
  33. package/fesm2020/plait-mind.mjs.map +1 -1
  34. package/interfaces/element-data.d.ts +9 -0
  35. package/interfaces/element.d.ts +2 -1
  36. package/interfaces/options.d.ts +3 -1
  37. package/node.component.d.ts +3 -0
  38. package/package.json +1 -1
  39. package/plugins/with-mind-image.d.ts +2 -0
  40. package/transforms/image.d.ts +3 -0
  41. package/transforms/index.d.ts +1 -0
  42. package/utils/draw/abstract-outline.d.ts +2 -0
  43. package/utils/node-style/shape.d.ts +1 -0
  44. package/utils/position/emoji.d.ts +4 -4
  45. package/utils/position/image.d.ts +6 -0
  46. package/utils/position/index.d.ts +1 -0
  47. package/utils/space/node-space.d.ts +1 -0
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, ChangeDetectionStrategy, NgModule, NgZone, Directive, Input, HostListener } from '@angular/core';
2
+ import { Directive, Input, Component, ChangeDetectionStrategy, NgModule, NgZone, HostListener } from '@angular/core';
3
3
  import * as i2 from '@plait/core';
4
- import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Path, PlaitBoard, depthFirstRecursion, drawLinearPath, drawBezierPath, createG, updateForeignObject, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, drawAbstractRoundRectangle, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, isMainPointer, BOARD_TO_HOST, PlaitPluginKey, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
4
+ import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Path, PlaitBoard, depthFirstRecursion, drawLinearPath, drawBezierPath, createG, updateForeignObject, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, isMainPointer, BOARD_TO_HOST, PlaitPluginKey, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
5
  import { MindLayoutType, isIndentedLayout, AbstractNode, getNonAbstractChildren, isStandardLayout, isLeftLayout, isRightLayout, isVerticalLogicLayout, isHorizontalLogicLayout, isTopLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, getAbstractLayout, ConnectingPosition, GlobalLayout } from '@plait/layouts';
6
6
  import { TEXT_DEFAULT_HEIGHT, buildText, getTextSize, TextManage, ExitOrigin, TextModule, getTextFromClipboard } from '@plait/text';
7
7
  import { fromEvent, Subject } from 'rxjs';
@@ -216,7 +216,9 @@ const NodeDefaultSpace = {
216
216
  emojiAndText: BASE * 1.5
217
217
  },
218
218
  vertical: {
219
- nodeAndText: BASE * 1.5
219
+ nodeAndText: BASE * 1.5,
220
+ nodeAndImage: BASE,
221
+ imageAndText: BASE * 1.5
220
222
  }
221
223
  };
222
224
  const RootDefaultSpace = {
@@ -246,17 +248,25 @@ const getSpaceEmojiAndText = (element) => {
246
248
  const NodeSpace = {
247
249
  getNodeWidth(board, element) {
248
250
  const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
251
+ const imageWidth = MindElement.hasImage(element) ? element.data.image?.width : 0;
249
252
  if (MindElement.hasEmojis(element)) {
250
253
  return (NodeSpace.getEmojiLeftSpace(board, element) +
251
254
  getEmojisWidthHeight(board, element).width +
252
255
  getSpaceEmojiAndText(element) +
253
- element.width +
256
+ Math.max(element.width, imageWidth) +
254
257
  nodeAndText);
255
258
  }
256
- return nodeAndText + element.width + nodeAndText;
259
+ return nodeAndText + Math.max(element.width, imageWidth) + nodeAndText;
257
260
  },
258
261
  getNodeHeight(board, element) {
259
262
  const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
263
+ if (MindElement.hasImage(element)) {
264
+ return (NodeDefaultSpace.vertical.nodeAndImage +
265
+ element.data.image.height +
266
+ NodeDefaultSpace.vertical.imageAndText +
267
+ element.height +
268
+ nodeAndText);
269
+ }
260
270
  return nodeAndText + element.height + nodeAndText;
261
271
  },
262
272
  getTextLeftSpace(board, element) {
@@ -270,7 +280,15 @@ const NodeSpace = {
270
280
  },
271
281
  getTextTopSpace(element) {
272
282
  const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
273
- return nodeAndText;
283
+ if (MindElement.hasImage(element)) {
284
+ return element.data.image.height + NodeDefaultSpace.vertical.nodeAndImage + NodeDefaultSpace.vertical.imageAndText;
285
+ }
286
+ else {
287
+ return nodeAndText;
288
+ }
289
+ },
290
+ getImageTopSpace(element) {
291
+ return NodeDefaultSpace.vertical.nodeAndImage;
274
292
  },
275
293
  getEmojiLeftSpace(board, element) {
276
294
  const options = board.getPluginOptions(WithMindPluginKey);
@@ -297,12 +315,12 @@ function getEmojiRectangle(board, element) {
297
315
  function getEmojiForeignRectangle(board, element) {
298
316
  let { x, y } = getRectangleByNode(MindElement.getNode(element));
299
317
  x = x + NodeSpace.getEmojiLeftSpace(board, element);
300
- const { width, height } = getEmojisWidthHeight(board, element);
318
+ const { width } = getEmojisWidthHeight(board, element);
301
319
  return {
302
320
  x,
303
321
  y,
304
322
  width,
305
- height: height + NodeSpace.getEmojiTopSpace(element) * 2
323
+ height: NodeSpace.getNodeHeight(board, element)
306
324
  };
307
325
  }
308
326
  const isHitEmojis = (board, element, point) => {
@@ -324,6 +342,23 @@ function getTopicRectangleByElement(board, nodeRectangle, element) {
324
342
  return { height, width, x, y };
325
343
  }
326
344
 
345
+ function getImageForeignRectangle(board, element) {
346
+ let { x, y } = getRectangleByNode(MindElement.getNode(element));
347
+ x = x + NodeSpace.getTextLeftSpace(board, element);
348
+ y = NodeSpace.getImageTopSpace(element) + y;
349
+ const { width, height } = element.data.image;
350
+ return {
351
+ x,
352
+ y,
353
+ width,
354
+ height
355
+ };
356
+ }
357
+ const isHitImage = (board, element, range) => {
358
+ const client = getImageForeignRectangle(board, element);
359
+ return RectangleClient.isHit(RectangleClient.toRectangleClient([range.anchor, range.focus]), client);
360
+ };
361
+
327
362
  const NODE_MIN_WIDTH = 18;
328
363
 
329
364
  function editTopic(element) {
@@ -433,7 +468,7 @@ const copyNewNode = (node) => {
433
468
  const extractNodesText = (node) => {
434
469
  let str = '';
435
470
  if (node) {
436
- str += Node.string(node.data.topic.children[0]) + ' ';
471
+ str += Node.string(node.data.topic) + ' ';
437
472
  for (const childNode of node.children) {
438
473
  str += extractNodesText(childNode);
439
474
  }
@@ -624,15 +659,20 @@ const adjustNodeToRoot = (board, node) => {
624
659
  };
625
660
 
626
661
  const DefaultAbstractNodeStyle = {
627
- strokeColor: GRAY_COLOR,
628
- strokeWidth: 2,
629
662
  branchColor: GRAY_COLOR,
630
- branchWidth: 2
663
+ branchWidth: 2,
664
+ shape: {
665
+ strokeColor: GRAY_COLOR,
666
+ strokeWidth: 2
667
+ }
631
668
  };
632
669
  const DefaultNodeStyle = {
633
- strokeWidth: 3,
634
670
  branchWidth: 3,
635
- fill: 'none'
671
+ shape: {
672
+ rectangleRadius: 4,
673
+ strokeWidth: 3,
674
+ fill: 'none'
675
+ }
636
676
  };
637
677
 
638
678
  const getAvailableProperty = (board, element, propertyKey) => {
@@ -867,11 +907,15 @@ const getStrokeByMindElement = (board, element) => {
867
907
  return element.strokeColor || defaultRootStroke;
868
908
  }
869
909
  if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
870
- return element.strokeColor || DefaultAbstractNodeStyle.strokeColor;
871
- ;
910
+ return element.strokeColor || DefaultAbstractNodeStyle.shape.strokeColor;
872
911
  }
873
912
  return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);
874
913
  };
914
+ const getStrokeWidthByElement = (board, element) => {
915
+ const strokeWidth = element.strokeWidth ||
916
+ (AbstractNode.isAbstract(element) ? DefaultAbstractNodeStyle.shape.strokeWidth : DefaultNodeStyle.shape.strokeWidth);
917
+ return strokeWidth;
918
+ };
875
919
  const getShapeByElement = (board, element) => {
876
920
  const shape = getAvailableProperty(board, element, 'shape');
877
921
  return shape || MindElementShape.roundRectangle;
@@ -1310,7 +1354,7 @@ function drawLogicLink(board, parent, node, isHorizontal, defaultStroke = null,
1310
1354
  const branchWidth = defaultStrokeWidth || getBranchWidthByMindElement(board, parent.origin);
1311
1355
  const hasStraightLine = branchShape === BranchShape.polyline ? true : !parent.origin.isRoot;
1312
1356
  const parentShape = getShapeByElement(board, parent.origin);
1313
- const shape = node.origin.shape ? node.origin.shape : parentShape;
1357
+ const shape = getShapeByElement(board, node.origin);
1314
1358
  const hasUnderlineShape = shape === MindElementShape.underline;
1315
1359
  const hasUnderlineShapeOfParent = parentShape === MindElementShape.underline;
1316
1360
  const nodeClient = getRectangleByNode(node);
@@ -1393,6 +1437,12 @@ const drawFakeDragNode = (board, element, offsetX, offsetY) => {
1393
1437
  updateForeignObject(fakeEmojisG, foreignRectangle.width, foreignRectangle.height, foreignRectangle.x + offsetX, foreignRectangle.y + offsetY);
1394
1438
  dragFakeNodeG?.append(fakeEmojisG);
1395
1439
  }
1440
+ if (MindElement.hasImage(element)) {
1441
+ const fakeImageG = activeComponent.imageDrawer.g.cloneNode(true);
1442
+ const foreignRectangle = getImageForeignRectangle(board, element);
1443
+ updateForeignObject(fakeImageG, foreignRectangle.width, foreignRectangle.height, foreignRectangle.x + offsetX, foreignRectangle.y + offsetY);
1444
+ dragFakeNodeG?.append(fakeImageG);
1445
+ }
1396
1446
  return dragFakeNodeG;
1397
1447
  };
1398
1448
  const drawFakeDropNode = (board, dropTarget, path) => {
@@ -1923,6 +1973,14 @@ const MindElement = {
1923
1973
  return false;
1924
1974
  }
1925
1975
  },
1976
+ hasImage(element) {
1977
+ if (element.data.image) {
1978
+ return true;
1979
+ }
1980
+ else {
1981
+ return false;
1982
+ }
1983
+ },
1926
1984
  getEmojis(element) {
1927
1985
  return element.data.emojis;
1928
1986
  },
@@ -1986,15 +2044,15 @@ function drawRoundRectangleByNode(board, node) {
1986
2044
  }
1987
2045
  function drawRoundRectangleByElement(board, nodeRectangle, element) {
1988
2046
  const defaultRootFill = getMindThemeColor(board).rootFill;
1989
- const fill = element.fill ? element.fill : element.isRoot ? defaultRootFill : DefaultNodeStyle.fill;
2047
+ const fill = element.fill ? element.fill : element.isRoot ? defaultRootFill : DefaultNodeStyle.shape.fill;
1990
2048
  const stroke = getStrokeByMindElement(board, element);
1991
- const strokeWidth = element.strokeWidth ? element.strokeWidth : DefaultNodeStyle.strokeWidth;
2049
+ const strokeWidth = getStrokeWidthByElement(board, element);
1992
2050
  const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), nodeRectangle.x, nodeRectangle.y, nodeRectangle.x + nodeRectangle.width, nodeRectangle.y + nodeRectangle.height, {
1993
2051
  stroke,
1994
2052
  strokeWidth,
1995
2053
  fill,
1996
2054
  fillStyle: 'solid'
1997
- });
2055
+ }, false, DefaultNodeStyle.shape.rectangleRadius);
1998
2056
  return nodeG;
1999
2057
  }
2000
2058
 
@@ -2207,12 +2265,9 @@ const normalizeWidthAndHeight = (board, width, height) => {
2207
2265
  };
2208
2266
  const setTopic = (board, element, topic, width, height) => {
2209
2267
  const newElement = {
2210
- data: { topic },
2268
+ data: { ...element.data, topic },
2211
2269
  ...normalizeWidthAndHeight(board, width, height)
2212
2270
  };
2213
- if (MindElement.hasEmojis(element)) {
2214
- newElement.data.emojis = element.data.emojis;
2215
- }
2216
2271
  const path = PlaitBoard.findPath(board, element);
2217
2272
  Transforms.setNode(board, newElement, path);
2218
2273
  };
@@ -2291,7 +2346,7 @@ const removeEmoji = (board, element, emojiItem) => {
2291
2346
  };
2292
2347
  const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2293
2348
  const newElement = {
2294
- data: { topic: element.data.topic }
2349
+ data: { ...element.data }
2295
2350
  };
2296
2351
  const newEmojis = element.data.emojis.map(value => {
2297
2352
  if (value === oldEmoji) {
@@ -2304,6 +2359,15 @@ const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2304
2359
  Transforms.setNode(board, newElement, path);
2305
2360
  };
2306
2361
 
2362
+ const removeImage = (board, element) => {
2363
+ const newElement = {
2364
+ data: { ...element.data }
2365
+ };
2366
+ delete newElement.data.image;
2367
+ const path = PlaitBoard.findPath(board, element);
2368
+ Transforms.setNode(board, newElement, path);
2369
+ };
2370
+
2307
2371
  const MindTransforms = {
2308
2372
  setLayout,
2309
2373
  setTopic,
@@ -2317,7 +2381,8 @@ const MindTransforms = {
2317
2381
  removeElements,
2318
2382
  insertNodes,
2319
2383
  insertAbstractNodes,
2320
- setRightNodeCountByRefs
2384
+ setRightNodeCountByRefs,
2385
+ removeImage
2321
2386
  };
2322
2387
 
2323
2388
  class BaseDrawer {
@@ -2505,6 +2570,48 @@ function handleBoardClass(board, activeHandlePosition, isHorizontal) {
2505
2570
  PlaitBoard.getBoardContainer(board).classList.remove('abstract-resizing-vertical');
2506
2571
  }
2507
2572
  }
2573
+ function drawAbstractRoundRectangle(rs, x1, y1, x2, y2, isHorizontal, options) {
2574
+ const width = Math.abs(x1 - x2);
2575
+ const height = Math.abs(y1 - y2);
2576
+ const radius = 5;
2577
+ const handleGap = 4;
2578
+ const handleLength = 10;
2579
+ const handleSpace = handleLength + handleGap * 2;
2580
+ if (isHorizontal) {
2581
+ const handleSideLine = (width - handleSpace - radius * 2) / 2;
2582
+ const sideLine = height - radius * 2;
2583
+ return rs.path(`M${x1 + radius},${y1}
2584
+ l${handleSideLine},0
2585
+ m${handleSpace},0
2586
+ l${handleSideLine},0
2587
+ a${radius},${radius},0,0,1,${radius},${radius}
2588
+ l0,${sideLine}
2589
+ a${radius},${radius},0,0,1,-${radius},${radius}
2590
+ l-${handleSideLine},0
2591
+ m-${handleSpace},0
2592
+ l-${handleSideLine},0
2593
+ a${radius},${radius},0,0,1,-${radius},-${radius}
2594
+ l0,-${sideLine}
2595
+ a${radius},${radius},0,0,1,${radius},-${radius}`, options);
2596
+ }
2597
+ else {
2598
+ const handleSideLine = (height - handleSpace - radius * 2) / 2;
2599
+ const sideLine = width - radius * 2;
2600
+ return rs.path(`M${x1 + radius},${y1}
2601
+ l${sideLine},0
2602
+ a${radius},${radius},0,0,1,${radius},${radius}
2603
+ l0,${handleSideLine}
2604
+ m0,${handleSpace}
2605
+ l0,${handleSideLine}
2606
+ a${radius},${radius},0,0,1,-${radius},${radius}
2607
+ l-${sideLine},0
2608
+ a${radius},${radius},0,0,1,-${radius},-${radius}
2609
+ l0,-${handleSideLine}
2610
+ m0,-${handleSpace}
2611
+ l0,-${handleSideLine}
2612
+ a${radius},${radius},0,0,1,${radius},-${radius}`, options);
2613
+ }
2614
+ }
2508
2615
 
2509
2616
  class NodeActiveDrawer extends BaseDrawer {
2510
2617
  canDraw(element, data) {
@@ -2523,14 +2630,13 @@ class NodeActiveDrawer extends BaseDrawer {
2523
2630
  activeG.append(this.abstractOutlineG);
2524
2631
  }
2525
2632
  const node = MindElement.getNode(element);
2526
- let { x, y, width, height } = getRectangleByNode(node);
2527
- const strokeG = drawRoundRectangle(PlaitBoard.getRoughSVG(this.board), x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, strokeWidth: 2, fill: '' }, true);
2633
+ const rectangle = getRectangleByNode(node);
2634
+ const activeStrokeWidth = 2;
2635
+ // add 0.1 to avoid white gap
2636
+ const offset = (getStrokeWidthByElement(this.board, element) + activeStrokeWidth) / 2 - 0.1;
2637
+ const activeRectangle = RectangleClient.getOutlineRectangle(rectangle, -offset);
2638
+ 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);
2528
2639
  this.g.appendChild(strokeG);
2529
- if (!data.isEditing) {
2530
- const fillG = drawRoundRectangle(PlaitBoard.getRoughSVG(this.board), x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, fill: PRIMARY_COLOR, fillStyle: 'solid' }, true);
2531
- fillG.style.opacity = '0.15';
2532
- this.g.appendChild(fillG);
2533
- }
2534
2640
  return activeG;
2535
2641
  }
2536
2642
  updateAbstractOutline(element, activeHandlePosition, resizingLocation) {
@@ -2636,6 +2742,88 @@ class CollapseDrawer extends BaseDrawer {
2636
2742
  }
2637
2743
  }
2638
2744
 
2745
+ class MindImageBaseComponent {
2746
+ get nativeElement() {
2747
+ return this.elementRef.nativeElement;
2748
+ }
2749
+ constructor(elementRef) {
2750
+ this.elementRef = elementRef;
2751
+ }
2752
+ ngOnInit() { }
2753
+ }
2754
+ MindImageBaseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
2755
+ MindImageBaseComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.5", type: MindImageBaseComponent, inputs: { imageItem: "imageItem", board: "board", element: "element" }, host: { classAttribute: "mind-node-image" }, ngImport: i0 });
2756
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, decorators: [{
2757
+ type: Directive,
2758
+ args: [{
2759
+ host: {
2760
+ class: 'mind-node-image'
2761
+ }
2762
+ }]
2763
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { imageItem: [{
2764
+ type: Input
2765
+ }], board: [{
2766
+ type: Input
2767
+ }], element: [{
2768
+ type: Input
2769
+ }] } });
2770
+
2771
+ class NodeImageDrawer {
2772
+ constructor(board, viewContainerRef) {
2773
+ this.board = board;
2774
+ this.viewContainerRef = viewContainerRef;
2775
+ this.componentRef = null;
2776
+ }
2777
+ drawImage(element) {
2778
+ this.destroy();
2779
+ if (MindElement.hasImage(element)) {
2780
+ this.g = createG();
2781
+ const foreignRectangle = getImageForeignRectangle(this.board, element);
2782
+ const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2783
+ this.g.append(foreignObject);
2784
+ if (this.componentRef) {
2785
+ this.componentRef.destroy();
2786
+ this.componentRef = null;
2787
+ }
2788
+ const componentType = this.board.getPluginOptions(WithMindPluginKey).imageComponentType || MindImageBaseComponent;
2789
+ if (!componentType) {
2790
+ throw new Error('Not implement drawEmoji method error.');
2791
+ }
2792
+ this.componentRef = this.viewContainerRef.createComponent(componentType);
2793
+ this.componentRef.instance.board = this.board;
2794
+ this.componentRef.instance.element = element;
2795
+ this.componentRef.instance.imageItem = element.data.image;
2796
+ foreignObject.append(this.componentRef.instance.nativeElement);
2797
+ return this.g;
2798
+ }
2799
+ return undefined;
2800
+ }
2801
+ drawActive(element) {
2802
+ this.destroyActive();
2803
+ const imageRectangle = getImageForeignRectangle(this.board, element);
2804
+ const rectangle = RectangleClient.getOutlineRectangle(imageRectangle, -1);
2805
+ const roughSVG = PlaitBoard.getRoughSVG(this.board);
2806
+ this.activeG = roughSVG.rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height, {
2807
+ stroke: PRIMARY_COLOR,
2808
+ fill: '',
2809
+ fillStyle: 'solid'
2810
+ });
2811
+ this.g?.append(this.activeG);
2812
+ }
2813
+ destroyActive() {
2814
+ this.activeG?.remove();
2815
+ }
2816
+ destroy() {
2817
+ if (this.g) {
2818
+ this.g.remove();
2819
+ }
2820
+ if (this.componentRef) {
2821
+ this.componentRef.destroy();
2822
+ this.componentRef = null;
2823
+ }
2824
+ }
2825
+ }
2826
+
2639
2827
  // 1. When the text at the end has an italic attribute, the text is partially covered
2640
2828
  // 2. There will be some differences in the width measured by different browsers
2641
2829
  const WIDTH_BUFFER = 4;
@@ -2655,6 +2843,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2655
2843
  this.nodeInsertDrawer = new NodeInsertDrawer(this.board);
2656
2844
  this.activeDrawer = new NodeActiveDrawer(this.board);
2657
2845
  this.collapseDrawer = new CollapseDrawer(this.board);
2846
+ this.imageDrawer = new NodeImageDrawer(this.board, this.viewContainerRef);
2658
2847
  const plugins = this.board.getPluginOptions(WithMindPluginKey).textPlugins;
2659
2848
  this.textManage = new TextManage(this.board, this.viewContainerRef, () => {
2660
2849
  const rect = getTopicRectangleByNode(this.board, this.node);
@@ -2685,6 +2874,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2685
2874
  this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
2686
2875
  this.drawEmojis();
2687
2876
  this.drawExtend();
2877
+ this.drawImage();
2688
2878
  if (PlaitMind.isMind(this.context.parent)) {
2689
2879
  this.g.classList.add('branch');
2690
2880
  }
@@ -2707,6 +2897,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2707
2897
  this.drawShape();
2708
2898
  this.drawLink();
2709
2899
  this.drawEmojis();
2900
+ this.drawImage();
2710
2901
  this.drawExtend();
2711
2902
  this.textManage.updateText(this.element.data.topic);
2712
2903
  this.textManage.updateRectangle();
@@ -2728,6 +2919,12 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2728
2919
  this.g.append(g);
2729
2920
  }
2730
2921
  }
2922
+ drawImage() {
2923
+ const image = this.imageDrawer.drawImage(this.element);
2924
+ if (image) {
2925
+ this.g.append(image);
2926
+ }
2927
+ }
2731
2928
  drawShape() {
2732
2929
  this.destroyShape();
2733
2930
  const shape = getShapeByElement(this.board, this.node.origin);
@@ -2796,6 +2993,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2796
2993
  super.ngOnDestroy();
2797
2994
  this.textManage.destroy();
2798
2995
  this.nodeEmojisDrawer.destroy();
2996
+ this.imageDrawer.destroy();
2799
2997
  this.destroy$.next();
2800
2998
  this.destroy$.complete();
2801
2999
  if (ELEMENT_TO_NODE.get(this.element) === this.node) {
@@ -3622,6 +3820,52 @@ const removeHovered = (element) => {
3622
3820
  }
3623
3821
  };
3624
3822
 
3823
+ const withMindImage = (board) => {
3824
+ let selectedImageElement = null;
3825
+ const { keydown, mousedown } = board;
3826
+ board.mousedown = (event) => {
3827
+ if (PlaitBoard.isReadonly(board) || !isMainPointer(event) || !PlaitBoard.isPointer(board, PlaitPointerType.selection)) {
3828
+ mousedown(event);
3829
+ return;
3830
+ }
3831
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3832
+ const range = { anchor: point, focus: point };
3833
+ const hitElements = getHitElements(board, { ranges: [range] });
3834
+ const hasImage = hitElements.length && MindElement.hasImage(hitElements[0]);
3835
+ const hitImage = hasImage && isHitImage(board, hitElements[0], range);
3836
+ if (hitImage) {
3837
+ const currentOptions = board.getPluginOptions(PlaitPluginKey.withSelection);
3838
+ board.setPluginOptions(PlaitPluginKey.withSelection, {
3839
+ isDisabledSelect: true
3840
+ });
3841
+ setTimeout(() => {
3842
+ board.setPluginOptions(PlaitPluginKey.withSelection, { ...currentOptions });
3843
+ }, 0);
3844
+ selectedImageElement = hitElements[0];
3845
+ const component = PlaitElement.getComponent(selectedImageElement);
3846
+ component.imageDrawer.drawActive(selectedImageElement);
3847
+ clearSelectedElement(board);
3848
+ }
3849
+ else {
3850
+ if (selectedImageElement) {
3851
+ const component = PlaitElement.getComponent(selectedImageElement);
3852
+ component && component.imageDrawer.destroyActive();
3853
+ }
3854
+ selectedImageElement = null;
3855
+ }
3856
+ mousedown(event);
3857
+ };
3858
+ board.keydown = (event) => {
3859
+ if (!PlaitBoard.isReadonly(board) && selectedImageElement && (hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
3860
+ MindTransforms.removeImage(board, selectedImageElement);
3861
+ selectedImageElement = null;
3862
+ return;
3863
+ }
3864
+ keydown(event);
3865
+ };
3866
+ return board;
3867
+ };
3868
+
3625
3869
  const withMind = (board) => {
3626
3870
  const { drawElement, dblclick, keydown, insertFragment, setFragment, deleteFragment, isHitSelection, getRectangle, isMovable, isRecursion } = board;
3627
3871
  board.drawElement = (context) => {
@@ -3636,15 +3880,9 @@ const withMind = (board) => {
3636
3880
  board.applyTheme = (element) => {
3637
3881
  const mindElement = element;
3638
3882
  const shouldClearProperty = !PlaitBoard.isBoard(element) && (mindElement?.branchColor || mindElement?.fill || mindElement?.strokeColor);
3639
- const isAbstract = AbstractNode.isAbstract(element);
3640
3883
  if (shouldClearProperty) {
3641
3884
  const path = PlaitBoard.findPath(board, element);
3642
- if (isAbstract) {
3643
- Transforms.setNode(board, { fill: null, strokeColor: DefaultAbstractNodeStyle.strokeColor, branchColor: DefaultAbstractNodeStyle.branchColor }, path);
3644
- }
3645
- else {
3646
- Transforms.setNode(board, { fill: null, strokeColor: null, branchColor: null }, path);
3647
- }
3885
+ Transforms.setNode(board, { fill: null, strokeColor: null, branchColor: null }, path);
3648
3886
  }
3649
3887
  };
3650
3888
  board.getRectangle = element => {
@@ -3739,7 +3977,7 @@ const withMind = (board) => {
3739
3977
  MindTransforms.removeElements(board, selectedElements);
3740
3978
  deleteFragment(data);
3741
3979
  };
3742
- return withNodeHover(withMindHotkey(withMindExtend(withCreateMind(withAbstract(withNodeDnd(board))))));
3980
+ return withMindImage(withNodeHover(withMindHotkey(withMindExtend(withCreateMind(withAbstract(withNodeDnd(board)))))));
3743
3981
  };
3744
3982
 
3745
3983
  class MindEmojiBaseComponent {
@@ -3793,5 +4031,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3793
4031
  * Generated bundle index. Do not edit.
3794
4032
  */
3795
4033
 
3796
- export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_FONT_FAMILY, BRANCH_WIDTH, BaseDrawer, BranchShape, DEFAULT_FONT_FAMILY, DefaultAbstractNodeStyle, DefaultNodeStyle, ELEMENT_TO_NODE, EXTEND_DIAMETER, EXTEND_OFFSET, GRAY_COLOR, INHERIT_ATTRIBUTE_KEYS, IS_DRAGGING, LayoutDirection, LayoutDirectionsMap, MindColorfulThemeColor, MindDarkThemeColor, MindDefaultThemeColor, MindElement, MindElementShape, MindEmojiBaseComponent, MindModule, MindNode, MindNodeComponent, MindPointerType, MindQueries, MindRetroThemeColor, MindSoftThemeColor, MindStarryThemeColor, MindThemeColor, MindThemeColors, 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, ROOT_TOPIC_HEIGHT, STROKE_WIDTH, TOPIC_COLOR, TOPIC_DEFAULT_MAX_WORD_COUNT, TOPIC_FONT_SIZE, TRANSPARENT, WithMindPluginKey, addActiveOnDragOrigin, adjustAbstractToNode, adjustNodeToRoot, adjustRootToNode, canSetAbstract, copyNewNode, correctLayoutByDirection, createDefaultMind, createEmptyMind, createMindElement, deleteElementHandleAbstract, deleteElementsHandleRightNodeCount, detectDropTarget, directionCorrector, directionDetector, divideElementByParent, drawFakeDragNode, drawFakeDropNode, editTopic, extractNodesText, findLastChild, findLocationLeftIndex, getAbstractBranchColor, getAbstractBranchWidth, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getBranchShapeByMindElement, getBranchWidthByMindElement, getChildrenCount, getCorrespondingAbstract, getDefaultBranchColor, getDefaultBranchColorByIndex, getDefaultLayout, getEmojiForeignRectangle, getEmojiRectangle, getFirstLevelElement, getHitAbstractHandle, getInCorrectLayoutDirection, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getMindThemeColor, getNextBranchColor, getOverallAbstracts, getPathByDropTarget, getRectangleByElement, getRectangleByNode, getRectangleByResizingLocation, getRelativeStartEndByAbstractRef, getRootLayout, getShapeByElement, getStrokeByMindElement, getTopicRectangleByElement, getTopicRectangleByNode, getValidAbstractRefs, handleTouchedAbstract, hasAfterDraw, hasPreviousOrNextOfDropPath, insertElementHandleAbstract, insertElementHandleRightNodeCount, insertMindElement, isChildElement, isChildOfAbstract, isChildRight, isChildUp, isCorrectLayout, isDragging, isDropStandardRight, isHitEmojis, isHitMindElement, isInRightBranchOfStandardLayout, isMixedLayout, isSetAbstract, isValidTarget, isVirtualKey, removeActiveOnDragOrigin, separateChildren, setIsDragging, withMind, withMindExtend };
4034
+ export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_FONT_FAMILY, BRANCH_WIDTH, BaseDrawer, BranchShape, DEFAULT_FONT_FAMILY, DefaultAbstractNodeStyle, DefaultNodeStyle, ELEMENT_TO_NODE, EXTEND_DIAMETER, EXTEND_OFFSET, GRAY_COLOR, INHERIT_ATTRIBUTE_KEYS, IS_DRAGGING, LayoutDirection, LayoutDirectionsMap, MindColorfulThemeColor, MindDarkThemeColor, MindDefaultThemeColor, MindElement, MindElementShape, MindEmojiBaseComponent, MindImageBaseComponent, MindModule, MindNode, MindNodeComponent, MindPointerType, MindQueries, MindRetroThemeColor, MindSoftThemeColor, MindStarryThemeColor, MindThemeColor, MindThemeColors, 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, ROOT_TOPIC_HEIGHT, STROKE_WIDTH, TOPIC_COLOR, TOPIC_DEFAULT_MAX_WORD_COUNT, TOPIC_FONT_SIZE, TRANSPARENT, WithMindPluginKey, addActiveOnDragOrigin, adjustAbstractToNode, adjustNodeToRoot, adjustRootToNode, canSetAbstract, copyNewNode, correctLayoutByDirection, createDefaultMind, createEmptyMind, createMindElement, deleteElementHandleAbstract, deleteElementsHandleRightNodeCount, detectDropTarget, directionCorrector, directionDetector, divideElementByParent, drawFakeDragNode, drawFakeDropNode, editTopic, extractNodesText, findLastChild, findLocationLeftIndex, getAbstractBranchColor, getAbstractBranchWidth, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getBranchShapeByMindElement, getBranchWidthByMindElement, getChildrenCount, getCorrespondingAbstract, getDefaultBranchColor, getDefaultBranchColorByIndex, getDefaultLayout, getEmojiForeignRectangle, getEmojiRectangle, getFirstLevelElement, getHitAbstractHandle, getImageForeignRectangle, getInCorrectLayoutDirection, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getMindThemeColor, getNextBranchColor, getOverallAbstracts, getPathByDropTarget, getRectangleByElement, getRectangleByNode, getRectangleByResizingLocation, getRelativeStartEndByAbstractRef, getRootLayout, getShapeByElement, getStrokeByMindElement, getStrokeWidthByElement, getTopicRectangleByElement, getTopicRectangleByNode, getValidAbstractRefs, handleTouchedAbstract, hasAfterDraw, hasPreviousOrNextOfDropPath, insertElementHandleAbstract, insertElementHandleRightNodeCount, insertMindElement, isChildElement, isChildOfAbstract, isChildRight, isChildUp, isCorrectLayout, isDragging, isDropStandardRight, isHitEmojis, isHitImage, isHitMindElement, isInRightBranchOfStandardLayout, isMixedLayout, isSetAbstract, isValidTarget, isVirtualKey, removeActiveOnDragOrigin, separateChildren, setIsDragging, withMind, withMindExtend };
3797
4035
  //# sourceMappingURL=plait-mind.mjs.map