GithubHelp home page GithubHelp logo

Comments (57)

cstoddart avatar cstoddart commented on July 25, 2024 5

I tried both portals and jsx to string solutions. I decided to go with a jsx to string solution similar to @stovmascript 's suggestion. This works with either renderToString() or renderToStaticMarkup().

import { renderToString } from 'react-dom/server';
import { Tooltip } from './CustomTooltip';

// ...
  return (
    <HighchartsReact
      options={{
        tooltip: {
          formatter: function() { // you can't use an arrow function here if you want to access the tooltip data off of 'this'
            const { x, y, point, series } = this;
            return renderToString(<Tooltip {...{ x, y, point, series }} />);
          },
          {/* ... */}

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024 4

Hello,

Unfortunately, there is currently no progress in this topic. As the autor of this issue rightly noticed, the implementation would be complicated and would require some changes in the Highcharts core.

However, I think that I can suggest a slightly different approach. React v16 provided portals:

Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.

which allow us to add React components for example to xAxis labels. Please check the following example:

Live demo: https://codesandbox.io/s/1o5y7r31k3
Docs: https://reactjs.org/docs/portals.html

Best regards!

from highcharts-react.

dankremniov avatar dankremniov commented on July 25, 2024 3

Both renderToString and renderToStaticMarkup work quite well. Obviously, they strip out all event handlers from components, and, thus, for tooltips with actions - usage of event bubbling is the only option.

However, since Highcharts v9.0.0, rendering of React components in the tooltip can be quite straightforward using React portals (thank you for the idea, @ppotaczek). In the previous version, tooltip DOM content was completely rerendered on each refresh regardless of whether it has changed or not (which was making the implementation using portals quite complicated).

I published POC for v9.0.0 using React portals here: https://gist.github.com/dankremniov/a9a6b969e63dfc4f0f83e6f82b82eb4f. @ppotaczek, I would love to hear your feedback and any suggestions.

from highcharts-react.

arnav-dt avatar arnav-dt commented on July 25, 2024 3

Writing some rough code(react + typescript) which worked for me. I don't have the exact code with me right now.
Add onclick to Highcharts

Highcharts.AST.allowedAttributes.push('onclick');

In Highcharts options use the tooltip property like so:

tooltip: {
    borderColor: 'transparent',
    borderRadius: 0,
    borderWidth: 0,
    className: 'charts-tooltip',
    outside: true,
    shadow: false,
    shape: 'square',
    shared: true,
    useHTML: true,
    formatter(): string {
      const scope = this as any;
      const tooltipInner = scope.points.reduce(
        (
          s: string,
          point: {
            x: string;
            y: number;
          },
        ) => {
          const pointerStyle = 'style="cursor: pointer"';
          const onClickAction = `onclick="document.dispatchEvent(new CustomEvent('my-event-${point.series.options.chartId}', { 'detail': { 'xVal': '${point.x}'}' } }));"`;
          const divAttributes = `${pointerStyle} ${onClickAction}`;
          return `${s}
                  <div class="charts-tooltip-inner"  ${divAttributes}>
                    <span>
                      Your other tooltip content goes here
                    </span>
                  </div>`;
        },
        `<div class="charts-tooltip-header">${scope.x}</div>`,
      );
      return `<div class="charts-tooltip-wrap">${tooltipInner}</div>`;
    },
  },

And an event listener in your react code to listen to the onclick

  useEffect(() => {
    const handleClick = ({
      detail: { xVal },
    }: any) => {
      console.log(xVal);
    };

    document.addEventListener(
      `my-event-${chartId}`,
      handleClick,
    );

    return () => {
      document.removeEventListener(
        `my-event-${chartId}`,
        handleClick,
      );
    };
  }, []);

@MaheshMohan3856 However I highly recommend you go by the portal way since the code becomes much more maintainable #23 (comment)

from highcharts-react.

Anwardo avatar Anwardo commented on July 25, 2024 2

Any update on this? Being able to render dom nodes inside formatters would make a huge difference. Right now it's really frustrating to properly add event handlers to elements inside a formatter function.

from highcharts-react.

stovmascript avatar stovmascript commented on July 25, 2024 2

Don't know if this is any help, but we're currently using renderToStaticMarkup to enable using JSX in the formatting function:

import { renderToStaticMarkup } from 'react-dom/server'

// ...
  return (
    <HighchartsReact
      options={{
        tooltip: {
          formatter() {
            return renderToStaticMarkup(
              <span style={{ color: 'red' }}>
                {/* ... */}

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024 1

@ksdelacruz,

By portals you can add React components to all HTML chart's elements. Please check the example with data labels: https://codesandbox.io/s/highcharts-react-demo-v9dns

Best regards!

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024 1

Hi @ksdelacruz, Thank you for the live demo!

The problem is that the chart re-renders after adding components from the portal, please check the order of functions in this example: https://codesandbox.io/s/highcharts-react-demo-tqzrr

You can prevent re-rendering, for example by setting allowChartUpdate option to false:

<HighchartsReact
    ...
    allowChartUpdate={false}
/>

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

Best regards!

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024 1

Hello @plotka, I converted the example into a functional component with small improvements here:
https://codesandbox.io/s/highcharts-react-demo-forked-e1v82?file=/demo.jsx

from highcharts-react.

maciej-gurban avatar maciej-gurban commented on July 25, 2024 1

I've reached out to him and got help in adjusting that solution to our use case, thanks. Do you think you could incorporate part of his solution into highcharts-react documentation, or even making it part of the library?

from highcharts-react.

Anwardo avatar Anwardo commented on July 25, 2024 1

renderToString works for simple dom nodes like divs and spans. However button + onclick handler fails inside tooltip useHTML formatter. Any idea how to get around this ? All onclicks fail image

Sidenote: Researched a lot on this and found https://codesandbox.io/s/highcharts-react-demo-gwk4k however this does not work with typescript as this is implicity any and I would need change tsconfig for the entire app. Like http://jsfiddle.net/BlackLabel/L6hygs35/ used to work but now fails @ppotaczek

Indeed, assigning an event handler does not work with renderToString. The workaround I'm using is assigning an ID, class or data attribute to the button and adding an event handler to the selector in useEffect. Not 'react-y' but it works.

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024 1

Hi @arnav-dt,
To add the onclick attribute, you need to add it to allowed attributes first:
Highcharts.AST.allowedAttributes.push('onclick')
Example: http://jsfiddle.net/BlackLabel/9w1za65g/

It will work with React and TypeScript in the same way, only type this in the formatter function to Highcharts.TooltipFormatterContextObject
API: https://api.highcharts.com/class-reference/Highcharts#.TooltipFormatterCallbackFunction

You can also think about portals: https://github.com/highcharts/highcharts-react#how-to-add-react-component-to-a-charts-element

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024 1

I am glad to hear that. According to portals, please check a comment and code example in a comment from this thread: #23 (comment)

from highcharts-react.

Angusross111 avatar Angusross111 commented on July 25, 2024 1

I found the last solution using the custom HTML tooltip bound with the mouseOver event has serious performance issues with large amounts of data due to the whole chart rerendering each time the mouseOver event fires due to the setState.
https://codesandbox.io/s/highcharts-react-demo-fork-forked-bwtmm3?file=/demo.jsx

I found a solution by using reacts useImperativeHandle to move the Tooltip setState to its own component, so it is the only thing that needs rerendering, not the whole chart.
https://codesandbox.io/s/highcharts-react-demo-fork-forked-29pvvi?file=/demo.jsx

from highcharts-react.

Anwardo avatar Anwardo commented on July 25, 2024

Hi, thanks for your detailed response, provided examples and insights! I considered using Portals but didn't figure out how to actually bring them into the chart yet. Very interesting solution.

I managed to utilize renderToString while binding a listener to a generated id for my use case for now, but might look into using your provided solution at a later stage.

from highcharts-react.

jon-a-nygaard avatar jon-a-nygaard commented on July 25, 2024

Related issue in highcharts repository highcharts/highcharts#7755

from highcharts-react.

ksdelacruz avatar ksdelacruz commented on July 25, 2024

I want to +1 on this feature. Currently, I'm trying to add React Router Links on my heatmap labels in order to load more detailed charts though since strings are the only accepted returns for formatters, I can't get to make router links work. Mimicking links using the <a> tags on labels would make the page reload which is different from the intended SPA behavior.

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Hi @ksdelacruz, Did you try to use the solution with portals?

from highcharts-react.

ksdelacruz avatar ksdelacruz commented on July 25, 2024

@ppotaczek I can't get to work the solution (or at least I can see how to incorporate it) on my development, because unlike the given example that access the ticks/label of x-Axis, I want to access the actual labels (points) of the series. Anyway, I just utilized the "onClick" event of the chart to save the point/label and just re-render a button with <Link> tag outside the heatmap.

from highcharts-react.

ksdelacruz avatar ksdelacruz commented on July 25, 2024

@ppotaczek Thank you very much for your help!

from highcharts-react.

ksdelacruz avatar ksdelacruz commented on July 25, 2024

@ppotaczek I would like to ask for additional help. I tried converting the implementation of your given solution into React Hooks but there's a problem and I tried looking for solution but can't find any. The portals do work but only on the first row of the heatmap. Hovering on the other rows would release an error

Uncaught TypeError: b.onMouseOver is not a function
at HTMLDivElement.e

Upon further checking/printing, it seems that the dataLabel attributes of points belonging to second row onward are missing.

P.S. Printing the points using chart.series[0].points logs 50 points but expanding the array on the console would show only 10 points.

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Hi @ksdelacruz,

Could you reproduce that issue in some online code editor? You can edit the live example that I provided previously.

from highcharts-react.

ksdelacruz avatar ksdelacruz commented on July 25, 2024

@ppotaczek Here's the example of the code that I've been talking to. https://codesandbox.io/s/highcharts-react-demo-w4fix

Kindly refer to the console for further clarifications. Thank you very much.

from highcharts-react.

ksdelacruz avatar ksdelacruz commented on July 25, 2024

@ppotaczek Again, thank you very much for assisting me!

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Hi @dankremniov,

Thanks for your comments.

Your code looks really well! The only thing I can see to improve is chart updating. You don't need to merge options, it is enough to apply only the new ones:

  chart.update(
    tooltip: {
      formatter,
      useHTML: true
    }
  );

Best regards!

from highcharts-react.

dankremniov avatar dankremniov commented on July 25, 2024

@ppotaczek, thank you 👍 I can add the link to the codesandbox to the corresponding FAQ section of the readme if you think it is worth it.

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Yes, it is worth it 👍 good idea!

from highcharts-react.

plotka avatar plotka commented on July 25, 2024

I was trying to add custom React component on x-axis labels, but I noticed the example sandbox (https://github.com/highcharts/highcharts-react#how-to-add-react-component-to-a-charts-element) is using highcharts-react v2 and does not work with v3. Does someone know how could I make it work with v3?

(I've checked @dankremniov's solution but it looks a lot more complex and I am not sure how to adapt it to labels instead of tooltips.)

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Hi @plotka,

I just checked the example and it also works for version 3.0.0, maybe you didn't update React version?

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

from highcharts-react.

plotka avatar plotka commented on July 25, 2024

Hi @ppotaczek. You are right, the React version needed to be updated. However, I tried to convert it into a functional component and for some reason, the labels are not being rendered. Do you think you could help? Thanks.

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

from highcharts-react.

maciej-gurban avatar maciej-gurban commented on July 25, 2024

Should I be seeing those custom labels in the above demo @ppotaczek? This is what renders for me in the linked code sandbox. Can't see the "React" word being rendered anywhere
Screen Shot 2021-03-22 at 16 09 30

Edit: Ah, I misunderstood. I was under the impression that this will render inside the tooltip shown when you hover over some data point. Is that possible to achieve?

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Hello @maciej-gurban, I recommend you to check the example from @dankremniov
Please let me know in case of any questions.

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Ok, great! Every case of using portals is slightly different, so adding something like this to the library is not a good idea, but I will add an example with tooltip to the docs.

from highcharts-react.

plotka avatar plotka commented on July 25, 2024

I agree that adding the examples to the documentation would be great, especially the one with the functional components. Thanks a lot @ppotaczek for the help!

from highcharts-react.

alvarotrigo avatar alvarotrigo commented on July 25, 2024

What would be the main benefit of using createPortal instead of ReactDOMServer.renderToStaticMarkup?
Is ReactDOMServer increasing the bundle size?
Does ReactDOMServer.renderToStaticMarkup has any performance downsides compared to just returning a plain HTML string?

@dankremniov any idea?

from highcharts-react.

dankremniov avatar dankremniov commented on July 25, 2024

@alvarotrigo, I mentioned one the reasons here previously. Another issue is that with ReactDOMServer.renderToStaticMarkup you will not be able to consume context within the tooltip unless you explicitly wrap it into a provider. Otherwise, if you need relatively simple tooltip without event handling or context - renderToStaticMarkup is a good option.

from highcharts-react.

alvarotrigo avatar alvarotrigo commented on July 25, 2024

@dankremniov yeah I read those, i was more concerned about performance and bundle size downsides. Does ReactDOMServer increase the bundle size at all?

from highcharts-react.

dankremniov avatar dankremniov commented on July 25, 2024

@alvarotrigo, I was not concerned about bundle sizes at that time, so, unfortunately, I cannot comment on that. I have not noticed any significant different in rendering performance.

from highcharts-react.

ashleyryan avatar ashleyryan commented on July 25, 2024

Does anyone have an example of a tooltip using a portal? I see the label example, but there's no tooltip dom element available at render time as far as I'm aware. I would prefer not to use renderToStaticMarkup since it's not part of react-dom

from highcharts-react.

alvarotrigo avatar alvarotrigo commented on July 25, 2024

I would prefer not to use renderToStaticMarkup since it's not part of react-dom

It increases bundle size?

from highcharts-react.

ashleyryan avatar ashleyryan commented on July 25, 2024

I would prefer not to use renderToStaticMarkup since it's not part of react-dom

It increases bundle size?

It's a separate package so ... yeah, I'm sure it will, though I haven't investigated by how much. I'm also building this as a reusable component and so don't want to lose events, which you'll lose when rendering to plain old html

from highcharts-react.

ashleyryan avatar ashleyryan commented on July 25, 2024

I got something half working for clicking a point, built on top of the example above and using one of the demos from the documentation

It's a really bad frankenstein of portal code plus rendering using the renderer - I need to be able to resize the tooltip I'm trying to render content into.

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

from highcharts-react.

arnav-dt avatar arnav-dt commented on July 25, 2024

renderToString works for simple dom nodes like divs and spans. However button + onclick handler fails inside tooltip useHTML formatter. Any idea how to get around this ? All onclicks fail
image

Sidenote: Researched a lot on this and found https://codesandbox.io/s/highcharts-react-demo-gwk4k however this does not work with typescript as this is implicity any and I would need change tsconfig for the entire app.
Also http://jsfiddle.net/BlackLabel/L6hygs35/ used to work but now fails @ppotaczek

from highcharts-react.

arnav-dt avatar arnav-dt commented on July 25, 2024

Thank you @ppotaczek and @Anwardo for your inputs I am able to fire an event using buttons onclick and listen to it in my react code. This will work well as a workaround for my usecase (button inside tooltip).

I tried using portals/ReactDOM.render() but the issue with them is that I need an HTML element to latch onto as the second parameter. For tooltips the tooltip HTML DOM nodes are created only after mouse hovers over any of the points/bars. Until then there is no DOM node for react render code inside of.

from highcharts-react.

MaheshMohan3856 avatar MaheshMohan3856 commented on July 25, 2024

Hi @arnav-dt, To add the onclick attribute, you need to add it to allowed attributes first: Highcharts.AST.allowedAttributes.push('onclick') Example: http://jsfiddle.net/BlackLabel/9w1za65g/

It will work with React and TypeScript in the same way, only type this in the formatter function to Highcharts.TooltipFormatterContextObject API: https://api.highcharts.com/class-reference/Highcharts#.TooltipFormatterCallbackFunction

You can also think about portals: https://github.com/highcharts/highcharts-react#how-to-add-react-component-to-a-charts-element

Can you attach a example code for onclick triggering a function in React js. Thank you in advance

from highcharts-react.

aAntak avatar aAntak commented on July 25, 2024

Did anyone had a chance to make tooltip size dynamic & adjust to the content size when using portals? Seems like the size is fixed after the tooltip initial render.
image

https://codesandbox.io/s/highcharts-react-tooltip-forked-5rc5xz

from highcharts-react.

arnav-dt avatar arnav-dt commented on July 25, 2024

Hello @aAntak You can render any custom react component using portals. The size can dynamically adjust based on the css of the custom react tooltip container used

from highcharts-react.

boris773 avatar boris773 commented on July 25, 2024

@aAntak I do not think it's possible. As far as I'm aware CSS will not help here. If we would have FIXED content on every point of the chart, we could specify width, but currently, if the content might be larger/smaller on every point, the tooltip will not resize.

from highcharts-react.

dankremniov avatar dankremniov commented on July 25, 2024

@aAntak, there is a possible solution above in the thread.

from highcharts-react.

aAntak avatar aAntak commented on July 25, 2024

@arnav-dt @boris773 @dankremniov thanks for quick reply!

I used that forked solution in my first question. If you hover on first point, and then on the second one you will see that the content overflows the tooltip container. https://codesandbox.io/s/highcharts-react-tooltip-forked-5rc5xz

image

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

@aAntak, You need to adjust dimensions of the box SVG element. Please check this thread: https://www.highcharts.com/forum/viewtopic.php?f=9&t=49412

from highcharts-react.

aAntak avatar aAntak commented on July 25, 2024

@ppotaczek thanks for reply,

Unfortunately, this does have "blinking & "jumping" effect. As far as I understand this happens because we are correcting tooltip size on the next render. https://codesandbox.io/s/highcharts-custom-tooltip-forked-9ji67s?file=/features/HighchartsTooltip.ts .

I think I will try to think of any other solutions viable for me without portals :/ .

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

@aAntak, Yes, it is really problematic to use portals with tooltip due to it's under the hood SVG logic. Another solution may be to build your own custom HTML tooltip, bound with the mouseOver point's event. Please check the below example.

Live example: https://codesandbox.io/s/highcharts-react-demo-fork-2tdxbb?file=/demo.jsx
API Reference: https://api.highcharts.com/highcharts/plotOptions.line.point.events.mouseOver

from highcharts-react.

Revanth12-creator avatar Revanth12-creator commented on July 25, 2024

I am facing highcharts_react_official_1 is not defined in React . Any solution ?

from highcharts-react.

ppotaczek avatar ppotaczek commented on July 25, 2024

Hi @Revanth12-creator, Please create a new issue with a more detailed description of the problem.

from highcharts-react.

Revanth12-creator avatar Revanth12-creator commented on July 25, 2024

Hi ,
Created the React component as blow
import React, { useRef } from 'react';
import * as Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';

const options: Highcharts.Options = {
title: {
text: 'My chart',
},
series: [
{
type: 'line',
data: [1, 2, 3],
},
],
};

const App = (props: HighchartsReact.Props) => {
return (
<HighchartsReact highcharts={Highcharts} options={options} {...props} />
);
};

export default App;

I have installed below packages
npm install highcharts
npm install highcharts-react-official

I was facing problem that Uncaught ReferenceError: highcharts_react_official_1 is not defined
below version config
Node -v=>14.20.0
NPM -v=>6.14.17
React -v=>17.0.2

from highcharts-react.

abhirocks550 avatar abhirocks550 commented on July 25, 2024

I am using JEST and RTL for writing unit tests. I can see charts being rendered inside tests when I check below assertion it is true
expect(container.getElementsByClassName("highcharts-point").length).toBeGreaterThan(0)

when I trigger event on the highcharts-point I also see highcharts-series-hover also gets applied which means hover was successful but the issue is formatter function is not triggered from tooltip options for highcharts due to which tooltip is not displayed and I am not able to test further assertions. can someone help what am I missing here?

tooltip: {
  useHTML: true,
  crosshairs: [{
      dashStyle: "dash"
    }, {
      dashStyle: "dash"
    }],
  shared: false,
  snap: 15,
  formatter(): string {
    return getTooltipData(this);
  }
}
    ```

from highcharts-react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.