使用D3画笔处理细粒度事件

时间:2013-02-04 23:12:37

标签: javascript events svg d3.js

我有一个使用D3生成的散点图。可以通过单击选择图上的点(SVG圆),并使用D3画笔选择区域。

为确保圈子获得点击事件,我需要先创建画笔,以便圈子位于其上方。不幸的是,这意味着当光标位于绘图中的某个点上时,我无法拖动以创建画笔范围。

有没有办法将悬停和点击事件传递给圈子,但是用画笔处理与拖动相关的事件?

2 个答案:

答案 0 :(得分:14)

可以用use of the D3 brush API完成(见下面的注释)。

这是一个示例http://bl.ocks.org/4747894,其中:

  1. brush元素圈子
  2. 之后
  3. 圈子响应mousedown事件。 (也可以回应其他事件。)
  4. 即使从其中一个圈内开始拖动,brush元素仍然表现良好。
  5. D3 source code进行一些跟踪和查看表明,当从画笔顶部的extent元素触发mousemove事件时,circle未正确重置。可以通过在extent元素的mousedown侦听器中重置画笔的circle来解决此问题:

            circles.on("mousedown", function (d, i) {
                // _svg_ is the node on which the brush has been created
                // x is the x-scale, y is the y-scale
                var xy = d3.mouse(svg.node()),
                    xInv = x.invert(xy[0]),
                    yInv = y.invert(xy[1]);
    
                // Reset brush's extent
                brush.extent([[xInv, yInv], [xInv, yInv]]);
    
                // Do other stuff which we wanted to do in this listener
            });
    

    注意: As per the API,在调用.extent(values)时,画笔的选择将不会自动刷新。只需点击一个圆圈即可重置extent,但不会重新绘制所做的选择。只有在circle内开始不同的选择时,或者通过点击圆圈和当前选择之外,才会丢弃选择。 正如我从问题中理解的那样,这是理想的行为。但是,这可能会破坏编写的代码,假设刷子的extent是图形上可见的选择。

答案 1 :(得分:5)

使用selection.onhttp://jsfiddle.net/NH6zD/1

var target,
    dimensions = {width: 200, height: 200},
    svg = d3.select("body").append("svg").attr(dimensions),
    rect = svg.append("rect").attr(dimensions); // Must be beneath circles 
svg
  .on("mousedown", function() {
      target = d3.event.target || d3.event.srcElement;
      if ( target === rect.node() ) {
          /* Brush */
      } else {
          /* Circle */
      }
  })
  .on("mousemove", function() {
      if (!target) return;
      if ( target === svg.rect() ) {
          /* Brush */
      } else {
          var mouse = d3.mouse(svg.node());
          target.attr({x: mouse[0], y: mouse[1]});
      }
  });
(function(exit) {
    for (var i in exit) svg.on(exit[i], function() { target = undefined; });
})(["mouseout", "mouseup"]);