@plait/mind 0.8.0 → 0.10.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.
- package/README.md +132 -13
- package/base/base.drawer.d.ts +4 -3
- package/constants/default.d.ts +1 -1
- package/constants/node-topic-style.d.ts +1 -0
- package/drawer/node-active.drawer.d.ts +13 -0
- package/drawer/node-collapse.drawer.d.ts +8 -0
- package/drawer/{emojis.drawer.d.ts → node-emojis.drawer.d.ts} +1 -1
- package/drawer/{quick-insert.drawer.d.ts → node-insert.drawer.d.ts} +2 -2
- package/esm2020/base/base.drawer.mjs +13 -1
- package/esm2020/constants/default.mjs +2 -2
- package/esm2020/constants/node-rule.mjs +1 -1
- package/esm2020/constants/node-topic-style.mjs +2 -1
- package/esm2020/drawer/node-active.drawer.mjs +43 -0
- package/esm2020/drawer/node-collapse.drawer.mjs +108 -0
- package/esm2020/drawer/node-emojis.drawer.mjs +72 -0
- package/esm2020/drawer/node-insert.drawer.mjs +98 -0
- package/esm2020/interfaces/element.mjs +5 -2
- package/esm2020/mind.component.mjs +2 -1
- package/esm2020/mind.module.mjs +5 -5
- package/esm2020/node.component.mjs +57 -424
- package/esm2020/plugins/with-abstract-resize.mjs +3 -3
- package/esm2020/plugins/with-mind-create.mjs +23 -15
- package/esm2020/plugins/with-mind.mjs +9 -8
- package/esm2020/plugins/with-node-dnd.mjs +7 -4
- package/esm2020/plugins/with-node-hover.mjs +65 -0
- package/esm2020/transforms/node.mjs +10 -7
- package/esm2020/utils/abstract/resize.mjs +4 -6
- package/esm2020/utils/dnd/common.mjs +8 -2
- package/esm2020/utils/draw/node-dnd.mjs +3 -3
- package/esm2020/utils/mind.mjs +4 -4
- package/esm2020/utils/node/adjust-node.mjs +4 -5
- package/esm2020/utils/node/common.mjs +3 -3
- package/esm2020/utils/node/create-node.mjs +4 -3
- package/fesm2015/plait-mind.mjs +567 -857
- package/fesm2015/plait-mind.mjs.map +1 -1
- package/fesm2020/plait-mind.mjs +567 -845
- package/fesm2020/plait-mind.mjs.map +1 -1
- package/interfaces/element.d.ts +1 -0
- package/mind.module.d.ts +2 -2
- package/node.component.d.ts +15 -31
- package/package.json +1 -1
- package/plugins/with-mind-create.d.ts +3 -5
- package/plugins/with-node-dnd.d.ts +1 -1
- package/plugins/with-node-hover.d.ts +5 -0
- package/styles/mixins.scss +13 -15
- package/styles/styles.scss +12 -16
- package/utils/abstract/resize.d.ts +2 -2
- package/utils/node/common.d.ts +1 -1
- package/esm2020/drawer/emojis.drawer.mjs +0 -72
- package/esm2020/drawer/quick-insert.drawer.mjs +0 -211
- package/esm2020/utils/draw/node-topic.mjs +0 -32
- package/utils/draw/node-topic.d.ts +0 -16
package/fesm2020/plait-mind.mjs
CHANGED
|
@@ -1,55 +1,19 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, ChangeDetectionStrategy, NgModule, Directive, Input, HostListener } from '@angular/core';
|
|
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,
|
|
4
|
+
import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitBoard, depthFirstRecursion, Path, drawLinearPath, createG, updateForeignObject, PlaitNode, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, drawAbstractRoundRectangle, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, transformPoint, toPoint, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, isMainPointer, BOARD_TO_HOST, PlaitPluginKey, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
|
|
5
5
|
import { MindLayoutType, isIndentedLayout, getNonAbstractChildren, isStandardLayout, AbstractNode, isLeftLayout, isRightLayout, isVerticalLogicLayout, isHorizontalLogicLayout, isTopLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, getAbstractLayout, ConnectingPosition, GlobalLayout } from '@plait/layouts';
|
|
6
|
-
import {
|
|
7
|
-
import { fromEvent, Subject
|
|
8
|
-
import {
|
|
9
|
-
import { Node, Path as Path$1, Editor, Operation } from 'slate';
|
|
6
|
+
import { getTextSize, TEXT_DEFAULT_HEIGHT, TextManage, TextModule } from '@plait/text';
|
|
7
|
+
import { fromEvent, Subject } from 'rxjs';
|
|
8
|
+
import { Node, Path as Path$1 } from 'slate';
|
|
10
9
|
import { isKeyHotkey } from 'is-hotkey';
|
|
11
10
|
import { pointsOnBezierCurves } from 'points-on-curve';
|
|
11
|
+
import { take, filter } from 'rxjs/operators';
|
|
12
12
|
import * as i1 from '@angular/common';
|
|
13
13
|
import { CommonModule } from '@angular/common';
|
|
14
14
|
|
|
15
15
|
const ELEMENT_TO_NODE = new WeakMap();
|
|
16
16
|
|
|
17
|
-
const BASE = 4;
|
|
18
|
-
const PRIMARY_COLOR = '#6698FF';
|
|
19
|
-
const TRANSPARENT = 'transparent';
|
|
20
|
-
const GRAY_COLOR = '#AAAAAA';
|
|
21
|
-
const STROKE_WIDTH = 3;
|
|
22
|
-
const BRANCH_WIDTH = 3;
|
|
23
|
-
const EXTEND_OFFSET = 8;
|
|
24
|
-
const EXTEND_RADIUS = 16;
|
|
25
|
-
const QUICK_INSERT_CIRCLE_OFFSET = 9;
|
|
26
|
-
const QUICK_INSERT_CIRCLE_COLOR = '#6698FF';
|
|
27
|
-
const QUICK_INSERT_INNER_CROSS_COLOR = 'white';
|
|
28
|
-
|
|
29
|
-
const DefaultAbstractNodeStyle = {
|
|
30
|
-
strokeColor: GRAY_COLOR,
|
|
31
|
-
strokeWidth: 2,
|
|
32
|
-
branchColor: GRAY_COLOR,
|
|
33
|
-
branchWidth: 2
|
|
34
|
-
};
|
|
35
|
-
const DefaultNodeStyle = {
|
|
36
|
-
strokeWidth: 3,
|
|
37
|
-
branchWidth: 3,
|
|
38
|
-
fill: 'none'
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const TOPIC_COLOR = '#333';
|
|
42
|
-
const TOPIC_FONT_SIZE = 14;
|
|
43
|
-
const ROOT_TOPIC_FONT_SIZE = 18;
|
|
44
|
-
const TOPIC_DEFAULT_MAX_WORD_COUNT = 34;
|
|
45
|
-
|
|
46
|
-
const NODE_MIN_WIDTH = 18;
|
|
47
|
-
|
|
48
|
-
const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //primary color 50% opacity
|
|
49
|
-
const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;
|
|
50
|
-
const ABSTRACT_HANDLE_LENGTH = 10;
|
|
51
|
-
const ABSTRACT_HANDLE_MASK_WIDTH = 8;
|
|
52
|
-
|
|
53
17
|
const MindNode = {
|
|
54
18
|
get(root, path) {
|
|
55
19
|
let node = root;
|
|
@@ -215,36 +179,17 @@ const MindThemeColor = {
|
|
|
215
179
|
}
|
|
216
180
|
};
|
|
217
181
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
function getRectangleByElement(board, originPoint, element) {
|
|
231
|
-
const nodeRectangle = {
|
|
232
|
-
x: originPoint[0],
|
|
233
|
-
y: originPoint[1],
|
|
234
|
-
width: NodeSpace.getNodeWidth(board, element),
|
|
235
|
-
height: NodeSpace.getNodeHeight(board, element)
|
|
236
|
-
};
|
|
237
|
-
return nodeRectangle;
|
|
238
|
-
}
|
|
239
|
-
function isHitMindElement(board, point, element) {
|
|
240
|
-
const node = MindElement.getNode(element);
|
|
241
|
-
if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
|
|
242
|
-
return true;
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
182
|
+
const BASE = 4;
|
|
183
|
+
const PRIMARY_COLOR = '#6698FF';
|
|
184
|
+
const TRANSPARENT = 'transparent';
|
|
185
|
+
const GRAY_COLOR = '#AAAAAA';
|
|
186
|
+
const STROKE_WIDTH = 3;
|
|
187
|
+
const BRANCH_WIDTH = 3;
|
|
188
|
+
const EXTEND_OFFSET = 8;
|
|
189
|
+
const EXTEND_DIAMETER = 16;
|
|
190
|
+
const QUICK_INSERT_CIRCLE_OFFSET = 9;
|
|
191
|
+
const QUICK_INSERT_CIRCLE_COLOR = '#6698FF';
|
|
192
|
+
const QUICK_INSERT_INNER_CROSS_COLOR = 'white';
|
|
248
193
|
|
|
249
194
|
function getEmojisWidthHeight(board, element) {
|
|
250
195
|
const options = board.getMindOptions();
|
|
@@ -264,6 +209,79 @@ function getEmojiFontSize(element) {
|
|
|
264
209
|
}
|
|
265
210
|
}
|
|
266
211
|
|
|
212
|
+
const NodeDefaultSpace = {
|
|
213
|
+
horizontal: {
|
|
214
|
+
nodeAndText: BASE * 3,
|
|
215
|
+
emojiAndText: BASE * 1.5
|
|
216
|
+
},
|
|
217
|
+
vertical: {
|
|
218
|
+
nodeAndText: BASE * 1.5
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const RootDefaultSpace = {
|
|
222
|
+
horizontal: {
|
|
223
|
+
nodeAndText: BASE * 4,
|
|
224
|
+
emojiAndText: BASE * 2
|
|
225
|
+
},
|
|
226
|
+
vertical: {
|
|
227
|
+
nodeAndText: BASE * 2
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const getHorizontalSpaceBetweenNodeAndText = (board, element) => {
|
|
231
|
+
const isMind = PlaitMind.isMind(element);
|
|
232
|
+
const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;
|
|
233
|
+
return nodeAndText;
|
|
234
|
+
};
|
|
235
|
+
const getVerticalSpaceBetweenNodeAndText = (element) => {
|
|
236
|
+
const isMind = PlaitMind.isMind(element);
|
|
237
|
+
const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;
|
|
238
|
+
return nodeAndText;
|
|
239
|
+
};
|
|
240
|
+
const getSpaceEmojiAndText = (element) => {
|
|
241
|
+
const isMind = PlaitMind.isMind(element);
|
|
242
|
+
const emojiAndText = isMind ? RootDefaultSpace.horizontal.emojiAndText : NodeDefaultSpace.horizontal.emojiAndText;
|
|
243
|
+
return emojiAndText;
|
|
244
|
+
};
|
|
245
|
+
const NodeSpace = {
|
|
246
|
+
getNodeWidth(board, element) {
|
|
247
|
+
const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
|
|
248
|
+
if (MindElement.hasEmojis(element)) {
|
|
249
|
+
return (NodeSpace.getEmojiLeftSpace(board, element) +
|
|
250
|
+
getEmojisWidthHeight(board, element).width +
|
|
251
|
+
getSpaceEmojiAndText(element) +
|
|
252
|
+
element.width +
|
|
253
|
+
nodeAndText);
|
|
254
|
+
}
|
|
255
|
+
return nodeAndText + element.width + nodeAndText;
|
|
256
|
+
},
|
|
257
|
+
getNodeHeight(board, element) {
|
|
258
|
+
const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
|
|
259
|
+
return nodeAndText + element.height + nodeAndText;
|
|
260
|
+
},
|
|
261
|
+
getTextLeftSpace(board, element) {
|
|
262
|
+
const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
|
|
263
|
+
if (MindElement.hasEmojis(element)) {
|
|
264
|
+
return NodeSpace.getEmojiLeftSpace(board, element) + getEmojisWidthHeight(board, element).width + getSpaceEmojiAndText(element);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
return nodeAndText;
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
getTextTopSpace(element) {
|
|
271
|
+
const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
|
|
272
|
+
return nodeAndText;
|
|
273
|
+
},
|
|
274
|
+
getEmojiLeftSpace(board, element) {
|
|
275
|
+
const options = board.getMindOptions();
|
|
276
|
+
const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
|
|
277
|
+
return nodeAndText - options.emojiPadding;
|
|
278
|
+
},
|
|
279
|
+
getEmojiTopSpace(element) {
|
|
280
|
+
const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
|
|
281
|
+
return nodeAndText;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
267
285
|
function getEmojiRectangle(board, element) {
|
|
268
286
|
let { x, y } = getRectangleByNode(MindElement.getNode(element));
|
|
269
287
|
x = x + NodeSpace.getEmojiLeftSpace(board, element);
|
|
@@ -290,18 +308,38 @@ const isHitEmojis = (board, element, point) => {
|
|
|
290
308
|
return RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), getEmojiRectangle(board, element));
|
|
291
309
|
};
|
|
292
310
|
|
|
293
|
-
function
|
|
311
|
+
function getTopicRectangleByNode(board, node) {
|
|
312
|
+
let nodeRectangle = getRectangleByNode(node);
|
|
313
|
+
return getTopicRectangleByElement(board, nodeRectangle, node.origin);
|
|
314
|
+
}
|
|
315
|
+
function getTopicRectangleByElement(board, nodeRectangle, element) {
|
|
316
|
+
const x = nodeRectangle.x + NodeSpace.getTextLeftSpace(board, element);
|
|
317
|
+
const y = nodeRectangle.y + NodeSpace.getTextTopSpace(element);
|
|
318
|
+
const width = Math.ceil(element.width);
|
|
319
|
+
const height = Math.ceil(element.height);
|
|
320
|
+
return { height, width, x, y };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const NODE_MIN_WIDTH = 18;
|
|
324
|
+
|
|
325
|
+
function editTopic(element) {
|
|
294
326
|
const component = PlaitElement.getComponent(element);
|
|
295
|
-
component.
|
|
327
|
+
component.editTopic();
|
|
296
328
|
}
|
|
297
329
|
|
|
330
|
+
const TOPIC_COLOR = '#333';
|
|
331
|
+
const TOPIC_FONT_SIZE = 14;
|
|
332
|
+
const ROOT_TOPIC_FONT_SIZE = 18;
|
|
333
|
+
const ROOT_TOPIC_HEIGHT = 25;
|
|
334
|
+
const TOPIC_DEFAULT_MAX_WORD_COUNT = 34;
|
|
335
|
+
|
|
298
336
|
const adjustRootToNode = (board, node) => {
|
|
299
337
|
const newNode = { ...node };
|
|
300
338
|
delete newNode.isRoot;
|
|
301
339
|
delete newNode.rightNodeCount;
|
|
302
340
|
delete newNode.type;
|
|
303
341
|
const text = Node.string(node.data.topic.children[0]) || ' ';
|
|
304
|
-
const { width, height } =
|
|
342
|
+
const { width, height } = getTextSize(board, text, TOPIC_DEFAULT_MAX_WORD_COUNT);
|
|
305
343
|
newNode.width = Math.max(width, NODE_MIN_WIDTH);
|
|
306
344
|
newNode.height = height;
|
|
307
345
|
if (newNode.layout === MindLayoutType.standard) {
|
|
@@ -326,7 +364,7 @@ const adjustNodeToRoot = (board, node) => {
|
|
|
326
364
|
delete newElement?.fill;
|
|
327
365
|
delete newElement?.shape;
|
|
328
366
|
delete newElement?.strokeWidth;
|
|
329
|
-
const { width, height } =
|
|
367
|
+
const { width, height } = getTextSize(board, text, TOPIC_DEFAULT_MAX_WORD_COUNT, ROOT_TOPIC_FONT_SIZE);
|
|
330
368
|
newElement.width = Math.max(width, NODE_MIN_WIDTH);
|
|
331
369
|
newElement.height = height;
|
|
332
370
|
return {
|
|
@@ -345,7 +383,7 @@ const createEmptyMind = (board, point) => {
|
|
|
345
383
|
return rootElement;
|
|
346
384
|
};
|
|
347
385
|
const createDefaultMind = (point, rightNodeCount, layout) => {
|
|
348
|
-
const root = createMindElement('思维导图', 72,
|
|
386
|
+
const root = createMindElement('思维导图', 72, ROOT_TOPIC_HEIGHT, { layout });
|
|
349
387
|
root.rightNodeCount = rightNodeCount;
|
|
350
388
|
root.isRoot = true;
|
|
351
389
|
root.type = 'mindmap';
|
|
@@ -452,7 +490,7 @@ const insertMindElement = (board, inheritNode, path) => {
|
|
|
452
490
|
clearSelectedElement(board);
|
|
453
491
|
addSelectedElement(board, newElement);
|
|
454
492
|
setTimeout(() => {
|
|
455
|
-
|
|
493
|
+
editTopic(newElement);
|
|
456
494
|
});
|
|
457
495
|
};
|
|
458
496
|
const findLastChild = (child) => {
|
|
@@ -582,6 +620,18 @@ const getRootLayout = (root) => {
|
|
|
582
620
|
return root.layout || getDefaultLayout();
|
|
583
621
|
};
|
|
584
622
|
|
|
623
|
+
const DefaultAbstractNodeStyle = {
|
|
624
|
+
strokeColor: GRAY_COLOR,
|
|
625
|
+
strokeWidth: 2,
|
|
626
|
+
branchColor: GRAY_COLOR,
|
|
627
|
+
branchWidth: 2
|
|
628
|
+
};
|
|
629
|
+
const DefaultNodeStyle = {
|
|
630
|
+
strokeWidth: 3,
|
|
631
|
+
branchWidth: 3,
|
|
632
|
+
fill: 'none'
|
|
633
|
+
};
|
|
634
|
+
|
|
585
635
|
const getAvailableProperty = (board, element, propertyKey) => {
|
|
586
636
|
return element[propertyKey];
|
|
587
637
|
};
|
|
@@ -684,6 +734,12 @@ const isDragging = (board) => {
|
|
|
684
734
|
};
|
|
685
735
|
const setIsDragging = (board, state) => {
|
|
686
736
|
IS_DRAGGING.set(board, state);
|
|
737
|
+
if (state) {
|
|
738
|
+
PlaitBoard.getBoardNativeElement(board).classList.add('mind-node-dragging');
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
PlaitBoard.getBoardNativeElement(board).classList.remove('mind-node-dragging');
|
|
742
|
+
}
|
|
687
743
|
};
|
|
688
744
|
const hasPreviousOrNextOfDropPath = (parent, dropTarget, dropPath) => {
|
|
689
745
|
let children = getNonAbstractChildren(parent);
|
|
@@ -897,23 +953,10 @@ const getPathByDropTarget = (board, dropTarget) => {
|
|
|
897
953
|
return targetPath;
|
|
898
954
|
};
|
|
899
955
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
function drawRoundRectangleByElement(board, nodeRectangle, element) {
|
|
905
|
-
const defaultRootFill = getMindThemeColor(board).rootFill;
|
|
906
|
-
const fill = element.fill ? element.fill : element.isRoot ? defaultRootFill : DefaultNodeStyle.fill;
|
|
907
|
-
const stroke = getStrokeByMindElement(board, element);
|
|
908
|
-
const strokeWidth = element.strokeWidth ? element.strokeWidth : DefaultNodeStyle.strokeWidth;
|
|
909
|
-
const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), nodeRectangle.x, nodeRectangle.y, nodeRectangle.x + nodeRectangle.width, nodeRectangle.y + nodeRectangle.height, {
|
|
910
|
-
stroke,
|
|
911
|
-
strokeWidth,
|
|
912
|
-
fill,
|
|
913
|
-
fillStyle: 'solid'
|
|
914
|
-
});
|
|
915
|
-
return nodeG;
|
|
916
|
-
}
|
|
956
|
+
const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //primary color 50% opacity
|
|
957
|
+
const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;
|
|
958
|
+
const ABSTRACT_HANDLE_LENGTH = 10;
|
|
959
|
+
const ABSTRACT_HANDLE_MASK_WIDTH = 8;
|
|
917
960
|
|
|
918
961
|
var HorizontalPlacement;
|
|
919
962
|
(function (HorizontalPlacement) {
|
|
@@ -1171,13 +1214,13 @@ const drawFakeDragNode = (board, element, offsetX, offsetY) => {
|
|
|
1171
1214
|
};
|
|
1172
1215
|
const textRectangle = getTopicRectangleByNode(board, activeComponent.node);
|
|
1173
1216
|
const fakeNodeG = drawRoundRectangleByNode(board, fakeDraggingNode);
|
|
1174
|
-
const richtextG = activeComponent.
|
|
1217
|
+
const richtextG = activeComponent.textManage.g.cloneNode(true);
|
|
1175
1218
|
updateForeignObject(richtextG, textRectangle.width, textRectangle.height, textRectangle.x + offsetX, textRectangle.y + offsetY);
|
|
1176
1219
|
dragFakeNodeG?.append(fakeNodeG);
|
|
1177
1220
|
dragFakeNodeG?.append(richtextG);
|
|
1178
1221
|
// draw emojis
|
|
1179
1222
|
if (MindElement.hasEmojis(element)) {
|
|
1180
|
-
const fakeEmojisG = activeComponent.
|
|
1223
|
+
const fakeEmojisG = activeComponent.nodeEmojisDrawer.g.cloneNode(true);
|
|
1181
1224
|
const foreignRectangle = getEmojiForeignRectangle(board, element);
|
|
1182
1225
|
updateForeignObject(fakeEmojisG, foreignRectangle.width, foreignRectangle.height, foreignRectangle.x + offsetX, foreignRectangle.y + offsetY);
|
|
1183
1226
|
dragFakeNodeG?.append(fakeEmojisG);
|
|
@@ -1637,9 +1680,7 @@ function findLocationLeftIndex(board, parentChildren, location, isHorizontal) {
|
|
|
1637
1680
|
}
|
|
1638
1681
|
function handleTouchedAbstract(board, touchedAbstract, endPoint) {
|
|
1639
1682
|
let touchedHandle;
|
|
1640
|
-
const abstract = getSelectedElements(board)
|
|
1641
|
-
.filter(element => AbstractNode.isAbstract(element))
|
|
1642
|
-
.find(element => {
|
|
1683
|
+
const abstract = getSelectedElements(board).filter(element => AbstractNode.isAbstract(element)).find(element => {
|
|
1643
1684
|
touchedHandle = getHitAbstractHandle(board, element, endPoint);
|
|
1644
1685
|
return touchedHandle;
|
|
1645
1686
|
});
|
|
@@ -1648,13 +1689,13 @@ function handleTouchedAbstract(board, touchedAbstract, endPoint) {
|
|
|
1648
1689
|
}
|
|
1649
1690
|
if (touchedAbstract) {
|
|
1650
1691
|
const component = PlaitElement.getComponent(touchedAbstract);
|
|
1651
|
-
component.
|
|
1692
|
+
component.activeDrawer.updateAbstractOutline(touchedAbstract);
|
|
1652
1693
|
touchedAbstract = undefined;
|
|
1653
1694
|
}
|
|
1654
1695
|
if (abstract) {
|
|
1655
1696
|
touchedAbstract = abstract;
|
|
1656
1697
|
const component = PlaitElement.getComponent(touchedAbstract);
|
|
1657
|
-
component.
|
|
1698
|
+
component.activeDrawer.updateAbstractOutline(touchedAbstract, touchedHandle);
|
|
1658
1699
|
}
|
|
1659
1700
|
return touchedAbstract;
|
|
1660
1701
|
}
|
|
@@ -1879,6 +1920,9 @@ const MindElement = {
|
|
|
1879
1920
|
},
|
|
1880
1921
|
getEmojis(element) {
|
|
1881
1922
|
return element.data.emojis;
|
|
1923
|
+
},
|
|
1924
|
+
getEditor(element) {
|
|
1925
|
+
return PlaitElement.getComponent(element).textManage.componentRef.instance.editor;
|
|
1882
1926
|
}
|
|
1883
1927
|
};
|
|
1884
1928
|
var MindElementShape;
|
|
@@ -1892,118 +1936,53 @@ var BranchShape;
|
|
|
1892
1936
|
BranchShape["polyline"] = "polyline";
|
|
1893
1937
|
})(BranchShape || (BranchShape = {}));
|
|
1894
1938
|
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1939
|
+
function getRectangleByNode(node) {
|
|
1940
|
+
const x = node.x + node.hGap;
|
|
1941
|
+
let y = node.y + node.vGap;
|
|
1942
|
+
const width = node.width - node.hGap * 2;
|
|
1943
|
+
const height = node.height - node.vGap * 2;
|
|
1944
|
+
return {
|
|
1945
|
+
x,
|
|
1946
|
+
y,
|
|
1947
|
+
width,
|
|
1948
|
+
height
|
|
1949
|
+
};
|
|
1950
|
+
}
|
|
1951
|
+
function getRectangleByElement(board, originPoint, element) {
|
|
1952
|
+
const nodeRectangle = {
|
|
1953
|
+
x: originPoint[0],
|
|
1954
|
+
y: originPoint[1],
|
|
1955
|
+
width: NodeSpace.getNodeWidth(board, element),
|
|
1956
|
+
height: NodeSpace.getNodeHeight(board, element)
|
|
1957
|
+
};
|
|
1958
|
+
return nodeRectangle;
|
|
1959
|
+
}
|
|
1960
|
+
function isHitMindElement(board, point, element) {
|
|
1961
|
+
const node = MindElement.getNode(element);
|
|
1962
|
+
if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
|
|
1963
|
+
return true;
|
|
1902
1964
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
horizontal: {
|
|
1906
|
-
nodeAndText: BASE * 4,
|
|
1907
|
-
emojiAndText: BASE * 2
|
|
1908
|
-
},
|
|
1909
|
-
vertical: {
|
|
1910
|
-
nodeAndText: BASE * 2
|
|
1965
|
+
else {
|
|
1966
|
+
return false;
|
|
1911
1967
|
}
|
|
1912
|
-
};
|
|
1913
|
-
const getHorizontalSpaceBetweenNodeAndText = (board, element) => {
|
|
1914
|
-
const isMind = PlaitMind.isMind(element);
|
|
1915
|
-
const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;
|
|
1916
|
-
return nodeAndText;
|
|
1917
|
-
};
|
|
1918
|
-
const getVerticalSpaceBetweenNodeAndText = (element) => {
|
|
1919
|
-
const isMind = PlaitMind.isMind(element);
|
|
1920
|
-
const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;
|
|
1921
|
-
return nodeAndText;
|
|
1922
|
-
};
|
|
1923
|
-
const getSpaceEmojiAndText = (element) => {
|
|
1924
|
-
const isMind = PlaitMind.isMind(element);
|
|
1925
|
-
const emojiAndText = isMind ? RootDefaultSpace.horizontal.emojiAndText : NodeDefaultSpace.horizontal.emojiAndText;
|
|
1926
|
-
return emojiAndText;
|
|
1927
|
-
};
|
|
1928
|
-
const NodeSpace = {
|
|
1929
|
-
getNodeWidth(board, element) {
|
|
1930
|
-
const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
|
|
1931
|
-
if (MindElement.hasEmojis(element)) {
|
|
1932
|
-
return (NodeSpace.getEmojiLeftSpace(board, element) +
|
|
1933
|
-
getEmojisWidthHeight(board, element).width +
|
|
1934
|
-
getSpaceEmojiAndText(element) +
|
|
1935
|
-
element.width +
|
|
1936
|
-
nodeAndText);
|
|
1937
|
-
}
|
|
1938
|
-
return nodeAndText + element.width + nodeAndText;
|
|
1939
|
-
},
|
|
1940
|
-
getNodeHeight(board, element) {
|
|
1941
|
-
const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
|
|
1942
|
-
return nodeAndText + element.height + nodeAndText;
|
|
1943
|
-
},
|
|
1944
|
-
getTextLeftSpace(board, element) {
|
|
1945
|
-
const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
|
|
1946
|
-
if (MindElement.hasEmojis(element)) {
|
|
1947
|
-
return NodeSpace.getEmojiLeftSpace(board, element) + getEmojisWidthHeight(board, element).width + getSpaceEmojiAndText(element);
|
|
1948
|
-
}
|
|
1949
|
-
else {
|
|
1950
|
-
return nodeAndText;
|
|
1951
|
-
}
|
|
1952
|
-
},
|
|
1953
|
-
getTextTopSpace(element) {
|
|
1954
|
-
const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
|
|
1955
|
-
return nodeAndText;
|
|
1956
|
-
},
|
|
1957
|
-
getEmojiLeftSpace(board, element) {
|
|
1958
|
-
const options = board.getMindOptions();
|
|
1959
|
-
const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
|
|
1960
|
-
return nodeAndText - options.emojiPadding;
|
|
1961
|
-
},
|
|
1962
|
-
getEmojiTopSpace(element) {
|
|
1963
|
-
const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
|
|
1964
|
-
return nodeAndText;
|
|
1965
|
-
}
|
|
1966
|
-
};
|
|
1967
|
-
|
|
1968
|
-
function getTopicRectangleByNode(board, node) {
|
|
1969
|
-
let nodeRectangle = getRectangleByNode(node);
|
|
1970
|
-
return getTopicRectangleByElement(board, nodeRectangle, node.origin);
|
|
1971
|
-
}
|
|
1972
|
-
function getTopicRectangleByElement(board, nodeRectangle, element) {
|
|
1973
|
-
const x = nodeRectangle.x + NodeSpace.getTextLeftSpace(board, element);
|
|
1974
|
-
const y = nodeRectangle.y + NodeSpace.getTextTopSpace(element);
|
|
1975
|
-
const width = Math.ceil(element.width);
|
|
1976
|
-
const height = Math.ceil(element.height);
|
|
1977
|
-
return { height, width, x, y };
|
|
1978
1968
|
}
|
|
1979
1969
|
|
|
1980
|
-
function
|
|
1981
|
-
const rectangle =
|
|
1982
|
-
return
|
|
1983
|
-
}
|
|
1984
|
-
function drawTopicByElement(board, rectangle, element, viewContainerRef) {
|
|
1985
|
-
const containerRef = viewContainerRef || PlaitBoard.getComponent(board).viewContainerRef;
|
|
1986
|
-
const classList = [];
|
|
1987
|
-
if (element.isRoot) {
|
|
1988
|
-
classList.push('root-node');
|
|
1989
|
-
classList.push('font-size-18');
|
|
1990
|
-
}
|
|
1991
|
-
else {
|
|
1992
|
-
classList.push('child-node');
|
|
1993
|
-
}
|
|
1994
|
-
// COMPAT: last character can not show in safari browser
|
|
1995
|
-
return drawRichtext(rectangle.x, rectangle.y, rectangle.width, rectangle.height, element.data.topic, containerRef, classList);
|
|
1970
|
+
function drawRoundRectangleByNode(board, node) {
|
|
1971
|
+
const rectangle = getRectangleByNode(node);
|
|
1972
|
+
return drawRoundRectangleByElement(board, rectangle, node.origin);
|
|
1996
1973
|
}
|
|
1997
|
-
function
|
|
1998
|
-
const
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
1974
|
+
function drawRoundRectangleByElement(board, nodeRectangle, element) {
|
|
1975
|
+
const defaultRootFill = getMindThemeColor(board).rootFill;
|
|
1976
|
+
const fill = element.fill ? element.fill : element.isRoot ? defaultRootFill : DefaultNodeStyle.fill;
|
|
1977
|
+
const stroke = getStrokeByMindElement(board, element);
|
|
1978
|
+
const strokeWidth = element.strokeWidth ? element.strokeWidth : DefaultNodeStyle.strokeWidth;
|
|
1979
|
+
const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), nodeRectangle.x, nodeRectangle.y, nodeRectangle.x + nodeRectangle.width, nodeRectangle.y + nodeRectangle.height, {
|
|
1980
|
+
stroke,
|
|
1981
|
+
strokeWidth,
|
|
1982
|
+
fill,
|
|
1983
|
+
fillStyle: 'solid'
|
|
1984
|
+
});
|
|
1985
|
+
return nodeG;
|
|
2007
1986
|
}
|
|
2008
1987
|
|
|
2009
1988
|
function drawAbstractLink(board, node, isHorizontal) {
|
|
@@ -2084,7 +2063,7 @@ class EmojiDrawer {
|
|
|
2084
2063
|
}
|
|
2085
2064
|
}
|
|
2086
2065
|
}
|
|
2087
|
-
class
|
|
2066
|
+
class NodeEmojisDrawer {
|
|
2088
2067
|
constructor(board, viewContainerRef) {
|
|
2089
2068
|
this.board = board;
|
|
2090
2069
|
this.viewContainerRef = viewContainerRef;
|
|
@@ -2210,11 +2189,15 @@ const correctLogicLayoutNode = (board, layout, path) => {
|
|
|
2210
2189
|
}
|
|
2211
2190
|
};
|
|
2212
2191
|
|
|
2192
|
+
const normalizeWidthAndHeight = (board, width, height) => {
|
|
2193
|
+
const newWidth = width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom;
|
|
2194
|
+
const newHeight = height / board.viewport.zoom;
|
|
2195
|
+
return { width: newWidth, height: newHeight };
|
|
2196
|
+
};
|
|
2213
2197
|
const setTopic = (board, element, topic, width, height) => {
|
|
2214
2198
|
const newElement = {
|
|
2215
2199
|
data: { topic },
|
|
2216
|
-
|
|
2217
|
-
height: height / board.viewport.zoom
|
|
2200
|
+
...normalizeWidthAndHeight(board, width, height)
|
|
2218
2201
|
};
|
|
2219
2202
|
if (MindElement.hasEmojis(element)) {
|
|
2220
2203
|
newElement.data.emojis = element.data.emojis;
|
|
@@ -2224,11 +2207,10 @@ const setTopic = (board, element, topic, width, height) => {
|
|
|
2224
2207
|
};
|
|
2225
2208
|
const setTopicSize = (board, element, width, height) => {
|
|
2226
2209
|
const newElement = {
|
|
2227
|
-
|
|
2228
|
-
height: height / board.viewport.zoom
|
|
2210
|
+
...normalizeWidthAndHeight(board, width, height)
|
|
2229
2211
|
};
|
|
2230
|
-
|
|
2231
|
-
|
|
2212
|
+
if (element.width !== newElement.width || element.height !== newElement.height) {
|
|
2213
|
+
const path = PlaitBoard.findPath(board, element);
|
|
2232
2214
|
Transforms.setNode(board, newElement, path);
|
|
2233
2215
|
}
|
|
2234
2216
|
};
|
|
@@ -2327,6 +2309,127 @@ const MindTransforms = {
|
|
|
2327
2309
|
setRightNodeCountByRefs
|
|
2328
2310
|
};
|
|
2329
2311
|
|
|
2312
|
+
class BaseDrawer {
|
|
2313
|
+
constructor(board) {
|
|
2314
|
+
this.board = board;
|
|
2315
|
+
}
|
|
2316
|
+
draw(element, parentG, data) {
|
|
2317
|
+
this.destroy();
|
|
2318
|
+
if (this.canDraw && this.canDraw(element, data)) {
|
|
2319
|
+
const g = this.baseDraw(element, data);
|
|
2320
|
+
if (g) {
|
|
2321
|
+
parentG.append(g);
|
|
2322
|
+
}
|
|
2323
|
+
if (hasAfterDraw(this)) {
|
|
2324
|
+
this.afterDraw(element);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
destroy() {
|
|
2329
|
+
if (this.g) {
|
|
2330
|
+
this.g.remove();
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
function hasAfterDraw(value) {
|
|
2335
|
+
if (value.afterDraw) {
|
|
2336
|
+
return true;
|
|
2337
|
+
}
|
|
2338
|
+
return false;
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
function findNewChildNodePath(board, element) {
|
|
2342
|
+
const children = getNonAbstractChildren(element);
|
|
2343
|
+
return PlaitBoard.findPath(board, element).concat(children.length);
|
|
2344
|
+
}
|
|
2345
|
+
function findNewSiblingNodePath(board, element) {
|
|
2346
|
+
const path = PlaitBoard.findPath(board, element);
|
|
2347
|
+
return Path$1.next(path);
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
class NodeInsertDrawer extends BaseDrawer {
|
|
2351
|
+
canDraw(element) {
|
|
2352
|
+
if (PlaitBoard.isReadonly(this.board) || element?.isCollapsed) {
|
|
2353
|
+
return false;
|
|
2354
|
+
}
|
|
2355
|
+
return true;
|
|
2356
|
+
}
|
|
2357
|
+
baseDraw(element) {
|
|
2358
|
+
const quickInsertG = createG();
|
|
2359
|
+
this.g = quickInsertG;
|
|
2360
|
+
quickInsertG.classList.add('quick-insert');
|
|
2361
|
+
const node = MindElement.getNode(element);
|
|
2362
|
+
const layout = MindQueries.getLayoutByElement(element);
|
|
2363
|
+
const isHorizontal = isHorizontalLayout(layout);
|
|
2364
|
+
let linkDirection = getLayoutDirection(node, isHorizontal);
|
|
2365
|
+
if (isIndentedLayout(layout)) {
|
|
2366
|
+
linkDirection = isTopLayout(layout) ? LayoutDirection.top : LayoutDirection.bottom;
|
|
2367
|
+
}
|
|
2368
|
+
const isUnderlineShape = getShapeByElement(this.board, element) === MindElementShape.underline;
|
|
2369
|
+
const nodeClient = getRectangleByNode(node);
|
|
2370
|
+
const branchWidth = getBranchWidthByMindElement(this.board, element);
|
|
2371
|
+
const branchColor = PlaitMind.isMind(element)
|
|
2372
|
+
? getNextBranchColor(this.board, element)
|
|
2373
|
+
: getBranchColorByMindElement(this.board, element);
|
|
2374
|
+
let distance = 8;
|
|
2375
|
+
let placement = [HorizontalPlacement.right, VerticalPlacement.middle];
|
|
2376
|
+
transformPlacement(placement, linkDirection);
|
|
2377
|
+
// underline shape and horizontal
|
|
2378
|
+
if (isHorizontal && isUnderlineShape && !element.isRoot) {
|
|
2379
|
+
placement[1] = VerticalPlacement.bottom;
|
|
2380
|
+
}
|
|
2381
|
+
let beginPoint = getPointByPlacement(nodeClient, placement);
|
|
2382
|
+
if (element.children.length > 0 && !element.isRoot) {
|
|
2383
|
+
beginPoint = moveXOfPoint(beginPoint, EXTEND_DIAMETER + 8, linkDirection);
|
|
2384
|
+
distance = 5;
|
|
2385
|
+
}
|
|
2386
|
+
const endPoint = moveXOfPoint(beginPoint, distance, linkDirection);
|
|
2387
|
+
const circleCenter = moveXOfPoint(endPoint, 8, linkDirection);
|
|
2388
|
+
const line = PlaitBoard.getRoughSVG(this.board).line(beginPoint[0], beginPoint[1], endPoint[0], endPoint[1], {
|
|
2389
|
+
stroke: branchColor,
|
|
2390
|
+
strokeWidth: branchWidth
|
|
2391
|
+
});
|
|
2392
|
+
const circle = PlaitBoard.getRoughSVG(this.board).circle(circleCenter[0], circleCenter[1], EXTEND_DIAMETER, {
|
|
2393
|
+
fill: QUICK_INSERT_CIRCLE_COLOR,
|
|
2394
|
+
stroke: QUICK_INSERT_CIRCLE_COLOR,
|
|
2395
|
+
fillStyle: 'solid'
|
|
2396
|
+
});
|
|
2397
|
+
const HLineBeginPoint = [circleCenter[0] - 5, circleCenter[1]];
|
|
2398
|
+
const HLineEndPoint = [circleCenter[0] + 5, circleCenter[1]];
|
|
2399
|
+
const VLineBeginPoint = [circleCenter[0], circleCenter[1] - 5];
|
|
2400
|
+
const VLineEndPoint = [circleCenter[0], circleCenter[1] + 5];
|
|
2401
|
+
const innerCrossHLine = PlaitBoard.getRoughSVG(this.board).line(HLineBeginPoint[0], HLineBeginPoint[1], HLineEndPoint[0], HLineEndPoint[1], {
|
|
2402
|
+
stroke: QUICK_INSERT_INNER_CROSS_COLOR,
|
|
2403
|
+
strokeWidth: 2
|
|
2404
|
+
});
|
|
2405
|
+
const innerCrossVLine = PlaitBoard.getRoughSVG(this.board).line(VLineBeginPoint[0], VLineBeginPoint[1], VLineEndPoint[0], VLineEndPoint[1], {
|
|
2406
|
+
stroke: QUICK_INSERT_INNER_CROSS_COLOR,
|
|
2407
|
+
strokeWidth: 2
|
|
2408
|
+
});
|
|
2409
|
+
quickInsertG.appendChild(line);
|
|
2410
|
+
quickInsertG.appendChild(circle);
|
|
2411
|
+
quickInsertG.appendChild(innerCrossHLine);
|
|
2412
|
+
quickInsertG.appendChild(innerCrossVLine);
|
|
2413
|
+
return quickInsertG;
|
|
2414
|
+
}
|
|
2415
|
+
afterDraw(element) {
|
|
2416
|
+
if (!this.g) {
|
|
2417
|
+
throw new Error(`can not find quick insert g`);
|
|
2418
|
+
}
|
|
2419
|
+
fromEvent(this.g, 'mousedown')
|
|
2420
|
+
.pipe(take(1))
|
|
2421
|
+
.subscribe(e => {
|
|
2422
|
+
e.stopPropagation();
|
|
2423
|
+
});
|
|
2424
|
+
fromEvent(this.g, 'mouseup')
|
|
2425
|
+
.pipe(take(1))
|
|
2426
|
+
.subscribe(() => {
|
|
2427
|
+
const path = findNewChildNodePath(this.board, element);
|
|
2428
|
+
insertMindElement(this.board, element, path);
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2330
2433
|
function drawAbstractIncludedOutline(board, roughSVG, element, activeHandlePosition, resizingLocation) {
|
|
2331
2434
|
const abstractIncludedG = createG();
|
|
2332
2435
|
const parentElement = MindElement.getParent(element);
|
|
@@ -2392,294 +2495,206 @@ function changeBoardClass(board, activeHandlePosition, isHorizontal) {
|
|
|
2392
2495
|
}
|
|
2393
2496
|
}
|
|
2394
2497
|
|
|
2395
|
-
class BaseDrawer {
|
|
2396
|
-
|
|
2397
|
-
|
|
2498
|
+
class NodeActiveDrawer extends BaseDrawer {
|
|
2499
|
+
canDraw(element, data) {
|
|
2500
|
+
if (data.selected) {
|
|
2501
|
+
return true;
|
|
2502
|
+
}
|
|
2503
|
+
else {
|
|
2504
|
+
return false;
|
|
2505
|
+
}
|
|
2398
2506
|
}
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2507
|
+
baseDraw(element, data) {
|
|
2508
|
+
const activeG = createG();
|
|
2509
|
+
this.g = activeG;
|
|
2510
|
+
if (AbstractNode.isAbstract(element)) {
|
|
2511
|
+
this.abstractOutlineG = drawAbstractIncludedOutline(this.board, PlaitBoard.getRoughSVG(this.board), element);
|
|
2512
|
+
activeG.append(this.abstractOutlineG);
|
|
2513
|
+
}
|
|
2514
|
+
const node = MindElement.getNode(element);
|
|
2515
|
+
let { x, y, width, height } = getRectangleByNode(node);
|
|
2516
|
+
const strokeG = drawRoundRectangle(PlaitBoard.getRoughSVG(this.board), x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, strokeWidth: 2, fill: '' }, true);
|
|
2517
|
+
this.g.appendChild(strokeG);
|
|
2518
|
+
if (!data.isEditing) {
|
|
2519
|
+
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);
|
|
2520
|
+
fillG.style.opacity = '0.15';
|
|
2521
|
+
this.g.appendChild(fillG);
|
|
2402
2522
|
}
|
|
2523
|
+
return activeG;
|
|
2403
2524
|
}
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2525
|
+
updateAbstractOutline(element, activeHandlePosition, resizingLocation) {
|
|
2526
|
+
if (this.abstractOutlineG) {
|
|
2527
|
+
this.abstractOutlineG.remove();
|
|
2528
|
+
}
|
|
2529
|
+
this.abstractOutlineG = drawAbstractIncludedOutline(this.board, PlaitBoard.getRoughSVG(this.board), element, activeHandlePosition, resizingLocation);
|
|
2530
|
+
this.g.append(this.abstractOutlineG);
|
|
2408
2531
|
}
|
|
2409
|
-
return false;
|
|
2410
|
-
}
|
|
2411
|
-
|
|
2412
|
-
function findNewChildNodePath(board, element) {
|
|
2413
|
-
const children = getNonAbstractChildren(element);
|
|
2414
|
-
return PlaitBoard.findPath(board, element).concat(children.length);
|
|
2415
|
-
}
|
|
2416
|
-
function findNewSiblingNodePath(board, element) {
|
|
2417
|
-
const path = PlaitBoard.findPath(board, element);
|
|
2418
|
-
return Path$1.next(path);
|
|
2419
2532
|
}
|
|
2420
2533
|
|
|
2421
|
-
class
|
|
2534
|
+
class CollapseDrawer extends BaseDrawer {
|
|
2422
2535
|
canDraw(element) {
|
|
2423
|
-
if (
|
|
2424
|
-
return
|
|
2536
|
+
if (element.children.length && !PlaitMind.isMind(element)) {
|
|
2537
|
+
return true;
|
|
2425
2538
|
}
|
|
2426
|
-
return
|
|
2539
|
+
return false;
|
|
2427
2540
|
}
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
quickInsertG.classList.add('quick-insert');
|
|
2541
|
+
baseDraw(element) {
|
|
2542
|
+
const collapseG = createG();
|
|
2543
|
+
this.g = collapseG;
|
|
2544
|
+
collapseG.classList.add('collapse-container');
|
|
2433
2545
|
const node = MindElement.getNode(element);
|
|
2434
|
-
const
|
|
2435
|
-
/**
|
|
2436
|
-
* 方位:
|
|
2437
|
-
* 1. 左、左上、左下
|
|
2438
|
-
* 2. 右、右上、右下
|
|
2439
|
-
* 3. 上、上左、上右
|
|
2440
|
-
* 4. 下、下左、下右
|
|
2441
|
-
*/
|
|
2442
|
-
const shape = getShapeByElement(this.board, element);
|
|
2443
|
-
// 形状是矩形要偏移边框的线宽
|
|
2546
|
+
const stroke = getBranchColorByMindElement(this.board, element);
|
|
2444
2547
|
const branchWidth = getBranchWidthByMindElement(this.board, element);
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2548
|
+
const layout = MindQueries.getLayoutByElement(element);
|
|
2549
|
+
const isUnderlineShape = getShapeByElement(this.board, element) === MindElementShape.underline;
|
|
2550
|
+
const isHorizontal = isHorizontalLayout(layout);
|
|
2551
|
+
const nodeClient = getRectangleByNode(node);
|
|
2552
|
+
let linkDirection = getLayoutDirection(node, isHorizontal);
|
|
2553
|
+
if (isIndentedLayout(layout)) {
|
|
2554
|
+
linkDirection = isTopLayout(layout) ? LayoutDirection.top : LayoutDirection.bottom;
|
|
2448
2555
|
}
|
|
2449
|
-
let
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
const extraOffset = 3;
|
|
2455
|
-
const underlineCoordinates = {
|
|
2456
|
-
// 画线方向:右向左 <--
|
|
2457
|
-
[MindLayoutType.left]: {
|
|
2458
|
-
// EXTEND_RADIUS * 0.5 是 左方向,折叠/收起的偏移量
|
|
2459
|
-
startX: x - (offset > 0 ? offset + EXTEND_RADIUS * 0.5 : 0) - offsetRootBorderLineWidth,
|
|
2460
|
-
startY: y + height,
|
|
2461
|
-
endX: x -
|
|
2462
|
-
offsetBorderLineWidth -
|
|
2463
|
-
offsetRootBorderLineWidth -
|
|
2464
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) -
|
|
2465
|
-
EXTEND_RADIUS,
|
|
2466
|
-
endY: y + height
|
|
2467
|
-
},
|
|
2468
|
-
// 画线方向:左向右 -->
|
|
2469
|
-
[MindLayoutType.right]: {
|
|
2470
|
-
startX: x + width + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
|
|
2471
|
-
startY: y + height,
|
|
2472
|
-
endX: x +
|
|
2473
|
-
width +
|
|
2474
|
-
offsetBorderLineWidth +
|
|
2475
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
|
|
2476
|
-
EXTEND_RADIUS +
|
|
2477
|
-
offsetRootBorderLineWidth,
|
|
2478
|
-
endY: y + height
|
|
2479
|
-
},
|
|
2480
|
-
// 画线方向:下向上 -->
|
|
2481
|
-
[MindLayoutType.upward]: {
|
|
2482
|
-
startX: x + width * 0.5,
|
|
2483
|
-
startY: y - offsetBorderLineWidth - (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) - offsetRootBorderLineWidth,
|
|
2484
|
-
endX: x + width * 0.5,
|
|
2485
|
-
endY: y -
|
|
2486
|
-
offsetBorderLineWidth -
|
|
2487
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) -
|
|
2488
|
-
EXTEND_RADIUS -
|
|
2489
|
-
offsetRootBorderLineWidth
|
|
2490
|
-
},
|
|
2491
|
-
// 画线方向:上向下 -->
|
|
2492
|
-
[MindLayoutType.downward]: {
|
|
2493
|
-
startX: x + width * 0.5,
|
|
2494
|
-
startY: y + height + offsetBorderLineWidth + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
|
|
2495
|
-
endX: x + width * 0.5,
|
|
2496
|
-
endY: y +
|
|
2497
|
-
height +
|
|
2498
|
-
offsetBorderLineWidth +
|
|
2499
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
|
|
2500
|
-
EXTEND_RADIUS +
|
|
2501
|
-
offsetRootBorderLineWidth
|
|
2502
|
-
},
|
|
2503
|
-
[MindLayoutType.leftBottomIndented]: {
|
|
2504
|
-
startX: x + width * 0.5,
|
|
2505
|
-
startY: y + height + offsetBorderLineWidth + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
|
|
2506
|
-
endX: x + width * 0.5,
|
|
2507
|
-
endY: y +
|
|
2508
|
-
height +
|
|
2509
|
-
offsetBorderLineWidth +
|
|
2510
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
|
|
2511
|
-
EXTEND_RADIUS +
|
|
2512
|
-
offsetRootBorderLineWidth
|
|
2513
|
-
},
|
|
2514
|
-
[MindLayoutType.leftTopIndented]: {
|
|
2515
|
-
startX: x + width * 0.5,
|
|
2516
|
-
startY: y - offsetBorderLineWidth - (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) - offsetRootBorderLineWidth,
|
|
2517
|
-
endX: x + width * 0.5,
|
|
2518
|
-
endY: y -
|
|
2519
|
-
offsetBorderLineWidth -
|
|
2520
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) -
|
|
2521
|
-
EXTEND_RADIUS -
|
|
2522
|
-
offsetRootBorderLineWidth
|
|
2523
|
-
},
|
|
2524
|
-
[MindLayoutType.rightBottomIndented]: {
|
|
2525
|
-
startX: x + width * 0.5,
|
|
2526
|
-
startY: y + height + offsetBorderLineWidth + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
|
|
2527
|
-
endX: x + width * 0.5,
|
|
2528
|
-
endY: y +
|
|
2529
|
-
height +
|
|
2530
|
-
offsetBorderLineWidth +
|
|
2531
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
|
|
2532
|
-
EXTEND_RADIUS +
|
|
2533
|
-
offsetRootBorderLineWidth
|
|
2534
|
-
},
|
|
2535
|
-
[MindLayoutType.rightTopIndented]: {
|
|
2536
|
-
startX: x + width * 0.5,
|
|
2537
|
-
startY: y - offsetBorderLineWidth - (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) - offsetRootBorderLineWidth,
|
|
2538
|
-
endX: x + width * 0.5,
|
|
2539
|
-
endY: y -
|
|
2540
|
-
offsetBorderLineWidth -
|
|
2541
|
-
(offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) -
|
|
2542
|
-
EXTEND_RADIUS -
|
|
2543
|
-
offsetRootBorderLineWidth
|
|
2544
|
-
}
|
|
2545
|
-
};
|
|
2546
|
-
if (shape === MindElementShape.roundRectangle || element.isRoot) {
|
|
2547
|
-
underlineCoordinates[MindLayoutType.left].startY -= height * 0.5;
|
|
2548
|
-
underlineCoordinates[MindLayoutType.left].endY -= height * 0.5;
|
|
2549
|
-
underlineCoordinates[MindLayoutType.right].startY -= height * 0.5;
|
|
2550
|
-
underlineCoordinates[MindLayoutType.right].endY -= height * 0.5;
|
|
2556
|
+
let placement = [HorizontalPlacement.right, VerticalPlacement.middle];
|
|
2557
|
+
transformPlacement(placement, linkDirection);
|
|
2558
|
+
// underline shape and horizontal
|
|
2559
|
+
if (isHorizontal && isUnderlineShape && !element.isRoot) {
|
|
2560
|
+
placement[1] = VerticalPlacement.bottom;
|
|
2551
2561
|
}
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
}
|
|
2560
|
-
const
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
stroke: QUICK_INSERT_INNER_CROSS_COLOR,
|
|
2588
|
-
strokeWidth: 2
|
|
2589
|
-
});
|
|
2590
|
-
const innerRingVLine = PlaitBoard.getRoughSVG(this.board).line(innerCrossCoordinates.vertical.startX, innerCrossCoordinates.vertical.startY, innerCrossCoordinates.vertical.endX, innerCrossCoordinates.vertical.endY, {
|
|
2591
|
-
stroke: QUICK_INSERT_INNER_CROSS_COLOR,
|
|
2592
|
-
strokeWidth: 2
|
|
2593
|
-
});
|
|
2594
|
-
quickInsertG.appendChild(underline);
|
|
2595
|
-
quickInsertG.appendChild(circle);
|
|
2596
|
-
quickInsertG.appendChild(innerCrossHLine);
|
|
2597
|
-
quickInsertG.appendChild(innerRingVLine);
|
|
2562
|
+
let startPoint = getPointByPlacement(nodeClient, placement);
|
|
2563
|
+
const endPoint = moveXOfPoint(startPoint, EXTEND_OFFSET, linkDirection);
|
|
2564
|
+
const circleCenter = moveXOfPoint(endPoint, EXTEND_DIAMETER / 2, linkDirection);
|
|
2565
|
+
const arrowPoints = this.getArrowPoints(circleCenter, linkDirection);
|
|
2566
|
+
const arrowLine = drawLinearPath(arrowPoints, {
|
|
2567
|
+
stroke,
|
|
2568
|
+
strokeWidth: 2
|
|
2569
|
+
});
|
|
2570
|
+
const extendLine = PlaitBoard.getRoughSVG(this.board).line(startPoint[0], startPoint[1], endPoint[0], endPoint[1], {
|
|
2571
|
+
strokeWidth: branchWidth,
|
|
2572
|
+
stroke
|
|
2573
|
+
});
|
|
2574
|
+
const badge = PlaitBoard.getRoughSVG(this.board).circle(circleCenter[0], circleCenter[1], EXTEND_DIAMETER, {
|
|
2575
|
+
fill: stroke,
|
|
2576
|
+
stroke,
|
|
2577
|
+
fillStyle: 'solid'
|
|
2578
|
+
});
|
|
2579
|
+
const hideCircleG = PlaitBoard.getRoughSVG(this.board).circle(circleCenter[0], circleCenter[1], EXTEND_DIAMETER, {
|
|
2580
|
+
fill: '#fff',
|
|
2581
|
+
stroke,
|
|
2582
|
+
strokeWidth: branchWidth > 3 ? 3 : branchWidth,
|
|
2583
|
+
fillStyle: 'solid'
|
|
2584
|
+
});
|
|
2585
|
+
if (element.isCollapsed) {
|
|
2586
|
+
let numberOffset = 0;
|
|
2587
|
+
if (getChildrenCount(element) >= 10)
|
|
2588
|
+
numberOffset = -2;
|
|
2589
|
+
if (getChildrenCount(element) === 1)
|
|
2590
|
+
numberOffset = 1;
|
|
2591
|
+
const badgeText = createText(circleCenter[0] - 4 + numberOffset, circleCenter[1] + 4, stroke, `${getChildrenCount(element)}`);
|
|
2592
|
+
badge.setAttribute('style', 'opacity: 0.15');
|
|
2593
|
+
badgeText.setAttribute('style', 'font-size: 12px');
|
|
2594
|
+
collapseG.appendChild(badge);
|
|
2595
|
+
collapseG.appendChild(badgeText);
|
|
2596
|
+
collapseG.appendChild(extendLine);
|
|
2598
2597
|
}
|
|
2599
|
-
|
|
2598
|
+
else {
|
|
2599
|
+
collapseG.appendChild(hideCircleG);
|
|
2600
|
+
collapseG.appendChild(arrowLine);
|
|
2601
|
+
}
|
|
2602
|
+
collapseG.appendChild(extendLine);
|
|
2603
|
+
return collapseG;
|
|
2600
2604
|
}
|
|
2601
2605
|
afterDraw(element) {
|
|
2602
2606
|
if (!this.g) {
|
|
2603
2607
|
throw new Error(`can not find quick insert g`);
|
|
2604
2608
|
}
|
|
2605
|
-
fromEvent(this.g, 'mousedown')
|
|
2606
|
-
.pipe(take(1))
|
|
2607
|
-
.subscribe(e => {
|
|
2608
|
-
e.stopPropagation();
|
|
2609
|
-
});
|
|
2610
2609
|
fromEvent(this.g, 'mouseup')
|
|
2611
|
-
.pipe(take(1))
|
|
2610
|
+
.pipe(filter(() => !PlaitBoard.isPointer(this.board, PlaitPointerType.hand) || !!PlaitBoard.isReadonly(this.board)), take(1))
|
|
2612
2611
|
.subscribe(() => {
|
|
2613
|
-
const
|
|
2614
|
-
|
|
2612
|
+
const isCollapsed = !element.isCollapsed;
|
|
2613
|
+
const newElement = { isCollapsed };
|
|
2614
|
+
const path = PlaitBoard.findPath(this.board, element);
|
|
2615
|
+
Transforms.setNode(this.board, newElement, path);
|
|
2615
2616
|
});
|
|
2616
2617
|
}
|
|
2618
|
+
getArrowPoints(circleCenter, linkDirection) {
|
|
2619
|
+
let arrowTopPoint = moveXOfPoint(circleCenter, 2, linkDirection);
|
|
2620
|
+
arrowTopPoint = moveYOfPoint(arrowTopPoint, 4, linkDirection);
|
|
2621
|
+
const arrowMiddlePoint = moveXOfPoint(circleCenter, -2, linkDirection);
|
|
2622
|
+
let arrowBottomPoint = moveXOfPoint(circleCenter, 2, linkDirection);
|
|
2623
|
+
arrowBottomPoint = moveYOfPoint(arrowBottomPoint, -4, linkDirection);
|
|
2624
|
+
return [arrowTopPoint, arrowMiddlePoint, arrowBottomPoint];
|
|
2625
|
+
}
|
|
2617
2626
|
}
|
|
2618
2627
|
|
|
2619
2628
|
class MindNodeComponent extends PlaitPluginElementComponent {
|
|
2620
|
-
|
|
2621
|
-
return this.board.pointer === PlaitPointerType.hand;
|
|
2622
|
-
}
|
|
2623
|
-
constructor(viewContainerRef, cdr, render2, ngZone) {
|
|
2629
|
+
constructor(viewContainerRef, cdr) {
|
|
2624
2630
|
super(cdr);
|
|
2625
2631
|
this.viewContainerRef = viewContainerRef;
|
|
2626
2632
|
this.cdr = cdr;
|
|
2627
|
-
this.render2 = render2;
|
|
2628
|
-
this.ngZone = ngZone;
|
|
2629
|
-
this.isEditable = false;
|
|
2630
|
-
this.activeG = [];
|
|
2631
2633
|
this.shapeG = null;
|
|
2632
2634
|
this.destroy$ = new Subject();
|
|
2633
2635
|
this.trackBy = (index, node) => {
|
|
2634
2636
|
return node.origin.id;
|
|
2635
2637
|
};
|
|
2636
2638
|
}
|
|
2639
|
+
initializeDrawer() {
|
|
2640
|
+
this.nodeEmojisDrawer = new NodeEmojisDrawer(this.board, this.viewContainerRef);
|
|
2641
|
+
this.nodeInsertDrawer = new NodeInsertDrawer(this.board);
|
|
2642
|
+
this.activeDrawer = new NodeActiveDrawer(this.board);
|
|
2643
|
+
this.collapseDrawer = new CollapseDrawer(this.board);
|
|
2644
|
+
this.textManage = new TextManage(this.board, this.viewContainerRef, () => {
|
|
2645
|
+
return getTopicRectangleByNode(this.board, this.node);
|
|
2646
|
+
}, (point) => {
|
|
2647
|
+
return isHitMindElement(this.board, point, this.element);
|
|
2648
|
+
}, (textManageRef) => {
|
|
2649
|
+
const width = textManageRef.width;
|
|
2650
|
+
const height = textManageRef.height;
|
|
2651
|
+
if (textManageRef.newValue) {
|
|
2652
|
+
MindTransforms.setTopic(this.board, this.element, textManageRef.newValue, width, height);
|
|
2653
|
+
}
|
|
2654
|
+
else {
|
|
2655
|
+
MindTransforms.setTopicSize(this.board, this.element, width, height);
|
|
2656
|
+
}
|
|
2657
|
+
});
|
|
2658
|
+
}
|
|
2637
2659
|
ngOnInit() {
|
|
2638
|
-
this.emojisDrawer = new EmojisDrawer(this.board, this.viewContainerRef);
|
|
2639
|
-
this.quickInsertDrawer = new QuickInsertDrawer(this.board);
|
|
2640
2660
|
super.ngOnInit();
|
|
2661
|
+
this.initializeDrawer();
|
|
2641
2662
|
this.node = MindElement.getNode(this.element);
|
|
2642
2663
|
this.index = NODE_TO_INDEX.get(this.element) || 0;
|
|
2643
2664
|
this.roughSVG = PlaitBoard.getRoughSVG(this.board);
|
|
2644
2665
|
this.parentG = PlaitElement.getComponent(MindElement.getRoot(this.board, this.element)).rootG;
|
|
2645
2666
|
this.drawShape();
|
|
2646
2667
|
this.drawLink();
|
|
2647
|
-
this.
|
|
2648
|
-
this.
|
|
2649
|
-
this.updateActiveClass();
|
|
2650
|
-
this.drawMaskG();
|
|
2668
|
+
this.drawText();
|
|
2669
|
+
this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
|
|
2651
2670
|
this.drawEmojis();
|
|
2652
2671
|
this.drawExtend();
|
|
2653
|
-
|
|
2672
|
+
}
|
|
2673
|
+
editTopic() {
|
|
2674
|
+
this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
|
|
2675
|
+
this.textManage.edit(() => {
|
|
2676
|
+
this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
|
|
2677
|
+
});
|
|
2654
2678
|
}
|
|
2655
2679
|
onContextChanged(value, previous) {
|
|
2656
2680
|
const newNode = MindElement.getNode(value.element);
|
|
2657
|
-
// resolve move node richtext lose issue
|
|
2658
|
-
if (this.node !== newNode) {
|
|
2659
|
-
if (this.foreignObject && this.foreignObject.children.length <= 0) {
|
|
2660
|
-
this.foreignObject?.appendChild(this.richtextComponentRef?.instance.editable);
|
|
2661
|
-
}
|
|
2662
|
-
}
|
|
2663
2681
|
const isEqualNode = RectangleClient.isEqual(this.node, newNode);
|
|
2664
2682
|
this.node = newNode;
|
|
2665
2683
|
const isChangeTheme = this.board.operations.find(op => op.type === 'set_theme');
|
|
2666
2684
|
if (!isEqualNode || value.element !== previous.element || isChangeTheme) {
|
|
2667
|
-
this.
|
|
2668
|
-
this.updateActiveClass();
|
|
2685
|
+
this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
|
|
2669
2686
|
this.drawShape();
|
|
2670
2687
|
this.drawLink();
|
|
2671
|
-
this.updateRichtext();
|
|
2672
|
-
this.drawMaskG();
|
|
2673
|
-
this.drawExtend();
|
|
2674
|
-
this.drawQuickInsert();
|
|
2675
2688
|
this.drawEmojis();
|
|
2689
|
+
this.drawExtend();
|
|
2690
|
+
this.textManage.updateText(this.element.data.topic);
|
|
2691
|
+
this.textManage.updateRectangle();
|
|
2676
2692
|
}
|
|
2677
2693
|
else {
|
|
2678
2694
|
const hasSameSelected = value.selected === previous.selected;
|
|
2679
2695
|
const hasSameParent = value.parent === previous.parent;
|
|
2680
2696
|
if (!hasSameSelected) {
|
|
2681
|
-
this.
|
|
2682
|
-
this.updateActiveClass();
|
|
2697
|
+
this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
|
|
2683
2698
|
}
|
|
2684
2699
|
if (!hasSameParent) {
|
|
2685
2700
|
this.drawLink();
|
|
@@ -2687,21 +2702,11 @@ class MindNodeComponent extends PlaitPluginElementComponent {
|
|
|
2687
2702
|
}
|
|
2688
2703
|
}
|
|
2689
2704
|
drawEmojis() {
|
|
2690
|
-
const g = this.
|
|
2705
|
+
const g = this.nodeEmojisDrawer.drawEmojis(this.element);
|
|
2691
2706
|
if (g) {
|
|
2692
2707
|
this.g.append(g);
|
|
2693
2708
|
}
|
|
2694
2709
|
}
|
|
2695
|
-
drawQuickInsert() {
|
|
2696
|
-
this.quickInsertDrawer.destroy();
|
|
2697
|
-
if (this.quickInsertDrawer.canDraw(this.element)) {
|
|
2698
|
-
const g = this.quickInsertDrawer.draw(this.element);
|
|
2699
|
-
if (hasAfterDraw(this.quickInsertDrawer)) {
|
|
2700
|
-
this.quickInsertDrawer.afterDraw(this.element);
|
|
2701
|
-
}
|
|
2702
|
-
this.extendG?.appendChild(g);
|
|
2703
|
-
}
|
|
2704
|
-
}
|
|
2705
2710
|
drawShape() {
|
|
2706
2711
|
this.destroyShape();
|
|
2707
2712
|
const shape = getShapeByElement(this.board, this.node.origin);
|
|
@@ -2743,389 +2748,33 @@ class MindNodeComponent extends PlaitPluginElementComponent {
|
|
|
2743
2748
|
this.linkG.remove();
|
|
2744
2749
|
}
|
|
2745
2750
|
}
|
|
2746
|
-
drawMaskG() {
|
|
2747
|
-
this.destroyMaskG();
|
|
2748
|
-
const lineWidthOffset = 2;
|
|
2749
|
-
const extendOffset = 15;
|
|
2750
|
-
const nodeLayout = MindQueries.getLayoutByElement(this.node.origin);
|
|
2751
|
-
const isTop = isTopLayout(nodeLayout);
|
|
2752
|
-
const isRight = isRightLayout(nodeLayout);
|
|
2753
|
-
const isBottom = isBottomLayout(nodeLayout);
|
|
2754
|
-
const isLeft = isLeftLayout(nodeLayout);
|
|
2755
|
-
const { x, y, width, height } = getRectangleByNode(this.node);
|
|
2756
|
-
let drawX = x;
|
|
2757
|
-
let drawY = y;
|
|
2758
|
-
let drawWidth = x + width;
|
|
2759
|
-
let drawHeight = y + height;
|
|
2760
|
-
switch (true) {
|
|
2761
|
-
case isTop:
|
|
2762
|
-
drawX = x - lineWidthOffset;
|
|
2763
|
-
drawY = y - extendOffset;
|
|
2764
|
-
drawWidth = x + width + lineWidthOffset;
|
|
2765
|
-
drawHeight = y + height + lineWidthOffset;
|
|
2766
|
-
break;
|
|
2767
|
-
case isBottom:
|
|
2768
|
-
drawX = x - lineWidthOffset;
|
|
2769
|
-
drawY = y - lineWidthOffset;
|
|
2770
|
-
drawWidth = x + width + lineWidthOffset;
|
|
2771
|
-
drawHeight = y + height + extendOffset;
|
|
2772
|
-
break;
|
|
2773
|
-
case isLeft:
|
|
2774
|
-
drawX = x - extendOffset;
|
|
2775
|
-
drawY = y - lineWidthOffset;
|
|
2776
|
-
drawWidth = x + width + lineWidthOffset;
|
|
2777
|
-
drawHeight = y + height + lineWidthOffset;
|
|
2778
|
-
break;
|
|
2779
|
-
case isRight:
|
|
2780
|
-
drawX = x - lineWidthOffset;
|
|
2781
|
-
drawY = y - lineWidthOffset;
|
|
2782
|
-
drawWidth = x + width + extendOffset;
|
|
2783
|
-
drawHeight = y + height + lineWidthOffset;
|
|
2784
|
-
break;
|
|
2785
|
-
}
|
|
2786
|
-
this.maskG = drawRoundRectangle(this.roughSVG, drawX, drawY, drawWidth, drawHeight, { stroke: 'none', fill: 'rgba(255,255,255,0)', fillStyle: 'solid' }, true);
|
|
2787
|
-
this.maskG.classList.add('mask');
|
|
2788
|
-
this.maskG.setAttribute('visibility', 'visible');
|
|
2789
|
-
this.g.append(this.maskG);
|
|
2790
|
-
if (this.isEditable) {
|
|
2791
|
-
this.disabledMaskG();
|
|
2792
|
-
}
|
|
2793
|
-
fromEvent(this.maskG, 'mouseenter')
|
|
2794
|
-
.pipe(takeUntil(this.destroy$), filter(() => {
|
|
2795
|
-
return PlaitBoard.isFocus(this.board) && !this.element.isCollapsed && !this.handActive;
|
|
2796
|
-
}))
|
|
2797
|
-
.subscribe(() => {
|
|
2798
|
-
this.g.classList.add('hovered');
|
|
2799
|
-
});
|
|
2800
|
-
fromEvent(this.maskG, 'mouseleave')
|
|
2801
|
-
.pipe(takeUntil(this.destroy$), filter(() => {
|
|
2802
|
-
return PlaitBoard.isFocus(this.board) && !this.element.isCollapsed;
|
|
2803
|
-
}))
|
|
2804
|
-
.subscribe(() => {
|
|
2805
|
-
this.g.classList.remove('hovered');
|
|
2806
|
-
});
|
|
2807
|
-
}
|
|
2808
|
-
destroyMaskG() {
|
|
2809
|
-
if (this.maskG) {
|
|
2810
|
-
this.maskG.remove();
|
|
2811
|
-
this.g.classList.remove('hovered');
|
|
2812
|
-
}
|
|
2813
|
-
}
|
|
2814
|
-
enableMaskG() {
|
|
2815
|
-
if (this.maskG) {
|
|
2816
|
-
this.maskG.setAttribute('visibility', 'visible');
|
|
2817
|
-
}
|
|
2818
|
-
}
|
|
2819
|
-
disabledMaskG() {
|
|
2820
|
-
if (this.maskG) {
|
|
2821
|
-
this.maskG.setAttribute('visibility', 'hidden');
|
|
2822
|
-
}
|
|
2823
|
-
}
|
|
2824
|
-
drawActiveG() {
|
|
2825
|
-
this.destroyActiveG();
|
|
2826
|
-
this.abstractIncludedOutlineG?.remove();
|
|
2827
|
-
if (this.selected) {
|
|
2828
|
-
if (AbstractNode.isAbstract(this.element)) {
|
|
2829
|
-
this.updateAbstractIncludedOutline();
|
|
2830
|
-
}
|
|
2831
|
-
let { x, y, width, height } = getRectangleByNode(this.node);
|
|
2832
|
-
const selectedStrokeG = drawRoundRectangle(this.roughSVG, x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, strokeWidth: 2, fill: '' }, true);
|
|
2833
|
-
// 影响 mask 移入移出事件
|
|
2834
|
-
selectedStrokeG.style.pointerEvents = 'none';
|
|
2835
|
-
this.g.appendChild(selectedStrokeG);
|
|
2836
|
-
this.activeG.push(selectedStrokeG);
|
|
2837
|
-
if (this.richtextComponentRef?.instance.plaitReadonly === true) {
|
|
2838
|
-
const selectedBackgroundG = drawRoundRectangle(this.roughSVG, x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, fill: PRIMARY_COLOR, fillStyle: 'solid' }, true);
|
|
2839
|
-
selectedBackgroundG.style.opacity = '0.15';
|
|
2840
|
-
// 影响双击事件
|
|
2841
|
-
selectedBackgroundG.style.pointerEvents = 'none';
|
|
2842
|
-
this.g.appendChild(selectedBackgroundG);
|
|
2843
|
-
this.activeG.push(selectedBackgroundG, selectedStrokeG);
|
|
2844
|
-
}
|
|
2845
|
-
}
|
|
2846
|
-
}
|
|
2847
|
-
destroyActiveG() {
|
|
2848
|
-
this.activeG.forEach(g => g.remove());
|
|
2849
|
-
this.activeG = [];
|
|
2850
|
-
}
|
|
2851
|
-
updateActiveClass() {
|
|
2852
|
-
if (!this.g) {
|
|
2853
|
-
return;
|
|
2854
|
-
}
|
|
2855
|
-
if (this.selected) {
|
|
2856
|
-
this.render2.addClass(this.g, 'active');
|
|
2857
|
-
}
|
|
2858
|
-
else {
|
|
2859
|
-
this.render2.removeClass(this.g, 'active');
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
drawRichtext() {
|
|
2863
|
-
const { richtextG, richtextComponentRef, foreignObject } = drawTopicByNode(this.board, this.node, this.viewContainerRef);
|
|
2864
|
-
this.richtextComponentRef = richtextComponentRef;
|
|
2865
|
-
this.richtextG = richtextG;
|
|
2866
|
-
this.foreignObject = foreignObject;
|
|
2867
|
-
this.render2.addClass(richtextG, 'richtext');
|
|
2868
|
-
this.g.append(richtextG);
|
|
2869
|
-
}
|
|
2870
2751
|
drawExtend() {
|
|
2871
2752
|
this.destroyExtend();
|
|
2872
|
-
// create extend
|
|
2873
2753
|
this.extendG = createG();
|
|
2874
|
-
const collapseG = createG();
|
|
2875
2754
|
this.extendG.classList.add('extend');
|
|
2876
|
-
collapseG.classList.add('collapse-container');
|
|
2877
2755
|
this.g.append(this.extendG);
|
|
2878
|
-
this.
|
|
2879
|
-
if (this.node.origin.isRoot) {
|
|
2880
|
-
return;
|
|
2881
|
-
}
|
|
2882
|
-
// interactive
|
|
2883
|
-
fromEvent(collapseG, 'mouseup')
|
|
2884
|
-
.pipe(filter(() => !this.handActive || !!PlaitBoard.isReadonly(this.board)), take(1))
|
|
2885
|
-
.subscribe(() => {
|
|
2886
|
-
const isCollapsed = !this.node.origin.isCollapsed;
|
|
2887
|
-
const newElement = { isCollapsed };
|
|
2888
|
-
const path = PlaitBoard.findPath(this.board, this.element);
|
|
2889
|
-
Transforms.setNode(this.board, newElement, path);
|
|
2890
|
-
});
|
|
2891
|
-
const { x, y, width, height } = getRectangleByNode(this.node);
|
|
2892
|
-
const stroke = getBranchColorByMindElement(this.board, this.element);
|
|
2893
|
-
const branchWidth = getBranchWidthByMindElement(this.board, this.element);
|
|
2894
|
-
const extendY = y + height / 2;
|
|
2895
|
-
const nodeLayout = MindQueries.getCorrectLayoutByElement(this.board, this.element);
|
|
2896
|
-
let extendLineXY = [
|
|
2897
|
-
[x + width, extendY],
|
|
2898
|
-
[x + width + EXTEND_OFFSET, extendY]
|
|
2899
|
-
];
|
|
2900
|
-
let arrowYOffset = [-4, 1, -0.6, 4];
|
|
2901
|
-
let arrowXOffset = [10, 5.5, 5.5, 10];
|
|
2902
|
-
let extendLineXOffset = [0, 0];
|
|
2903
|
-
let extendLineYOffset = [0, 0];
|
|
2904
|
-
let circleOffset = [EXTEND_RADIUS / 2, 0];
|
|
2905
|
-
if (isHorizontalLayout(nodeLayout) && !isIndentedLayout(nodeLayout)) {
|
|
2906
|
-
extendLineYOffset =
|
|
2907
|
-
getShapeByElement(this.board, this.node.origin) === MindElementShape.roundRectangle
|
|
2908
|
-
? [0, 0]
|
|
2909
|
-
: [height / 2, height / 2];
|
|
2910
|
-
if (isLeftLayout(nodeLayout)) {
|
|
2911
|
-
//左
|
|
2912
|
-
extendLineXOffset = [-width, -width - EXTEND_OFFSET * 2];
|
|
2913
|
-
circleOffset = [-EXTEND_RADIUS / 2, 0];
|
|
2914
|
-
arrowXOffset = [-10, -5.5, -5.5, -10];
|
|
2915
|
-
}
|
|
2916
|
-
}
|
|
2917
|
-
else {
|
|
2918
|
-
arrowXOffset = [-4, 0.6, -1, 4];
|
|
2919
|
-
if (isTopLayout(nodeLayout)) {
|
|
2920
|
-
//上
|
|
2921
|
-
extendLineXOffset = [-width / 2, -width / 2 - EXTEND_OFFSET];
|
|
2922
|
-
extendLineYOffset = [-height / 2, -height / 2 - EXTEND_OFFSET];
|
|
2923
|
-
arrowYOffset = [-10, -5.5, -5.5, -10];
|
|
2924
|
-
circleOffset = [0, -EXTEND_RADIUS / 2];
|
|
2925
|
-
}
|
|
2926
|
-
else {
|
|
2927
|
-
//下
|
|
2928
|
-
extendLineXOffset = [-width / 2, -width / 2 - EXTEND_OFFSET];
|
|
2929
|
-
extendLineYOffset = [height / 2, height / 2 + EXTEND_OFFSET];
|
|
2930
|
-
arrowYOffset = [10, 5.5, 5.5, 10];
|
|
2931
|
-
circleOffset = [0, EXTEND_RADIUS / 2];
|
|
2932
|
-
}
|
|
2933
|
-
}
|
|
2934
|
-
extendLineXY = [
|
|
2935
|
-
[extendLineXY[0][0] + extendLineXOffset[0], extendLineXY[0][1] + extendLineYOffset[0]],
|
|
2936
|
-
[extendLineXY[1][0] + extendLineXOffset[1], extendLineXY[1][1] + extendLineYOffset[1]]
|
|
2937
|
-
];
|
|
2938
|
-
const extendLine = this.roughSVG.line(extendLineXY[0][0], extendLineXY[0][1], extendLineXY[1][0], extendLineXY[1][1], {
|
|
2939
|
-
strokeWidth: branchWidth,
|
|
2940
|
-
stroke
|
|
2941
|
-
});
|
|
2942
|
-
//绘制箭头
|
|
2943
|
-
const hideArrowTopLine = this.roughSVG.line(extendLineXY[1][0] + arrowXOffset[0], extendLineXY[1][1] + arrowYOffset[0], extendLineXY[1][0] + arrowXOffset[1], extendLineXY[1][1] + arrowYOffset[1], {
|
|
2944
|
-
stroke,
|
|
2945
|
-
strokeWidth: 2
|
|
2946
|
-
});
|
|
2947
|
-
const hideArrowBottomLine = this.roughSVG.line(extendLineXY[1][0] + arrowXOffset[2], extendLineXY[1][1] + arrowYOffset[2], extendLineXY[1][0] + arrowXOffset[3], extendLineXY[1][1] + arrowYOffset[3], {
|
|
2948
|
-
stroke,
|
|
2949
|
-
strokeWidth: 2
|
|
2950
|
-
});
|
|
2951
|
-
if (this.node.origin.isCollapsed) {
|
|
2952
|
-
const badge = this.roughSVG.circle(extendLineXY[1][0] + circleOffset[0], extendLineXY[1][1] + circleOffset[1], EXTEND_RADIUS, {
|
|
2953
|
-
fill: stroke,
|
|
2954
|
-
stroke,
|
|
2955
|
-
fillStyle: 'solid'
|
|
2956
|
-
});
|
|
2957
|
-
let numberOffset = 0;
|
|
2958
|
-
if (getChildrenCount(this.node.origin) >= 10)
|
|
2959
|
-
numberOffset = -2;
|
|
2960
|
-
if (getChildrenCount(this.node.origin) === 1)
|
|
2961
|
-
numberOffset = 1;
|
|
2962
|
-
const badgeText = createText(extendLineXY[1][0] + circleOffset[0] - 4 + numberOffset, extendLineXY[1][1] + circleOffset[1] + 4, stroke, `${getChildrenCount(this.node.origin)}`);
|
|
2756
|
+
if (this.element.isCollapsed) {
|
|
2963
2757
|
this.g.classList.add('collapsed');
|
|
2964
|
-
badge.setAttribute('style', 'opacity: 0.15');
|
|
2965
|
-
badgeText.setAttribute('style', 'font-size: 12px');
|
|
2966
|
-
collapseG.appendChild(badge);
|
|
2967
|
-
collapseG.appendChild(badgeText);
|
|
2968
|
-
collapseG.appendChild(extendLine);
|
|
2969
2758
|
}
|
|
2970
2759
|
else {
|
|
2971
2760
|
this.g.classList.remove('collapsed');
|
|
2972
|
-
if (this.node.origin.children.length > 0) {
|
|
2973
|
-
const hideCircleG = this.roughSVG.circle(extendLineXY[1][0] + circleOffset[0], extendLineXY[1][1] + circleOffset[1], EXTEND_RADIUS - 1, {
|
|
2974
|
-
fill: '#fff',
|
|
2975
|
-
stroke,
|
|
2976
|
-
strokeWidth: branchWidth > 3 ? 3 : branchWidth,
|
|
2977
|
-
fillStyle: 'solid'
|
|
2978
|
-
});
|
|
2979
|
-
collapseG.appendChild(hideCircleG);
|
|
2980
|
-
collapseG.appendChild(hideArrowTopLine);
|
|
2981
|
-
collapseG.appendChild(hideArrowBottomLine);
|
|
2982
|
-
}
|
|
2983
2761
|
}
|
|
2762
|
+
this.nodeInsertDrawer.draw(this.element, this.extendG);
|
|
2763
|
+
this.collapseDrawer.draw(this.element, this.extendG);
|
|
2984
2764
|
}
|
|
2985
2765
|
destroyExtend() {
|
|
2986
2766
|
if (this.extendG) {
|
|
2987
2767
|
this.extendG.remove();
|
|
2988
2768
|
}
|
|
2989
2769
|
}
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
}
|
|
2994
|
-
if (this.richtextComponentRef) {
|
|
2995
|
-
this.richtextComponentRef.destroy();
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
updateAbstractIncludedOutline(activeHandlePosition, resizingLocation) {
|
|
2999
|
-
this.abstractIncludedOutlineG?.remove();
|
|
3000
|
-
this.abstractIncludedOutlineG = drawAbstractIncludedOutline(this.board, this.roughSVG, this.element, activeHandlePosition, resizingLocation);
|
|
3001
|
-
PlaitBoard.getHost(this.board).append(this.abstractIncludedOutlineG);
|
|
3002
|
-
}
|
|
3003
|
-
updateRichtext() {
|
|
3004
|
-
updateRichText(this.node.origin.data.topic, this.richtextComponentRef);
|
|
3005
|
-
updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
|
|
3006
|
-
}
|
|
3007
|
-
startEditText(isEnd, isClear) {
|
|
3008
|
-
if (!this.richtextComponentRef) {
|
|
3009
|
-
throw new Error('undefined richtextComponentRef');
|
|
3010
|
-
}
|
|
3011
|
-
const richtextInstance = this.richtextComponentRef.instance;
|
|
3012
|
-
this.isEditable = true;
|
|
3013
|
-
IS_TEXT_EDITABLE.set(this.board, true);
|
|
3014
|
-
this.disabledMaskG();
|
|
3015
|
-
updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
|
|
3016
|
-
if (richtextInstance.plaitReadonly) {
|
|
3017
|
-
richtextInstance.plaitReadonly = false;
|
|
3018
|
-
this.richtextComponentRef.changeDetectorRef.detectChanges();
|
|
3019
|
-
this.drawActiveG();
|
|
3020
|
-
const location = isEnd ? Editor.end(richtextInstance.editor, [0]) : [0];
|
|
3021
|
-
setFullSelectionAndFocus(richtextInstance.editor, location);
|
|
3022
|
-
if (isClear) {
|
|
3023
|
-
Editor.deleteBackward(richtextInstance.editor);
|
|
3024
|
-
}
|
|
3025
|
-
// handle invalid width and height (old data)
|
|
3026
|
-
let { width, height } = getRichtextContentSize(richtextInstance.editable);
|
|
3027
|
-
if (width !== this.element.width || height !== this.element.height) {
|
|
3028
|
-
MindTransforms.setTopicSize(this.board, this.element, width, height);
|
|
3029
|
-
}
|
|
3030
|
-
}
|
|
3031
|
-
let richtext = richtextInstance.plaitValue;
|
|
3032
|
-
// use debounceTime to wait DOM render complete
|
|
3033
|
-
const valueChange$ = richtextInstance.plaitChange
|
|
3034
|
-
.pipe(debounceTime(0), filter(event => {
|
|
3035
|
-
// 过滤掉 operations 中全是 set_selection 的操作
|
|
3036
|
-
return !event.operations.every(op => Operation.isSelectionOperation(op));
|
|
3037
|
-
}))
|
|
3038
|
-
.subscribe(event => {
|
|
3039
|
-
if (richtext === event.value) {
|
|
3040
|
-
return;
|
|
3041
|
-
}
|
|
3042
|
-
this.updateRichtext();
|
|
3043
|
-
// 更新富文本、更新宽高
|
|
3044
|
-
let { width, height } = getRichtextContentSize(richtextInstance.editable);
|
|
3045
|
-
MindTransforms.setTopic(this.board, this.element, event.value, width, height);
|
|
3046
|
-
MERGING.set(this.board, true);
|
|
3047
|
-
});
|
|
3048
|
-
const composition$ = richtextInstance.plaitComposition.pipe(debounceTime(0)).subscribe(event => {
|
|
3049
|
-
let { width, height } = getRichtextContentSize(richtextInstance.editable);
|
|
3050
|
-
if (width < NODE_MIN_WIDTH) {
|
|
3051
|
-
width = NODE_MIN_WIDTH;
|
|
3052
|
-
}
|
|
3053
|
-
if (event.isComposing && (width !== this.node.origin.width || height !== this.node.origin.height)) {
|
|
3054
|
-
const newElement = {
|
|
3055
|
-
width: width / this.board.viewport.zoom,
|
|
3056
|
-
height: height / this.board.viewport.zoom
|
|
3057
|
-
};
|
|
3058
|
-
const path = PlaitBoard.findPath(this.board, this.element);
|
|
3059
|
-
Transforms.setNode(this.board, newElement, path);
|
|
3060
|
-
MERGING.set(this.board, true);
|
|
3061
|
-
}
|
|
3062
|
-
});
|
|
3063
|
-
const mousedown$ = fromEvent(document, 'mousedown').subscribe((event) => {
|
|
3064
|
-
const point = transformPoint(this.board, toPoint(event.x, event.y, PlaitBoard.getHost(this.board)));
|
|
3065
|
-
const clickInNode = isHitMindElement(this.board, point, this.element);
|
|
3066
|
-
if (clickInNode && !hasEditableTarget(richtextInstance.editor, event.target)) {
|
|
3067
|
-
event.preventDefault();
|
|
3068
|
-
}
|
|
3069
|
-
else if (!clickInNode) {
|
|
3070
|
-
// handle composition input state, like: Chinese IME Composition Input
|
|
3071
|
-
timer(0).subscribe(() => {
|
|
3072
|
-
exitHandle();
|
|
3073
|
-
this.enableMaskG();
|
|
3074
|
-
});
|
|
3075
|
-
}
|
|
3076
|
-
});
|
|
3077
|
-
const editor = richtextInstance.editor;
|
|
3078
|
-
const { keydown } = editor;
|
|
3079
|
-
editor.keydown = (event) => {
|
|
3080
|
-
if (event.isComposing) {
|
|
3081
|
-
return;
|
|
3082
|
-
}
|
|
3083
|
-
if (event.key === 'Escape') {
|
|
3084
|
-
event.preventDefault();
|
|
3085
|
-
event.stopPropagation();
|
|
3086
|
-
exitHandle();
|
|
3087
|
-
this.drawActiveG();
|
|
3088
|
-
this.enableMaskG();
|
|
3089
|
-
return;
|
|
3090
|
-
}
|
|
3091
|
-
if (event.key === 'Enter' && !event.shiftKey) {
|
|
3092
|
-
event.preventDefault();
|
|
3093
|
-
event.stopPropagation();
|
|
3094
|
-
exitHandle();
|
|
3095
|
-
this.drawActiveG();
|
|
3096
|
-
this.enableMaskG();
|
|
3097
|
-
return;
|
|
3098
|
-
}
|
|
3099
|
-
if (event.key === 'Tab') {
|
|
3100
|
-
event.preventDefault();
|
|
3101
|
-
event.stopPropagation();
|
|
3102
|
-
exitHandle();
|
|
3103
|
-
this.drawActiveG();
|
|
3104
|
-
this.drawMaskG();
|
|
3105
|
-
}
|
|
3106
|
-
};
|
|
3107
|
-
const exitHandle = () => {
|
|
3108
|
-
this.ngZone.run(() => {
|
|
3109
|
-
// unsubscribe
|
|
3110
|
-
valueChange$.unsubscribe();
|
|
3111
|
-
composition$.unsubscribe();
|
|
3112
|
-
mousedown$.unsubscribe();
|
|
3113
|
-
editor.keydown = keydown; // reset keydown
|
|
3114
|
-
// editable status
|
|
3115
|
-
MERGING.set(this.board, false);
|
|
3116
|
-
richtextInstance.plaitReadonly = true;
|
|
3117
|
-
this.richtextComponentRef?.changeDetectorRef.markForCheck();
|
|
3118
|
-
this.isEditable = false;
|
|
3119
|
-
updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
|
|
3120
|
-
IS_TEXT_EDITABLE.set(this.board, false);
|
|
3121
|
-
});
|
|
3122
|
-
};
|
|
2770
|
+
drawText() {
|
|
2771
|
+
this.textManage.draw(this.element.data.topic);
|
|
2772
|
+
this.g.append(this.textManage.g);
|
|
3123
2773
|
}
|
|
3124
2774
|
ngOnDestroy() {
|
|
3125
2775
|
super.ngOnDestroy();
|
|
3126
|
-
this.
|
|
3127
|
-
this.
|
|
3128
|
-
this.emojisDrawer.destroy();
|
|
2776
|
+
this.textManage.destroy();
|
|
2777
|
+
this.nodeEmojisDrawer.destroy();
|
|
3129
2778
|
this.destroy$.next();
|
|
3130
2779
|
this.destroy$.complete();
|
|
3131
2780
|
if (ELEMENT_TO_NODE.get(this.element) === this.node) {
|
|
@@ -3133,7 +2782,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
|
|
|
3133
2782
|
}
|
|
3134
2783
|
}
|
|
3135
2784
|
}
|
|
3136
|
-
MindNodeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindNodeComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }
|
|
2785
|
+
MindNodeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindNodeComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3137
2786
|
MindNodeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.5", type: MindNodeComponent, selector: "plait-mind-node", usesInheritance: true, ngImport: i0, template: `
|
|
3138
2787
|
<plait-children
|
|
3139
2788
|
*ngIf="!element.isCollapsed"
|
|
@@ -3158,7 +2807,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
|
|
|
3158
2807
|
`,
|
|
3159
2808
|
changeDetection: ChangeDetectionStrategy.OnPush
|
|
3160
2809
|
}]
|
|
3161
|
-
}], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }
|
|
2810
|
+
}], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
|
|
3162
2811
|
|
|
3163
2812
|
const getLayoutOptions = (board) => {
|
|
3164
2813
|
function getMainAxle(element, parent) {
|
|
@@ -3231,6 +2880,7 @@ class PlaitMindComponent extends MindNodeComponent {
|
|
|
3231
2880
|
ngOnInit() {
|
|
3232
2881
|
this.updateMindLayout();
|
|
3233
2882
|
super.ngOnInit();
|
|
2883
|
+
this.g.classList.add('root');
|
|
3234
2884
|
}
|
|
3235
2885
|
beforeContextChange(value) {
|
|
3236
2886
|
if (value.element !== this.element && this.initialized) {
|
|
@@ -3271,19 +2921,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
|
|
|
3271
2921
|
class MindModule {
|
|
3272
2922
|
}
|
|
3273
2923
|
MindModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
3274
|
-
MindModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: MindModule, declarations: [PlaitMindComponent, MindNodeComponent], imports: [CommonModule,
|
|
3275
|
-
MindModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, imports: [CommonModule,
|
|
2924
|
+
MindModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: MindModule, declarations: [PlaitMindComponent, MindNodeComponent], imports: [CommonModule, TextModule, PlaitModule], exports: [PlaitMindComponent, MindNodeComponent] });
|
|
2925
|
+
MindModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, imports: [CommonModule, TextModule, PlaitModule] });
|
|
3276
2926
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, decorators: [{
|
|
3277
2927
|
type: NgModule,
|
|
3278
2928
|
args: [{
|
|
3279
2929
|
declarations: [PlaitMindComponent, MindNodeComponent],
|
|
3280
|
-
imports: [CommonModule,
|
|
2930
|
+
imports: [CommonModule, TextModule, PlaitModule],
|
|
3281
2931
|
exports: [PlaitMindComponent, MindNodeComponent]
|
|
3282
2932
|
}]
|
|
3283
2933
|
}] });
|
|
3284
2934
|
|
|
3285
2935
|
const DRAG_MOVE_BUFFER = 5;
|
|
3286
|
-
const
|
|
2936
|
+
const withNodeDnd = (board) => {
|
|
3287
2937
|
const { mousedown, mousemove, globalMouseup } = board;
|
|
3288
2938
|
let activeElements = [];
|
|
3289
2939
|
let correspondingElements = [];
|
|
@@ -3293,7 +2943,10 @@ const withDnd = (board) => {
|
|
|
3293
2943
|
let dropTarget = null;
|
|
3294
2944
|
let targetPath;
|
|
3295
2945
|
board.mousedown = (event) => {
|
|
3296
|
-
if (
|
|
2946
|
+
if (PlaitBoard.isReadonly(board) ||
|
|
2947
|
+
PlaitBoard.hasBeenTextEditing(board) ||
|
|
2948
|
+
!PlaitBoard.isPointer(board, PlaitPointerType.selection) ||
|
|
2949
|
+
event.button === 2) {
|
|
3297
2950
|
mousedown(event);
|
|
3298
2951
|
return;
|
|
3299
2952
|
}
|
|
@@ -3634,7 +3287,7 @@ const withAbstract = (board) => {
|
|
|
3634
3287
|
newProperty =
|
|
3635
3288
|
abstractHandlePosition === AbstractHandlePosition.start ? { start: locationIndex + 1 } : { end: locationIndex };
|
|
3636
3289
|
}
|
|
3637
|
-
abstractComponent.
|
|
3290
|
+
abstractComponent.activeDrawer.updateAbstractOutline(activeAbstractElement, abstractHandlePosition, location);
|
|
3638
3291
|
}
|
|
3639
3292
|
mousemove(event);
|
|
3640
3293
|
};
|
|
@@ -3651,7 +3304,7 @@ const withAbstract = (board) => {
|
|
|
3651
3304
|
}
|
|
3652
3305
|
else {
|
|
3653
3306
|
const abstractComponent = PlaitElement.getComponent(activeAbstractElement);
|
|
3654
|
-
abstractComponent.
|
|
3307
|
+
abstractComponent.activeDrawer.updateAbstractOutline(activeAbstractElement);
|
|
3655
3308
|
}
|
|
3656
3309
|
activeAbstractElement = undefined;
|
|
3657
3310
|
}
|
|
@@ -3703,22 +3356,29 @@ const withCreateMind = (board) => {
|
|
|
3703
3356
|
const nodeG = drawRoundRectangleByElement(board, nodeRectangle, emptyMind);
|
|
3704
3357
|
const topicRectangle = getTopicRectangleByElement(newBoard, nodeRectangle, emptyMind);
|
|
3705
3358
|
if (!fakeCreateNodeRef) {
|
|
3706
|
-
const
|
|
3359
|
+
const textManage = new TextManage(board, PlaitBoard.getComponent(board).viewContainerRef, () => {
|
|
3360
|
+
return topicRectangle;
|
|
3361
|
+
});
|
|
3362
|
+
PlaitBoard.getComponent(board)
|
|
3363
|
+
.viewContainerRef.injector.get(NgZone)
|
|
3364
|
+
.run(() => {
|
|
3365
|
+
textManage.draw(emptyMind.data.topic);
|
|
3366
|
+
});
|
|
3707
3367
|
fakeCreateNodeRef = {
|
|
3708
|
-
|
|
3368
|
+
g: createG(),
|
|
3709
3369
|
nodeG,
|
|
3710
|
-
|
|
3711
|
-
topicG: richtextG
|
|
3370
|
+
textManage
|
|
3712
3371
|
};
|
|
3713
|
-
|
|
3714
|
-
PlaitBoard.getHost(board).append(
|
|
3372
|
+
fakeCreateNodeRef.g.classList.add('root');
|
|
3373
|
+
PlaitBoard.getHost(board).append(fakeCreateNodeRef.g);
|
|
3374
|
+
fakeCreateNodeRef.g.append(...[fakeCreateNodeRef.nodeG, textManage.g]);
|
|
3715
3375
|
}
|
|
3716
3376
|
else {
|
|
3377
|
+
fakeCreateNodeRef.textManage.updateRectangle(topicRectangle);
|
|
3717
3378
|
fakeCreateNodeRef.nodeG.remove();
|
|
3718
3379
|
fakeCreateNodeRef.nodeG = nodeG;
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
updateForeignObject(fakeCreateNodeRef.topicG, topicRectangle.width, topicRectangle.height, topicRectangle.x, topicRectangle.y);
|
|
3380
|
+
fakeCreateNodeRef.g.append(nodeG);
|
|
3381
|
+
fakeCreateNodeRef.g.append(fakeCreateNodeRef.textManage.g);
|
|
3722
3382
|
}
|
|
3723
3383
|
}
|
|
3724
3384
|
});
|
|
@@ -3734,6 +3394,7 @@ const withCreateMind = (board) => {
|
|
|
3734
3394
|
const targetPoint = transformPoint(board, toPoint(movingPoint[0], movingPoint[1], PlaitBoard.getHost(board)));
|
|
3735
3395
|
const emptyMind = createEmptyMind(board, targetPoint);
|
|
3736
3396
|
Transforms.insertNode(board, emptyMind, [board.children.length]);
|
|
3397
|
+
clearSelectedElement(board);
|
|
3737
3398
|
addSelectedElement(board, emptyMind);
|
|
3738
3399
|
BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
|
|
3739
3400
|
}
|
|
@@ -3754,9 +3415,8 @@ const withCreateMind = (board) => {
|
|
|
3754
3415
|
};
|
|
3755
3416
|
function destroy() {
|
|
3756
3417
|
if (fakeCreateNodeRef) {
|
|
3757
|
-
fakeCreateNodeRef.
|
|
3758
|
-
fakeCreateNodeRef.
|
|
3759
|
-
fakeCreateNodeRef.topicG.remove();
|
|
3418
|
+
fakeCreateNodeRef.textManage.destroy();
|
|
3419
|
+
fakeCreateNodeRef.g.remove();
|
|
3760
3420
|
fakeCreateNodeRef = null;
|
|
3761
3421
|
}
|
|
3762
3422
|
}
|
|
@@ -3788,6 +3448,68 @@ const isExpandHotkey = (keyboardEvent) => {
|
|
|
3788
3448
|
return isKeyHotkey('mod+/', keyboardEvent);
|
|
3789
3449
|
};
|
|
3790
3450
|
|
|
3451
|
+
const withNodeHover = (board) => {
|
|
3452
|
+
const { mousemove, mouseleave } = board;
|
|
3453
|
+
let hoveredMindElement = null;
|
|
3454
|
+
board.mousemove = (event) => {
|
|
3455
|
+
throttleRAF(() => {
|
|
3456
|
+
let target = null;
|
|
3457
|
+
const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
|
|
3458
|
+
depthFirstRecursion(board, element => {
|
|
3459
|
+
if (target) {
|
|
3460
|
+
return;
|
|
3461
|
+
}
|
|
3462
|
+
if (!MindElement.isMindElement(board, element)) {
|
|
3463
|
+
return;
|
|
3464
|
+
}
|
|
3465
|
+
const isHitElement = isHitMindElement(board, point, element);
|
|
3466
|
+
if (isHitElement) {
|
|
3467
|
+
target = element;
|
|
3468
|
+
}
|
|
3469
|
+
}, node => {
|
|
3470
|
+
if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
|
|
3471
|
+
return true;
|
|
3472
|
+
}
|
|
3473
|
+
else {
|
|
3474
|
+
return false;
|
|
3475
|
+
}
|
|
3476
|
+
});
|
|
3477
|
+
if (hoveredMindElement && target && hoveredMindElement === target) {
|
|
3478
|
+
return;
|
|
3479
|
+
}
|
|
3480
|
+
if (hoveredMindElement) {
|
|
3481
|
+
removeHovered(hoveredMindElement);
|
|
3482
|
+
}
|
|
3483
|
+
if (target) {
|
|
3484
|
+
addHovered(target);
|
|
3485
|
+
hoveredMindElement = target;
|
|
3486
|
+
}
|
|
3487
|
+
else {
|
|
3488
|
+
hoveredMindElement = null;
|
|
3489
|
+
}
|
|
3490
|
+
});
|
|
3491
|
+
mousemove(event);
|
|
3492
|
+
};
|
|
3493
|
+
board.mouseleave = (event) => {
|
|
3494
|
+
if (hoveredMindElement) {
|
|
3495
|
+
removeHovered(hoveredMindElement);
|
|
3496
|
+
hoveredMindElement = null;
|
|
3497
|
+
}
|
|
3498
|
+
mouseleave(event);
|
|
3499
|
+
};
|
|
3500
|
+
return board;
|
|
3501
|
+
};
|
|
3502
|
+
const addHovered = (element) => {
|
|
3503
|
+
const component = PlaitElement.getComponent(element);
|
|
3504
|
+
component.g.classList.add('hovered');
|
|
3505
|
+
};
|
|
3506
|
+
const removeHovered = (element) => {
|
|
3507
|
+
const component = PlaitElement.getComponent(element);
|
|
3508
|
+
if (component && component.g) {
|
|
3509
|
+
component.g.classList.remove('hovered');
|
|
3510
|
+
}
|
|
3511
|
+
};
|
|
3512
|
+
|
|
3791
3513
|
const withMind = (board) => {
|
|
3792
3514
|
const { drawElement, dblclick, keydown, insertFragment, setFragment, deleteFragment, isHitSelection, getRectangle, isMovable, isRecursion } = board;
|
|
3793
3515
|
board.drawElement = (context) => {
|
|
@@ -3914,7 +3636,7 @@ const withMind = (board) => {
|
|
|
3914
3636
|
if (!isVirtualKey(event)) {
|
|
3915
3637
|
event.preventDefault();
|
|
3916
3638
|
const selectedElement = selectedElements[0];
|
|
3917
|
-
|
|
3639
|
+
editTopic(selectedElement);
|
|
3918
3640
|
return;
|
|
3919
3641
|
}
|
|
3920
3642
|
}
|
|
@@ -3936,7 +3658,7 @@ const withMind = (board) => {
|
|
|
3936
3658
|
.forEach(mindMap => {
|
|
3937
3659
|
depthFirstRecursion(mindMap, node => {
|
|
3938
3660
|
if (!PlaitBoard.hasBeenTextEditing(board) && isHitMindElement(board, point, node)) {
|
|
3939
|
-
|
|
3661
|
+
editTopic(node);
|
|
3940
3662
|
}
|
|
3941
3663
|
}, node => {
|
|
3942
3664
|
if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
|
|
@@ -3972,7 +3694,7 @@ const withMind = (board) => {
|
|
|
3972
3694
|
}
|
|
3973
3695
|
else {
|
|
3974
3696
|
const text = data?.getData(`text/plain`);
|
|
3975
|
-
const { width, height } =
|
|
3697
|
+
const { width, height } = getTextSize(board, text, TOPIC_DEFAULT_MAX_WORD_COUNT);
|
|
3976
3698
|
const selectedElements = getSelectedElements(board);
|
|
3977
3699
|
if (text && selectedElements.length === 1) {
|
|
3978
3700
|
insertClipboardText(board, selectedElements[0], text, width, height);
|
|
@@ -3990,7 +3712,7 @@ const withMind = (board) => {
|
|
|
3990
3712
|
MindTransforms.removeElements(board, selectedElements);
|
|
3991
3713
|
deleteFragment(data);
|
|
3992
3714
|
};
|
|
3993
|
-
return withMindHotkey(withMindExtend(withCreateMind(withAbstract(
|
|
3715
|
+
return withNodeHover(withMindHotkey(withMindExtend(withCreateMind(withAbstract(withNodeDnd(board))))));
|
|
3994
3716
|
};
|
|
3995
3717
|
|
|
3996
3718
|
class MindEmojiBaseComponent {
|
|
@@ -4044,5 +3766,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
|
|
|
4044
3766
|
* Generated bundle index. Do not edit.
|
|
4045
3767
|
*/
|
|
4046
3768
|
|
|
4047
|
-
export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_WIDTH, BaseDrawer, BranchShape, DefaultAbstractNodeStyle, DefaultNodeStyle, ELEMENT_TO_NODE,
|
|
3769
|
+
export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_WIDTH, BaseDrawer, BranchShape, 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, 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, isChildRight, isChildUp, isCorrectLayout, isDragging, isDropStandardRight, isHitEmojis, isHitMindElement, isInRightBranchOfStandardLayout, isMixedLayout, isSetAbstract, isValidTarget, isVirtualKey, removeActiveOnDragOrigin, separateChildren, setIsDragging, withMind, withMindExtend };
|
|
4048
3770
|
//# sourceMappingURL=plait-mind.mjs.map
|