Updated answer:
I don't know anything about typescript or angular. That's why I wrote my program in plain Javascript.
Took me quite some time, updating the legend is not that easy in chart.js
...
I know it's quite complexe and may not be an optimal solution. Please feel free to ask me about the code or tell me possible improvements.
Complete code with live-preview: https://jsbin.com/detiqucime/6/edit?js,output
Complete code:
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,
});