175 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <section class="AiEchart">
 | 
						|
    <div ref="AiEchart" class="chart" :style="{minWidth:grid.width,minHeight:grid.height}"/>
 | 
						|
    <slot v-if="$slots.default"/>
 | 
						|
    <render-component v-else-if="ops.render" :render="ops.render" :options="chartOptions" :data="data"/>
 | 
						|
  </section>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
export default {
 | 
						|
  name: "AiEchart",
 | 
						|
  props: {
 | 
						|
    data: {default: () => []},
 | 
						|
    ops: {default: () => ({})},
 | 
						|
    type: {default: "line"},
 | 
						|
    series: Object,
 | 
						|
    theme: {
 | 
						|
      default: '0'
 | 
						|
    },
 | 
						|
  },
 | 
						|
  components: {
 | 
						|
    renderComponent: {
 | 
						|
      functional: true,
 | 
						|
      props: {
 | 
						|
        render: Function,
 | 
						|
        options: {default: () => ({})},
 | 
						|
        data: {default: () => []}
 | 
						|
      },
 | 
						|
      render(h, ins) {
 | 
						|
        let {options = {}, data} = ins.props
 | 
						|
        return ins.props.render(h, {...options, data})
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
  data() {
 | 
						|
    return {
 | 
						|
      chart: null,
 | 
						|
      timer: null
 | 
						|
    }
 | 
						|
  },
 | 
						|
  computed: {
 | 
						|
    colors() {
 | 
						|
      if (this.theme === '0') {
 | 
						|
        return ['#2896FF', '#09DBFE', '#61FDB9', '#FFBB69', '#8429FF', '#ea7ccc']
 | 
						|
      }
 | 
						|
      return this.color || ['#D4380D', '#CF1322', '#D55800', '#FA8C16', '#FFC53D', '#FFA940', '#FFC53D', '#780000']
 | 
						|
    },
 | 
						|
    chartOptions() {
 | 
						|
      let {type, data, ops: options = {}} = this,
 | 
						|
          style = this.series ? this.series : this.ops.daemon ? this.ops.daemon : {},
 | 
						|
          colors = this.theme === '1' ? this.colors : (options.color || this.colors),
 | 
						|
          legend = {textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14}},
 | 
						|
          series = data?.[0] ? Array(Object.keys(data?.[0]).length - 1).fill(1)
 | 
						|
              .map((e, i) => ({type, ...(typeof style == 'object' ? style : style(colors[i]))})) : []
 | 
						|
      let ops = {
 | 
						|
        tooltip: {},
 | 
						|
        xAxis: {
 | 
						|
          type: 'category', nameGap: 20, axisTick: false,
 | 
						|
          axisLabel: {
 | 
						|
            color: '#fff',
 | 
						|
            interval: 0,
 | 
						|
            rotate: this.data.length > 10 ? 40 : 0
 | 
						|
          },
 | 
						|
          axisLine: {
 | 
						|
            lineStyle: {
 | 
						|
              color: this.theme === '1' ? 'rgba(239, 163, 51, 0.8)' : 'rgba(255,255,255,.5)'
 | 
						|
            }
 | 
						|
          }
 | 
						|
        },
 | 
						|
        // 声明一个 Y 轴,数值轴。
 | 
						|
        yAxis: {
 | 
						|
          nameGap: 23, minInterval: 1,
 | 
						|
          splitLine: {
 | 
						|
            lineStyle: {
 | 
						|
              color: this.theme === '1' ? 'rgba(255, 197, 52, 0.4)' : 'rgba(255, 255, 255, .2)',
 | 
						|
              type: 'dashed'
 | 
						|
            }
 | 
						|
          },
 | 
						|
          axisLabel: {color: '#fff'}
 | 
						|
        },
 | 
						|
        grid: {
 | 
						|
          left: '0%',
 | 
						|
          right: '0%',
 | 
						|
          bottom: '0%',
 | 
						|
          top: '40px',
 | 
						|
          containLabel: true
 | 
						|
        },
 | 
						|
        legend, series, ...options,
 | 
						|
        color: colors,
 | 
						|
      }
 | 
						|
      if (JSON.stringify(this.ops) != JSON.stringify(ops)) this.$emit("update:ops", ops)
 | 
						|
      return ops
 | 
						|
    },
 | 
						|
    grid() {
 | 
						|
      let {width, height} = this.chartOptions.grid || {}
 | 
						|
      return {
 | 
						|
        width: width ? width + 'px' : 'auto',
 | 
						|
        height: height ? height + 'px' : 'auto'
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
  watch: {
 | 
						|
    data: {
 | 
						|
      deep: true, handler(v, old) {
 | 
						|
        let oldDims = Object.keys(old?.[0] || {})?.toString(),
 | 
						|
            current = Object.keys(v?.[0] || {})?.toString()
 | 
						|
        this.getChartData(oldDims != current)
 | 
						|
      }
 | 
						|
    },
 | 
						|
    theme() {
 | 
						|
      this.refresh()
 | 
						|
    }
 | 
						|
  },
 | 
						|
  methods: {
 | 
						|
    getChartData(render) {
 | 
						|
      if (!render) {
 | 
						|
        this.chart?.setOption({
 | 
						|
          dataset: {
 | 
						|
            source: this.data || []
 | 
						|
          }
 | 
						|
        })
 | 
						|
      } else {
 | 
						|
        this.chart?.setOption({
 | 
						|
          ...this.chartOptions,
 | 
						|
          dataset: {
 | 
						|
            source: this.data || []
 | 
						|
          }
 | 
						|
        }, true)
 | 
						|
      }
 | 
						|
      this.resize()
 | 
						|
    },
 | 
						|
    initChart() {
 | 
						|
      this.chart = echarts.init(this.$refs.AiEchart)
 | 
						|
      this.chart.setOption(this.chartOptions || {})
 | 
						|
    },
 | 
						|
    resize() {
 | 
						|
      const {clientHeight, clientWidth} = this.$refs.AiEchart || {},
 | 
						|
          h = this.chart?.getHeight(), w = this.chart?.getWidth()
 | 
						|
      if (h != clientHeight || w != clientWidth) {
 | 
						|
        this.chart?.resize()
 | 
						|
      }
 | 
						|
    },
 | 
						|
    watchResize() {
 | 
						|
      window.onresize = this.resize
 | 
						|
    },
 | 
						|
    refresh() {
 | 
						|
      this.chart.setOption(this.chartOptions || {})
 | 
						|
    }
 | 
						|
  },
 | 
						|
  mounted() {
 | 
						|
    this.$nextTick(() => {
 | 
						|
      this.watchResize()
 | 
						|
      this.initChart()
 | 
						|
      this.getChartData()
 | 
						|
    })
 | 
						|
  }
 | 
						|
}
 | 
						|
</script>
 | 
						|
 | 
						|
<style lang="scss" scoped>
 | 
						|
.AiEchart {
 | 
						|
  width: 100%;
 | 
						|
  height: 100%;
 | 
						|
  flex: 1;
 | 
						|
  min-width: 100px;
 | 
						|
  min-height: 0;
 | 
						|
  position: relative;
 | 
						|
 | 
						|
  .chart {
 | 
						|
    height: 100%;
 | 
						|
    min-height: 100px;
 | 
						|
  }
 | 
						|
}
 | 
						|
</style>
 |