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. 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.
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.
The problem seems to be that d3 fires a brushend
event when the rectangle is clicked, which I'm guessing stops event propagation somewhere?
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.
Getting the event you want might be a bit hairy and require changes to the D3 source code. 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.
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.
This is a slightly improved version of Lars's answer, to handle two edge cases:
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.