I have a line chart and I set up my tooltip like this
options: {
tooltips:{
mode: 'x',
intersect: false,
callbacks: {
footer: function(tooltipItem, data) {
return 'some text'
}
}
},
}
It works fine. The problem I have is that when I move my cursor to the x-axis ticks, which are outside the main plot/canvas, the tooltips stills appear. I've tried to set intersect: true but then the tooltip only shows up when I hover directly over the points. Ideally I want the tooltips to appear whenever I hover over the vertical gridlines (happens when intersect:false), but to not appear when my cursor moves outside of the main canvas. Is it possible?
Fiddle: https://jsfiddle.net/dqdqdq/yp47oL9t/47/
You can use the onHover callback in the options to check if the mouse is in the chartArea if so set the tooltip to enabled else disable the tooltip.
You might want to check also if the value you are setting is already the correct value since it will save a lot of unesesarry updates
Example (V2):
const updateTooltipShow = (chart, enabled) => {
chart.options.tooltips.enabled = enabled;
chart.update();
}
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [1, 2, 3, 4],
datasets: [{
data: [1, 2, 3, 4],
backgroundColor: "rgba(153,255,51,0.6)"
},
]
},
options: {
onHover: function(e, activeElements) {
const {
bottom,
top,
right,
left
} = this.chartArea;
if (e.x >= left && e.x <= right && e.y <= bottom && e.y >= top) {
updateTooltipShow(this, true)
} else {
updateTooltipShow(this, false)
}
},
tooltips: {
mode: 'x',
intersect: false,
callbacks: {
footer: function(tooltipItem, data) {
return 'some text'
}
}
},
}
});
<canvas id="myChart"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.2.0/dist/chartjs-plugin-datalabels.min.js"></script>
Example (V3):
const updateTooltipShow = (chart, enabled) => {
chart.options.plugins.tooltip.enabled = enabled;
chart.update();
}
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [1, 2, 3, 4],
datasets: [{
data: [1, 2, 3, 4],
backgroundColor: "rgba(153,255,51,0.6)"
},
]
},
options: {
onHover: (e, activeElements, chart) => {
const {
bottom,
top,
right,
left
} = chart.chartArea;
if (e.x >= left && e.x <= right && e.y <= bottom && e.y >= top) {
updateTooltipShow(chart, true)
} else {
updateTooltipShow(chart, false)
}
},
plugins: {
tooltip: {
mode: 'x',
intersect: false,
callbacks: {
footer: function(tooltipItem, data) {
return 'some text'
}
}
},
}
}
});
<canvas id="myChart"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
I wrote a simple plugin for hiding the caption when you move your cursor out of the main canvas:
plugins: [{
id: "toolbarHider",
afterEvent: (chart: any, evt: any, opts: any) => {
const { left, right, bottom, top } = chart.chartArea;
const e = evt.event;
const status = e.x >= left && e.x <= right && e.y <= bottom && e.y >= top;
if (status !== chart.options.plugins.tooltip.enabled) {
chart.options.plugins.tooltip.enabled = status;
chart.update();
}
}
}]
More about Chart.js plugins.
Related
This bounty has ended. Answers to this question are eligible for a +50 reputation bounty. Bounty grace period ends in 3 hours.
Software Dev wants to draw more attention to this question.
I have a bar chart in Chart.js (using the latest version), and I want to make some visual change when the mouse is hovering over a category label. How would I implement either or both of the following visual changes?
Make the cursor be a pointer while hovering over a label.
Make the label be in a different color while it is being hovered on.
A related question is here: How to detect click on chart js 3.7.1 axis label?. However, my question is about hovering over a label, without clicking on the label.
In the example below, I want something to happen when hovering on these texts: Item A, Item B, Item C.
window.onload = function() {
var ctx = document.getElementById('myChart').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Item A', 'Item B', 'Item C'],
datasets: [{
data: [1, 2, 3],
backgroundColor: 'lightblue'
}]
},
options: {
responsive: true,
indexAxis: 'y',
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
},
}
}
});
};
.chart-container {
position: relative;
height: 90vh;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#4.2.0"></script>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
You can just use the custom plugin from that question and ignore everything but mousemove events instead of ignoring everything but click events:
const findLabel = (labels, evt) => {
let found = false;
let res = null;
labels.forEach(l => {
l.labels.forEach((label, index) => {
if (evt.x > label.x && evt.x < label.x2 && evt.y > label.y && evt.y < label.y2) {
res = {
label: label.label,
index
};
found = true;
}
});
});
return [found, res];
};
const getLabelHitboxes = (scales) => (Object.values(scales).map((s) => ({
scaleId: s.id,
labels: s._labelItems.map((e, i) => ({
x: e.translation[0] - s._labelSizes.widths[i],
x2: e.translation[0] + s._labelSizes.widths[i] / 2,
y: e.translation[1] - s._labelSizes.heights[i] / 2,
y2: e.translation[1] + s._labelSizes.heights[i] / 2,
label: e.label,
index: i
}))
})));
const plugin = {
id: 'customHover',
afterEvent: (chart, event, opts) => {
const evt = event.event;
if (evt.type !== 'mousemove') {
return;
}
const [found, labelInfo] = findLabel(getLabelHitboxes(chart.scales), evt);
if (found) {
console.log(labelInfo);
}
}
}
Chart.register(plugin);
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange'
}
]
},
options: {}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>
To change the cursor to a pointer when hovering over a category label in a Chart.js bar chart, you can add:
options: {
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
},
interaction: {
mode: 'index',
intersect: false
},
onHover: function(evt, elements) {
if (elements.length) {
document.getElementById("myChart").style.cursor = "pointer";
} else {
document.getElementById("myChart").style.cursor = "default";
}
},
// ...
}
To change the color of a label when it is being hovered on, you can add:
options: {
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
},
interaction: {
mode: 'index',
intersect: false
},
onHover: function(evt, elements) {
if (elements.length) {
var chart = evt.chart;
var datasetIndex = elements[0].datasetIndex;
var index = elements[0].index;
chart.data.labels[index] = '<span style="color: red;">' + chart.data.labels[index] + '</span>';
chart.update();
} else {
var chart = evt.chart;
chart.data.labels = ['Item A', 'Item B', 'Item C'];
chart.update();
}
},
// ...
}
To make the cursor a pointer while hovering over a label, you can try to assign a CSS cursor value to event.native.target.style.cursor when hover is triggered.
event.native.target.style.cursor = 'pointer';
To make the label a different color while it is being hovered on, you can try this
myChart.config.options.scales.y.ticks.color = hoverColors; // ['black','red','black'], ['black','black','red'], ['red','black','black']
UPDATE
Thanks to LeeLenalee for giving an almost correct answer. I've edited the code above so it fits what is required in the problem. Don't forget to change source of the library in the HTML from :
https://cdn.jsdelivr.net/npm/chart.js#4.2.0
to :
https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js
Updated code:
window.onload = function() {
const findLabel = (labels, evt) => {
let found = false;
let res = null;
try {
labels.forEach(l => {
l.labels.forEach((label, index) => {
if (evt.x > label.x && evt.x < label.x2 && evt.y > label.y && evt.y < label.y2) {
res = {
label: label.label,
index
};
found = true;
}
});
});
} catch (e) {}
return [found, res];
};
const getLabelHitboxes = (scales) => {
try {
return Object.values(scales).map((s) => ({
scaleId: s.id,
labels: s._labelItems.map((e, i) => ({
x: e.translation[0] - s._labelSizes.widths[i],
x2: e.translation[0] + s._labelSizes.widths[i] / 2,
y: e.translation[1] - s._labelSizes.heights[i] / 2,
y2: e.translation[1] + s._labelSizes.heights[i] / 2,
label: e.label,
index: i
}))
}));
} catch (e) {}
};
const changeCursorAndLabelColor = (event, chart, index, hoverMode) => {
// your hover color here
// const hoverColor = '#ff0000';
const hoverColor = 'red';
const hoverColors = [];
for (let i = 0; i < myChart.data.datasets[0].data.length; i++) {
if (hoverMode) {
// change cursor
event.native.target.style.cursor = 'pointer';
if (index === i) {
hoverColors.push(hoverColor);
} else {
hoverColors.push(defaultLabelColor);
}
} else {
// change cursor
event.native.target.style.cursor = 'default';
hoverColors.push(defaultLabelColor);
}
}
// change label to your hover color
myChart.config.options.scales.y.ticks.color = hoverColors;
// update chart when hover is triggered
myChart.update();
}
let foundMode = false;
const plugin = {
id: 'customHover',
afterEvent: (chart, event, opts) => {
const evt = event.event;
if (evt.type !== 'mousemove') {
return;
}
const [found, labelInfo] = findLabel(getLabelHitboxes(chart.scales), evt);
if (found && myChart.data.labels.includes(labelInfo.label)) {
changeCursorAndLabelColor(evt, chart, labelInfo.index, true);
foundMode = true;
} else {
if (foundMode) changeCursorAndLabelColor(evt, chart, null, false);
foundMode = false;
}
}
}
Chart.register(plugin);
var ctx = document.getElementById('myChart');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Item A', 'Item B', 'Item C'],
datasets: [{
label: 'My Data',
data: [1, 2, 3],
backgroundColor: 'lightblue'
}]
},
options: {
responsive: true,
indexAxis: 'y',
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
},
},
onHover: (event, chart) => {
if (foundMode) changeCursorAndLabelColor(event, chart, null, false);
foundMode = false;
}
}
});
const defaultLabelColor = myChart.config.options.scales.y.ticks.color;
};
.chart-container {
position: relative;
height: 90vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
I can't figure out why I'm not able to remove this random padding injected inside my line chart in Chart.js (file attached).
Here is a part of my chart configuration :
myChart.current = new Chart(canvasRef.current, {
type: "line",
data,
options: {
tension: 0.6,
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,
external: (context) => {
const tooltipModel = context.tooltip;
if (tooltipModel.opacity === 0) {
setShowTooltip(false);
return;
}
setShowTooltip(true);
const tooltipEl = tooltipRef.current;
const currentTooltipWidth = tooltipEl.clientWidth;
const currentTooltipHeight = tooltipEl.clientHeight;
const currentTooltipCenterAlign = currentTooltipWidth / 2;
let left =
tooltipModel.dataPoints[0].element.x -
currentTooltipCenterAlign;
if (left < 0) {
left = Math.abs(left);
}
let top =
tooltipModel.dataPoints[0].element.y -
currentTooltipHeight -
offsetY;
if (top < 0) {
top = tooltipModel.dataPoints[0].element.y + offsetY;
}
const date = tooltipModel.dataPoints[0].label;
const value = tooltipModel.dataPoints[0].raw;
setPositionAndData(top, left, date, value);
},
},
},
},
});
Thank you very much for your help :) !
[1]: https://i.stack.imgur.com/lNi5p.png
on Bar click event of first chart "config.categoriesChart" gets the console error "chart.js:10403 Uncaught TypeError: Cannot read property 'handleEvent' of undefined"
enter image description here which diplayed as chart.legend.handleEvent(args.event);
The issue happens after destroy the First chart on the bar click Event of first chart.
But if I use $('#how_i_spend_canvas').replaceWith($(''));
its working fine without destroy the chart.
enter image description here
Please let me what is the issue?
All code in document.ready
let Chart = require('chart.js');/
let ChartDataLabels = require('chartjs-plugin-datalabels');
let config = window.MvpFE.globalConfiguration.howISpend;
let dataChart = window.dataHowISpendCharts;
let labels = dataChart.howISpendDataCatgories.map(function (e) {
return e.label;
});
let data = dataChart.howISpendDataCatgories.map(function (e) {
return e.data;
});
//Chart Axis's
let scales = {
x: {
ticks: {
font: {
size: config.size,
},
color: config.dataLabelsColor,
},
},
y: {
display: false,
}
};
//Chart legend
let plugins = {
legend: {
display: false,
},
tooltip: {
enabled: true,
},
};
//Chart Data Labels
let dataLabels = {
color: config.dataLabelsColor,
anchor: 'end',
align: 'top',
offset: 0,
formatter: function (value) {
//Include a dollar sign
return '$' + value.toLocaleString();
},
};
//chart data
let howISpendChartdata = {
labels: labels,
datasets: [{
data: data,
backgroundColor: config.catogriesBackgroundColor,
borderColor: config.catogriesBorderColor,
hoverBackgroundColor: config.unSelectedColor,
hoverBorderColor: config.unSelectedColor,
borderWidth: config.barWidth,
borderRadius: config.barRadius,
borderSkipped: 'false',
datalabels: dataLabels
}]
}
// Category heading label text will be from json data
let categoryLabel = "";
//Array to store the bar background colors.
const barColors = [];
//Code to draw Chart
var ctx = document.getElementById('how_i_spend_canvas').getContext('2d');
config.categoriesChart = new Chart(ctx, {
type: 'bar',
data: howISpendChartdata,
// Chart pulgins & Options
plugins: [ChartDataLabels],
options: {
responsive: true,
maintainAspectRatio: false,
aspectRatio: 2,
plugins: plugins,
scales: scales,
onClick: function (evt, element) {
if (element.length > 0) {
const categoriesChart = config.categoriesChart;
let activeBarIndex = element[0].index;
categoryLabel = categoriesChart.data.labels[activeBarIndex];
// destroy any chart instances that are created
if (categoriesChart instanceof Chart) {
categoriesChart.destroy();
}
//$('#how_i_spend_canvas').replaceWith($('<canvas id="SelectedCategory" height="400px"></canvas>')); //replace current canvas
// Code to draw Chart
config.monthlyChart = new Chart(ctx, {
type: 'bar',
data: howISpendChartdata,
plugins: [ChartDataLabels],
options: {
responsive: true,
maintainAspectRatio: false,
aspectRatio: 2,
plugins: plugins,
scales: scales,
onClick: function (e, activeElements) {
//get the colors for bars
if (activeElements.length > 0) { // check the element is selected
const monthlyChart = config.monthlyChart;
monthlyChart.options.animation.colors = false;
monthlyChart.update();
}
}
}
},
});
config.monthlyChart.render();
}
},
}
}); // document.Ready Ends()
WARNING: This solution makes sense only if you're not using the legend plugin or don't need to handle legend item click event.
In my case I was getting this error even though I disabled legend plugin in chart options, like this:
plugins: {
legend: {
display: false
}
}
The error stopped happening after I filtered events handled by the legend plugin, like this:
plugins: {
legend: {
display: false,
events: [] // this line was the key
},
}
I came accros the same issue, reason for the exception is:
Inside the onclick event if you try to destroy the same chart, chart reference becomes null before the event callback function returns. And that's why exception is thrown.
You can fix this by destroying the chart instance after the event callback is completed i.e. using setTimeout function you can destroy the chart after 100ms or so. you can do it like this:
options: {
onClick: function (evt, element) {
if (element.length > 0) {
const categoriesChart = config.categoriesChart;
let activeBarIndex = element[0].index;
categoryLabel = categoriesChart.data.labels[activeBarIndex];
setTimeout(() => {
// destroy any chart instances that are created
if (categoriesChart instanceof Chart) {
categoriesChart.destroy();
}
//$('#how_i_spend_canvas').replaceWith($('<canvas id="SelectedCategory" height="400px"></canvas>')); //replace current canvas
// Code to draw Chart
config.monthlyChart = new Chart(ctx, {
type: 'bar',
data: howISpendChartdata,
plugins: [ChartDataLabels],
options: {
responsive: true,
maintainAspectRatio: false,
aspectRatio: 2,
plugins: plugins,
scales: scales,
onClick: function (e, activeElements) {
//get the colors for bars
if (activeElements.length > 0) { // check the element is selected
const monthlyChart = config.monthlyChart;
monthlyChart.options.animation.colors = false;
monthlyChart.update();
}
}
}
});
config.monthlyChart.render();
}, 100);
}
}
}
Below is solution for anyone facing similar problem:
options: {
onClick: function (evt, element) {
// get the require data from click event
let chart = Chart.getChart(e.chart.canvas.id);
const points = chart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (points.length) {
const firstPoint = points[0];
const elementIndex = firstPoint.index;
const datasetIndex = firstPoint.datasetIndex;
const dataset = chart.data.datasets[datasetIndex];
const datasetFieldLabel = dataset.label;
const itemLabel = chart.data.labels[elementIndex];
const itemValue = dataset.data[elementIndex];
setTimeout(() => {
// destroy the chart
// Render another chart
}, 100);
}
}
}
I have a graph created with Chart.js. There are options and one of them 'responsive: true' that provides a responsive view. The problem is when I load a graph with data the first time the y-ax labels overflow border and show as on the screen below. When I change the view y-ax labels show with overflow hidden and elepsis at the end of the label.
Also, I need to add a custom baloon for labels, how can I do it?
Before view change:
After view change:
Here is my chank of code:
drawWordsChart: function(placeholder, data, options = {}) {
console.log('drawWordsChart', data);
var sortable = [];
for (var word in data) {
sortable.push([data[word].text, data[word].weight]);
}
sortable.sort(function(a, b) {
return b[1] - a[1];
});
sortable = sortable.slice(0, 20);
let labels = [];
let values = [];
let colors = [], intense = 1;
angular.forEach(sortable, (elem, key) => {
colors.push('rgb(30, 144, 255,' + (intense - key / 20) + ')');
labels.push(elem[0]);
values.push(elem[1]);
});
var horizontalBarChartData = {
labels: labels,
datasets: [{
label: options.label || 'weight',
backgroundColor: colors,
borderColor: colors,
data: values
}]
};
const ctx = document.getElementById(placeholder).getContext('2d');
const myHorizontalBar = new Chart(ctx, {
type: options.type || 'horizontalBar',
data: horizontalBarChartData,
options: {
elements: {
rectangle: {
borderWidth: 1,
}
},
responsive: true,
legend: {
position: 'right',
display: false
},
scales: {
yAxes: [{
barPercentage: 0.1,
barThickness: 10,
maxBarThickness: 10,
minBarLength: 2,
gridLines: {
offsetGridLines: true
},
ticks: {
callback: function(value, index, values) {
return $filter('limitTo')(value, 8) + (value.length > 8 ? '...' : '');
}
}
}]
},
maintainAspectRatio: false
}
});
return myHorizontalBar;
}
Here I added property 'ticks' in options with callback, which limiting value to 8 letters, and add ellipsis at the end. Also, I added a custom filter.
ticks: {
callback: function(value, index, values) {
return $filter('limitTo')(value, 8) + (value.length > 8 ? '...' : '');
}
}
I'm creating a Stacked bar chart. Everything is working as expected except the tooltips. One bar is behind the other one (Kinda like a progress bar) and the problem is that once one bar is getting closer to the other one, the tooltips overlap. So, my question is if I can set "yAlign" position for each data(or each bar) so that I can display the tooltips on the top for one set of bars, and on the bottom to the other set of bars.
Here's my code:
<script>
var ctx = document.getElementById("examples").getContext('2d');
var data = {
labels:[
"A", "B", "C",],
datasets: [{
label: false,
data: [40, 110, 18],
backgroundColor: [
'rgba(255, 99, 132, 0.7)',
'rgba(158, 112, 225, 0.7)',
'rgba(174, 122, 215, 0.7)',
]
},
{
label: false,
data: [100, 200, 50],
backgroundColor: [
'rgb(128,128,128)',
'rgb(128,128,128)',
'rgb(128,128,128)',
]
},
]
};
var currentX = null;
var currentY = null;
var customTooltips = function (tooltip) {
var helpers = Chart.helpers;
var ctx = this._chart.ctx;
var vm = this._view;
if (vm == null || ctx == null || helpers == null || vm.opacity === 0) {
return;
}
var tooltipSize = this.getTooltipSize(vm);
var pt = {
x: vm.x,
y: vm.y
};
if (currentX == vm.x && currentY == vm.y) {
return;
}
currentX = vm.x;
currentY = vm.y;
// IE11/Edge does not like very small opacities, so snap to 0
var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
// Draw Background
var bgColor = helpers.color(vm.backgroundColor);
ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
ctx.fill();
// Draw Caret
this.drawCaret(pt, tooltipSize, opacity);
// Draw Title, Body, and Footer
pt.x += vm.xPadding;
pt.y += vm.yPadding;
// Titles
this.drawTitle(pt, vm, ctx, opacity);
// Body
this.drawBody(pt, vm, ctx, opacity);
// Footer
this.drawFooter(pt, vm, ctx, opacity);
};
Chart.plugins.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) {
// This line checks if the item is visible to display the tooltip
if(!tooltip._active[0].hidden){
tooltip.initialize();
// tooltip._options.position = "outer";
// tooltip._options.displayColors = false;
// tooltip._options.bodyFontSize = tooltip._chart.height*0.025;
//tooltip._options.yPadding = tooltip._options.bodyFontSize*0.30;
// tooltip._options.xPadding = tooltip._options.bodyFontSize*0.30;
//tooltip._options.caretSize = tooltip._options.bodyFontSize*0.5;
//tooltip._options.cornerRadius = tooltip._options.bodyFontSize*0.50;
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: 'bar',
data: data,
options: {
showAllTooltips: true,
legend: {
display: false
},
tooltips: {
titleFontSize: 10,
bodyFontSize: 10,
pointHitDetectionRadius : 3,
yAlign: 'top',
responsive: false,
customTool: customTooltips,
callbacks: {
title: function() {}
},
},
scales:{
xAxes: [{
stacked: true,
ticks: {
beginAtZero: true
},}]
},
}
});
</script>
JSFiddle: https://jsfiddle.net/560gortq/2/