ECharts 事件系統(tǒng)
當(dāng)我們的圖表變得越來(lái)越龐大之后,我們加入的組件也會(huì)越來(lái)越多,所以我們之后做的不單單只有 “看”這一個(gè)動(dòng)作,還要有其他的動(dòng)作,對(duì)應(yīng)的就是一個(gè)個(gè)事件的處理,用戶操作觸發(fā)事件,我們則可以通過(guò)監(jiān)聽事件并處理來(lái)完成一系列的事件操作,所以這一節(jié)我們就來(lái)從事件三要素,事件綁定,事件解綁這幾個(gè)方面去了解一下 ECharts 的事件系統(tǒng)。
1. 簡(jiǎn)介
在 ECharts 的圖表中用戶的操作將會(huì)觸發(fā)相應(yīng)的事件。開發(fā)者可以監(jiān)聽這些事件,然后通過(guò)回調(diào)函數(shù)做相應(yīng)的處理,比如跳轉(zhuǎn)到一個(gè)地址,或者彈出對(duì)話框,或者做數(shù)據(jù)下鉆等等。更多細(xì)節(jié)可參考 官網(wǎng)。
慕課解釋
ECharts 開放了兩套 API 體系,一是 ECharts 類接口及實(shí)例的接口,例如常用的 echarts.init
方法、echartInstance.setOption()
;二是圍繞事件展開的動(dòng)態(tài)交互接口,包括用于監(jiān)聽事件的 echartInstance.on
函數(shù)和用于觸發(fā)行為的 echartInstance.dispatchAction
函數(shù)。
本文討論使用 echartInstance.on
接口實(shí)現(xiàn)的事件監(jiān)聽功能。
2. 事件三要素
與 Dom Event 規(guī)范 類似,ECharts 通過(guò)事件名稱、事件源、事件參數(shù)三個(gè)要素精確描述誰(shuí)在何處執(zhí)行了何種操作。在展開示例討論前,有必要簡(jiǎn)單討論下 ECharts 事件三要素的含義。
2.1 事件名稱
ECharts 中存在兩種類型的事件,第一種是鼠標(biāo)在圖形示例上的行為所觸發(fā)的鼠標(biāo)事件,包括:
上述事件除 globalout 外,均與 DOM Event 規(guī)范 定義的同名事件有相同的語(yǔ)義、觸發(fā)條件。globalout 在鼠標(biāo)移出圖表示例范圍時(shí)觸發(fā)。
第二種稱為行為事件,在組件、圖表狀態(tài)發(fā)生某種業(yè)務(wù)狀態(tài)遷移時(shí)觸發(fā),包括:
事件名 | 適用組件 | 觸發(fā)時(shí)機(jī) |
---|---|---|
legendselectchanged | legend | 切換圖例選中狀態(tài)后的事件 |
legendselected | legend | 圖例選中后的事件 |
legendunselected | legend | 圖例取消選中后的事件 |
legendscroll | legend | 圖例滾動(dòng)事件 |
datazoom | datazoom | 數(shù)據(jù)區(qū)域縮放后的事件 |
datarangeselected | visualMap | 視覺(jué)映射組件中,range 值改變后觸發(fā)的事件 |
timelinechanged | timeline | 時(shí)間軸中的時(shí)間點(diǎn)改變后的事件 |
timelineplaychanged | timeline | 時(shí)間軸中播放狀態(tài)的切換事件 |
dataviewchanged | toolbox | 工具欄中數(shù)據(jù)視圖的修改事件 |
magictypechanged | toolbox | 工具欄中動(dòng)態(tài)類型切換的切換事件 |
brush | brush | 選框添加事件 |
globalcursortaken | brush | brush 組件捕獲鼠標(biāo) cursor 時(shí)觸發(fā) |
brushselected | brush | 選框內(nèi)容變更事件 |
geoselectchanged | geo | geo 中地圖區(qū)域切換選中狀態(tài)的事件 |
geoselected | geo | geo 中地圖區(qū)域選中后的事件 |
geounselected | geo | geo 中地圖區(qū)域取消選中后的事件 |
axisareaselected | 平行坐標(biāo)軸 | 平行坐標(biāo)軸范圍選取事件 |
pieselectchanged | 餅圖 | 餅圖扇形切換選中狀態(tài)的事件 |
pieselected | 餅圖 | 餅圖扇形選中后的事件 |
pieunselected | 餅圖 | 餅圖扇形取消選中后的事件 |
mapselectchanged | 地圖 | 地圖區(qū)域切換選中狀態(tài)的事件 |
mapselected | 地圖 | 地圖區(qū)域選中后的事件 |
mapunselected | 地圖 | 地圖區(qū)域取消選中后的事件 |
focusnodeadjacency | 連接圖 | graph 圖鄰接節(jié)點(diǎn)高亮事件 |
unfocusnodeadjacency | 連接圖 | graph 的鄰接節(jié)點(diǎn)取消高亮事件 |
restore | ECharts 實(shí)例 | 重置 option 事件 |
rendered | ECharts 實(shí)例 | 渲染完成事件 |
finished | ECharts 實(shí)例 | 同樣是渲染完成事件,當(dāng)動(dòng)畫或漸進(jìn)渲染結(jié)束時(shí)觸發(fā) |
上表只摘錄行為事件的關(guān)鍵部分,更詳細(xì)的介紹請(qǐng)參考 官網(wǎng)文檔。
行為事件的發(fā)生代表著組件實(shí)體內(nèi)部狀態(tài)發(fā)生了某些變更,有兩種原因可能觸發(fā)行為事件:
- 用戶交互行為,例如圖例組件中,用戶通過(guò)鼠標(biāo)點(diǎn)擊切換圖例開關(guān)時(shí),ECharts 除觸發(fā)鼠標(biāo) click 事件外,還會(huì)觸發(fā) legendselectchanged 行為事件;
- 接口調(diào)用,例如圖例組件中,調(diào)用
echartInstance.dispatchAction({ type: 'legendToggleSelect' })
后也依然會(huì)觸發(fā) legendselectchanged 行為事件。
2.2 事件源
事件源描述了觸發(fā)事件的主體,對(duì)于鼠標(biāo)事件,事件源通常是行為發(fā)生時(shí)鼠標(biāo)焦點(diǎn)所在圖形區(qū)域?qū)?yīng)的圖表。所有類型的圖表都支持鼠標(biāo)事件;部分組件支持觸發(fā)鼠標(biāo)事件,但默認(rèn)是關(guān)閉的,需要通過(guò)設(shè)置 triggerEvent: true
來(lái)啟動(dòng)。組件對(duì)鼠標(biāo)事件的支持情況如下:
- 支持:
title
,xAxis
,yAxis
,radiusAxis
,angleAxis
,radar
,parallelAxis
,singleAxis
,timeline
,calendar
; - 不支持:
polar
,legend
,grid
,datazoom
,visualMap
,tooltip
,axisPointer
,toolbox
,brush
,geo
,parallel
,graphic
。
Tips:
graphic 是原生圖形組件,不支持
echartInstance.on
接口,但可直接調(diào)用element.onclick
等接口實(shí)現(xiàn)事件監(jiān)聽。
行為事件由特定的組件、圖表觸發(fā),例如 legendselectchanged 的事件源只能是 legend 組件,更多信息請(qǐng)參考 事件名稱 一節(jié)。
2.3 事件參數(shù)
事件參數(shù)描述事件發(fā)生時(shí)的上下文信息,ECharts中不同事件的參數(shù)信息相差極大,甚至同種事件在不同組件觸發(fā)時(shí),回調(diào)參數(shù)也有差異。
2.3.1 鼠標(biāo)事件參數(shù)
ECharts 鼠標(biāo)事件,雖然名稱上與 DOM Event 規(guī)范 一致,但回調(diào)中傳遞的參數(shù)比標(biāo)準(zhǔn)相差很大。以 click 為例,DOM 的 click 事件參數(shù)是一個(gè) MouseEvent 對(duì)象,主要屬性有:
{
isTrusted: boolean,
screenX: number,
screenY: number,
clientX: number,
clientY: number,
ctrlKey: boolean,
shiftKey: boolean,
altKey: boolean,
metaKey: boolean,
relatedTarget: object,
pageX: number,
pageY: number,
x: number,
y: number,
offsetX: number,
offsetY: number,
...
}
可以看出 DOM 的 click 事件參數(shù)詳細(xì)描述了點(diǎn)擊行為發(fā)生的位置、事件源的 dom、是否帶有快捷鍵、捕獲的階段等。而 ECharts 在 series 上發(fā)生的 click 事件帶有如下參數(shù):
{
// 當(dāng)前點(diǎn)擊的圖形元素所屬的組件名稱,
// 其值如 'series'、'markLine'、'markPoint'、'timeLine' 等。
componentType: string,
// 圖形元素所屬二級(jí)組件類型
// 如 `bar`、`line`、`pie` 等
componentSubType: string,
componentIndex: number,
// 系列類型。值可能為:'line'、'bar'、'pie' 等
seriesType: string,
// 系列在傳入的 option.series 中的 index
seriesIndex: number,
// 系列ID
seriesId: string,
// 系列名稱
seriesName: string,
// 數(shù)據(jù)名,類目名
name: string,
// 觸發(fā)事件的數(shù)據(jù)在data數(shù)組中的index
dataIndex: number,
// 觸發(fā)事件的數(shù)據(jù)所傳入的原始data值
data: number,
// sankey、graph 等圖表同時(shí)含有 nodeData 和 edgeData 兩種 data,
// dataType 的值會(huì)是 'node' 或者 'edge',表示當(dāng)前點(diǎn)擊在 node 還是 edge 上。
// 其他大部分圖表中只有一種 data,dataType 無(wú)意義。
dataType: string,
// 傳入的數(shù)據(jù)值
value: number | Array,
// 數(shù)據(jù)圖形的顏色
color: string,
// 數(shù)據(jù)圖形的邊框色
borderColor: undefined,
// 數(shù)據(jù)圖形的維度信息
dimensionNames: object,
encode: object,
// 標(biāo)記信息的html內(nèi)容
marker: string,
$vars: object,
// 原始click事件參數(shù)
event: object,
// 事件名稱,本例中為 `click`
type: string,
}
可以看出,ECharts 傳遞的 click 事件參數(shù)側(cè)重于描述發(fā)生點(diǎn)擊行為的圖形所對(duì)應(yīng)的組件信息、狀態(tài)、配置,比如上例中的 componentType、componentSubType 指明單擊的組件類別、子類別;seriesType、seriesIndex、data 等指明單擊組件所對(duì)應(yīng)的數(shù)據(jù)配置值;marker、encode 則指明單擊發(fā)生時(shí),組件內(nèi)部狀態(tài)信息。大多數(shù)情況下這些信息是足夠使用的,必要時(shí)也可以通過(guò) event 屬性讀取原始 dom 事件參數(shù)。
需要注意的第二點(diǎn)是,即使是同種事件,不同組件所暴露的參數(shù)也是不一樣的,以 click 為例,在 series.bar
上觸發(fā)時(shí)有如下屬性:
componentType
、componentSubType
、componentIndex
、seriesType
、seriesIndex
、seriesId
、seriesName
、name
、dataIndex
、data
、dataType
、value
、color
、borderColor
、dimensionNames
、encode
、marker
、$vars
、event
、type
在 yAxis
則有:
componentType
、componentIndex
、yAxisIndex
、targetType
、value
、event
、type
在 title
上則是:
componentType
、componentIndex
、event
、type
Tips:
遺憾的是,官網(wǎng)并未就此給出詳細(xì)、完整的列表,建議開發(fā)時(shí)通過(guò)console.log
、debugger
等手段獲取各種組件所傳遞的事件參數(shù)。
2.3.2 行為事件參數(shù)
與鼠標(biāo)事件參數(shù)一樣,行為事件也沒(méi)有提供一致的參數(shù)模型,不過(guò)官網(wǎng)提供了 明細(xì)說(shuō)明,開發(fā)時(shí)建議前往查閱。
3. 監(jiān)聽事件
ECharts 中可通過(guò) echartInstance.on
函數(shù)綁定事件處理函數(shù),on 函數(shù)簽名:
(eventName: string, query?: string|Object, handler: Function, context?: Object)
各參數(shù)說(shuō)明:
參數(shù)名 | 類型 | 必選 | 說(shuō)明 |
---|---|---|---|
eventName | string | 是 | 指定監(jiān)聽的事件名稱 |
query | string|object | 否 | 指定在特定的組件或者元素上響應(yīng) ,僅在鼠標(biāo)事件中有效 |
handler | function | 是 | 事件回調(diào)函數(shù) |
context | object | 否 | 回調(diào)函數(shù)執(zhí)行時(shí)的 this 對(duì)象,默認(rèn)為觸發(fā)事件的 ECharts 實(shí)例對(duì)象 |
3.1 全局監(jiān)聽
若未提供 query 參數(shù),ECharts 將不對(duì)事件源做任何過(guò)濾,相當(dāng)于注冊(cè)了一個(gè)全局事件回調(diào)。例如:
<!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.common.js"></script>
<script type="text/javascript">
const myChart = echarts.init(document.getElementById('main'));
const option = {
title: {
text: 'test',
// 通過(guò) triggerEvent 顯式聲明
// 該組件將觸發(fā)事件回調(diào)
triggerEvent: true,
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
triggerEvent: true,
},
yAxis: {
type: 'value',
triggerEvent: true,
},
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'bar',
},
],
};
myChart.setOption(option);
// 注冊(cè) `click` 事件回調(diào)
myChart.on('click', function (e) {
console.log(`click invoke at ${e.componentType}`);
});
</script>
</body>
</html>
示例效果:
Tips:
需要注意,所謂的全局監(jiān)聽并不是所有組件的交互行為都可以被監(jiān)聽,對(duì)于鼠標(biāo)事件,需要滿足如下條件:
- 組件本身支持鼠標(biāo)交互事件,詳情可參考 2.2 事件源 一節(jié)。
- 組件啟用了鼠標(biāo)事件功能,所有圖表默認(rèn)啟用;其他組件則需要設(shè)置
triggerEvent: true
顯式聲明,如上例的title
、yAxis
、xAxis
組件。
在回調(diào)函數(shù)中,可以通過(guò)回調(diào)參數(shù)的 componentType
、componentSubType
等屬性事件發(fā)生的具體位置,詳情可參考 2.3 事件參數(shù) 一節(jié)。
3.2 帶過(guò)濾條件的監(jiān)聽
若提供了 query 參數(shù),則 ECharts 在執(zhí)行回調(diào)前,會(huì)先判斷事件源是否滿足過(guò)濾條件。 query 參數(shù)支持 string、object 兩種形式,當(dāng)使用字符串時(shí),內(nèi)容格式可以是 mainType、mainType.subType 兩種形式,例如:
<!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.common.js"></script>
<script type="text/javascript">
const myChart = echarts.init(document.getElementById('main'));
const option = {
xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] },
yAxis: { type: 'value', min: 800 },
series: [
{ data: [820, 932, 901, 934, 1290, 1330, 1320], type: 'bar' },
{ data: [920, 1032, 1001, 1034, 1390, 1430, 1420], type: 'line' },
],
};
myChart.setOption(option);
// 在所有 series 上都觸發(fā)
myChart.on('click', 'series', function (e) {
console.log(`series listener: click invoke at ${e.componentType}.${e.componentSubType}`);
});
// 只在 line 圖表上觸發(fā)
myChart.on('click', 'series.line', function (e) {
console.log(`line listener: click invoke at ${e.componentType}.${e.componentSubType}`);
});
</script>
</body>
</html>
示例有兩個(gè) click 回調(diào),第一個(gè)指定過(guò)濾參數(shù)為 series,將在所有圖表發(fā)生單擊事件時(shí)執(zhí)行回調(diào);第二個(gè)指定過(guò)濾參數(shù)為 series.line
,則只在折線圖發(fā)生單擊事件時(shí)觸發(fā)。示例效果:
query 還可以以對(duì)象方式傳入,對(duì)象可以包含如下屬性:
{
<mainType>Index: number // 組件 index
<mainType>Name: string // 組件 name
<mainType>Id: string // 組件 id
dataIndex: number // 數(shù)據(jù)項(xiàng) index
name: string // 數(shù)據(jù)項(xiàng) name
dataType: string // 數(shù)據(jù)項(xiàng) type,如關(guān)系圖中的 'node', 'edge'
element: string // 自定義系列中的 el 的 name
}
其中 mainType 為組件類型,如 seriesIndex、xAxisIndex 等。示例:
const option = {
...
series: [
{ data: [820, 932, 901, 934, 1290, 1330, 1320], type: 'bar', name: 'series1' },
{ data: [920, 1032, 1001, 1034, 1390, 1430, 1420], type: 'line', name: 'series2' },
],
};
myChart.on(
'click',
// 在 series1 上觸發(fā)
{seriesName:'series1'},
function(e) {
}
);
字符串與對(duì)象形式過(guò)濾的功能不同,字符串形式只能根據(jù)組件類型、子類型過(guò)濾;對(duì)象形式則精確到組件、數(shù)據(jù)項(xiàng)維度。繼續(xù)看看示例:
<!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'));
const option = {
grid: { triggerEvent: true },
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'bar',
},
],
title: { text: 'test' },
};
myChart.setOption(option);
myChart.on('click', { dataIndex: 1 }, (e) => {
console.log(`click invoke with data index: ${e.dataIndex}`);
});
</script>
</body>
</html>
示例聲明過(guò)濾參數(shù)為 { dataIndex: 1 }
,則只會(huì)在數(shù)據(jù)項(xiàng) 1 上觸發(fā),效果:
4. 解綁事件監(jiān)聽
可通過(guò) echartInstance.off
接觸事件綁定,函數(shù)簽名:
(eventName: string, handler?: Function)
handler 參數(shù)可選,若未提供該參數(shù)則解除所有 eventName 的事件監(jiān)聽。
5. 個(gè)人經(jīng)驗(yàn)
ECharts 的事件系統(tǒng)設(shè)計(jì)的比較隱晦,有很多隱藏邏輯并沒(méi)有表現(xiàn)在官方文檔上,本文嘗試對(duì)事件系統(tǒng)做個(gè)全局的介紹,總結(jié)重點(diǎn)如下:
- ECharts 事件包括鼠標(biāo)事件、交互事件兩種類型;
- 所有圖表組件都支持鼠標(biāo)事件;部分組件支持鼠標(biāo)事件,但需要設(shè)置
triggerEvent: true
顯式聲明啟動(dòng)鼠標(biāo)組件支持; - 監(jiān)聽函數(shù) on 默認(rèn)監(jiān)聽實(shí)例上所有的組件,可通過(guò) query 過(guò)濾事件源,不過(guò) query 參數(shù)只對(duì)鼠標(biāo)事件有效;
- 對(duì)于鼠標(biāo)事件,種類型的事件在不同組件觸發(fā)時(shí),事件參數(shù)不同,且目前官方未提供詳盡的說(shuō)明文檔,只能又開發(fā)者自行摸索;
- 同一組件的所有鼠標(biāo)事件的事件參數(shù)相同。
6. 小結(jié)
本節(jié)完整地介紹 Echarts 中事件系統(tǒng)的設(shè)計(jì)理念與用法,包括事件名稱、事件源、事件參數(shù)三類要素的意義;綁定、解綁事件的接口;官方事件,以及如何自定義事件等。