亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

ECharts 創建圖表

經過前面的學習,相信大家已經在自己的項目中繪制了一個基本的 ECharts 圖表,但是前面學習只是為了讓我們更好的了解安裝的流程。所以該小節,我們將會去更加詳細的了解到 ECharts 的 創建,更新,也會通過一個案例去跟蹤分析整個過程,所謂 萬事開頭難,在這個過程中也會有許許多多需要同學們注意的地方,希望大家在學習的時候也能靜下心來完成這重要的一步。

1. 簡介

ECharts 用法非常簡單,定義圖表的基本流程是實例化 echarts 后,調用 setOption 傳入配置對象,ECharts 根據配置對象的描述渲染各類圖表、組件。本節主要講解初始配置圖表的基本流程,以及實例化后動態更新圖表內容的方法。

2. 創建圖表

2.1 創建圖表的步驟

通常,創建一個 ECharts 圖表需要執行如下步驟:

  1. 定義 DOM 節點作為圖表的容器;
  2. 調用 echarts.init 方法實例化 ECharts 對象;
  3. 調用 echartInstance.setOption 方法傳入圖表配置。

例如:

實例演示
預覽 復制
復制成功!
<!DOCTYPE html>
<html lang="zh-CN">
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width,initial-scale=1.0" />
		<title>Echarts Example</title>
	</head>
	<body>
		<!-- 第一步,設定圖表容器 DOM 節點 -->
		<div id="main" style="width: 600px; height: 400px;"></div>

		<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
		<script type="text/javascript">
			// 第二步,調用 init 函數初始化echarts對象
			const myChart = echarts.init(document.getElementById('main'));

			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],
					},
				],
			};
			// 第三步,調用 setOption 設定圖表配置
			myChart.setOption(option);
		</script>
	</body>
</html>
運行案例 點擊 "運行案例" 可查看在線運行效果

示例效果:

圖片描述

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 默認內置 lightdark 兩種主題,用戶也可以通過 echarts.registerTheme 接口注冊自定義主題;
  • opts: 附加參數,支持配置屬性:
{
	// 設備像素比,默認取瀏覽器的值 `window.devicePixelRatio`
	devicePixelRatio: 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 的使用方法絕大部分都圍繞著這些屬性展開。根據配置作用,可以將上述屬性劃分為以下幾類:

  1. 圖表配置,對應 series 項。該屬性接受一個數組值,每個數組項對應一個圖表,數組項至少需要提供 type 屬性用于指定圖表類型;
  2. 組件配置,包括 title、radar、toolbox 等項。ECharts 將圖表的常見的各項元素按功能組織為組件形式,組件與圖表通常是松耦合的,可以應用到多個圖表上;
  3. 基礎配置,包括 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:

圖表大致上可以分為以下幾類:

  1. 直角坐標系圖表,包括 line、bar、scatterboxplot 等;
  2. 極坐標系圖表,包括 line、bar、scatter
  3. 日歷坐標系圖表,支持 heatmap、scatter、graph;
  4. 地圖坐標系圖表,包括 heatmapscatter 等;
  5. 無坐標系,不依賴于坐標系環境的圖表,包括:funnel、pie、treemapgraph 等。

上例圖表依賴于坐標系組件,必須同時提供圖表系列與坐標系的定義才能正常運行。對于這部分圖表,坐標系相當于一個容器,圖表的數據語義、渲染、邊界都由坐標系控制。第 5 類圖表則更加內聚,不依賴于其他組件。

2.2.2 組件配置

ECharts 組件大致可分為:

  1. 坐標系與坐標軸組件,這類組件直接參與到圖表定位、渲染過程中,包括 gridxAxis、radar、calendar、polar 等;
  2. 信息增強組件,用以傳達關于圖表的更多信息,包括title、tooltipaxisPointer;
  3. 交互增強組件,為使用者提供改變圖表視圖的交互能力,包括 toolbox、legend、visualMap、dataZoom、brushtimeline。

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
lazyUpdatetrue 時,圖表不會立刻被更新渲染,ECharts 會等待下一幀發生時再嘗試執行更新,幀的調度由 zepto 實現,底層依賴 requestAnimationFrame 接口,詳情可參考 源碼

merge 特性實現了形式上的部分更新,ECharts 底層執行的實際上是清空圖表之后重新渲染所有組件、圖表 —— 即使我們只是修改了配置上的一小部分。這種處理模型的背后是 ECharts 將配置對象視作原子對象,每次調用 setOption 接口都被認為是一個全新的配置對象,不對之前的渲染結果做任何復用。ECharts 提供了另一個性能更佳,但功能受限的更新接口: appendData,詳情請參考下一節。

3.2 數據增量更新

echartInstance.appendData 接口用于向已有的數據序列追加更多數據項,接口調用后不會改變任何已渲染的組件、圖表,只會在對應圖表上追加數據圖案,性能更佳。appendData 接口簽名:

(opts: {
	// 要增加數據的系列序號。
	seriesIndex?: string,
	// 增加的數據。
	data?: Array | TypedArray,
}) => void;

Tips
官網文檔 顯示的返回值是 string,但實測幾個版本都返回 undefined,不知是不是接口與文檔沒有同步更新好。

基礎示例:

實例演示
預覽 復制
復制成功!
<!DOCTYPE html>
<html lang="zh-CN">
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width,initial-scale=1.0" />
		<title>Echarts Example</title>
	</head>
	<body>
		<div id="main" style="width: 600px; height: 400px;"></div>

		<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
		<script type="text/javascript">
			const myChart = echarts.init(document.getElementById('main'));
			let len = 0;
			const random = (min = 0, max = 180) => Math.round(Math.random() * (max - min) + min);
			const range = (from, to) => {
				const result = [];
				for (let i = from; i <= to; i++) {
					result.push(`X-${i}`);
				}
				return result;
			};

			const option = {
				// appendData 接口不會更改初始渲染后的任何組件
				// 所以需要預留足夠的空間來容納追加的圖案
				xAxis: { type: 'category', data: range(1, 20) },
				// 同樣的,在 y 軸上也需要設定好序列的最大值,以容納追加的圖案
				yAxis: { type: 'value', max: 180 },
				series: [
					{
						type: 'bar',
						data: [random(), random()],
					},
				],
			};
			myChart.setOption(option);

			setInterval(() => {
				myChart.appendData({ seriesIndex: 0, data: [random()] });
			}, 300);
		</script>
	</body>
</html>
運行案例 點擊 "運行案例" 可查看在線運行效果

示例中調用 setInterval 不斷追加數據項,效果:

圖片描述

appendData 有一個很大的限制 —— 它不會改變任何已經渲染好的圖形元素,比如上例在渲染追加圖表項時,即使坐標軸預定的數值范圍無法容納新增的數據,ECharts 也不會對坐標軸做任何變動,因此在上述示例需要在 xAxis、yAxis 配置上預留足夠的空間來容納追加的數據。

Tips
這個限制導致 appendData 接口對坐標系圖表來說特別雞肋,實用性低,甚至在官網提供的實例也很少見到 appendData 的用例。一個變通方法是混合使用 setOptionappendData,例如在直角坐標系中,用額外的變量記錄當前 x、y 軸的最大最小值,如果新增的數值超出這個范圍的時候就通過 setOption 更新圖表;否則盡量使用 appendData。

appendData 在地圖散點圖上表現的很好,但其他場景上限制多功能弱,帶來的問題多過便利,所以多數情況下都會退化為使用 setOption 接口維護數據狀態。

此外,appendData 還有如下限制:

  1. 只能應用在少數圖表類型上,目前支持: 散點圖(scatter)、線圖(line)、柱形圖(bar);ECharts GL 版本的 散點圖(scatterGL)、線圖(linesGL) 和 可視化建筑群(polygons3D)。
  2. 不兼容 dataset,使用 appendData 時圖表的數據只能通過 series.data 定義。

Tips

setOptionappendData 外,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: 是否禁止拋出事件。

為了實現圖表元素響應屏幕尺寸的變化,通??梢约尤肴缦麓a片段:

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 最常用的幾類接口,大多數應用都圍繞著他們展開,讀者應多加學習,為正式環境應用打下堅實基礎。