前言
最近要在vue中使用echarts,觉得挺好玩的,这里记一下笔记。最终得到的是一个可自动刷新的可适应屏幕尺寸的图表,并可手动全屏
使用
安装echarts依赖
npm i echarts -s
main.js中配置echarts全局使用:
/*全局使用echarts*/
import Echarts from 'echarts'
Vue.prototype.$echarts = Echarts;
在子组件中使用:
<!--测试图表-->
<template>
<div class="chart-default-size" ref="TestChart_ref"></div>
</template>
<script>
//导入主题,也可以不导入,使用默认的主题
import 'echarts/theme/dark'
export default {
name: "TestChart",
data() {
return {
chartInstance: null,
allData: null, // 服务器返回的数据
currentPage: 1, // 当前显示的页数
totalPage: 0, //共有多少页
timerId: null //定时器标识
}
},
created() {
},
mounted() {
this.initChart()
this.getData()
},
beforeDestroy() {
clearInterval(this.timerId)
},
methods: {
// 初始化echartInstance对象
initChart() {
this.chartInstance = this.$echarts.init(this.$refs.TestChart_ref, 'dark')
// 对图表对象进行鼠标事件的监听
this.chartInstance.on('mouseover', () => {
clearInterval(this.timerId)
})
this.chartInstance.on('mouseout', () => {
this.startInterval()
})
},
// 获取服务器的数据
async getData() {
const {data: ret} = await this.$http.get('/pro/order')
console.log(ret)
this.allData = ret
// 对数据进行排序
this.allData.sort((a, b) => {
return b.value - a.value //从小到大排序
})
console.log(this.allData)
console.log(ret)
//每五个元素显示一次,总页数
this.totalPage = this.allData.length % 5 === 0 ? this.allData.length / 5 : this.allData.length / 5 + 1
this.updateChart()
// 启动定时器
this.startInterval()
},
// 更新图表
updateChart() {
const start = (this.currentPage - 1) * 5 //第一页0
const end = this.currentPage * 5 //第一页5
// slice包含start不包含end
const showData = this.allData.slice(start, end)
// 将获取的对象中的某一部分提取到数组中
const sellerNames = showData.map((item) => {
return item.name
}).reverse() // 反转显示顺序
const sellerValues = showData.map((item) => {
return item.value
}).reverse() // 反转显示顺序
const option = {
title: {
text: '| 商家销售统计',
textStyle: {
fontSize: 44,
},
left: 20,
top: 20
},
grid: {
top: '20%',
left: '3%',
right: '6%',
bottom: '3%',
// 位置调整包含坐标轴文字
containLabel: true
},
xAxis: {
type: 'value',
},
yAxis: {
type: 'category',
data: sellerNames
},
//文字提示
tooltip:{
trigger:'axis',
axisPointer:{
type:'line',
z:0,
lineStyle:{
width:44,
color:'#2D3443'
}
}
},
series: [
{
type: 'bar',
data: sellerValues,
barWidth: 44, //柱宽度
label: { //指定标签
show: true, //文字展示
position: 'right', //展示位置
textStyle: {
color: 'white', // 文字颜色
}
},
itemStyle: { //指定主要对象
barBorderRadius: [0, 22, 22, 0], //柱状圆角
// 颜色渐变,通过调用echarts中的线性渐变实现
// 对应参数:color:new this.$echarts.graphic.LinearGradient(x1,y1,x2,y2,[])
// x1,y1,x2,y2参数指明方向
// []中指明不同百分比之下颜色的值
color:new this.$echarts.graphic.LinearGradient(0,0,1,0,[
// 百分之0状态之下的颜色值
{
offset:0,
color:'#5052EE'
},
// 百分之100状态之下的颜色值
{
offset:1,
color:'#AB6EE5'
}
])
}
}
]
}
this.chartInstance.setOption(option)
},
// 定时器切换
startInterval() {
// 查看是否已经有定时器
if (this.timerId) {
clearInterval(this.timerId)
}
this.timerId = setInterval(() => {
this.currentPage++
if (this.currentPage > this.totalPage) {
this.currentPage = 1
}
this.updateChart()
}, 3000)
},
}
}
</script>
<style lang="less" scoped>
.chart-default-size {
height: 100%;
width: 100%;
}
</style>
加圆角(整个图表四角)
canvas{
border-radius: 20px;
}
展示
这个图表会循环展示
关于数据接口问题
get请求想得到的json数据为:
[{'name': '商家1', 'value': 50}, {'name': '商家2', 'value': 80}, {'name': '商家3', 'value': 90}, {'name': '商家4', 'value': 70}, {'name': '商家5', 'value': 100}, {'name': '商家6', 'value': 120}, {'name': '商家7', 'value': 50}, {'name': '商家8', 'value': 80}, {'name': '商家9', 'value': 110}, {'name': '商家10', 'value': 150}, {'name': '商家11', 'value': 180}]
可以修改getData()为:
getData() {
// const {data: ret} = await this.$http.get('/pro/order')
// console.log(ret)
let ret = [{'name': '商家1', 'value': 50}, {'name': '商家2', 'value': 80}, {'name': '商家3', 'value': 90}, {'name': '商家4', 'value': 70}, {'name': '商家5', 'value': 100}, {'name': '商家6', 'value': 120}, {'name': '商家7', 'value': 50}, {'name': '商家8', 'value': 80}, {'name': '商家9', 'value': 110}, {'name': '商家10', 'value': 150}, {'name': '商家11', 'value': 180}]
拆分图表配置项option并实现分辨率适配
首先我们需要知道,echarts的setOption是可以多次设置的,在这个过程中会整合配置,而不是重置,所以我们可以将配置option拆分为三部分:初始化配置initOption,数据配置dataOption,分辨率适配配置adapterOption。
从而可以在合适的地方针对性地更新配置
先将dataOption分离:
const dataOption = {
yAxis: {
data: sellerNames
},
series: [
{
data: sellerValues,
}
]
}
this.chartInstance.setOption(dataOption)
再将分辨率适配部分配置:
这里我们先要得到容器的宽度,然后根据这个宽度去自适应
更新后代码:
<!--测试图表-->
<template>
<div class="chart-default-size" ref="testchart_ref"></div>
</template>
<script>
import 'echarts/theme/dark'
export default {
name: "TestChart",
data() {
return {
chartInstance: null,
allData: null, // 服务器返回的数据
currentPage: 1, // 当前显示的页数
totalPage: 0, //共有多少页
timerId: null //定时器标识
}
},
created() {
},
mounted() {
this.initChart()
this.getData()
// 给浏览器窗口添加一个监听事件
window.addEventListener('resize',this.screenAdapter)
// 在界面加载完成时,主动进行屏幕适配
this.screenAdapter()
},
// 组件销毁时
beforeDestroy() {
// 清除定时器循环
clearInterval(this.timerId)
// 移除监听事件
window.removeEventListener('resize',this.screenAdapter)
},
methods: {
// 初始化echartInstance对象
initChart() {
this.chartInstance = this.$echarts.init(this.$refs.testchart_ref, 'dark')
// 对图表初始化配置的控制
const initOption ={
title: {
text: '| 商家销售统计',
textStyle: {
fontSize: 44,
},
left: 20,
top: 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:{
width:44,
color:'#2D3443'
}
}
},
series: [
{
type: 'bar',
barWidth: 44, //柱宽度
label: { //指定标签
show: true, //文字展示
position: 'right', //展示位置
textStyle: {
color: 'white', // 文字颜色
}
},
itemStyle: { //指定主要对象
barBorderRadius: [0, 22, 22, 0], //柱状圆角
// 颜色渐变,通过调用echarts中的线性渐变实现
// 对应参数:color:new this.$echarts.graphic.LinearGradient(x1,y1,x2,y2,[])
// x1,y1,x2,y2参数指明方向
// []中指明不同百分比之下颜色的值
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() {
const {data: ret} = await this.$http.get('/pro/order')
console.log(ret)
this.allData = ret
// 对数据进行排序
this.allData.sort((a, b) => {
return b.value - a.value //从小到大排序
})
console.log(this.allData)
console.log(ret)
//每五个元素显示一次,总页数
this.totalPage = this.allData.length % 5 === 0 ? this.allData.length / 5 : this.allData.length / 5 + 1
this.updateChart()
// 启动定时器
this.startInterval()
},
// 更新图表
updateChart() {
const start = (this.currentPage - 1) * 5 //第一页0
const end = this.currentPage * 5 //第一页5
// slice包含start不包含end
const showData = this.allData.slice(start, end)
// 将获取的对象中的某一部分提取到数组中
const sellerNames = showData.map((item) => {
return item.name
}).reverse() // 反转显示顺序
const sellerValues = showData.map((item) => {
return item.value
}).reverse() // 反转显示顺序
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.testchart_ref.offsetWidth);
const titleFontSize = this.$refs.testchart_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 lang="less" scoped>
</style>
此时已经拆分了echarts的配置项,并且已经可以根据浏览器宽度进行适配了
实现全屏切换
既然以及实现了分辨率适配,那么实现全屏就很简单了,只需加一个点击事件,改变样式即可
父组件中:
<template>
<div style="width: 100%;height: 100%">
<!--多个类绑定-->
<div :class="['test',test ? 'fullscreen' : '']" >
<test-chart ref="test"></test-chart>
<div class="resize">
<span @click="changeSize('test')" :class="[test ? 'el-icon-bottom-left' : 'el-icon-top-right']"></span>
</div>
</div>
</div>
</template>
<script>
import TestChart from "../../../components/charts/TestChart";
export default {,
components:{
TestChart
},
data(){
return {
chartId:'testChart',
//定义全屏状态
test:false,
}
},
methods:{
changeSize(chartName){
// 1.改变test的数据
this.test = !this.test
// 2.需要调用每一个图表组件的screenAdapter的方法
// Vue中DOM更新是异步的
// 数据变动后不会即时更新完成,需要调用$nextTick当数据更新完成,下一次组件更新的时候调用方法
this.$nextTick(()=>{
this.$refs[chartName].screenAdapter()
})
}
}
}
</script>
<style lang="less" scoped>
.test{
width: 50%;
height: 50%;
position: relative;
.resize{
position: absolute;
right: 20px;
top:20px;
cursor: pointer;
color: white;
}
}
.fullscreen{
position: fixed!important;
top:0!important;
left: 0!important;
width: 100%!important;
height: 100%!important;
margin: 0!important;
z-index: 100;
}
</style>
初始状态:
点击右上角后全屏:
ok,开发完成