Question

The d3.js source in /src/layout/force.js has an early return if you customize force layout dragging:

  force.drag = function() {
    if (!drag) drag = d3.behavior.drag()
        .origin(d3_identity)
        .on("dragstart.force", d3_layout_forceDragstart)
        .on("drag.force", dragmove)
        .on("dragend.force", d3_layout_forceDragend);

    if (!arguments.length) return drag;

    this.on("mouseover.force", d3_layout_forceMouseover)
        .on("mouseout.force", d3_layout_forceMouseout)
        .call(drag);

  };

It will skip the sticky hover code when the simulation is running. You can see it on this demo http://bl.ocks.org/mbostock/3750558. When you get the simulation to move around a lot and try to stop a node by hovering over it, they no longer stop.

I have a work around that I am using like so:

force.drag()
   .on('dragstart', function(d) {
      //...
   })
   .on('dragend', function(d) {
      //...
   }) ;

//...

node.call(force.drag);

This code will call the early return version of force.drag first so you can listen for events, then call the default version to get the extra mouse behavior. The second call skips the drag events section because it was already registered, which is unexpectedly good for this case.

Here is the code I would like to use, but you will lose the sticky nodes on hover functionality:

var drag = force.drag()
   .on('dragstart', function(d) {
      //...
   })
   .on('dragend', function(d) {
      //...
   }) ;

//...

node.call(drag);

The reason I didn't just use my own d3.behavior.drag is because I wanted to use as much of the force layout's d.fixed handling as possible.

Does anyone know why the code has an early return when you want to customize the dragging? My workaround is very fragile for future force drag changes. Unfortunately moving the return to the bottom might break some people's simulations.

Was it helpful?

Solution

The latter part of the force.drag function attaches the drag behaviour to a set of elements by establishing the listeners. When you call it without any arguments, this wouldn't be a selection and the code wouldn't do what you intended (and quite likely give you an error). Therefore, it checks that and returns if there's nothing to attach listeners to.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top