Skip to content

Commit f3bc1da

Browse files
authored
fix(mind): depreciate the width and height on mind element to resolve the issue of the text can not show completely (#1077)
* fix(mind): fix topic text can not show completely in different machines * chore: add changeset * fix(mind): set correct font size on getElementSize
1 parent 8c90c00 commit f3bc1da

File tree

11 files changed

+121
-35
lines changed

11 files changed

+121
-35
lines changed

.changeset/cool-guests-attend.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@plait/common': minor
3+
'@plait/mind': minor
4+
---
5+
6+
fix topic text can not show completely in different machines
7+
8+
1. add getElementSize to remeasure the width and height for text element and cache to `ELEMENT_TO_SIZE_MAP`.
9+
2. apply getElementSize to get the width and height for mind node topic text.
10+
3. handling the effect of mind node functions, such as editing topic, resizing mind node width and so on.

packages/common/src/text/text-manage.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ import {
1515
import { fromEvent, timer } from 'rxjs';
1616
import { Editor, Element, NodeEntry, Range, Text, Node, Transforms, Operation } from 'slate';
1717
import { PlaitTextBoard, TextPlugin } from './with-text';
18-
import { measureElement } from './text-measure';
18+
import { clearElementSizeCache, measureElement, updateElementSizeCache } from './text-measure';
1919
import { TextChangeData, TextComponentRef, TextProps } from './with-text';
20+
import { ParagraphElement } from './types';
2021

2122
export interface TextManageChangeData {
2223
newText?: Element;
@@ -75,11 +76,13 @@ export class TextManage {
7576
},
7677
onComposition: (event: CompositionEvent) => {
7778
if (event.type === 'compositionend') {
79+
clearElementSizeCache(this.board, this.editor.children[0] as ParagraphElement);
7880
return;
7981
}
8082
const fakeRoot = buildCompositionData(this.editor, event.data);
8183
if (fakeRoot) {
8284
const sizeData = this.getSize(fakeRoot.children[0]);
85+
updateElementSizeCache(this.board, this.editor.children[0] as ParagraphElement, sizeData);
8386
// invoking onChange asap to avoid blinking on typing chinese
8487
this.options.onChange && this.options.onChange({ ...sizeData });
8588
MERGING.set(this.board, true);

packages/common/src/text/text-measure.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Node } from 'slate';
2-
import { CustomText, ParagraphElement } from './types';
2+
import { CustomText, ElementSize, ParagraphElement } from './types';
33
import { getLineHeightByFontSize } from '../utils/text';
44
import { PlaitBoard } from '@plait/core';
55

66
const BOARD_TO_CANVAS_MAP = new WeakMap<PlaitBoard, HTMLCanvasElement>();
77

8+
const ELEMENT_TO_SIZE_MAP = new WeakMap<ParagraphElement, ElementSize>();
9+
810
const getCanvasForBoard = (board: PlaitBoard | null): HTMLCanvasElement => {
911
if (board) {
1012
if (!BOARD_TO_CANVAS_MAP.get(board)) {
@@ -17,6 +19,32 @@ const getCanvasForBoard = (board: PlaitBoard | null): HTMLCanvasElement => {
1719
return document.createElement('canvas');
1820
};
1921

22+
export const getElementSize = (
23+
board: PlaitBoard | null,
24+
element: ParagraphElement,
25+
options: {
26+
fontSize: number;
27+
fontFamily: string;
28+
},
29+
containerMaxWidth: number = 10000
30+
) => {
31+
let size = ELEMENT_TO_SIZE_MAP.get(element);
32+
if (size) {
33+
return size;
34+
}
35+
size = measureElement(board, element, options, containerMaxWidth);
36+
ELEMENT_TO_SIZE_MAP.set(element, size);
37+
return size;
38+
};
39+
40+
export const updateElementSizeCache = (board: PlaitBoard | null, element: ParagraphElement, size: ElementSize) => {
41+
ELEMENT_TO_SIZE_MAP.set(element, size);
42+
};
43+
44+
export const clearElementSizeCache = (board: PlaitBoard | null, element: ParagraphElement) => {
45+
ELEMENT_TO_SIZE_MAP.delete(element);
46+
};
47+
2048
export function measureElement(
2149
board: PlaitBoard | null,
2250
element: ParagraphElement,

packages/common/src/text/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { BaseElement, Editor } from 'slate';
1+
import { BaseElement } from 'slate';
2+
3+
export type ElementSize = {
4+
width: number;
5+
height: number;
6+
}
27

38
export enum Alignment {
49
left = 'left',

packages/mind/src/mind-node.component.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,7 @@ export class MindNodeComponent
8888
}
8989
},
9090
getMaxWidth: () => {
91-
if (this.element.manualWidth) {
92-
return NodeSpace.getNodeDynamicWidth(this.board, this.element);
93-
} else {
94-
return Math.max(NodeSpace.getNodeDynamicWidth(this.board, this.element), NodeTopicThreshold.defaultTextMaxWidth);
95-
}
91+
return NodeSpace.getTopicMaxDynamicWidth(this.board, this.element);
9692
},
9793
textPlugins: plugins || []
9894
});

packages/mind/src/plugins/with-node-resize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export const withNodeResize = (board: PlaitBoard) => {
4444
beforeResize: (resizeRef: ResizeRef<MindElement, null>) => {
4545
targetElementRef = {
4646
minWidth: NodeSpace.getNodeResizableMinWidth(board as PlaitMindBoard, resizeRef.element),
47-
currentWidth: NodeSpace.getNodeDynamicWidth(board as PlaitMindBoard, resizeRef.element),
47+
currentWidth: NodeSpace.getTopicDynamicWidth(board as PlaitMindBoard, resizeRef.element),
4848
path: PlaitBoard.findPath(board, resizeRef.element),
4949
textManage: getFirstTextManage(resizeRef.element)
5050
};

packages/mind/src/transforms/node.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,12 @@ import { MindElement, PlaitMind } from '../interfaces/element';
33
import { PlaitBoard, PlaitHistoryBoard, PlaitNode, Transforms, removeSelectedElement } from '@plait/core';
44
import { AbstractRef, getRelativeStartEndByAbstractRef, insertElementHandleAbstract } from '../utils/abstract/common';
55
import { RightNodeCountRef, insertElementHandleRightNodeCount, isInRightBranchOfStandardLayout } from '../utils/node/right-node-count';
6-
import { NodeSpace } from '../utils/space/node-space';
6+
import { normalizeWidthAndHeight } from '../utils/space/node-space';
77
import { PlaitMindBoard } from '../plugins/with-mind.board';
88
import { findNewChildNodePath, findNewSiblingNodePath, insertMindElement } from '../utils';
99
import { setAbstractsByRefs } from './abstract-node';
1010
import { AbstractNode } from '@plait/layouts';
1111

12-
const normalizeWidthAndHeight = (board: PlaitMindBoard, element: MindElement, width: number, height: number) => {
13-
const minWidth = NodeSpace.getNodeTopicMinWidth(board, element);
14-
const newWidth = width < minWidth ? minWidth : width;
15-
return { width: Math.ceil(newWidth), height };
16-
};
17-
1812
export const setTopic = (board: PlaitMindBoard, element: MindElement, topic: Element, width: number, height: number) => {
1913
const newElement = {
2014
data: { ...element.data, topic },
@@ -48,7 +42,7 @@ export const setTopicSize = (board: PlaitMindBoard, element: MindElement, width:
4842

4943
export const insertNodes = (board: PlaitBoard, elements: MindElement[], path: Path) => {
5044
const pathRef = board.pathRef(path);
51-
elements.forEach(element => {
45+
elements.forEach((element) => {
5246
if (pathRef.current) {
5347
Transforms.insertNode(board, element, pathRef.current);
5448
}
@@ -59,7 +53,7 @@ export const insertNodes = (board: PlaitBoard, elements: MindElement[], path: Pa
5953
export const insertAbstractNodes = (board: PlaitBoard, validAbstractRefs: AbstractRef[], elements: MindElement[], path: Path) => {
6054
const parent = PlaitNode.get(board, Path.parent(path));
6155
const abstractPath = [...Path.parent(path), parent.children?.length!];
62-
const abstracts = validAbstractRefs.map(refs => {
56+
const abstracts = validAbstractRefs.map((refs) => {
6357
const { start, end } = getRelativeStartEndByAbstractRef(refs, elements);
6458
return {
6559
...refs.abstract,
@@ -72,7 +66,7 @@ export const insertAbstractNodes = (board: PlaitBoard, validAbstractRefs: Abstra
7266
};
7367

7468
export const setRightNodeCountByRefs = (board: PlaitBoard, refs: RightNodeCountRef[]) => {
75-
refs.forEach(ref => {
69+
refs.forEach((ref) => {
7670
Transforms.setNode(board, { rightNodeCount: ref.rightNodeCount }, ref.path);
7771
});
7872
};

packages/mind/src/utils/position/topic.spec.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { getTopicRectangleByNode } from './topic';
77
import { getRectangleByNode } from './node';
88
import { NodeSpace } from '../space/node-space';
99
import { PlaitMindBoard } from '../../plugins/with-mind.board';
10+
import { DEFAULT_FONT_FAMILY, getElementSize } from '@plait/common';
11+
import { DEFAULT_FONT_SIZE } from '@plait/text-plugins';
1012

1113
describe('utils position topic', () => {
1214
let board: PlaitMindBoard;
@@ -36,7 +38,12 @@ describe('utils position topic', () => {
3638
const rectangle1 = getTopicRectangleByNode(board, mindNode);
3739
expect(rectangle1.x).toEqual(x);
3840
expect(rectangle1.y).toEqual(y);
39-
expect(Math.ceil(rectangle1.width)).toEqual(Math.ceil(mindNode.origin.width));
40-
expect(rectangle1.height).toEqual(mindNode.origin.height);
41+
expect(rectangle1.width).not.toEqual(mindNode.origin.width);
42+
const topicSize = getElementSize(null, mindNode.origin.data.topic, {
43+
fontSize: DEFAULT_FONT_SIZE,
44+
fontFamily: DEFAULT_FONT_FAMILY
45+
});
46+
expect(rectangle1.width).toEqual(topicSize.width);
47+
expect(rectangle1.height).toEqual(topicSize.height);
4148
});
4249
});

packages/mind/src/utils/position/topic.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ import { RectangleClient } from '@plait/core';
88
export function getTopicRectangleByNode(board: PlaitMindBoard, node: MindNode) {
99
let nodeRectangle = getRectangleByNode(node);
1010
const result = getTopicRectangleByElement(board, nodeRectangle, node.origin);
11-
result.width = result.width;
1211
return result;
1312
}
1413

1514
export function getTopicRectangleByElement(board: PlaitMindBoard, nodeRectangle: RectangleClient, element: MindElement) {
1615
const x = nodeRectangle.x + NodeSpace.getTextLeftSpace(board, element);
1716
const y = nodeRectangle.y + NodeSpace.getTextTopSpace(board, element);
18-
const width = NodeSpace.getNodeDynamicWidth(board, element);
19-
const height = Math.ceil(element.height);
17+
const width = NodeSpace.getTopicDynamicWidth(board, element);
18+
const height = NodeSpace.getTopicHeight(board, element);
2019
return { height, width, x, y };
2120
}

packages/mind/src/utils/space/node-space.ts

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { getEmojisWidthHeight } from './emoji';
88
import { Element } from 'slate';
99
import { getStrokeWidthByElement } from '../node-style/shape';
1010
import { getDefaultMindElementFontSize } from '../mind';
11-
import { DEFAULT_FONT_SIZE, MarkTypes, PlaitMarkEditor } from '@plait/text-plugins';
12-
import { getFirstTextEditor } from '@plait/common';
11+
import { DEFAULT_FONT_SIZE, getFirstTextMarks, MarkTypes, PlaitMarkEditor } from '@plait/text-plugins';
12+
import { DEFAULT_FONT_FAMILY, getElementSize, getFirstTextEditor } from '@plait/common';
13+
import { NodeTopicThreshold } from '../../constants/node-topic-style';
1314

1415
const NodeDefaultSpace = {
1516
horizontal: {
@@ -61,24 +62,55 @@ export const NodeSpace = {
6162
NodeSpace.getEmojiLeftSpace(board, element) +
6263
getEmojisWidthHeight(board, element).width +
6364
getSpaceEmojiAndText(element) +
64-
NodeSpace.getNodeDynamicWidth(board, element) +
65+
NodeSpace.getTopicDynamicWidth(board, element) +
6566
nodeAndText
6667
);
6768
}
68-
return nodeAndText + NodeSpace.getNodeDynamicWidth(board, element) + nodeAndText;
69+
return nodeAndText + NodeSpace.getTopicDynamicWidth(board, element) + nodeAndText;
6970
},
7071
getNodeHeight(board: PlaitMindBoard, element: MindElement) {
72+
const topicSize = getElementSize(
73+
board,
74+
element.data.topic,
75+
{ fontSize: DEFAULT_FONT_SIZE, fontFamily: DEFAULT_FONT_FAMILY },
76+
NodeSpace.getTopicMaxDynamicWidth(board, element)
77+
);
78+
const normalizedSize = normalizeWidthAndHeight(board, element, topicSize.width, topicSize.height);
7179
const nodeAndText = getVerticalSpaceBetweenNodeAndText(board, element);
7280
if (MindElement.hasImage(element)) {
73-
return NodeSpace.getTextTopSpace(board, element) + element.height + nodeAndText;
81+
return NodeSpace.getTextTopSpace(board, element) + normalizedSize.height + nodeAndText;
7482
}
75-
return nodeAndText + element.height + nodeAndText;
83+
return nodeAndText + normalizedSize.height + nodeAndText;
7684
},
77-
getNodeDynamicWidth(board: PlaitMindBoard, element: MindElement) {
78-
const width = element.manualWidth || element.width;
85+
getTopicDynamicWidth(board: PlaitMindBoard, element: MindElement) {
86+
const topicSize = getElementSize(
87+
board,
88+
element.data.topic,
89+
{ fontSize: getDefaultMindElementFontSize(board, element), fontFamily: DEFAULT_FONT_FAMILY },
90+
NodeSpace.getTopicMaxDynamicWidth(board, element)
91+
);
92+
const normalizedSize = normalizeWidthAndHeight(board, element, topicSize.width, topicSize.width);
93+
const width = element.manualWidth || normalizedSize.width;
7994
const imageWidth = MindElement.hasImage(element) ? element.data.image?.width : 0;
8095
return Math.max(width, imageWidth);
8196
},
97+
getTopicHeight(board: PlaitMindBoard, element: MindElement) {
98+
const topicSize = getElementSize(
99+
board,
100+
element.data.topic,
101+
{ fontSize: DEFAULT_FONT_SIZE, fontFamily: DEFAULT_FONT_FAMILY },
102+
NodeSpace.getTopicMaxDynamicWidth(board, element)
103+
);
104+
const normalizedSize = normalizeWidthAndHeight(board, element, topicSize.width, topicSize.height);
105+
return normalizedSize.height;
106+
},
107+
getTopicMaxDynamicWidth(board: PlaitMindBoard, element: MindElement) {
108+
return Math.max(
109+
NodeTopicThreshold.defaultTextMaxWidth,
110+
element.manualWidth || 0,
111+
MindElement.hasImage(element) ? element.data.image?.width : 0
112+
);
113+
},
82114
/**
83115
* use it when upload image first or resize image
84116
*/
@@ -96,9 +128,8 @@ export const NodeSpace = {
96128
},
97129
getNodeTopicMinWidth(board: PlaitMindBoard, element: MindElement) {
98130
const defaultFontSize = getDefaultMindElementFontSize(board, element);
99-
const editor = getFirstTextEditor(element);
100-
const marks = PlaitMarkEditor.getMarks(editor);
101-
const fontSize = (marks[MarkTypes.fontSize] as number) || defaultFontSize;
131+
const firstText = getFirstTextMarks(element.data.topic);
132+
const fontSize = (firstText[MarkTypes.fontSize] ? Number(firstText[MarkTypes.fontSize]) : null) || defaultFontSize;
102133
return fontSize;
103134
},
104135
getTextLeftSpace(board: PlaitMindBoard, element: MindElement) {
@@ -141,3 +172,9 @@ export const getFontSizeBySlateElement = (text: string | Element) => {
141172
const fontSize = (marks[MarkTypes.fontSize] as number) || defaultFontSize;
142173
return fontSize;
143174
};
175+
176+
export const normalizeWidthAndHeight = (board: PlaitMindBoard, element: MindElement, width: number, height: number) => {
177+
const minWidth = NodeSpace.getNodeTopicMinWidth(board, element);
178+
const newWidth = width < minWidth ? minWidth : width;
179+
return { width: newWidth, height };
180+
};

0 commit comments

Comments
 (0)