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官网