Implementing drag behavior

Another common behavior in interactive visualization that we will cover in this chapter is drag. Drag is useful to provide capabilities in visualization allowing graphical rearrangement or even user input through force, which we will discuss in the next chapter. In this recipe we will explore how drag behavior is supported in D3.

Getting ready

Open your local copy of the following file in your web browser:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter10/drag.html.

How to do it...

Here, we will produce four circles that can be dragged using D3 drag behavior support and additionally with SVG boundary detection while dragging. Now, let's see how to implement this in code:

<script type="text/javascript">
    var width = 960, height = 500, r = 50;

    var data = [
        [width / 2 - r, height / 2 - r],
        [width / 2 - r, height / 2 + r],
        [width / 2 + r, height / 2 - r],
        [width / 2 + r, height / 2 + r]
    ];

    var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .append("g");

    var drag = d3.behavior.drag()
            .on("drag", move);

    svg.selectAll("circle")
            .data(data)
            .enter().append("circle")
            .attr("r", r)
            .attr("transform", function (d) {
                return "translate(" + d + ")";
            })
            .call(drag);

    function move(d) {
        var x = d3.event.x, 
            y = d3.event.y;

        if(inBoundaries(x, y))
            d3.select(this) 
                .attr("transform", function (d) {
                    return "translate(" + x + ", " + y + ")";
                });
    }
    
    function inBoundaries(x, y){
        return (x >= (0 + r) && x <= (width - r)) 
            && (y >= (0 + r) && y <= (height - r));
    }
</script>

This recipe generates drag behavior on the following four circles:

How to do it...

Original

How to do it...

Dragged

How it works...

As we can see, similar to D3 zoom support, drag support follows a similar pattern. The main drag capability is provided by d3.behavior.drag function (line A). D3 drag behavior automatically creates appropriate low-level event listeners to handle drag gestures on the given element then translates low-level events to high-level D3 drag events. Both mouse and touch events are supported:

var drag = d3.behavior.drag() // <-A
            .on("drag", move);

In this recipe we are interested in the drag event and it is handled by our move function. Similar to the zoom behavior, D3 drag behavior support is event driven, therefore, allowing maximum flexibility in implementation, supporting not only SVG but also the HTML5 canvas. Once defined, the behavior can be attached to any element by calling it on a given selection:

svg.selectAll("circle")
            .data(data)
            .enter().append("circle")
            .attr("r", r)
            .attr("transform", function (d) {
                return "translate(" + d + ")";
            })
            .call(drag); // <-B

Next, in the move function we simply use SVG transformation to move the dragged element to proper location (line D) based on the information conveyed by the drag event (line C):

   function move(d) {
        var x = d3.event.x, // <-C
            y = d3.event.y;

        if(inBoundaries(x, y))
            d3.select(this) 
                .attr("transform", function (d) { // <-D
                    return "translate(" + x + ", " + y + ")";
                });
}

One additional condition we check here is to calculate the SVG boundaries constraint so the user cannot drag an element outside of the SVG. This is achieved by the following check:

    function inBoundaries(x, y){
        return (x >= (0 + r) && x <= (width - r)) 
            && (y >= (0 + r) && y <= (height - r));
}

There's more...

Other than the drag event, D3 drag behavior also supports two other event types. The following list shows all supported drag event types and their attributes:

  • dragstart: Triggered when a drag gesture starts.
  • drag: Fired when the element is dragged. d3.event will contain x and y properties representing the current absolute drag coordinates of the element. It will also contain dx and dy properties representing the element's coordinates relative to its position at the beginning of the gesture.
  • dragend: Triggered when a drag gesture has finished.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset