ECharts 數(shù)據(jù)縮放組件
在一個數(shù)據(jù)圖表中,可能由于數(shù)據(jù)所表示的時間范圍較大,從而導(dǎo)致整個圖表相當?shù)拈L,當這些數(shù)據(jù)都不得不展示的時候,對我們分析某一段時間內(nèi)數(shù)據(jù)的變化造成的極大的影響,所以當我們遇到這種情況的時候就需要用到 ECharts 的數(shù)據(jù)縮放組件了。
1. 簡介
dataZoom 組件 用于區(qū)域縮放,從而能自由關(guān)注細節(jié)的數(shù)據(jù)信息,或者概覽數(shù)據(jù)整體,或者去除離群點的影響。
慕課解釋
dataZoom 組件提供了一套在圖表運行狀態(tài)下,終端用戶可以通過鼠標、手指(觸屏下)的動作觸發(fā)圖表視圖窗口變化,使圖表聚焦在某個局部區(qū)域的交互功能。dataZoom 有 3 個變種:
2. 實例解析
原理上,dataZoom 通過控制坐標軸的數(shù)值范圍實現(xiàn)圖表視圖窗口的變化,所以對于開發(fā)者來說,無論使用變種,最基本的需要確定 dataZoom 控制的是那個(或那些)數(shù)軸,以及對其他數(shù)軸的影響。
Tips:
dataZoom 只適用于直角坐標系、極坐標系,對于地圖、日歷坐標系等可考慮使用 visualmap 組件。
2.1 選定主軸
使用 dataZoom 的第一步是確定縮放組件要控制那一條坐標軸,方法很簡單,在直角坐標系下通過設(shè)定 xAxisIndex或 yAxisIndex 為對應(yīng)坐標軸下標;極坐標系下通過設(shè)定 radiusAxisIndex 或 angleAxisIndex 為對應(yīng)坐標軸下標即可。例如下例設(shè)定兩個 dataZoom 實例并分別指向兩個不同類型的坐標軸:
<!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: 1020px; height: 400px;"></div>
<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
<script type="text/javascript">
const random = (min, max) => Math.round(Math.random() * (max - min) + min);
const myChart = echarts.init(document.getElementById('main'));
const option = {
toolbox: {
feature: {
saveAsImage: {},
},
},
dataZoom: [
// 作用在直角坐標系上
{ type: 'slider', xAxisIndex: 0, right: '55%', left: 0 },
// 作用在極坐標系上
{ type: 'slider', angleAxisIndex: 0, left: '55%', right: '5%' },
],
grid: { left: 0, containLabel: true, width: '45%' },
xAxis: { type: 'value' },
yAxis: { type: 'category' },
polar: { left: '50%', containLabel: true, radius: '55%', center: ['77%', '50%'] },
angleAxis: { type: 'category' },
radiusAxis: { type: 'value' },
series: [
{
data: genSeriesData(7),
type: 'bar',
},
{
data: genSeriesData(7),
type: 'bar',
coordinateSystem: 'polar',
},
],
};
myChart.setOption(option);
function genSeriesData(len) {
const result = [];
for (let i = 0; i < len; i += 1) {
const node = [random(10, 100), `S${i + 1}`];
result.push(node);
}
return result;
}
</script>
</body>
</html>
示例效果:
Tips:
dataZoom 三個變種功能相似,其中只有 slider 類型提供了視覺組件,為演示的便利,本文中的示例默認使用 slider 類型,inside、select 功能類似,以此類推即可。
dataZoom 也支持同時控制兩條軸的數(shù)據(jù)窗口,只需同時指定 xAxisIndex 和 yAxisIndex(極坐標下則同時指定 angleAxisIndex、radiusAxisIndex),不過需要兩個軸有相同的類型和數(shù)值范圍,例如下例:
<!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: 1020px; height: 400px;"></div>
<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
<script type="text/javascript">
const random = (min, max) => Math.round(Math.random() * (max - min) + min);
const myChart = echarts.init(document.getElementById('main'));
const option = {
// 同時控制x軸、y軸
dataZoom: [{ type: 'slider', xAxisIndex: 0, yAxisIndex: 0, filterMode: 'weakFilter' }],
grid: {},
xAxis: { type: 'value' },
yAxis: { type: 'value' },
tooltip: { trigger: 'axis' },
series: [
{
data: genSeriesData(20),
type: 'line',
smooth: true,
areaStyle: {},
},
],
};
myChart.setOption(option);
function genSeriesData(len) {
const result = [];
let cursor = 0;
for (let i = 0; i < len; i += 1) {
const node = [(cursor = cursor + random(10, 100)), random(100, 1000)];
result.push(node);
}
return result;
}
</script>
</body>
</html>
縮放后,要求數(shù)值項的 x、y 值同時在窗口內(nèi)才會顯示,可以仔細觀察下圖,隨著 dataZoom 滑塊的變化,圖表 x、y 軸的數(shù)值范圍同時發(fā)生變化:
2.2 選擇過濾模式
選定主軸后,可以通過 filterMode 屬性設(shè)定 dataZoom 對其它軸及圖表數(shù)值點的副作用。filterMode 屬性支持如下值:
- filter:對于序列中的數(shù)據(jù)項,只要有一個維度在數(shù)據(jù)窗口外,整個數(shù)據(jù)項就會被過濾掉;
- weakFilter:對于序列中的數(shù)據(jù)項,當所有維度都在數(shù)據(jù)窗口外時,才會被過濾掉;
- empty:數(shù)據(jù)窗口之外的數(shù)據(jù)會被設(shè)置為空;
- none:不過濾數(shù)據(jù)。
2.3 優(yōu)化導(dǎo)出功能
在使用 dataZoom 的場景中,導(dǎo)出圖片時會保持經(jīng)過 dataZoom 調(diào)整過的視圖窗口,導(dǎo)致圖片無法完整地展示整個圖表的內(nèi)容,例如:
<!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: 1020px; height: 400px;"></div>
<button id="export">export png</button>
<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
<script type="text/javascript">
const random = (min, max) => Math.round(Math.random() * (max - min) + min);
const myChart = echarts.init(document.getElementById('main'));
const option = {
toolbox: { feature: { saveAsImage: {} } },
dataZoom: [{ type: 'slider', xAxisIndex: 0, start: 14, end: 50 }],
grid: {},
xAxis: { type: 'category' },
yAxis: { type: 'value' },
series: [
{
data: genSeriesData(20),
type: 'bar',
},
],
};
myChart.setOption(option);
function genSeriesData(len) {
const result = [];
for (let i = 0; i < len; i += 1) {
const node = [`S${i + 1}`, random(10, 100)];
result.push(node);
}
return result;
}
</script>
</body>
</html>
點擊右上角工具欄的 saveAsImage 按鈕后,導(dǎo)出的結(jié)果:
此時,可以綜合使用 ECharts 提供的各類接口,自行實現(xiàn)導(dǎo)出過程。基本流程是:
- 通過 dataZoom 行為 將數(shù)值范圍設(shè)置為 0% ~ 100%,以展示完整的視圖;
- 監(jiān)聽 finished 事件,在圖表重新渲染完成后,執(zhí)行導(dǎo)出函數(shù) getDataUrl;
- 通過
document.createElement('a')
并設(shè)置 src 屬性為上一步得到圖片 base64 值,模擬點擊下載行為,得到完整圖片; - 移除 finished 事件監(jiān)聽,避免重復(fù)導(dǎo)出;
- 重置 dataZoom,恢復(fù)操作前的值。
完整示例:
<!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: 1020px; height: 400px;"></div>
<button id="export">export png</button>
<script src="//cdn.bootcss.com/echarts/4.5.0/echarts.js"></script>
<script type="text/javascript">
const random = (min, max) => Math.round(Math.random() * (max - min) + min);
const myChart = echarts.init(document.getElementById('main'));
const option = {
toolbox: { feature: { saveAsImage: {} } },
dataZoom: [{ type: 'slider', xAxisIndex: 0, start: 14, end: 50 }],
grid: {},
xAxis: { type: 'category' },
yAxis: { type: 'value' },
series: [
{
data: genSeriesData(20),
type: 'bar',
},
],
};
myChart.setOption(option);
// 此處實現(xiàn)自定義的圖片導(dǎo)出過程
document.getElementById('export').addEventListener('click', () => {
const dz = myChart.getModel().option.dataZoom[0];
// 記錄當前時刻的偏移值
const oldStart = dz.start;
const oldEnd = dz.end;
// 通過 action 將dataZoom組件數(shù)值范圍設(shè)置為 0%-100%
myChart.dispatchAction({ type: 'dataZoom', start: 0, end: 100 });
// 監(jiān)聽渲染完成事件
myChart.on('finished', download);
function download() {
const img = myChart.getDataURL({
backgroundColor: '#fff',
// 導(dǎo)出時排除 dataZoom 組件
excludeComponents: ['toolbox', 'dataZoom'],
pixelRatio: 1,
});
const anchor = document.createElement('a');
anchor.href = img;
anchor.setAttribute('download', 'test.jpeg');
anchor.click();
// 移除事件監(jiān)聽,避免多次導(dǎo)出
myChart.off('finished', download);
myChart.dispatchAction({ type: 'dataZoom', start: oldStart, end: oldEnd });
}
});
function genSeriesData(len) {
const result = [];
for (let i = 0; i < len; i += 1) {
const node = [`S${i + 1}`, random(10, 100)];
result.push(node);
}
return result;
}
</script>
</body>
</html>
通過該示例能夠正確導(dǎo)出完整圖表,結(jié)果如:
3. 小結(jié)
本節(jié)結(jié)合多個實例,講述 Echarts 數(shù)據(jù)縮放組件(dataZoom)的使用方法,包括選定縮放主軸的策略;各類過濾模式的表現(xiàn);以及在縮放組件介入的場景下,如何完整導(dǎo)出圖表。