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