👍:1
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,
});
- Line chart: align x axis (timestamps) for multiple data sets
- Make chartJS labels clickable and get label details
👍:0
Please find the updated code snippet of the component below. Updated the answer accordingly in the stackblitz here
import { Component, OnInit } from '@angular/core';
import { ChartDataSets, ChartOptions } from 'chartjs';
import { Color, Label } from 'ng2-charts';
import 'chartjs-plugin-zoom';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
lineChartData: ChartDataSets[] = [];
lineChartLabels: Label[] = [];
lineChartOptions: ChartOptions = {
legend: {
reverse: true
},
responsive: true,
scales: {
yAxes: [{}],
xAxes:[{}]
},
pan: {
enabled: true,
mode: 'x',
},
zoom: {
enabled: true,
mode: 'x',
speed: 1.5
},
};
lineChartColors: Color[] = [];
lineChartLegend = true;
lineChartPlugins = [];
lineChartType = 'line';
ngOnInit() {
this.lineChartData = [
{ data: [65, 59, 80, 81, 56, 55, 40], label: 'First'},
{ data: [28, 48, 40, 19, 110, 27, 90], label: 'Second'},
{ data: [22, 44, 23, 69, 82, 47, 50], label: 'Third'}
];
this.lineChartLabels = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
}
}
👍:0
What you could do is to find maximum y value of your graph and then calculate each other value as a percentage of this found maximum one.
For example like this:
let sumOfData = [];
this.lineChartData.forEach((elem) => elem.data.forEach((value, index) => {
if(!sumOfData[index]) {
sumOfData[index] = value;
} else {
sumOfData[index] += value;
}
}));
this.maxChartValue = Math.max(...sumOfData);
Working example on stackblitz
Of course any other arbitrary number to calculate percents for the graph may be used. If it is greater, than a maximum one, then it will look more similar to the example from anychart.com that you linked to.
In any case you need some number in order to determine percent of it.
Just some values in array won’t do.