0
点赞
收藏
分享

微信扫一扫

大屏图表,ECharts 从“熟练”到入门


📖阅读本文,你将

  1. 了解 配置驱动 的思想
  2. 理解 ​​Echarts​​ 基本概念
  3. 了解 ​​graphic​​​ 和 ​​动画基本玩法​​。
  4. 了解 ​​Echarts​​ 基底组件的封装的思路

一、不是标题党!​​Echarts​​,简历上人均 “熟练”?

公司最近在招外包,而因为目前大屏的需求比较多,所以我就稍微关注了一下候选人们简历上对于 ​​Echarts​​ 的熟悉程度。

不看不知道,一看下一跳,​​Echarts​​ 属实已经是业内人均 “熟练” 的基本技能了。

大屏图表,ECharts 从“熟练”到入门_Vue.js

以上是短短几篇简历中摘选的自我描述,可以看出,​​Echarts​​​ 在大众研发的心中,已经是和 ​​Antd​​​、​​ElementUI​​​、​​Bootstrap​​ 相当的常用第三方库了。

所以,我就开始在面试中加入了关于 Echarts 使用的相关问题,想看看 熟练 到底是什么意思。

但是一轮问题问下来,大家好像又对它很陌生。

难道,所谓 熟练,就是能在社区里找到 ​​Demo​​​,然后把配置项 ​​Copy​​ 到项目之中?

问:“现在你找到 ​​Demo​​​ 了,但是 ​​Demo​​ 没有显示图例(也就是那些彩色小方块小圆圈,表示各类数据颜色的东西),你应该查文档的什么关键词?”

答:“一时说不出来,但我肯定能试出来...”

问:“我想把UI出的一张图片放在饼图的背面,作为背景,应该怎么弄?”

答:“先去社区找找 ​​Demo​​ 吧...”

问:“这种 ​​Demo​​​ 可能不太好找吧...而且有些场景,​​Demo​​ 涉及的也不多,比如需要在某个特定位置放一些字,做一些动画,应该怎么办?”

答:……

虽然我的习惯和大家是一样的,遇到需求,先去社区里找一个相似度最高的 ​​Demo​​ 再说,但是开发大屏,怎么可能不遇到 “特异化、定制化” 的诉求呢?

当 ​​Demo​​ 帮不了你的时候,你是否可以熟练地通过文档,找到合适的解决之道呢?

如果 找DEMO 就是 熟练,那我建议咱还是先忘记 “万事求DEMO” 的这种熟练方式,重头捋一捋 ​​Echarts​​ 这个框架,先力求 入门

这就是标题所谓的,从 熟练入门 的意思。

二、大屏图表,为什么我选 ​​Echarts​​?

在问出这个问题之前,我觉得还是先问一问:为什么不选Echarts 呢?

大屏的本质是什么?是讲故事,是给客户 量身定做 的讲故事!因此,大屏需求,更多的情况就是 做项目,而不是 做产品

做项目,什么最重要?

六个字:成本低、效率高

老板:你说复用、优雅?我都觉得好笑。

  • 成本低
    软件项目最大的成本,就是人的成本,现在哪怕是培训班刚出来的小萌新,哪怕他压根不知道 ​​g2plot​​ 是什么,但简历上大概率会写上 熟练使用 Echarts​​。如果招到那种五六年的前端老兵,那 ​​Echarts​​ 的 ​​API​​ 熟练度只会更高。
    花更低的钱,能招来直接做项目的人,这就是成本低。
  • 效率高
    为什么 ​​Echarts​​ 效率更高,因为它的社区实在太成熟,各种样式风格 ​​Demo​​ 的沉淀实在太多。 比如:早期的 ​​Echarts gallery​​ (已被关闭)、又比如:www.isqqw.com/
    在这些社区里,你可以快速找到各类你想要的风格和实现,从而低成本改造成 ​​UI​​ 想要的样子。

​Echarts​​​ 通常被拿来和 ​​AntV​​ 进行横向对比,关于孰优孰劣,某乎上的争论也比较大,但大家似乎都能达成一种共识:

社区方面,​​Echarts​​ 完胜。

社区完胜,效率就完胜,这是很容易推导的结果;毕竟,大多数时候,大家的开发模式就是 社区找相似度高的DEMO

