Chart.js 堆叠条形图 - 按值对条形中的值进行排序
Chart.js stacked bar chart - sorting values in bar by value
我尝试使用 Chart.js 框架(2.7 版)实现堆叠条形图,但遇到了以下问题:每个条形中的单个数据元素的绘制顺序与 JSON 结构中提供的顺序相同(这是绝对合乎逻辑且可以理解的)。我想让它们排序:最大的元素在栏的底部,最小的在顶部。
我想这可以使用一些插件自定义黑魔法来完成,但我想不通。
如有任何帮助,我们将不胜感激。
示例:
var chart = new Chart(document.getElementById('canvas'), {
type : 'bar',
data : {
labels : ["2018-07-06", "2018-07-07", "2018-07-08", "2018-07-09", "2018-07-10"],
datasets : [
{
label: "Dataset 1",
backgroundColor: "red",
data: [ {x: "2018-07-06", y: 1}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 3}]
},
{
label: "Dataset 2",
backgroundColor: "blue",
data: [ {x: "2018-07-06", y: 3}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 1}]
},
{
label: "Dataset 3",
backgroundColor: "green",
data: [ {x: "2018-07-06", y: 2}, {x: "2018-07-07", y: 1}, {x: "2018-07-08", y: 2}]
}
],
borderWidth : 1
},
options : {
responsive : true,
maintainAspectRatio : false,
title : {
display : true,
text : 'Test'
},
scales : {
xAxes : [ {
stacked : true,
time : {
unit : 'day'
}
} ],
yAxes : [ {
stacked : true,
ticks : {
beginAtZero : true
}
} ]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="canvas" height="500" width="500"></canvas>
在这个例子中,我想在每列中反转颜色顺序:
第一个是蓝绿红,
其次是红蓝绿或蓝红绿,
第三个是红绿蓝。
可能它可以以某种方式更有效和/或更漂亮地完成,但我必须自己解决它。
/*
* chart.js do not support stacked bar charts, which are sorted by value,
* therefore it's needed to perform this functionality with custom plugins
*/
Chart.plugins.register({
/*
* Sorts data by value and calculates values for bar stacks
*/
beforeDraw(chart) {
// create data container in chart instance
chart.sortedData = {};
// iterate over datasets
chart.data.datasets.forEach((dataset, datasetIndex) => {
// iterate over dataset records
dataset.data.forEach((data, index) => {
// create data container for bar stack data
if(!chart.sortedData[index]) {
chart.sortedData[index] = {
data: []
};
}
// save data
chart.sortedData[index].data[datasetIndex] = {
datasetIndex: datasetIndex,
hidden: chart.getDatasetMeta(datasetIndex).hidden ? true : false,
color: dataset.backgroundColor,
value: dataset.data[index].y,
y: chart.getDatasetMeta(datasetIndex).data[index]._model.y,
base: chart.getDatasetMeta(datasetIndex).data[index]._model.base,
};
});
});
var chartTop = chart.scales['y-axis-0'].top;
var max = chart.scales['y-axis-0'].max;
var h = chart.scales['y-axis-0'].height / max;
// iterate over datasets
chart.data.datasets.forEach((dataset, datasetIndex) => {
// iterate over dataset records
dataset.data.forEach((data, index) => {
// sort data in bar stack by value
chart.sortedData[index].data = Object.keys(chart.sortedData[index].data)
.map(k => chart.sortedData[index].data[k])
.sort((a, b) => a.value - b.value);
// iterate over stack records
chart.sortedData[index].data.forEach((d, i) => {
// calculate base value
d.base = chartTop + (max - Object.keys(chart.sortedData[index].data)
.map(k => chart.sortedData[index].data[k].value)
.reduce((a, b) => a + b, 0)) * h
+ Object.keys(chart.sortedData[index].data)
.map(k => chart.sortedData[index].data[k])
.filter(d => d.hidden)
.reduce((a, b) => a + b.value, 0) * h;
// increase base value with values of previous records
for (var j = 0; j < i; j++) {
d.base += chart.sortedData[index].data[j].hidden
? 0
: h * chart.sortedData[index].data[j].value;
}
// set y value
d.y = d.base + h * d.value;
});
});
});
},
/*
* Sets values for base and y
*/
beforeDatasetDraw(chart, args) {
chart.getDatasetMeta(args.index).data.forEach((data, index) => {
var el = chart.sortedData[index].data.filter(e => e.datasetIndex === args.index)[0];
data._model.y = el.y;
data._model.base = el.base;
});
}
});
var chart = new Chart(document.getElementById('canvas'), {
type : 'bar',
data : {
labels : ["2018-07-06", "2018-07-07", "2018-07-08", "2018-07-09", "2018-07-10"],
datasets : [
{
label: "Dataset 1",
backgroundColor: "red",
data: [ {x: "2018-07-06", y: 1}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 3}]
},
{
label: "Dataset 2",
backgroundColor: "blue",
data: [ {x: "2018-07-06", y: 3}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 1}]
},
{
label: "Dataset 3",
backgroundColor: "green",
data: [ {x: "2018-07-06", y: 2}, {x: "2018-07-07", y: 1}, {x: "2018-07-08", y: 2}]
}
],
borderWidth : 1
},
options : {
responsive : true,
maintainAspectRatio : false,
title : {
display : true,
text : 'Test'
},
scales : {
xAxes : [ {
stacked : true,
time : {
unit : 'day'
}
} ],
yAxes : [ {
stacked : true,
ticks : {
beginAtZero : true
}
} ]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="canvas" height="500" width="500"></canvas>
我尝试使用 Chart.js 框架(2.7 版)实现堆叠条形图,但遇到了以下问题:每个条形中的单个数据元素的绘制顺序与 JSON 结构中提供的顺序相同(这是绝对合乎逻辑且可以理解的)。我想让它们排序:最大的元素在栏的底部,最小的在顶部。
我想这可以使用一些插件自定义黑魔法来完成,但我想不通。
如有任何帮助,我们将不胜感激。
示例:
var chart = new Chart(document.getElementById('canvas'), {
type : 'bar',
data : {
labels : ["2018-07-06", "2018-07-07", "2018-07-08", "2018-07-09", "2018-07-10"],
datasets : [
{
label: "Dataset 1",
backgroundColor: "red",
data: [ {x: "2018-07-06", y: 1}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 3}]
},
{
label: "Dataset 2",
backgroundColor: "blue",
data: [ {x: "2018-07-06", y: 3}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 1}]
},
{
label: "Dataset 3",
backgroundColor: "green",
data: [ {x: "2018-07-06", y: 2}, {x: "2018-07-07", y: 1}, {x: "2018-07-08", y: 2}]
}
],
borderWidth : 1
},
options : {
responsive : true,
maintainAspectRatio : false,
title : {
display : true,
text : 'Test'
},
scales : {
xAxes : [ {
stacked : true,
time : {
unit : 'day'
}
} ],
yAxes : [ {
stacked : true,
ticks : {
beginAtZero : true
}
} ]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="canvas" height="500" width="500"></canvas>
在这个例子中,我想在每列中反转颜色顺序:
第一个是蓝绿红,
其次是红蓝绿或蓝红绿,
第三个是红绿蓝。
可能它可以以某种方式更有效和/或更漂亮地完成,但我必须自己解决它。
/*
* chart.js do not support stacked bar charts, which are sorted by value,
* therefore it's needed to perform this functionality with custom plugins
*/
Chart.plugins.register({
/*
* Sorts data by value and calculates values for bar stacks
*/
beforeDraw(chart) {
// create data container in chart instance
chart.sortedData = {};
// iterate over datasets
chart.data.datasets.forEach((dataset, datasetIndex) => {
// iterate over dataset records
dataset.data.forEach((data, index) => {
// create data container for bar stack data
if(!chart.sortedData[index]) {
chart.sortedData[index] = {
data: []
};
}
// save data
chart.sortedData[index].data[datasetIndex] = {
datasetIndex: datasetIndex,
hidden: chart.getDatasetMeta(datasetIndex).hidden ? true : false,
color: dataset.backgroundColor,
value: dataset.data[index].y,
y: chart.getDatasetMeta(datasetIndex).data[index]._model.y,
base: chart.getDatasetMeta(datasetIndex).data[index]._model.base,
};
});
});
var chartTop = chart.scales['y-axis-0'].top;
var max = chart.scales['y-axis-0'].max;
var h = chart.scales['y-axis-0'].height / max;
// iterate over datasets
chart.data.datasets.forEach((dataset, datasetIndex) => {
// iterate over dataset records
dataset.data.forEach((data, index) => {
// sort data in bar stack by value
chart.sortedData[index].data = Object.keys(chart.sortedData[index].data)
.map(k => chart.sortedData[index].data[k])
.sort((a, b) => a.value - b.value);
// iterate over stack records
chart.sortedData[index].data.forEach((d, i) => {
// calculate base value
d.base = chartTop + (max - Object.keys(chart.sortedData[index].data)
.map(k => chart.sortedData[index].data[k].value)
.reduce((a, b) => a + b, 0)) * h
+ Object.keys(chart.sortedData[index].data)
.map(k => chart.sortedData[index].data[k])
.filter(d => d.hidden)
.reduce((a, b) => a + b.value, 0) * h;
// increase base value with values of previous records
for (var j = 0; j < i; j++) {
d.base += chart.sortedData[index].data[j].hidden
? 0
: h * chart.sortedData[index].data[j].value;
}
// set y value
d.y = d.base + h * d.value;
});
});
});
},
/*
* Sets values for base and y
*/
beforeDatasetDraw(chart, args) {
chart.getDatasetMeta(args.index).data.forEach((data, index) => {
var el = chart.sortedData[index].data.filter(e => e.datasetIndex === args.index)[0];
data._model.y = el.y;
data._model.base = el.base;
});
}
});
var chart = new Chart(document.getElementById('canvas'), {
type : 'bar',
data : {
labels : ["2018-07-06", "2018-07-07", "2018-07-08", "2018-07-09", "2018-07-10"],
datasets : [
{
label: "Dataset 1",
backgroundColor: "red",
data: [ {x: "2018-07-06", y: 1}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 3}]
},
{
label: "Dataset 2",
backgroundColor: "blue",
data: [ {x: "2018-07-06", y: 3}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 1}]
},
{
label: "Dataset 3",
backgroundColor: "green",
data: [ {x: "2018-07-06", y: 2}, {x: "2018-07-07", y: 1}, {x: "2018-07-08", y: 2}]
}
],
borderWidth : 1
},
options : {
responsive : true,
maintainAspectRatio : false,
title : {
display : true,
text : 'Test'
},
scales : {
xAxes : [ {
stacked : true,
time : {
unit : 'day'
}
} ],
yAxes : [ {
stacked : true,
ticks : {
beginAtZero : true
}
} ]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="canvas" height="500" width="500"></canvas>