数据可视化项目---售票员业绩排行

在数据可视化项目的初期, 我们会每个图表单独的进行开发, 最后再将所有的图表合并到一个界面中.
本项目中使用的ehcarts图表官网
最终的效果如下图所示:

在这里插入图片描述

售票员业绩排行-组件代码

<!--售票员销量统计的横向柱状图-->
<template>
    <div class="com-container">
        <div class="com-chart" ref="seller_ref"></div>
    </div>
</template>

<script>
    export default {
        name: "Seller",
        data(){
            return{
                chartInstance:null,
                allData:null,//服务器返回的数据
                currentPage:1,//当前显示的页数
                totalPage:0,//总页数
                timerId:null,//定时器标识
            }
        },
        mounted(){
          this.initChart();
          this.getData();
          window.addEventListener('resize',this.screenAdapter);
          //在页面加载完成忠厚,主动进行屏幕的适配
          this.screenAdapter();
        },
        destroy(){
            //停止定时器
            clearInterval(this.timerId);
            //在组件销毁的时候,将窗口监听器取消掉
            window.removeEventListener('resize',this.screenAdapter);
        },
        methods:{
            //初始化echartInstance对象
            initChart(){
                this.chartInstance=this.echarts.init(this.$refs.seller_ref,'chalk');
                //对图表初始化配置的控制
                const initOption={
                    //标题
                    title:{
                        text:'┃ 售票员业绩排行',
                        top:20,
                        left:20
                    },
                    //坐标轴
                    grid:{
                        top:'20%',
                        left:'3%',
                        right:'6%',
                        bottom:'3%',
                        containLabel:true   //设置距离包括图表上的文字
                    },
                    xAxis:{
                        type:'value'
                    },
                    yAxis:{
                        type:'category',
                    },
                    //提示工具
                    tooltip:{
                        trigger:'axis',
                        axisPointer:{
                            type:'line',
                            z:0,
                            lineStyle:{
                                color:'#2D3443'
                            }
                        }
                    },
                    //条目
                    series:[
                        {
                            type:'bar',
                            //条目上的文字
                            label:{
                                show:true,
                                position:'right',
                                textStyle:{
                                    color:'white'
                                }
                            },
                            //每一个柱子样式
                            itemStyle:{
                                //指明颜色渐变的方向
                                //指明不同百分比之下颜色的值
                                //echart中的颜色渐变对象----参数(指明颜色渐变的方向,指明不同百分比之下颜色的值)
                                color:new this.echarts.graphic.LinearGradient(0,0,1,0,[
                                    //百分之0状态下的颜色值
                                    {
                                        offset:0,
                                        color:'#5052EE'
                                    },
                                    //状态100%下的颜色值
                                    {
                                        offset:1,
                                        color:'#AB6EE5'
                                    }
                                ]),
                            }
                        }
                    ]
                };
                this.chartInstance.setOption(initOption);
                //对图表对象进行鼠标事件的监听
                this.chartInstance.on('mouseover',()=>{
                    //鼠标移入,轮播定时器停止
                    clearInterval(this.timerId);
                });
                this.chartInstance.on('mouseout',()=>{
                    //鼠标移入,轮播定时器开启
                    this.startInterval();
                });
            },
            //获取服务器数据
            async getData(){
                await this.axios.get("/order/querySellerOrder").then(res=>{
                    this.allData=res.data;
                });
                //对数组进行排序
                this.allData.sort((a,b)=>{
                    return a.value-b.value;//从小到大的顺序排序
                });
                //计算总页数(3个一页)
                this.totalPage=this.totalPage.length % 3 === 0 ? this.allData.length/3 : this.allData.length/3 +1;
                this.updateChart();
                //启动定时器
                this.startInterval()
            },
            //更新图表
            updateChart(){
                const start=(this.currentPage-1)*3;
                const end=(this.currentPage*3);
                const showData=this.allData.slice(start,end);
                const sellerNames=showData.map((item)=>{
                    return item.name
                });
                const sellerValues=showData.map((item)=>{
                    return item.value
                });
                const dataOption={
                    yAxis:{
                        data:sellerNames
                    },
                    //条目
                    series:[
                        {
                            data:sellerValues,
                        }
                    ]
                };
                this.chartInstance.setOption(dataOption);
            },
            startInterval(){//定时换页更新图表数据
                if (this.timerId) {
                    clearInterval(this.timerId);
                }
                this.timerId=setInterval(()=>{
                    this.currentPage++;
                    if (this.currentPage > this.totalPage) {
                        this.currentPage=1;
                    }
                    this.updateChart();
                },3000)
            },
            //当浏览器的大小发生变化的时候,调用该方法,来完成屏幕的适配
            screenAdapter(){
                //console.log(this.$refs.seller_ref.offsetWidth);
                const  titleFontSize=this.$refs.seller_ref.offsetWidth/100 * 3.6;
                //和分辨率大小相关的配置项
                const  adapterOption={
                    //标题
                    title:{
                        textStyle:{
                            fontSize:titleFontSize
                        },
                    },
                    //提示工具
                    tooltip:{
                        axisPointer:{
                            lineStyle:{
                                width:titleFontSize,
                            }
                        }
                    },
                    //条目
                    series:[
                        {
                            barWidth:titleFontSize,
                            //每一个柱子样式
                            itemStyle:{
                                barBorderRadius:[0,titleFontSize/2,titleFontSize/2,0],
                            }
                        }
                    ]
                };
                this.chartInstance.setOption(adapterOption);
                //手动的调用图表的resize方法
                this.chartInstance.resize();
            }
        }
    }
</script>

<style scoped>
    .com-container{
        width: 100%;
        height: 100%;
        overflow: hidden;
    }
    .com-chart{
        width: 100%;
        height: 100%;
        overflow: hidden;
        border-radius: 20px;
    }
</style>

售票员业绩排行-接口获取的图表数据

JSON数据

[{"name":"刘总","value":"1105"},{"name":"刘师傅","value":"6"},{"name":"小丁","value":"4"},{"name":"小陈","value":"5"}]

截图
在这里插入图片描述

售票员业绩排行-设计流程

最终的效果如下图所示:

在这里插入图片描述

1.组件结构设计

  • src/components/ 目录下建立 Seller.vue , 这个组件是真实展示图表的组件
    • 给外层div增加类样式 com-container
    • 建立一个显示图表的div元素
    • 给新增的这个div增加类样式 com-chart
<!-- 显示商家销量统计的图表 --> 
<template>
	<div class="com-containter">
		Seller组件
		<div class="com-chart"></div>
	</div>
</template>

<script>
export default {
    data(){
        return {}
    },
    methods:{}
}
</script>

<style lang="less" scoped>
</style>
  • src/views/ 目录下建立 SellerPage.vue ,这个组件是对应于路由 /seller 而展示的
    • 给外层div元素增加样式 com-page
    • SellerPage 中引入 Seller 组件,并且注册和使用
<!--
    针对于 /sellerpage 这条路径显示出来的
    在这个组件中,通过子组件注册的方式,要显示除Seller.vue这个组件
-->
<template>
    <div class="com-page">
        <Seller></Seller>
    </div>
</template>

<script>
    import Seller from "../components/Seller";
    export default {
        name: "SellerPage",
        components: {Seller},
    }
</script>

<style lang='less' scoped>
</style>
  • 增加路由规则,在src/router/index.js文件中修改
......
import SellerPage from "../views/SellerPage";
......
cost routes=[
  {
    path: '/sellerpage',
    name: 'SellerPage',
    component:SellerPage
  },
]
  • 新建src/assets/css/global.less增加宽高的样式
    原则就是将所有的容器的宽度和高度设置为占满父容器
html,
body,
#app {
	width:100%;
	heigth:100%;
	padding:0;
	overflow:hidden;
}
.com-page {
	width:100%;
	heigth:100%;
	overflow:hidden;
}
.com-container{
	width:100%;
	heigth:100%;
	overflow:hidden;
}
.com-chart{
	width:100%;
	heigth:100%;
	overflow:hidden;
}

main.js中引入样式

import './assets/css/global.less'
  • 打开浏览器,输入http://127.0.0.1:8080/sellerpage看Seller组件是否能够显示

2.图表Seller.vue基本功能的实现

  • 1.在mounted生命周期中初始化echartsInstance对象
  • 2.在mounted中获取服务器的数据
  • 3.将获取到的数据设置到图表上
<script>
	export default{
		data(){
            return {
                charInstance:null,//echarts实例对象
                allData:[]//服务器获取的所有数据
            }
        }, 
        mounted (){
            //由于初始化echarts实例对象需要使用到dom元素,因此必需要放到mounted中,而不是created
            this.initChart();
            this.getData();
        },
        methods:{
            initChart(){
				this.charInstance=this.echarts.init(this.$refs.seller_ref)//初始化echarts对象
            },
            async getData(){
                await this.axios.get("/order/querySellerOrder").then(res=>{
                    this.allData=res.data;
                });
                //对数组进行排序
                this.allData.sort((a,b)=>{
                    return a.value-b.value;//从小到大的顺序排序
                });
                this.updateChart()
            },
            updateChart(){
                //处理数据并更新界面图表
                const sellerNames=this.allData.map((item)=>{
                    return item.name
                })
                const sellervalues=this.allData.map((item)=>{
                    return item.value
                })
                const option={
                    xAxis:{
                        type:'value'
                    },
                    yAxis:{
                        type:'category',
                        data:sellerName
                    },
                    series:[
                        {
                            type:'bar',
                            data:sellervalues
                        }
                    ]
                }
                this.charInstance.setOption(option)
            }    
        }    
	}    