另外,​​Echarts​​​ 早已经是 ​​Apache​​​ 基金会在托管了,没有面向 ​​KPI​​ 的压力。(你懂我的意思吧?)

三、认识 ​​Echarts​

一个基于 JavaScript 的开源可视化图表库。 ——官网

一个看似什么都说了,却什么都没说的客观发言。

但是作为开发者,我们却需要通过阅读文档,自行去摸索一些更为核心的内容,以了解:Echarts 能做什么? ​Echarts​ 擅长做什么? ​Echarts​ 有哪些特性? ”

  • 它能开发图表、地图、做图形渲染
  • 它擅长做图表开发

至于特性?

我虽然也只是 ​​Echarts​​ 入门使用者,我冒昧而经验地认为它的三个核心特性是:

  • 1、配置驱动
  • 2、事件驱动
  • 3、图形能力

理解以上三点,我认为大概就能做到 “入门Echarts” 这个常用前端工具了。但本文还是会把重点放在 配置驱动 这个最为核心的能力讲解上。

3.1 什么是配置驱动

什么是 配置驱动

这其实是很好理解的一个定义:

我只需要修改配置,就能让它显示的画面完成更新。

在使用 ​​Echarts​​​ 的过程中,最重要的 ​​API​​​ 一定是 ​​Echarts.setOption​​。

伪代码如下:

// 让图表显示状态A
chart.setOption(optionA)
// 让图表更新状态到B
chart.setOption(optionB)

对,这就是 配置驱动

稍微改动官方示例:

<template>
<div class="chart" ref="chartEl"></div>
</template>

<script setup>

const chartEl = ref(null);
let chart = null
const categories = ['老包', '老南', '老君']
const genDataArr = () => {
return categories.map(t => {
return Math.ceil(Math.random() * 100)
})
}
onMounted(() => {
// 指定图表的配置项和数据
const chart = echarts.init(chartEl.value);
const option = {
tooltip: {},
legend: {
data: ['黑子程度']
},
xAxis: {
data: categories
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: genDataArr()
}
]
};
chart.setOption(option)

setInterval(() => {
chart.setOption({ series: [
{
data: genDataArr()
}
] })
}, 1000)
})
</script>

通过修改配置项中某一项的值,我们可以清晰看到呈现出的动态变化:

大屏图表,ECharts 从“熟练”到入门_数据_02

如果你无法看到上述 码上掘金 内容的变化,那有可能是因为网络原因,无妨,其 ​​gif​​ 效果如下:

大屏图表,ECharts 从“熟练”到入门_配置项_03

配置驱动 就是这么直观,且易于理解。

它最大的优点就在于:

当我们希望图表从"状态A"进化到"状态B"时,我们其实无需关注当前的状态到底是什么样,我们只需要组装好"状态B"的配置,并将它交付给 ​​Echarts​​ 即可。

基本上,你可以利用 配置项 完成绝大多数工作上你遇到的各种需求。鲜明而无状态的 ​​API​​ 设计,也是它如此受到大家喜爱的根本原因。

本文,我们先专注于 配置驱动 封装一个能应对前端 90% 业务开发场景的基础 ​​Vue3​​ 基底组件。

3.2 配置项基本概念

配置项固然简单,但你首先需要知道 “我要实现某个能力实,应该去寻找什么样的配置” 。

对此,最快去了解各种概念的办法是看官方文档的 ​​常用组件说明​​。

如果你觉得看文档不如看图片,我也单独整理了一份简图:

大屏图表,ECharts 从“熟练”到入门_JavaScript_04

通过图中相关对照,我们可以在官方文档的​​配置项手册​​ 中快速浏览相关内容的支持选项及用法。

3.3 轻度自定义的神器:graphic

以上配置项中,大多数能力都是 Echarts 预设好,我们直接拿来用” 模式的,但难免会遇到产品经理或者 ​​UI​​ 同学突发奇想,增加一些特殊的文本或者图案,比如:

大屏图表,ECharts 从“熟练”到入门_JavaScript_05

这种就属于,乍一眼看上去很容易,然后一琢磨:不对啊,DEMO 里找不到可以直接拿来用 的类型了。

怎么办?

'graphic' 可能是个不错的选择。

​graphic​​ 配置提供了以下节点能力的渲染配置:

  • 图片
  • 文本
  • 元素组(可包含子节点,对子节点进行整体缩放、旋转等)
  • 以及 其他各种图形,例如(圆形、扇形、环形、多边形、折线、矩形、直线、贝塞尔曲线、圆弧)

其中,我认为最常用的两种:

  • 图片
  • 文本

让我们先通过一个例子认识 图片文本 的用法,核心代码如下:

option = {
...// 省略其他,
graphic: [
{
type: 'image',
style: {
image: 'https://pic.zhangshichun.top/pic/circle.png',
width: 150,
height: 150
},
top: 'middle',
left: 'center',
},
{
type: 'text',
style: {
x: 100,
y: 150,
text: `鸡你太美`,
fill: '#fff',
stroke: '#fff',
textAlign: 'center',
fontSize: 14
}
},
{
type: 'text',
style: {
x: 100,
y: 180,
text: `唱跳rap`,
fill: '#fff',
stroke: '#fff',
textAlign: 'center',
fontSize: 14
}
},
]
}

相关片段,赶紧亲自试试:

大屏图表,ECharts 从“熟练”到入门_JavaScript_06

效果图:

大屏图表,ECharts 从“熟练”到入门_数据_07

3.4 配置化与动画

细心的同学想必已经发现了,我并没有声明和动画相关的东西,但我上面的示例里已经有了最基本的 补间动画,这是因为 ​​echarts​​ 内置了一部分默认动画逻辑。

但实际上,你也拥有配置动画的能力

  1. 关键帧效果,以及循环动画
    尝试在 ​​type: 'image'​​ 的元素上添加以下代码:

{
// ... 其他配置暂且省略
transition: 'rotation',
originX: 75,
originY: 75,
keyframeAnimation: {
duration: 3000,
loop: true,
keyframes: [{
percent: 0.5,
easing: 'linear',
rotation: Math.PI
}, {
percent: 1,
easing: 'linear',
rotation: Math.PI * 2
}]
}
}

而你会看到如下效果:

大屏图表,ECharts 从“熟练”到入门_配置项_08

鸡哥的篮球 背景的圆环永远地滚动了起来。

大屏图表,ECharts 从“熟练”到入门_JavaScript_09

这个效果正是借助了 ​​Echarts​​ 提供的关键帧动画能力,指定时长、以及不同进度上元素应该表现的配置状态,驱使它完成了页面的渲染。

  1. 进入/离开/更新动画
    关键帧动画更倾向于按照 编码者指定的方式 进行运转,而 “进入/离开/更新动画” 则适用于 更新数据状态时,自动获取动画 的能力。
    看代码:

// 移除上面 keyframeAnimation 这一段代码
// 增加以下代码:
setInterval(() => {
const rotation = Math.random() * 2 * Math.PI
chart.setOption({
graphic: [
{
rotation
}
]
})
}, 500)

效果如下:

大屏图表,ECharts 从“熟练”到入门_前端_10

鸡哥的篮球 背景的圆环 ​​rap​​ 起来了。

大屏图表,ECharts 从“熟练”到入门_Vue.js_11

学会以上动画能力,也基本算可以称得上在 ​​Echarts​​​ 使用上入门了,可以应对大多数 ​​UI​​ 和产品的奇思妙想了。

四、 基底组件的能力?

我对 基底组件 的期望,其实很简单:

  • 它能自适应容器的宽高,并让自身的图表自适应容器宽高的变化

这当然是痛点了,我不止一次,不止在一个项目里,发现大屏进行布局调整、或者是浏览器页面大小调整后,图表的大小变得不适宜。依靠研发在紧张工期下,依然保持严谨的防御性代码编写习惯,是一种奢望。

  • 它能具备基础的主题能力

大屏通常有自己的主题色,自带 “主题色” 的 ​​Echarts​​ 组件,可以让研发节省大量时间。

  • 当数据为空时,它能智能的显示 “空值缺省”

试想,哪个客户希望对着一个空空如也的折线图猜测用意呢?此时,一句简简单单的 暂无数据 是多么的贴心。

  • 它应该给我最大限度的 自定义 的能力

永远不要失去能力,封装的意义在于 增强,而不是 阉割

基于以上诉求,我们可以开始设计自己的 Echarts 基底组件 的API。

​src/components/BaseECharts/index.vue​

// 提供 props 属性 empty,让组件稳定感知当前是否是空数据
defineProps({
empty: {
type: Boolean,
default: false
}
})

