混合图表计算两个柱之间的差异 - ChartJS
Mixed Chart calculating difference between two bars - ChartJS
我已经使用 Chart.JS 一个多星期了,我遇到了一些问题,但现在我真的卡住了。
我需要创建类似的东西,有 1 个产品(蓝色)值,橙色的是下个月的估计值。所以我需要做的基本上是 (((a — b) * 100) / a (or b I can't really remember))
并且这是一个标签而不是实际数据,结果将是某个百分比,将用作一个产品顶部的一行。
到目前为止,我只得到了这段代码,但它并没有像我需要的那样工作。
{
type: "line",
label: monthsLabels?.mesBaseLabel,
data: [
productsValues?.receitaLiquidaBase[0],
productsValues?.receitaLiquidaOrcado[0],
],
fill: false,
},
{
type: "line",
label: monthsLabels?.mesOrcadoLabel,
data: [
productsValues?.receitaLiquidaBase[0],
productsValues?.receitaLiquidaOrcado[0],
],
// data: productsValues?.receitaLiquidaOrcado,
fill: false,
},
{
type: "bar",
label: monthsLabels?.mesBaseLabel,
data: productsValues?.receitaLiquidaBase,
// [
// productsValues?.receitaLiquidaBase[0],
// productsValues?.receitaLiquidaBase[1],
// ],
backgroundColor: ["rgba(42,62,176, 1)"],
borderWidth: 4,
datalabels: {
// anchor: "end",
// align: "top",
font: {
size: 10,
},
rotation: -90,
color: "white",
formatter: (value, context) => {
// console.log(value);
if (value !== 0) {
return value?.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, "$&,");
} else {
return 0;
}
},
},
},
{
type: "bar",
label: monthsLabels?.mesOrcadoLabel,
data: productsValues?.receitaLiquidaOrcado,
backgroundColor: "orange",
borderWidth: 4,
datalabels: {
// anchor: "end",
// align: "top",
font: {
size: 10,
},
rotation: -90,
color: "black",
formatter: (value, context) => {
// console.log(value);
if (value !== 0) {
return value?.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, "$&,");
} else {
return 0;
}
},
},
},
data
和 label
上的对象是来自某些获取的数字数组。
您最好为此使用自定义内联插件:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'red'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
backgroundColor: 'blue'
}
]
},
options: {
plugins: {
customValue: {
offset: 5,
dash: [5, 15]
}
}
},
plugins: [{
id: 'customValue',
afterDraw: (chart, args, opts) => {
const {
ctx,
data: {
datasets
},
_metasets
} = chart;
datasets[1].data.forEach((dp, i) => {
let increasePercent = dp * 100 / datasets[0].data[i] >= 100 ? Math.round((dp * 100 / datasets[0].data[i] - 100) * 100) / 100 : Math.round((100 - dp * 100 / datasets[0].data[i]) * 100) / 100 * -1;
let barValue = `${increasePercent}%`;
const lineHeight = ctx.measureText('M').width;
const offset = opts.offset || 0;
const dash = opts.dash || [];
ctx.textAlign = 'center';
ctx.fillText(barValue, _metasets[1].data[i].x, (_metasets[1].data[i].y - lineHeight * 1.5), _metasets[1].data[i].width);
if (_metasets[0].data[i].y >= _metasets[1].data[i].y) {
ctx.beginPath();
ctx.setLineDash(dash);
ctx.moveTo(_metasets[0].data[i].x, _metasets[0].data[i].y);
ctx.lineTo(_metasets[0].data[i].x, _metasets[1].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[1].data[i].y - offset);
ctx.stroke();
} else {
ctx.beginPath();
ctx.setLineDash(dash);
ctx.moveTo(_metasets[0].data[i].x, _metasets[0].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[0].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[1].data[i].y - offset - lineHeight * 2);
ctx.stroke();
}
});
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.1/chart.js"></script>
</body>
我已经使用 Chart.JS 一个多星期了,我遇到了一些问题,但现在我真的卡住了。
我需要创建类似的东西,有 1 个产品(蓝色)值,橙色的是下个月的估计值。所以我需要做的基本上是 (((a — b) * 100) / a (or b I can't really remember))
并且这是一个标签而不是实际数据,结果将是某个百分比,将用作一个产品顶部的一行。
到目前为止,我只得到了这段代码,但它并没有像我需要的那样工作。
{
type: "line",
label: monthsLabels?.mesBaseLabel,
data: [
productsValues?.receitaLiquidaBase[0],
productsValues?.receitaLiquidaOrcado[0],
],
fill: false,
},
{
type: "line",
label: monthsLabels?.mesOrcadoLabel,
data: [
productsValues?.receitaLiquidaBase[0],
productsValues?.receitaLiquidaOrcado[0],
],
// data: productsValues?.receitaLiquidaOrcado,
fill: false,
},
{
type: "bar",
label: monthsLabels?.mesBaseLabel,
data: productsValues?.receitaLiquidaBase,
// [
// productsValues?.receitaLiquidaBase[0],
// productsValues?.receitaLiquidaBase[1],
// ],
backgroundColor: ["rgba(42,62,176, 1)"],
borderWidth: 4,
datalabels: {
// anchor: "end",
// align: "top",
font: {
size: 10,
},
rotation: -90,
color: "white",
formatter: (value, context) => {
// console.log(value);
if (value !== 0) {
return value?.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, "$&,");
} else {
return 0;
}
},
},
},
{
type: "bar",
label: monthsLabels?.mesOrcadoLabel,
data: productsValues?.receitaLiquidaOrcado,
backgroundColor: "orange",
borderWidth: 4,
datalabels: {
// anchor: "end",
// align: "top",
font: {
size: 10,
},
rotation: -90,
color: "black",
formatter: (value, context) => {
// console.log(value);
if (value !== 0) {
return value?.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, "$&,");
} else {
return 0;
}
},
},
},
data
和 label
上的对象是来自某些获取的数字数组。
您最好为此使用自定义内联插件:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'red'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
backgroundColor: 'blue'
}
]
},
options: {
plugins: {
customValue: {
offset: 5,
dash: [5, 15]
}
}
},
plugins: [{
id: 'customValue',
afterDraw: (chart, args, opts) => {
const {
ctx,
data: {
datasets
},
_metasets
} = chart;
datasets[1].data.forEach((dp, i) => {
let increasePercent = dp * 100 / datasets[0].data[i] >= 100 ? Math.round((dp * 100 / datasets[0].data[i] - 100) * 100) / 100 : Math.round((100 - dp * 100 / datasets[0].data[i]) * 100) / 100 * -1;
let barValue = `${increasePercent}%`;
const lineHeight = ctx.measureText('M').width;
const offset = opts.offset || 0;
const dash = opts.dash || [];
ctx.textAlign = 'center';
ctx.fillText(barValue, _metasets[1].data[i].x, (_metasets[1].data[i].y - lineHeight * 1.5), _metasets[1].data[i].width);
if (_metasets[0].data[i].y >= _metasets[1].data[i].y) {
ctx.beginPath();
ctx.setLineDash(dash);
ctx.moveTo(_metasets[0].data[i].x, _metasets[0].data[i].y);
ctx.lineTo(_metasets[0].data[i].x, _metasets[1].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[1].data[i].y - offset);
ctx.stroke();
} else {
ctx.beginPath();
ctx.setLineDash(dash);
ctx.moveTo(_metasets[0].data[i].x, _metasets[0].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[0].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[1].data[i].y - offset - lineHeight * 2);
ctx.stroke();
}
});
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.1/chart.js"></script>
</body>