javascriptd3.jssnapping

d3 force layout snap to grid on drag


How do you snap to a grid after dragging is finished in d3?

I tried adding an event listener to the dragend event and rounding the values, but it doesn't seem to work:

force.drag()
    .on('dragend', function(d) {
        d.fixed = false;
        d.x = Math.round(d.x / 10) * 10;
        d.y = Math.round(d.y / 10) * 10;
    });

http://jsfiddle.net/zc89zj9e/


Solution

  • There're 2 issues with your jsfiddle. First, the nodes become undraggable once they have been dragged -- this is because you set d.fixed = true on dragend. This prevents any further position changes. The solution is to set d.fixed = false on dragstart.

    Second, in addition to d.x and d.y, you need to set d.px and d.py (which the force layout uses internally) for the position change to take effect.

    function dragstarted(d) {
      // ...
      d.fixed = false;
    }
    
    function dragended(d) {
      d.fixed = true;
      d.x = d.px = Math.round(d.x / 100) * 100;
      d.y = d.py = Math.round(d.y / 100) * 100;
    }
    

    Complete demo here.