Updating chart.js based on selections from dropdown - chart.js

I have a calculator that takes values from two drop downs and runs them through an array to calculate odds in which a certain condition will end. I got it working and I show the results in a text format. My boss now wants me to show the results in a bar graph. I chose to use chart.js and can get the chart working with entering actual data into the chart, but need to have the data be pulled from the results of the selected drop downs.
For some reason the calculator in jsfiddle its not working correctly but does on my site. Not sure why.
Below I have the script that I use for the chart.js
<script src="js/Chart.js"></script>
<script src="js/Chart.HorizontalBar.js"></script>
<script src="js/Chart.StackedBar.js"></script>
<script>
var barData = {
labels : ["50% Probability","80% Probability","95% Probability","99% Probability"],
datasets : [
{
label: "Birth No Condition",
fillColor : "#137fc1",
strokeColor : "#137fc1",
data : [0,5,10,15]
},
{
label: "Current Age",
fillColor : "#ff0000",
strokeColor : "#ff0000",
data : [0,5,10,15]
}
]
}
var myChart = document.getElementById("myChart").getContext("2d");
new Chart(myChart).StackedBar(barData, {
scaleShowLabels: true,
responsive: true
});
</script>
I need to load in the data from the dropdowns into each of the datasets data so instead of it saying
datasets : [
{
label: "Birth No Condition",
fillColor : "#137fc1",
strokeColor : "#137fc1",
data : [0,5,10,15]
},
It would say
datasets : [
{
label: "Birth No Condition",
fillColor : "#137fc1",
strokeColor : "#137fc1",
data : colicWeeks
},
datasets : [
{
label: "Birth No Condition",
fillColor : "#137fc1",
strokeColor : "#137fc1",
data : finalAge50
},
I guess what I am trying to say is how do you push data from the results of each dropdown selection run it through the array and spit the results out into the chart.js bar graph?

Just update the latter part of your script (you should be able to locate where you need to paste it in based on the 1st line below)
...
if (colicWeeks >= 0) {
document.getElementById('totalWeeks').style.display = 'block';
var barData = {
labels: ["50% Probability", "80% Probability", "95% Probability", "99% Probability"],
datasets: [
{
label: "Birth No Condition",
fillColor: "#137fc1",
strokeColor: "#137fc1",
data: [c50F, c80F, c95F, c99F]
},
{
label: "Current Age",
fillColor: "#ff0000",
strokeColor: "#ff0000",
data: [
finalAge50,
finalAge80,
finalAge95,
finalAge99
]
}
]
}
document.getElementById('myChart').style.display = 'block';
var myChart = document.getElementById("myChart").getContext("2d");
if (myBarChart !== undefined)
myBarChart.destroy();
myBarChart = new Chart(myChart).StackedBar(barData, {
scaleShowLabels: true,
responsive: true
});
} else {
document.getElementById('myChart').style.display = 'none';
document.getElementById('totalWeeks').style.display = 'none';
}
divobj.innerHTML = "Your child has currently had colic for " + colicWeeks + " weeks. <br /><br />Their is a " + p50 + "% chance that your childs colic will end in " + c50F + " weeks at " + finalAge50 + " weeks of age. <br /><br />Their is a " + p80 + "% chance that your childs colic will end in " + c80F + " weeks at " + finalAge80 + " weeks of age. <br /><br />Their is a " + p95 + "% chance that your childs colic will end in " + c95F + " weeks at " + finalAge95 + " weeks of age. <br /><br />Their is a " + p99 + "% chance that your childs colic will end in " + c99F + " weeks at " + finalAge99 + " weeks of age.";
}
var myBarChart;
function hideTotal() {
var divobj = document.getElementById('totalWeeks');
divobj.style.display = 'none';
document.getElementById('myChart').style.display = 'none';
}
then add a canvas element, probably after the results block
<div id="totalWeeks"></div>
<canvas id="myChart"></canvas>

Related

Chart.js: Thousand Separator and Tittle ind the Middle of the Doughnut

I have searched a lot and included a thousand separator in tooltips. But I would like to make it work everywhere there is text. Where I live we use "." to separate thousands and "," for decimal.
I didn't find a simple way to put the title in the middle of the doughnut.
This is what I have:
Chart.defaults.global.defaultFontColor = '#7792b1';
var ctx = document.getElementById('myChart').getContext('2d');
var dataset = [{
label: 'Volume de Operações',
data: [254000.87, 355000.57],
backgroundColor: ['#4bb8df', '#6290df']
}]
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['CALL', 'PUT'],
datasets: dataset
},
options: {
rotation: 1 * Math.PI,
circumference: 1 * Math.PI,
legend: {
display: false
},
cutoutPercentage: 60,
plugins: {
labels: [{
render: 'label',
arc: true,
fontStyle: 'bold',
position: 'outside'
}, {
render: 'percentage',
fontColor: '#ffffff',
precision: 1
}],
},
title: {
display: true,
fontSize: 15,
text: [
dataset.reduce((t, d) => t + d.data.reduce((a, b) => a + b), 0),
'Volume Total'
],
position: 'bottom'
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var dataLabel = data.labels[tooltipItem.index];
var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();
if (Chart.helpers.isArray(dataLabel)) {
dataLabel = dataLabel.slice();
dataLabel[0] += value;
} else {
dataLabel += value;
}
return dataLabel;
}
}
}
}
});
<canvas id="myChart" style="max-width: 450px"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<script src="https://cdn.jsdelivr.net/gh/emn178/chartjs-plugin-labels/src/chartjs-plugin-labels.js"></script>
In short:
Global thousand separator: (.)
Title in the middle of doughnut
Tooltip without label: Only value
To not show a title in your tooltip you will have to only return the value in your custom label calback. So your callback will become this:
label: function(tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();
}
There is no build in way to get the title in the middle of the circle, you will have to write a custom plugin for that.
To replace the thousand serperator in the percentage label, you will have to write a custom render. So instead render: 'percentage'. You will get something like this:
// custom render
{
render: function (args) {
// args will be something like:
// { label: 'Label', value: 123, percentage: 50, index: 0, dataset: {...} }
return '$' + args.value;
}
}
You will have to make the logic so the value gets transformed to a percentage still
EDIT custom tooltip so you dont see the color in front.
Chart.defaults.global.defaultFontColor = '#7792b1';
var ctx = document.getElementById('myChart').getContext('2d');
var dataset = [{
label: 'Volume de Operações',
data: [254000.87, 355000.57],
backgroundColor: ['#4bb8df', '#6290df']
}]
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['CALL', 'PUT'],
datasets: dataset
},
options: {
rotation: 1 * Math.PI,
circumference: 1 * Math.PI,
legend: {
display: false
},
cutoutPercentage: 60,
plugins: {
labels: [{
render: 'label',
arc: true,
fontStyle: 'bold',
position: 'outside'
}, {
render: 'percentage',
fontColor: '#ffffff',
precision: 1
}],
},
title: {
display: true,
fontSize: 15,
text: [
dataset.reduce((t, d) => t + d.data.reduce((a, b) => a + b), 0),
'Volume Total'
],
position: 'bottom'
},
tooltips: {
enabled: false,
custom: function(tooltipModel) {
// Tooltip Element
var tooltipEl = document.getElementById('chartjs-tooltip');
// Create element on first render
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.id = 'chartjs-tooltip';
tooltipEl.innerHTML = '<table></table>';
document.body.appendChild(tooltipEl);
}
// Hide if no tooltip
if (tooltipModel.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set caret Position
tooltipEl.classList.remove('above', 'below', 'no-transform');
if (tooltipModel.yAlign) {
tooltipEl.classList.add(tooltipModel.yAlign);
} else {
tooltipEl.classList.add('no-transform');
}
function getBody(bodyItem) {
return bodyItem.lines[0].split(': ')[1].replace('.', ',');
}
// Set Text
if (tooltipModel.body) {
var titleLines = tooltipModel.title || [];
var bodyLines = tooltipModel.body.map(getBody);
var innerHtml = '<thead>';
innerHtml += '</thead><tbody>';
bodyLines.forEach(function(body, i) {
var colors = tooltipModel.labelColors[i];
var style = 'background:' + colors.backgroundColor;
style += '; border-color:' + colors.borderColor;
style += '; border-width: 2px';
var span = '<span style="' + style + '"></span>';
innerHtml += '<tr><td>' + span + body + '</td></tr>';
});
innerHtml += '</tbody>';
var tableRoot = tooltipEl.querySelector('table');
tableRoot.innerHTML = innerHtml;
}
// `this` will be the overall tooltip
var position = this._chart.canvas.getBoundingClientRect();
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.position = 'absolute';
tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX + 'px';
tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY + 'px';
tooltipEl.style.fontFamily = tooltipModel._bodyFontFamily;
tooltipEl.style.fontSize = tooltipModel.bodyFontSize + 'px';
tooltipEl.style.fontStyle = tooltipModel._bodyFontStyle;
tooltipEl.style.padding = tooltipModel.yPadding + 'px ' + tooltipModel.xPadding + 'px';
tooltipEl.style.pointerEvents = 'none';
}
/*
callbacks: {
label: function(tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index].toLocaleString();
},
}*/
}
}
});
#chartjs-tooltip {
opacity: 1;
position: absolute;
background: rgba(0, 0, 0, .7);
color: white;
border-radius: 3px;
-webkit-transition: all .1s ease;
transition: all .1s ease;
pointer-events: none;
-webkit-transform: translate(-50%, 0);
transform: translate(-50%, 0);
}
<canvas id="myChart" style="max-width: 450px"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<script src="https://cdn.jsdelivr.net/gh/emn178/chartjs-plugin-labels/src/chartjs-plugin-labels.js"></script>
You might want to add some dots as thousand seperators in the tooltip but thats up to you. Best place to do it is in the getBody method.

Grid lines on google charts are not rendering as per data

Link to jsFiddle
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
format: "$ #,###"
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols =   [0];
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
The grid lines on a stacked bar type google charts are not rendering properly.
As per the data, $5 is recorded against Category1, but when it's rendered the bar is slightly over $5.
Can someone suggest a fix?
removing the option --> format: "$ #,###" -- reveals the problem
although the tick mark displays --> $ 5 -- the actual number used is 4.5
see following working snippet...
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
//format: "$ #,###"
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols =   [0];
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="provision_chart" style="width: 500px; height: 500px;"></div>
to correct, you can add a decimal place to the format --> $ #,##0.0
or provide your own vAxis.ticks in an array --> [0, 1, 2, 3, 4, 5, 6]
see following working snippet...
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
format: "$ #,###",
ticks: [0, 1, 2, 3, 4, 5, 6]
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols =   [0];
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="provision_chart" style="width: 500px; height: 500px;"></div>
the getColumnRange(colIndex) method can assist in building the ticks dynamically
the method returns an object {} with properties for min and max for the column index provided
see following working snippet for an example...
google.charts.load('current', {
'packages': ['corechart']
});
//Input data
var data = [
['Data', 'CAT1', 'CAT2', 'CAT3', 'CAT4'],
['Provisions', 5, 0, 0, 0],
];
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
var options = {
colors: ['#00699B', '#087EB4', '#CBE7F7', '8A6996'],
isStacked: true,
chartArea: {
width: '40%'
},
bar: {
groupWidth: "40%"
},
// tooltip: { isHtml: true },
trigger: 'both',
vAxis: {
gridlines: {
color: '#0000006b',
minValue: 0,
baseline: 0
},
format: "$ #,###"
},
};
var dataTable = google.visualization.arrayToDataTable(data);
//Formatters
var intergerFormatter = new google.visualization.NumberFormat({
groupingSymbol: ",",
fractionDigits: 0
});
for (var i = 0; i < data[0].length; i++) {
intergerFormatter.format(dataTable, i);
}
var view = new google.visualization.DataView(dataTable);
var cols = [0];
var ticksY = [];
var maxY = null;
var minY = null;
for (var i = 1; i < view.getNumberOfColumns(); i++) {
var range = view.getColumnRange(i);
if (maxY === null) {
maxY = Math.ceil(range.max);
} else {
maxY = Math.max(maxY, Math.ceil(range.max));
}
if (minY === null) {
minY = Math.floor(range.min);
} else {
minY = Math.min(minY, Math.floor(range.min));
}
}
for (var i = minY; i <= maxY + 1; i++) {
ticksY.push(i);
}
options.vAxis.ticks = ticksY;
for (var i = 1; i < data[0].length; i++) {
cols.push({
sourceColumn: i,
type: "number",
label: data[0][i]
});
cols.push({
calc: createTooltip(i),
type: "string",
role: "tooltip",
});
}
view.setColumns(cols);
var chart = new google.visualization.ColumnChart(document.getElementById('provision_chart'));
chart.draw(view, options);
function createTooltip(col) {
return function(dataTable, row) {
var html = dataTable.getColumnLabel(col) + ":" + "\n";
html += "4 " + dataTable.getValue(row, 0) + "\n";
html += "$ " + intergerFormatter.formatValue(dataTable.getValue(row, col)) + " total" + "\n";
return html;
};
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="provision_chart" style="width: 500px; height: 500px;"></div>

How get sum of total values in stackedBar ChartJs

I'm trying to get the sum of all values of a stackedBar and include this total in tooltip.
Note: my datasets aren't static, this is an example
var barChartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: 'Corporation 1',
backgroundColor: "rgba(220,220,220,0.5)",
data: [50, 40, 23, 45, 67, 78, 23]
}, {
label: 'Corporation 2',
backgroundColor: "rgba(151,187,205,0.5)",
data: [50, 40, 78, 23, 23, 45, 67]
}, {
label: 'Corporation 3',
backgroundColor: "rgba(151,187,205,0.5)",
data: [50, 67, 78, 23, 40, 23, 55]
}]
};
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
title:{
display:true,
text:"Chart.js Bar Chart - Stacked"
},
tooltips: {
mode: 'label',
callbacks: {
label: function(tooltipItem, data) {
var corporation = data.datasets[tooltipItem.datasetIndex].label;
var valor = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
var total = eval(data.datasets[tooltipItem.datasetIndex].data.join("+"));
return total+"--"+ corporation +": $" + valor.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
}
}
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
}
});
};
Now total is the sum per dataset and I need the sum per stackedBar.
Example
Label A: value A
Label B: value B
Label C: value C
TOTAL: value A + value B + value C
It is possible to get that total value?
Thanks, Idalia.
First you should know that if you return an array instead of a single string in the callback of the tooltip, it will display all the strings in your array as if it were different datasets (see this answer for more details).
So I edited a little bit your callback to the following:
callbacks: {
label: function(tooltipItem, data) {
var corporation = data.datasets[tooltipItem.datasetIndex].label;
var valor = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
// Loop through all datasets to get the actual total of the index
var total = 0;
for (var i = 0; i < data.datasets.length; i++)
total += data.datasets[i].data[tooltipItem.index];
// If it is not the last dataset, you display it as you usually do
if (tooltipItem.datasetIndex != data.datasets.length - 1) {
return corporation + " : $" + valor.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
} else { // .. else, you display the dataset and the total, using an array
return [corporation + " : $" + valor.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,'), "Total : $" + total];
}
}
}
You can see the full code in this jsFiddle, and here is its result :
i modified tektiv answer to show Total only for active sets and move it to tooltips footer.
tooltips: {
mode: 'label',
callbacks: {
afterTitle: function() {
window.total = 0;
},
label: function(tooltipItem, data) {
var corporation = data.datasets[tooltipItem.datasetIndex].label;
var valor = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
window.total += valor;
return corporation + ": " + valor.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
},
footer: function() {
return "TOTAL: " + window.total.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}
}
}
Shorter version of Gaspar's answer:
tooltips: {
callbacks: {
footer: (tooltipItems, data) => {
let total = tooltipItems.reduce((a, e) => a + parseInt(e.yLabel), 0);
return 'Total: ' + total;
}
}
}
Example: https://jsfiddle.net/g3ba60zc/2/
In the other answers you replace the last dataset, with this you don't need to
tooltips: {
callbacks: {
title: function(tooltipItems, data) {
return _this.chart.data.labels[tooltipItems[0].index];
},
footer: function(tooltipItems, data) {
let total = 0;
for (let i = 0; i < tooltipItems.length; i++) {
total += parseInt(tooltipItems[i].yLabel, 10);
}
return 'Total: ' + total;
}
}
}
Ps: It's typescript lang.
#Haider this is what you were looking for, I had the same problem.
I have reused your code and built upon it #tektiv
I have made one small change where instead of building into the label I have made use of the afterbody. This removes the key color
afterBody code:
afterBody: function (tooltipItem, data) {
var corporation = data.datasets[tooltipItem[0].datasetIndex].label;
var valor = data.datasets[tooltipItem[0].datasetIndex].data[tooltipItem[0].index];
var total = 0;
for (var i = 0; i < data.datasets.length; i++)
total += data.datasets[i].data[tooltipItem[0].index];
return "Total : $" + total;
}
Full code here at JSFiddle
Picture demonstration of the finished tooltip
Using Chart.js 2.5.0
var valor = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
returns a string value. To calculate the correct sum value you have to add a parseFloat statement:
tooltips: {
mode: 'label',
callbacks: {
afterTitle: function() {
window.total = 0;
},
label: function(tooltipItem, data) {
var corporation = data.datasets[tooltipItem.datasetIndex].label;
var valor = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
//THIS ONE:
valor=parseFloat(valor);
window.total += valor;
return corporation + ": " + valor.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
},
footer: function() {
return "TOTAL: " + window.total.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}
}
}
If you are on older ChartJs version you have to handle this in a different way. I'm using Chart.js Version 2.7.2 and this is how I handled it:
tooltips: {
mode: 'label',
callbacks: {
footer: function (data) {
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i].yLabel;
}
return 'Total: ' + total
}
}
}
Chart.js made their own, very satisfying solution:
options: {
interaction: {
intersect: false,
mode: 'index',
},
plugins: {
tooltip: {
callbacks: {
footer: footer,
}
}
}
}
and somewhere else in your code:
const footer = (tooltipItems) => {
let sum = 0;
tooltipItems.forEach(function(tooltipItem) {
sum += tooltipItem.parsed.y;
});
return 'Sum: ' + sum;
};
Worked just fine for me!

