229 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			5.9 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>
 | ||
| import * as echarts from 'echarts'
 | ||
| 
 | ||
| export default {
 | ||
|   name: "AiEchartV2",
 | ||
|   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,
 | ||
|       AiEchart: `AiEchart-${new Date().getTime()}`
 | ||
|     }
 | ||
|   },
 | ||
|   computed: {
 | ||
|     colors() {
 | ||
|       if (this.theme === '0') {
 | ||
|         return ['#00F9FF', '#1890FF', '#B13BFF', '#FC3BFF', '#95FF44', '#ea7ccc']
 | ||
|       }
 | ||
| 
 | ||
|       return ['#FFBA44', '#EC6666', '#FF3E18', '#C9FF82', '#29D7FA', '#ea7ccc']
 | ||
|     },
 | ||
| 
 | ||
|     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}, show: false},
 | ||
|           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: '#C3C4C4',
 | ||
|             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)',
 | ||
|               width: 1
 | ||
|             }
 | ||
|           }
 | ||
|         },
 | ||
|         // 声明一个 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: '#C3C4C4' },
 | ||
|           axisLine: {
 | ||
|             lineStyle: {
 | ||
|               color: '#C3C4C4'
 | ||
|             }
 | ||
|           }
 | ||
|         },
 | ||
|         legend, series, ...options,
 | ||
|         color: colors,
 | ||
|         grid: {
 | ||
|           left: '0%',
 | ||
|           right: '0%',
 | ||
|           bottom: '0%',
 | ||
|           top: '40px',
 | ||
|           containLabel: true
 | ||
|         }
 | ||
|       }
 | ||
|       return ops
 | ||
|     },
 | ||
|     grid() {
 | ||
|       let {width, height} = this.chartOptions.grid || {}
 | ||
|       return {
 | ||
|         width: width ? (width - this.legend === '1' ? 160 : 0) + '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: {
 | ||
|     deepAssign() {
 | ||
|       let name, options, src, copy
 | ||
|       let length = arguments.length
 | ||
|       // 记录要复制的对象的下标
 | ||
|       let i = 1
 | ||
|       // target默认是第一个参数
 | ||
|       let target = arguments[0] || {}
 | ||
|       // 如果target不是对象,我们是无法进行复制的,所以设为{}
 | ||
|       if (typeof target !== 'object') {
 | ||
|         target = {}
 | ||
|       }
 | ||
|       // 循环遍历要复制的对象
 | ||
|       for (; i < length; i++) {
 | ||
|         // 获取当前对象
 | ||
|         options = arguments[i]
 | ||
|         // 要求不能为空 避免extend(a,,b)这种情况
 | ||
|         if (options != null) {
 | ||
|           for (name in options) {
 | ||
|             // 目标属性值
 | ||
|             src = target[name]
 | ||
|             // 要复制的对象的属性值
 | ||
|             copy = options[name]
 | ||
| 
 | ||
|             if (copy && typeof copy == 'object') {
 | ||
|               // 递归调用
 | ||
|               target[name] = this.deepAssign( src, copy)
 | ||
|             } else if (copy !== undefined) {
 | ||
|               target[name] = copy
 | ||
|             }
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       return target
 | ||
|     },
 | ||
|     getChartData(render) {
 | ||
|       if (!render) {
 | ||
|         this.chart?.setOption({
 | ||
|           dataset: {
 | ||
|             source: this.data || []
 | ||
|           }
 | ||
|         })
 | ||
|       } else {
 | ||
|         this.chart?.setOption({
 | ||
|           ...this.chartOptions,
 | ||
|           dataset: {
 | ||
|             source: this.data || []
 | ||
|           }
 | ||
|         }, true)
 | ||
|       }
 | ||
|     },
 | ||
|     initChart() {
 | ||
|       this.chart = echarts.init(this.$refs[this.AiEchart])
 | ||
|       this.chart.setOption(this.chartOptions || {})
 | ||
|     },
 | ||
|     watchResize() {
 | ||
|       this.timer && clearInterval(this.timer)
 | ||
|       this.timer = setInterval(() => {
 | ||
|         if (this.chart?.getHeight() != this.$refs[this.AiEchart]?.clientHeight ||
 | ||
|             this.chart?.getWidth() != this.$refs[this.AiEchart]?.clientWidth) {
 | ||
|           this.chart?.resize()
 | ||
|         }
 | ||
|       }, 1000)
 | ||
|       //5分钟后停止监听
 | ||
|       setTimeout(() => this.timer && clearInterval(this.timer), 5 * 60 * 1000)
 | ||
|     },
 | ||
|     refresh() {
 | ||
|       this.chart.setOption(this.chartOptions || {})
 | ||
|     }
 | ||
|   },
 | ||
|   mounted() {
 | ||
|     this.$nextTick(() => {
 | ||
|     console.log(this.$refs[this.AiEchart])
 | ||
|       this.watchResize()
 | ||
|       this.initChart()
 | ||
|       this.getChartData()
 | ||
|     })
 | ||
|   },
 | ||
|   beforeDestroy() {
 | ||
|     this.timer && clearInterval(this.timer)
 | ||
|   }
 | ||
| }
 | ||
| </script>
 | ||
| 
 | ||
| <style lang="scss" scoped>
 | ||
| .AiEchart {
 | ||
|   display: flex;
 | ||
|   width: 100%;
 | ||
|   height: 100%;
 | ||
|   flex: 1;
 | ||
|   min-width: 100px;
 | ||
|   min-height: 0;
 | ||
|   position: relative;
 | ||
| 
 | ||
|   .chart {
 | ||
|     flex: 1;
 | ||
|     height: 100%;
 | ||
|     min-height: 100px;
 | ||
|   }
 | ||
| }
 | ||
| </style>
 |