【问题标题】:Show values on top of bars in a barChart在条形图中的条形顶部显示值
【发布时间】:2014-09-21 10:57:39
【问题描述】:

我有一个带有 x 轴序数刻度的条形图。我想在每个条的顶部或每个条的底部显示 y 值。当鼠标悬停在条上时显示 y 值也是可以接受的。 dc.js 中是否有功能或方法可以做到这一点?这是jsfiddle,我的代码在图片下方>

编辑:这是我的代码: HTML

<body>
    <div id='Chart'>
    </div>
</body>

JS

var data = [{
    Category: "A",
    ID: "1"
}, {
    Category: "A",
    ID: "1"
}, {
    Category: "A",
    ID: "1"
}, {
    Category: "A",
    ID: "2"
}, {
    Category: "A",
    ID: "2"
}, {
    Category: "B",
    ID: "1"
}, {
    Category: "B",
    ID: "1"
}, {
    Category: "B",
    ID: "1"
}, {
    Category: "B",
    ID: "2"
}, {
    Category: "B",
    ID: "3"
}, {
    Category: "B",
    ID: "3"
}, {
    Category: "B",
    ID: "3"
}, {
    Category: "B",
    ID: "4"
}, {
    Category: "C",
    ID: "1"
}, {
    Category: "C",
    ID: "2"
}, {
    Category: "C",
    ID: "3"
}, {
    Category: "C",
    ID: "4"
}, {
    Category: "C",
    ID: "4"
},{
    Category: "C",
    ID: "5"
}];

var ndx = crossfilter(data);

var XDimension = ndx.dimension(function (d) {
    return d.Category;
});

var YDimension = XDimension.group().reduceCount(function (d) {
    return d.value;
});


dc.barChart("#Chart")
    .width(480).height(300)
    .dimension(XDimension)
    .group(YDimension)
    .transitionDuration(500)
    .xUnits(dc.units.ordinal)
    .label(function(d) {return d.value})
    .x(d3.scale.ordinal().domain(XDimension)) 

dc.renderAll();

【问题讨论】:

  • 您能发布您的代码和/或JSFiddle 之类的吗?
  • @mdml 完成!如果您还需要什么,请告诉我。
  • 获取 FIREBASE 警告:/UniqueActivities 的 on() 或 once() 失败:错误:permission_denied:客户端无权访问所需数据。
  • @elzi 我创建了一个jsfiddle 并简化了代码。

标签: javascript d3.js bar-chart dc.js crossfilter


【解决方案1】:

检查更新jsfiddle

.renderlet(function(chart){

    var barsData = [];
    var bars = chart.selectAll('.bar').each(function(d) { barsData.push(d); });

    //Remove old values (if found)
    d3.select(bars[0][0].parentNode).select('#inline-labels').remove();
    //Create group for labels 
    var gLabels = d3.select(bars[0][0].parentNode).append('g').attr('id','inline-labels');

    for (var i = bars[0].length - 1; i >= 0; i--) {

        var b = bars[0][i];
        //Only create label if bar height is tall enough
        if (+b.getAttribute('height') < 18) continue;
        
        gLabels
            .append("text")
            .text(barsData[i].data.value)
            .attr('x', +b.getAttribute('x') + (b.getAttribute('width')/2) )
            .attr('y', +b.getAttribute('y') + 15)
            .attr('text-anchor', 'middle')
            .attr('fill', 'white');
    }

})

如果您不希望在重绘条形图时显示标签(例如,当用户过滤/单击其他图表后条形图发生变化时),您可以将旧值的检查从 de renderlet 移动到 preRedraw 听众。

.on("preRedraw", function(chart){

    //Remove old values (if found)
    chart.select('#inline-labels').remove();

})

另类

D3-ish 方式

演示jsfiddle

.renderlet(function (chart) {
    
    //Check if labels exist
    var gLabels = chart.select(".labels");
    if (gLabels.empty()){
        gLabels = chart.select(".chart-body").append('g').classed('labels', true);
    }
    
    var gLabelsData = gLabels.selectAll("text").data(chart.selectAll(".bar")[0]);
    
    gLabelsData.exit().remove(); //Remove unused elements
    
    gLabelsData.enter().append("text") //Add new elements
    
    gLabelsData
    .attr('text-anchor', 'middle')
    .attr('fill', 'white')
    .text(function(d){
        return d3.select(d).data()[0].data.value
    })
    .attr('x', function(d){ 
        return +d.getAttribute('x') + (d.getAttribute('width')/2); 
    })
    .attr('y', function(d){ return +d.getAttribute('y') + 15; })
    .attr('style', function(d){
        if (+d.getAttribute('height') < 18) return "display:none";
    });
    
})

