Giter Site home page Giter Site logo

rncharts's Introduction

Using Recharts in React Native project

Source: https://dzone.com/articles/using-recharts-in-react-native-project

0. Get started:

Step 1. Start Web part: Open terminal, change current directory to RNCharts/web directory

Run yarn to install all depdendencies. Run yarn start to start web part

Step 2. Start React Native part: Open new terminal, change current directory to RNCharts directory:

Run yarn to install all dependencies. Run yarn start to start React Native part

Step 3. Run on emulartor: Open new terminal, change current directory to RNCharts directory:

Run react-native run-ios to run app on iOS emulator. To run app on Android emulator, goto RNCharts/config/app.js change chartPage to http://10.0.2.2:9000. Run react-native run-android

1. Introduction to Recharts:

Recharts (http://recharts.org) is a chart library built with React and D3. Recharts supports many kinds of chart such as AreaChart, BarChart, LineChart, and PieChart. The strength of Recharts is easy to extend and customize. For example, we can change active cursor, legend, and tick in Axises to our own component and styling. Following is an example of how to customize tick in XAxis:

const CustomizedAxisTick = React.createClass({
  render () {
    const {x, y, stroke, payload} = this.props;
   	return <g transform={`translate(${x},${y})`}>
        <text x={0} y={0} dy={16} textAnchor="end" 
            fill="#666" transform="rotate(-35)">
            {payload.value}
        </text>
    </g>
  }
});

const SimpleLineChart = React.createClass({
  render () {
    return <LineChart>
        <XAxis dataKey="name" tick={<CustomizedAxisTick/>}/>
        <YAxis/>
        <CartesianGrid />
        <Line type="monotone" dataKey="pv" />
    </LineChart>
  }
});

Find more examples here http://recharts.org/#/en-US/examples and full Recharts API here http://recharts.org/#/en-US/api

2. Project Structure:

In my React Native project, I add ‘web' directory for React project which uses Recharts library:

Structure

In development, web part runs at port 9000 and loaded by Webview Bridge component in React Native part (https://github.com/alinz/react-native-webview-bridge) . I choose Webview Bridge over built-in Webview (https://facebook.github.io/react-native/docs/webview.html) because it supports communication between React Native and Web part. For example, when a user clicks on a custom button in chart component we want to change the screen to another Scene or when he clicks on Navigation Button, chart content will be changed. All these things can do with Webview Bridge. Below is an example of how to work with Webview Bridge:

In Web part: listen and send a message to React Native part:

if (WebViewBridge) {
    WebViewBridge.onMessage = function (message) {
        console.log(message)
    };
    WebViewBridge.send("hello from webview");
}

In React Native part: listen and send a message to Web part:

let Sample = React.createClass({
    onBridgeMessage(message) {
        const { webviewbridge } = this.refs;
        switch (message) {
            case "hello from webview":
                webviewbridge.sendToBridge("hello from react-native");
                break;
        }
    },
    render() {
        return <WebViewBridge
            ref="webviewbridge"
            onBridgeMessage={this.onBridgeMessage.bind(this)}
            source={{uri: "http://localhost:9000"}}
        />
  }
});

3. Responsive design for charts:

To make the app works with wide range of devices, charts must be responsive design. In ChartPage component, need to listen “window resize” event and store screen width in component state:

componentWillMount() {
    this.props.getPoints();
    $(window).resize(() => {
        this.setState({
            chartWidth: $(window).width()
        });
    });
    // fire resize:
    $(window).trigger('resize');
}

chartWidth will be set to width property to render responsive chart in ChartPage.renderChart function:

// File: web/ui/page/ChartPage.jsx
let props = {
    width:this.state.chartWidth,
    height: this.state.chartHeight,
    lock: this.handleLock.bind(this),
    unlock: this.handleUnlock.bind(this),
    margin: {top: 5, right: MARGIN_RIGHT, left: 0, bottom: 5}
}
if(chartConfig.type != 'pie') {
    props.data = this.props.stats.points[chartConfig.dataKey];
}
return <div key={'chart-' + chartConfig.dataKey} className='gt-chart'>
    <div className='gt-tooltip-contents'>
        <span className='header'>{label}</span>
    </div>
    <Chart {...props}>
        {this.renderChartBody(chartConfig)}
    </Chart>
</div>

And unregister before component unmount:

// File: web/ui/page/ChartPage.jsx
componentWillUnmount() {
    $(window).off('resize');
}

After all, here’re the results:

Line Chart and Bar Chart:

Line Chart and Bar Chart

AreaChart and PieChart:

AreaChart and PieChart

4. Patch Recharts to support iOS gesture:

There's a difference between touch gesture in iOS and Android. In Android, Webview component can react with both vertical and horizontal at the same time, but in iOS, it cannot. This makes moving chart cursor in iOS very difficult. If user touches and moves the cursor a bit not horizontal, it will turn the move to Webview scrollbar instead of keeping moving the chart cursor.

My solution is patch Recharts to lock Webview scrollbar while user is using chart cursor and release it when he finishes. In file web/ui/components/recharts/generateCategoricalChart.js, I add some functions to listen to touch events to detect whether user is using chart cursor or not. If they start using chart cursor, send lock message to Webview Bridge: generateCategoricalChart.js

// File: web/ui/components/recharts/generateCategoricalChart.js
this.handleTouchMove = function (e) {};
this.handleTouchStart = function(e) {}
this.handleTouchEnd = function() {}

this.lock = function() {
    window.locked = true;
    if(self.props.lock != null) {
        self.props.lock();
    }
}

this.unlock = function() {
    window.locked = false;
    if(self.props.unlock != null) {
        self.props.unlock();
    }
}

In ChartScreen.js, store 'locked' value in component state and set it to WebViewBridge.scrollEnabled:

// File: screens/ChartScreen.js
render() {
    let contentInset = {
        right: -1 * config.chartScrollbarWidth,
        top: 0,
        bottom: 0,
        left: 0
    }
    let browserStyle = {
        ...styles.browser,
    }
    if(!this.state.loaded) {
        browserStyle.opacity = 0;
    }
    let browser = <WebViewBridge
        contentInset={contentInset}
        source={{uri: this.buildUrl()}}
        style={browserStyle}
        scrollEnabled={!this.state.locked}
        onLoadEnd={this.handleLoadEnd.bind(this)}
        onBridgeMessage={this.handleBridgeMessage.bind(this)}
        startInLoadingState={false}
    />;
    return <View style={styles.container}>
        {browser}
    </View>
}

Run web/patch-recharts.sh to replace original generateCategoricalChart.js file in recharts library.

5. Deployment

If your app is analysis app with many charts I recommend you to deploy web part in a server and load it in React Native remotely. By doing this, when the charts are updated user no need to re-install the app to have the latest version of charts. Otherwise, if chart is only small part of the app you should build the web part then load index.html and bundle.js from internal device file system.

6. My project

Visit and fork my project at https://github.com/thoqbk/RNCharts or contact me by [email protected] for further information.

rncharts's People

Contributors

thoqbk avatar

Stargazers

Volodymyr avatar

Watchers

James Cloos avatar

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.