4

I am using d3's drag behavior on an svg element that might need to be dropped outside of the visible area. I have it setup within two divs with overflow set to auto to enable scrolling. I have this only working with some browsers but not all.

The issue is that in some browsers, you will be able to scroll while dragging, but in others the window will not scroll while dragging. I have as of yet been unable to find a way to make this work consistently.

for a working example see the fiddle: http://jsfiddle.net/glanotte/qd5Td/1/

This is working as expected on:

chrome - mac/windows safari - mac

But not working on

Firefox - mac/windows IE - windows

html:

<div id="outerFrame">
    <div id="innerFrame">
        <svg width="600" height="600">
        </svg>
    </div>
</div>

css:

#outerFrame{
    width: 300px;
    height: 300px;
    border: 1px solid red;
    overflow: auto;
}

#innerFrame{
    width: 600px;
    height: 600px;
    background-color: lightgrey;
}

javascript:

var drag = d3.behavior.drag()
    .on("dragstart", dragstart)
    .on("drag", dragmove)
    .on("dragend", dragend);

function dragstart() {
  d3.select(this).style("border", "1px solid red");
}

function dragmove(d) {
    var coordinates = d3.mouse(d3.select("svg").node());
    d3.select(this).attr({
        x: coordinates[0] - 50,
        y: coordinates[1] - 25
    })

}

function dragend() {
  d3.select(this).style("border", null);
}

d3.select("svg")
    .append("rect")
    .attr({x: 100, y: 100, width: 100, height: 50})
    .call(drag);
Geoff Lanotte
  • 7,490
  • 1
  • 38
  • 50

1 Answers1

4

You have unfortunately struck upon a bug in Firefox which has been noticed before by mbostock and marked as WONT-FIX.

As per suggestion in the bug report, you can make it work, but only by scrolling the container manually: http://jsfiddle.net/62CYD/

The implementation is pretty simple and can be improved by:

  1. Using animations
  2. Taking into account width of scroll bars, like done in DOMUtilityService in ng-grid.
  3. Taking current mouse position into account to avoid snapping of the dragged item and smoother scrolling.
  4. Use setTimeout to continue scrolling even if dragging stops
function dragmove(d) {
    var svg = d3.select("svg").node(),
        $parent = $('#outerFrame'),
        w = $parent.width(), h = $parent.height(),
        sL = $parent.scrollLeft(), sT = $parent.scrollTop();

    var coordinates = d3.mouse(svg),
        x = coordinates[0],
        y = coordinates[1];

    if (x > w + sL) {
        $parent.scrollLeft(x - w);  
    } else if (x < sL) {
        $parent.scrollLeft(x);
    }

    if (y > h + sT) {
        $parent.scrollTop(y - h);
    } else if (y < sT) {
        $parent.scrollTop(y);
    }

    d3.select(this).attr({
        x: x - 50,
        y: y - 25
    })
}
Community
  • 1
  • 1
musically_ut
  • 34,028
  • 8
  • 94
  • 106
  • Thank you, I was hoping that it was just some simple setting that I was missing. But I like your work around. I will work on implementing this and update at that time. – Geoff Lanotte Nov 02 '13 at 00:46