When defining an External implementation for Tooltip, chart.canvas.offsetLeft doesn't work when chart in a table
Expected behavior
No matter where a chart is positioned, correct coordinates should be available for the tooltip implementation (with respect to the viewport?).
Current behavior
chart.canvas.offsetLeft and chart.canvas.offsetTop etc... have values representing the relative positioning of the chart within the table element.
Reproducible sample
https://www.chartjs.org/dist/master/chart.umd.js
Optional extra steps/info to reproduce
<script src="https://npmcdn.com/chart.js@latest/dist/chart.umd.js"></script>
<TABLE>
<TR><TD><CANVAS id="chart1" height="200px" width="500px"></TD></TR>
<TR><TD><CANVAS id="chart2" height="200px" width="500px"></TD></TR>
</TABLE>
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
.chartTooltip {
position: absolute;
background-color: #345;
font-size:80%;
box-shadow: 3px 3px 4px 0px #aaa;
opacity: 1;
border-radius: 5px 5px 5px 5px;
pointer-events: none;
transform: translate(-50%, 0);
transition: all .1s ease;
z-index: 9999;
color: #CCC;
}
function getOrCreateTooltip(chart)
{
let tooltipEl = document.getElementById('chartjs-tooltip');
if (!tooltipEl)
{
tooltipEl = document.createElement('div');
tooltipEl.id = 'chartjs-tooltip';
tooltipEl.className="chartTooltip";
chart.canvas.parentNode.appendChild(tooltipEl);
}
return tooltipEl;
};
function tooltipExternal(context)
{
// Tooltip Element
const {chart, tooltip} = context;
const tooltipEl = getOrCreateTooltip(chart);
// Hide if no tooltip
if (tooltip.opacity === 0)
return tooltipEl.style.opacity = 0;
// table
tooltipEl.innerHTML = '<H2>Hello!</H2>';
// console.log("chart.canvas.getBoundingClientRect(): ", chart.canvas.getBoundingClientRect());
// console.log("chart.canvas.offsetst: ", [chart.canvas.offsetLeft, chart.canvas.offsetTop]);
// console.log("tooltip.carets: ", [tooltip.caretX, tooltip.caretY]);
// console.log("window.scrolls: ", [window.scrollX, window.scrollY]);
const positionX = chart.canvas.offsetLeft;
const positionY = chart.canvas.offsetTop;
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.left = (positionX + tooltip.caretX) + 'px';
tooltipEl.style.top = (positionY + tooltip.caretY) + 'px';
};
var ctx = document.getElementById("chart1");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3, 5, 10, 8]
}]
},
options: {
plugins: {
tooltip: {
enabled: false
,borderColor: '#CCC'
,external: tooltipExternal
}
}
}
});
var ctx = document.getElementById("chart2");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3, 5, 10, 8]
}]
},
options: {
plugins: {
tooltip: {
enabled: false
,borderColor: '#CCC'
,external: tooltipExternal
}
}
}
});
Possible solution
No response
Context
We are trying to use ChartJS in an environment where lots of HTML tables are used. We can figure out some work arounds, but painful. In general though, for tooltips, we should be able to get viewport-relative coordinates.
chart.js version
v4.2.1
Browser name and version
Firefox and Chrome (latest) on Windows 11
Link to your project
No response
As I can read in the documentation about the offsetTop property, it returns the offset to the closest anchor element. In this case its the TD. Because of this in both the charts it will return 1 as the offset. To get the accurate position you will need to use getBoundingClientRect on the client. If you use that you get the real position and then you can feed the y and x coordinates of those to the position of the tooltip and that will work fine.
https://codepen.io/leelenaleee/pen/qBzEpvK
Agreed, but the documentation and sample are not so clear about this. This works for a general tooltip DIV attached at the document level and with position:relative. The positioning then works anywhere everywhere all at once.