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

news2025/7/15 17:32:00

📖阅读本文,你将

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

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

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

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

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

所以,我就开始在面试中加入了关于 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>
复制代码

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

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

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

它最大的优点就在于:

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

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

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

3.2 配置项基本概念

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

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

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

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

3.3 轻度自定义的神器:graphic

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

这种就属于,乍一眼看上去很容易,然后一琢磨:不对啊,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
        }
      },
  ]
}
复制代码

码上掘金相关片段,赶紧亲自试试:

效果图:

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 提供的关键帧动画能力,指定时长、以及不同进度上元素应该表现的配置状态,驱使它完成了页面的渲染。

  2. 进入/离开/更新动画

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

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

    效果如下: 

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

学会以上动画能力,也基本算可以称得上在 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) => {
    }
  }
)
复制代码

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

先了解一个 APIResizeObserver。 (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 使用,应该就不会再出现尴尬的场景了吧。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于ASP学生资助管理系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做ASP程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问题…

用Python蹭别人家图片接口,做一个【免费图床】吧

打开本文&#xff0c;相信你确实需要一个免费且稳定的图床&#xff0c;这篇博客就让你实现。 文章目录⛳️ 谁家的图床⛳️ 实战编码⛳️ 第一轮编码⛳️ 第二轮编码⛳️ 第三轮编码⛳️ 第四轮编码⛳️ 谁家的图床 这次咱们用新浪微博来实现【免费图床应用】&#xff0c;通过…

栈浅谈(上)

目录 栈的定义 栈的实现 初始化 判断栈是否为空 入栈操作 获取栈顶元素 出栈操作 遍历栈 销毁栈 完整代码演示 栈—STL 基本操作 例题 参考代码 栈的定义 说到栈&#xff0c;一些不会计算机语言的“小白”&#xff08;我就是&#xff09;就会想到栈道之类的词语…

基于JavaWeb的婚恋交友网站设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

如何平衡新老策略的好与坏,一道常见风控送命题解答

作为一个风控策略从业者&#xff0c;在做风险管理的过程中一直在做的就是&#xff0c;不断的挖掘有效的变量特征来填充风控决策体系&#xff0c;使决策体系的功效变大变强&#xff0c;最终形成一套可变的稳定风险护盾。我们常见的一个场景比如如何筛选一些新策略来挑战老策略&a…

【C++中预处理语句 include、define、if】

1.预处理阶段 预处理阶段&#xff0c;在实际发生编译之前就根据对应的预处理语句进行操作&#xff0c;等到预处理阶段完成之后才进行编译阶段 。 2.预处理语句 预处理语句主要有include、define、if 和 program。利用 # 进行标记 2.1 include语句 include语句就是将所包含的…

if-else练习

if单分支 输入两个数&#xff0c;分别放入x和y中&#xff0c;若两数不相等&#xff0c;则输出其中的大数&#xff0c;若两数相等&#xff0c;则输出字符串“xy&#xff1a;”并输出其值 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() {int a 0;int …

智慧油田解决方案-最新全套文件

智慧油田解决方案-最新全套文件一、建设背景1、智慧油田的概念及意义2、智慧油田的建设目标二、建设思路三、建设方案四、获取 - 智慧油田全套最新解决方案合集一、建设背景 1、智慧油田的概念及意义 石油产量、采收率、安全生产等都与石油工业未来息息相关&#xff0c;随着石…

十八、CANdelaStudio深入-Data Types

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的Data Types(数据类型),欢迎各位朋友订…

旧系统改造

背景 很多时候&#xff0c;我们在项目前期会优先确保项目业务的落地&#xff0c;在短时间内进行项目冲刺&#xff0c;最后完成项目上线。这样做让短时间内的目标达貌似达成了&#xff0c;却给系统留下了很大的隐患。 在项目的冲刺过程中&#xff0c;我们的精力大部分花在了业…

动态规划-不同路径

一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff1f; 示例 …

单源广度优先搜索 (leetcode经典例题 C++实现)

文章目录01矩阵地图分析腐烂的橘子深度优先搜索与广度优先搜索前情回顾&#xff1a; 深度搜索dfs与广度搜索bfs算法总结&#xff08;c 例题&#xff09; 本节是广度优先搜索的进阶&#xff1a; 01矩阵 传送门&#xff1a; https://leetcode.cn/problems/01-matrix/?envType…

JavaWeb----Servlet技术

JavaEE简介 什么是JavaEE JavaEE&#xff08;Java Enterprise Edition&#xff09;&#xff0c;Java企业版&#xff0c;是一个用于企业 级web开发平台,它是一组Specification。最早由Sun公司定制并发 布&#xff0c;后由Oracle负责维护。在JavaEE平台规范了在开发企业级web 应…

【操作系统】死锁(详细)

文章目录一、死锁的概念二、死锁的产生因素三、死锁的必要条件1、互斥条件2、占有和等待条件&#xff08;部分分配条件&#xff09;3、不剥夺条件4、循环等待条件&#xff08;环路条件&#xff09;四、死锁防止1、破坏互斥条件2、破坏占有和等待条件3、破坏不剥夺条件4、破坏循…

Ceph文件系统

目录 一、环境准备 二、什么是文件系统 三、ceph块存储与文件系统区别 四、创建ceph文件系统 1、启动MDS服务 2、创建存储池 3、创建Ceph文件系统 4、客户端挂载 一、环境准备 Ceph集群搭建参照&#xff1a;Ceph集群部署_桂安俊kylinOS的博客-CSDN博客 以下Ceph存储实…

springcloud22:sentinal的使用

sentinal对比&#xff08;分布式系统的流量防卫&#xff09; 监控保护微服务 Hystrix 需要自己去手工搭建监控平台&#xff0c;没有一套web界面可以进行细粒度化的配置&#xff0c;流控&#xff0c;速率控制&#xff0c;服务熔断&#xff0c;服务降级… 整合机制&#xff1a;se…

外卖项目08---Linux

目录 一、 Linux简介 119 二、Linux安装 120 三、常用命令 122 3.1Linux命令初体验 3.1.1 command [-options] [parameter] 3.2Linux常用命令---文件目录操作命令-ls&-cd&-cat 124 3.2.1list 3.2.2 cd 3.2.3 cat 3.3 Linux常用命令---文件目录操作命令…

9.前端笔记-CSS-CSS三大特性

三大特性&#xff1a;层叠性、继承性、优先级 1、层叠性&#xff08;覆盖性&#xff09; 给相同的选择器设置相同的样式&#xff0c;此时一个样式会覆盖&#xff08;层叠&#xff09;其他冲突的样式。 层叠性原则&#xff1a; 同一选择器&#xff0c;样式冲突&#xff0c;遵…

OpenMV输出PWM,实现对舵机控制

OpenMV的定时器官方函数介绍&#xff1a;Timer类 – 控制内部定时器 目录 OpenMV的PWM资源介绍 为什么要用OpenMV输出PWM OpenMV的PWM资源分配 资源 注意 建议 PWM输出代码 代码讲解 Timer Timer.channel tim.channel与Timer.channel区别 Timer.channel解析 OpenM…

Iframe通信

跨域的种类 一般有两种形式的跨域问题&#xff1a; ①使用XmlHttpRequest(XHR)或者使用AJAX发送的POST或者GET请求。这种形式的跨域是&#xff1a;前端页面与后端进行的跨域请求。 ②父子页面之间进行的DOM操作&#xff08;父子窗口之间的document操作&#xff09;。这种形式…