Implementing zoom and pan behavior

Zooming and panning are common and useful techniques in data visualization, which work particularly well with SVG based visualization since vector graphic does not suffer from pixelation as its bitmap counterpart would. Zooming is especially useful when dealing with large data set when it is impractical or impossible to visualize the entire data set, thus a zoom and drill-down approach needs to be employed. In this recipe we will explore D3's built-in support for both zooming and panning.

Getting ready

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

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

How to do it...

In this recipe we will implement geometric zooming and panning using D3 zoom support. Let's see how this is done 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)
            .call(
                d3.behavior.zoom()
                    .scaleExtent([1, 10])
                    .on("zoom", zoom)
            )
            .append("g");

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

    function zoom() {
        svg.attr("transform", "translate(" 
            + d3.event.translate 
+ ")scale(" + d3.event.scale + ")");
    }
</script>

This recipe generates the following zooming and panning effect:

How to do it...

Original

How to do it...

Zoom

How to do it...

Pan

How it works...

At this point you might be surprised to see how little code is necessary to implement this fully-functional zoom and pan effect with D3. If you have this recipe open in your browser, you will also notice zooming and panning reacts perfectly well to both mouse wheel and multi-touch gesture. Most of the heavy lifting is done by D3 library. What we have to do here is to simply define what zoom behavior is. Let's see how this is done in the code. Firstly, we need to define zoom behavior on a SVG container:

var svg = d3.select("body").append("svg")
            .attr("style", "1px solid black")
            .attr("width", width)
            .attr("height", height)
            .call( // <-A
                d3.behavior.zoom() // <-B
                    .scaleExtent([1, 10]) // <-C
                    .on("zoom", zoom) // <-D
            )
            .append("g");

As we can see on line A, a d3.behavior.zoom function was created (line B) and invoked on the svg container. d3.behavior.zoom will automatically create event listeners to handle the low-level zooming and panning gesture on the associated SVG container (in our case the svg element itself). The low-level zoom gesture will then be translated to a high-level D3 zoom event. The default event listeners support both mouse and touch events. On line C we define scaleExtent with a 2-element array [1, 10] (a range). The scale extent defines how much zoom should be allowed (in our case we allow 10X zoom). Finally, on line D we register a custom zoom event handler to handle D3 zoom events. Now, let's take a look at what job this zoom event handler performs:

function zoom() {
        svg.attr("transform", "translate(" 
            + d3.event.translate 
            + ")scale(" + d3.event.scale + ")");
}

In the zoom function we simply delegate the actual zooming and panning to SVG transformation. To further simplify this task D3 zoom event has also calculated necessary translate and scale. So all we need to do is embed them into SVG transform attribute. Here are the properties contained in a zoom event:

  • scale: A number representing the current scale
  • translate: A two-element array representing the current translation vector

At this point you might be asking what is the point of having this zoom function. Why can't D3 take care of this step for us? The reason is that D3 zoom behavior is not designed specifically for SVG, but rather designed as a general zoom behavior support mechanism. Therefore, this zoom function implements the translation of general zoom and pan events into SVG specific transformation.

There's more...

The zoom function is also capable of performing additional tasks other than simple coordinate system transformation. For example, a common technique is to load additional data when the user issues a zoom gesture, hence implementing the drill-down capability in zoom function. A well-known example is a digital map; as you increase zoom level on a map, more data and details then can be loaded and illustrated.

See also

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

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