javascriptd3.jsc3.js

C3.js: Assigning a chart height independently of the legend height


(sorry for double posting, but the issue on github was not answered after one week: https://github.com/c3js/c3/issues/2254)

I'm using C3 JS and I have several stacked bar charts showing on the same page. Each one has a different legend, and some legends are quite bigger than others. Since I can only define the height for the whole image, the y-axis of charts with a bigger legend become smaller.

The figure bellow illustrates the issue:

enter image description here

My target is that the y-axis have the same height on both charts. It does not matter the overall chart height (chart+legend).

Is there any possibility of assigning a fixed height to the chart without including the legend height in this size? Maybe should I use D3 directly?

Thanks for the attention and for this awesome library.

best, alan


Solution

  • I think the only way is to use a custom legend as in the c3js examples (see http://c3js.org/samples/legend_custom.html).

    So you have to disable legend:

    legend: {
      show: false
    }
    

    and create your own legend (for example using d3.js):

    function createLegend(chart, container) {
      var dataKeys = Object.keys(chart.internal.data.xs);
      var names = chart.data.names();
    	console.log("createLegend", dataKeys, names, chart);
      
      $(container).css("max-height", "none");
      $(container).css("width", chart.internal.currentWidth);
      
      d3.select(container).insert('div', '.chart').attr('class', 'legend').selectAll('div')
        .data(dataKeys)
        .enter().append('div')
        .attr('class', 'legend-item')
        .attr('data-id', function(id) {
          return id;
        })
        .each(function(id) {
          d3.select(this)
          .append('span').style('background-color', chart.color(id)).attr('class', 'legend-box');
          var text = names[id];
          if (!text) text = id;
          d3.select(this)
          .append('span').html(text).attr('class', 'legend-text');
        })
        .on('mouseover', function(id) {
          chart.focus(id);
        })
        .on('mouseout', function(id) {
          chart.revert();
        })
        .on('click', function(id) {
          $(this).toggleClass("c3-legend-item-hidden")
          chart.toggle(id);
          $(container).css("max-height", "none");
        });
    }
    
    var chart1 = c3.generate({
      bindto: '#chart1',
      size: {
        height: 250,
        width: 400
      },
      data: {
        x: 'x',
        columns: [
          ['x', 'one', 'two'],
          ['data1', 30, 200],
          ['data2', 130, 100],
          ['data3', 30, 200],
          ['data4', 130, 100],
          ['data5', 30, 1200],
          ['data6', 130, 50],
          ['data7', 30, 20],
          ['data8', 130, 100],
          ['data9', 230, 10]
        ],
        type: 'bar',
        names: {
          data1: 'Long Name 1',
          data2: 'Long Name 2',
          data3: 'Long Name 3',
          data4: 'Long Name 4',
          data5: 'Long Name 5',
          data6: 'Long Name 6',
          data7: 'Long Name 7',
          data8: 'Long Name 8',
          data9: 'Long Name 9',
        },
        groups: [
          ['data1', 'data2', 'data3', 'data4', 'data5', 'data6', 'data7', 'data8', 'data9']
        ]
      },
      axis: {
        x: {
          type: 'category' // this needed to load string x value
        }
      },
      legend: {
        show: false
      },
      onrendered: function() {
      	$('#chart1').css("max-height", "none");
      }
    });
    
    createLegend(chart1, '#chart1');
    /* only to highlight chart container */
    .chart {
      background: lightgray;
      border: solid 1px red;
    }
    
    .legend-box {
      display: inline-block;
      margin-left: 7px;
      margin-right: 7px;
      padding: 5px;
    }
    
    .legend-item {
      cursor: pointer;
      display: inline-block;
    }
    
    .legend-text {
      font-family: "Helvetica";
      font-size:12px;
      white-space: nowrap;
    }
    
    .legend {
      width: 100%;
      display: inline-block;
      text-align: center;
      overflow: hidden;
    }
    <script src="https://code.jquery.com/jquery-3.1.0.min.js" type="text/javascript"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.18/c3.css" rel="stylesheet" type="text/css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js" type="text/javascript"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.18/c3.min.js" type="text/javascript"></script>
    
    <div id="chart1" class="chart"></div>

    Here is a jsfiddle showing a complete example: https://jsfiddle.net/beaver71/zp7km2L1/