Flexible encapsulation of react histogram components based on echarts

Posted by md_grnahid on Sun, 29 Sep 2019 13:08:12 +0200

Now all kinds of frameworks and libraries are very powerful, but also because of their powerful functions, many configurations are too heavy, so there are only a few that are really useful. Today, we encapsulate a general-purpose cylindrical graph based on echarts!

If you want to know about other components, you can see that other components I encapsulated before have good ideas or other components that will be shared.
Transverse drag time axis based on antd package

The general cylindrical graph mainly contains several parts.

  1. title display, label display on xAxis;
  2. maxShow, bar chart display should not be more than 12, otherwise it will affect the beauty (or observation data);
  3. In UI, we need to support the modification of the color and width of the column without data hints.
  4. In terms of interaction, we need to support the most basic click events, double-click events, return to temporarily fix the data part of the current click, all data sets and echarts objects. Besides click events, we also need to support resize, so that when the viewport changes, the pie chart will be redrawn accordingly.
  5. Support the most commonly used toolbox, tooltip and other configurations;
  6. Need to support deletion, new configuration (sometimes we encapsulate the imperfect need the user to execute the configuration part);

Realization function

Based on the above points, we started to write code:

In the component DidMount cycle, we accept the attributes from the parent component and construct the most basic option. Before constructing the option, we first do the processing of maxShow.

First declare an empty data to be processed

let newChartsData = [];

Then process maxShow

if (maxShow && maxShow >= 0 && chartsData.length > maxShow) {
      chartsData.sort((a, b) => {
        return b.value - a.value;
      });

      newChartsData = chartsData.slice(0, maxShow);
      let total = 0;
      chartsData.map((item, index) => {
        if (index > 4) {
          total += item.value
        }
      });
      newChartsData = [...newChartsData, {value: total, name: 'Other'}];
    }
    else {
      newChartsData = [...chartsData]
    }

* Note here that we default not to deal with maxShow, that is to say, adding parent not to pass, so the default is all displayed, without using zoom configuration, it is recommended that maxShow=12 is the best; specific time default 12 or default not to deal with the data to be processed by users, I deal with most of the data situation. In this case, it will not be more than 12, so it will not be processed by default.

Initialize the sketchpad, build option s, etc.

let myCharts = echarts.init(document.getElementById(`${idPrefix}_pie`));

    if (getCharts && typeof func === 'function') {
      getCharts(myCharts);
    }
    myCharts.clear();

    _eventType.map(item => {
      myCharts.off(item);
    });
 let option = {
      color: newChartsData.length ? chartColor : '#bfbfbf',
      title: {
        text: title,
        top: 20,
        x: 'center'
      },
      toolbox: {
        feature: {
          saveAsImage: {
            type: 'png',
            title: 'Click to download',
          }
        },
        top: 13,
        right: 13
      },
      tooltip: {
        trigger: 'item',
        formatter: "{a} <br/>{b} : {c} ({d}%)"
      },
      series: [
        {
          name: title,
          type: 'pie',
          radius,
          center,
          avoidLabelOverlap: false,
          label: {
            show: label,
          },
          labelLine: {
            normal: {
              show: label
            }
          },
          itemStyle: {
            borderWidth: 2, //How wide is the border set?
            borderColor: bgColor,
          },
          hoverAnimation: false,
          hoverOffset: 0,
          data: newChartsData.length ? newChartsData : [{value: 0, name: 'No data'}],
        },
      ],
      graphic: newChartsData.length
        ? null
        : [{
          type: 'text',
          left: 'center',
          top: radius[0] === '0' ? 'auto' : center[1],
          bottom: 10,
          cursor: 'auto',
          style: {
            text: 'No data',
            textAlign: 'center',
            fill: '#bfbfbf',
            fontSize: 16,
            stroke: '#bfbfbf',
            lineWidth: 0
          }
        }]
    };

In addition, I added the display code about no data. See the way I encapsulated it before. Flexible encapsulation of react pie chart components based on echarts There is no repetition here.

Add and delete additional configuration functions, instantiate option s

 if (deleteOption) {
      deleteOption.map(item => {
        delete option[item]
      });
    } // Delete function

    if (options) {
      option = {...option, ...options}
    } // Supplementary options

    myCharts.setOption(option);

Add click event return value, resize anti-jitter function

 if (eChartsEvent && typeof eChartsEvent === 'function') {
      myCharts.on(eventType, 'series', params => {
        eChartsEvent(params, chartsData, myCharts);
      });
    }

    window.onresize = () => {
      let target = this;
      if (target.resizeFlag) {
        clearTimeout(target.resizeFlag);
      }
      target.resizeFlag = setTimeout(function () {
        myCharts.resize();
        if (onResize && typeof onResize === 'function') {
          onResize();
        }
        target.resizeFlag = null;
      }, 100);
    }

Complete code

import React, {PureComponent} from 'react';
import echarts from 'echarts/lib/echarts';
import 'echarts/lib/chart/bar';
import 'echarts/lib/component/title';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/toolbox';
import 'echarts/lib/component/graphic';
import PropTypes from 'prop-types';

/*
* Column Graph Component
* Including no data to show, onresize redraw events
* You can customize option s to support multiple mouse events
* Other functions such as zoom, zoom, etc., which are not encapsulated for the time being, can be added through options'own definitions
* deleteOption: ['title', 'toolbox', 'tooltip', 'graphic'] Containing attributes contained in echarts
*
* */

