react-chartjs-2 icon indicating copy to clipboard operation
react-chartjs-2 copied to clipboard

Custom Tooltip opacity always 1

Open velthune opened this issue 6 years ago • 9 comments

I need to have custom Tooltip and I design a react-component using hooks, check out the code:

import {Line} from "react-chartjs-2";
import {Button} from "reactstrap";
import React, {useState, useRef} from "react";
// noinspection ES6UnusedImports
// eslint-disable-next-line no-unused-vars
// import Drag from "../DraggableChart";

export default function ProgramChart({data}) {
    const [tooltipData, setTooltipData] = useState(null);
    const chartRef = useRef(null);
    return (
        <div>
            <Line
                ref={chartRef}
                options={{
                    legend: {
                        display: false
                    },
                        tooltips: {
                        "enabled": false,
                        "mode": "point",
                        "intersect": false,
                        custom: (tooltipModel) => {
                            // hide tooltip if needed
                            if (tooltipModel.opacity === 0) {
                                setTooltipData(null);
                                console.log("Hide tooltip");
                                return;
                            }
                            const chart = chartRef.current.chartInstance;
                            const canvas = chart.ctx.canvas;

                            if (canvas) {
                                const position = canvas.getBoundingClientRect();
                               
                                // set position of tooltip
                                const left = position.left + tooltipModel.caretX;
                                const top = position.top + tooltipModel.caretY;

                                setTooltipData({top, left});
                            }
                        }
                    },
                 }}
                data={chartData}
                style={{
                    display: "flex",
                    justifyContent: "center",
                    alignItems: "center",
                    textAlign: "center",
                    flex: 1,
                    height: "100%",
                }}/>
            {tooltipData ? <GraphTooltip data={tooltipData}/> : <div/>}
        </div>
    );
};

const GraphTooltip = ({data}) => <div
    style={{
        padding: 20,
        position: "fixed",
        border: "1px solid",
        borderColor: "#fff8f9",
        backgroundColor: "rgba(53,53,53,0.81)",
        borderRadius: 4,
        top: data.top,
        left: data.left,
    }}
>
    <Button>Whatever</Button>
</div>;

Tooltip is rendered but it never disappear!

If I remove setTooltipData({top, left}); line than there are no problem..

Have anyone any idea?

velthune avatar Oct 24 '19 13:10 velthune

@velthune I've copied your code into a sandbox and it functions exactly the same way the chart.js examples do: https://www.chartjs.org/samples/latest/tooltips/custom-points.html

Can you please describe the behaviour you are expecting in a bit more detail? Do you want the tooltips to disappear when the mouse moves out of the chart/tooltip element? Or if a user clicks elsewhere on the page?

If that's the case then you will need to manage those events yourself on custom tooltip elements.

Pringels avatar Nov 30 '19 10:11 Pringels

@velthune Did you ever figure this out? Seems like the function is only run when the tooltip is active (opacity:1). In this example https://www.chartjs.org/samples/latest/tooltips/custom-points.html the tooltip disappears if you move the mouse off the canvas as the custom tooltip function is called on exit.

georgefeast avatar Jan 22 '20 00:01 georgefeast

If anyone is still looking for an answer, I was able to solve this by putting the function into a useCallback with empty dependencies. Without useCallback it doesn't work and I'm not sure why. So if anyone knows a reason that would be great!

wongJonathan avatar Apr 12 '20 23:04 wongJonathan

Could you please be more specific on how you solved it? I have been trying to do so but I keep having the same problem, my tooltip opacity is always 1.

rubenlopezlozoya avatar Apr 24 '20 14:04 rubenlopezlozoya

I decided to take it out due to having issues creating my own that looked nice but I found what I used that worked.

const customTooltip = useCallback((tooltipModel: any) => {
    // if chart is not defined, return early
    let chart = chartRef.current;
    if (!chart) {
      return;
    }

    // hide the tooltip when chartjs determines you've hovered out
    if (tooltipModel.opacity === 0) {
      setOpenToolTip(false);
      return;
    }

    const position = chart.chartInstance.canvas.getBoundingClientRect();

    // assuming your tooltip is `position: fixed`
    // set position of tooltip
    const left = position.left + tooltipModel.caretX;
    const top = position.top - tooltipModel.height;

    // set values for display of data in the tooltip
    const label = tooltipModel.dataPoints[0].xLabel;
    const index = tooltipModel.dataPoints[0].index;

    setPositionAndData({top, left, label, index});
    setOpenToolTip(true);
  }, []);

And then I called it in the options:

tooltips: {
            enabled: false,
            custom: customTooltip,
          }

From what I remember, not defining the customTooltip with a useCallback gave the error where opacity did not change. Hope it helps!

wongJonathan avatar Apr 24 '20 21:04 wongJonathan

Unfortunately, useCallback doesn't work for me. But I found another workaround using setTimeout.

  const customTooltip = tooltipModel => {
    const result = {}

    // Hide if no tooltip
    result.visible = tooltipModel.opacity !== 0

    // Get content for the tooltip
    if (tooltipModel.dataPoints) {
      result.xLabel = tooltipModel.dataPoints[0].xLabel
      result.yLabel = tooltipModel.dataPoints[0].yLabel
    }

    result.xPos = tooltipModel.caretX
    result.yPos = tooltipModel.caretY

    setTimeout(setTooltipAttr, 20, result)
  }

But if anybody can explain, why is there a problem, it would be great. I don't have any idea.

miestassimon avatar Apr 28 '20 10:04 miestassimon

None of you guys have a problem where hovering while using a custom tooltip rerenders the chart itself?

PCPbiscuit avatar Jul 11 '21 18:07 PCPbiscuit

None of you guys have a problem where hovering while using a custom tooltip rerenders the chart itself?

@PCPbiscuit I'm facing same issue, did you find any workaround ?

parth-khiera avatar Sep 01 '21 08:09 parth-khiera

None of you guys have a problem where hovering while using a custom tooltip rerenders the chart itself?

@PCPbiscuit I'm facing same issue, did you find any workaround ?

The only workaround which works for me is using test-react-chartjs2

PCPbiscuit avatar Sep 01 '21 08:09 PCPbiscuit