分类
Flash

使用React和Echarts封装K线图组件

最近一朋友让我帮他弄一个股票图。了解我的人都知道很长一段时间我的工作就是画图表,Flex之后我用Flotr2开发过图表,但这个插件不支持K线图。我在网上找了找,发现Echart的K线图很好用也支持K线图。考虑到以后可能会复用,就结合React封装了一个K线组件。

基本上是在官网实例上封装的。组件的封装其实就是确定输入输出接口的过程,朋友的需求比较简单,不涉及组件的数据输出,只需要传入dataset(图表数据源)和seriesName(K线系列名称)两个属性就可以了,我还加了一个option属性,设置它可以完全覆盖组件内部的默认设置,这样复用性就相对高一些。

一、属性定义如下:
StockChart.propTypes = {
  dataset: PropTypes.arrayOf(PropTypes.array).isRequired,
  option: PropTypes.object,
  seriesName: PropTypes.string,
};

注意

这里的合并对象层级很深,要用深拷贝。考虑到时兼容必问题,我们使用lodash的merge函数来实现。

二、考虑到Echart整体上是很重的,我选择发按需引入组件。
import 'echarts/lib/chart/line';
import 'echarts/lib/chart/candlestick';
import 'echarts/lib/component/gridSimple';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/legend';
import 'echarts/lib/component/dataZoom';
三、原实例的的工具提示不是中文的,显示顺序不符合国人的习惯,也没有涨跌、成交、振幅这些指标,所以自定义如下:
formatter: ([param, ...tail]) => {
  const data = param.data;
  const float = data[4] - data[3];
  return param.seriesName +
    '<br/>' + param.name +
    '<br/>开盘:' + data[1] +
    '<br/>最高:' + data[4] +
    '<br/>最低:' + data[3] +
    '<br/>收盘:' + data[2] +
    '<br/>涨跌:' + data[5] + '(' + data[6] + ')' +
    '<br/>成交:' + (+data[7] / 100000000).toFixed(2) + '亿手' +
    '<br/>振幅:' + float.toFixed(2) + '(' + (float / data[4] * 100).toFixed(2) + '%)' + 
    '<br/>' + tail.map(item => item.seriesName + ':' + item.value).join('<br/>')
}
四、原实例的图例数据和系列名称存在耦合,我处理了一下:
getMas(ranges) {
  return ranges.map(item => {
    return {
      name: 'MA' + String(item),
      type: 'line',
      data: this.calculateMA(item),
      smooth: true,
      showSymbol: false,
      lineStyle: {
        width: 1
      }
    }
  })
}

get series() {
  const arr = this.getMas([5, 10, 20, 30])
  return [
    {
      type: 'candlestick',
      name: this.props.seriesName,
      data: this.data,
      itemStyle: {
        normal: {
          color: '#FD1050',
          color0: '#0CF49B',
          borderColor: '#FD1050',
          borderColor0: '#0CF49B'
        }
      }
    },
    ...arr
  ]
}
五、原实例的图表自适应代码写在父窗口上了,此处我们要在组件中实现这一功能,需要处理一下:
componentDidMount() {
  // 初始化图表
  this.chart = echarts.init(this.el, this.props.theme);
  // 将传入的配置(包含数据)注入
  this.setOption();
  // 监听屏幕缩放,重新绘制 echart 图表
  window.addEventListener('resize', throttle(() => {
    // 减少回流提高性能
    this.resize()
  }, 100));
}

componentWillUnmount() {
  // 组件卸载前卸载图表
  window.removeEventListener('resize', this.resize)
  if (!this.chart) {
    return;
  }
  this.chart.dispose();
  this.chart = null;
}

注意

我们是在componentDidMount中监听window的resize事件,这个事件浏览器无法自动进行垃圾回收,有可能导致内存泄露,因此需要我们在componentWillUnmount中手动销毁。另外,resize是个高频事件,我们使用lodash的throttle函数来做节流操作,减少回流提高性能。

点击此处查看完整代码,点击此处查看最终效果。

😀Happy coding!