</script>
  • 4.拆分配置项option
    • 初始化配置项在这里插入图片描述

    • 拥有数据之后的配置项[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QkJW9GPz-1603789673884)(C:\Users\Chef Liu\AppData\Roaming\Typora\typora-user-images\image-20201027162916997.png)]

3.分页动画的实现

  • 数据的处理,每5个元素显示一页

    • 数据的处理2是在这里插入图片描述

    • 动画的的启动和停止2在这里插入图片描述在这里插入图片描述

    • 鼠标事件的处理2

  • 细节的处理

    • 固定x轴最大值
const option={
	xAxis:{
		type:'value',
		max:this.allData[this.allData.length-1].value
	}
}

4.ui效果调整

  • 主题文件的导入

    main,js中引入s

  • 主题的指定,在初始化echarts实例对象的时候指定

    src/components/Seller.vue3

  • 边框圆角的设置

    src/assets/css/global.less

    canvas{
        border-radius:20px;
    }
    
  • 其他图表样式的配置

    • 标题的位置和颜色

      const initOption={
           //标题
          title:{
              text:'┃ 售票员业绩排行',
              top:20,
              left:20,
              textStyle:{
                  textStyle:{
                      "color":"#fff"
                  }
              }
          },
      }
      
    • 坐标轴的大小

      const initOption={
      		//坐标轴
              grid:{
                  top:'20%',
                  left:'3%',
                  right:'6%',
                  bottom:'3%',
                  containLabel:true   //设置距离包括图表上的文字
              },
      }
      
    • 工具提示和背景

      const initOption={
              //提示工具
              tooltip:{
                  trigger:'axis',
                  axisPointer:{
                      type:'line',
                      z:0,
                      lineStyle:{
                          color:'#2D3443'
                      }
                  }
              },
      }
      
    • 文字提示和位置

      const initOption={
              //提示工具
              series:[
                  {
                   	......
                      label:{
                          show:true,
                          position:'right',
                          textStyle:{
                              color:'#fff'
                          }
                      }
                  }
              ],
      }
      
    • 柱宽度和柱圆角的实现

      const initOption={
              series:[
                  {
                   	......
                      barwidth:66,
                      itemStyle:{
                          barBorderRadius:[0,33,33,0]
                      }
                  }
              ],
      }
      
    • 柱颜色渐变的实现

      线性渐变可以通过LinearGradient进行实现

      LinearGradient需要传递5个参数,前四个代表两点的相对位置。第五个参数代表颜色变化的范围

      0,0,1,0代表的是从左往右的方向

      const initOption={
              series:[
                  {
                   	......
                      itemStyle:{
                                      //指明颜色渐变的方向
                                      //指明不同百分比之下颜色的值
                                      //echart中的颜色渐变对象----参数(指明颜色渐变的方向,指明不同百分比之下颜色的值)
                                      color:new this.echarts.graphic.LinearGradient(0,0,1,0,[
                                          //百分之0状态下的颜色值
                                          {
                                              offset:0,
                                              color:'#5052EE'
                                          },
                                          //状态100%下的颜色值
                                          {
                                              offset:1,
                                              color:'#AB6EE5'
                                          }
                                      ]),
                                  }
                  }
              ],
      }
      

5.分辨率适配

  • 对窗口大小变化的事件进行监听

    mounted时候监听

    mounted(){
        this.initChart();
        this.getData();
        window.addEventListener('resize',this.screenAdapter);
    },
    

    组件销毁时取消监听

     destroy(){
         //停止定时器
         clearInterval(this.timerId);
         //在组件销毁的时候,将窗口监听器取消掉
         window.removeEventListener('resize',this.screenAdapter);
     },
    
  • 获取图表容器的宽度计算字体的大小

     screenAdapter(){
                    const  titleFontSize=this.$refs.seller_ref.offsetWidth/100 * 3.6;
    
  • 将字体大小的值设置给图表的某些区域

    • 标题大小

    • 背景大小

    • 柱宽度

    • 圆角大小

      //当浏览器的大小发生变化的时候,调用该方法,来完成屏幕的适配
      screenAdapter(){
          //console.log(this.$refs.seller_ref.offsetWidth);
          const  titleFontSize=this.$refs.seller_ref.offsetWidth/100 * 3.6;
          //和分辨率大小相关的配置项
          const  adapterOption={
              //标题
              title:{
                  textStyle:{
                      fontSize:titleFontSize
                  },
              },
              //提示工具
              tooltip:{
                  axisPointer:{
                      lineStyle:{
                          width:titleFontSize,
                      }
                  }
              },
              //条目
              series:[
                  {
                      barWidth:titleFontSize,
                      //每一个柱子样式
                      itemStyle:{
                          barBorderRadius:[0,titleFontSize/2,titleFontSize/2,0],
                      }
                  }
              ]
          };
          this.chartInstance.setOption(adapterOption);
          //手动的调用图表的resize方法
          this.chartInstance.resize();
      }
      

下一篇:数据可视化项目—客源分析趋势图

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值