如何根据文本宽度动态调整 SVG 矩形的大小?
Posted
技术标签:
【中文标题】如何根据文本宽度动态调整 SVG 矩形的大小?【英文标题】:How can I dynamically resize an SVG rect based on text width? 【发布时间】:2019-05-17 19:12:06 【问题描述】:在 SVG 图形中,我创建了由矩形和一些文本组成的节点元素。文本的数量可能会有很大差异,因此我想根据文本的宽度设置矩形的宽度。
下面是使用 D3.js 创建矩形(使用固定的宽度和高度值):
var rects = nodeEnter.append("rect")
.attr("width", rectW)
.attr("height", rectH);
后跟文本元素:
var nodeText = nodeEnter.append("text")
.attr("class", "node-text")
.attr("y", rectH / 2)
.attr("dy", ".35em")
.text(function (d)
return d.data.name;
);
nodeText // The bounding box is valid not before the node addition happened actually.
.attr("x", function (d)
return (rectW - this.getBBox().width) / 2;
);
如您所见,目前我将文本置于可用空间的中心。然后我尝试根据它们的文本设置矩形的宽度,但我从来没有同时得到矩形元素和文本 html 元素(用于 getBBox())。这是我的尝试之一:
rects.attr("width",
d => this.getBBox().width + 20
);
但显然this
是错误的,因为它指的是rects
而不是文本。
这里的正确方法是什么?
【问题讨论】:
您可以通过在问题中添加 CSS 标签来获得更多帮助 嗯,这不是一个真正的 CSS 问题。我主要需要知道如何设置一些东西,而不是什么。 这有帮助吗? ***.com/questions/15500894/… 它帮助我解决了另一个问题。我实际上赞成那里的一个答案。 【参考方案1】:我会使用getComputedTextLength
来测量文本。我不知道在 D3.js 中是否有等价物我的答案是使用纯 javascript 并假设 rect 和文本中心是 x:50,y:25 并且您使用的是textdominant-baseline:middle;text-anchor:middle;
let text_length = txt.getComputedTextLength();
rct.setAttributeNS(null,"width",text_length )
rct.setAttributeNS(null,"x",(50 - text_length/2) )
svgborder:1px solid
textdominant-baseline:middle;text-anchor:middle;
<svg viewBox="0 0 100 50">
<rect x="25" y="12.5" stroke="black" fill="none" id="rct" />
<text x="50" y="25" id="txt">Test text</text>
</svg>
您也可以使用txt.textLength.baseVal.value
代替txt.getComputedTextLength()
【讨论】:
好建议,但不是我真正需要的。【参考方案2】:当您记得 attr()
调用中的 this
绑定引用关联的 HTML (SVG) 元素时,解决方案非常简单:
rects.attr("width",
d => this.parentNode.childNodes[1].getComputedTextLength() + 20
);
rect
是组成显示节点的 SVG 元素列表中的第一个元素。该节点的 text
位于索引 1 处(如下来自 append
调用)。
【讨论】:
【参考方案3】:通常我会发表评论,但我没有足够的声望点。
接受的答案有正确的想法,但它不起作用,他是如何编码的。第一个问题是,他使用箭头函数而不是匿名函数。在箭头函数中,this
具有不同的作用域。所以在这里使用匿名函数。
第二个问题是rect
和text
的顺序,你可以在源代码中看到,在问题中。由于rect
附加在text
之前,因此父节点还没有子text
。所以你必须just append
rect
,然后追加text
并设置它的attrs
,然后设置rect
的attrs
。所以解决办法是:
var rects = nodeEnter.append("rect")
var nodeText = nodeEnter.append("text")
.attr("class", "node-text")
.attr("y", rectH / 2)
.attr("dy", ".35em")
.text(function (d)
return d.data.name;
);
nodeText // The bounding box is valid not before the node addition happened actually.
.attr("x", function (d)
return (rectW - this.getBBox().width) / 2;
);
rect
.attr('width', function ()
return this.parentNode.childNodes[1].getComputedTextLength();
)
.attr("height", rectH);
注意:如果你不需要参数d
,你不必像我一样接受它。
【讨论】:
问题是,这是我自己对我的问题的回答,我发布了它,因为它的工作原理与书面完全一样。箭头函数是必不可少的(您可能应该始终使用它,除非您有特定的理由不这样做),因为它将this
绑定到不同的上下文(取决于调用者),但始终绑定到所有者类/函数(这是你最想要的)。
我试过你的例子,但它没有那样工作。我首先必须应用我的修复程序,所以我为这个案例发布了它,其他的问题和我一样
我无法想象,在你的例子中,dom/javascript 没有抱怨,孩子text
还没有被附加。
另外值得注意的是,d3 本身使用了匿名函数。以上是关于如何根据文本宽度动态调整 SVG 矩形的大小?的主要内容,如果未能解决你的问题,请参考以下文章