简体   繁体   中英

calling functions from within functions in d3

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 (ie 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)
                        })

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.

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 (ie 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);

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.

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