/*
 * chartsData format
 * const barChartsData = {
 *  xAxis: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
 *  data:[10, 52, 200, 334, 390, 330, 220]
 * };
 * Standby color:
 * '#13c2c2', '#52c41a', '#faad14', '#f5222d', '#722ed1', '#eb2f96', '#faad14']
 * */
const _eventType = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseup', 'mouseover', 'mouseout', 'globalout', 'contextmenu'];

class BarChart extends PureComponent {

  static propTypes = {
    chartsData: PropTypes.object.isRequired, // graphic data
    idPrefix: PropTypes.oneOfType([
      PropTypes.string.isRequired, // Unique identification distinguishes multiple bar graphs.
      PropTypes.number.isRequired, // Unique identification distinguishes multiple bar graphs.
    ]),
    getCharts: PropTypes.func, // Getting echarts objects out
    onResize: PropTypes.func, // Global onResize event,
    eChartsEvent: PropTypes.func, // Graphic click events, return the data of each graph and the corresponding param, echarts objects
    barWidth: PropTypes.string, // Width of column
    bottom: PropTypes.string || PropTypes.number, // Bottom distance
    title: PropTypes.string, // Title bar, name
    chartColor: PropTypes.string, // Column area color
    label: PropTypes.bool, // Is the x-axis label displayed?
    tooltip: PropTypes.bool, // Do you show tooltip?
    options: PropTypes.object, // Modify the configuration you want to update, directly to eCharts
    deleteOption: PropTypes.array, // Delete unwanted configurations
    eventType: PropTypes.oneOf(_eventType), // Event type
  };

  static defaultProps = {
    title: '',
    barWidth: '25',
    chartColor: '#1890ff',
    label: false,
    eventType: 'click',
    bottom: '8%',
    tooltip: true
  };

  componentDidMount() {
    const {
      chartsData, idPrefix, getCharts, onResize, title, chartColor,
      label, deleteOption, options, eChartsEvent, eventType, barWidth,
      bottom
    } = this.props;
    let myCharts = echarts.init(document.getElementById(`${idPrefix}_bar`));

    if (getCharts && typeof func === 'function') {
      getCharts(myCharts);
    }
    _eventType.map(item => {
      myCharts.off(item);
    });

    let series = JSON.parse(JSON.stringify(chartsData.data));

    myCharts.clear();

    if (!chartsData.data.length) {
      chartsData.data = [7, 8, 6, 9]
    }

    let option = {
      color: series.length ? chartColor : ['#bfbfbf'],
      title: {
        text: title,
        top: 20,
        x: 'center'
      },
      toolbox: {
        feature: {
          saveAsImage: {
            type: 'png',
            title: 'Click to download',
          }
        },
        top: 13,
        right: 13
      },
      tooltip: {
        trigger: 'axis',
        axisPointer: {   // Coordinate axis indicator, coordinate axis trigger is effective
          type: 'shadow' // The default is a straight line, optional:'line'|'shadow'
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: series.length ? bottom : 40,
        containLabel: true
      },
      xAxis: [
        {
          type: 'category',
          data: series.length ? chartsData.xAxis : [],
          axisTick: {
            alignWithLabel: true
          },
          axisLine: {
            lineStyle: {
              color: series.length ? '#333' : '#ccc',
            }
          },
          axisLabel: {
            show: series.length && label,
          }
        }
      ],
      yAxis: [
        {
          type: 'value',
          show: series.length,
          splitLine: {
            show: false,
          },
        }
      ],
      series: [
        {
          name: title,
          type: 'bar',
          barWidth,
          data: chartsData.data
        }
      ],
      graphic: series.length
        ? null
        : [{
          type: 'text',
          left: 'center',
          bottom: 15,
          cursor: 'auto',
          style: {
            text: 'No data',
            textAlign: 'center',
            fill: '#bfbfbf',
            fontSize: 16,
            stroke: '#bfbfbf',
            lineWidth: 0
          }
        }]
    };

    if (deleteOption) {
      deleteOption.map(item => {
        delete option[item]
      });
    } // Delete function

    if (options) {
      option = {...option, ...options}
    } // Supplementary options

    if (eChartsEvent && typeof eChartsEvent === 'function') {
      myCharts.on(eventType, 'series', params => {
        eChartsEvent(params, chartsData, myCharts);
      });
    }

    myCharts.setOption(option);
    window.onresize = () => {
      let target = this;
      if (target.resizeFlag) {
        clearTimeout(target.resizeFlag);
      }
      target.resizeFlag = setTimeout(function () {
        myCharts.resize();
        if (onResize && typeof onResize === 'function') {
          onResize();
        }
        target.resizeFlag = null;
      }, 100);
    }
  }

  render() {
    const {idPrefix} = this.props;

    return (
      <div
        id={`${idPrefix}_bar`}
        style={{width: '100%', height: '100%'}}/>
    )
  }
}

export default BarChart;

Two more pictures

Normally displayed

Display of no data

Color matching website

The default color of the bar chart I choose is the default color matching of ant gallery, many small partners do not know how to match the color, then below and share several color matching websites (basically cut out from our company UE mouth);

  1. antd official colour - with this basic is enough
  2. Colordot - A color picker for humans
  3. Colourco.de - find your colour palette
  4. Color Scheme Designer 3 Advanced Online Colour Matching Device Colour Matching Network
  5. Color Hunt - Trendy Color Palettes

If you think it's OK to write, you have to give a compliment before you go. It's OK.

Topics: Javascript React JSON network