Support React
tobiaslins opened this issue · comments
Currently it is not possible to use this library with React (easily).
Some modifications are needed to use it.
I want to discuss what should happen in this repository and what not.
I already did small changes to use it as a simple React component.
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Frappe from 'frappe-charts/src/scripts/charts.js'
import 'frappe-charts/dist/frappe-charts.min.css' // to import styling
class Chart extends Component {
componentDidMount() {
const {title, data, type = 'bar', height = 250} = this.props
this.c = new Frappe({
parent: this.chart,
title,
data,
type,
height
})
}
render() {
return <div ref={chart => (this.chart = chart)}/>
}
}
export default Chart
I created a demo repo for showcase: https://github.com/tobiaslins/frappe-charts-react-example
@tobiaslins, Could you add your credits to our README with reference to your example? 😄
@achillesrasquinha how do you want it to be added? :)
New section for example & credits?
I'll update my example as soon as you released the new version on NPM!
Edit: Already updated to use offical 0.0.4 release! Thanks :)
I just started to use it within my current react project and figured out that I'll need to adapt it.
I want to update the chart as soon as the react properties where changed.
The strange thing is - if I call the method with the new labels and values with following code
this.c.update_values( [{ values: props.data.datasets[0].values }], props.data.labels)
The chart is rerendered with the labels and hover is working - but the actual bars are not shown and I'm getting errors.
First line are the values & second labels
Do you know what the problem could be?
My initial chart data was:
data: {
labels: [],
datasets: [{ color: 'red', values: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1] }]
},
Edit
I just recognized that it is rendering corretly if I initialize the chart with the same amount of values/labels. That is a problem in my opinion. It should be possible to run update_values with a complete different amount of data. (probably fill the missing data with zeros)
Great work. React support would be an awesome addition to this lib 👍
What is possible right now with React with v0.0.4 of the lib?
@tobiaslins just wondering if you have figured out click handler support within react? Say for handling clicks for the heat map squares?
@viperfx I'll update the react component in the following days. It is currently NOT updating on prop changes & not supporting click handlers atm.
I've come to this solution (to update the chart on props changes):
import React from 'react'
import PropTypes from 'prop-types'
import Chart from 'frappe-charts/dist/frappe-charts.min.esm'
import 'frappe-charts/dist/frappe-charts.min.css'
class ChartBuilder extends React.Component {
componentDidMount () {
const { title, data, type, height } = this.props
this.c = new Chart({ parent: this.chart, title, data, type, height });
}
componentWillReceiveProps(nextProps) {
if (nextProps && !nextProps.data || this.props.data !== nextProps.data) {
const { title, data, type, height } = nextProps;
this.c = new Chart({ parent: this.chart, title, data, type, height });
}
}
render () {
return (<div ref={ chart => (this.chart = chart) } />)
}
}
export default ChartBuilder
Build a chart:
import React from 'react'
import PropTypes from 'prop-types'
import ChartBuilder from './ChartBuilder'
import { BAR } from './ChartType'
import { defaultChartPropTypes } from './defaults';
class BarChart extends React.Component {
render() {
return <ChartBuilder { ...this.props } />
}
}
BarChart.defaultProps = {
type: BAR
}
BarChart.propTypes = defaultChartPropTypes;
export default BarChart
We have to do a better check at this point:
if (nextProps && !nextProps.data || this.props.data !== nextProps.data) {
But the chart gets updated properly.
How i used it:
import React, { Component } from 'react'
import { render } from 'react-dom'
import PropTypes from 'prop-types'
import BarChart from '../lib/BarChart'
import LineChart from '../lib/LineChart'
import PercentageChart from '../lib/PercentageChart'
import PieChart from '../lib/PieChart'
import ScatterChart from '../lib/ScatterChart'
class App extends React.Component {
constructor() {
super();
this.state = {
data: {
labels: ['12am-3am', '3am-6pm', '6am-9am', '9am-12am',
'12pm-3pm', '3pm-6pm', '6pm-9pm', '9am-12am'
],
datasets: [
{
title: 'Some Data',
color: 'light-blue',
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
title: 'Another Set',
color: 'violet',
values: [25, 50, -10, 15, 18, 32, 27, 14]
}
]
}
};
}
updateSomeProps() {
const newData = {
labels: ['12am-3am', '3am-6pm'],
datasets: [
{
title: 'Some Data',
color: 'light-blue',
values: [25, 40]
},
{
title: 'Another Set',
color: 'violet',
values: [25, 50]
}
]
}
this.setState({ data: newData });
}
render () {
return (
<div>
<button onClick={this.updateSomeProps.bind(this)}>Changing props example ...</button>
<hr/>
<BarChart title="Test Bar Chart" data={this.state.data} height={250} />
<LineChart title="Test Line Chart" data={this.state.data} height={250} />
<PercentageChart title="Test Percentage Chart" data={this.state.data} height={250} />
<PieChart title="Test Pie Chart" data={this.state.data} height={250} />
<ScatterChart title="Test Scatter Chart" data={this.state.data} height={250} />
</div>
)
}
}
render(<App />, document.getElementById('app'))
@charlesrochati forgot to write here, already this this:
https://github.com/tobiaslins/frappe-charts-react-example/blob/master/src/chart.js
I'm just using their function update_values
instead of reinitializing the whole chart (works with animation)
@tobiaslins cool, just added it to my example:
import React from 'react'
import PropTypes from 'prop-types'
import Chart from 'frappe-charts/dist/frappe-charts.min.esm'
import 'frappe-charts/dist/frappe-charts.min.css'
class ChartBuilder extends React.Component {
componentDidMount () {
const { title, data, type, height } = this.props
this.c = new Chart({ parent: this.chart, title, data, type, height });
}
componentWillReceiveProps(nextProps) {
if (nextProps && !nextProps.data || this.props.data !== nextProps.data) {
this.c.update_values(nextProps.data.datasets, nextProps.data.labels)
}
}
render () {
return (<div ref={ chart => (this.chart = chart) } />)
}
}
export default ChartBuilder
It doesn't work with both Percentage and Pie chart, the update_values
function gets undefined. Did you noticed that?
@tobiaslins For the record, added progress on this to the readme. Cheers!
@tobiaslins is there any update on the support for react??
I have tried to use the example above, however, I wasn't successful.
Can u please let me know if there is any info on that.
Thanks
@tobiaslins I have actually tried using the same code in https://github.com/tobiaslins/frappe-charts-react-example. However, that didn't go well. I am getting errors while rendering the same example
@charlesrochati thanks for the suggestion. However, I am kind of using another library already. Thought of trying out frappe charts also
@charlesrochati working for me, thanks
Is there any support for the latest version of Frappe Charts v1.1
?
I'm using the latest version of Frappe Charts and it was quite easy to use in React JS.
In my App render() {}:
<div id="chart"></div>
{!this.state.isLoading &&
<ChartRender chartData={this.state.chartData} />
}
Then in the same file, under the App component:
const ChartRender = (props) => {
let data = {
labels: props.chartData.dates,
datasets: [
...
]
}
let chart = new Chart("#chart", {
...
});
return null;
}
I've tried using multiple solutions, including mrdavey's, and while I can see the chart in Elements (using Dev Inspector), it doesn't actually show up on the page. It's just...invisible? Here's my code:
import React, { Component } from 'react';
import { Chart } from 'frappe-charts/dist/frappe-charts.min.esm';
class AppChart extends Component {
render() {
document.addEventListener(
'DOMContentLoaded',
() => {
const data = {
labels: [
'12am-3am',
'3am-6pm',
'6am-9am',
'9am-12am',
'12pm-3pm',
'3pm-6pm',
'6pm-9pm',
'9am-12am'
],
datasets: [
{
name: 'Some Data',
type: 'bar',
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
name: 'Another Set',
type: 'line',
values: [25, 50, -10, 15, 18, 32, 27, 14]
}
]
};
const chart = new Chart('#chart', {
title: 'My Awesome Chart',
data: data,
type: 'axis-mixed',
height: 250,
colors: ['#7cd6fd', '#743ee2']
});
return null;
},
false
);
return (
<div>
<div id="chart" style={{ opacity: '1', zIndex: '9999' }} />
</div>
);
}
}
export default AppChart;
@AmnonSkladman instead of using document.addEventListener
wrap your code within a hook effect
e.g.,
function App() {
useEffect(() => {
const data = {
... data
};
const chart = new Chart("#chart", {
title: "My Awesome Chart",
data: data,
type: "axis-mixed",
height: 250,
colors: ["#7cd6fd", "#743ee2"]
});
return () => {
chart.unbindWindowEvents();
};
}, []);
return (
<div>
<div id="chart" style={{ opacity: "1", zIndex: "9999" }} />
</div>
)
}
I made a React/TypeScript wrapper - https://github.com/sheshbabu/react-frappe-charts 😊
Storybook - https://react-frappe-charts.netlify.com/?path=/story/playground--default
You might be better off dealing with frappe as a cjs module especially in react, doing the following below works for both SSR and CSR
const { Chart } = require('frappe-charts/dist/frappe-charts.min.cjs');