Ashley Coolman Ashley Coolman - 5 months ago 146x
Javascript Question

Attaching drag behaviour without using data().enter() in D3 v4

I have a project with a draggable circle. In the process of upgrading from D3 v3 > v4 the drag behaviour broke. It only seems to work when the draggable element is created using

. See the simple jsfiddle example for a simplified version

Can someone explain what I'm doing wrong?

Edit 1: Github issue opened

Edit 2: Working jsfiddle as per accepted answer


[This is copied from my response to your issue.] This is the expected behavior, though perhaps it could be improved. As the documentation for drag.subject says:

The default subject is the datum of the element in the originating selection (see drag) that received the initiating input event. When dragging circle elements in SVG, the default subject is the datum of the circle being dragged…


If the subject is null or undefined, no drag gesture is started for this pointer; however, other starting touches may yet start drag gestures.

In your failing example, the datum of your circle is undefined, so it can’t initiate a drag gesture. Giving the circle a non-null datum, such as 1, fixes it.

Yet even your non-failing example isn’t ideal because the drag gesture can’t infer the x- and y-coordinates of the circle, and so when you start a drag gesture, the circle center will jump to the mouse (or touch) position, rather than maintaining the relative position of the circle and pointer. A better way of creating a single, draggable circle would be:"svg").append("circle")
    .datum({x: 4 * 30, y: 4* 30})
    .attr("r", 30)
    .attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; });

It’s possible we should change the default subject to be something else if the element’s datum is undefined… such as the element itself. That would make the drag behavior work as you expect, although the above code is a better solution in my opinion.