javascriptreactjshovervictory-charts

React Component called but not rendering properly


I have a pie chart implemented with VictoryPie. I would like to display a label when the mouse hovers over each slice.

I put a print statement inside the MouseFollowToolTip component. When the page loads, the statement has printed five times, which makes sense as there are five slices. Then when I move my mouse around the pie, it continues to print.

However, at no point does it display the label associated with the slice.

import React from 'react';
import Grid from '$components/grid';
import { VictoryLegend, VictoryPie, VictoryTooltip, VictoryLabel, Selection } from 'victory';

const creditScoreMakeup = [
    {
        x: 'Payment history',
        y: 35,
        label:
            'The best way for you to improve \nyour credit score is to \nfocus on making payments on time.',
    },
    {
        x: 'Credit utilization',
        y: 30,
        label:
            'You should try to carry little \nto no balance on your credit card \nto lower your credit utilization and \nimprove your credit score.',
    },
    {
        x: 'Length of history',
        y: 15,
        label:
            'A longer credit history provides lenders with more information about how you use credit which helps them predict how you will behave financially long-term.',
    },
    {
        x: 'Credit diversity',
        y: 10,
        label:
            'Having a mix of loans and credit cards \ngives lenders the impression that you can \nhandle various forms of credit responsibly.',
    },
    {
        x: 'Credit inquiries',
        y: 10,
        label:
            'Having many inquiries in a \nshort period of time in your \ncredit history suggests that you \nare in financial trouble and need \na significant amount of money.',
    },
];

class MouseFollowToolTip extends React.Component {

  static defaultEvents = [
    {
      target: "data",
      eventHandlers: {
        onMouseOver: evt => {
          const { x, y } = Selection.getSVGEventCoordinates(evt);
          return {
            mutation: () => ({
              target: "labels",
              x,
              y,
              active: true
            })
          };
        },
        onMouseMove: evt => {
          const { x, y } = Selection.getSVGEventCoordinates(evt);
          return {
            mutation: () => ({
              target: "labels",
              x,
              y,
              active: true
            })
          };
        },
        onMouseOut: () => {
          return { target: "labels", mutation: () => ({ active: false }) };
        }
      }
    }
  ];
  render() {
    console.log("called")
    return <VictoryTooltip {...this.props} pointerLength={0} renderInPortal={false} />;
  }
}


class CreditScore extends React.Component {
  render() {
    return (

        <svg width={1000} height={1000}>
            <VictoryLegend
                standalone={false}
                renderInPortal={false}
                colorScale="green"
                legendWidth={50}
                x={20}
                y={40}
                gutter={20}
                title="Legend"
                centerTitle
                style={{ border: { stroke: 'black' } }}
                data= {creditScoreMakeup.map((a, ind) => {
                    return { name: a.x };
                })}
            />
            <VictoryPie
                    colorScale="green"
                    data={creditScoreMakeup}
                    standalone={false}
                    renderInPortal={false}
                    width={800}
                    height={400}
                    padding-right={100}
                    style={{ parent: { maxWidth: '50%' } }}
                    //labels={d => `${d.label}%`}
                    labelComponent= {<MouseFollowToolTip/>}
                />


            </svg>

    );
  }

}

I've made a sandbox here


Solution

  • Here is a solution that tracks the mouse movement inside the CreditScore Component:

    class MouseFollowTooltip extends VictoryTooltip {
      render() {
        return (
          <VictoryTooltip
            {...this.props}
            pointerLength={16}
            renderInPortal={false}
          />
        );
      }
    }
    
    class CreditScore extends React.Component {
      state = {
        x: 0,
        y: 0
      };
    
      updateCoords = e => {
        this.setState({ x: e.clientX, y: e.clientY });
      };
    
      render() {
        return (
          <svg onMouseMove={this.updateCoords} width={1000} height={1000}>
            <VictoryLegend
              standalone={false}
              renderInPortal={false}
              colorScale="green"
              legendWidth={50}
              x={20}
              y={40}
              gutter={20}
              title="Legend"
              centerTitle
              style={{ border: { stroke: "black" } }}
              data={creditScoreMakeup.map((a, ind) => {
                return { name: a.x };
              })}
            />
            <VictoryPie
              colorScale="green"
              data={creditScoreMakeup}
              standalone={false}
              renderInPortal={false}
              width={800}
              height={400}
              padding-right={100}
              style={{ parent: { maxWidth: "50%" } }}
              labels={d => `${d.label}%`}
              labelComponent={
                <MouseFollowTooltip x={this.state.x} y={this.state.y} />
              }
            />
          </svg>
        );
      }
    }