NVD3.js - 如何将条形文本添加到堆叠图中的每个条形?

NVD3.js - How to add bar text to each bar in a stacked graph?

我在 NVD3/AngularJS 中创建了一个多条形图。我想在每个矩形条内显示文本及其值,如下面 JSON 所示。

如何在每个条形图内显示文本值?

NVD3 图表定义

multiBarChart: {
        options: function(){
          return {
            chart: {
              type: 'multiBarChart',
              stacked: true,
              x: function(d){return d.x;},
              y: function(d){return d.y;},
              text: function(d){return d.x;},
              showLabels: true,
              showLegend: false,
              transitionDuration: 500,
              forceX: ["Team", "Meeting", "Phase", "Source"],
              xAxis: {
                axisLabel: 'Category',
                axisLabelDistance: -8
              },
              yAxis: {
                axisLabel: 'Number Of Action Items',
              }
            }
          }
        },
        data: categoryChartData
      }

JSON 数据(类别图表数据)

  [ 
                                {"values" : [
                                    {
                                        "y" :10,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Team1"
                                },

                                {"values" : [
                                    {
                                        "y" :5,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Team2"
                                },
                                    {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 7,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Meeting1"
                                },
                                    {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 3,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Meeting2"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :9,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Phase1"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :5,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Phase1"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 2,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Internal"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 1,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Customer"
                                }


                                ];

Angular-nvd3 本身不会为 multi-bar 图表执行此操作,因为动画堆叠条形图会带来一些复杂性,但它会为离散条形图执行此操作,因为 explored. However, in an update to his answer to that question, @Topicus linked to a gist they wrote满足您的需求。

我根据你的情况调整了要点;你可以在 this Plunker 中看到结果。如果标签显示有点不稳定,您可以稍微调整一下格式。关键是标签需要在动画完成后追加,所以我设置了一个超时等于(也可以稍微大于)transitionDuration图表的值属性。我还删除了所有零值,这样它们就不会掩盖非零值。

$scope.options = {
  chart: {
    type: 'multiBarChart',
    height: 500,
    transitionDuration: 500,
    ...
  }
};

$scope.data...

$timeout(function () {
  d3.selectAll('.nv-multibar .nv-group').each(function(group){
    var g = d3.select(this);
  
    // Remove previous labels if there is any
    g.selectAll('text').remove(); 
    g.selectAll('.nv-bar').each(function(bar) {
      var b = d3.select(this);
      var barWidth = b.attr('width');
      var barHeight = b.attr('height');

      g.append('text')
        // Transforms shift the origin point then the x and y of the bar
        // is altered by this transform. In order to align the labels
        // we need to apply this transform to those.
        .attr('transform', b.attr('transform'))
        .text(function() {
          // No decimals format and eliminate zero values
          if (bar.y === 0) {
            return;
          }
          return parseFloat(bar.y).toFixed(0);
        })
        .attr('y', function() {
          // Center label vertically
          var height = this.getBBox().height;
          return parseFloat(b.attr('y')) + 15; // 15 is the label's margin from the top of bar
        })
        .attr('x', function() {
          // Center label horizontally
          var width = this.getBBox().width;
          return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
        })
        .style("stroke","black")
        .attr('class', 'bar-values');
    });
  });
}, 500);

我认为答案有两点需要补充。 1.我们添加代码在回调中添加值文本function.like:

callback: function(chart){
    chart.dispatch.on('stateChange', function(e){
        setMultiBarValue(e.stacked);
    });

    setMultiBarValue(config.stacked);
}

2.add 函数在 group/stacked 选项中显示正确的文本

function setMultiBarValue(chart, config, dataRange, stacked, time){
    if(config.type === 'multiBarChart'){
        if(stacked === true){
            //stack set your totalMin, totalMax to make all the value visible.
            chart.yDomain([dataRange.totalMin, dataRange.totalMax]);
            initStackLables(d3.select(chart.container), time || 1000);
        }else{
            //group: set your min,max to make all the value visible.
            chart.yDomain([dataRange.yMin, dataRange.yMax]);
            initGroupLabels(d3.select(chart.container), time || 1000);
        }
    }
}
  1. 定义拖车函数initStackLabels, initGroupLabels,like:

    1).initGroupLabels

    var initGroupLabels = function(container, time) { 时间=时间|| 500; container.selectAll('.nv-multibar .nv-group').each(函数(组){ var g = d3.select(这个); // 如果有的话,移除之前的标签 g.selectAll('text').删除(); }); $超时(功能(){ container.selectAll('.nv-multibar .nv-group').each(函数(组){ var g = d3.select(这个);

                g.selectAll('.nv-bar').each(function(bar, index) {
                    var b = d3.select(this);
                    var barWidth = b.attr('width');
                    var barHeight = b.attr('height');
    
                    g.append('text')
                    // Transforms shift the origin point then the x and y of the bar
                    // is altered by this transform. In order to align the labels
                    // we need to apply this transform to those.
                    .attr('transform', b.attr('transform')).text(function() {
                        // No decimals format and eliminate zero values
                        if (bar.y === 0) {
                            return;
                        }
                        return parseFloat(bar.y);
                    }).attr('y',
                    function() {
                        // Center label vertically
                        var height = this.getBBox().height;
                        return parseFloat(b.attr('y')) - 10; // 10 is the label's margin from the top of bar
                    }).attr('x',
                    function() {
                        // Center label horizontally
                        var width = this.getBBox().width;
                        return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
                    }).style('stroke', 'black').attr('class', 'bar-values');
                });
            });
        },
        time);
    }
    

    2)initStackLables

    var initStackLables =函数(容器,时间){ 时间=时间|| 500;

    container.selectAll('.nv-multibar .nv-group').each(function(group){
        var g = d3.select(this);
        // Remove previous labels if there is any
        g.selectAll('text').remove(); 
    });
    $timeout(function () {
        var length = container.selectAll('.nv-multibar .nv-group').length;
        var vArr = []; var yArr = [];
        container.selectAll('.nv-multibar .nv-group').each(function(group){
            var g = d3.select(this);
            g.selectAll('.nv-bar').each(function(bar, index){
                var b = d3.select(this); var by = parseFloat(b.attr('y'));
                var barHeight = b.attr('y');
                vArr[index] = vArr[index] || 0;
                vArr[index] += parseFloat(bar.y) || 0;
                yArr[index] = yArr[index] || by;
                yArr[index] = yArr[index] > by ? by : yArr[index];
            });
        });
        container.selectAll('.nv-multibar .nv-group').each(function(group, index){
            if(index === 0){
                var g = d3.select(this);
                // Remove previous labels if there is any
                g.selectAll('text').remove(); 
                g.selectAll('.nv-bar').each(function(bar, index){
                    var b = d3.select(this);
                    var barWidth = b.attr('width');
                    var barHeight = b.attr('height');
    
                    g.append('text')
                        .attr('transform', b.attr('transform'))
                        .text(function(){
                            if (bar.y === 0) {
                                return;
                            }
                            return parseFloat(vArr[index];
                        })
                        .attr('y', function(){
                            var height = this.getBBox().height;
                            return parseFloat(yArr[index]) - 10; // 10 is the label's margin from the top of bar
                        })
                        .attr('x', function(){
                            var width = this.getBBox().width;
                            return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
                        })
                        .style('stroke','black')
                        .attr('class', 'bar-values');
                });
            }
        });
    
    }, time);
    

    }