Reputation: 1317
I have what I suspect is a rather basic question on how d3 works. I've started off with this code that works perfectly and triggers the nodeClick actions...
var nodeEnter = node.enter()
.append("g")
.attr("class", "node")
.on("click", nodeClick)
But then I changed it to use a function on click to determine whether a single or double click was used...
.on("click", function(d) {
if some logic () {
console.log("double click");
} else {
console.log("single click only");
nodeClick;
}
})
This works perfectly in terms of outputting the correct console messages, but it seems like my call to nodeClick isn't working properly while embedded within in a function (i.e. the node click behaviours aren't triggered). I tried changing to nodeClick() and nodeClick(d) but that just results in errors.
Am I missing something that could explain this behaviour? Seems very strange to me that I'm seeing 2 different behaviours to calling "nodeClick" from outside and inside a function.
Thanks for any help!
Here's the complete code in question...
dblclick_timer = false;
//.on("click", nodeClick) //works perfectly
.on("click", function(d) {
if ( dblclick_timer ) {
clearTimeout(dblclick_timer)
dblclick_timer = false
console.log("double click");
d.fixed=false;
}
else dblclick_timer = setTimeout( function(){
dblclick_timer = false
console.log("single click only");
d3.select(this).nodeClick;
}, 250)
})
After all the great feedback, here's the working solution by storing d3.event before it becomes null...
.on("click", function(d,i) {
var cacheEvent = d3.event;
if ( dblclick_timer ) {
clearTimeout(dblclick_timer)
dblclick_timer = false
console.log("double click");
d.fixed=false;
force.start();
}
else dblclick_timer = setTimeout( function(){
dblclick_timer = false
console.log("single click only");
d3.event = cacheEvent;
nodeClick.call(d3.select(this), d, i);
}, 250)
})
Upvotes: 0
Views: 1411
Reputation: 6476
As stated in the first comment, you have to establish the correct context: it's a javaScript thing, not a d3 thing. If you establish the correct this
context and pass the same parameters it will work exactly the same. The key is to use Function.prototype.call
to invoke the callback. This is standard javaScript.
.on("click", function(d, i) {
if some logic () {
console.log("double click");
} else {
console.log("single click only");
nodeClick.call(this, d, i);
}
})
As stated in the documents
The specified listener is invoked in the same manner as other operator functions, being passed the current datum d and index i, with the this context as the current DOM element.
Upvotes: 2
Reputation: 109292
As pointed out in the comments, you're not actually calling the function. In the case
.on("click", nodeClick)
the function nodeClick()
is installed as the handler for the click event. Here nodeClick
refers to the function object -- that is, the function itself, not any value it may return for a particular input.
In the second case, you're doing the same thing, except that you're passing in an anonymous (i.e. defined on the spot) function rather than a named function. In both cases, the function will be called when the event occurs.
The statement nodeClick;
on its own has no effect -- it is essentially the same as saying 1;
or foo;
where foo
is a variable or function defined elsewhere.
To make this work, you need to call the function -- add ()
after the name. In addition, you need to pass any arguments the callback has received -- nodeClick(d)
. You also need to call it with the same this
context as the implementation of the function relies on it. All of this is done for you if you use selection.each()
:
d3.select(this).each(nodeClick);
Upvotes: 1