D3charts 事件机制
D3charts提供事件监听和事件触发的API,基于这些API,可以完成图表的各类用户交互的监听和触发,比如监听散点图的散点点击事件、监听坐标轴的鼠标移动事件等等。
在处理事件时,需要保证已经使用D3charts绘制出了图形,即已完成如下操作:
// 自己设置一个option
var option = {
// ......略
};
// 初始化图表,声明为chart
var chart = D3Charts.init('zr');
// 设置option,进行图表初始化绘制
chart.setOption(option);
一、监听图表全局事件
1.1 监听初始化绘图结束
使用场景:在setOption之后,图表会进行异步绘制,若马上执行一些操作可能由于未绘制完成,导致对应的操作由于对象未初始化完成而报错,因此需监听图表初始化完成后再进行相应绘制,监听事件:
chart.on('VIEW_DID_RENDER', function(){
// do something
});
1.2 监听图表非初始化设置Option绘图结束
使用场景:初始化绘图完成后还需继续监听绘图结束时使用:
chart.on('VIEW_DID_RENDER_AFTER_SET_OPTION', function(){
// do something
});
二、监听图表局部事件
使用chart.registerAction即可监听图表各组成部分的用户事件,该方法包含三个参数:监听对象的Model、监听的事件名称、事件发生时的回调函数。
下面单独解释一下各个部分应该填写什么内容:
第一个参数:对象的Model
所有的事件都是发生在一个对象上的,如x轴、数据线、坐标轴指示器等,因此想要注册一个时间,首先需要说明事件的作用对象是谁,使用chart.getModel方法可以获取到这样的对象,如一张最简单的柱状图的配置中,option可能是这样的
option = {
"grid": [{ "top": "10%", "left": "10%", "right": "10%", "bottom": "10%" }],
"axis": [
{
"position": "bottom",
"$dataIndex": 0,
"dataKey": 0,
"tick": { "show": false },
"line": {
"show": true,
"style": { "stroke": "#D1D1D1", "lineWidth": 2 }
},
"label": {
"show": true,
"padding": 10,
"style": { "fill": "rgba(51, 51, 51, 0.4)", "fontSize": 12 }
}
},
{
"position": "left",
"type": "linear",
"xOrY": "y",
"splitNumber": 5,
"tick": { "show": false },
"line": {
"show": true,
"style": { "stroke": "#D1D1D1", "lineWidth": 1 }
},
"label": {
"show": true,
"padding": 10,
"style": { "fill": "rgba(51, 51, 51, 0.4)", "fontSize": 12 }
},
"axisName": {
"show": true,
"text": "销量/万件",
"offset": [0, -10],
"style": { "fill": "rgba(51, 51, 51, 0.4)", "fontSize": 12 }
},
"splitLine": {
"show": true,
"style": { "color": "#E4E4E4", "lineWidth": 1 }
}
}
],
"legend": [
{
"show": true,
"left": "80%",
"top": "5%",
"textStyle": { "color": "#485465", "fontSize": 12 },
"data": ["销量"]
}
],
"series": [
{
"type": "bar",
"$dataIndex": 0,
"dataKey": 1,
"name": "销量",
"itemStyle": { "normal": { "fill": "#2F97FF" } },
"label": {
"normal": {
"show": true,
"style": { "position": "top", "fill": "#43A1FF", "fontSize": 12 }
}
}
}
],
"data": [
{
"originData": [
["Jan", 1850],
["Feb", 900],
["Mar", 760],
["Apr", 1300],
["May", 2250],
["Jun", 1650]
]
}
],
"tooltip": [{ "style": { "backgroundColor": "rgba(57,93,129,0.6)" } }],
"axisPointer": [
{
"$axisIndex": 0,
"line": { "show": false },
"label": {
"show": true,
"style": {
"fill": "#2F97FF",
"textBackgroundColor": "rgba(255,255,255,1)",
"fontSize": 12,
"textPadding": 0
}
}
}
]
}
从配置项中,我们可以看到axis、series、legend等一级配置项,而这些内容均可以被我们的事件监听系统所监听,我们需要确认的是监听具体的哪个对象,比如监听坐标轴的第一根,即对应axis[0],转化为代码即为myChart.getModel('axis', 0),这个函数第一个参数为监听的是什么,若不填第二个参数,则会以数组形式返回所有的axis,第二个参数是下标,即返回第几个axis,由此,我们可以获得任一实体对象的model了。
第二个参数:监听的事件名称
第一个参数我们已经确认了要监听谁,第二个参数我们需要填写的是监听的这个对象的事件,在文末的“附录”中已经列出了所有对象支持监听的事件,事件名均为大写,以下划线连接,可以按照自己的需要选择合适的事件使用。
举例:如我们要监听x轴上鼠标移动,则选用事件AXIS_MOVE
第三个参数:回调函数
第三个参数为回调函数,当监听的事件发生时,会主动触发回调函数,不同的事件会有不同的参数,具体的可以通过打印arguments的方法进行查看,以AXIS_MOVE事件为例,第三个参数写function(e){console.log(e)}即可获取到鼠标事件e。
调用实例
我们以上面的柱状图为例,监听x轴鼠标移动事件
var xAxisModel = myChart.getModel('axis',0);
myChart.registerAction(xAxisModel, 'AXIS_MOVE', function(e){
console.log(e);
})
事件监听输出的内容如下,通过这个参数,我们就可以轻松获得当前鼠标移动在哪个数据上,对应的值是什么等信息:

