需求
在编辑节点名称的时候,我们希望节点框的大小随着内容的大小进行变化。简单来说就是节点根据内容自适应大小。如何获取内容文本的大小下面有两种方法实现。
实现
水平文本测量大小的实现
这种方式仅对水平文本有效,能测量出文本的宽度,测量文本的高度无效。
1
2
3
4
|
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context!.font = '14px Arial, helvetica, sans-serif'; // 设置字体和字号,根据你要测的文本设置
const textWidth = context!.measureText(node.getAttrs()['text']['text']?.toString()!).width;
|
主要思路就是利用 HTML5 Canvas 的绘图功能来测量文本的宽度,然后根据文本的宽度动态调整节点的尺寸,以确保文本内容完全显示在节点内部。
-
创建画布和上下文:
- 首先,通过
document.createElement('canvas') 创建了一个 HTML5 Canvas 元素。
- 然后,通过
getContext('2d') 获取了 2D 绘图上下文,以便后续进行文本测量。
-
设置字体和字号:
- 使用
context.font 设置了绘制文本时所使用的字体和字号。这个需要和你节点内容字体、字号相匹配,否则存在误差
-
测量文本宽度:
- 调用了
context.measureText() 方法来测量给定文本在当前字体和字号下的宽度。measureText() 方法返回一个 TextMetrics 对象,其中包含了文本的宽度等信息。
另一种实现方式
这种方式类似于打一个草稿,先创建一个svg然后渲染然后获得文本的宽高,这个对于水平排列的文本和竖直排列的文本都有效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 创建一个包含字符串的 svg 元素
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute('width', '100');
svg.setAttribute('height', '100');
// 创建一个 <text> 元素
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute('font-family', 'Microsoft YaHei');
text.setAttribute('font-size', '14');
text.setAttribute('white-space', 'nowrap');
text.setAttribute('writing-mode', 'vertical-rl');
text.style.textOrientation = 'upright'
text.textContent = node.getAttrs()['text']['text']?.toString()!
// 将 <text> 元素添加到 <svg> 中
svg.appendChild(text);
// 将 <svg> 元素添加到文档中
document.body.appendChild(svg);
// 获取字符串的宽高
const textHeight = text.getBBox().height;
const textWidth = text.getBBox().width;
|
主要思路和水平节点的测量相同,不过因为竖直节点的定义和水平节点的不同,竖直节点中的内容是竖直排列,而canvas不能测量文本的高度,所以这里创建和antv X6中svg节点相同的元素,把文本放在其中渲染,然后获取高度,最后完成节点高度的动态调整。
- 其中,竖直节点的实现是在css上加上下面三个属性:
1
2
3
|
white-space: 'nowrap';
writing-mode: 'vertical-rl';
text-orientation = 'upright';
|
其他
刚开始我尝试的方法是先修改节点的名称,再通过DOM的getBoundingClientRect获取修改后的文本宽高,但是因为X6 实现了异步的渲染调度算法,所以会出现获取不到DOM元素的情况,如果通过settimeout设置一定的时延再获取,容易造成修改时的频闪,或者有时未动态调整的情况。