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

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

Flying
2020-07-25 / 0 评论 / 161 阅读 / 正在检测是否收录...

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

chart-stock.svg

基本上是在官网实例 上封装的。组件的封装其实就是确定输入输出接口的过程,朋友的需求比较简单,不涉及组件的数据输出,只需要传入 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 函数来做节流操作,减少回流提高性能。

示例资源

访问 codesandbox 查看完整项目代码及最终效果

?Happy coding!

0

评论 (0)

取消