13

I have a (rather simple) question: How to "un-call" force.drag on a selection made by D3.js? Let's say I created a set of elements and called "call" on it, giving it the drag-callback of a force-directed layout. That looked like this:

    d3.selectAll('rect').call(force.drag);

Now it shall be possible to remove that behavior from some of the nodes later on. My approaches included resetting various listeners, such as 'click', 'drag' etc. using

    d3.select('rect#no-drag').on('click', null);

None of them worked. Does anybody know how to remove the callback?

VividD
  • 10,456
  • 6
  • 64
  • 111
user654123
  • 465
  • 6
  • 19

3 Answers3

24

You are close. The drag event is initiated by a mousedown event with a namespace called drag. See: https://github.com/mbostock/d3/blob/master/src/behavior/drag.js#L5

So, to remove this you could do:

d3.select('rect#no-drag').on('mousedown.drag', null);
nautat
  • 5,193
  • 32
  • 22
  • That perfectly solves it, I just tried it and it works :) Are events namespaced by default in D3.js? – user654123 Oct 30 '12 at 13:47
  • Yes. Also if you add your own event listeners it can makes sense to namespace them. They make it possible to use multiple listeners listening to the same event. – nautat Oct 30 '12 at 14:00
  • Ok, I was already familiar with namespaced events from jQuery plug-in development. Seems that D3.js lets you only register a single callback for each qualified event, thus it makes sense to namespace them. Thanks again. – user654123 Oct 30 '12 at 14:38
  • 1
    Any idea how to re enable the drag behaviour? After calling `d3.select('rect#no-drag').on('mousedown.drag', null)`, calling `d3.select('rect#no-drag').call(force.drag)` doesn't bring it back – kdbanman Jul 31 '14 at 00:56
  • Sorry, saved too early above. It's a bit hacky and YMMV, but one way to restore the drag behavior after using the above solution is to first grab a reference to d3's drag callback: `var dragCallback = d3.select('rect#no-drag').property('__onmousedown.drag')['_'];` and then restoring it later: `d3.selectAll('rect#no-drag').on('mousedown.drag', dragCallback);` – Jonathan Guerrera Apr 18 '15 at 18:29
  • Updates in d3v4+ ? – Alex Lenail Nov 21 '18 at 14:35
4

This question isn't asking how to have fine grained control on the drag element, but I came here looking for how to toggle the drag on/off based on conditions, and the asker also asked how to get the drag back after removing it in the comments.

Thus, for anyone looking for how to conditionally allow the drag event, use drag.filter.

drag.filter takes a callback that needs to return a boolean. If the callback returns true, the drag happens, otherwise the drag doesn't trigger.

This is much cleaner than removing the drag from the selection and then trying to re-apply it.

YouCodeThings
  • 590
  • 3
  • 13
1

This line somehow it's not mobile compatible (chrome/android)

d3.select('rect#no-drag').on('mousedown.drag', null);
alfredopacino
  • 2,979
  • 9
  • 42
  • 68