vue2+echarts:后台传递一天有多类数据的时候,如何渲染柱状图

1.需求描述

后台传输过来的json数据:

  • 一天可能有多个支付渠道进行交易,从而产生交易记录
  • 每天的支付渠道类型不定,需要进行判断

需求描述: 两个展示各渠道支付环境(支付渠道可能有多重)的柱状图,如下:

  • 柱状图1:

    • 需求: 每天需要展示的数据有:各个渠道的支付金额、退款金额、实收金额
    • 注意:
      • 每个渠道的所有都要展示完
      • 如果某渠道当天没有数据,已经在后台置零处理,故前台不再做处理
  • 柱状图2:

    • 需求:每天需要展示的数据有:各个渠道的支付笔数、退款笔数
    • 注意:
      • 每个渠道的所有都要展示完
      • 如果某渠道当天没有数据,已经在后台置零处理,故前台不再做处理

2.需求实现

柱状图样式代码:

        <div id="channelPayMoneyCharts" style="width: 100%;height:400px;" />
        <div id="channelPayTimeCharts" style="width: 100%;height:400px;" />

js:

  • 注意:channelData是父容器调用后台接口后传输过来的数据,数据格式如上所示
<script>
export default {
  name: 'channelPie',
  props: ['channelData'],
  data () {
    return {
      // 动态赋值给柱状图
      channelPayMoneyOptionData : [],
      channelPayMoneyOptionLegend : [],
      channelPayTimeOptionData : [],
      channelPayTimeOptionLegend : [],
	  
	  channelPayMoneyOption: {
        // 提示框组件,用于配置鼠标滑过或点击图表时的显示框
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow',
          },
        },
        // 标题
        title: {
          text: '各渠道支付次数汇总分析[单位:元]',
        },
        // 左侧显示图例(按钮)
        legend: {
          type: 'scroll',
          orient: 'horizontal',
          bottom: 10,
          // data: this.channelPayMoneyOptionLegend,
          data: []
        },
        toolbox: {
          show: true,
          orient: 'vertical',
          left: 'right',
          top: 'center',
          feature: {
            mark: { show: true, },
            dataView: { show: true, readOnly: false, },
            magicType: { show: true, type: ['line', 'bar', 'stack', 'tiled'], },
            restore: { show: true, },
            saveAsImage: { show: true, },
          },
        },
        xAxis: [
          {
            type: 'category',
            axisTick: { show: false, },
            data: [],
          }
        ],
        // y轴
        yAxis: [
          {
            type: 'value',
          }
        ],
        series: []
      },
      channelPayTimeOption: {
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow',
          },
        },
        title: {
          text: '各渠道支付次数汇总分析',
        },
        legend: {
          type: 'scroll',
          orient: 'horizontal',
          bottom: 10,
          data: [],
        },
        toolbox: {
          show: true,
          orient: 'vertical',
          left: 'right',
          top: 'center',
          feature: {
            mark: { show: true, },
            dataView: { show: true, readOnly: false, },
            magicType: { show: true, type: ['line', 'bar', 'stack', 'tiled'], },
            restore: { show: true, },
            saveAsImage: { show: true, },
          },
        },
        xAxis: [
          {
            type: 'category',
            axisTick: { show: false, },
            data: [],
          }
        ],
        yAxis: [
          {
            type: 'value',
            minInterval: 1,
            axisLabel: {
              formatter: '{value} 笔',
            },
          }
        ],
        series: []
      },
    }
  },
  watch: {
    channelData: {
      handler (newValue, oldValue) {
        this.setChannelCharts(newValue)
      },
      immediate: true,
    },
  },
  mounted () {
    this.showChannelPayMoneyCharts()
    this.showChannelPayTimeCharts()
  },
  methods: {
    // 初始化series的data数组的对象元素
    dataItem() {
      return {
        // 每个柱的名字
        name: '',
        type: '',
        data: []
      }
    },
    showChannelPayMoneyCharts () {
      const channelPayMoneyCharts = this.$echarts.init(document.getElementById('channelPayMoneyCharts'))
      channelPayMoneyCharts.setOption(this.channelPayMoneyOption,true)
    },
    showChannelPayTimeCharts () {
      const channelPayTimeCharts = this.$echarts.init(document.getElementById('channelPayTimeCharts'))
      channelPayTimeCharts.setOption(this.channelPayTimeOption,true)
    },
    setChannelCharts (data) {

	  // 每次赋值之前,先将数据置空一次
      this.channelPayMoneyOptionData = []
      this.channelPayMoneyOptionLegend = []
      this.channelPayTimeOptionData = []
      this.channelPayTimeOptionLegend = []

      if (data.channelTotals.length > 0 && data.channelDays.length > 0) {

        // region 柱状图数据获取
        // x轴的值
        const x = []
        for (let i = 0; i < data.channelDays.length; i++) {
          x.push(data.channelDays[i].day.substring(data.channelDays[i].day.length - 2, data.channelDays[i].day.length))
        }

        for (let i = 0; i < data.channelTotals.length; i++) {
          // 初始化5个对象,并给name赋值,有n个渠道,这里就初始化n*5个对象
          //截取name来判断支付渠道的类型
          const channelPayMoneyOptionDataItem1 = this.dataItem()
          channelPayMoneyOptionDataItem1.name = data.channelTotals[i].chName + "支付金额"
          channelPayMoneyOptionDataItem1.type = 'line'
          this.channelPayMoneyOptionData.push(channelPayMoneyOptionDataItem1)

          const channelPayMoneyOptionDataItem2 = this.dataItem()
          channelPayMoneyOptionDataItem2.type = 'line'
          channelPayMoneyOptionDataItem2.name = data.channelTotals[i].chName + "退款金额"
          this.channelPayMoneyOptionData.push(channelPayMoneyOptionDataItem2)

          const channelPayMoneyOptionDataItem3 = this.dataItem()
          channelPayMoneyOptionDataItem3.type = 'bar'
          channelPayMoneyOptionDataItem3.name = data.channelTotals[i].chName + "实收金额"
          this.channelPayMoneyOptionData.push(channelPayMoneyOptionDataItem3)

          const channelPayTimeOptionDataItem1 = this.dataItem()
          channelPayTimeOptionDataItem1.name = data.channelTotals[i].chName + "支付笔数"
          channelPayTimeOptionDataItem1.type = 'bar'
          this.channelPayTimeOptionData.push(channelPayTimeOptionDataItem1)

          const channelPayTimeOptionDataItem2 = this.dataItem()
          channelPayTimeOptionDataItem2.name = data.channelTotals[i].chName + "退款笔数"
          channelPayTimeOptionDataItem2.type = 'line'
          this.channelPayTimeOptionData.push(channelPayTimeOptionDataItem2)

          // 给legend数组的名字赋值
          this.channelPayMoneyOptionLegend.push(data.channelTotals[i].chName + "支付金额")
          this.channelPayMoneyOptionLegend.push(data.channelTotals[i].chName + "退款金额")
          this.channelPayMoneyOptionLegend.push(data.channelTotals[i].chName + "实收金额")

          this.channelPayTimeOptionLegend.push(data.channelTotals[i].chName + "支付笔数")
          this.channelPayTimeOptionLegend.push(data.channelTotals[i].chName + "退款笔数")
        }

        // 给柱状图标题赋值
        this.channelPayTimeOption.title.text = `${data.channelDays[0].day.substr(0, 4)}${data.channelDays[0].day.substr(5, 2)}月每天各支付渠道支付次数汇总统计`
        this.channelPayMoneyOption.title.text = `${data.channelDays[0].day.substr(0, 4)}${data.channelDays[0].day.substr(5, 2)}月每天各支付渠道支付金额汇总统计[单位:元]`


        for (let i = 0; i < data.channelDays.length; i++) {
          // 一天的数据
          for (let j = 0; j < data.channelDays[i].channelDayDetails.length; j++) {

            for (let k = 0; k < this.channelPayMoneyOptionData.length; k++) {
              if (data.channelDays[i].channelDayDetails[j].chName === this.channelPayMoneyOptionData[k].name.substring(0,this.channelPayMoneyOptionData[k].name.length-4)) {
                this.channelPayMoneyOptionData[k].data.push(data.channelDays[i].channelDayDetails[j].totalMoney)
                this.channelPayMoneyOptionData[k + 1].data.push(data.channelDays[i].channelDayDetails[j].refundMoney)
                this.channelPayMoneyOptionData[k + 2].data.push(data.channelDays[i].channelDayDetails[j].realPay)
                k += 2
              }
            }
            for (let l = 0; l < this.channelPayTimeOptionData.length; l++) {
              if (data.channelDays[i].channelDayDetails[j].chName === this.channelPayTimeOptionData[l].name.substring(0,this.channelPayTimeOptionData[l].name.length-4)) {
                this.channelPayTimeOptionData[l].data.push(data.channelDays[i].channelDayDetails[j].payTime)
                this.channelPayTimeOptionData[l + 1].data.push(data.channelDays[i].channelDayDetails[j].refundTimes)
                l++
              }
            }
          }
        }

        this.channelPayTimeOption.xAxis[0].data = x
        this.channelPayMoneyOption.xAxis[0].data = x
        this.channelPayMoneyOption.legend.data = this.channelPayMoneyOptionLegend
        this.channelPayMoneyOption.series = this.channelPayMoneyOptionData
        this.channelPayTimeOption.legend.data = this.channelPayTimeOptionLegend
        this.channelPayTimeOption.series = this.channelPayTimeOptionData

        // endregion

        //region 数据渲染
        this.showChannelPayMoneyCharts()
        this.showChannelPayTimeCharts()
        // endregion
      } else {
		// 清空数据
        if (this.channelPayTimeOption.series.length > 0) {
          for (let i = 0; i < this.channelPayTimeOption.series.length; i++) {
            this.channelPayTimeOption.series[i].data = []
          }
          this.channelPayTimeOption.xAxis[0].data = []
        }
        if (this.channelPayMoneyOption.series.length > 0) {
          for (let i = 0; i < this.channelPayMoneyOption.series.length; i++) {
            this.channelPayMoneyOption.series[i].data = []
          }
          this.channelPayMoneyOption.xAxis[0].data = []
        }

        this.showChannelPayCharts()
        this.showChannelTimesCharts()
        this.showChannelPayMoneyCharts()
        this.showChannelPayTimeCharts()
      }
      console.log(this.channelPayMoneyOption)
      console.log(this.channelPayTimeOption)
    },
  },
}
</script>

