Add value to horizontal bar in chart.js - javascript

I have been looking around for a way to add the value inside each bar in a horizontal bar chart, using chart.js but all posts seem to show how to add the label. Tooltip shows both label and value but I wanted to show the value so users can see the result without having to mouse-over the bar.
I put break points in the script to see if there is any property of "model" that contains the value but couldn't find one.
This is how I set up the chart including the animation section that shows the label instead of the value.
Dataset comes from an ajax call and chart is displayed in its onSuccess:
function OnSuccess_(response) {
var jResult = JSON.parse(response.d);
var chartLabels = [];
var chartData = []
$.each(jResult, function (index, val) {
chartLabels.push(val.TIMERANGE);
chartData.push(val.COUNT); // <--- This is what I want to display on each bar
});
var ctx = document.getElementById("rtChart").getContext("2d");
if (chartRespTime)
chartRespTime.destroy();
chartRespTime = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: chartLabels,
datasets: [{
label: "Response Time (ms)",
backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"],
data: chartData
}]
},
options: {
title: {
display: true,
text: 'Database Response Time (milli-seconds)'
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Count'
},
ticks: {
major: {
fontStyle: 'bold',
fontColor: '#FF0000'
}
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Response Time (ms)'
}
}]
},
animation: {
onComplete: function () {
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'left';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
left = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._xScale.left;
ctx.fillStyle = '#444'; // label color
var label = model.label; // <--- need value not label
ctx.fillText(label, left + 15, model.y + 8);
}
});
}
},
maintainAspectRatio: false,
responsive: true,
showInlineValues: true,
centeredInllineValues: true,
tooltipCaretSize: 0
}
});
//console.log(ctx);
$('#rtChart').show();
}

There is no build in way to do this, but there is a verry good plugin that achieves what you want: the datalabels plugin https://chartjs-plugin-datalabels.netlify.app/samples/charts/bar.html

Related

Chart.JS value on top disappear when tooltip show up

I have chart witch i need show up value on top each bar, and i need show tooltip too, so i try these code
var ctx3 = document.getElementById('canvasppicinh').getContext('2d');
window.myMixedChart = new Chart(ctx3, {
type: 'bar',
data: chartData,
options: {
maintainAspectRatio: false,
title: {
display: true,
text: 'Chart KPI Financial Perfective',
padding: 50
},
legend :{
position : 'bottom'
},
tooltips: {
mode: 'index',
intersect: true,
enabled: true,
callbacks: {
label: function(tooltipItem, data) {
var val = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +',-';
}
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
categoryPercentage: 1.0
},
gridLines: {
display: false
}
}]
},
hover: {
mode: false
},
animation: {
duration : 1,
onProgress: function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
}
}
});
Well is kinda work for me, my chart show value on top each bar but my problem is, everytime i try show tooltip value on top disappear. If tooltip disappear (not hovering) top value appearing. Did i miss something? And I have searching these problem on google, it said i need extend. But i don't have any idea how to use extend with my oldest code. Please help me.
I found the solution you need plugin chartjs-plugin-datalabels, and add inside option chart
plugins: {
datalabels: {
color: 'white',
formatter: function(value, context) {
return Math.round(value) + '%';
}
}
}
And remove animation

How to only draw the graph and the Xaxis gridlines using chart.js

I am trying to draw a graph, but the left and the bottom corners keep getting this blank margin. How do I get rid of that? I managed to erase them, but at the same time it erases the gridLines for the X axis. I want to keep the Xaxis gridlines.
Notice that I also want that border around the graph. Didn't find a way to draw the border using the chart.js.
The white spaces are very evidient, right on the bottom and on the left, spacing the gray border away. You can see it on the image:
I tried disabling the ticks display.
My chart so far:
var myChart = new Chart(modalChart, {
type: 'bar',
data: {
labels: ['Total enviado', 'Total recebido', 'total aberto', 'total convertido'],
datasets: [{
backgroundColor: my_gradient,
data: [totalEnviado,totalRecebido, totalAberto,totalConvertido]
}]
},
options: {
legendCallback: function(chart){
var text = [];
text.push('<div class = "modal-graph-container">');
text.push('<div class = "modal-graph-inner">');
for (var i=0; i<chart.data.labels.length; i++) {
console.log(chart.data.datasets[i]); // see what's inside the obj.
text.push('<div class = "modal-graph-child">');
text.push('<span style="">' + chart.data.labels[i] + '</span>');
console.log(chart.data.labels[i]);
text.push('</div>');
}
text.push('</div>');
text.push('</div>');
return text.join("");
},
legend: {
display:false
},
scales: {
xAxes:[{
display: true,
categoryPercentage:1.0,
barPercentage:1.0,
ticks: {
beginAtZero: true,
display:false
}
}],
yAxes: [{
ticks: {
beginAtZero:true,
display: false
},
gridLines:{
display:false
}
}]
}
}
});
Notice that I also want that border around the graph. Didn't find a way to draw the border using the chart.js only. This gray border around the graph and the gray borders separating the bars are very important.
You need to set the drawTicks option to false for both the x- and y-axis:
gridLines: {
drawTicks: false
}
Working example:
var modalChart = document.getElementById("chart"),
totalEnviado = 4,
totalRecebido = 3,
totalAberto = 2,
totalConvertido = 1,
my_gradient = "orange";
// --
var myChart = new Chart(modalChart, {
type: 'bar',
data: {
labels: ['Total enviado', 'Total recebido', 'total aberto', 'total convertido'],
datasets: [{
backgroundColor: my_gradient,
data: [totalEnviado, totalRecebido, totalAberto, totalConvertido]
}]
},
options: {
legendCallback: function(chart) {
var text = [];
text.push('<div class = "modal-graph-container">');
text.push('<div class = "modal-graph-inner">');
for (var i = 0; i < chart.data.labels.length; i++) {
console.log(chart.data.datasets[i]); // see what's inside the obj.
text.push('<div class = "modal-graph-child">');
text.push('<span style="">' + chart.data.labels[i] + '</span>');
console.log(chart.data.labels[i]);
text.push('</div>');
}
text.push('</div>');
text.push('</div>');
return text.join("");
},
legend: {
display: false
},
scales: {
xAxes: [{
display: true,
categoryPercentage: 1.0,
barPercentage: 1.0,
ticks: {
beginAtZero: true,
display: false
},
gridLines: {
drawTicks: false
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
display: false
},
gridLines: {
display: false,
drawTicks: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<div style="border:1px solid #000">
<canvas id="chart"></canvas>
</div>

Want to show small part of js Bar Chart when value is zero

I have these bar charts that will sometimes show zero values to the user. I'd like to show a bit of the bar chart so it does not look completely empty, but the data is connected to the visual representation of the bar. Is there any way I could have the top number say zero but the value be 3(or something small) in each column? Here is the code and a screenshots. One screenshot has data, the other is zero. I'd like the zero graph to show just a bit of the orange and green when at zero. Thanks
<canvas id="bar-chart" width="900" height="350"></canvas>
<script type="text/javascript">
var ctx = document.getElementById("bar-chart");
debugger;
var data = {
labels: ["Page Views", "Data Requests"],
datasets: [{
data: [<?php echo $databaseClass->totalViewsSelectedMonth($user_id, $year, 1);
?>, <?php
echo $databaseClass->isRfYearMonth($user_id, $year, 1);
?>],
backgroundColor: ["orange", "green"]
}]
}
var myChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
"hover": {
"animationDuration": 0
},
"animation": {
"duration": 1,
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
legend: {
"display": false
},
tooltips: {
"enabled": false
},
scales: {
yAxes: [{
display: false,
gridLines: {
display: false
},
ticks: {
max: Math.max(...data.datasets[0].data) + 20,
display: false,
beginAtZero: true
}
}],
xAxes: [{
gridLines: {
display: false
},
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
It looks like you can update the axes of your charts to a new default. So, using a modified form of their example, something like the following (modified to fit your code):
// ...
scales: {
yAxes: [{
display: false,
gridLines: {
display: false
},
ticks: {
max: Math.max(...data.datasets[0].data) + 20,
min: -3, // ADDED
display: false,
beginAtZero: true
}
}],
// ...
... would do what you're looking for - with the side benefit that 0 and 3 wouldn't look like the same value, the relative bar size should stay accurate.

Label is not showing in ChartJS

I'm using ChartJS for my implementation of charts, but I notice that one of my graph's label is hidden. It is not showing its label above the bar. I've added a screenshot below for the comparison of two different bar graphs. The left graph shows the label even if it is on the very top but the other one is not showing. Please see my screenshot and code below.
function createChart(context, type, bgColor, bdColor, labels, actualData, options = {}){
new Chart(context, {
type: type,
data: {
labels: labels,
datasets: [{
label: "Actual",
backgroundColor: bgColor,
borderColor: bdColor,
data: actualData,
}]
},
options: options
});
}
function getOptions(displayLegend = true){
return {
events: false,
showTooltips: false,
legend: {
display: displayLegend
},
animation: {
duration: 0,
onComplete: function(){
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseLine = 'bottom';
ctx.fillStyle = '#0b7707';
this.data.datasets.forEach(function(dataset){
console.log(dataset);
for(var i = 0; i < dataset.data.length; i++){
for(var key in dataset._meta){
var model = dataset._meta[key].data[i]._model;
ctx.fillText(dataset.data[i], model.x, model.y - 13);
}
}
});
}
}
};
}
I solved this problem by adding an empty title to the chart, so it will create space above the chart and show labels above the bar
options: {
title: {
display: true,
text: ' '
},
....
This looks like a clear case of the datalabels going out of the canvas since the bar takes height dynamically as per the data values. You can set the max y-tick setting to solve this. Here is the jsfiddle -> https://jsfiddle.net/Luaf2tm4/5979/
Hope it helps!
var canvas = document.getElementById('myChart');
var data = {
labels: ["January", "February", "March", "April", "May", "June"],
datasets: [{
label: "My First dataset",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: [500, 2000, 800, 600, 950, 890],
}]
};
function getOptions(displayLegend = false) {
return {
events: false,
showTooltips: false,
legend: {
display: displayLegend
},
scales: {
yAxes: [{
display: true,
stacked: true,
ticks: {
stepSize: 200,
min: 0, // minimum value
max: 2200 // maximum value, you can either hard code if you know your datainput, else computer the value through some logic i.e taking the max value from the dataset and adding some extra value to it.
}
}]
},
animation: {
duration: 0,
onComplete: function() {
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseLine = 'bottom';
ctx.fillStyle = '#0b7707';
this.data.datasets.forEach(function(dataset) {
console.log(dataset);
for (var i = 0; i < dataset.data.length; i++) {
for (var key in dataset._meta) {
var model = dataset._meta[key].data[i]._model;
ctx.fillText(dataset.data[i], model.x, model.y - 10);
}
}
});
}
}
};
}
var myBarChart = Chart.Bar(canvas, {
data: data,
options: getOptions()
});

Hide Y-axis labels when data is not displayed in Chart.js

I have a Chart.js bar graph displaying two sets of data: Total SQL Queries and Slow SQL Queries. I have Y-axis labels for each respective set of data. The graph can be seen below:
When I toggle one of the sets of data to not display, the corresponding Y-axis labels still display. When interpreting the graph, this is a bit confusing. As seen below:
My question: How can I hide the Y-axis labels of any set of data that is currently not being displayed?
This is how I currently have my chart set up:
<canvas id="SQLPerformanceChart" minHeight="400"></canvas>
<script type="text/javascript">
...
var data = {
labels: labelArray,
datasets: [{
label: "Total SQL Queries",
fill: false,
borderWidth: 1,
borderColor: "green",
backgroundColor: "rgba(0, 255, 0, 0.3)",
yAxisID: "y-axis-0",
data: totalQueriesArray
}, {
label: "Slow SQL Queries",
fill: false,
borderWidth: 1,
borderColor: "orange",
backgroundColor: "rgba(255, 255, 0, 0.3)",
yAxisID: "y-axis-1",
data: slowQueriesArray,
}]
};
var options = {
animation: false,
scales: {
yAxes: [{
position: "left",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Total SQL Queries'
},
id: "y-axis-0"
}, {
position: "right",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Slow SQL Queries'
},
id: "y-axis-1"
}]
},
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
title: function(tooltipItem, data) {
return data.label;
},
beforeLabel: function(tooltipItem, data) {
if (tooltipItem.index == 24) {
return data.labels[tooltipItem.index] + " - Now";
} else {
return data.labels[tooltipItem.index] + " - " + data.labels[(tooltipItem.index) + 1];
}
}
}
}
}
var ctx = document.getElementById("SQLPerformanceChart");
var SQLPerformanceChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
</script>
You can add a callback function to legends onClick:
var options = {
animation: false,
scales: {
yAxes: [{
position: "left",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Total SQL Queries'
},
id: "y-axis-0"
}, {
position: "right",
ticks: {
beginAtZero: true
},
scaleLabel: {
display: true,
labelString: 'Slow SQL Queries'
},
id: "y-axis-1"
}]
},
legend: {
onClick: function(event, legendItem) {
//get the index of the clicked legend
var index = legendItem.datasetIndex;
//toggle chosen dataset's visibility
SQLPerformanceChart.data.datasets[index].hidden =
!SQLPerformanceChart.data.datasets[index].hidden;
//toggle the related labels' visibility
SQLPerformanceChart.options.scales.yAxes[index].display =
!SQLPerformanceChart.options.scales.yAxes[index].display;
SQLPerformanceChart.update();
}
}
}
This solution applies if you are using angular-chartjs, and if you want to apply this behaviour to all displayed charts.
If you want to skip to the code, check this fiddlejs.
You can also check this other fiddlejs to check the default Angular-Chartjs behaviour.
Step by step:
I use the first chart example in angular-chart.js, so this will be the final result after clicking:
<div ng-app="app" ng-controller="MainController as mainCtrl">
<canvas id="line" class="chart chart-line" chart-data="data"
chart-labels="labels" chart-series="series" chart-options="options"
chart-dataset-override="datasetOverride" chart-click="onClick">
</canvas>
</div>
Replace the handler of the global Chart:
Chart.defaults.global.legend.onClick = function (e, legendItem) {
var idx = legendItem.datasetIndex;
// IMPORTANT charts will be created in the second and third step
var chart = charts[e.srcElement.id];
chart.options.scales.yAxes[idx].display = !chart.options.scales.yAxes[idx].display;
var meta = chart.getDatasetMeta(idx);
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null ? !chart.data.datasets[idx].hidden : null;
chart.update();
};
Create a global variable charts so we can get access each of the charts with the canvas id:
var charts = {};
Fill up the charts variables using the chart-create event:
angular.module("app", ["chart.js"]).controller("MainController", function ($scope) {
$scope.$on('chart-create', function (event, chart) {
charts[chart.chart.canvas.id] = chart;
});
$scope.labels = ["January", "February", "March", "April", "May", "June", "July"];
$scope.series = ['Series A', 'Series B'];
$scope.data = [...
I wish there would be a better way of getting a chart from the canvas id, but as far as I know this is the suggested way by the developers.
This solution applies if you are using ng2-charts with chart.js and Angular 7^ and if you want to apply this behavior to all displayed charts.
import Chart from chart.js
Chart.defaults.global.legend.onClick = function (e: MouseEvent, chartLegendLabelItem: ChartLegendLabelItem) {
const idx: number = chartLegendLabelItem.datasetIndex;
const chart = this.chart;
chart.options.scales.yAxes[idx].display = !chart.options.scales.yAxes[idx].display;
const meta = chart.getDatasetMeta(idx);
meta.hidden = meta.hidden === null ? !chart.data.datasets[idx].hidden : null;
chart.update();
};
or for local configuration
legend: <ChartLegendOptions>{
onClick: function (e: MouseEvent, chartLegendLabelItem:ChartLegendLabelItem) {
const idx: number = chartLegendLabelItem.datasetIndex;
const chart = this.chart;
chart.options.scales.yAxes[idx].display =
!chart.options.scales.yAxes[idx].display;
const meta = chart.getDatasetMeta(idx);
meta.hidden = meta.hidden === null ?
!chart.data.datasets[idx].hidden : null;
chart.update();
}
}
I came along this problem using v3.8.0, none of the obove worked for me.
This code works for me.
Note I'm storing all my chart instances in a Map because I have multiple charts on the same page.
var instances = new Map();
When createing the incances I put them there.
and now the hiding of the y axis label and data on legend click:
onClick: function (event, legendItem) {
var instance = instances.get(event.chart.id);
var meta = instance.getDatasetMeta(legendItem.datasetIndex);
var newValue = !meta.yScale.options.display;
meta.hidden = meta.yScale.options.display;
meta.yScale.options.display = newValue;
instance.update();
}

Categories