// 向外弹射事件 'resize'
const emits = defineEmits(['resize'])

defineExpose(
{
// 向父组件暴露方法:获得ECharts实例
getChart: () => {
},
// 向父组件暴露方法:更新ECharts配置
setOption: (v) => {
}
}
)

五、如何实现动态适配容器宽高

先了解一个 ​​API​​​: ​​ResizeObserver​​​。 (​​MDN相关参考​​)

通过 ​​ResizeObserver​​,我们可以从容地监听某个元素的尺寸变化。

既然这个 ​​API​​​ 这么优秀,那我们直接用它?你们可以随便用,但本老年 ​​vue-coder​​​ 选择逻辑完备的 ​​Hooks​​​: ​​useElementSize​​,一行代码解决元素尺寸监听的问题:

const el = ref(null)
const { width, height } = useElementSize(el) // width和 height 都是响应式的 `ref` 对象

然后再监听相关变化,适时地调用 ​​chart.resize()​​ 方法即可:

watchEffect(() => {
if (width.value && height.value) {
emits('resize', { width: width.value, height: height.value })
chartRef.value?.resize();
}
})

这样,当视窗大小变化后,相关的图表也会重新根据新视窗的大小调整尺寸。

而在 ​​@resize​​​ 事件里,用户因为得到了 ​​{width, height}​​​,对于一些依赖绝对尺寸的场景,也可以从容更新 ​​option​​​,保证 ​​resize​​ 后尺寸不会出现问题。

比如,在父组件中,我们可以这样写:

<template>
<BaseECharts @resize="size => onResize(size)" ref="chartRef"></BaseECharts>
</template>
<script setup>
import BaseECharts from '@/components/BaseECharts'

const chartRef = ref(null)
const genOption = ({ width, height }) => {
const minSideLength = Math.min(width, height)
return {
series: [
// ...其他选项省略
{
radius: [0.3 * minSideLength, 0.4 * minSideLength],
center: [minSideLength / 2, minSideLength / 2],
type: 'pie',
}
]
}
}
const onResize = (size) => {
const option = genOption(size)
chartRef.value.setOption(option)
}
</script>

从而实现 “像素级” 的尺寸操控(当然,能用百分比解决的就用百分比,但某些场景不支持百分比,那就必须上像素了);

六、如何具备内置的主题色?

首先,​​ECharts​​​ 是支持自定义主题的,访问: ​​echarts.apache.org/zh/theme-bu…​​

可以通过左侧的操作栏,让 ​​UI​​​同学快速定制一套适合你们系统的主题色,然后导出主题 ​​json​​ 配置文件,并将它存在 '@/theme/echarts-dark.json' 文件中。

在 ​​src/main.js​​ 中写如下带代码:

import * as ECharts from "echarts";
import theme from '@/theme/echarts-dark.json'

ECharts.registerTheme('dark', theme)

完成对主题的注册,(写在 ​​main.js​​​ 是为了避免重复注册),当然,如果要充分组件化的话,此处应该有 ​​vue-plugin​​。

然后,在基底组件中如此写:

onMounted(() => {
const chart = Echarts.init(chartEl.value, 'dark');
})

完成对主题的初始化。

七、空值缺省

这一步,其实不太涉及到 ​​Echarts​​​ 本身的内容,只需要通过判断 ​​empty​​​ 属性,通过 ​​v-show​​ 切换展示内容。

为什么用 ​​v-show​​​ 不用 ​​v-if​​​ ? 为了降低 ​​echarts​​ 实例周期管理的复杂度。

​src/components/BaseECharts/index.vue​

<template>
<div class="chart">
<div v-show="!empty" class="chart__el" ref="chartEl"></div>
<NoData v-show="empty" class="chart__empty"></NoData>
</div>

</template>

八、总结

通过:

  • 学习配置驱动的思想
  • 理解 ​​Echarts​​ 基本概念
  • 学习 ​​graphic​​​ 和 ​​动画基本玩法​​。
  • 完成基底组件的封装

你已经可以胜任简单大屏项目图表的快速开发和迭代了,此时,如果在简历上写上 入门 Echarts 使用,应该就不会再出现尴尬的场景了吧。

面对面试官高深场景的问题,也可以理直气壮地回答一句:

我就入门水平,你还想怎样?

举报

相关推荐

0 条评论