I tried creating custom tooltip. The below code provides a tooltip with scrollbar, but unable to scroll through the tooltip. Not sure what I missed.
There is a callback function which provided a list of item that I have to display in the tool tip. But the tooltip does not scroll. It only gives a scrollbar at the right but on trying to scroll thorough, the list stays still.
import React from 'react';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js';
import { Bar } from 'react-chartjs-2';
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);
interface IChartProps {
xAxis: any[]
yAxis: any[]
horizontal: boolean
height: string
width: string
tooltip: any | undefined
}
function BarGraph(props: IChartProps) {
let options: any = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top',
},
title: {
display: false,
text: ' Bar-Chart',
},
},
scales: {
x: {
grid: { display: false },
ticks: {
autoSkip: false,
},
},
y: {
grid: { display: false },
ticks: {
// callback: function(value: any) {
// return value.substring(0, 5);
// },
// maxRotation: 0,
// minRotation: 0,
autoSkip: false,
},
}
},
}
const getOrCreateTooltip = (chart: any) => {
let tooltipEl = chart.canvas.parentNode.querySelector('div');
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.style.background = 'rgba(0, 0, 0, 0.7)';
tooltipEl.style.borderRadius = '3px';
tooltipEl.style.color = 'white';
tooltipEl.style.opacity = 1;
tooltipEl.style.pointerEvents = 'none';
tooltipEl.style.position = 'absolute';
tooltipEl.style.transform = 'translate(-50%, 0)';
tooltipEl.style.transition = 'all .1s ease';
const table = document.createElement('table');
table.style.margin = '0px';
tooltipEl.appendChild(table);
chart.canvas.parentNode.appendChild(tooltipEl);
}
return tooltipEl;
};
const externalTooltipHandler = (context: any) => {
// Tooltip Element
const { chart, tooltip } = context;
let datasetIndex = tooltip.dataPoints[0].datasetIndex
const tooltipEl = getOrCreateTooltip(chart);
// Hide if no tooltip
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set Text
if (tooltip.body) {
const titleLines = tooltip.title || [];
const bodyLines = tooltip.body.map((b: any) => b.lines);
const footerLines = tooltip.footer || [];
const tableHead = document.createElement('thead');
titleLines.forEach((title: any) => {
const tr: any = document.createElement('tr');
tr.style.borderWidth = 0;
const th: any = document.createElement('th');
th.style.borderWidth = 0;
const text = document.createTextNode(title);
th.appendChild(text);
tr.appendChild(th);
tableHead.appendChild(tr);
});
const tableBody = document.createElement('tbody');
bodyLines.forEach((body: any, i: any) => {
const colors = tooltip.labelColors[i];
const span = document.createElement('span');
span.style.background = colors.backgroundColor;
span.style.borderColor = colors.borderColor;
span.style.borderWidth = '2px';
span.style.marginRight = '10px';
span.style.height = '10px';
span.style.width = '10px';
span.style.display = 'inline-block';
const tr: any = document.createElement('tr');
tr.style.backgroundColor = 'inherit';
tr.style.borderWidth = 0;
const td: any = document.createElement('td');
td.style.borderWidth = 0;
const text = document.createTextNode(body);
td.appendChild(span);
td.appendChild(text);
tr.appendChild(td);
tableBody.appendChild(tr);
});
const tableFooter = document.createElement('tfoot');
footerLines.forEach((title: any) => {
const tr: any = document.createElement('tr');
tr.style.borderWidth = 0;
const td: any = document.createElement('td');
td.style.borderWidth = 0;
const text = document.createTextNode(title);
td.appendChild(text);
tr.appendChild(td);
tableFooter.appendChild(tr);
});
const tableRoot = tooltipEl.querySelector('table');
// Remove old children
while (tableRoot.firstChild) {
tableRoot.firstChild.remove();
}
// Add new children
tableRoot.appendChild(tableHead);
tableRoot.appendChild(tableBody);
tableRoot.appendChild(tableFooter);
}
const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas;
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.maxHeight = "400px";
tooltipEl.style.position = 'absolute';
tooltipEl.style.fontSize = '0.7rem';
tooltipEl.style.left = positionX + tooltip.caretX + 'px';
tooltipEl.style.font = tooltip.options.bodyFont.string;
tooltipEl.style.padding = tooltip.options.padding + 'px ' + tooltip.options.padding + 'px';
if (datasetIndex === 0) {
tooltipEl.style.top = positionY + 'px';
tooltipEl.style.overflowY = "auto";
tooltipEl.style.scrollBehavior = "smooth";
}
else {
tooltipEl.style.top = positionY + tooltip.caretY + 'px';
}
};
if (props.tooltip !== undefined) {
if (props.tooltip['enabled'] === false) {
props.tooltip['external'] = externalTooltipHandler
}
options['plugins']['tooltip'] = props.tooltip
}
if (props.horizontal === true) {
options['indexAxis'] = 'y'
}
const labels = props.xAxis
const data = {
labels,
datasets: props.yAxis
};
return (<Bar options={options} data={data} height={props.height} width={props.width} />);
}
export default BarGraph;
The chart options are set with the “options” variable, where the “plugins” option is set to enable the tooltip and make it scrollable.