-
Notifications
You must be signed in to change notification settings - Fork 108
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
Difficult to use React components with Highcharts formatters. #23
Comments
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. |
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:
which allow us to add React components for example to Live demo: https://codesandbox.io/s/1o5y7r31k3 Best regards! |
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. |
Related issue in highcharts repository highcharts/highcharts#7755 |
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 |
Hi @ksdelacruz, Did you try to use the solution with portals? |
@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 |
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! |
@ppotaczek Thank you very much for your help! |
Don't know if this is any help, but we're currently using import { renderToStaticMarkup } from 'react-dom/server'
// ...
return (
<HighchartsReact
options={{
tooltip: {
formatter() {
return renderToStaticMarkup(
<span style={{ color: 'red' }}>
{/* ... */} |
@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
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 |
Hi @ksdelacruz, Could you reproduce that issue in some online code editor? You can edit the live example that I provided previously. |
@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. |
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
Live example: https://codesandbox.io/s/highcharts-react-demo-nvve6 Best regards! |
@ppotaczek Again, thank you very much for assisting me! |
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 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 }} />);
},
{/* ... */} |
Both 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. |
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:
Best regards! |
@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. |
Yes, it is worth it 👍 good idea! |
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.) |
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 |
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 |
Hello @plotka, I converted the example into a functional component with small improvements here: |
Should I be seeing those custom labels in the above demo @ppotaczek? This is what renders for me in the linked code sandbox. 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? |
Hello @maciej-gurban, I recommend you to check the example from @dankremniov |
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 |
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 |
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 |
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 Sidenote: Researched a lot on this and found https://codesandbox.io/s/highcharts-react-demo-gwk4k however this does not work with typescript as |
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. |
Hi @arnav-dt, It will work with React and TypeScript in the same way, only type You can also think about portals: https://github.com/highcharts/highcharts-react#how-to-add-react-component-to-a-charts-element |
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. |
I am glad to hear that. According to portals, please check a comment and code example in a comment from this thread: #23 (comment) |
Can you attach a example code for onclick triggering a function in React js. Thank you in advance |
Writing some rough code(react + typescript) which worked for me. I don't have the exact code with me right now.
In Highcharts options use the tooltip property like so:
And an event listener in your react code to listen to the onclick
@MaheshMohan3856 However I highly recommend you go by the portal way since the code becomes much more maintainable #23 (comment) |
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. https://codesandbox.io/s/highcharts-react-tooltip-forked-5rc5xz |
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 |
@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. |
@aAntak, there is a possible solution above in the thread. |
@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 |
@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 |
@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 :/ . |
@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 Live example: https://codesandbox.io/s/highcharts-react-demo-fork-2tdxbb?file=/demo.jsx |
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. 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. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Hi @ppotaczek, was there any specific reason for not using callback for chart context as in other class-based examples? Even if we are using the useRef, do we need to get the ticks from the event render method as that can be accessed through chartComponent. as well. |
Hi @vivekd005, There is no any reason, both ways should work fine. Maybe you could reproduce your current implementation in codesandbox? This way I could easily test what might be wrong. |
I have received feedback from a user asking how they can render React components in a Highcharts formatter function.
This proved to be quite difficult and we should try to somehow make it more user friendly.
I made one example where I am rendering a component with a react router in xAxis.labels.formatter using a helper function named
formatter
: GistThe solution was complicated by a bug in Highcharts.fireEvent, and that the Highcharts formatters expects a string in return.
One way I believe this can perhaps be simplified is that the Highcharts formatters can be modified to handle dom elements as return values.
Still this will not solve the full issue, as the Highcharts formatters will still not be able to handle a React component. So in my opinion there will likely be a need for some sort of helper as middleware.
The text was updated successfully, but these errors were encountered: