Skip to content

Instantly share code, notes, and snippets.

@jon-a-nygaard
Last active June 3, 2019 23:07
Show Gist options
  • Save jon-a-nygaard/7d0253b2c73ae634d5804d6794a67c0c to your computer and use it in GitHub Desktop.
Save jon-a-nygaard/7d0253b2c73ae634d5804d6794a67c0c to your computer and use it in GitHub Desktop.
Example of rendering React components in a Highcharts formatter function.

Example of rendering React components in a Highcharts formatter function.

The index.js file shows an example of creating a React app with Highcharts using the offical wrapper. It also demonstrates a possible solution to render React components in a Highcharts formatter function.

The helper function named formatter takes a react component and render it to a string which is returned to the Highcharts formatter. It also takes the arguments and context in the Highcharts formatter and passes them into the component as props named arguments and context

import React from 'react'
import { render } from 'react-dom'
import Highcharts from 'highcharts/highstock'
import HighchartsReact from 'highcharts-react-official'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
// Used in the helper function named formatter
import { renderToString } from 'react-dom/server'
// Axis formatter which renders labels with links.
class AxisFormatter extends React.Component {
renderLabel = (match, ctx) => {
const msg = (
match.params.id === ctx.value.toString() ?
'You clicked me' :
'Click me!'
)
const text = `${ctx.value}: ${msg}`
return <Link to={`/${ctx.value}`}>{text}</Link>
}
render() {
const ctx = this.props.context
const fn = ({ match }) => this.renderLabel(match, ctx)
return <Router>
<div>
<Route path="/:id" render={fn} />
<Route exact path="/" render={fn} />
</div>
</Router>
}
}
// Helper to render components in a formatter function.
const formatter = (Component) => {
return function () {
const args = arguments
const ctx = this
const uniqueId = () => Math.random().toString(36).substring(2, 9)
const id = 'highcharts-formatter-' + uniqueId()
const axis = ctx.axis;
const chart = axis.chart;
const addEvent = Highcharts.addEvent;
// When issue with fireEvent is fixed, remove the following block.
if (!chart.removeFormatterCleanUp) {
chart.formatterCleanUp = [];
chart.removeFormatterCleanUp = addEvent(chart, 'beforeRedraw', function () {
this.formatterCleanUp.forEach(function (removeEvent) {
removeEvent();
});
this.formatterCleanUp = [];
})
}
const removeEvent = addEvent(axis, 'afterRender', function () {
const el = document.getElementById(id);
if (el) {
// Render the component as an element with events handlers and so on.
render(<Component arguments={args} context={ctx} />, el);
el.removeAttribute('id');
}
// When issue with fireEvent is fixed, remove next line, and uncomment the second next line.
chart.formatterCleanUp.push(removeEvent)
//removeEvent()
});
return '<span id="' + id + '">' +
// Render content to have correct positioning
renderToString(<Component arguments={args} context={ctx} />) +
'</span>'
}
}
const options = {
title: {
text: 'My stock chart'
},
series: [{
data: [1, 2, 3]
}],
xAxis: {
labels: {
useHTML: true,
// Passing the component into the helper function
formatter: formatter(AxisFormatter)
}
}
}
const App = () => <div>
<HighchartsReact
highcharts={Highcharts}
constructorType={'stockChart'}
options={options}
/>
</div>
render(<App />, document.getElementById('root'))
@jon-a-nygaard
Copy link
Author

Nice, that's an interesting workaround 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment