欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在react项目中使用ECharts

程序员文章站 2022-07-03 11:29:08
...

在react项目中使用ECharts

  这里我们要在自己搭建的react项目中使用ECharts,我们可以在ECharts官网上看到有一种方式是在 webpack 中使用 ECharts,我们需要的就是这种方法。

  我们在使用ECharts之前要先安装ECharts,在以往的开发模式中,我们很多使用就是把官网中的ECharts的核心js文件导入到我们的html或者是jsp等文件里面,但是在react项目中,我们可以直接使用node.js的npm命令安装

npm install echarts --save

  这个时候我们的ECharts就被下载到项目中的node_modules文件夹中,这个时候我们就可以在编写的react组件中使用ECharts了,下面直接看代码:

在react项目中使用ECharts
import React, { Component } from 'react';

// 引入 ECharts 主模块
import echarts from 'echarts/lib/echarts';
// 引入柱状图
import  'echarts/lib/chart/bar';
// 引入提示框和标题组件
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';

class EchartsTest extends Component {
    componentDidMount() {
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));
        // 绘制图表
        myChart.setOption({
            title: { text: 'ECharts 入门示例' },
            tooltip: {},
            xAxis: {
                data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        });
    }
    render() {
        return (
            <div id="main" style={{ width: 400, height: 400 }}></div>
        );
    }
}

export default EchartsTest;
在react项目中使用ECharts

  这里我们在使用ECharts的时候要在render()方法中return一个有id和大小的div,然后在componentDidMount()方法中像我们以往的方式一样渲染数据,这里都是一些静态的数据,当我们的数据是动态获取的时候,我们就要把渲染ECharts的数据放入到state中,这样我们才能够做出有交互性的动态效果。

  下面是展示代码的效果:

在react项目中使用ECharts

在 React 项目中使用 ECharts

说明

重要文件版本

  • “react”: “^16.2.0”
  • “echarts”: “^4.0.2”
  • “redux”: “^3.7.2”,
  • “react-router-dom”: “^4.2.2”
  • “react-router-redux”: “^5.0.0-alpha.9”
  • “react-hot-loader”: “^4.0.0-beta.21”

在 React 项目中使用 ECharts 生成图表,与使用其他第三方库没有太大的区别,只要在 React 的组件 componentDidMount 声明周期中初始化 ECharts 图表,然后在每次更新组件时调用 ECharts 实例的 setOption() 方法更新配置即可,以下记录了使用当中的一些细节

项目模板源码

编写 <Chart/> 图表组件

>

/*
* ECharts 组件基础部分
* */

import React, { PureComponent } from 'react';
import * as echarts from 'echarts';
import 'zrender/lib/svg/svg';
import throttle from '../../utils/throttle'; // 一个节流函数

export default class Chart extends PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            width: '100%',
            height: '100%'
        };
        this.chart = null;
    }
    /*
        注意:
            虽然在 componentDidMount 中组件已经被装配,
            但是如果设置容器宽高为百分比的值,那么容器的 clientWidth 和 clientHeight 有可能还处于计算中
            这个时候如果在容器中实例化 echarts,echarts 获得的 clientWidth 和 clientHeight 不一定是我们预期的,
            因此这里使用了定时器延迟实例化,也可以提前计算出像素之后 赋值给 width、height,这样不是百分比就没有问题
    */
    async componentDidMount() {
        console.log('did mount');
        // 初始化图表
        await this.initChart(this.el);
        // 将传入的配置(包含数据)注入
        this.setOption(this.props.option);
        // 监听屏幕缩放,重新绘制 echart 图表
        window.addEventListener('resize', throttle(this.resize, 100));
    }
    componentDidUpdate() {
        // 每次更新组件都重置
        this.setOption(this.props.option);
    }
    componentWillUnmount() {
        // 组件卸载前卸载图表
        this.dispose();
    }
    render() {
        const { width, height } = this.state;

        return (
            <div
                className="default-chart"
                ref={el => (this.el = el)}
                style={{ width, height }}
            />
        );
    }
    initChart = el => {
        // renderer 用于配置渲染方式 可以是 svg 或者 canvas
        const renderer = this.props.renderer || 'canvas';
        console.log(renderer);

        return new Promise(resolve => {
            setTimeout(() => {
                this.chart = echarts.init(el, null, {
                    renderer,
                    width: 'auto',
                    height: 'auto'
                });
                resolve();
            }, 0);
        });
    };
    setOption = option => {
        if (!this.chart) {
            return;
        }

        const notMerge = this.props.notMerge;
        const lazyUpdate = this.props.lazyUpdate;

        this.chart.setOption(option, notMerge, lazyUpdate);
    };
    dispose = () => {
        if (!this.chart) {
            return;
        }

        this.chart.dispose();
        this.chart = null;
    };
    resize = () => {
        this.chart && this.chart.resize();
    };
    getInstance = () => {
        return this.chart;
    };
}

其他组件中引用图表组件

/*
   Heatmap 热力图
*/
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';
import 'echarts/lib/component/grid';
import 'echarts/lib/chart/heatmap';
import 'echarts/lib/component/visualMap';
import Chart from '../components/Chart/index';
import { getChart } from '../modules/charts/actions';

class HeatmapChart extends Component {
    constructor(props) {
        super(props);
        this.state = {
            renderer: 'canvas'
        };
    }
    async componentWillMount() {
        // 装载前 获取数据
        const path = '/heatmap';
        const key = 'heatmap';

        await this.props.getChart({ path, key });
    }
    render() {
        const renderer = this.state.renderer;
        const option = this.getOption();

        return <Chart renderer={renderer} option={option} />;
    }
    // getOption 这个函数主要用于配置 option,包括将数据配置进去
    // 也可以将其放在 state 中,然后通过 setState 更新
    getOption = () => {
        // 组装数据,返回配置 option
        const currentData = this.props.charts.heatmap;

        return {
            tooltip: {
                position: 'top'
            },
            grid: {
                containLabel: true
            },
            xAxis: {
                type: 'category',
                splitArea: {
                    show: true
                },
                boundaryGap: true
            },
            yAxis: {
                type: 'category',
                splitArea: {
                    show: true
                },
                boundaryGap: true
            },
            visualMap: {
                min: 0,
                max: 20,
                calculable: true,
                left: 'left',
                bottom: 'bottom',
                dimension: 2
            },
            dataset: {
                source: currentData
            },
            series: [
                {
                    name: '热力图',
                    type: 'heatmap',
                    emphasis: {
                        itemStyle: {
                            shadowBlur: 10,
                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                        }
                    },
                    encode: {
                        x: 0,
                        y: 1
                    },
                    tooltip: {
                        formatter(params) {
                            const [x, y, value] = params.data;

                            return [
                                `x: ${x}`,
                                `y: ${y}`,
                                `value: ${value}`
                            ].join('<br/>');
                        }
                    }
                }
            ]
        };
    };
}

export default connect(
    state => ({ charts: state.charts }),
    dispatch => ({
        getChart: bindActionCreators(getChart, dispatch)
    })
)(HeatmapChart);

NO!!!

在这里,我使用echarts提供的模块化加载方式,实现了几个react-echarts图表组件:react-echarts图表在线渲染查看

你可以打开控制台,观察每个图表组件的加载情况。

但是,如果你认为仅仅是模块导入echarts的tooltip、grid这些插件就完事了,那么我也用不着写这篇文章分享了,下面会讲到另外一种异步加载方式。

导入echarts,最烦人的是什么?配置option是其一,其二就是极其庞大的echarts!特别是管理后台使用到echarts的时候,如果需要同个页面展示数十种图表类型,你就该好好考虑性能问题了。

插件版本号

  "echarts": "^3.6.2",
  "react": "^15.6.1",
  "react-dom": "^15.6.1"

实现了哪些图表组件

1、饼图
2、柱状图
3、折线图
4、散点图
5、地图
6、雷达图
7、k线图

我们不总是需要插件

实现这些echarts-react组件的目的,是告诉大家,react可以不需要引入第三方插件,使用echarts,不要惧怕react组件!

看过很多人说react难写,因为他们习惯了在jQuery开发模式下导入echarts、swiper、d3等插件。而突然切换到react中,就产生了不知所措的感觉。
如何在react中导入第三方插件,成为了他们心中的痛点,所以一些人就认为需要别人封装好的echarts-react插件或者其他react插件,才能使用,这种想法是错的。

echarts体积太大,使用模块化加载

以柱状图为例子,我们根据需要渲染的插件采取模块导入,不渲染的组件不导入,最大程度减小js。

import echarts from 'echarts/lib/echarts' //必须
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/grid'
import 'echarts/lib/chart/bar'

组件化开发的福音,react组件模块化加载

demo中采用单个echarts组件异步打包加载的模式,因为echarts组件普遍偏大,即使压缩也效果不明显,所以异步加载是最好的方式。

import { pieOption, barOption, lineOption, scatterOption, mapOption, radarOption, candlestickOption } from './optionConfig/options'
const PieReact = asyncComponent(() => import(/* webpackChunkName: "PieReact" */'./EchartsDemo/PieReact'))  //饼图组件
const BarReact = asyncComponent(() => import(/* webpackChunkName: "BarReact" */'./EchartsDemo/BarReact')) //柱状图组件
const LineReact = asyncComponent(() => import(/* webpackChunkName: "LineReact" */'./EchartsDemo/LineReact'))  //折线图组件
const ScatterReact = asyncComponent(() => import(/* webpackChunkName: "ScatterReact" */'./EchartsDemo/ScatterReact'))  //散点图组件
const MapReact = asyncComponent(() => import(/* webpackChunkName: "MapReact" */'./EchartsDemo/MapReact'))  //地图组件
const RadarReact = asyncComponent(() => import(/* webpackChunkName: "RadarReact" */'./EchartsDemo/RadarReact')) //雷达图组件
const CandlestickReact = asyncComponent(() => import(/* webpackChunkName: "CandlestickReact" */'./EchartsDemo/CandlestickReact')) //k线图组件

启动项目

//安装
npm install

//启动
npm start

打包项目

npm run build

实现方案介绍

1、每个图表单独封装成一个组件,通过参数传递数据,你会发现,图表内部代码几乎完全一样,只有import的类型不同。

2、异步加载是提高图表加载性能的最佳方式,不管是服务端还是客户端渲染。

3、在这些demo中,我认为对你来说最有价值的是react组件异步加载模式,很多人异步加载组件是通过拆分路由的方式,而非路由组件的异步加载,并不多人去尝试。但我想告诉你的是,
非路由组件的异步加载会将你的庞大的父组件拆分的更细,体积更小,加载的更加流畅。

方法一:

echarts-for-react 是一个非常简单的针对于 React 的 Echarts 封装插件。

和使用所有其他插件一样,首先,我们需要 install 它:

第一步:

npminstall --save echarts(依赖)

npminstall --save echarts-for-react

第二步:

在我们的项目中导入:

importReactEcharts from 'echarts-for-react'

第三步:

在 render 函数中使用:

  option={this.getOption}

  notMerge={true}

  lazyUpdate={true}

  style={{width: ‘400px’, height: ‘400px’}}

/>

组件基本参数介绍:

option:接收一个对象,该对象为 echarts 的配置项,详见:                 http://echarts.baidu.com/option.html#title

notMerge:可选,是否不跟之前设置的 option 进行合并,默认为 false,即合并。

LazyUpdate:可选,在设置完 option 后是否不立即更新图表,默认为 false,即立即更新。

style:echarts 容器 div 大小,默认:{height: ‘300px’}

在react项目中使用ECharts

方法二:

当然,我们也不是真的需要一个 react-echarts 插件,我们可以使用 echarts 提供的模块化加载方法,按需导入我们需要的图表:

首先,我们需要在项目中导入 echarts:

importecharts from 'echarts/lib/echarts'    //必须

import'echarts/lib/component/tooltip'        //图表提示框(按需)

import'echarts/lib/component/grid'      //图表网格(按需)

import 'echarts/lib/chart/bar'                 //引入柱状图(按需)

import'echarts/lib/chart/line’              //引入折线图(按需)

然后:我们需要在 render 函数中为图表放好一个容器:

{this.chartContainer = refs}} style={{width: ‘400px’, height: ‘400px’}}>

最后,我们需要在合适的生命周期中绘制我们的图表:

letmyChart = echarts.init(this.chartContainer)

letoption = {//echarts配置项}

myChart.setOption(option,true)


好了,echarts 已经成功的在项目中跑起来啦!


-END-