这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
对于Echarts,不能说熟练使用吧,但最起码踩了很多坑。在上一篇文章中,重点介绍了世界地图的实现思路,本篇文章就来分别介绍其他图表的使用及部分配置项的使用。
封装组件库
原本我封装的chart组件并没有涵盖太多内容,后期我打算再处理下,争取能做到传值,option只做到写一套,另外loading啊,empty的情况啊,后期都加进来,时间关系,本次不做处理,后期处理后统一来更新。
<template>
<div id="chart" ref="charts" />
</template>
<script>
import throttle from 'lodash/throttle';
import ResizeObserver from 'resize-observer-polyfill';
// / 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';
// 引入柱状图图表,图表后缀都为 Chart
import { BarChart } from 'echarts/charts';
import 'echarts-wordcloud';
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent
} from 'echarts/components';
// 标签自动布局,全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers';
// 注册必须的组件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
BarChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);
export default {
name: 'Chart',
props: {
height: {
type: String,
default: ''
}
},
data() {
return {
chart: null,
resizeChart: null
};
},
mounted() {
this.$refs.charts.style.height = this.height;
this.chart = echarts.init(this.$refs.charts);
this.resize(document.getElementById('chart'));
},
destroyed() {
window.removeEventListener('resize', this.resizeChart);
this.chart && this.chart.dispose();
},
methods: {
resize(dom) {
this.resizeChart = throttle(() => {
this.chart.resize();
}, 500);
this.observer = new ResizeObserver(() => this.resizeChart());
this.observer.observe(dom);
},
}
};
</script>
上述代码就是整个封装的chart组件,在这里主要引入了Echarts必须的配置项,当然我这里是按需引入,所以配置项较多,其实如果用的图表多,完全可以全部引入。 在上述代码中,你应该看到了有三个内容,是不必须的。是的,我来介绍下这三个。
- ResizeObserver是用来监听图表对应组件容器的大小,从而来自适应;
- throttle这个api应该很熟悉了,在代码中也能看出来,用在了自适应的过程中;
- echarts-wordcloud,对啦,就是来实现词云的。
数据拿到了,图表不显示
echarts图表的dom结构会在mounted的时候去挂载,然而这个时候我们的数据还没有请求回来,自然也就无法渲染出来了,我们需要在挂载之前就将数据请求回来,就是将数据请求放在created生命周期中。 或者像我,数据如果是通过组件传值拿到的,那么就可以这样来处理,用 $nextTick方法,让它在下一个事件队列中去渲染。
this.$nextTick(() => {
this.$refs.pieChart.chart.setOption(this.initOption);
});
词云实现过程中遇到的问题
既然上面提到了,那就先来说一下词云吧。在Echarts的提供的示例中并没有词云,但是他提供了一个库,供我们使用,就是上面提到的echarts-wordcloud,我们只需要装一下,就可以使用啦。 该图标的type设置为:wordCloud即可。 这里有几个配置项来介绍下:
// 字体分布的密集程度
gridSize: 10,
// 字体大小的范围
sizeRange: [12, 20],
// 字体旋转的角度
rotationRange: [0, 0],
上面几个配置项还蛮关键的,因为当时我在实现的时候,容器特别小,词又特别长,以至于返回一条数据,我的容器都放不下,你敢信?当时我还以为出bug了,命名返回了一条数据,我的div中却是空白一片。这可不行啊,查了一番才明白,是放不下,所以空白了。这个时候就可以调节上面几个参数来处理。 另外呢,也是因为我的div太小了,会出现返回十条数据,却展示了六七条的情况,这个怎么处理呢?同样有一个配置项,很管用哦:
drawOutOfBound: true,
就这小小的代码,能够保证返回的数据全部显示哦。
折线图实现的时候,纵坐标表示流量,会出现1M点在下,100K点在上的情况
这种场景不知道有没有小伙伴遇到过?是这样的,我拿到的数据单位是字节,然而我需要根据数值的大小转换为K,或M,或G,进而渲染到图表上。第一次在实现的时候,我是这样处理的:
getTrafficDetail(data) {
let detail = data / 1000;
if (detail < 1000) {
return detail.toFixed(2) + 'K';
} else if (detail >= 1000 && detail < 1000 * 1000) {
return (detail / 1000).toFixed(2) + 'M';
} else if (detail >= 1000 * 1000) {
return (detail / (1000 * 1000)).toFixed(2) + 'G';
}
}
上述代码遇到的问题是什么呢?就是上面标题中的问题。因为当我拿到一个数据的时候,不管单位,只管大小,那计算出来有可能是M,有可能是G,而对于折线图的纵坐标来说,他只管你的value值,什么单位,他才不管呢。解决方案就是统一单位,最后是这样处理的:
let unit = '';
if (detail < 1000) {
unit = 'K';
} else if (detail >= 1000 && detail < 1000 * 1000) {
unit = 'M';
} else if (detail >= 1000 * 1000) {
unit = 'G';
}
getTrafficDetailChart(data, unit) {
let detail = data / 1000;
if (unit === 'K') {
return detail.toFixed(2) + 'K';
} else if (unit === 'M') {
return (detail / 1000).toFixed(2) + 'M';
} else if (unit === 'G') {
return (detail / (1000 * 1000)).toFixed(2) + 'G';
}
}
半圆环图是如何实现的
一如往常,我的需求是实现半圆环,好家伙,去官网示例中找,咦,没找到。
好吧,有圆环,那就从圆环上截取吧。
主要思路是配置项用圆环的配置项,而圆环下面的50%的颜色设置为页面背景色的颜色,在上面的50%上做文章。是不是思路很清晰呢?这个时候只要注意几个点就没问题了:
- 图例legend:最后一个图例要返回空,否则会显示在页面上;
- 悬浮tooltip:下半部分要返回空即可;
- 在处理series.data的时候,一定不要忘记在最后push上name值为空,value值为返回的总total值,这样就能保证上下都是一样大啦;
- tooltip上若显示百分比,这儿要计算一下,否则算出来的上面部分就会等于50%,而不是100%。