ECharts common configuration items

Posted by paulnaj on Sat, 01 Jan 2022 00:02:09 +0100

preface

Ecarts is a chart control commonly used by us. It is particularly powerful. It is cumbersome to check the API every time you use it. Here are the commonly used configurations in development.

Official website: https://echarts.apache.org/handbook/zh/get-started

Configuration item: https://echarts.apache.org/zh/option.html#title

Third party sample platforms: https://www.makeapie.com/explore.html

quote

install

npm install echarts --save

quote

import * as echarts from 'echarts';

// Initialize the ecarts instance based on the prepared dom
var myChart = echarts.init(document.getElementById('main'));
// Draw a chart
myChart.setOption({
  title: {
    text: 'ECharts Getting started example'
  },
  tooltip: {},
  xAxis: {
    data: ['shirt', 'cardigan', 'Chiffon shirt', 'trousers', 'high-heeled shoes', 'Socks']
  },
  yAxis: {},
  series: [
    {
      name: 'sales volume',
      type: 'bar',
      data: [5, 20, 36, 10, 10, 20]
    }
  ]
});

Set rendering mode

Mode selection

In the scene with good software and hardware environment and small amount of data, both renderers can be applied without too much entanglement.

In scenes with poor environment and performance problems that need to be optimized, you can determine which renderer to use through experiments.

For example, these experiences:

  • When you need to create many ecarts instances and the browser is prone to crash (perhaps because the memory occupation exceeds the capacity of the mobile phone due to the large number of Canvas), you can use the SVG renderer to improve it. Roughly speaking, if the chart is running on a low-end Android, or we are using some specific charts, such as Water polo diagram Etc., the SVG renderer may work better.
  • When the amount of data is large (empirical judgment > 1K) and there are many interactions, it is recommended to select the Canvas renderer.

Set code

// Use the Canvas renderer (default)
var chart = echarts.init(containerDom, null, { renderer: 'canvas' });
// Equivalent to:
var chart = echarts.init(containerDom);

// Using the SVG renderer
var chart = echarts.init(containerDom, null, { renderer: 'svg' });

Data change re rendering

chart.setOption(option, notMerge, lazyUpdate);

Or:

chart.setOption(option, {
  notMerge: false,
  lazyUpdate: false,
  silent: false
});

Parameter interpretation:

  • option See the configuration item manual for the configuration items and data of the chart.
  • notMerge Optional, whether to not merge with the previously set option. The default is false, that is, merge.
  • lazyUpdate Optional. Whether to not update the chart immediately after setting the option. The default is false, that is, update immediately.
  • silent Optional. Prevent events from being thrown when calling setOption. The default value is false, that is, events are thrown.

The second parameter, notMerge, is set to true, that is, the previous options are not merged and the new options are used.

Size of response container

var myChart = echarts.init(document.getElementById('main'));
window.onresize = function() {
  myChart.resize();
};

Note that when used in combination with VUE, you must wait for the DOM rendering to complete before calling, otherwise it will not take effect.

async leftbar_click() {
  this.show_left = !this.show_left;
  await this.$nextTick();
  this.echart && this.echart.resize()
}

In addition to calling resize() directly without parameters, you can also specify the width and height to achieve the effect that the chart size is not equal to the container size.

myChart.resize({
  width: 800,
  height: 400
});

VUE encapsulation chart auto scaling

VUE encapsulates components to automatically scale the chart with page changes.

resize.js

import { debounce } from '@/utils/utils.js'

export default {
  data() {
    return {
      $_mDom: null,
      $_resizeHandler: null
    }
  },
  mounted() {
    this.initListener()
  },
  activated() {
    if (!this.$_resizeHandler) {
      // avoid duplication init
      this.initListener()
    }

    // when keep-alive chart activated, auto resize
    this.resize()
  },
  beforeDestroy() {
    this.destroyListener()
  },
  deactivated() {
    this.destroyListener()
  },
  methods: {
    // use $_ for mixins properties
    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
    $_sidebarResizeHandler(e) {
      if (e.propertyName === 'width') {
        this.$_resizeHandler()
      }
    },
    initListener() {
      this.$_resizeHandler = debounce(() => {
        this.resize()
      }, 100)
      window.addEventListener('resize', this.$_resizeHandler)
      this.$_mDom = document.getElementById('app')
      this.$_mDom && this.$_mDom.addEventListener('transitionend', this.$_sidebarResizeHandler)
    },
    destroyListener() {
      window.removeEventListener('resize', this.$_resizeHandler)
      this.$_resizeHandler = null
      this.$_mDom && this.$_mDom.removeEventListener('transitionend', this.$_sidebarResizeHandler)
    },
    resize() {
      const { chart } = this
      chart && chart.resize()
    }
  }
}

utils.js

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function() {
    // According to the last trigger interval
    const last = +new Date() - timestamp

    // The last call interval of the wrapped function last is less than the set interval wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // If it is set to immediate===true, because the start boundary has been called, there is no need to call here
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // If the delay does not exist, reset the delay
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

Call in custom chart component

import * as echarts from 'echarts'
import resize from "@/components/charts/mixins/resize.js"

export default {
  mixins: [resize],
  data() {
    return {
      chart: null,
    };
  },
}

Complete example

PieRateChart.vue

<template>
<div :class="className" :style="{ height: height, width: width }"/>
</template>

<script>
  import * as echarts from 'echarts'
  import resize from "@/components/charts/mixins/resize.js"

  export default {
    mixins: [resize],
    props: {
      className: {
        type: String,
        default: "chart",
      },
      width: {
        type: String,
        default: 0,
      },
      height: {
        type: String,
        default: "300px",
      },
      title: {
        type: String,
        default: ''
      },
      mRate: {
        type: String,
        default: () => {
          return "0"
        }
      }
    },
    data() {
      return {
        chart: null,
      };
    },
    watch: {
      mRate: function () {
        this.initChart()
      }
    },
    async mounted() {
      await this.$nextTick();
      this.initChart();
    },
    beforeDestroy() {
      if (!this.chart) {
        return;
      }
      this.chart.dispose();
      this.chart = null;
    },
    methods: {
      initChart() {
        if (!this.chart) {
          this.chart = echarts.init(this.$el);
        }
        let title = this.title;
        let num = parseFloat(this.mRate);
        let mydata = [num, 100 - num];
        let opts = {
          backgroundColor: '#ffffff',
          tooltip: {
            show: true,
          },
          color: ['#3c90f7', '#55bfc0'],
          series: [
            {
              type: 'pie',
              radius: ['60%', '80%'],
              center: ['50%', '50%'],
              hoverAnimation: true,
              data: mydata,
              itemStyle: {
                normal: {
                  borderWidth: 2,
                  borderColor: '#ffffff',
                },
              },
              label: {
                show: false,
              },
            },
          ],
          title: {
            text: num + '%',
            top: '38%',
            textAlign: 'center',
            left: '49%',
            textStyle: {
              color: '#666',
              fontSize: 16,
              fontWeight: '400',
            },
          },
        };
        this.chart.setOption(opts)
      },
    }
  };
</script>

Configuration item

title

Title component, including main title and subtitle.

title:{
  show:true,
  text : '',
  textStyle:{
    color: '#333' ,
    fontStyle: 'normal' ,
    fontWeight: 'bolder' ,
    fontFamily: 'sans-serif' ,
    fontSize: 18 ,
    lineHeight ... ,
    width ... ,
    height ... ,
    textBorderColor ... ,
    textBorderWidth ... ,
    textBorderType: 'solid' ,
    textBorderDashOffset: 0 ,
    textShadowColor: 'transparent' ,
    textShadowBlur: 0 ,
    textShadowOffsetX: 0 ,
    textShadowOffsetY: 0 ,
    overflow: 'none' ,
    ellipsis: '...' ,
  },
  subtext: '' ,
  subtextStyle:{},
  zlevel: 0 ,
  z: 2 ,
  left: 'auto' ,
  top: 'auto' ,
  right: 'auto' ,
  bottom: 'auto' ,
}

xAxis/yAxis

The x/y axis in a rectangular coordinate system grid. Generally, a single grid component can only be placed on the next two x/y axes at most. More than two x/y axes need to be configured offset Property prevents overlapping of multiple x/y axes at the same location.

xAxis:[
  {
    type: "category",
    data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
    axisTick: {
      alignWithLabel: true,
    },
    axisLabel: {
      rotate: 20
    },
    nameLocation: "end",
    name: "%"
  },
]

axisTick: axis scale related settings.

axisLabel: related settings of axis scale label.

name: related is the text on one side of the axis, such as the display unit.

Custom label content

option = {
  yAxis: {
    axisLabel: {
      formatter: '{value} element',
      align: 'center'
    }
  }
};

grid

For the drawing grid in the rectangular coordinate system, the upper and lower X axes and the left and right Y axes can be placed in a single grid. You can draw on a mesh Line chartHistogramScatter chart (bubble chart).

grid: {
  top: 20,
  left: "2%",
  right: "2%",
  bottom: 10,
  containLabel: true,
},

Percentages and specific values can be used in all four directions

When containLabel is true, left right top bottom width height determines the position of the rectangle formed by all contents including the coordinate axis label.

legend

Legend components.

The legend component shows different series of symbols, colors and names. You can control which series are not displayed by clicking the legend.

legend: {
  type: 'plain',
  orient: 'horizontal',
  data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
  bottom: 20,
  align: 'left',
  textStyle: {
    color: '#333',
  },
  itemGap: 10,
  formatter: (name) => {
    let item = null;
    for (const _item of chartData) {
      if (_item.chainName === name) {
        item = _item;
        break;
      }
    }
    if (item) {
      return name + '  ' + item.total + 'second ' + ((item.successCount * 100) / item.total).toFixed(1) + '%';
    } else {
      return name;
    }

  },
},

Of which:

  • itemGap: the interval between each item in the legend. Horizontal spacing for horizontal layout and vertical spacing for vertical layout.

tooltip

Suspension frame assembly.

tooltip: {
  show: true,
  formatter: '{b0}Success rate: {c0}%',
},

dataZoom

The dataZoom component is used for area scaling, so that you can freely pay attention to the detailed data information, or overview the data as a whole, or remove the influence of outliers.

dataZoom: {
  right: '2%', //Distance of the lower slider from the bottom of the x-axis
  top: '5%',
  height: '90%', //Height adjustment of lower slider handle
  width: 20,
  type: 'slider', //Type, sliding block plug-in
  show: true, //Show lower slider
  yAxisIndex: [0], //Selected y-axis
  start: 0, //How much does the initial data show
  end: 100, //What is the maximum initial data displayed
},

series

Line chart

series: [
  {
    data: [820, 932, 901, 934, 1290, 1330, 1320],
    type: 'line',
    smooth: true
  }
]

Histogram

series: [
  {
    type: 'bar',
    showBackground: false,
    data: valueData,
    barWidth: 16,
    itemStyle: {
      normal: {
        color: '#3c90f7',
        barBorderRadius: [0, 8, 8, 0],
      },
    },
    emphasis: {
      itemStyle: {
        color: specialColor,
      },
    },
  },
],

Of which:

  • emphasis: highlight graphic styles and label styles.

Pie chart

series: [
  {
    type: 'pie',
    radius: ['30%', '45%'],
    center: ['50%', '30%'],
    hoverAnimation: true,
    itemStyle: {
      normal: {
        borderWidth: 2,
        borderColor: '#ffffff',
        label: {
          show: true,
          position: 'outside',
          color: '#ddd',
          formatter: function (params) {
            var percent = 0;
            var total = 0;
            for (var i = 0; i < mydata.length; i++) {
              total += mydata[i].value;
            }
            percent = ((params.value / total) * 100).toFixed(0);
            if (params.name !== '') {
              return 'name:' + params.name + '\n' + '\n' + 'proportion:' + percent + '%';
            } else {
              return '';
            }
          },
        },
        labelLine: {
          length: 30,
          length2: 100,
          show: true,
          color: '#00ffff',
        },
      },
    },
    label: {
      show: false,
    },
    data: mydata,
    labelLine: {
      show: true,
    },
  },
],

other

Multiple drawings

option = {
  xAxis: [
    { type: 'category', gridIndex: 0, data: ['1 month', '2 month', '3 month'] },
    { type: 'category', gridIndex: 1, data: ['4 month', '5 month', '6 month'], position: 'top' },
  ],
  yAxis: [
    { gridIndex: 0 }, 
    { gridIndex: 1, inverse: true }
  ],
  grid: [
    { bottom: '55%' },
    { top: '55%' }
  ],
  series: [
    // These series appear in the first Cartesian coordinate system
    { type: 'bar', data: [1, 5, 10] },
    { type: 'bar', data: [2, 4, 3] },
    // These series will appear in the second rectangular coordinate system,
    { type: 'line', xAxisIndex: 1, yAxisIndex: 1, data: [2, 5, 8] },
    { type: 'line', xAxisIndex: 1, yAxisIndex: 1, data: [8, 2, 6] },
  ],
};

Two key attributes:

  • Position in xAxis: 'top'
  • Inverse in yAxis: true

The effects are as follows:

Gradient

var specialColor = {
  type: 'linear',
  x: 0,
  y: 0,
  x2: 1,
  y2: 0,
  colorStops: [
    {
      offset: 0,
      color: '#3c90f7 ', / / color at 0%
    },
    {
      offset: 1,
      color: '#55bfc0 ', / / color at 100%
    },
  ],
  globalCoord: false, // The default is false
};

option={
  series: [
    {
      type: 'bar',
      showBackground: false,
      data: [1,3,5,2,4],
      barWidth: 16,
      itemStyle: {
        normal: {
          color: '#3c90f7',
          barBorderRadius: [0, 8, 8, 0],
        },
      },
      emphasis: {
        itemStyle: {
          color: specialColor,
        },
      },
    },
  ],
}