如何根据文本宽度动态调整SVG矩形的大小?

时间:2018-12-17 12:05:02

标签: javascript d3.js svg

在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;
    });

如您所见,当前我将文本放在可用空间的中心。然后,我尝试根据它们的文本设置rect的宽度,但是我从没有同时获得rect元素和文本HTML元素(对于getBBox())。这是我的尝试之一:

rects.attr("width",
        d => this.getBBox().width + 20
    );

但显然this是错误的,因为它指的是rects而不是文本。

这里正确的方法是什么?

3 个答案:

答案 0 :(得分:6)

我将使用getComputedTextLength来测量文本。我不知道D3.js中是否有与此等效的程序。我的答案是使用纯JavaScript,并假设rect和文本中心为{x:50,y:25},而您正在使用{{1} }

text{dominant-baseline:middle;text-anchor:middle;}
let text_length = txt.getComputedTextLength();

rct.setAttributeNS(null,"width",text_length )
rct.setAttributeNS(null,"x",(50 - text_length/2) )
svg{border:1px solid}
text{dominant-baseline:middle;text-anchor:middle;}

或者您可以使用<svg viewBox="0 0 100 50"> <rect x="25" y="12.5" width="50" height="25" stroke="black" fill="none" id="rct" /> <text x="50" y="25" id="txt">Test text</text> </svg>

代替txt.getComputedTextLength()

答案 1 :(得分:2)

当您记得this调用中的attr()绑定引用关联的HTML(SVG)元素时,解决方案非常简单:

rects.attr("width",
    d => this.parentNode.childNodes[1].getComputedTextLength() + 20;
);

rect是构成要显示的节点的SVG元素列表中的第一个元素。该节点的文本位于索引1(如来自append调用的索引)。

答案 2 :(得分:0)

通常我会发表评论,但是我没有足够的声誉。 公认的答案具有正确的想法,但不管他如何编码,都行不通。第一个问题是,他使用箭头函数而不是匿名函数。在箭头功能中,this具有不同的范围。因此,请在此处使用匿名函数。

第二个问题是问题中recttext的顺序,如您在源代码中所见。由于rect附加在text之前,所以父节点还没有子text。因此,您必须just append rect,然后附加text并设置其attrs,然后设置attrs的{​​{1}}。因此解决方案是:

rect

注意:如果不需要参数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); ,则不必像我一样接受它。