Dispatching drag-end event
Asked Answered
T

1

6

I want to programmatically fire the "end" event of d3-drag. I have some circles and have the drag-handling of them implemented like so:

...
.call(d3.drag()
     .on("drag", function () {...})
     .on("end", function () {...})
)

Now, later in my code, I would like to trigger the "end" part of this programmatically.

I have already tried something like this:

d3.select("#myID").dispatch("end");
d3.select("#myID").dispatch("dragend");
d3.select("#myID").call(d3.drag().dispatch("end"));
Thermography answered 29/10, 2020 at 14:48 Comment(2)
Do you need to pass any specific event information to the function, or does it just need to run on a specified selection?Overlook
The function runs on the selection of those circles and uses "this" to reference the dragged circle and the data/position of the circleThermography
O
2

If you don't need to generate any actual event data, and I understand the question correctly, you can do this relatively easily without d3.dispatch directly. The below will give you this and the node data itself (in d3v5 it will also give you i and nodes).

D3v5 and earlier

In d3v5 and earlier, the signatures for a function passed to selection.each() and drag.on() were the same. In this case you can easily assign the function to a variable and pass it to both. Alternatively, you could access the drag event function with drag.on("typeName").

Here's a quick example:

var svg = d3.select("body")
  .append("svg")
  .attr("width",500)
  .attr("height",300);
  
var data = [{x:40,y:100},{x:250,y:100}];

var circles = svg.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("r", 10)
  .attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; })
  .attr("fill", function(d,i) {
    return ["steelblue","crimson"][i]
  })

var drag = d3.drag()
  .on("drag", function(d) {
    d.x = d3.event.x; d.y = d3.event.y;
    d3.select(this)
      .attr("cx", d.x)
      .attr("cy", d.y);
  })
  .on("end", function(d) {
     console.log(d.x+","+d.y);
     d3.select(this)
       .transition()
       .attr("r", 30)
       .transition()
       .attr("r", 10);
  })
  
circles.call(drag);

d3.select("button").on("click", function() {
  var circle = d3.select("circle")
    .each(drag.on("end"));
})
circle {
   cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<button>Trigger Drag End On Blue Circle</button>

D3v6

In d3v6 the signatures of functions passed to selection.each() and drag.on() are different. The datum is the first parameter of the former and the second parameter of the latter. So we could use Function.apply() within selection.each() to trigger the end function and pass the proper this and d while passing null for the event data.

var svg = d3.select("body")
  .append("svg")
  .attr("width",500)
  .attr("height",300);
  
var data = [{x:40,y:100},{x:250,y:100}];

var circles = svg.selectAll(null)
  .data(data)
  .enter()
  .append("circle")
  .attr("r", 10)
  .attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; })
  .attr("fill", function(d,i) {
    return ["steelblue","crimson"][i]
  })

var drag = d3.drag()
  .on("drag", drag)
  .on("end", dragend)

circles.call(drag);

d3.select("button").on("click", function() {
   var circle = d3.select("circle")
    .each(function(d) { 
       dragend.apply(this,[null,d]) 
    })
})


function dragend(event,d) {
  console.log(d.x+","+d.y);
  d3.select(this)
    .transition()
    .attr("r", 30)
    .transition()
    .attr("r", 10);
}
function drag(event,d) {
  d.x = event.x; d.y = event.y;
  d3.select(this)
    .attr("cx", d.x)
    .attr("cy", d.y);
}
circle {
   cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.0.0/d3.min.js"></script>
<button>Trigger Drag End On Blue Circle</button>
Overlook answered 29/10, 2020 at 22:53 Comment(1)
And what if I need to access event data? I tried all possible solutions mentioned here and in other posts, but with no luck :-/ My selection calls select(#element).call(drag.drag()..) on which event handlers are registered, so seems like that is an obstacle while dispatchingTidewater

© 2022 - 2024 — McMap. All rights reserved.