javascript - 使用 Charts.js 和 Angular 8 在 y 轴上带有百分比值的堆积面积图
问题描述
我正在使用 Angular 8 和 ng2-charts 包来创建堆叠面积图。我想创建一个这样的图表。我尝试使用最小值和最大值来创建从 0% 到 100% 的 Y 轴,但它对不同的数据不正确(如果每个标签的数据总和大于 100,则图表超出范围)。我也想将它们堆叠在一起显示,但不知道如何实现这一点。
我还将我的代码附在我试图写这个的 stackblitz 上。
解决方案
更新的答案:
我对打字稿或角度一无所知。这就是为什么我用纯 Javascript 编写程序的原因。
花了我一些时间,更新图例并不容易chart.js
......
我知道这很复杂,可能不是最佳解决方案。请随时向我询问代码或告诉我可能的改进。
带有实时预览的完整代码:https ://jsbin.com/detiqucime/6/edit?js,output
完整代码:
let canvas = document.getElementById("chart");
let ctx = canvas.getContext("2d");
const dataLabels = [
'First',
'Second',
'Third'
]
const colors = {
'First': '#bad96b',
'Second': '#8ad0f9',
'Third': '#ffda78'
}
let data = [
[65, 59, 80, 81, 56, 55, 40],
[28, 48, 40, 19, 86, 27, 90],
[22, 44, 23, 69, 82, 47, 50]
]
// hiddenArray (array with 'true' or 'null' (hidden or not) to know which datasets are hidden, those get not calculated)
let hiddenArray = []
// Initiate hiddenArray: nothing hidden at start
for (let i = 0; i < data.length; i++) {
hiddenArray.push(null)
}
// New data array we use for the chart
let percentageData = []
calcPercentages(hiddenArray)
function calcPercentages(hiddenArray) {
percentageData = []
// Fill percentageData with empty arrays for same structure like data
for (let i = 0; i < data.length; i++) {
percentageData.push([])
}
for (let innerKey in data[0]) {
// Get the sum of each data
let sum = 0
for (let outerKey in data) {
if (hiddenArray[outerKey]) {
continue;
}
sum = sum + data[outerKey][innerKey]
}
// Calculate the new percentageData
for (let outerKey in data) {
if (hiddenArray[outerKey]) {
percentageData[outerKey][innerKey] = 0
} else {
percentageData[outerKey][innerKey] = (data[outerKey][innerKey]/sum)*100
}
}
}
}
let chartData = {
labels: ['2006', '2007', '2008', '2009', '2010', '2011', '2012'],
datasets: []
}
for (let i = 0; i < data.length; i++) {
let newDataset = {}
newDataset.label = dataLabels[i]
newDataset.backgroundColor = colors[dataLabels[i]]
newDataset.data = percentageData[i]
chartData.datasets.push(newDataset)
}
let options = {
responsive: true,
legend: {
//reverse: true,
onClick: function(e, legendItem) {
let index = legendItem.datasetIndex;
let ci = this.chart;
let meta = ci.getDatasetMeta(index);
// Change 'hidden'-property
meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
// Get hiddenArray
let hiddenArray = []
ci.data.datasets.forEach(function(e, i) {
let meta = ci.getDatasetMeta(i);
hiddenArray.push(meta.hidden)
});
// Update percentageData
calcPercentages(hiddenArray)
for (let i = 0; i < percentageData.length; i++) {
chartData.datasets[i].data = percentageData[i]
}
// Rerender the chart
ci.update();
}
},
scales: {
yAxes: [{
stacked: true,
ticks: {
min: 0,
max: 100,
callback: function(value) {
return value + '%'
}
}
}],
},
tooltips: {
callbacks: {
label: function(tooltipItem){
return data[tooltipItem.datasetIndex][tooltipItem.index]
}
}
}
}
let myChart = new Chart(ctx, {
type: 'line',
data: chartData,
options: options,
});
推荐阅读
- android - Android Studio 正在创建数十个 Java.exe 进程
- php - 无法安装 composer 需要 rtconner/laravel-tagging
- sql - 数据库:最有效的方式来组织具有嵌套的 has-many 关系的表
- linux - 如何通过在.sh文件中编码在命令行中打印文本文件的特定部分
- html - 具有相等高度位置的 SVG 路径将不会呈现
- c# - 如何在 C# 中使用 Socket 访问标准输入?
- django - 模态Django中的轮播
- python - 熊猫过滤一列中的多个同名条目以在另一列中提供所有其他相关项
- python - ValueError:无法将输入数组从形状 (32,256,256,3) 广播到形状 (32)
- android - 在 webview 中将卡凭证插入到加载的 html