How to modify chartjs tooltip to add customized attribute

How I have to edit the tooltip template that i can add customized attributes from my json file ? Below the example:
ChartJS Example
In the x-axis are the Months with the first letter, but in the tooltip i want to show the first three letters of the month - How can i do this ?
EDIT: My JSON File:
{"modules":[{
"name":"Chart 1",
"link":"www.google.com",
"type":"Bar",
"series":"SeriesA",
"data":[[20,40,50,40,20,20,20,20,20,20,20,20]],
"labels":["M","J","J","A","S","O","N","D","J","F","M","A","M"],
"colors":[{
"fillColor":"blue"
}],
"options":{
"scaleShowGridLines":false
}
}]}
Different Labels in Tooltip vs Scale
Just use the tooltipTemplate option
Preview
Script
function Label(short, long) {
this.short = short;
this.long = long
}
Label.prototype.toString = function() {
return this.short;
}
var data = {
labels: [
new Label("J", "JAN"),
new Label("F", "FEB"),
new Label("M", "MAR"),
new Label("A", "APR"),
new Label("M", "MAY"),
new Label("J", "JUN"),
new Label("J", "JUL")
],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.5)",
strokeColor: "rgba(220,220,220,0.8)",
highlightFill: "rgba(220,220,220,0.75)",
highlightStroke: "rgba(220,220,220,1)",
data: [65, 59, 80, 81, 56, 55, 40]
}
]
};
// create chart
var ctx = document.getElementById("chart").getContext('2d');
new Chart(ctx).Bar(data, {
tooltipTemplate: "<%if (label){%><%=label.long%>: <%}%><%= value %>",
});
Fiddle - https://jsfiddle.net/7z1s1feg/
This part of the documentation explain you how to extend the tooltips elements.
var myPieChart = new Chart(ctx).Pie(data, {
customTooltips: function(tooltip) {
};
});
Plus, this example show you how to modify the HTML of the tooltip inside this function. The example from GitHub :
var innerHtml = '';
for (var i = tooltip.labels.length - 1; i >= 0; i--) {
innerHtml += [
'<div class="chartjs-tooltip-section">',
' <span class="chartjs-tooltip-key" style="background-color:' + tooltip.legendColors[i].fill + '"></span>',
' <span class="chartjs-tooltip-value">' + tooltip.labels[i] + '</span>',
'</div>'
].join('');
}
tooltipEl.html(innerHtml);
With these elements, you will be able to customize your tooltips however you want.

Format tooltip content of Google column chart generated via Keen

We use Keen on a site to track view data. This works well but I’m having an issue with how some of the data is presented in the graphs (using v3.0.5 of the JS SDK). On the users dashboard we have a graph showing the last 4 months data (timeframe : this_4_months). I have a query though -
When the user hovers over one of the columns you see detail in a tooltip e.g. "April 1, 2015 12:00:00 AM" - is there any way to format this tooltip into something more user-friendly? e.g. "April 2015"
Keen.ready(function() {
var query = new Keen.Query('count', {
'eventCollection' : 'profile_views',
'timeframe' : 'this_4_months',
'interval' : 'monthly',
'groupBy' : 'view.membership_type',
'filters' : [
{
'property_name' : 'view.user_id',
'operator' : 'eq',
'property_value' : String(user_id)
}
]
});
client.draw(query, document.getElementById(element_id), {
chartType: 'columnchart',
width : graph_width,
height : 250,
colors : ['#abdd99', '#8dc7d9', '#eeeeee'],
colorMapping : {
'pro' : '#abdd99',
'basic' : '#8dc7d9'
},
labelMapping: {
"basic": "BASIC",
"pro": "PRO"
},
title : '',
chartOptions: {
width : '100%',
height : '100%',
isStacked: true,
fontName : 'Helvetica',
fontSize : '11px',
chartArea : {
left : '10px',
top : '0',
width : '90%',
height : '90%'
},
axisTitlesPosition : 'in',
vAxis : {
viewWindowMode : 'pretty',
gridlines : { color : '#eeeeee' },
baselineColor : '#eeeeee',
textPosition : 'in'
},
hAxis : {
viewWindowMode : 'pretty',
gridlines : {
color : '#eeeeee'
},
baselineColor : '#eeeeee',
textPosition : 'none'
},
legend : {
position : 'in'
},
titlePosition : 'none'
}
});
});
Here is a screenshot of how the tooltip appears :
Instead of
var chart = keenIoClient.draw(query, document.getElementById("chart2"), options );
Collect all your data to array manually, so you can add more columns there. Here is example with dates and pageviews:
keenIoClient.run(query, function(err, response){
if (err) {
// there was an error!
}
else {
var arrayData = [];
arrayData.push(['Day','Views']);
response.result.forEach(function (element, index, array) {
var date = new Date(element.timeframe.start);
arrayData.push([date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear() , element.value]);
});
var data = google.visualization.arrayToDataTable(arrayData);
var chart = new google.visualization.ColumnChart( document.getElementById('chart2'));
chart.draw(data, options);
}
});
The "options" variable stays the same.
P.S. on the way you can set up the format for your dates.
P.P.S. in my case the Query was:
var query = new Keen.Query("count", {
eventCollection: "views",
interval: "daily",
timeframe: "this_7_days",
});