frappe / charts

Simple, responsive, modern SVG Charts with zero dependencies

Home Page:https://frappe.io/charts

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 :)

@achillesrasquinha @pratu16x7

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
image

image

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.

@tobiaslins

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!

@viperfx So the click handler doesn't work with non axis charts yet. Please keep an eye on #70 for updates.

@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;
}
commented

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>
  )
}

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');