stacked bar chart with overlapping bars C3js

2019-09-07 03:15发布

问题:

Good day.

I'm trying to create a bar chart using C3.js that looks like the following:

I've tried stacked bar chart, but the problem is that I can't make each bar with different width, and also I can't make them overlap (be in top of each other).

Any help in getting to do it like the image above?

Thanks

UPDATE 1:

after trying couple of ideas, I ended up with this:

var chart = c3.generate({
data: {
    columns: [
      ['result1', null],
      ['result2', null],
      ['data1', -30],
      ['data2', -130],
      ['data3', -230],
      ['data4', -130],
      ['data5', -30],
      ['empty',''],
      ['data11', -30],
      ['data22', -130],
      ['data33', -230],
      ['data44', -130],
      ['data55', -30]
    ],

    type: 'bar',

    colors: {
      result1: '#c3c8d4',
      data1: '#c3c8d4',
      data2: '#c3c8d4',
      data3: '#c3c8d4',
      data4: '#c3c8d4',
      data5: '#c3c8d4',

      result2: '#3c9fbf',
      data11: '#3c9fbf',
      data22: '#3c9fbf',
      data33: '#3c9fbf',
      data44: '#3c9fbf',
      data55: '#3c9fbf',
    },
},
axis: {
    y: {
      tick: {
        format: function(d) {
          return (d >= 0) ? d : d * -1;
        }
      },
    }
},
bar: {
    width: {
      ratio: 0.1
    }
},
tooltip: {
    format: {
      value: function(value, ratio, id) {
        return;
      }
    }
}
});


d3.select('.c3-legend-item-result1').on('mouseover', function(id) {
    var tmparr = [];
    tmparr.push(id);
    for (var i = 0; i < 5; i++)
        tmparr.push('data' + (i + 1));
    chart.focus(tmparr);
  })
  .on('mouseout', function(id) {
    chart.revert();
  })
  .on('click', function(id) {
    var tmparr = [];
    for (var i = 0; i < 5; i++)
        tmparr.push('data' + (i + 1));
    chart.toggle(tmparr);
  });

d3.select('.c3-legend-item-result2').on('mouseover', function(id) {
    var tmparr = [];
    tmparr.push(id);
    for (var i = 0; i < 5; i++)
        tmparr.push('data' + (i + 1) + (i + 1));
    chart.focus(tmparr);
  })
  .on('mouseout', function(id) {
    chart.revert();
  })
  .on('click', function(id) {
    var tmparr = [];
    for (var i = 0; i < 5; i++)
        tmparr.push('data' + (i + 1) + (i + 1));
    chart.toggle(tmparr);
  });

JSFiddle: http://jsfiddle.net/h2ndL9cb/

but I think it's too much code, any other ideas?

Thanks

回答1:

You could define your chart data as such (see below). After you have your data, you can transform and hide the legend items.

The transformed data can be merged, using a library such as lodash, with the c3js object.

Of course, this does not solve your issue entirely, but this should give you an idea of how to transform your data to get the desired result.

var chartData = {
  data : {
    result1: [-30, -130, -230, -130, -30],
    result2: [-30, -130, -230, -130, -30]
  },
  colors: {
    result1: '#c3c8d4',
    result2: '#3c9fbf'
  },
};

function transformData(data) {
  var data_columns = [];
  var data_colors = {};
  var legend_hide = ['empty'];
  var keys = Object.keys(data.data);

  for (var k = 0; k < keys.length; k++) {
    var key = keys[k];
    var values = data.data[key];

    data_columns.splice(k, 0, [key, null]);
    data_colors[key] = data.colors[key];

    for (var i = 0; i < values.length; i++) {
      var value_key = key + '_' + k + '_' + i

      data_columns.push([value_key, values[i]]);
      data_colors[value_key] = data.colors[key];
      legend_hide.push(value_key);
    }
    if (k < keys.length - 1) {
      data_columns.push(['empty', '']);
    }
  }

  return {
    data : {
      columns : data_columns,
      colors : data_colors
    },
    legend : {
      hide : legend_hide
    }
  };
}

var chart = c3.generate(_.merge({
  data : {
    type : 'bar'
  },
  axis: {
    y: {
      tick: {
        format: function(d) {
          return (d >= 0) ? d : d * -1;
        }
      },
    }
  },
  bar: {
    width: {
      ratio: 0.1
    }
  },
  tooltip: {
    format: {
      value: function(value, ratio, id) {
        return;
      }
    }
  }
}, transformData(chartData))); // Transform and merge data...
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css">

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.10/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>

<div id="chart"></div>