1
votes

enter image description here

I am using Flotcharts to create a stacked bar chart to show breakdown of values. I have this working so that once I hover over the stack it will show a tool tip with the value for that stack in it (you can see this in the second column).

What I need is at the top of all the stacks that it shows a label of the total value.

Something like High Charts Stacked Column.

You can see my code below. I loop through the data (using Smarty) and set it there.

// set the data
var data = [
    {
        label: 'Tenant',
        data: [
            {foreach $metrics.rent_applied_by_month as $rent_applied}
                [{$rent_applied@index}, {$rent_applied.tenant_value|number_format:2:'.':''}],
            {/foreach}
        ],
        color: '#008000'
    },
    {
        label: 'Benefit',
        data: [
            {foreach $metrics.rent_applied_by_month as $rent_applied}
                [{$rent_applied@index}, {$rent_applied.benefit_value|number_format:2:'.':''}],
            {/foreach}
        ],
        color: '#0000ff'
    }
];

// set the xasis labels
var ticks = [
    {foreach $metrics.rent_applied_by_month as $rent_applied}
        [{$rent_applied@index}, '{$rent_applied.period}'],
    {/foreach}
];

// chart options
var options = {
    series: {
        stack: 0,
        bars: {
            show: true,
            align: "center",
            barWidth: 0.6,
            fill: .75,
        }
    },
    xaxis: {
        ticks: ticks,
        tickLength: 1
    },
    grid: {
        hoverable: true,
        clickable: true,
        borderWidth: {
            top: 0,
            right: 0,
            bottom: 1,
            left: 1
        },
        borderColor: {
            top: "#e5e5e5",
            right: "#e5e5e5",
            bottom: "#a5b2c0",
            left: "#a5b2c0"
        }
    },
    legend: {
        show: true,
        noColumns: 2,
        position: "nw",
        margin: [10, 0],
        labelBoxBorderColor: null
    }
};

$.plot("#rent_applied", data, options);
1

1 Answers

0
votes

You'll need to loop through each of the bars in each stack to get the total value of all bars in each stack. With that total value in hand, you can pass it into flot's plot.pointOffset() method to get the position of the top of the stacked bars.

The code below has a sample method to get all of the values of a stack of bars, then uses the plot.pointOffset() to append a div showing the value on top of the bar.

$(function() {
  var data = [{
    data: [ [0, 21.51], [1, 32.50], [2, 47.14], [3, 10] ],
    stack: 0,
    label: 'Bottom'
  }, {
    data: [ [0, 37.77], [1, 24.65], [2, 7.67], [4, 15]],
    stack: 0,
    label: 'Top'
  }];

  var options = {
    series: {
      bars: {
        show: true,
        barWidth: .5,
        align: "center"
      },
      points: { show: false }
    }
  };

  var plot = $.plot($('#graph'), data, options);

  displayBarValues();

  // display values on top of bars  
  function displayBarValues() {
    var plotData = plot.getData();
    var xValueToStackValueMapping = [];

    // loop through each data series
    for (var i = 0; i < plotData.length; i++) {
      var series = plotData[i];

      // loop through each data point in the series
      for (var j = 0; j < series.data.length; j++) {
        var value = series.data[j];

        // if the x axis value is not in the mapping, add it.
        if (!xValueExistsInMapping(xValueToStackValueMapping, value[0])) {
          xValueToStackValueMapping.push([value[0], 0]);
        }

        // add the value of the bar to the x value mapping
        addValueToMapping(xValueToStackValueMapping, value[0], value[1]);
      }
    }

    // loop through each of our stacked values and place them on the bar chart
    $.each(xValueToStackValueMapping, function(i, value) {
      // find the offset of the top left of the bar
      var leftoffset = plot.pointOffset({ x: value[0] - .5, y: value[1] });

      // find the offset of the top right of the bar (our bar width is .5)
      var rightoffset = plot.pointOffset({ x: value[0] + .5, y: value[1] });

      $('<div class="data-point-value">' + value[1] + '</div>').css({
        left: leftoffset.left,
        top: leftoffset.top - 14,
        width: rightoffset.left - leftoffset.left,
        textAlign: 'center'
      }).appendTo(plot.getPlaceholder());
    });


  }

  function xValueExistsInMapping(mapping, value) {
    for (var i = 0; i < mapping.length; i++) {
      if (mapping[i][0] !== undefined && mapping[i][0] === value) {
        return true;
      }
    }
    return false;
  }

  function addValueToMapping(mapping, xValue, yValue) {
    for (var i = 0; i < mapping.length; i++) {
      if (mapping[i][0] === xValue) {
        mapping[i][1] = mapping[i][1] + yValue;
      }
    }
  }
});
#graph {
  margin: 0 auto;
  text-align: center;
  width: 600px;
  height: 400px;
}

.data-point-value {
  position: absolute;
  white-space: nowrap;
  font-size: 11px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.js"></script>
<script src="https://rawgit.com/flot/flot/master/jquery.flot.stack.js"></script>
<div id="graph"></div>