How to use echart chart more gracefully in Vue3
Tags: echart, vue, javascript
Published: 2022-11-20 10:09:08

### preface

In large screen visualization projects, we often need to use a lot of chart components. Usually, you will write a lot of 'options' to render charts, and import some of the components they need and use`chart.use`.



In `Vue2`, we often separate reusable components, and then pass the data required by the components to the reusable components through `props`,`emits` and other methods. In `Vue3`, we can write some logical functions as hooks for extraction and reuse, and then pass them to the view. This will not only make the code in your components more elegant but also more readable.

### thinking

#### import modules

We first create a `lib. ts` file to import and export all the components needed in the' chart '.

> Because there are too many modules introduced, we extract the code of the modules it introduces to increase the readability of the code

```typescript
// lib.ts
import * as echarts from 'echarts/core';

import {
    BarChart,
    LineChart,
    PieChart,
    MapChart,
    PictorialBarChart,
    RadarChart,
    ScatterChart
} from 'echarts/charts';

import {
    TitleComponent,
    TooltipComponent,
    GridComponent,
    PolarComponent,
    AriaComponent,
    ParallelComponent,
    LegendComponent,
    RadarComponent,
    ToolboxComponent,
    DataZoomComponent,
    VisualMapComponent,
    TimelineComponent,
    CalendarComponent,
    GraphicComponent
} from 'echarts/components';


echarts.use([
    LegendComponent,
    TitleComponent,
    TooltipComponent,
    GridComponent,
    PolarComponent,
    AriaComponent,
    ParallelComponent,
    BarChart,
    LineChart,
    PieChart,
    MapChart,
    RadarChart,
    PictorialBarChart,
    RadarComponent,
    ToolboxComponent,
    DataZoomComponent,
    VisualMapComponent,
    TimelineComponent,
    CalendarComponent,
    GraphicComponent,
    ScatterChart
]);

export default echarts;

```

#### Encapsulation function

Create a `useChart. ts` file in the same level directory. and reuse the `echartook` file.

feature：

- Monitor chart element changes and views, and automatically re render the chart to adapt to the height
- Theme and rendering mode can be imported (`SVG`, `Canvas`)
- loading effect

```typescript
import { nextTick, onMounted, onUnmounted, Ref, unref } from "vue";
import type { EChartsOption } from 'echarts';
import echarts from "./lib";
import { SVGRenderer, CanvasRenderer } from "echarts/renderers";
import { RenderType, ThemeType } from "./types";

export default function useChart(elRef: Ref<HTMLDivElement>, autoChartSize = false, animation: boolean = false, render: RenderType = RenderType.SVGRenderer, theme: ThemeType = ThemeType.Default) {
    // render mode
    echarts.use(render === RenderType.SVGRenderer ? SVGRenderer : CanvasRenderer)
    // echart instance
    let chartInstance: echarts.ECharts | null = null;

    // init echart
    const initCharts = () => {
        const el = unref(elRef)
        if (!el || !unref(el)) {
            return
        }
        chartInstance = echarts.init(el, theme);
    }

    // update or set options
    const setOption = (option: EChartsOption) => {
        nextTick(() => {
            if (!chartInstance) {
                initCharts();
                if (!chartInstance) return;
            }

            chartInstance.setOption(option)
            hideLoading()
        })

    }

    // get echart instance
    function getInstance(): echarts.ECharts | null {
        if (!chartInstance) {
            initCharts();
        }
        return chartInstance;
    }

    // resize cheats
    function resize() {
        chartInstance?.resize();
    }

    // observe chart
    function watchEl() {
        // add animation effect
        if (animation) { elRef.value.style.transition = 'width 1s, height 1s' }
        const resizeObserver = new ResizeObserver((entries => resize()))
        resizeObserver.observe(elRef.value);
    }

    // show loading
    function showLoading() {
        if (!chartInstance) {
            initCharts();
        }
        chartInstance?.showLoading()
    }
    // hide loading
    function hideLoading() {
        if (!chartInstance) {
            initCharts();
        }
        chartInstance?.hideLoading()
    }

    onMounted(() => {
        window.addEventListener('resize', resize)
        if (autoChartSize) watchEl();
    })

    onUnmounted(() => {
        window.removeEventListener('resize', resize)
    })

    return {
        setOption,
        getInstance,
        showLoading,
        hideLoading
    }
}
```

```typescript
// types.ts
export enum RenderType {
    SVGRenderer = 'SVGRenderer',
    CanvasRenderer = 'SVGRenderer'
}
export enum ThemeType {
    Light = 'light',
    Dark = 'dark',
    Default = 'default'
}
```

With the above encapsulated code, it will be simpler and more efficient to use the 'chart' library in components.

#### e.g

```vue
// index.vue
<template>
    <div ref="chartEl" :style="{ width: `300px`, height: `300px` }"></div>
</template>

<script setup lang="ts">
import { onMounted, Ref, ref, computed, nextTick } from "vue";
import type { EChartsOption } from 'echarts'
import useChart, { RenderType, ThemeType } from '../../useChart'
import axios from 'axios'

const option = computed<EChartsOption>(() => ({
   // ...chart option
}))

const chartEl = ref<HTMLDivElement | null>(null)

const {
    setOption,
    showLoading
} = useChart(chartEl as Ref<HTMLDivElement>, true, true, RenderType.SVGRenderer, ThemeType.Dark)



onMounted(() => {
    nextTick(() => {
    	// show loading
        showLoading()
        // request data ...
        // render
        setOption(option.value);
    })
})

</script>
```

### npm
 
github repo : https://github.com/QC2168/useCharts

> npm install echart @qc2168/use-charts