简体   繁体   English

将事件侦听器添加到d3画笔

[英]Adding an event listener to a d3 brush

I'm trying to figure out how to make the rectangle created by a d3 brush (the events rectangle, in particular), respond to a click event. 我试图弄清楚如何制作由d3画笔创建的矩形(特别是事件矩形),响应点击事件。 Eventually, I'd like to have a single click on this object bring up a menu, but I can't seem to get the rect element to catch the event. 最后,我想在这个对象上单击一下菜单,但我似乎无法获取rect元素来捕获事件。

I've tried the following code: 我试过以下代码:

var selector = d3.svg.brush();

var x = d3.scale.linear()
    .range([0,500])
    .domain([0,500]);

var y = d3.scale.linear()
    .range([0,500])
    .domain([0,500]);

d3.select('#myDiv')
    .append('svg')
    .attr('id','mySVG')
    .attr('height',500)
    .attr('width',500)
    .call(selector.x(x).y(y).on('brushend',bindSelect))

function bindSelect(){
    d3.select('#mySVG rect.extent')
        .on('click',function(){alert('hi mom!')})
}

bindSelect seems to fire just fine, and successfully select the .extent rectangle, but I'm not getting any response on clicking the rectangle. bindSelect似乎很好,并成功选择.extent矩形,但我没有得到任何响应单击矩形。

The problem seems to be that d3 fires a brushend event when the rectangle is clicked, which I'm guessing stops event propagation somewhere? 问题似乎是,当点击矩形时,d3会触发brushend事件,我猜这会阻止事件在某处传播?

Does anyone know how to get around this? 有谁知道怎么解决这个问题? My only thought is to create another rect on top of the extents rect on the brushend event, and then use that one to handle click behavior, but it seems like a messy way of doing things. 我唯一的想法是在brushend事件上的extents rect上创建另一个rect,然后使用那个来处理点击行为,但这似乎是一种混乱的做事方式。

Also, here is a fiddle of the code. 此外, 这里是代码的小提琴。

Getting the event you want might be a bit hairy and require changes to the D3 source code. 获得您想要的活动可能有点毛茸茸,需要更改D3源代码。 However, you can use the brushend event together with the methods provided for the brush to figure out whether somebody has clicked on the brush rectangle. 但是,您可以将brushend事件与为画笔提供的方法一起使用,以确定是否有人单击了画笔矩形。

var extent = selector.extent();

function bindSelect(){
  if(!selector.empty() && !(extent < selector.extent() || extent > selector.extent())) {
    console.log("foo");
  }
  extent = selector.extent();
}

The idea is that if the selection is not empty and the selected extent is the same as it was at the last brushend event, then the user clicked on the selection instead of manipulating it. 我们的想法是,如果选择不为空且所选范围与上次brushend事件相同,则用户单击选择而不是操纵它。

This is a slightly improved version of Lars's answer, to handle two edge cases: 这是Lars答案的略微改进版本,用于处理两个边缘情况:

  1. If you drag the brush and return it to it's exact original position, this will trigger the event. 如果拖动画笔并将其返回到其原始位置,则会触发该事件。
  2. If you drag the brush past the end of the container, the brush will not move while your cursor does, also triggering the event. 如果将画笔拖过容器的末端,则在光标移动时画笔不会移动,也会触发事件。

First, set up your brush like this: 首先,像这样设置你的画笔:

selector.x(x).y(y).on('brushstart', saveCursorPos)
                  .on('brushend',   checkIfMoved))

Then, 然后,

var clickPos = [-1,-1];

function saveCursorPos() {
    var e = d3.event.sourceEvent;
    clickPos = [e.clientX,e.clientY];
}

function checkIfMoved() {
    var e = d3.event.sourceEvent;
    if(!selector.empty() && clickPos[0] === e.clientX && clickPos[1] === e.clientY) {
        alert("foo");
    }
}

The idea being to save the mouse position as opposed to the brush extent when you start dragging, and check if that has changed when the button is released. 当您开始拖动时,想法是保存鼠标位置而不是画笔范围,并在释放按钮时检查是否已更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM