How to display labels inside pie Chart with Chart.Js V2.3 - javascript

I am trying to show the values of the pie slices inside the pie chart with Chart.JS v2.3
I've tried various ones to see if I could get them to work
Chart.js v2: How to make tooltips always appear on pie chart?
When I try this, the tooltips are still hover over.
Tried this as well and this did not work.
options: {
events: false,
animation: {
duration: 0
},
onAnimationComplete: function () {
var self = this;
var elementsArray = [];
Chart.helpers.each(self.data.datasets, function (dataset, datasetIndex) {
Chart.helpers.each(dataset.metaData, function (element, index) {
var tooltip = new Chart.Tooltip({
_chart: self.chart,
_data: self.data,
_options: self.options,
_active: [element]
}, self);
tooltip.update();
tooltip.transition(Chart.helpers.easingEffects.linear).draw();
}, self);
}, self);
}
},
If I try one of the resolutions that use a plugin service it fails with the following error:
Uncaught TypeError: Cannot read property 'register' of undefined
Here is the full code I'm trying to work with:
var data = {
labels: ["People", "Process", "Technology"],
datasets: [
{
data: [10,20,30],
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}
]
};
// render chart
Chart.pluginService.register({
beforeRender: function(chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function(dataset, i) {
chart.getDatasetMeta(i)
.data.forEach(function(sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options,
_active: [sector]
},
chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function(chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips,
function(tooltip) {
tooltip.initialize();
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});
var ctx = document.getElementById("pieChart").getContext("2d");
var myPieChart = new Chart(ctx,
{
type: 'pie',
data: data,
options: {
showAllTooltips: true
}
});
I'm also trying to avoid having to use chartNEW.js
Also if it matters this is being done in Asp.Net with MVC.

Related

Unable to display point values without mouse hover

Herewith I used JavaScript line chart within Laravel framework. Mouse hover tool tip to display point values working perfectly with label:function(...). I need to display only y-axis value on every point at chart on create (Without mouse hovering). To perform this I used drawDatasetPointsLabels() method from How to display Line Chart dataset point labels with Chart.js? and call it on chart options. But unfortunately it is not working. Below is the code.
chart.blade
monthlabels={.......};
salesqty = {......};
stockqty = {......};
document.getElementById("history_canvas_holder").innerHTML = ' ';
document.getElementById("history_canvas_holder").innerHTML = '<canvas id="historyChart" width="500" height="350"></canvas>';
var ctx = document.getElementById("historyChart").getContext('2d');
var myLineChart = new Chart(ctx,
{
type: 'line',
data:
{
labels: monthlabels,
datasets: [{
label: 'Sales',
data: salesqty,
borderColor: [
'rgba(255,99,132,1)'
],
borderWidth: 2
},
{
label: 'Stock',
data: stockqty,
borderColor: [
'rgba(0,161,232)'
],
borderWidth: 2
}
]
},
options: {
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += Math.round(tooltipItem.yLabel * 100) / 100;
return label;
},
onAnimationProgress: function() { drawDatasetPointsLabels(ctx) },
onAnimationComplete: function() { drawDatasetPointsLabels(ctx) }
}
}
}
});
function drawDatasetPointsLabels(ctx) {
ctx.font = '.9rem "ABCD",sans-serif';
ctx.fillStyle = '#AAA';
ctx.textAlign="center";
$(historyChart.datasets).each(function(idx,dataset){
$(dataset.points).each(function(pdx,pointinfo){
if ( pointinfo.value !== null ) {
ctx.fillText(pointinfo.value,pointinfo.x,pointinfo.y - 15);
}
});
});
}
In the type of v2.5.0
`options: {
tooltips: {
enabled: false
}
}`
or
`tooltips :{
custom : function(tooltipModel) {
tooltipModel.opacity = 0;
}
}`
type of v2.1.4
`Chart.defaults.global.tooltips.enabled = false;`
people said those ways are work, but not in all charts type.

How to detect when Tooltip closes in chart.js?

I'm using chart.js for a web project and it's working pretty fine. However, I do have one question. I'm trying to connect a line graph with n data points to a list of n html divs. When the user hovers over data point 2, div 2 will be highlighted and a function is called. That does work. However, when the user unhovers data point 2, div 2 should change its style back to the default style.
My question is: How can I detect the mouseout event on data points?
That is how I define what happens when the data point is hovered.
myChart = new Chart(ctx, {
type: 'line',
data: chartData,
options: {
title: {
...
},
tooltips: {
enabled: true,
custom: function(tooltip) {
if (!tooltip) {
return;
}
if(tooltip.dataPoints != null) {
// here, the function that highlights the respective div is called, and it works fine
}
}
}
}
});
Is there such a thing for unhovering? I found out that there is a global events -> mousout option, but I don't figure out how to use it and I also think that it references the whole chart.
Thank you!
Not sure if this will help you, but I had a similar issue with stacked bar charts. I wanted to show values at the top of the bars, but I found that if the tooltips were open the values were written over the top of the tooltips, making both unreadable. I decided I wanted to show the values only if the tooltips were not showing (and were not rendered if a tooltip was open).
Turns out I can use the tooltip's opacity setting to determine if the tooltip is showing or not. This is very over-simplified, but this is what I came up with:
options: {
tooltips: {
custom: function( tooltip ) {
if( tooltip.opacity > 0 ) {
console.log( "Tooltip is showing" );
} else {
console.log( "Tooltip is hidden" );
}
return;
}
}
}
Having worked that out, I was then able to save a global variable that I could test elsewhere to see if the tooltip was showing.
var ctx = document.getElementById("canvas").getContext("2d");
var data = {
labels: [
"Red",
"Green",
"Yellow"
],
datasets: [{
data: [300, 50, 100],
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
};
Chart.pluginService.register({
beforeRender: function(chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function(dataset, i) {
chart.getDatasetMeta(i).data.forEach(function(sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function(chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function(tooltip) {
tooltip.initialize();
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
})
var myPieChart = new Chart(ctx, {
type: 'pie',
data: data,
options: {
showAllTooltips: true
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<canvas id="canvas"></canvas>

Google charts getting custom tooltips to work with an animation

Well this is my code, it's broken. I want to have absolute figures appear on mouse over, instead of percentages. Google's guides do not have an example of this with an animation, their examples use data table methods rather than arrays. I think I need to somehow tell Google that I have a third column which is a tooltip, at present it draws it as a bar.
google.load("visualization", "1", {
packages: ["corechart"]
});
google.setOnLoadCallback(init);
function init() {
var rowData1 = [
['key', 'Percentage', 'tooltip'],
['PLUS', 20.9, 3855],
['EDU', 18.4, 3400],
['GEO', 15.6, 2872],
['NO FLAG', 45.2, 8342]
];
var rowData2 = [
['key', 'Percentage', 'tooltip'],
['PLUS', 54.2, 974],
['EDU', 6.7, 120],
['GEO', 39.2, 704],
['NO FLAG', 0.0, 0]
];
// Create and populate the data tables.
var data = [];
data[0] = google.visualization.arrayToDataTable(rowData1);
data[1] = google.visualization.arrayToDataTable(rowData2);
var options = {
// removes the key
legend: {
position: 'none'
},
// puts popup boxes on bar
width: 600,
height: 300,
vAxis: {
title: "vertical axis"
},
hAxis: {
title: "horizontal axis"
},
seriesType: "bars",
series: {
5: {
type: "line"
}
},
animation: {
duration: 1000,
easing: 'out'
},
};
var current = 0;
// Create and draw the visualization.
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
var button = document.getElementById('b1');
function drawChart() {
// Disabling the button while the chart is drawing.
button.disabled = true;
google.visualization.events.addListener(chart, 'ready',
function() {
button.disabled = false;
button.value = 'Switch to ' + (current ? 'Tea' : 'Coffee');
});
options['title'] = 'Monthly ' + (current ? 'Coffee' : 'Tea') + ' Production by Country';
// custom popup box request
chart.draw(data[current], options);
}
drawChart();
button.onclick = function() {
current = 1 - current;
drawChart();
}
}
I've tried converting the array data to DataTables and using
if (current == 0) { chart.draw(dataTable1, options); }
else{ chart.draw(dataTable2, options); }
To select which chart to draw, but this isn't working. And it's less intelligible and inelegant, the dataTables need lots of properties set, so repetition.
need to define tooltip column with object notation...
var rowData1 = [
['key', 'Percentage', {role: 'tooltip'}],
['PLUS', 20.9, 3855],
['EDU', 18.4, 3400],
['GEO', 15.6, 2872],
['NO FLAG', 45.2, 8342]
];
var rowData2 = [
['key', 'Percentage', {role: 'tooltip'}],
['PLUS', 54.2, 974],
['EDU', 6.7, 120],
['GEO', 39.2, 704],
['NO FLAG', 0.0, 0]
];
Change google visualization Combo Chart series option as below:
series: {
0: {
type: "line"
}
}
Every data table column is considered as one series in google visualization Combo Chart.
Here
"Percentage" is line series no is 0
"tooltip" is bar series no is 1
Nothing wrong with google visualization Combo Chart.
After above change you will get below output:

Chart JS: Donut/Doughnut Chart: Tooltip to be shown always for all the data. All tooltip is not shown when multiple data are with 0 data

I have created a donut chart. I want to display the tooltip always in the donut chart along with the legends.
I have followed this stack overflow question.
Question which explain the tooltip to be shown always
I have followed the answer and created a doughnut chart and tried to show the tooltip always.
it works fine, however it is not showing all the label, esp. when you have multiple data with 0 value.It just overwrite the label.
my label and values are
"Red" -0,
"Green" -0 &
"Yellow"-100
here is shows tooltip for "Yellow-100" and "Green-0", i think it is overwriting on top of "Red-0". How to show tooltip for "Red-0" and "Green-0" both together.
html:
<canvas id="canvas"></canvas>
Javascript:
var ctx = document.getElementById("canvas").getContext("2d");
var data = {
labels: [
"Red",
"Green",
"Yellow"
],
datasets: [
{
data: [0, 0, 100],
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
};
Chart.pluginService.register({
beforeRender: function (chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function (dataset, i) {
chart.getDatasetMeta(i).data.forEach(function (sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options,
_active: [sector]
}, chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function (chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
tooltip.initialize();
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
})
var myPieChart = new Chart(ctx, {
type: 'pie',
data: data,
options: {
showAllTooltips: true
}
});
here is the link for jsfiddle.
doughnut chart 0 data tooltip is not shown for all
Chart Version : 2.1.0
please help.
you could use the tooltip callbacks in order to check which data is inside and place it on a different position.
For example you could return the red label in the title and the green one in the footer:
callbacks: {
title: function(tooltipItems, data) {
return (HERE YOUR CONDITION FOR FILTERING GREEN OR RED);
},
label: function(tooltipItem, data) {
//remove body, show data only in title
},
footer: function(tooltipItems, data) {
return (HERE YOUR CONDITION FOR FILTERING GREEN OR RED);
}
}

Chart.js: Bar Chart Click Events

I've just started working with Chart.js, and I am getting very frustrated very quickly. I have my stacked bar chart working, but I can't get the click "events" to work.
I have found a comment on GitHub by nnnick from Chart.js stating to use the function getBarsAtEvent, even though this function cannot be found in the Chart.js documentation at all (go ahead, do a search for it). The documentation does mention the getElementsAtEvent function of the chart reference, but that is for Line Charts only.
I set an event listener (the right way) on my canvas element:
canv.addEventListener('click', handleClick, false);
...yet in my handleClick function, chart.getBarsAtEvent is undefined!
Now, in the Chart.js document, there is a statement about a different way to register the click event for the bar chart. It is much different than nnnick's comment on GitHub from 2 years ago.
In the Global Chart Defaults you can set an onClick function for your chart. I added an onClick function to my chart configuration, and it did nothing...
So, how the heck do I get the on-click-callback to work for my bar chart?!
Any help would be greatly appreciated. Thanks!
P.S.: I am not using the master build from GitHub. I tried, but it kept screaming that require is undefined and I was not ready to include CommonJS just so that I could use this chart library. I would rather write my own dang charts. Instead, I downloaded and am using the Standard Build version that I downloaded straight from the link at the top of the documentation page.
EXAMPLE: Here is an example of the configuration I am using:
var chart_config = {
type: 'bar',
data: {
labels: ['One', 'Two', 'Three'],
datasets: [
{
label: 'Dataset 1',
backgroundColor: '#848484',
data: [4, 2, 6]
},
{
label: 'Dataset 2',
backgroundColor: '#848484',
data: [1, 6, 3]
},
{
label: 'Dataset 3',
backgroundColor: '#848484',
data: [7, 5, 2]
}
]
},
options: {
title: {
display: false,
text: 'Stacked Bars'
},
tooltips: {
mode: 'label'
},
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
stacked: true
}
],
yAxes: [
{
stacked: true
}
]
},
onClick: handleClick
}
};
I managed to find the answer to my question by looking through the Chart.js source code.
Provided at line 3727 of Chart.js, Standard Build, is the method .getElementAtEvent. This method returns me the "chart element" that was clicked on. There is sufficent data here to determine what data to show in a drill-down view of the dataset clicked on.
On the first index of the array returned by chart.getElementAtEvent is a value _datasetIndex. This value shows the index of the dataset that was clicked on.
The specific bar that was clicked on, I believe, is noted by the value _index. In my example in my question, _index would point to One in chart_config.data.labels.
My handleClick function now looks like this:
function handleClick(evt)
{
var activeElement = chart.getElementAtEvent(evt);
..where chart is the reference of the chart created by chart.js when doing:
chart = new Chart(canv, chart_config);
The specific set of data that was selected by the click can therefore be found as:
chart_config.data.datasets[activeElement[0]._datasetIndex].data[activeElement[0]._index];
And there you have it. I now have a datapoint that I can build a query from to display the data of the bar that was clicked on.
AUGUST 7TH, 2021. UPDATE
There is now a method for what we are looking for. Take a look at here
Hi this is the click event under options which is getting values from x and y-axis
onClick: function(c,i) {
e = i[0];
console.log(e._index)
var x_value = this.data.labels[e._index];
var y_value = this.data.datasets[0].data[e._index];
console.log(x_value);
console.log(y_value);
}
I found this solution at https://github.com/valor-software/ng2-charts/issues/489
public chartClicked(e: any): void {
if (e.active.length > 0) {
const chart = e.active[0]._chart;
const activePoints = chart.getElementAtEvent(e.event);
if ( activePoints.length > 0) {
// get the internal index of slice in pie chart
const clickedElementIndex = activePoints[0]._index;
const label = chart.data.labels[clickedElementIndex];
// get value by index
const value = chart.data.datasets[0].data[clickedElementIndex];
console.log(clickedElementIndex, label, value)
}
}
}
You can use onClick like this.
var worstCells3GBoxChart = new Chart(ctx, {
type: 'bar',
data: {
labels: lbls,
datasets: [{
label: 'Worst Cells by 3G',
data: datas,
backgroundColor: getColorsUptoArray('bg', datas.length),
borderColor: getColorsUptoArray('br', datas.length),
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
onClick: function (e) {
debugger;
var activePointLabel = this.getElementsAtEvent(e)[0]._model.label;
alert(activePointLabel);
}
}
});
Chartjs V3.4.1
This is what worked for me in v3, after looking at solutions for older versions:
const onClick = (event, clickedElements) => {
if (clickedElements.length === 0) return
const { dataIndex, raw } = clickedElements[0].element.$context
const barLabel = event.chart.data.labels[dataIndex]
...
}
raw is the value of the clicked bar.
barLabel is the label of the clicked bar.
You need to pass the onClick to the bar chart config:
const barConfig = {
...
options: {
responsive: true,
onClick,
...
}
}
Well done! This seems to return the data value being charted though, which in many cases might be possible to appear more than once, thus making it unclear what was clicked on.
This will return the actual data label of the bar being clicked on. I found this more useful when drilling down into a category.
chart_config.data.labels[activeElement[0]._index]
I was able to make this work in another way.
Might not be supported, but sometimes, I find that neither the label nor the value is adequate to get me the necessary information to populate a drill-through.
So what I did was add a custom set of attributes to the data:
var ctx = document.getElementById("cnvMyChart").getContext("2d");
if(theChart != null) {theChart.destroy();}
theChart = new Chart(ctx, {
type: typ,
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datakeys: ["thefirstone","thesecondone","thethirdone","thefourthone","thefifthone","thesixthone"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
...etc
Then when I need to push the drillthrough key into another ajax call, I was able to get it with this:
var theDrillThroughKey = theChart.config.data.datakeys[activePoints[0]._index];
So I'm really not sure that it's appropriate to be adding custom elements into the data for the Chart, but it's working so far in Chrome, IE and Firefox. I needed to be able to put more information into the drillthrough than I really wanted displayed.
Example of the full thing: https://wa.rrdsb.com/chartExamples
Thoughts?
I had the same problem with multiple datasets, and used this workaround:
var clickOnChart = function(dataIndex){
...
}
var lastHoveredIndex = null;
var chart_options = {
...
tooltips: {
...
callbacks: {
label: function(tooltipItem, chart) {
var index = tooltipItem.datasetIndex;
var value = chart.datasets[index].data[0];
var label = chart.datasets[index].label;
lastHoveredIndex = index;
return value + "€";
}
}
},
onClick:function(e, items){
if ( items.length == 0 ) return; //Clicked outside any bar.
clickOnChart(lastHoveredIndex);
}
}
Let's say that you declared a chart using a method like so:
window.myBar = new Chart({chart_name}, {
type: xxx,
data: xxx,
events: ["click"],
options: {
...
}
});
A good way of declaring onclick events would involve listening for the canvas click, like so:
({chart_name}.canvas).onclick = function(evt) {
var activePoints = myBar.getElementsAtEvent(evt);
// let's say you wanted to perform different actions based on label selected
if (activePoints[0]._model.label == "label you are looking for") { ... }
}
In the chart options for Chart.js v3.5.1 which is latest
Check below sample code
let enterpriseChartOptions = {
responsive:true,
maintainAspectRatio: false,
onClick: (c,i) => {
console.log('Get the underlying label for click,', c.chart.config._config.data.labels[i[0].index]);
},
plugins: {
title:{
text:'Enterprise Dashboard (Health Status of 10 stores) updated every 30 minutes',
fontSize:20
},
},
scales: {
x: {
display: true,
type: 'category',
position: 'right',
ticks: {
padding: 8,
},
},
y: {
display: true,
ticks: {
callback: function(val, index) {
// Show the label
return val < 1 ? "All good" : (val < 2 && val >=1) ? "Warning": val === 2 ? "Critical" : "";
},
//color: 'red',
stepSize: 1,
padding: 8
}
}
},
layout: {
padding: {
left: 20,
right: 20,
top: 25,
bottom: 0
}
},
};
var employeeDetailsCtx = document.getElementById("employee-details").getContext("2d");
var employee_details_data = {
labels: ["Late Present", "On Leave", "Training", "Tour"],
datasets: [{
label: "Officer",
backgroundColor: "#5A8DEE",
data: [
...
]
}, {
label: "Staff",
backgroundColor: "#4BC0C0",
data: [
...
]
}]
};
var myoption = {
tooltips: {
enabled: true
},
hover: {
animationDuration: 1
},
onClick: function (evt, i) {
var activePoint = employeeDetailsBarChart.getElementAtEvent(evt)[0];
var data = activePoint._chart.data;
var datasetIndex = activePoint._datasetIndex;
var label = data.datasets[datasetIndex].label;
var value = data.datasets[datasetIndex].data[activePoint._index];
e = i[0];
var x_value = this.data.labels[e._index];
console.log(x_value)
console.log(label)
console.log(value)
},
animation: {
duration: 1,
onComplete: function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.textAlign = 'center';
ctx.fillStyle = "rgba(0, 0, 0, 1)";
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);
});
});
}
}
};
var employeeDetailsBarChart = new Chart(employeeDetailsCtx, {
type: 'bar',
data: employee_details_data,
options: myoption
});

Categories