Adjust appearance of tooltip in lien chart rendered by Chart.js - chart.js

Is it possible to adjust the tooltips displayed in a line chart rendered using Chart.js 2.4.0?
It recently shows both x and y value and the name of the dataset. I would need only the name of the dataset.

You can change the configuration for tooltip in options. In tooltip, we have callback object. In which, you set the title to a custom function that returns the title you want to give to the tooltip.
[sample-code]
var chartInstanceHoverModeNearest = new Chart(ctx, {
type: 'bar',
data: data,
options:{
events:["click"],
title : {
display : true
},
scales: {
xAxes: [{
categorySpacing: 0
}]
},
tooltips: {
enabled: true,
callbacks : {
title : function(){
return "Your Custom Title";
},
label : function(){
return "";
}
}
}
}
});
Below are the methods in callback object. If you want to extend more you can override these methods to give custom functionality
callbacks : {
afterBody:(),
afterFooter:(),
afterLabel:(),
afterTitle:(),
beforeBody:(),
beforeFooter:(),
beforeLabel:(),
beforeTitle:(),
footer:(),
label:(tooltipItem, data),
labelColor:(tooltipItem, chartInstance),
title:(tooltipItems, data)
}

Related

Add custom JavaScript function callback in Blazor

I'm creating a Razor component to encapsulate Chart.js. The source code is on GitHub.
At the moment I create nice chart but the problem I'm facing is about the callback. To create a new chart is quite straight forward. In the page I add the component
<Chart Config="_config1" #ref="_chart1" Id="#Id1"></Chart>
and in the code, I add the configuration for a bar chart. The object BarChartConfig is converted in a json to create the chart.
_config1 = new BarChartConfig()
{
CanvasId = Id1,
Type = ChartType.Bar,
Options = new Options()
{
Plugins = new Plugins()
{
Legend = new Legend()
{
Align = LegendAlign.Center,
Display = false,
Position = LegendPosition.Right
}
},
Scales = new Scales()
{
X = new XAxes()
{
Stacked = true,
Ticks = new Ticks()
{
MaxRotation = 0,
MinRotation = 0
}
},
Y = new YAxes()
{
Stacked = true
}
}
}
};
What I try to do now is to add some callback or function. For example, I like to add a custom function like this one in the ticks part.
const config = {
type: 'line',
data: data,
options: {
responsive: true,
plugins: {
title: {
display: true,
text: 'Chart with Tick Configuration'
}
},
scales: {
x: {
ticks: {
// For a category axis, the val is the index so the lookup via getLabelForValue is needed
callback: function(val, index) {
// Hide every 2nd tick label
return index % 2 === 0 ? this.getLabelForValue(val) : '';
},
color: 'red',
}
}
}
},
};
I'm pretty sure I can use JSInterop in some way to achieve that but I don't know how.
For example, how can I bind/add a JavaScript function at runtime?
Another nice thing I found is the user can click on the legend to exclude a category for the chart. How can I add a callback for this event?

How to dynamically update Chartjs legend label colors?

I am using vue-chartjs and chartjs-plugin-colorschemes to style a doughnut graph. I'm trying to allow the user to choose from a select which theme they prefer. I have it 90% working; the user can select a theme, hit update, and the doughnut plus its label correctly change color. What doesn't work though, is on initial page load, the doughnut has a color scheme but the legend does not.
I am currently passing a default theme down as props, and I am using a watch method to watch for changes to the theme. The error occurs inside of this watch method.
How can I dynamically update the legend label colors? Here is a minimal example of my component:
<script>
/* eslint-disable no-new */
import convert from 'convert-units';
import { Doughnut } from 'vue-chartjs';
import Chart from 'chart.js';
import { calculateCategoryWeight } from '~/helpers/functions';
import 'chartjs-plugin-colorschemes';
export default {
extends: Doughnut,
props: {
selected: {
type: Object,
default: () => {}
},
theme: {
type: String,
default: ''
}
},
data () {
const vm = this;
return {
chartData: {
labels: this.selected.categories.map(category => {
return this.$options.filters.truncate(category.name, 20);
}),
datasets: [
{
label: 'Selected Graph',
data: this.selected.categories.map(category => {
return parseFloat(convert(category).from('g').to('oz')).toFixed(2);
})
}
]
},
options: {
cutoutPercentage: 75,
legend: {
display: true,
position: 'right'
},
plugins: {
colorschemes: {
scheme: this.theme
}
},
responsive: true,
maintainAspectRatio: false,
tooltips: {
enabled: false
},
}
};
},
mounted () {
this.renderChart(this.chartData, this.options);
},
watch: {
theme (newVal, oldVal) {
const { chart } = this.$data._chart;
chart.options.plugins.colorschemes.scheme = newVal; //<--- updates chart only
chart.update();
}
}
};
</script>
Well I discovered the fix finally.
Essentially in the watch method, I was digging in too deep into the chart instance. By moving up a level in the chart object, both the legend and chart colors are both updated correctly.
watch: {
theme (newVal, oldVal) {
const chart = this.$data._chart; //<-- changed here
chart.options.plugins.colorschemes.scheme = newVal;
chart.update();
}
}

Is it possible to define data attributes for each dataset value in a Chart.js chart?

Is it possible to define HTML5 data attributes for each dataset value in a Chart.js chart? The goal is to enhance the default tooltip information (e.g. X-axis value & Y-axis value) with additional information related to the target dataset value.
In the example below, a chart is displayed that plots the total number of diapers used by 6 children. When the tooltip displays, it says the name of the child and the number of diapers. I would like the tooltip to display age and gender, as well, and figured the tooltip callback could get these from data attributes attached to each dataset value.
I've reviewed the Chart.js documentation and searched online forums, like StackOverflow, without success.
var myChart = new Chart(document.getElementById('myChart'), {
type: 'bar',
data: {
labels: ['Gabriel', 'Zelie', 'Santiago', 'Serafina', 'Berenice', 'Pia'],
datasets: [{ label: 'Diapers', data: [1050, 1224, 1382, 1166, 1471, 0] }]
},
options: {
legend: { display: false },
scales: { yAxes: [{ ticks: { beginAtZero: true } }] },
title: { display: true, text: 'Total Diapers Used' },
tooltips: {
titleFontSize: 18,
callbacks: {
label: function(tooltipItem, data) {
var defaultLabel = data.datasets[tooltipItem.datasetIndex].label + ': ' + tooltipItem.yLabel;
var age = "Age: <age>";
var gender = "Gender: <gender>";
var labels = [defaultLabel, age, gender];
return labels;
}
}
}
}
});
</script>
It depends how you structure your data. In my example I made an object that contains all the data.
let dataObject = {
Gabriel: {
diapers: 40,
age: 4
},
// Same structure here...
Zelie: {...},
Santiago: {...},
Serafina: {...},
Berenice: {...},
Pia: {...}
}
This way you can easily access your data in your tooltip with
tooltips: {
callbacks: {
label: function(tooltipItem, data){
return ['Name: '+tooltipItem.label, 'Diapers: '+tooltipItem.value, 'Age: '+dataObject[tooltipItem.label].age]
}
}
}
You should get all the information you need in the jsbin.
https://jsbin.com/qiyeyohavo/1/edit?html,js,output

Pie Chart Legend - Chart.js

I need help to put the number of the pie chart in the legend
Chart Image
If i hover the chart with mouse i can see the number relative to each item
i want to display it in the legend either
the important code so far:
var tempData = {
labels: Status,
datasets: [
{
label: "Status",
data: Qtd,
backgroundColor: randColor
},
]
};
var ctx = $("#pieStatus").get(0).getContext("2d");
var chartInstance = new Chart(ctx, {
type: 'pie',
data: tempData,
options: {
title: {
display: true,
fontsize: 14,
text: 'Total de Pedidos por Situação'
},
legend: {
display: true,
position: 'bottom',
},
responsive: false
}
});
"Qtd","randColor" are "var" already with values
You need to edit the generateLabels property in your options :
options: {
legend: {
labels: {
generateLabels: function(chart) {
// Here
}
}
}
}
Since it is quite a mess to create on your own a great template. I suggest using the same function as in the source code and then edit what is needed.
Here are a small jsFiddle, where you can see how it works (edited lines - from 38 - are commented), and its result :
Maybe this is a hacky solution, but for me seems simpler.
The filter parameter
ChartJS legend options have a filter parameter. This is a function that is called for each legend item, and that returns true/false whether you want to show this item in the legend or not.
filter has 2 arguments:
legendItem : The legend item to show/omit. Its properties are described here
data : The data object passed to the chart.
The hack
Since JS passes objects by reference, and filter is called for each legend item, then you can mutate the legendItem object to show the text that you want.
legend : {
labels: {
filter: (legendItem, data) => {
// First, retrieve the data corresponding to that label
const label = legendItem.text
const labelIndex = _.findIndex(data.labels, (labelName) => labelName === label) // I'm using lodash here
const qtd = data.datasets[0].data[labelIndex]
// Second, mutate the legendItem to include the new text
legendItem.text = `${legendItem.text} : ${qtd}`
// Third, the filter method expects a bool, so return true to show the modified legendItem in the legend
return true
}
}
}
Following on from tektiv's answer, I've modified it for ES6 which my linter requires;
options: {
legend: {
labels: {
generateLabels: (chart) => {
const { data } = chart;
if (data.labels.length && data.datasets.length) {
return data.labels.map((label, i) => {
const meta = chart.getDatasetMeta(0);
const ds = data.datasets[0];
const arc = meta.data[i];
const custom = (arc && arc.custom) || {};
const { getValueAtIndexOrDefault } = Chart.helpers;
const arcOpts = chart.options.elements.arc;
const fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
const stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
const bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
const value = chart.config.data.datasets[arc._datasetIndex].data[arc._index];
return {
text: `${label}: ${value}`,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
hidden: Number.isNaN(ds.data[i]) || meta.data[i].hidden,
index: i,
};
});
}
return [];
},
},
},
},
I wanted to let the user select from 100+ data sets, but rather than adding/removing them from my Chart I decided to set the showLine: false on any dataset that I want hidden. Unfortunately the default legend would show all 100+. So in my solution I generate the legend manually, filtering out any dataset that has showLine: false.
Your settings will have this:
legend: {
labels: {
generateLabels: (a) => {
return a.data.labels
}
}
And you'll generate your own labels with a helper function:
function updateAllLabels() {
const myNewLabels = [];
myChart.data.datasets.forEach((element) => {
if (element.showLine) {
myNewLabels.push(generateLabel(element));
}
});
myChart.data.labels = myNewLabels;
}
And you'll generate the label with another function:
function generateLabel(data) {
return {
fillStyle: data.borderColor,
lineWidth: 1,
strokeStyle: data.borderColor,
text: data.countyName, // I attach countryName to my datasets for convenience
}
}
Now just don't forget to call the function whenever updating your chart:
updateAllLabels();
myChart.update();
Happy graphing!

I want to hide the label in a tooltip because it shows undefined

I am using chart.js to show a line chart. How can I hide a tooltip label for a chart.js line chart? The label in the tooltip is showing undefined so I want to hide the label (please see the screenshot)?
Perhaps there is a way to modify tooltip where I can show only the legends value in tooltip? My code is as follows:
myLine = new Chart(ctx).Line(lineChartData, {
type: 'line',
responsive: true,
scaleShowGridLines : false,
bezierCurve : false,
animationEasing: "linear",
tooltipEvents: ["mousemove", "touchstart", "touchmove"],
showTooltips: true,
scaleLineColor: "rgba(0,0,0,.8)",
});
Just set the tooltipTitleFontSize to 0 in your options.
Preview
Script
myLine = new Chart(ctx).Line(lineChartData, {
...
tooltipTitleFontSize: 0
});
I know I am late, but I guess it still has merit to add this one.
check this : https://stackoverflow.com/a/44632748/12061669
It uses a function to hide the title:
options:{
tooltips:{
callbacks:{
title: ()=>{}
}
}
}
Setting the title's font size to zero is not ideal as you will still see an (ugly) extra space on top of the tooltip, as if the title line is still there - which honestly is what you'd expect.
Instead, I used Yumin Gui's answer but had to return null for it to work:
`
tooltips: {
callbacks: {
title: () => null,
},
},
The result is exactly as in the pie charts (which does not have a title in its default tooltips).
To hide the tooltip title/label, it should be added in the options object for that chart as follows:
options: {
plugins: {
tooltip: {
callbacks: {
title : () => null // or function () { return null; }
}
}
}
}
Do refer to the documentation to understand better that it should be handled with a custom callback function, and it is not a config that can be set in options directly.
The accepted answer won't work in newer versions of chart.js, as Aman said in comments, what you can use now is this:
tooltips: { titleFontSize: 0 }
Example:
var bar_chart = document.getElementById('bar_canvas').getContext('2d');
window.myBar = new Chart(bar_chart, {
type: 'bar',
data: bar_chart_data,
options: {
tooltips: {
titleFontSize: 0,
bodyFontSize: 14,
}
}
});