Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Legend item - on hover event #194

Closed
jmacioszek opened this issue Jan 31, 2020 · 9 comments
Closed

Legend item - on hover event #194

jmacioszek opened this issue Jan 31, 2020 · 9 comments

Comments

@jmacioszek
Copy link

Is there a way to handle on hover event in legend item? It seems to be possible to access legend item in jquery and override such event:

serie.legendItem.on('mouseover', function(){))

Unfortunately I haven't found a way to do that in React. Any help much appriciated.

@jmacioszek jmacioszek changed the title Legend item - on hover Legend item - on hover event Jan 31, 2020
@ppotaczek
Copy link
Contributor

Hi @jmacioszek,

Thank you for using Highcharts!

You can do the same with our wrapper. You need to only get the chart reference:

constructor(props) {
  super(props);
  this.afterChartCreated = this.afterChartCreated.bind(this);
}

afterChartCreated(chart) {
  this.internalChart = chart;
}

componentDidMount() {
  this.internalChart.series.forEach(function(s) {
    s.legendItem.on("mouseover", function() {
      console.log("Series legend mouseover");
    });
  });
}

render() {
  return (
    <div>
      <HighchartsReact
        highcharts={Highcharts}
        options={options}
        callback={this.afterChartCreated}
      />
    </div>
  );
}

Live example: https://codesandbox.io/s/highcharts-react-demo-of87n

Best regards!

@nickbrinser
Copy link

Hi @jmacioszek,

Thank you for using Highcharts!

You can do the same with our wrapper. You need to only get the chart reference:

constructor(props) {
  super(props);
  this.afterChartCreated = this.afterChartCreated.bind(this);
}

afterChartCreated(chart) {
  this.internalChart = chart;
}

componentDidMount() {
  this.internalChart.series.forEach(function(s) {
    s.legendItem.on("mouseover", function() {
      console.log("Series legend mouseover");
    });
  });
}

render() {
  return (
    <div>
      <HighchartsReact
        highcharts={Highcharts}
        options={options}
        callback={this.afterChartCreated}
      />
    </div>
  );
}

Live example: https://codesandbox.io/s/highcharts-react-demo-of87n

Best regards!

I'm looking at doing something like this in a project, but with functional components.

How would you go about setting this mouseover event in a functional component?

@ppotaczek
Copy link
Contributor

Hi @nickbrinser,

You just need to do the same, but in a slightly different way:

  function App() {
    const chartComponent = useRef(null);

    useEffect(() => {
      chartComponent.current.chart.series.forEach(function (s) {
        s.legendItem.on("mouseover", function () {
          console.log("Series legend mouseover");
        });
      });
    }, []);

    return (
      <div>
        <HighchartsReact
          highcharts={Highcharts}
          options={options}
          ref={chartComponent}
        />
      </div>
    );
  }

Here is an example: https://codesandbox.io/s/highcharts-react-demo-forked-fy2fw?file=/demo.jsx

@nickbrinser
Copy link

Thanks for the response @ppotaczek

I was on the right track!

@104gogo
Copy link

104gogo commented Jul 20, 2022

This way will kill some of the default behavior, is there any other better way?

@ppotaczek
Copy link
Contributor

Hi @104gogo, Which behavior do you mean? In the last example, you can see that the default mouseover behavior is kept.

@104gogo
Copy link

104gogo commented Jul 20, 2022

Hi @ppotaczek, Thanks for the reminder, now I know the problem is caused by setting legend.useHTML = true.
Example: https://codesandbox.io/s/highcharts-react-demo-forked-7mmjt3?file=/demo.jsx

But now there is a new problem, If useHTML is not used, labelFormat will not take effect, just like the following two pictures, the first picture is the effect of use, and the second picture is not used.
image

image

Is there any way to solve this problem?

@ppotaczek
Copy link
Contributor

Hi @104gogo, Thanks for more details!

First of all, labelFormat takes effect with disabled useHTML, but it has a restricted possibility for styling (because legend item is SVG not HTML).

Secondary, depending on the useHTML option, events are added on a different level. Please see this comment:

// Set the events on the item group, or in case of useHTML, the item
// itself (#1249)

Adding the same event, on the same element by using the on method will just overwrite the previous one (default behavior).

As a solution, you can add new events on legendGroup element and store your options in a state. Example:

  useEffect(() => {
    chartComponentRef?.current?.chart?.legend?.allItems.forEach((item: any) => {
      item?.legendGroup?.on("mouseover", function () {
        console.log("over");
        setCount(item.y);
      });

      item?.legendGroup?.on("mouseout", function () {
        console.log("out");
        setCount(100);
      });
    });
  }, []);

  const [state] = useState(...);

Live demo: https://codesandbox.io/s/highcharts-react-demo-fork-teh63d?file=/demo.jsx
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGElement#on

@104gogo
Copy link

104gogo commented Jul 22, 2022

Hi @ppotaczek, Thank you very much for your tips, it gave me a lot of inspiration! After tried many times, I solved my problem and then completed the functional requirements.

The code example:

useEffect(() => {
    // console.log('chartComponentRef?.current?.chart.legend', chartComponentRef?.current?.chart?.legend)

    chartComponentRef?.current?.chart?.legend?.contentGroup?.on("mouseout", function () {
      setCount(100);
    });

    chartComponentRef?.current?.chart?.legend?.allItems.forEach((item: any) => {
      const childNode = item?.legendItem?.element?.getElementsByTagName('div')[0];

      childNode?.addEventListener("mouseover" , function() {
        setCount(item.y || 0);
      });
    });
  }, []);

Also modify the labelFormat

legend: {
        ...
        labelFormat:
        `
          <div style="min-width: 170px; height: 23px;">
            <span style="float:left; font-size:14px; font-weight:normal; display: block; max-width: 120px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">{name}</span>
            <span style="float:right; padding-top: 2px;">{percentage:.1f}%</span>
          </div>
        `,
        useHTML: true
      },

Live demo: https://codesandbox.io/s/highcharts-react-demo-forked-pwwifb?file=/demo.jsx

Finally thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants