echarts封装公共组件

【vue2+ts】echarts封装公共组件

记录笔记…

在这里插入图片描述

VueEChart:

<template>
  <div ref="el" :class="clsName"></div>
</template>
<script lang="ts">
import {
    
     Component, Prop, Watch } from 'vue-property-decorator';
// 引入echarts
import echarts from 'echarts';
// eslint-disable-next-line import/extensions
import 'echarts-liquidfill/src/liquidFill.js';
import abpbase from '../../libs/abpbase';
import 'echarts-gl';

const EVENTS = [
  'legendselectchanged',
  'legendselected',
  'legendunselected',
  'legendscroll',
  'datazoom',
  'datarangeselected',
  'timelinechanged',
  'timelineplaychanged',
  'restore',
  'dataviewchanged',
  'magictypechanged',
  'geoselectchanged',
  'geoselected',
  'geounselected',
  'pieselectchanged',
  'pieselected',
  'pieunselected',
  'mapselectchanged',
  'mapselected',
  'mapunselected',
  'axisareaselected',
  'focusnodeadjacency',
  'unfocusnodeadjacency',
  'brush',
  'brushselected',
  'rendered',
  'finished',
  'click',
  'dblclick',
  'mouseover',
  'mouseout',
  'mousemove',
  'mousedown',
  'mouseup',
  'globalout',
  'contextmenu',
];

@Component({
    
     name: 'VueEChart' })
export default class VueEChart extends abpbase {
    
    
  @Prop({
    
    
    type: Array,
    default: () => ([]),
  }) cname: string[];

  @Prop({
    
    
    type: Object,
    default: () => ({
    
    }),
  }) options: object;

  @Prop({
    
    
    type: String,
    default: '',
  }) themeName: string;

  @Prop({
    
    
    type: Object,
    default: () => ({
    
    }),
  }) themeData: object;

  chart: any = null;

  resizeInterval = null;

  get clsName() {
    
    
    return ['container', ...this.cname];
  }

  get echart() {
    
    
    return this.chart;
  }

  init() {
    
    
    if (this.chart) {
    
    
      this.freeChart();
    }

    if (this.themeName && this.themeData) {
    
    
      echarts.registerTheme(this.themeName, this.themeData);
      this.chart = echarts.init(this.$refs.el as HTMLCanvasElement, this.themeName);
    } else {
    
    
      this.chart = echarts.init(this.$refs.el as HTMLCanvasElement);
    }
    this.chart.setOption(this.options, true);
    this.chart.resize();

    const self = this;
    EVENTS.forEach((event) => {
    
    
      self.chart.on(event, (params) => {
    
    
        self.$emit(event, params);
      });
      self.chart.getZr()
          .on(event, (params) => {
    
    
            if (params) {
    
    
              const pointInPixel = [params.offsetX, params.offsetY];
              let xIndex: any; // x轴索引
              if (self.chart.containPixel('grid', pointInPixel)) {
    
    
                [xIndex] = self.chart.convertFromPixel({
    
     seriesIndex: 0 }, [params.offsetX, params.offsetY]);
              }
              // 点击到图表其他区域不操作
              if (typeof xIndex !== 'number') {
    
    
                return;
              }
              const option = self.chart.getOption();

              self.$emit(`${
      
      event}Zr`, {
    
    
                option,
                xIndex,
                dataIndex: xIndex,
                params,
              });
            }
          });
    });
  }

  resizeEle() {
    
    
    if (this.chart != null) {
    
    
      this.chart.resize();
    }
  }

  mounted() {
    
    
    this.$nextTick(() => {
    
    
      const self = this;
      self.init();
      self.resizeInterval = setInterval(() => {
    
    
        self.resizeEle();
      }, 2000);
    });
  }

  @Watch('options', {
    
    
    deep: true,
  })
  valueChange(newVal, oldVal) {
    
    
    if (newVal && newVal !== oldVal) {
    
    
      if (!this.chart) {
    
    
        this.chart = echarts.init(this.$refs.el as HTMLCanvasElement);
      }

      this.chart.setOption(newVal, true);
    }
  }

  freeChart() {
    
    
    clearInterval(this.resizeInterval);
    // 释放内存!
    if (this.chart) {
    
    
      this.chart.clear();
      this.chart.dispose();
    }
  }

  destroyed() {
    
    
    this.freeChart();
  }
}
</script>
<style scoped>
.container {
    
    
  position: relative;
  width: 100%;
  height: 100%;
}
</style>

使用:

<!--
 * @fileName: 数据统计-数量统计-NumberStatistics.vue
 * @date: yanghaoxing-2024-10-15 17:11:54
!-->
<template>
  <div class="body-con pt-2">
    <div class="flex title">
      <img :src="'/images/pageIcon/sltj.png' | imgBasePath">
      <span class="y-page-card-title">数量统计</span>
    </div>
    <div class="content">
      <VueEChart :style="{ height: echartsHeight, width: '100%'}"
                 :options="state.options" />
    </div>
  </div>
</template>

<script lang="ts">
import abpbase from '@/libs/abpbase';
import {
    
    
  Component, Emit, Mixins, Prop, Watch,
} from 'vue-property-decorator';
import EchartsMixin from '@/mixins/echartsMixin';
import VueEChart from '@/components/common/VueEChart.vue';
import echarts from 'echarts';

@Component({
    
    
  name: 'NumberStatistics',
  components: {
    
    
    VueEChart,
  },
})
export default class NumberStatistics extends Mixins(abpbase, EchartsMixin) {
    
    
  state = {
    
    
    options: {
    
    
      xAxis: {
    
    
        type: 'category',
        axisLabel: {
    
     interval: 0, rotate: 35 },
        data: [
          '历史文化名城',
          '历史文化名镇',
          '历史文化名村',
          '历史文化名街',
          '中国传统村落',
          '历史建筑',
        ],
      },
      yAxis: {
    
    
        type: 'value',
      },
      grid: {
    
    
        left: '1%',
        right: '4%',
        bottom: 0,
        top: '30px',
        containLabel: true,
      },
      series: [
        {
    
    
          data: [300, 260, 210, 140, 220, 240],
          type: 'bar',
          label: {
    
    
            show: true,
            position: 'top',
            valueAnimation: true,
            formatter: ({
     
      value }) => `${
      
      value}`,
          },
          barMaxWidth: '50%',
          itemStyle: {
    
    
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              {
    
     offset: 0, color: '#d0a2a8' },
              {
    
     offset: 0.5, color: '#d0737e' },
              {
    
     offset: 1, color: '#c85460' },
            ]),
          },
        },
      ],
    },
  }
}
</script>

<style lang="less" scoped>
.body-con {
    
    
  width: 100%;

  .title {
    
    
    align-items: center;

    img {
    
    
      height: 19px;
      width: 19px;
      margin-right: 2px;
    }
  }

  .content {
    
    
    width: 100%;
    height: 100%;
    min-height: 150px;
  }
}
</style>

猜你喜欢

转载自blog.csdn.net/qq_61950936/article/details/142969654