【问题标题】:Fine-grained event handling with D3 brushes使用 D3 画笔进行细粒度事件处理
【发布时间】:2013-02-04 23:12:36
【问题描述】:

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

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

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

【问题讨论】:

    标签: javascript events svg d3.js


    【解决方案1】:

    这可以通过use of the D3 brush API 来完成(见下面的注释)。

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

    1. brush 元素圆圈的后面
    2. 圈子响应mousedown 事件。 (也可以响应其他事件。)
    3. brush 元素表现良好,即使从其中一个圆圈内开始拖动也是如此。

    一些跟踪和查看D3 source code 表明,当从画笔顶部的circle 元素触发mousemove 事件时,extent 未正确重置。这可以通过在mousedown 侦听器中为circle 元素重置画笔的extent 来解决:

            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 是图表上可见的选择的情况下编写的代码。

    【讨论】:

    • 这非常接近。理想情况下,我希望能够在创建画笔后拖动它,即使我从一个圆圈开始,但它现在的工作方式是一个巨大的进步!
    • 确实,我发现从<circle> 内部拖动选择仍然是不可能的。我会考虑如何干净地做到这一点,尽管我怀疑做一个干净的事件传递会涉及 d3 的补丁。
    【解决方案2】:

    使用@987654321@http://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"]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      • 1970-01-01
      • 2021-12-23
      • 1970-01-01
      • 1970-01-01
      • 2018-10-01
      • 1970-01-01
      相关资源
      最近更新 更多