基于vue2、echarts5的数据大屏

16,534 阅读4分钟

屏幕适配

大屏成像原理几乎都是投屏,也就是把电脑屏幕通过有线信号投放到大屏上,电脑上呈现什么内容,大屏上就会呈现什么内容,所以电脑屏幕横向和纵向上都不能出现滚条。在网上看了一些适配方案,最后参考了大屏数据可视化——屏幕适配方案(多分辨率下),用CSS3的scale,将容器设置为设计稿宽高,如3840*2160,动态根据浏览器视口的宽高进行缩放,从而实现容器始终铺满浏览器视口,而不出现滚动条。

容器组件的结构:

<template>
<div class="bsd-frame" :style="{'background': bgColor}" ref="bsdFrame">
  <slot></slot>
</div>
</template>

第一步、获取容器实际宽高,通常是设计稿宽高,或者电脑屏幕的宽高。

setSize () {
  this.frameWidth = this.width || screen.width 
  this.frameHeight = this.height || screen.height

  const frame = this.$refs.bsdFrame  //为容器根元素设置宽高
  frame.style.width = this.frameWidth + 'px'
  frame.style.height = this.frameHeight + 'px'
}

第二步、根据浏览器视口的的宽高,为容器设置缩放比例。

setScale () {
   const bodyWidth = document.body.clientWidth  //前提是html,body的height: 100%; width: 100%
   const bodyHeight = document.body.clientHeight
   const scaleX = bodyWidth / this.frameWidth
   const scaleY = bodyHeight / this.frameHeight

   this.$refs.bsdFrame.style.transform = `scale(${scaleX},${scaleY})`
}

第三部、监听resize事件,每次触发resize事件时,重新计算容器缩放比例。

mounted () {
  this.setSize()
  this.setScale()
  window.addEventListener('resize', this.setScale)
},
destroyed () {
  window.removeEventListener('resize', this.setScale)
}

echarts开发图表

主要用了柱状图、折线图、饼图等基础图表,以及地图。这部分主要的工作就是对着echarts配置项调整图标配置。 echarts.apache.org/zh/option.h…

echarts5对按需引入作了调整。将渲染器、组件和图表从echarts核心分离开来,根据需要进行引用,之前默认包含canvas和svg渲染器,现在可以根据需要选择canvas渲染器或是svg渲染器。组件和图表的按需引入方式和之前也不一样。比如要画一个带标题的折线图,就像下面这样引入TitleComponent、LineChart。

