9

I have a d3 selection upon which I have defined event callbacks.

var obj = d3.select("#kk").on("mouseleave",function(){
              console.log("mouse leave");       
          });

How can I trigger the event externally? Is there something like:

obj.mouseleave(); // actuall mouse leave function calling

If there is, and if I select the object without referring to obj, will the trigger still work?

As in:

var newObje=d3.select("#kk");
newObje.mouseleave(); //will this trigger the previously defined instructions
Jigar7521
  • 1,549
  • 14
  • 27
S.Dan
  • 1,826
  • 5
  • 28
  • 55

4 Answers4

15

If you are already on D3 v4, you can use selection.dispatch() which was specifically designed to do exactly what you are looking for:

# selection.dispatch(type[, parameters]) <>

Dispatches a custom event of the specified type to each selected element, in order.

This was included in v4 as a result of the issue "Ability to trigger event handlers manually. #100".

Furthermore, the method will enable you to dispatch events of the same type to all elements contained in the selection. The implementation of that method looks similar to the approach the other answerers took by putting event.dispatch() to use, but will make your life somewhat easier. The following snippet has a listener for each individual circle, which may all be triggered by the button at once.

var circles = d3.select("svg").selectAll("circle")
  .data(d3.range(5))
  .enter().append("circle")
    .attr("cx", function(d, i) { return 60 * i + 20; })
    .attr("cy", "30")
    .attr("r", "20").attr("fill", "blue")
    .on("mouseleave",function(){
      d3.select(this)
        .attr("fill", "red")
        .transition().duration(1000)
        .attr("fill", "blue");
    });

d3.select("#btn")
  .on("click", function() {
    circles.dispatch("mouseleave");
  });
<script src="https://d3js.org/d3.v4.js"></script>
<svg width="400" height="70"></svg>

<button id="btn">Dispatch mouseleave to all circles</button>
Community
  • 1
  • 1
altocumulus
  • 21,179
  • 13
  • 61
  • 84
  • I wanted to use selection.dispatch to trigger drag events but did not manage to do so. Also see https://stackoverflow.com/questions/60847359/how-to-programmatically-trigger-drag-events-with-d3-js – Stefan Mar 25 '20 at 11:51
  • Same here, Stefan - did you maybe find a way to fix it? I can trigger all events whose handlers are not defined inside the call() function, but since drag is called inside call(), that seems to be the issue :-/ – borgmater Oct 26 '22 at 06:17
9

Yes, you don't need d3 to trigger the event, vanilla javascript is enough for that. You simply need to use the dispatchEvent function.

Here is an example of how you would do it (from a button for example).

I added both the d3.select way and the plain JS way, both should work fine.

d3.select("#kk").on("mouseleave",function(){
  console.log("mouseleave");
});

var button = document.getElementById('trigger-event');
button.onclick = function() {
  var evt = new MouseEvent("mouseleave");
  
  // The way to dispatch the event using d3
  d3.select('#kk').node().dispatchEvent(evt);
  
  // The way to dispatch it with plain JS
  document.getElementById('kk').dispatchEvent(evt);
};
#kk {
  width:100px;
  height:100px;
  background-color:blue;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="kk">
  
</div>


<button id="trigger-event">trigger event</button>
Hugo Migneron
  • 4,867
  • 1
  • 32
  • 52
4

The following will trigger the mouseleave event on the elements via dispatchEvent().

  var event = document.createEvent('Event');
  event.initEvent('mouseleave', true, true);

  d3.selectAll("circle").node().dispatchEvent(event);

Example: http://codepen.io/anon/pen/eBYvVN (I've added a button at the bottom to trigger it. The mouseleave event is attached to the circles)

K Scandrett
  • 16,390
  • 4
  • 40
  • 65
1

You can make one constant function for mouseleave and call it on mouse leave or externally as well like this :

function mouseleave(){            // Main mouse leave function.
     console.log('inside mouseleave function.');    
}



var obj = d3.select("#kk").on("mouseleave",function(){ // It will call on actual mouse leave event
                  console.log("mouseleave");
                  mouseleave();
              });

    mouseleave(); // call it externally when ever you want.
Jigar7521
  • 1,549
  • 14
  • 27
  • My application has a complex structure of backbone models and the callback function is actually stored in a nested collection and the trigger is made by a totally different one and I don't wish to make a global function. – S.Dan Nov 04 '16 at 04:46