I made tooltips for all points using the plugin with two background colors dark and light. But the plugin works only after refreshing page. I made a code sandbox to show a problem. When you'll open sandbox, you'll see a button toggle. Click on dark theme and refresh page.
import React, { useEffect, useState } from "react";
import { Chart as ChartJS} from "chart.js";
import { Line } from "react-chartjs-2";
import faker from "faker";
const labels = ["January", "February", "March", "April", "May", "June", "July"];
export function App() {
const [theme, setTheme] = useState(() => {
const initialTheme = localStorage.getItem("theme");
return initialTheme ? initialTheme : "light";
});
function getThemeFromLocalStorage() {
const savedTheme = localStorage.getItem("theme");
if (savedTheme) {
setTheme(savedTheme);
}
}
function toggleTheme() {
setTheme((prevTheme) => {
const newTheme = prevTheme === "light" ? "dark" : "light";
localStorage.setItem("theme", newTheme);
return newTheme;
});
}
useEffect(() => {
getThemeFromLocalStorage();
}, [theme]);
const allTooltips = theme?.startsWith("d") ? "#151429" : "#FFF";
const data = {
labels,
datasets: [
{
fill: true,
label: "Dataset 2",
data: labels.map(() => faker.datatype.number({ min: 0, max: 1000 })),
borderColor: "rgb(53, 162, 235)",
backgroundColor: "rgba(53, 162, 235, 0.5)",
},
],
};
const alwaysShowTooltip = {
id: "alwaysShowTooltip",
afterDatasetsDraw(chart) {
const { ctx } = chart;
ctx.save();
chart.data.datasets.forEach((dataset, i: number) => {
chart.getDatasetMeta(i).data.forEach((datapoint, index: number) => {
const { x, y } = datapoint.tooltipPosition();
const itemText = chart.data.datasets[i].data[index];
const text = itemText !== null ? itemText + "%" : "";
ctx.beginPath();
ctx.fillStyle = itemText !== null ? allTooltips : "transparent";
const textWidth = ctx.measureText(text).width;
ctx.stroke();
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 5;
ctx.shadowBlur = 5;
ctx.shadowColor = "rgba(0, 0, 0, 0.15)";
ctx.roundRect(
x - (textWidth + 10) / 2,
y - 25,
textWidth + 10,
16,
4,
);
ctx.fill();
ctx.shadowColor = "transparent";
//text
ctx.font = "Regular 10px Poppins";
ctx.fillStyle = "gray";
ctx.fillText(text, x - textWidth / 2, y - 14);
});
});
},
};
return (
<>
<Line options={options} data={data} plugins={[alwaysShowTooltip]} />
<button onClick={toggleTheme}>Toggle Theme: {theme}</button>
</>
);
}
I tried some ideas and looked for decisions but haven't found any.
A very trivial solution would be to use a React key on the Line
component that updates when the theme
state updates.
Example using the theme
state value as the key:
<Line
key={theme} // <--
options={options}
data={data}
plugins={[alwaysShowTooltip]}
/>
The idea here is that the Line
component will remount and use the current computed data
and options
for rendering the chart.