3.小结

  • legend的data赋值的时候,直接声明一个数组(存放字符串),然后将后台数据装进数组,然后再把数组的值传给legend.data就可以了

  • series赋值的时候,直接声明一个数组(存放对象),需要声明一个构造器来实例化对象,然后存进数组中,构造器的内容参考官方文档后,其属性有:name、type、data

        dataItem() {
          return {
            // 每个柱的名字
            name: '',
            type: '',
            data: []
          }
        },
    
  • 当一天的柱状图有 n 条,那么legenddata就需要装 n 个字符串,series就需要装 n 个对象

4.优化代码思路

这是一个前后端分离的项目,先说一下后台优化的思路,即如何数据置零:

  • 先遍历总体数据的所有支付渠道

  • 然后给每天的数据中都添加进所有支付渠道,即使那天渠道数据为空

    	这一步很简单,先实例化pojo赋初值,然后判断数据库数据是否为空
    		- 如果为空,那么久直接把pojo对象传进去(这时候,pojo所有值都是初始值,主要用来占位,保证数据与x轴日期一一对应)
    		- 如果不为空,那就将数据库数据赋值给pojo对象
    
  • 优化之后,后台传过来的每日数据如下:

接着是对上面的前端js代码的优化思路

  • legendseries 直接指向空数组,然后在赋值方法中声明对应的数组对象,最后给 legend和series赋值

            legend: {
              type: 'scroll',
              orient: 'horizontal',
              bottom: 10,
              data: [],
            },
            series: [],
            
            ...
            
            // Series==>需要显示的每一项数据名字、类型、以及数据
            const channelPayMoneySeries = []
            const channelPayTimeSeries = []
    
            // legend==>需要显示的标签(数据标签)
            const channelPayMoneyLegend = []
            const channelPayTimeLegend = []
    		...
    		// 给option赋值
    		this.channelPayTimeOption.xAxis[0].data = x
            this.channelPayMoneyOption.xAxis[0].data = x
            this.channelPayMoneyOption.legend.data = channelPayMoneyLegend
            this.channelPayMoneyOption.series = channelPayMoneySeriesNew
            this.channelPayTimeOption.legend.data = channelPayTimeLegend
            this.channelPayTimeOption.series = channelPayTimeSeriesNew
    
  • 因为后台数据已经优化,所以前端赋值代码也要改变,给legendseries的name和type的赋值只需要遍历 channelDays[0].channelDayDetails 就可
    因为js弱类型语言的特性,所以可以直接给series的data中的对象添加chId属性进去,进行类型判断,就不需要进行字符串截取判断了,这样更方便

    data.channelDays[0].channelDayDetails.forEach((channelDayDetail) => {
          const channelPayMoneyItem = this.dataItem()
          channelPayMoneyItem.name = channelDayDetail.chName + '支付金额'
          channelPayMoneyItem.chId = channelDayDetail.chId
          channelPayMoneyItem.type = 'line'
    
  • 现在给series赋值,其逻辑如下:

    • 循环赋值的语句依旧可以使用上述循环赋值的逻辑,不过现在是根据chId进行匹配对应的渠道数据
              data.channelDays.forEach((channelDay) => {
                channelDay.channelDayDetails.forEach((channelDayDetail) => {
                  channelPayMoneySeries.forEach((channelPayMoneySerie) => {
                    if (channelDayDetail.chId == channelPayMoneySerie.chId) {
      
    • 在赋值完成之后,为了显示的美观,需要删除没有数据的渠道(支付渠道存在多种,有的渠道在total中统计了,但是实际上并额没有人通过该渠道付款,如果不清除,会影响数据的直观显示)
              // 删除没有统计数据的渠道
              const channelPayMoneySeriesNew = channelPayMoneySeries.filter((channelPayMoneySerie) => {
                let dataSum = 0
                channelPayMoneySerie.data.forEach((dataItem) => {
                  dataSum += dataItem
                })
                return dataSum > 0
              })
      
              const channelPayTimeSeriesNew = channelPayTimeSeries.filter((channelPayTimeSerie) => {
                let dataSum = 0
                channelPayTimeSerie.data.forEach((dataItem) => {
                  dataSum += dataItem
                })
                return dataSum > 0
              })
      
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
是使用Vue2和Echarts实现立体柱状图的步骤: 1. 首先,需要在Vue项目中安装Echarts。可以使用npm或yarn进行安装,命令如下: ``` npm install echarts --save ``` 或者 ``` yarn add echarts ``` 2. 在Vue组件中引入Echarts,并创建一个Echarts实例: ```javascript import echarts from 'echarts' export default { data() { return { chartData: null } }, mounted() { this.initChart() }, methods: { initChart() { const chartDom = this.$refs.chart const myChart = echarts.init(chartDom) this.chartData = myChart } } } ``` 3. 在模板中添加一个div元素,用于渲染Echarts图表: ```html <template> <div class="chart-container"> <div ref="chart" class="chart"></div> </div> </template> ``` 4. 在Vue组件的方法中,使用Echarts的API创建立体柱状图: ```javascript const option = { tooltip: {}, visualMap: { max: 20, inRange: { color: ['#e0ffff', '#006edd'] } }, xAxis3D: { type: 'category', data: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] }, yAxis3D: { type: 'category', data: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] }, zAxis3D: { type: 'value' }, grid3D: { boxWidth: 200, boxDepth: 80, viewControl: { // projection: 'orthographic' }, light: { main: { intensity: 1.2, shadow: true }, ambient: { intensity: 0.3 } } }, series: [{ type: 'bar3D', data: [ ['A', 'Monday', 10], ['B', 'Monday', 8], ['C', 'Monday', 7], ['D', 'Monday', 6], ['E', 'Monday', 5], ['F', 'Monday', 4], ['G', 'Monday', 3], ['H', 'Monday', 2], ['A', 'Tuesday', 3], ['B', 'Tuesday', 5], ['C', 'Tuesday', 6], ['D', 'Tuesday', 7], ['E', 'Tuesday', 8], ['F', 'Tuesday', 9], ['G', 'Tuesday', 10], ['H', 'Tuesday', 11], ['A', 'Wednesday', 12], ['B', 'Wednesday', 10], ['C', 'Wednesday', 9], ['D', 'Wednesday', 8], ['E', 'Wednesday', 7], ['F', 'Wednesday', 6], ['G', 'Wednesday', 5], ['H', 'Wednesday', 4], ['A', 'Thursday', 5], ['B', 'Thursday', 7], ['C', 'Thursday', 8], ['D', 'Thursday', 9], ['E', 'Thursday', 10], ['F', 'Thursday', 11], ['G', 'Thursday', 12], ['H', 'Thursday', 13], ['A', 'Friday', 15], ['B', 'Friday', 13], ['C', 'Friday', 12], ['D', 'Friday', 11], ['E', 'Friday', 10], ['F', 'Friday', 9], ['G', 'Friday', 8], ['H', 'Friday', 7], ['A', 'Saturday', 4], ['B', 'Saturday', 6], ['C', 'Saturday', 7], ['D', 'Saturday', 8], ['E', 'Saturday', 9], ['F', 'Saturday', 10], ['G', 'Saturday', 11], ['H', 'Saturday', 12], ['A', 'Sunday', 16], ['B', 'Sunday', 14], ['C', 'Sunday', 13], ['D', 'Sunday', 12], ['E', 'Sunday', 11], ['F', 'Sunday', 10], ['G', 'Sunday', 9], ['H', 'Sunday', 8] ], shading: 'lambert', label: { textStyle: { fontSize: 16, borderWidth: 1 } }, itemStyle: { opacity: 0.8 } }] } this.chartData.setOption(option) ``` 这里的option是一个包含Echarts图表配置的对象,其中包括了x轴、y轴、z轴、数据等信息。可以根据实际需求进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

364.99°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值