reactjsnivo-react

How to add tooltip on "custom layer" in nivo bar chart?


I have used @nivo/bar for plotting bar charts in my react application. added line to display average value. on bars, the tooltip is working fine. I want to add a tooltip when the user hover over the line to show the average value.attached image


Solution

  • I am not sure if anyone will ever need to implement similar functionality. but I did some research on this one, here is the answer to my own questions:

    const CustomTagretLine = ({ props }) => {
    const { bars } = props
    const { showTooltipAt, hideTooltip } = useTooltip()
    
    
    //show tooltip on mouse enter
    const handleMouseEnter = (point) => {
      showTooltipAt(
        props.tooltip(point),
        [point.x + props.margin.left, point.y + props.margin.top],
        'top'
      )
    }
    
    //move tooltip with mouse position
    const handleMouseMove = (point) => {
      showTooltipAt(
        props.tooltip(point),
        [point.x + props.margin.left, point.y + props.margin.top],
        'top'
      )
    }
    
    const handleMouseLeave = () => {
      hideTooltip()
    }
    
    return (
      <>
        {bars.map((bar, idx) => (
          <>
            {bar.height && (
              <line
                onMouseOver={() =>
                  handleMouseEnter({
                    x: bar.x - 5,
                    y: props.yScale(bar?.data?.data?.avgVal || 0), //whatever you want
                    absX: bar.x - 5 + 70,
                    absY: props.yScale(bar?.data?.data?.avgVal || 0) + 50,
                    width: 70,
                    height: 4,
                    data: {
                      ...bar?.data?.data,
                      isAvg: true,
                    },
                    formattedValue: formatNumber(
                      parseInt(bar?.data?.data?.avgVal) || 0
                    ),
                  })
                }
                onMouseLeave={() =>
                  handleMouseLeave({
                    x: bar.x - 5,
                    y: props.yScale(bar?.data?.data?.avgVal || 0), //whatever you want
                    absX: bar.x - 5 + 70,
                    absY: props.yScale(bar?.data?.data?.avgVal || 0) + 50,
                    width: 70,
                    height: 4,
                    data: {
                      ...bar?.data?.data,
                      isAvg: true,
                    },
                    formattedValue: formatNumber(
                      parseInt(bar?.data?.data?.avgVal) || 0
                    ),
                  })
                }
                onMouseMove={() =>
                  handleMouseMove({
                    x: bar.x - 5,
                    y: props.yScale(bar?.data?.data?.avgVal || 0), //whatever you want
                    absX: bar.x - 5 + 70,
                    absY: props.yScale(bar?.data?.data?.avgVal || 0) + 50,
                    width: 70,
                    height: 4,
                    data: {
                      ...bar?.data?.data,
                      isAvg: true,
                    },
                    formattedValue: formatNumber(
                      parseInt(bar?.data?.data?.avgVal) || 0
                    ),
                  })
                }
                key={idx}
                opacity="1"
                x1={bar.x - 5}
                x2={bar.x + bar.width + 5}
                y1={props.yScale(bar?.data?.data?.avgVal || 0)}
                y2={props.yScale(bar?.data?.data?.avgVal || 0)}
                stroke="#000000"
                strokeWidth="3"
              ></line>
            )}
          </>
        ))}
      </>
    )}
    

    CustomTargetLine is custom layer, which can be added like this in bar

    layers={[
          'grid',
          'axes',
          'bars',
          'legends',
          'annotations',
          (props) => <CustomTagretLine props={props} />,
        ]} 
    

    refrence: https://nivo.rocks/bar/