Skip to main content

Custom Tooltip

tip

There are some known timing problems when setting Plugins Object, solution is to set the Plugins Object on Did Mount.

Custom Tooltip Content

This sample shows how to use the tooltip callbacks to add additional content to the tooltip. Chart.js Example

Outputs.Plugins = {
tooltip: {
callbacks: {
footer: (tooltipItems) => {
let sum = 0;

tooltipItems.forEach(function (tooltipItem) {
sum += tooltipItem.parsed.y;
});
return "Sum: " + sum;
},
},
},
};

External HTML Tooltip

This sample shows how to use the external tooltip functionality to generate an HTML tooltip. Chart.js Example

const getOrCreateTooltip = (chart) => {
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) => {
// Tooltip Element
const { chart, tooltip } = context;
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) => b.lines);

const tableHead = document.createElement("thead");

titleLines.forEach((title) => {
const tr = document.createElement("tr");
tr.style.borderWidth = 0;

const th = 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, i) => {
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 = document.createElement("tr");
tr.style.backgroundColor = "inherit";
tr.style.borderWidth = 0;

const td = 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 tableRoot = tooltipEl.querySelector("table");

// Remove old children
while (tableRoot.firstChild) {
tableRoot.firstChild.remove();
}

// Add new children
tableRoot.appendChild(tableHead);
tableRoot.appendChild(tableBody);
}

const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas;

// 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";
tooltipEl.style.font = tooltip.options.bodyFont.string;
tooltipEl.style.padding =
tooltip.options.padding + "px " + tooltip.options.padding + "px";
};

Outputs.Plugins = {
tooltip: {
enabled: false,
position: "nearest",
external: externalTooltipHandler,
},
};

Only show titles

For this we just change the code to only return the titles.

const getOrCreateTooltip = (chart) => {
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) => {
// Tooltip Element
const { chart, tooltip } = context;
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) => b.lines);

const tableHead = document.createElement("thead");

titleLines.forEach((title) => {
const tr = document.createElement("tr");
tr.style.borderWidth = 0;

const th = document.createElement("th");
th.style.borderWidth = 0;
const text = document.createTextNode(title);

th.appendChild(text);
tr.appendChild(th);
tableHead.appendChild(tr);
});

const tableRoot = tooltipEl.querySelector("table");

// Remove old children
while (tableRoot.firstChild) {
tableRoot.firstChild.remove();
}

// Add new children
tableRoot.appendChild(tableHead);
}

const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas;

// 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";
tooltipEl.style.font = tooltip.options.bodyFont.string;
tooltipEl.style.padding =
tooltip.options.padding + "px " + tooltip.options.padding + "px";
};

Outputs.Plugins = {
tooltip: {
enabled: false,
position: "nearest",
external: externalTooltipHandler,
},
};