(1)Echarts图表绑定特殊事件
前言:Echarts插件是基于canvas画布而构建的一个图表库,每一个图表由一个或者多个canvas画布构成,大多数时候都由一个canvas构成,图表内部不同组件和图形可以分属于不同的层级,类似于html的z-index属性的功能。不同的层级组件在刷新的时候,有性能的差异。而事件的捕捉和监听,与html存在本质的不同,dom事件的那一套处理规则,在Echarts插件内部并没有具体的元素去支撑,这与基于svg技术的d3和highcharts图表存在本质不同,也可以说是canvas图表库的天然缺陷。
Echarts事件处理原理:Echarts事件的监听和响应,是由底层的zrender库来模拟和封装的。封装后,接口的调用和使用,跟dom元素的事件接口的使用方法类似。具体的实现原理:监听事件的发生坐标(如鼠标点击或者悬浮时候的坐标),判断在哪个绘制元素的范围中,如果在某个元素包含的范围中,该元素就可以监听该事件,执行与该事件相关的事件处理逻辑。具体的解释可参考:HTML5 Canvas绘制的图形的事件处理。Echarts内部每一个类都有一个getBoundingRect方法,该方法会返回与这个类相关的矩形信息。该矩形对应这个元素在图表上的包含范围。如图1所示,当点击y轴的时候,Echarts内部会判断,鼠标的点击位置是否在y轴组件的矩形框包含的范围内。
Echarts初始化事件的总函数:该函数是echartsProto原型下_initEvents的函数,这个函数处理和逻辑,决定我们在内部编写的自定义事件,能不能正常执行和响应。这个坑是我当初花了很多时间才发现的。如下代码段是它的源码。从源码中,不知大家有木有发现params参数的秘密:params若为空,则无法触发事件。而只有el && el.dataIndex和
el && el.eventData这两种情况下,params才不为空,事件才能正常监听。故要监听某图表元素绑定的事件,一定要满足上面两个条件,或者传递某个参数,然后根据参数在_initEvents函数内部做处理,如代码2所示,通过在el元素添加eventData属性,然后在_initEvents函数中添加代码2所示的代码,即可实现。
代码1:
echartsProto._initEvents = function () {
each(MOUSE_EVENT_NAMES, function (eveName) {
this._zr.on(eveName, function (e) {
var ecModel = this.getModel();
var el = e.target;
var params;
// no e.target when 'globalout'.
if (eveName === 'globalout') {
params = {};
}
else if (el && el.dataIndex != null) {
var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);
params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType) || {};
}
// If element has custom eventData of components
else if (el && el.eventData) {
params = zrUtil.extend({}, el.eventData);
}
if (params) {
params.event = e;
params.type = eveName;
this.trigger(eveName, params);
}
}, this);
}, this);
each(eventActionMap, function (actionType, eventType) {
this._messageCenter.on(eventType, function (event) {
this.trigger(eventType, event);
}, this);
}, this);
};
代码2:
if (eveName === 'contextmenu') {
if (el && el.eventData && el.eventData.selectMode) {
e.event.preventDefault();
e.event.stopPropagation();
params = zrUtil.extend(params, el.eventData);
} else {
params = null;
}
}
option配置项的配置
此外,我们在源码中绑定的自定义事件,要生效还需要修改两个配置项属性,一个是silent属性:当它为true的时候,会禁止所有的事件响应,为false的时候,响应事件。triggerEvent属性: 为true的 时候,响应事件。这两个配置项,silent属性每一个图表元素都具有;triggerEvent则是组件和图形元素才有。