d3.js:圆环图中文本的垂直对齐 [英] d3.js: vertical alignment of text in a donut chart

查看:235
本文介绍了d3.js:圆环图中文本的垂直对齐的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在d3.js中有一个简单的圆环图,只用于比较2或3个项目。

I've got a simple donut chart in d3.js, which will only be used to compare 2 or 3 items.

http://jsfiddle.net/Ltqu2/

我想合并图例

在当前实现中,文本对齐对于3个项目是确定的,但对于2个项目,它不调整。对齐方式有点硬编码:

In the current implementation, the text alignment is ok for 3 items, but for 2 items it doesn't adjust. The alignment is somewhat hard coded:

    var l = svg.selectAll('.legend')
        .data(data)
        .enter().append('g')
        .attr('class', 'legend');

    l.append('text')
        .attr('x', 0)
        .attr('y', function(d, i) { return i * 40 - radius / 2 + 10; })
        .attr('class', function(d, i){return 'legend-label data-label value-' + (i+1)})
        .text(function(d, i) { return d + '%'; });

    l.append('text')
        .attr('x', 0)
        .attr('y', function(d, i) { return i * 40 - radius / 2 + 22; })
        .attr('class', function(d, i){return 'legend-label units-label value-' + (i+1)})
        .text(function(d, i) { return legend[i]; });

如何使文本对齐更加灵活,所以它均匀分配2和3项?有什么我可以使用.rangeround?

How can I make the text alignment more flexible, so it distributes evenly for both 2 and 3 items? Is there something I can use .rangeround for?

这是完整的脚本

    /**
 *  Donut chart for d3.js
 */

 function donutChart() {
    var width = 420,
        height = 420,
        radius = 0,
        factor = 0.7;

    var legend = ['Low', 'Medium', 'High'];

    function chart(selection) {
        selection.each(function(data) {
            if (radius == 0) {
               radius = Math.min(width, height) / 2 - 10;
            }

            var arc = d3.svg.arc()
                .innerRadius(radius * factor)
                .outerRadius(radius);

            var pie = d3.layout.pie()
                .sort(null)
                .value(function(d) { return d; });

            var svg = d3.select(this).append('svg')
                .attr('width', width)
                .attr('height', height)
                .attr('class', 'donut')
                .append('g')
                .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
            var g = svg.selectAll('.arc')
                .data(pie(data))
                .enter().append('g')
                .attr('class', 'arc');

            g.append('path')
                .attr('d', arc)
                .attr('class', function(d, i){return 'value-' + (i+1)})
                .style('stroke', '#fff');

            var l = svg.selectAll('.legend')
                .data(data)
                .enter().append('g')
                .attr('class', 'legend');

            l.append('text')
                .attr('x', 0)
                .attr('y', function(d, i) { return i * 40 - radius / 2 + 10; })
                .attr('class', function(d, i){return 'legend-label data-label value-' + (i+1)})
                .text(function(d, i) { return d + '%'; });

            l.append('text')
                .attr('x', 0)
                .attr('y', function(d, i) { return i * 40 - radius / 2 + 22; })
                .attr('class', function(d, i){return 'legend-label units-label value-' + (i+1)})
                .text(function(d, i) { return legend[i]; });
        });
    }

    chart.width = function(_) {
        if (!arguments.length) return width;
        width = _;
        return chart;
    };

    chart.height = function(_) {
        if (!arguments.length) return height;
        height = _;
        return chart;
    };

    chart.radius = function(_) {
        if (!arguments.length) return radius;
        radius = _;
        return chart;
    };

    chart.factor = function(_) {
        if (!arguments.length) return factor;
        factor = _;
        return chart;
    };

    chart.legend = function(_) {
        if (!arguments.length) return legend;
        legend = _;
        return chart;
    };

    return chart;
 }

d3.select('#chart')
  .datum([78, 20])
  .call(donutChart()
  .width(220)
  .height(220)
  .legend(['This Thing', 'That Thing'])
);

d3.select('#chart2')
  .datum([63, 20, 15])
  .call(donutChart()
  .width(220)
  .height(220)
  .legend(['This Thing', 'That Thing', 'Another Thing'])
);


推荐答案

我会把所有的图例文字元素放在一个共同的< g> 元素,然后可以垂直平移到中心。确定SVG中的实际文本大小总是很痛苦,您可以查看 getBBox()获取更多信息。但使用预定的文本高度将工作正常。这里有一点计算(为了清楚起见,分成许多步骤):

I would put all the legend text elements in a common <g> element which can then be translated to center vertically. Determining actual text sizes in SVG is always a pain, you can look into getBBox() for more information on that. But using a predetermined text height will work fine. Here's a bit of calculation (separated into many steps for clarity):

// hardcoding 36 here, you could use getBBox to get the actual SVG text height using sample text if you really wanted.
var legendItemHeight = 36;

// calculated height of all legend items together
var actualLegendHeight = data.length * legendItemHeight;

// inner diameter
var availableLegendHeight = radius * factor * 2;

// y-coordinate of first legend item (relative to the center b/c the main svg <g> element is translated
var legendOffset = (availableLegendHeight - actualLegendHeight) / 2 - (radius*factor);

然后创建一个< g> / code>元素来保存< text> 元素:

// append all the legend items to a common group which is translated
var l = svg.selectAll('.legend')
    .data(data)
    .enter().append('g')
    .attr('class', 'legend')
    .attr('transform', function(d, i) { 
        return 'translate(0, '+ (legendOffset + i * legendHeight)+')'; 
    });

修改jsFiddle: http://jsfiddle.net/rshKs/2/

Modified jsFiddle: http://jsfiddle.net/rshKs/2/

这篇关于d3.js:圆环图中文本的垂直对齐的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