如何在D3图表中的标签中包含换行符?

bde*_*ham 62 javascript svg d3.js

我正在使用D3生成条形图(我使用了此示例中的代码).我在x轴上使用的标签每个都是两个字,因为这使得所有标签重叠,我需要跨行打破这些标签.(如果我可以用换行符替换每个标签中的所有空格,那就没问题了.)

我最初尝试使用文字换行符(&#xA;)替换空格并xml:space="preserve"在标签<text>元素上设置.不幸的是,事实证明SVG不尊重这个属性.接下来,我尝试将每个单词包装成<tspan>我以后可以使用的单词.我通过这个函数传递了每个标签:

function (text) {
    return '<tspan>' + text.replace(/ /g, '</tspan><tspan>') + '</tspan>';
}
Run Code Online (Sandbox Code Playgroud)

但这只是将文字<tspan>放入输出中.如何将文本标签包装在tspans中(或执行其他操作)以使我的标签不重叠?

bde*_*ham 86

我最终使用以下代码来跨行打破每个x轴标签:

var insertLinebreaks = function (d) {
    var el = d3.select(this);
    var words = d.split(' ');
    el.text('');

    for (var i = 0; i < words.length; i++) {
        var tspan = el.append('tspan').text(words[i]);
        if (i > 0)
            tspan.attr('x', 0).attr('dy', '15');
    }
};

svg.selectAll('g.x.axis g text').each(insertLinebreaks);
Run Code Online (Sandbox Code Playgroud)

请注意,这假定已经创建了标签.(如果您遵循规范直方图示例,那么标签将以您需要的方式设置.)也没有任何真正的断行逻辑; 该函数将每个空格转换为换行符.这符合我的目的,但您可能需要编辑该split()行以更智能地将字符串的各个部分划分为行.

  • 这正是我需要的,谢谢.对于那些可能处于类似情况的人,我应该指出`d`这里是一个数据点而*不是*你要格式化的字符串,所以`.split()`(至少对我而言)需要改变到`d.description.split("\n");`. (6认同)
  • 除了@ DanielQuinn建议拆分换行符之外的另一个改进:使用`d3.select(this).text()`来获取实际的元素文本而不是绑定的数据值.这有两个原因:首先,您的轴值可能是数字而不是字符串(此代码在这种情况下失败),其次,我的改进允许自定义文本由轴生成器上的`tickFormat`函数插入. (2认同)

Ily*_*din 8

SVG文本元素不支持文本换行,因此有两个选项:

  • 将文本拆分为多个SVG文本元素
  • 在SVG上使用叠加HTML div

请参阅本迈克·博斯托克的评论在这里.


小智 6

我发现有用的东西是使用'foreignObject'标签而不是text或tspan元素.这允许简单地嵌入HTML,允许单词自然地破解.需要注意的是满足特定需求的对象的整体尺寸:

var myLabel = svg.append('foreignObject')
    .attr({
        height: 50,
        width: 100, // dimensions determined based on need
        transform: 'translate(0,0)' // put it where you want it...
     })
     .html('<div class"style-me"><p>My label or other text</p></div>');
Run Code Online (Sandbox Code Playgroud)

您可以使用d3.select/selectAll动态更新文本值,以便随后可以获取此对象内部的任何元素.


Joh*_*kin 5

环顾四周后,我发现 Mike Bostock 提供了一个解决方案,使您可以将文本环绕。

http://bl.ocks.org/mbostock/7555321

要在我的代码上实现它(我正在使用折叠树图)。我只是复制了“wrap”方法。

然后附加以下内容

    // Standard code for a node    
    nodeEnter.append("text")
        .attr("x", function(d) { return d.children || d._children ? -10 : 10; })
        .attr("dy", ".35em")
        .text(function(d) { return d.text; })
        // New added line to call the function to wrap after a given width
        .call(wrap, 40);
Run Code Online (Sandbox Code Playgroud)

我看不出有任何理由这不适用于力导向、条形或任何其他模式

修正案 :

对于阅读本文并使用可折叠图的任何人,我已将换行函数修改为以下内容。“x”属性的更改正确设置了对齐方式,增加行号是在单独的行上执行的,因为原始代码中注意到了问题,并且“y”已硬设置为零,否则会出现行距增加的问题每行。

function wrap(text, width) {
    text.each(function() {
        var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        lineHeight = 1.1, // ems
        tspan = text.text(null).append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", y).attr("dy", dy + "em");     
        while (word = words.pop()) {
            line.push(word);
            tspan.text(line.join(" "));
            var textWidth = tspan.node().getComputedTextLength();
            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(" "));
                line = [word];
                ++lineNumber;
                tspan = text.append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", 0).attr("dy", lineNumber * lineHeight + dy + "em").text(word);
            }
        }
    });
}
Run Code Online (Sandbox Code Playgroud)