VChart是一款开箱即用的图表库,默认提供了20+的图表类型,随着图表类型的增加,功能的丰富,包体积也是大 家非常关注的一个点,所以VChart通过按需加载机制来满足各种场景对vchart的不同需要;在介绍具体设计之前,我们需要了解两个前置概念:
-
vchart图表构成
-
什么是tree-shaking
本文将从这两个角度介绍vchart按需加载的原理
VChart 图表组成
术语定义
在深入了解VChart图表组成之前,我们需要了解以下术语:
-
series- 图表主体,也称系列,包含一组图元及其对应的图表逻辑。 -
mark- 基本图形元素,也称基础图元,如点、线条形等。 -
region- 空间信息元素,关联一组或多组 series,帮助定位空间。 -
component- 组件,帮助图表阅读和交互的元素,如图例、坐标轴、提示等。 -
layout- 布局,管理图表元素的空间分布。 -
chart- 图表抽象概念,整合、管理数据、图元、组件、布局各种元素的管理者。
图表定义
逻辑层图表元素
我们将图表的逻辑层元素拆解为以下四个部分:
-
series 是图表主体,含一组图元和对应类型的图表逻辑。例如线图中,series 指点和线的集合以及线图所有的逻辑等。
-
component 提供辅助能力,帮助图表阅读和交互的组件,比如图例,坐标轴,tooltip,dataZoom 等。
-
region 是一个空间信息元素,它可以关联一组或多组 series,帮助 series 进行空间定位,同时 region 还是一个最小组合单元。
-
chart 是一个抽象概念,它是对图表的各种元素进行整合、管理布局的管理者,是图表逻辑层的核心上下文。
简单图表
简单图表是由一个 region、一个确定类型的 series、component 和一个管理图表逻辑的 chart 构成。以一个常见的折线图为例,其组成如下

组合图表
我们将组合图定义为由多个 region、多个确定类型的 series、component 和一个管理图表逻辑的 chart 构成,这里的 chart 我们将其封装为 type: 'common' 的组合图表。
在组合图中可以定义若干不同类型的子图。每个子图可以独立配置自己的数据和组件,所有子图默认关联在同一个 region。此时各个子图在 region 上是重叠的。我们以常见的柱线双轴图为例来详细介绍组合图表:
-
首先如果我们需要创建组合图,我们需要声明
type: 'common',表示我们需要创建的图表类型为组合图 -
在上面我们提到,chart 是整合、管理数据、图元、组件、布局各种元素的管理者,从逻辑层组成上他是由 region + series + layout 组成的,而柱线分别对应 'bar' 和 'line' 这两种系列类型,而默认所有的系列都是关联在同一个 region 的,所以这里我们不需要配置 region
-
每个系列可以有自己的数据源,也可以直接将数据源配置在 chart 上,series 中通过
fromDataId或者fromDataIndex来关联,当前的例子我们选择配置在 chart 上

如前所述,region 是空间信息元素,可以结合布局利用多个不同定位的 region 对画布进行空间划分;同时,组件也可以指定与 region 关联的关系,当一个组件关联了多个 region 时,会默认收集所有 region 下子图的数据维度进行展示,如下示例所示:

图元 mark
图元是图表视图层对图形的定义,VChart 定义图表中的图元包括基础图元和组合图元。
基础图元包括:标记(symbol)、矩形(rect)、线条(line)、直线(rule)、弧形(arc)、面积(area)、文本(text)、路径(path)、图片(image)、3D 矩形(rect3d)、3D 弧线(arc3d)、多边形(polygon)等。
由多个基础图元进行组合就构成了组合图元,我们把基础图元和组合图元统称为图元。
逻辑层元素(如 series 系列)是由若干图元构成的,如面积图('area')系列,包括点、线、面积组成,对应的基础图元分别为:标记(Symbol)、线条(line)、面积(area)
什么是tree-shaking
Tree Shaking 是一种代码优化技术,用于移除 JavaScript 中未使用的代码(dead code)。这个概念最早由 Rollup 提出,后来被 Webpack 等构建工具广泛采用。
Tree Shaking 的实现主要依赖于 ES Module 的这些特性:
-
导入导出语句只能在模块顶层
-
导入导出的模块名字不能是动态的
-
导入的模块是不可变的
// 1. 导入导出语句只能在模块顶层
import { foo } from './foo';
export const bar = () => {};
// 2. 导入导出的模块名字不能是动态的
import { 'f' + 'oo' }; // 错误
// 3. 导入的模块是不可变的
import { foo } from './foo';
foo = 'bar'; // 错误
打包工具根据文件之间的依赖关系,在标记阶段构建模块依赖图,分析导入导出关系,在打包阶段移除未使用的导出,仅保留使用的代码
// 1. 标记阶段
// module.js
export const foo = () => console.log('foo');
export const bar = () => console.log('bar');
// main.js
import { foo } from './module';
foo(); // foo被标记为使用
// bar未被使用,标记为dead code
// 2. 删除阶段
// 打包后,bar函数被删除
const foo = () => console.log('foo');
foo();
在使用 Tree Shaking 时,sideEffects 配置在确保未使用代码被正确移除方面起着关键作用。在项目的 package.json 文件中,sideEffects 字段用于告知打包工具哪些文件或模块具有副作用,即除了导出值之外还会执行其他操作(例如修改全局状态、执行初始化代码等)。如果一个模块没有副作用,打包工具可以安全地移除未被引用的部分。
VChart 按需加载的原理
基于上述对 VChart 图表组成和 Tree Shaking 概念的了解,VChart 按需加载的核心思路就是利用 Tree Shaking 技术,只打包用户实际使用到的图表类型、组件、图元等代码,从而减小包体积。再下一章节,我们将详述一些实现细节。