三、主动触发事件
主动触发事件的使用场景较少,整体形势与监听事件类似,使用dispatchAction方法触发,其参数前两个与registerAction相同,第三个参数变为事件本身的参数。
场景举例:当图表无法满足业务需求的legend样式时,会选择自己使用dom实现legend,然后监听dom的点击事件,主动触发legend的点击事件,以达成可以点击dom实现原本legend支持的数据显隐操作。
var legendModel = chart.getModel('legend', 0);
// 外部调用legend
document.getElementById('btn1').onclick = function(){
chart.dispatchAction(legendModel, 'LEGEND_CLICK', {name: '销量 1'})
}
不同的事件要求不同的数据参数,理论上只要能够提供对应的事件参数,任一事件都是可以主动触发的。
附录
D3charts事件一览表
| 事件对象 | 事件名称 | 事件说明 |
|---|---|---|
| axis | AXIS_DOMAIN_CHANGED | 坐标轴范围改变 |
| AXIS_MOVE | 鼠标在坐标轴上移动 | |
| AXIS_OUT | 鼠标移出 | |
| AXIS_ZOOM_CHANGED | 坐标轴范围改变 | |
| axisPointer | AFTER_AXISPOINTER_MOVE | 指示器移动后 |
| BEFORE_AXISPOINTER_MOVE | 指示器移动前 | |
| AXISPOINTER_MOVE | 指示器移动 | |
| AXISPOINTER_OUT | 指示器移出 | |
| dataZoom | ZOOM_CHANGE | 缩放值改变 |
| ZOOM_MOVE_END | 范围移动结束 | |
| ZOOM_MOVING | 移动范围 | |
| ZOOM_MOVE_START | 范围移动开始 | |
| ZOOM_WHEEL | 滚轮缩放 | |
| legend | LEGEND_CLICK | 图例点击 |
| LEGEND_MOUSEMOVE | 图例鼠标移动 | |
| LEGEND_MOUSEOUT | 图例鼠标移出 | |
| LEGEND_MOUSEOVER | 图里鼠标移入 | |
| markLine | MARKLINE_CLICK | 点击标记线 |
| MARKLINE_MOUSEMOVE | 鼠标标记线移动 | |
| MARKLINE_MOUSEOUT | 鼠标标记线移出 | |
| MARKLINE_MOUSEOVER | 鼠标标记线移入 | |
| markPoint | MARKPOINT_CLICK | 点击标记点 |
| MARKPOINT_MOUSEMOVE | 鼠标标记点移动 | |
| MARKPOINT_MOUSEOUT | 鼠标标记点移出 | |
| MARKPOINT_MOUSEOVER | 鼠标标记点移入 | |
| series | ITEM_CLICK | 点击数据项 |
| DBL_CLICK | 双击数据项 | |
| ITEM_MOUSEMOVE | 鼠标数据项移动 | |
| ITEM_MOUSEOUT | 鼠标数据项移出 | |
| ITEM_MOUSEOVER | 鼠标数据项移入 | |
| SELECTEDLIST_CHANGE | 选中的数据项改变 | |
| radarAxis | RADAR_AXIS_MOVE | 鼠标雷达图坐标轴移动 |
| RADAR_AXIS_OUT | 鼠标雷达图坐标移出 | |
| sketch | ITEM_CLICK | 点击绘图工具 |
| title | TITLE_CLICK | 点击标题 |
| dagre | EDGE_CLICK | 点击边 |
| EDGE_MOUSEMOVE | 鼠标在边上移动 | |
| EDGE_MOUSEOUT | 鼠标移出边 | |
| EDGE_MOUSEOVER | 鼠标在边上移动 | |
| NODE_CLICK | 节点点击 | |
| NODE_MOUSEMOVE | 鼠标移入节点 | |
| NODE_MOUSEOUT | 鼠标移出节点 | |
| NODE_MOUSEOVER | 鼠标在节点上移动 | |
| dataPool | POOL_UPDATE | 数据池更新 |
| dataProvider | PROVIDER_UPDATE | dataProvider更新 |
| force | FOCUS_EDGE | 聚焦边 |
| FOCUS_NODE | 聚焦点 | |
| geo | ITEM_CLICK | 点击地图 |
| LABEL_NAME | 点击标记 | |
| ITEM_MOUSEOUT | 地图移入 | |
| ITEM_MOUSEMOVE | 地图移动 | |
| LABEL | 显示标签 | |
| geoAxis | GEO_AXIS_ITEM_CLICK | 地图坐标点击 |
| GEO_AXIS_OUT | 地图坐标移出 | |
| GEO_AXIS_OVER | 地图坐标移入 |
提升:如何获取绘图结束后的图形对象
有的时候,我们需要在绘图结束后拿到一些绘图元素的值或属性,比如拿到y轴坐标轴标签的所有数值,我们就需要操纵绘图对象的view,从而拿到我们所需要的东西。
通过getModel、getViewOfComponentModel函数配合使用,即可获取对象对应的view,从而拿到想要拿到的信息,以获取y轴标签的内容为例(获取时需保证图表已经绘制完成,可采用1.1的事件监听):
var yAxisModel = myChart.getModel('axis', 1);
var yAxixView = myChart.getViewOfComponentModel(yAxisModel);
// 通过以下代码,即可获取到所有的y轴标签内容
yAxixView.group.childAt(1).eachChild(label=>{
console.log(label.style.text);
})
注意:拿到的view为Zrender实例,具体的文档可以参考zrender官网