echarts柱图和线图组件

以前云桌面项目写的,功能不多,但是适配基础的柱图和线图完全够了,还可以优化或者拓展很多,后面用vue3开发某个项目的时候有基于这个做过完善和拓展,不过就不是v2的组件了
若有用到,可自行完善

  • html和css部分
<template>
  <div ref="myChars" class="com-bar-chart" />
</template>
<style scoped>
.com-bar-chart {
  width: 100%;
  height: 100%;
}
</style>
  • js部分
<script>
import * as echarts from 'echarts'
export default {
  name: 'EchartLineBar',
  props: {
    // 数据,数据结构就为数组对象结构[{key1:'', key2:'', key3:'',...},{}]
    sourceData: {
      type: Array,
      default: () => []
    },
    // echarts配置[{field: '', name: '', color: '', type: 'line',...}, {}]
    // 多个对象代表多个线或柱
    // field(字段名),name(series的名字),color(颜色,可单个,可数组两值渐变),type(图类型)
    seiresConfig: {
      type: Array,
      default: () => []
    },
    // grid位置
    grid: {
      type: Object,
      default() {
        return {}
      }
    },
    // 值轴配置,可以双值轴
    yAxisList: {
      type: Array,
      default() {
        return []
      }
    },
    // 类目轴配置
    xAxis: {
      type: Object,
      default() {
        return {}
      }
    },
    // 颜色
    colors: {
      type: Array,
      default: () => ['#0EECE4', '#306FFF']
    },
    // legend配置
    legendConfig: {
      type: Object,
      default() {
        return {}
      }
    },
    titleConfig: {
      type: Object,
      default() {
        return {}
      }
    },
    dataZoom: {
      type: [Object, Array],
      default: () => {}
    },
    // 是否X轴作为类目轴
    xCategory: {
      type: Boolean,
      default: true
    },
    // 是否展示tooltip
    tooltip: {
      type: Object,
      default() {
        return {}
      }
    },
    // 是否需要点击折线图的线条返回索引
    isClickLine: {
      type: Boolean,
      default: false
    },
    // 定时器重复渲染,秒数,为0则不重复渲染
    isInfinite: {
      type: [Number, String],
      default: 0
    }
  },
  data() {
    return {
      curCharts: null,
      timer: null
    }
  },
  computed: {
    watchData() {
      return {
        data: this.sourceData,
        config: this.seiresConfig
      }
    }
  },
  watch: {
    watchData: {
      handler() {
        this.drawChart()
      },
      deep: true
    }
  },
  mounted() {
    this.drawChart()
  },
  methods: {
    _map(data, field) {
      return data.map((item) => (item[field] || '--'))
    },
    drawChart() {
      this.curCharts = echarts.init(this.$refs.myCharts, undefined, { renderer: 'canvas' })
      const legends = []
      // 处理数据
      // 传入原始数据处理
      const seriesList = this.seiresConfig
        // .filter((item) => !!item.field)
        .map((item, index) => {
          legends.push({
            name: item.name,
            itemStyle: {
              color: item.color ? (typeof item.color === 'string' ? item.color : item.color[0]) : '#fff'
            }
          })
          const obj = {
            name: item.name || '',
            // 为了适配传入的series的data模式为对象模式,条件是type为bar
            data:
              !item.colors || item.colors.length === 0
                ? this._map(this.sourceData, item.field || 'value')
                : this.sourceData.map((sitem, sindex) => {
                    const sobj = {
                      name: sitem.name || '',
                      value: sitem[item.field || 'value'],
                      barWidth: item.barWidth || 6,
                      barGap: item.barGap || '30%',
                      z: item.z || '1',
                      itemStyle: {},
                      label: {}
                    }
                    if (item.type === 'bar') {
                      sobj.itemStyle = {
                        color:
                          typeof item.colors[sindex % item.colors.length] === 'string'
                            ? item.colors[sindex % item.colors.length]
                            : new echarts.graphic.LinearGradient(0, 0, this.xCategory ? 0 : 1, this.xCategory ? 1 : 0, [
                                {
                                  offset: 0,
                                  color: item.colors[sindex % item.colors.length][0],
                                  opacity: 0.85
                                },
                                {
                                  offset: 1,
                                  color: item.colors[sindex % item.colors.length][1],
                                  opacity: 0.79
                                }
                              ])
                      }
                      sobj.label = {
                        color:
                          typeof item.colors[0] === 'string'
                            ? item.colors[sindex % item.colors.length]
                            : item.colors[sindex % item.colors.length][0],
                        ...item.label
                      }
                    }
                    return sobj
                  }),
            type: item.type || 'line',
            yAxisIndex: item.yAxisIndex || 0,
            stack: item.stack || '',
            label: {
              show: false,
              fontSize: 14,
              position: 'top',
              color: item.color ? (typeof item.color === 'string' ? item.color : item.color[0]) : '#fff',
              ...item.label
            }
          }
          if (!item.type || item.type === 'line') {
            obj.smooth = item.smooth || true
            obj.symbol = item.symbol || 'circle'
            obj.symbolSize = item.symbolSize || 10
            obj.itemStyle = {
              color: item.color || (this.colors.length > 0 ? this.colors[index % this.colors.length] : '#fff'),
              borderWidth: ((item.symbolSize || 10) / 4).toFixed(0),
              borderColor: '#fff'
            }
            obj.lineStyle = {
              width: item.lineWidth || 2,
              type: item.lineType || 'solid',
              color: item.color || (this.colors.length > 0 ? this.colors[index % this.colors.length] : '#fff')
            }
            // 线条填充区域
            if (item.areaColor) {
              obj.areaStyle = {
                color:
                  typeof item.areaColor === 'string'
                    ? item.areaColor
                    : new echarts.graphic.LinearGradient(0, 0, this.xCategory ? 0 : 1, this.xCategory ? 1 : 0, [
                        {
                          offset: 0,
                          color: item.areaColor[0]
                        },
                        {
                          offset: 1,
                          color: item.areaColor[1]
                        }
                      ])
              }
            }
          } else {
            obj.barWidth = item.barWidth || 6
            obj.barGap = item.barGap || '30%'
            obj.z = item.z || '1'
            // bar的颜色,判断不存在就用props中的颜色,如果单个字符串,就为纯色,否则数组两个颜色渐变
            obj.itemStyle = {
              color: item.color
                ? typeof item.color === 'string'
                  ? item.color
                  : new echarts.graphic.LinearGradient(0, 0, this.xCategory ? 0 : 1, this.xCategory ? 1 : 0, [
                      {
                        offset: 0,
                        color: item.color[0],
                        opacity: 0.85
                      },
                      {
                        offset: 1,
                        color: item.color[1],
                        opacity: 0.79
                      }
                    ])
                : this.colors.length > 0
                ? this.colors[index % this.colors.length]
                : '#fff'
            }
          }
          return obj
        })
      // console.log(seriesList,'1111');

      // 定义渲染参数
      const option = {
        tooltip: {
          trigger: 'axis',
          confine: true,
          padding: [5, 10],
          borderColor: '#25324F',
          backgroundColor: '#25324F',
          axisPointer: {
            // 鼠标移入坐标指示器
            type: 'cross',
            animation: false,
            label: {
              backgroundColor: '#505765'
            }
          },
          show: true,
          extraCssText: 'border-radius: 2px;',
          textStyle: {
            color: '#ffffff',
            fontSize: 14
          },
          formatter: (params) => {
            let result = ''
            if (Object.prototype.toString.call(params) === '[object Object]') {
              params = [params]
            }
            params = params.filter((item) => item.seriesName !== 'noTooltip' && item.data !== '-')
            // 处理尺寸大小问题
            for (const item of params) {
              const dotHtml = `<span style="display:inline-block;margin-right:3px;border-radius:${8}px;height:${8}px;width:${8}px;background-color:${
                item.seriesType === 'line'
                  ? item.color || item.borderColor
                  : typeof item.color === 'string'
                  ? item.color
                  : item.color.colorStops[0].color
              }"></span>`
              result += `</br>${dotHtml}${item.seriesName || ''} ${item.value || 0}`
            }
            return (params[0].axisValue || params[0].name || '') + result
          },
          ...this.tooltip
        },
        color: this.colors,
        title: {
          ...this.titleConfig
        },
        grid: {
          top: 30,
          bottom: 25,
          left: 25,
          right: 10,
          ...this.grid
        },
        legend: {
          data: legends,
          top: 5,
          right: 10,
          itemGap: 10,
          itemWidth: 10,
          itemHeight: 10,
          itemStyle: {
            // color:,
            borderWidth: 0
          },
          lineStyle: {
            width: 5
          },
          orient: 'horizontal', // vertical:纵向  horizontal: 横向
          textStyle: {
            color: '#fff',
            fontSize: 14,
            padding: [0, 0, 0, 5]
          },
          ...this.legendConfig
        },
        animationDuration: 2000,
        series: seriesList
      }
      if (this.dataZoom) {
        option.dataZoom = this.dataZoom
      }
      // 类目对象属性
      const categoryObj = {
        type: 'category',
        scale: true,
        boundaryGap: true, //两边是否留白
        data: this._map(this.sourceData, 'name'),
        // nameGap: 90, // 坐标轴名称与轴线之间的距离
        ...this.xAxis,
        ...{
          axisLine: {
            show: false,
            lineStyle: {
              width: 2,
              color: '#fff'
            },
            ...(this.xAxis.axisLine || {})
          },
          minorTick: {
            lineStyle: {
              color: 'rgba(255,255,255,0.2)'
            },
            ...(this.xAxis.minorTick || {})
          },
          axisTick: {
            show: false,
            length: 5,
            inside: true, // 朝内
            lineStyle: {
              width: 7
            },
            ...(this.xAxis.axisTick || {})
          },
          axisLabel: {
            show: true,
            fontSize: 14,
            color: '#ffffff',
            margin: 10,
            // overflow: 'truncate',
            // interval: 0,
            ...(this.xAxis.axisLabel || {})
          },
          axisPointer: {
            // 鼠标移入坐标指示器
            type: 'line',
            lineStyle: {
              type: 'dashed'
            },
            ...(this.xAxis.axisPointer || {})
          }
        }
      }
      // 值轴属性
      const valueObj = []
      if (this.yAxisList && this.yAxisList.length > 0) {
        this.yAxisList.map((item) => {
          valueObj.push({
            type: 'value',
            // splitNumber: 5, // 分几个区间
            ...item,
            ...{
              nameTextStyle: {
                fontSize: 14,
                color: '#fff',
                align: 'center',
                padding: [0, 0, 0, 0],
                ...(item.nameTextStyle || {})
              },
              axisLine: {
                show: false,
                lineStyle: {
                  width: 1,
                  color: '#fff'
                },
                ...(item.axisLine || {})
              },
              axisLabel: {
                formatter: '{value}',
                margin: 4,
                textStyle: {
                  color: '#fff',
                  fontSize: 14
                },
                ...(item.axisLabel || {})
              },
              splitLine: {
                show: true,
                lineStyle: {
                  type: 'dashed',
                  width: 1,
                  color: 'rgba(255,255,255,0.1)'
                },
                ...(item.splitLine || {})
              }
            }
          })
        })
      }
      if (this.xCategory) {
        option.xAxis = categoryObj
        option.yAxis = valueObj
      } else {
        option.xAxis = valueObj
        option.yAxis = categoryObj
      }
      if (valueObj.length > 0) {
        this.curCharts.setOption(option)
        if (this.isClickLine) {
          // 如果需要点击折现也回调,则使用下面的方法
          this.curCharts.getZr().on('click', (item) => {
            let index = 0
            if (item.target) {
              index = item.target.parent.parent['__ecComponentInfo'].index || 0
              this.$emit('itemClick', index)
            }
          })
        } else {
          // 普通柱子和折现的点点击回调
          this.curCharts.on('click', (item) => {
            this.$emit('itemClick', item)
          })
        }
      }
      // 定时器,循环播放动画
      if (this.isInfinite > 0) {
        this.timer = setInterval(() => {
          this.curCharts.clear()
          this.curCharts.setOption(option)
        }, Number(this.isInfinite) * 1000)
      }
    }
  },
  beforeDestroy() {
    clearInterval(this.timer)
  }
}
</script>
  • 示例

临时加的示例,若有问题请自行修正,很久以前的云桌面项目中写的了,没有项目源码
多个图若配置差不多,甚至于可以就用同一个配置,不同的config
list仅仅是为了demo数据,实际对接接口的时候可以单独提出来传入,如第二个图

<template>
<EchartLineBar 
	:tooltip="chartConfig.tooltip"
	:grid="chartConfig.grid"
	:legendConfig="chartConfig.legend"
	:sourceData="chartConfig.list"
	:seiresConfig="chartConfig.config"
	 />
<EchartLineBar 
	:tooltip="chartConfig.tooltip"
	:grid="chartConfig.grid"
	:legendConfig="chartConfig.legend"
	:dataZoom="chartConfig.dataZoom"
	:sourceData="lineData"
	:seiresConfig="chartConfig.configLine"
	 />
</template>
<script>
export default {
  data() {
    return {
      // 第二个线图数据
      lineData: [
      	{ name: '四川省', value: 985, value2: 830 },
        { name: '广东省', value: 8, value2: 8 },
        { name: '江苏省', value: 5, value2: 12 },
      ],
      // 线图和柱图的共有配置
	  chartConfig: {
		    tooltip: {
		        show: true
		    },
		    grid: {
		        top: 40,
		        bottom: 50,
		    },
		    legend: {
		        icon: 'rect',
		        show: true,
		        itemWidth: 16,
		        itemHeight: 16,
		        left: 'center',
		        top: 7,
		        textStyle: {
		            padding: 25,
		            color: '#FFF',
		            fontSize: 17
		        }
		    },
		    config: [
		        {
		            name: '迁入',
		            type: 'bar',
		            field: 'value',
		            barWidth: 25,
		            color: ['#A5DB0D', '#05D23F'],
		            label: {
		                show: true,
		                position: 'top'
		            },
		        },
		        {
		            name: '迁出',
		            type: 'bar',
		            field: 'value2',
		            barWidth: 25,
		            color: ['#ECBB0E', '#E78D05'],
		            label: {
		                show: true,
		                position: 'top'
		            },
		        },
		    ],
		    configLine: [
		    	{ 
		    		name: '水位', 
		    		field: 'z', 
		    		color: '#2082e6', 
		    		symbol: 'none', 
		    		areaColor: ['#64a7eb', '#64a7eb36']
		    	},
		    	{ 
			    	name: '流量', 
			    	field: 'q', 
			    	yAxisIndex: 1, 
			    	color: '#26e3d6', 
			    	symbol: 'none' 
		    	},
		        { 
			        name: '警戒水位', 
			        field: 'wrz', 
			        color: '#ffdd98', 
			        symbol: 'none', 
			        lineType: 'dashed' 
		        },
		    ],
	        dataZoom: {
		      show: true,
		      height: 10,
		      bottom: 40,
		      start: 0,
		      end: 100,
		      handleIcon:
		        'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
		      handleStyle: {
		        color: '#d3dee5'
		      }
		    },
		    list: [
		        { name: '四川省', value: 985, value2: 830 },
		        { name: '广东省', value: 8, value2: 8 },
		        { name: '江苏省', value: 5, value2: 12 },
		        { name: '山东省', value: 4, value2: 12 },
		        { name: '重庆市', value: 4, value2: 6 },
		        { name: '甘肃省', value: 4, value2: 0 },
		        { name: '陕西省', value: 3, value2: 1 },
		        { name: '北京市', value: 2, value2: 0 },
		        { name: '浙江省', value: 2, value2: 12 },
		        { name: '贵州省', value: 2, value2: 0 },
		        { name: '西藏', value: 2, value2: 1 },
		        { name: '上海市', value: 1, value2: 2 },
		        { name: '福建省', value: 1, value2: 20 },
		        { name: '湖北省', value: 1, value2: 0 },
		        { name: '湖南省', value: 1, value2: 1 },
		        { name: '云南省', value: 1, value2: 0 },
		        { name: '新疆', value: 1, value2: 0 },
		        { name: '河南省', value: 0, value2: 7 },
		        { name: '天津市', value: 1, value2: 2 },
		        { name: '河北省', value: 2, value2: 1 },
		        { name: '安徽省', value: 3, value2: 1 },
		        { name: '宁夏', value: 4, value2: 1 },
		    ]
		}
	}
  },
}
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值