import * as echarts from 'echarts/core';
import { TitleComponent } from 'echarts/components';
import { LineChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use(
    [TitleComponent, LineChart, CanvasRenderer]
);

使用:

var dom = document.getElementById('main');
var myChart = echarts.init(dom);    //初始化
var option = {
    xAxis: {
        type: 'category',
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    },
    yAxis: {
        type: 'value'
    },
    series: [{
        data: [150, 230, 224, 218, 135, 147, 260],
        type: 'line'
    }]
};

option && myChart.setOption(option);  // 设置选项

要在一个dom中绘制图表,首先是echarts.init(dom)初始化一个echarts实例,然后为这个实例设置选项myChart.setOption(option),就可以完成图表的绘制了。可以参考官网的案例,echarts案例

当数据发生改变,要重新绘制,就再次调用myChart.setOption(newOption)

项目中很多地方都要用到echarts,之前用的vue-echarts组件库是基于echarts4的,所以就简易地基于echarts5封装了一个组件,可以根据传入的option初始化图表,当option发生改变,重新渲染图表。

<template>
  <div class="echarts"></div>
</template>
<script>
import * as echarts from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([CanvasRenderer])
export default {
  name: 'vue-echarts',
  props: {
    options: {
      type: Object,
      required: true
    }
  },
  watch: {
    options (newValue, oldValue) {
      if (this.chart && newValue) {  //没有设置deep:true,所以当数据改变时,要改变option指针,才能触发该方法。
        this.chart.setOption(newValue)
      }
    }
  },
  methods: {
    init (opt) {
      if (!this.chart) {
        this.chart = echarts.init(this.$el)
      }
      this.chart.setOption(this.options)
    }
  },
  mounted () {
    this.init()
  }
}
</script>
<style lang="scss" scoped>
.echarts {
  width: 100%;
  height: 100%;
}
</style>

使用:

<vue-echarts :options="chartOption" />
computed: {
  chartOption () {
    const categorySales = this.$store.state.categorySales
    categoryOpt.series[0].data = categorySales
    return Object.assign({}, categoryOpt)
  }
}

滚动播放

滚动播放用的是transition,改变最上面一行的高度height,transition: height 0.3s linear;

当最上面一行隐藏后,将它的数据从数组头部移到尾部。实现循环滚动。

//this.rowHeight为计算出的每一行的高度,这里是将所有行高都还原成初始值,len是数组长度
this.rowHeights = new Array(len).fill(this.rowHeight) 

//将最上面一行的高度设为0
this.rowHeights.splice(0, 1, 0)

//将数组头部的数据移到尾部, this.currentIndex为移动指针,初始值为0
const temp = this.rowsx.slice(this.currentIndex)
temp.push(...this.rowsx.slice(0, this.currentIndex))
this.rowsData = temp
this.currentIndex += 1
<div v-for="(item, index) in rowsData" :key = "item.index"></div>

地图开发

echarts.registerMapapi支持自定义地理坐标系,如echarts.registerMap('china', map),第一个参数是自定义的地图名称,第二参数是GeoJson格式的数据,长下面这样: GeoJson格式的数据可以在这个网站输入地名获取。 datav.aliyun.com/tools/atlas…

自定义地理坐标系的使用

  • 直接画地图,用于type: 'map'的图表类型
series: [
  {
     name: '产品流向分布',
     type: 'map',
     map: 'china',
     zoom: 1.6,
     center: [104.114129, 36.050339],
     itemStyle: {
       borderColor: 'blue',
       borderWidth: 2
     }
  }
]

再加上视觉映射组件visualMap, 就可以实现热力分布地图。

visualMap: {
  show: false,
  min: 0,
  max: 10000,
  seriesIndex: [0],
  inRange: {
    color: ['#a7d5f2', '#3f95ff', '#5470c6']
  }
},
series: [
  {
     name: '产品流向分布',
     type: 'map',
     map: 'china',
     zoom: 1.6,
     center: [104.114129, 36.050339],
     itemStyle: {
       borderColor: 'blue',
       borderWidth: 2
     }
  }
]

  • 作为坐标系,在坐标系上绘制散点图,线集等。
geo: {
  map: 'china',  //自定义的地图名称
  zoom: 1.6,
  center: [104.114129, 36.050339],
  itemStyle: {
    borderColor: 'blue',
    borderWidth: 2
  }
},
series: [
  {
    type: 'effectScatter',
    coordinateSystem: 'geo',  //指定geo坐标系
    symbolSize: function (val) {
      return val[2] / 200
    },
    rippleEffect: {
      brushType: 'stroke'
    },
    label: {
      show: true,
      position: ['20', '0'],
      formatter: '{b}',
      fontSize: 16
   },
   itemStyle: {
      color: 'yellow'
   }
 }]

自定义地理坐标系的使用是很常见的,省市区域的一些统计情况都可以用上述的方法进行实现。

数据

项目用的是模拟数据,用vuex进行数据的管理通信。更新方式采用定时轮询。

//Home.vue
created () {
  this.$store.dispatch('updateAll')
  setInterval(() => { // 模拟定时轮询
    this.$store.dispatch('updateAll')
  }, 5 * 60 * 1000)
}

在actions中模拟请求数据。

actions: {
  updateAll (context) {
    setTimeout(() => { // 模拟成功请求接口数据
      // 接口返回,数据变化,更新状态
      //context.commit('updateOverall', data)
        ...
    }, 1000)
  }
},

在组件的computed中处理使用数据:

computed: {
  chartOption () {
    const categorySales = this.$store.state.categorySales
    categoryOpt.series[0].data = categorySales
    return Object.assign({}, categoryOpt)
  }
}

参考资料