Sudarshan Tanwar
Sudarshan Tanwar

Reputation: 3607

Possible d3 Bug: dragend fires without any drag event

I am using d3js drag behavior. here is demo. When I click on element the 'drag' and 'dragend' event fired. Even though I do not try to drag them, still the event fires. I want to call some other function on click of item.And drag event should be fired only when I drag item. So how to separate out drag event and click event here.

function onDragDrop(dragHandler, dropHandler) {
    var drag = d3.behavior.drag();

drag.on("drag", dragHandler)
.on("dragend", dropHandler);
return drag;
}

  var d = [{ x: 20, y: 20 }];

    var g = d3.select("body").select("svg").data(d).append("g").attr("transform", function (d) { return        "translate(" + d.x + "," + d.y + ")"; })
     .call(onDragDrop(dragmove, dropHandler));

g.append("rect")
.attr("width", 40)
.attr("height", 40)
.attr("stroke", "red")
.attr("fill","transparent")
.attr("x", "20" )
.attr("y", "20")

g.append("text")
.text("Any Text")
.attr("x", "20" )
.attr("y", "20")

function dropHandler(d) {
    alert('dropped');
}

function dragmove(d) {
  alert('dragged');
  d.x += d3.event.dx;
  d.y += d3.event.dy;
  d3.select(this).attr("transform", "translate(" + d.x + "," + d.y + ")");
 }

Upvotes: 3

Views: 1144

Answers (2)

Sudarshan Tanwar
Sudarshan Tanwar

Reputation: 3607

As i did'nt get expected answer, so i am giving an alternate to acheive this. Hope somebody has some answer for it. and thanks again @jonah. if you find any update in this regard just let me know. Here is Alternate way to do this.

  var d = [{ x: 20, y: 20 }];
  var flag = false;

  var g = d3.select("svg").data(d).append("rect")
    .attr("width", 40)
    .attr("height", 40)
    .attr("stroke", "red")
    .attr("fill","transparent")
    .attr("x", "20" )
    .attr("y", "20")
    .on("click", function(){ console.log('clicked');})
   .call(d3.behavior.drag().on("drag", dragHandler).on("dragend", dropHandler))

 function dropHandler(d) {
       if(flag){
            console.log('dropped');
            flag = false;
        }}

 function dragHandler(d) {
        flag = true;
        console.log('dragged');
        d.x += d3.event.dx;
        d.y += d3.event.dy;
        d3.select(this).attr("transform", "translate(" + d.x + "," + d.y + ")");
    }

Upvotes: 1

Jonah
Jonah

Reputation: 16242

EDIT 3

This is in response to your alternate answer post. The fiddle you posted there does not accurately reflect the solution I was trying to describe. I updated it. The fiddle below should be an example of the correct way to differentiate click and "true" dragend events. Note that we are not using a "click" handler.

http://jsfiddle.net/V92CF/

EDIT 2

Ok, I posted this question on the d3 google group and got an answer from Jason Davies. The behavior we're seeing is the intended behavior, it's not a bug. A "click" is simply considered a trival (0 pixels moved) drag, but it is still a drag. Mike, the creator of d3, explains the reasoning here:

https://github.com/mbostock/d3/pull/368

Hence the correct solution to your problem is the one I described as a hack before: You need to detect if a movement has actually been made inside your dragend handler, and then only trigger your logic if it has.

EDIT

Please note my original answer below is wrong. I had misunderstood the problem. The comments below and my edit to the OP should clarify

Original Post Below

The only problem here is using alert. I changed all the alerts to console.logs and it works fine:

http://jsfiddle.net/TrWw3/

I think it's getting confused with the alerts because as soon as you start dragging, it fires the alert box, which requires you to close it. But then by the time you've closed it the mouse has jumped, and something about the process is messing things up.

Anyway, console.log with chrome or firefox js console open will fix you up nice.

Upvotes: 2

Related Questions