-->

How to show values stacked bar chart utilizing dc.

2019-07-22 13:29发布

问题:

Based on this question, I was able to create a bar chart using dc.js and d3.js with labels. However, I turned the bar chart into a stacked bar chart (based on this documentation), and I'm having difficulty showing the labels for each of the stacks.

For example each stack in the below chart should show the number, but it's showing [object Object]

See below for code and here for codepen

Javascript

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

var ndx = crossfilter(data);

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



var YDimension = XDimension.group().reduce(
    function reduceAdd(p, d) {
      p[d.ID] = (p[d.ID]|| 0) + 1;
      return p;
    },
    function reduceRemove(p, d) {
      p[d.ID] = (p[d.ID]|| 0) -1;
      return p;
    },
    function reduceInitial() {
      return {};})


dc.barChart("#Chart")
    .width(480).height(300)
    .dimension(XDimension)
    .group(YDimension,"1A",function(d) {return d.value["1A"];})
    .stack(YDimension,"2B",function(d) {return d.value["2B"];})
    .stack(YDimension,"3C",function(d) {return d.value["3C"];})
    .stack(YDimension,"4D",function(d) {return d.value["4D"];})
    .stack(YDimension,"5E",function(d) {return d.value["5E"];})
    .transitionDuration(500)
    .xUnits(dc.units.ordinal)
    .x(d3.scale.ordinal().domain(XDimension))
    .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){
        text_object =  d3.select(d).data()[0].data.value
        return text_object
    })
    .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";
    });

})


dc.renderAll();

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/dc/1.7.0/dc.css" media="screen">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
<script src="https://rawgithub.com/NickQiZhu/dc.js/master/web/js/crossfilter.js"></script>
<script src="https://cdnjs.site44.com/dc3.js"></script>
<script src="https://rawgithub.com/NickQiZhu/dc.js/master/web/js/crossfilter.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<body>
    <div id='Chart'></div>
</body>

回答1:

Typically what I do in these situations is put a breakpoint on the line in question and poke around and see if the object contains the data that I want somewhere else.

It looks like you can use .datum().y here:

    text_object =  d3.select(d).datum().y

http://codepen.io/gordonwoodhull/pen/EgNvNr?editors=1010

This is still kind of weird code (using DOM elements as data for a data join for some other elements is pretty hacky) but hopefully this will get you moving.