ECharts 创建图表
经过前面的学习,相信大家已经在自己的项目中绘制了一个基本的 ECharts 图表,但是前面学习只是为了让我们更好的了解安装的流程。所以该小节,我们将会去更加详细的了解到 ECharts 的 创建 , 更新 ,也会通过一个案例去跟踪分析整个过程,所谓 万事开头难,在这个过程中也会有许许多多需要同学们注意的地方,希望大家在学习的时候也能静下心来完成这重要的一步。
1. 简介
ECharts 用法非常简单,定义图表的基本流程是实例化 echarts 后,调用 setOption 传入配置对象,ECharts 根据配置对象的描述渲染各类图表、组件。本节主要讲解初始配置图表的基本流程,以及实例化后动态更新图表内容的方法。
2. 创建图表
2.1 创建图表的步骤
通常,创建一个 ECharts 图表需要执行如下步骤:
- 定义 DOM 节点作为图表的容器;
 - 调用 
echarts.init方法实例化 ECharts 对象; - 调用 
echartInstance.setOption方法传入图表配置。 
例如:
示例效果:

2.1.1 定义容器
图表容器通常使用 div 标签定义,调用 init 函数后 ECharts 会在节点中插入多个 canvas 或 svg 标签,用以渲染图表。容器节点必须具备初始宽高,常用如下形式定义:
<!-- 使用像素定义宽高 -->
<div id="main" style="width: 600px; height:450px"></div>
<!-- 也支持使用百分比定义宽高 -->
<div id="main" style="width: 100%; height:450px"></div>
提示:
ECharts 3 之后支持直接使用 canvas 元素作为容器,这样绘制完图表可以直接将 canvas 作为图片应用到其它地方,例如在 WebGL 中作为贴图,这跟使用
echartsInstance.getDataURL生成图片链接相比可以支持图表的实时刷新。但缺点是无法根据组件的
z属性将组件分离渲染到不同的 canvas 上,所以有一定的性能损失。
2.1.2 echarts.init 接口
echarts.init 函数用于创建 ECharts 对象,不能在同一个容器上多次调用,函数签名:
(dom: HTMLDivElement|HTMLCanvasElement, theme?: Object|string, opts?: {
    devicePixelRatio?: number
    renderer?: string
    width?: number|string
    height? number|string
}) => ECharts
函数参数:
dom: 指定容器节点,通常为div标签的 DOM 对象,例如上例中的document.getElementById('main');theme: 图表主题,支持传入主题配置对象或主题名称。配置对象可参考 light 主题源码;ECharts 默认内置light、dark两种主题,用户也可以通过echarts.registerTheme接口注册自定义主题;- 
opts: 附加参数,支持配置属性:{ // 设备像素比,默认取浏览器的值
window.devicePixelRatiodevicePixelRatio: Number, // 渲染器,支持 canvas 或 svg renderer: String, // 可显式指定实例宽度,单位为像素。如果传入值为 null/undefined/'auto',则取 dom(实例容器)的宽度。 width: Number|String|null|undefined, // 可显式指定实例高度,单位为像素。如果传入值为 null/undefined/'auto',则取 dom(实例容器)的高度。 height: Number|String|null|undefined, } 
提示:
容器的宽高应通过节点的样式定义,尽量避免通过
opts属性定义,这样在调用init前后,作为容器的 DOM 的尺寸才能保持一致。
2.1.3 echartInstance.setOption 接口
实例化 ECharts 对象后,需调用 echartInstance.setOption 接口传入图表配置,接口签名:
(option: Object, notMerge?: boolean, lazyUpdate?: boolean) => void
// 或
(option: Object, opts?: Object) => void
第一种形态的参数为:
option: 图表实例配置;notMerge: 可选,默认false,用于设定是否与之前提供的配置合并;lazyUpdate: 可选,默认false,是否延迟更新。
第二种形态的 opts 参数接受如下对象:
{
    // 默认 `false`,用于设定是否与之前提供的配置合并
    notMerge: ...,
    // 默认 `false`,是否延迟更新
    lazyUpdate: ...,
    // 默认 `false`,指定图表更新时是否触发事件
    silent: ...
}
其中 option 对象是必不可少的,用于描述开发者对图表的各项需求,包括使用什么组件、有什么数据、使用什么图表、图表有哪些操作等等。
2.2 配置对象概述
ECharts 是配置驱动的图表框架,主要功能都以配置对象形式声明,某种程度上可以说 ECharts 的应用都是围绕配置对象展开的。配置对象结构如下:
{
        title: object,
        legend: object,
        grid: object,
        xAxis: object,
        yAxis: object,
        polar: object,
        radiusAxis: object,
        angleAxis: object,
        radar: object,
        dataZoom: array,
        visualMap: array,
        tooltip: object,
        axisPointer: object,
        toolbox: object,
        brush: object,
        geo: object,
        parallel: object,
        parallelAxis: object,
        singleAxis: object,
        timeline: object,
        graphic: object,
        calendar: object,
        dataset: object,
        aria: object,
        series: array,
        color: array,
        backgroundColor: string,
        textStyle: object,
        animation: boolean,
        animationThreshold: number,
        animationDuration: number,
        animationEasing: string,
        animationDelay: number,
        animationDurationUpdate: number,
        animationEasingUpdate: string,
        animationDelayUpdate: number,
        blendMode: string,
        hoverLayerThreshold: number,
        useUTC: boolean,
}
ECharts 的使用方法绝大部分都围绕着这些属性展开。根据配置作用,可以将上述属性划分为以下几类:
- 图表配置 ,对应 
series项。该属性接受一个数组值,每个数组项对应一个图表,数组项至少需要提供type属性用于指定图表类型; - 组件配置 ,包括 
title、radar、toolbox等项。ECharts 将图表的常见的各项元素按功能组织为组件形式,组件与图表通常是松耦合的,可以应用到多个图表上; - 基础配置 ,包括 
textStyle、color、animation等项。用以设定实例的基本运行逻辑。 
2.2.1 图表配置
ECharts 的图表由 series 数组指定。series 数组项接受对象形式,每个数组项对应一个图表,数组项通过 type 声明图表类型;通过 data 数组声明图表数据序列。比如:
series: [
    {
        data: [820, 932, 901, 934, 1290, 1330, 1320],
        type: 'bar',
    },
    {
        data: [620, 1032, 401, 624, 690, 730, 1420],
        type: 'line',
    },
],
上述配置会渲染出一个柱形图,一个折线图,效果:

不同类型图表的配置结构有较大区别,详情请参考 官网
Tips :
图表大致上可以分为以下几类:
- 直角坐标系图表,包括
 line、bar、scatter、boxplot等;- 极坐标系图表,包括
 line、bar、scatter;- 日历坐标系图表,支持
 heatmap、scatter、graph;- 地图坐标系图表,包括
 heatmap、scatter等;- 无坐标系,不依赖于坐标系环境的图表,包括:
 funnel、pie、treemap、graph等。上例图表依赖于坐标系组件,必须同时提供图表系列与坐标系的定义才能正常运行。对于这部分图表,坐标系相当于一个容器,图表的数据语义、渲染、边界都由坐标系控制。第 5 类图表则更加内聚,不依赖于其他组件。
2.2.2 组件配置
ECharts 组件大致可分为:
- 坐标系与坐标轴组件,这类组件直接参与到图表定位、渲染过程中,包括 
grid、xAxis、radar、calendar、polar等; - 信息增强组件,用以传达关于图表的更多信息,包括
title、tooltip、axisPointer; - 交互增强组件,为使用者提供改变图表视图的交互能力,包括 
toolbox、legend、visualMap、dataZoom、brush、timeline。 
Tips :
部分组件不能单独使用,需要与关联组件同时配置才能生效,比如grid+xAxis+yAxis组合用于配置直角坐标系;polar+angleAxis+radiusAxis组合用于配置极坐标系。
2.2.3 基础配置
许多配置项在设计上具有多级继承的特性,方法是在组件、图表的配置上设定相同的同名属性。运行时,ECharts 会沿着配置链路逐层向下 merge,比如 textStyle 属性,在 title 配置项中有同名属性 title.textStyle,在下例中:
const option = {
    textStyle: { color: '#fff', fontStyle: 'normal' },
    title: {
        textStyle: { color: '#eee' },
    },
};
最终作用在 title 上的 textStyle 值等于 merge(option.textStyle, option.title.textStyle),结果为:
title.textStyle = {
    // 属性值来自 option.title.textStyle.color
    color: '#eee',
    // 属性值来自 option.textStyle.fontStyle
    fontStyle: 'normal',
};
Tips :
继承能力能够实现配置项的复用,当某些配置值能够在多个组件、图表上复用时,应该提出来在更上层作为基础配置,可有效减少冗余配置项。
3. 图表的更新
3.1 配置更新
在实例运行过程中可多次调用 setOption 接口,实现动态更新图表。接口能够对先后提供的多个 option 参数做 merge 操作,达到增量更新的效果,例如上面示例中,首次提供的配置项为:
const option = {
    toolbox: { feature: { saveAsImage: {} } },
    xAxis: {
        type: 'category',
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    },
    yAxis: { type: 'value' },
    series: [
        {
            type: 'line',
            data: [820, 932, 901, 934, 1290, 1330, 1320],
        },
    ],
};
myChart.setOption(option);
后续更新时,只需要提供发生变动的那一部分的配置项, setOption 会对前后配置对象做 merge 计算,例如:
const partialOption = {
    series: [{ data: [1280, 762, 901, 934, 1290, 1330, 1320] }],
};
myChart.setOption(partialOption);
// merge 后的结果:
{
    toolbox: { feature: { saveAsImage: {} } },
    xAxis: {
        type: 'category',
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    },
    yAxis: { type: 'value' },
    series: [
        {
            type: 'line',
            // 原始配置
            // data: [820, 932, 901, 934, 1290, 1330, 1320],
            // merge 后的series数组
            data: [1280, 762, 901, 934, 1290, 1330, 1320]
        },
    ],
}
Tips :
当lazyUpdate为true时,图表不会立刻被更新渲染,ECharts 会等待下一帧发生时再尝试执行更新,帧的调度由 zepto 实现,底层依赖requestAnimationFrame接口,详情可参考 源码。
merge 特性实现了形式上的部分更新,ECharts 底层执行的实际上是清空图表之后重新渲染所有组件、图表 —— 即使我们只是修改了配置上的一小部分。这种处理模型的背后是 ECharts 将配置对象视作原子对象,每次调用 setOption 接口都被认为是一个全新的配置对象,不对之前的渲染结果做任何复用。ECharts 提供了另一个性能更佳,但功能受限的更新接口: appendData,详情请参考下一节。
3.2 数据增量更新
echartInstance.appendData 接口用于向已有的数据序列追加更多数据项,接口调用后不会改变任何已渲染的组件、图表,只会在对应图表上追加数据图案,性能更佳。appendData 接口签名:
(opts: {
    // 要增加数据的系列序号。
    seriesIndex?: string,
    // 增加的数据。
    data?: Array | TypedArray,
}) => void;
Tips :
官网文档 显示的返回值是string,但实测几个版本都返回undefined,不知是不是接口与文档没有同步更新好。
基础示例:
示例中调用 setInterval 不断追加数据项,效果:

appendData 有一个很大的限制 —— 它不会改变任何已经渲染好的图形元素,比如上例在渲染追加图表项时,即使坐标轴预定的数值范围无法容纳新增的数据,ECharts 也不会对坐标轴做任何变动,因此在上述示例需要在 xAxis、yAxis 配置上预留足够的空间来容纳追加的数据。
Tips :
这个限制导致appendData接口对坐标系图表来说特别鸡肋,实用性低,甚至在官网提供的实例也很少见到appendData的用例。一个变通方法是混合使用setOption与appendData,例如在直角坐标系中,用额外的变量记录当前 x、y 轴的最大最小值,如果新增的数值超出这个范围的时候就通过setOption更新图表;否则尽量使用appendData。
appendData在地图散点图上表现的很好,但其他场景上限制多功能弱,带来的问题多过便利,所以多数情况下都会退化为使用setOption接口维护数据状态。
此外,appendData 还有如下限制:
- 只能应用在少数图表类型上,目前支持: 散点图(scatter)、线图(line)、柱形图(bar);ECharts GL 版本的 散点图(scatterGL)、线图(linesGL) 和 可视化建筑群(polygons3D)。
 - 不兼容 dataset,使用 
appendData时图表的数据只能通过series.data定义。 
Tips :
除
setOption、appendData外,Echarts 没有再提供其他维护数据内容的接口,数据的删除、插入、更改都没有官方推荐的方法,需要开发者自行处理。
3.3 宽度自适应
ECharts 图表不具备响应式特性,初次渲染后不会因为容器尺寸的变化做自适应调节,需要用户自行监听屏幕尺寸的变化,并随之调用 resize 函数,函数签名:
(opts?: { width?: number | string, height?: number | string, silent?: boolean }) => ECharts;
参数:
width: 显式指定实例宽度,单位为像素。如果传入值为null/undefined/'auto',则表示自动取 dom(实例容器)的宽度;height: 显式指定实例高度,单位为像素。如果传入值为null/undefined/'auto',则表示自动取 dom(实例容器)的高度;silent: 是否禁止抛出事件。
为了实现图表元素响应屏幕尺寸的变化,通常可以加入如下代码片段:
window.addEventListener('resize', myChart.resize);
增加上述代码片段后,在 SPA 场景下,当图表随页面跳转而析构后务必移除对应的事件监听,否则 ECharts 实例对象会一直被事件系统保留引用,导致内存泄漏!但是 ECharts 并没有暴露示例的析构事件,处理时机只能由开发者自行把握,以
vue为例,推荐的用法:Vue.component('HelloWorld', { mounted() { this._ec = echarts.init(xxx); window.addEventListener('resize', this._ec.resize); }, beforeDestroy() { window.removeEventListener('resize', this._ec.resize); }, });
4. 小结

本节主要讲述 Echarts 图表常规的创建、配置、动态更新方法,这些是 Echarts 最常用的几类接口,大多数应用都围绕着他们展开,读者应多加学习,为正式环境应用打下坚实基础。
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
