简体   繁体   中英

Chart.js stacked and grouped horizontalBar chart

I've been trying to display somewhat complex data on my webpage and chose chart.js to do so. Therefor I need to group multiple stacked bars horizontally.

I already found this fiddle for "normal" bars but couldn't quite change it to work with horizontalBar yet.

Stackoverflow question: Chart.js stacked and grouped bar chart

The original Fiddle ( http://jsfiddle.net/2xjwoLq0/ ) has

Chart.defaults.groupableBar = Chart.helpers.clone(Chart.defaults.bar);

And I just replaced the .bar everywhere in the code with .horizontalBar (well knowing that this won't make the cut).

Chart.defaults.groupableBar = Chart.helpers.clone(Chart.defaults.horizontalBar);

Since that didn't quite work, I tried adding the second stacked modifier as suggested for horizontal bars here: Horizontal stacked bar chart with chart.js and flipped the functions for X and Y calculation (calculateBarY/calculateBarX)

Which quite work either because the stacks won't get merged onto each other correctly.

http://jsfiddle.net/2xjwoLq0/3/

I would appreciate if anyone could help me out on this one.

Looking for something similar, I took a look on example you gave, and decide to write something.

Rather than trying to fix the code or reusing the 'groupableBar', I get Chart.js code from Chart.controllers.horizontalBar and rewrite some part in functions calculateBarY , calculateBarHeight . Just reused the getBarCount function from your example.

 Chart.defaults.groupableHBar = Chart.helpers.clone(Chart.defaults.horizontalBar); Chart.controllers.groupableHBar = Chart.controllers.horizontalBar.extend({ calculateBarY: function(index, datasetIndex, ruler) { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); var barIndex = me.getBarIndex(datasetIndex); var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo); topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0; var stackIndex = this.getMeta().stackIndex; if (yScale.options.stacked) { if(ruler.datasetCount>1) { var spBar=ruler.categorySpacing/ruler.datasetCount; var h=me.calculateBarHeight(ruler); return topTick + (((ruler.categoryHeight - h) / 2)+ruler.categorySpacing-spBar/2)+(h+spBar)*stackIndex; } return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing; } return topTick + (ruler.barHeight / 2) + ruler.categorySpacing + (ruler.barHeight * barIndex) + (ruler.barSpacing / 2) + (ruler.barSpacing * barIndex); }, calculateBarHeight: function(ruler) { var returned=0; var me = this; var yScale = me.getScaleForId(me.getMeta().yAxisID); if (yScale.options.barThickness) { returned = yScale.options.barThickness; } else { returned= yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight; } if(ruler.datasetCount>1) { returned=returned/ruler.datasetCount; } return returned; }, getBarCount: function () { var stacks = []; // put the stack index in the dataset meta Chart.helpers.each(this.chart.data.datasets, function (dataset, datasetIndex) { var meta = this.chart.getDatasetMeta(datasetIndex); if (meta.bar && this.chart.isDatasetVisible(datasetIndex)) { var stackIndex = stacks.indexOf(dataset.stack); if (stackIndex === -1) { stackIndex = stacks.length; stacks.push(dataset.stack); } meta.stackIndex = stackIndex; } }, this); this.getMeta().stacks = stacks; return stacks.length; } }); var data = { labels: ["January", "February", "March"], datasets: [ { label: "Dogs", backgroundColor: "rgba(255,0,0,0.2)", data: [20, 10, 25], stack: 1, xAxisID: 'x-axis-0', yAxisID: 'y-axis-0' }, { label: "Cats", backgroundColor: "rgba(255,255,0,0.2)", data: [70, 85, 65], stack: 1, xAxisID: 'x-axis-0', yAxisID: 'y-axis-0' }, { label: "Birds", backgroundColor: "rgba(0,255,255,0.2)", data: [10, 5, 10], stack: 1, xAxisID: 'x-axis-0', yAxisID: 'y-axis-0' }, { label: ":-)", backgroundColor: "rgba(0,255,0,0.2)", data: [20, 10, 30], stack: 2, xAxisID: 'x-axis-1', yAxisID: 'y-axis-0' }, { label: ":-|", backgroundColor: "rgba(0,0,255,0.2)", data: [40, 50, 20], stack: 2, xAxisID: 'x-axis-1', yAxisID: 'y-axis-0' }, { label: ":-(", backgroundColor: "rgba(0,0,0,0.2)", data: [60, 20, 20], stack: 2, xAxisID: 'x-axis-1', yAxisID: 'y-axis-0' }, ] }; var ctx = document.getElementById("myChart").getContext("2d"); new Chart(ctx, { type: 'groupableHBar', data: data, options: { scales: { yAxes: [{ stacked: true, type: 'category', id: 'y-axis-0' }], xAxes: [{ stacked: true, type: 'linear', ticks: { beginAtZero:true }, gridLines: { display: false, drawTicks: true, }, id: 'x-axis-0' }, { stacked: true, position: 'top', type: 'linear', ticks: { beginAtZero:true }, id: 'x-axis-1', gridLines: { display: true, drawTicks: true, }, display: false }] } } }); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script> <canvas id="myChart"></canvas> 

Also put example on jsfiddle here: https://jsfiddle.net/b7gnron7/4/

Code is not strongly tested, you might found some bugs especially if you try to display only one stacked group (use horizontalBar instead in this case).

Your post is a little bit old... not sure that you still need a solution, but it could be useful for others ^_^

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM