Closed kerron closed 8 years ago
At the moment, there is no way to do this. I'd be happy to look over a PR adding this.
thanks @etimberg!
@kerron if you want to try modifying the library yourself, I'd suggest looking at Core.Tooltip.draw
or Core.Tooltip.update
in https://github.com/nnnick/Chart.js/blob/v2.0-dev/src/core/core.tooltip.js
I'd be happy to look at a PR adding this functionality
Update: see this answer: http://stackoverflow.com/a/37297802/1827284**
I modify the library to do this:
First I add tooltip
option to _model
in updateElement
function of each type (radar, doughnut, line...). Bar example:
Chart.controllers.bar = Chart.DatasetController.extend({
updateElement: function updateElement(rectangle, index, reset, numBars) {
...
helpers.extend(rectangle, {
...
// Desired view properties
_model: {
...
// Tooltip
label: this.chart.data.labels[index],
datasetLabel: this.getDataset().label,
tooltip: this.getDataset().tooltip, // Line added !!
...
Then I modify Core.Tooltip.draw to add showTooltip
condition to if
:
Chart.Tooltip = Chart.Element.extend({
...
draw: function draw() {
...
// Check if show dataset tooltip
var showTooltip = (this._active[0] && this._active[0]._model.tooltip !== false);
if (this._options.tooltips.enabled && showTooltip) {
Finally I define this option in my datasets:
this.myChart = new Chart(this.ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [
{ type: 'line', data: data3 },
{ type: 'bar', data: data1, backgroundColor: "#3EAFD5" , tooltip: false},
{ type: 'bar', data: data2, backgroundColor: "#D24B47", tooltip: false}
]
}
}
Hi, I'm on v2.5, I have a multi datasets in a line chart, and I just wanna show tooltip for one dataset, your solution doesn't work for me, here's my code
data: {
labels: labels,
datasets: [
{ data: data3 },
{ data: data1, backgroundColor: "#3EAFD5" , tooltip: false},
{ data: data2, backgroundColor: "#D24B47", tooltip: false}
]
}
Any idea?
@qiluo I suggest you using the option filter
that you can find in the tooltip documentation:: http://www.chartjs.org/docs/#chart-configuration-tooltip-configuration
@qiluo try:
options: {
tooltips: {
filter: function (tooltipItem) {
return tooltipItem.datasetIndex === 0;
}
}
}
hi guys, I successfully hide the tooltip now with above method, thanks
I am using the above approach to filter points from the tooltip, but I want to not show the tooltip at all when all points have been filtered out. Right now i'm getting an empty tooltip.
IE: I have a line chart with multiple datasets and a feature to highlight one line by clicking on it and when a line is highlighted only tooltips for that dataset are visible.
Hey guys, the solution of @andrei-kondakov was not enough in my case. Also a custom tooltip must be added which resets some tooltip styles like
tooltips: {
custom: function(tooltipModel) {
// EXTENSION: filter is not enough! Hide tooltip frame
if (!tooltipModel.body || tooltipModel.body.length < 1) {
tooltipModel.caretSize = 0;
tooltipModel.xPadding = 0;
tooltipModel.yPadding = 0;
tooltipModel.cornerRadius = 0;
tooltipModel.width = 0;
tooltipModel.height = 0;
}
},
// Hide tooltip body
filter: function(tooltipItem, data) {
return !data.datasets[tooltipItem.datasetIndex].tooltipHidden; // custom added prop to dataset
}
Have a look at my sample https://jsfiddle.net/Lq3aptph/
The solution of @thomasjoscht works perfectly! Only thing I have to add is that you need to add hoverRadius: 0
to the dataset that you are hiding the tooltips from to prevent the increase in size upon hovering.
This is only the case when you want to have that dataset visible ofcourse, in the fiddle the dataset is completely opaque, making this unnecessary.
@andrei-kondakov you saved my life. Thank you!
@Evertvdw Where did you add hoverRadius: 0
? I am using @thomasjoscht hack for line charts as well as for pie charts...
You can search the docs for hoverRadius
: https://www.chartjs.org/docs/latest/configuration/elements.html#point-configuration
I thought I'd contribute some. I have 3 datasets and I created a 4th one as a trendline, but I didn't want to show that in the legend or in the basic tooltip. Using this code, I was able to get what I wanted. Legend and the default tooltip only show the first 3 datasets, but the line is still there on the line chart.
plugins: {
legend: {
align: 'center',
position: 'bottom',
labels: {
padding: 20,
boxWidth: 30,
color: theme.palette.text.primary,
usePointStyle: true,
filter: function(item, chart) {
// Logic to remove a particular legend item goes here
return !item.text.includes('Trend');
}}
},
tooltip: {
filter: function (tooltipItem) {
return [0, 1, 2].includes(tooltipItem.datasetIndex);
},
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label = ' ' + label; // Add a space at the beginning
}
if (context.parsed.y !== null) {
label += ': ' + abbreviateNumber(`${context.parsed.y}`);
}
return label;
}
}
},
}
Just in case someone comes across this like me and has some questions / it's still not working / not a perfect solution, I have found the perfect solution for me. I will be more verbose to reduce questions.
"dependencies": { "bootstrap": "^5.3.2", "chart.js": "^4.4.0", "core-js": "^3.8.3", "superagent": "^8.1.2", "vue": "^3.2.13", "vue-chartjs": "^5.2.0" },
App.vue relevant snippet:
<BarChart v-if="dataLoaded" :items="items" dataset="Service" id="service-chart" />
<BarChart v-if="dataLoaded" :items="items" dataset="Customer" id="service-chart" />
Relevant to the question of filtering values within datasets:
plugins: {
tooltip: {
filter: function (tooltipItem) { // we don't need 'data'
return tooltipItem.dataset.data[tooltipItem.dataIndex] > 0; // i am displaying all values greater than 0. zero is filtered.
},
callbacks: {
footer: helpers.tooltipFooter, // the helpers.tooltipFooter is defined in helpers.js
},
}
},
And this code for me was within the BarChart.vue component:
<script>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
import helpers from './../helpers';
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
export default {
name: 'BarChart',
components: { Bar },
props: {
items: {},
dataset: String, // this is used to "swap" datasets and labels
},
data() {
return {
data: {
labels: {},
datasets: {}
},
dataLoaded: false, // chart will be empty because of async data loading from a db or api.
options: {
interaction: {
intersect: false,
mode: 'x', // when hovering over a x-value, tooltip will display regardless of being on the bar or not.
},
plugins: {
tooltip: {
filter: function (tooltipItem) { // we don't need 'data'
return tooltipItem.dataset.data[tooltipItem.dataIndex] > 0; // i am displaying all values greater than 0. zero is filtered.
},
callbacks: {
footer: helpers.tooltipFooter, // the helpers.tooltipFooter is defined in helpers.js
},
}
},
responsive: true,
scales: {
x: {
stacked: true,
},
y: {
stacked: true,
beginAtZero: true,
title: {
display: true,
text: 'CHF', // CHF is the Swiss currency symbol. Use USD, EUR, MXN, GBP, BTC, ...
},
}
}
},
}
},
mounted() {
if (this.dataset === "Customer") {
// Create an object to store prices for all services dynamically
const pricesByService = {};
// Populate prices for all services
this.items.forEach((item) => {
const customerName = item.companyName;
const serviceName = item.serviceName;
const price = item.price;
// Create an object for the service if it doesn't exist
if (!pricesByService[serviceName]) {
pricesByService[serviceName] = {};
}
// Add the price for the customer of the service
pricesByService[serviceName][customerName] = price;
});
// Get unique customer names and sort them alphabetically
const customerNames = Array.from(
new Set(this.items.map((item) => item.companyName))
).sort();
// Create datasets for all services
const datasets = Object.keys(pricesByService).map((service) => ({
label: service,
backgroundColor: helpers.stringToColor(service),
data: customerNames.map((customerName) =>
pricesByService[service][customerName] || 0
),
}));
this.data.labels = customerNames;
this.data.datasets = datasets;
this.dataLoaded = true; // the data is loaded, so now the component can render the chart. notice v-if="dataLoaded"
}
if (this.dataset === "Service") {
// ... basically the same code as "Customer" again but swaped data.labels and data.datasets with the magic of chatgeepetee ...
}
},
}
</script>
'./../helpers.js'
const tooltipFooter = (tooltipItems) => {
let sum = 0;
tooltipItems.forEach(function(tooltipItem) {
sum += tooltipItem.parsed.y;
});
return 'CHF ' + sum;
};
// stringToColor such that the datasets backgroundcolor values persist over time yet are derrived from the data.
// because md5 hashes are hexadecimal in nature, we can just use the first 6 values with slice after a '#'
const stringToColor = (str) => {
let md5string = md5(str);
let color = `#${md5string.slice(0, 6)}`;
return color;
}
// md5 function by [dkellner](https://stackoverflow.com/users/1892607/dkellner) is exactly 42 lines long and has a size of 4000.
const md5 = (inputString) => {
var hc="0123456789abcdef";
function rh(n) {var j,s="";for(j=0;j<=3;j++) s+=hc.charAt((n>>(j*8+4))&0x0F)+hc.charAt((n>>(j*8))&0x0F);return s;}
function ad(x,y) {var l=(x&0xFFFF)+(y&0xFFFF);var m=(x>>16)+(y>>16)+(l>>16);return (m<<16)|(l&0xFFFF);}
function rl(n,c) {return (n<<c)|(n>>>(32-c));}
function cm(q,a,b,x,s,t) {return ad(rl(ad(ad(a,q),ad(x,t)),s),b);}
function ff(a,b,c,d,x,s,t) {return cm((b&c)|((~b)&d),a,b,x,s,t);}
function gg(a,b,c,d,x,s,t) {return cm((b&d)|(c&(~d)),a,b,x,s,t);}
function hh(a,b,c,d,x,s,t) {return cm(b^c^d,a,b,x,s,t);}
function ii(a,b,c,d,x,s,t) {return cm(c^(b|(~d)),a,b,x,s,t);}
function sb(x) {
var i;var nblk=((x.length+8)>>6)+1;var blks=new Array(nblk*16);for(i=0;i<nblk*16;i++) blks[i]=0;
for(i=0;i<x.length;i++) blks[i>>2]|=x.charCodeAt(i)<<((i%4)*8);
blks[i>>2]|=0x80<<((i%4)*8);blks[nblk*16-2]=x.length*8;return blks;
}
var i,x=sb(""+inputString),a=1732584193,b=-271733879,c=-1732584194,d=271733878,olda,oldb,oldc,oldd;
for(i=0;i<x.length;i+=16) {olda=a;oldb=b;oldc=c;oldd=d;
a=ff(a,b,c,d,x[i+ 0], 7, -680876936);d=ff(d,a,b,c,x[i+ 1],12, -389564586);c=ff(c,d,a,b,x[i+ 2],17, 606105819);
b=ff(b,c,d,a,x[i+ 3],22,-1044525330);a=ff(a,b,c,d,x[i+ 4], 7, -176418897);d=ff(d,a,b,c,x[i+ 5],12, 1200080426);
c=ff(c,d,a,b,x[i+ 6],17,-1473231341);b=ff(b,c,d,a,x[i+ 7],22, -45705983);a=ff(a,b,c,d,x[i+ 8], 7, 1770035416);
d=ff(d,a,b,c,x[i+ 9],12,-1958414417);c=ff(c,d,a,b,x[i+10],17, -42063);b=ff(b,c,d,a,x[i+11],22,-1990404162);
a=ff(a,b,c,d,x[i+12], 7, 1804603682);d=ff(d,a,b,c,x[i+13],12, -40341101);c=ff(c,d,a,b,x[i+14],17,-1502002290);
b=ff(b,c,d,a,x[i+15],22, 1236535329);a=gg(a,b,c,d,x[i+ 1], 5, -165796510);d=gg(d,a,b,c,x[i+ 6], 9,-1069501632);
c=gg(c,d,a,b,x[i+11],14, 643717713);b=gg(b,c,d,a,x[i+ 0],20, -373897302);a=gg(a,b,c,d,x[i+ 5], 5, -701558691);
d=gg(d,a,b,c,x[i+10], 9, 38016083);c=gg(c,d,a,b,x[i+15],14, -660478335);b=gg(b,c,d,a,x[i+ 4],20, -405537848);
a=gg(a,b,c,d,x[i+ 9], 5, 568446438);d=gg(d,a,b,c,x[i+14], 9,-1019803690);c=gg(c,d,a,b,x[i+ 3],14, -187363961);
b=gg(b,c,d,a,x[i+ 8],20, 1163531501);a=gg(a,b,c,d,x[i+13], 5,-1444681467);d=gg(d,a,b,c,x[i+ 2], 9, -51403784);
c=gg(c,d,a,b,x[i+ 7],14, 1735328473);b=gg(b,c,d,a,x[i+12],20,-1926607734);a=hh(a,b,c,d,x[i+ 5], 4, -378558);
d=hh(d,a,b,c,x[i+ 8],11,-2022574463);c=hh(c,d,a,b,x[i+11],16, 1839030562);b=hh(b,c,d,a,x[i+14],23, -35309556);
a=hh(a,b,c,d,x[i+ 1], 4,-1530992060);d=hh(d,a,b,c,x[i+ 4],11, 1272893353);c=hh(c,d,a,b,x[i+ 7],16, -155497632);
b=hh(b,c,d,a,x[i+10],23,-1094730640);a=hh(a,b,c,d,x[i+13], 4, 681279174);d=hh(d,a,b,c,x[i+ 0],11, -358537222);
c=hh(c,d,a,b,x[i+ 3],16, -722521979);b=hh(b,c,d,a,x[i+ 6],23, 76029189);a=hh(a,b,c,d,x[i+ 9], 4, -640364487);
d=hh(d,a,b,c,x[i+12],11, -421815835);c=hh(c,d,a,b,x[i+15],16, 530742520);b=hh(b,c,d,a,x[i+ 2],23, -995338651);
a=ii(a,b,c,d,x[i+ 0], 6, -198630844);d=ii(d,a,b,c,x[i+ 7],10, 1126891415);c=ii(c,d,a,b,x[i+14],15,-1416354905);
b=ii(b,c,d,a,x[i+ 5],21, -57434055);a=ii(a,b,c,d,x[i+12], 6, 1700485571);d=ii(d,a,b,c,x[i+ 3],10,-1894986606);
c=ii(c,d,a,b,x[i+10],15, -1051523);b=ii(b,c,d,a,x[i+ 1],21,-2054922799);a=ii(a,b,c,d,x[i+ 8], 6, 1873313359);
d=ii(d,a,b,c,x[i+15],10, -30611744);c=ii(c,d,a,b,x[i+ 6],15,-1560198380);b=ii(b,c,d,a,x[i+13],21, 1309151649);
a=ii(a,b,c,d,x[i+ 4], 6, -145523070);d=ii(d,a,b,c,x[i+11],10,-1120210379);c=ii(c,d,a,b,x[i+ 2],15, 718787259);
b=ii(b,c,d,a,x[i+ 9],21, -343485551);a=ad(a,olda);b=ad(b,oldb);c=ad(c,oldc);d=ad(d,oldd);
}
return rh(a)+rh(b)+rh(c)+rh(d);
}
export default { stringToColor, md5, tooltipFooter };
Result:
plugins: {
tooltip: {
callbacks:{
label :((tooltipItem ,data)=>{
console.log("label" , tooltipItem.dataset.label)
if(tooltipItem.dataset.label=== 'poids' && this.unitepoids === 'mm'){
return ''
}
})
}
},
}
Is there a way I can hide the tooltip of a specific datasets in v2-beta? I can hide the data using the callback functions, but this still leaves a tooltip, albeit empty.
Is there a way to hide its entirety?