【讨论】:

  • 你太棒了。非常感谢。
  • 这很棒。它还不是非常惯用的 d3 代码,因为通常您使用选择来进行循环,并且更少的手动索引,但它越来越接近了。谢谢!
  • @Gordon 我用更惯用代码的替代方法更新了我的答案
  • 使用 dc 2.0,.on('pretransition', function {...}) 优于 .renderlet(function {...})
  • @dimirc - 感谢这个惊人的答案。我已经使用了很多,但我正在尝试将此解决方案用于堆叠条形图。我在这里发布了一个关于此的问题:stackoverflow.com/questions/39581885/…
【解决方案2】:

在 dc.js 版本 3.* 中。您可以使用.renderLabel(true)。它将在顶部打印值

【讨论】:

    【解决方案3】:

    这里有一个使用 renderlet 方法的 hacky 解决方案。 jsFiddlehttp://jsfiddle.net/tpsc5f9f/4/

    JS

    var barChart = dc.barChart("#Chart")
        .width(480).height(300)
        .dimension(XDimension)
        .group(YDimension)
        .transitionDuration(500)
        .xUnits(dc.units.ordinal)
        .x(d3.scale.ordinal().domain(XDimension)) 
    
    dc.renderAll();
    
    barChart.renderlet(function(chart){
        moveGroupNames();
    });
    
    
    function moveGroupNames() {
       var $chart = $('#Chart'),
           bar  = $chart.find('.bar');
    
        bar.each(function (i, item) {
            var bar_top    = this.height.baseVal.value;
            var bar_left   = this.width.baseVal.value;
            var bar_offset_x = 30;
            var bar_offset_y = 33;
    
            var bar_val = $(this).find('title').html().split(':')[1];
    
            $chart.append('<div class="val" style="bottom:'+(bar_top+bar_offset_y)+'px;left:'+((bar_left*i)+(bar_offset_x))+'px;width:'+bar_left+'px">'+bar_val+'</div>');
    
        });
    }
    

    添加了 CSS

    body {
        margin-top:20px;
    }
    #Chart {
        position:relative;
    }
    
    #Chart .val {
        position:absolute;
        left:0;
        bottom:0;
        text-align: center;
    }
    

    【讨论】:

    • 太棒了。但是,我正在寻找在每个栏的顶部显示数字,而不是栏名称。很抱歉造成混淆。我实际上用 renderlet 实现了相同的结果,但不知道如何在每个条形图的顶部显示数字(y 值)。
    • 好吧,在这种情况下,这是一个非常老套的解决方案,哈哈:jsfiddle.net/tpsc5f9f/4
    • 哎呀哎呀。我很生气它不是 dc.js 的默认功能。
    • 提交公关!不过,我认为您应该能够直接从栏中获取数据。 d3 用其数据注释每个 dom 元素。 @elzi,是否愿意在上面编辑您的答案,至少使用标题 hack?
    • 谢谢。请注意,d3.each 提供的 d 参数提供了数据,因此不需要标题 hack。您的解决方案非常有创意,但它所做的工作超出了它的需要。
    【解决方案4】:

    如果您对图表使用专门的 valueAccessor,您可以在 dimirc 的“D3-ish way”解决方案中进行以下替换。

    改变

    .text(function(d){
        return d3.select(d).data()[0].data.value
    })
    

    .text(function(d){
        return chart.valueAccessor()(d3.select(d).data()[0].data)
    });
    

    【讨论】:

      【解决方案5】:

      此函数会将行图的标签重新定位到每行的末尾。类似的技术可以用于使用“y”属性的条形图。

      • 标签与行矩形一起动画,使用图表的 transitionDuration
      • 使用图表的 valueAccessor 函数
      • 使用图表的 xAxis 比例计算标签位置

      rowChart.on('pretransition', function(chart) {
          var padding = 2;
              
          chart.selectAll('g.row > text') //find all row labels
              .attr('x', padding) //move labels to starting position
              .transition() //start transition
              .duration(chart.transitionDuration()) //use chart's transitionDuration so labels animate with rows
              .attr('x', function(d){ //set label final position
                  var dataValue = chart.valueAccessor()(d); //use chart's value accessor as basis for row label position
                  var scaledValue = chart.xAxis().scale()(dataValue); //convert numeric value to row width
                  return scaledValue+padding; //return scaled value to set label position
              });
      });

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-25
        • 1970-01-01
        • 2020-08-05
        相关资源
        最近更新 更多