D3 Zoom Behavior Part Two
FREE     Duration: 17:51
Part of Course: Intermediate D3 Course
 

Takeaways:

  • The D3 Zoom Behavior, d3.behavior.zoom(), constructs a zoom behavior that creates an even listener to handle zoom gestures (mouse and touch) on the SVG elements you apply the zoom behavior onto
  • The D3 Zoom Behavior Zooming behavior is made up of being able to zoom in and out
  • The D3 Zoom Behavior Panning behavior is made up of being able to pan along the X and Y axis, like a camera panning across an image - everything stays the same distance to everything else, it's just that all of the elements move together
  • The reason D3 Zoom Behavior contains the Zoom & Pan behavior is for specific point zooming - that is, when you zoom in on a specific point, not only do you need to zoom in, you also need to move the camera so that the point you zoomed in is still in the picture (same thing with zoom out)
  • The D3 Zoom Behavior listens to one specific event named the "zoom" event, which means you only have to write one function to encapsulate the D3 Zoom Behavior
  • The D3 Zoom Behavior, d3.behavior.zoom(), provides two different properties within the d3.event object: d3.event.scale and d3.event.translate
  • The d3.event.scale will provide the current zoom scale, and if the zoom behavior was defined with a scaleExtent, then this will be limited by the scale extent
  • The d3.event.translate will provide a two-element JavaScript array that represents the current X coordinate and Y coordinate translations (the first array element is the X coordinate and the second array element is the Y coordinate)
  • There are two main ways to resize things within the zoom event listener function: either through the SVG Transform Scale attribute or through doing the actual math of using the d3.event.scale to recalculate the size of the SVG objects you've drawn on the screen

Transcript:

D3 Zoom Behavior Part Two

D3 Translate


The Panning behavior allows us to pan along the X and Y axis.

// Zoom Pan Behavior

You can think of panning behavior as moving the camera across the image.

That is, everything stays the same distance from everything else, it's just that the images move together.


Rather than thinking about it like we are dragging one element around, think about it like we are dragging the whole coordinate space around.

// Pan not Drag

Everything remains in the exact location relative to everything else, it's just that the element moves around according to how it is being panned.


We have access to the Pan behavior regardless of whether we have zoomed in, zoomed out or done nothing at all.

// Pan on Zoom

// Pan on no Zoom

This means that we can pan the coordinate system without doing any zooming.

All we have to do is click down on an element and then drag it and the whole coordinate system will pan with the mouse.

The pan is done in the x, y coordinate SVG space.

Horizontal is the x space.

Vertical is the y scape.

Let's take a look at the example on the screen.


Run the source code for this video, but take out anything related to the drawing/creating/redrawing of the circle - so leave in code related to D3 event scale and leave in code related to translate.

// Variables
var svgWidth  = 400,
    svgHeight = 400,    
    originalCircle = {"cx": 100, "cy": 100, "radius": 20},
    margin = {"top": 25, "right": 25, "bottom": 50, "left": 50},
    width  = svgWidth - margin.left - margin.right,       
    height = svgHeight - margin.top  - margin.bottom;

// SVG Viewport
var svgViewport = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .style("border", "2px solid")

// Scales
var xAxisScale = d3.scale.linear()
    .domain([0, width])
    .range([0, width]);

var yAxisScale = d3.scale.linear()
    .domain([0, height])
    .range([height, 0]);

// Axis Functions
var xAxis = d3.svg.axis()
    .scale(xAxisScale)
    .orient("bottom")
    .ticks(5);

var yAxis = d3.svg.axis()
    .scale(yAxisScale)
    .orient("left")
    .ticks(5);

// Zoom Function
var zoom = d3.behavior.zoom()
    .x(xAxisScale)
    .y(yAxisScale)
    .on("zoom", zoomFunction);

// Inner Drawing Space
var innerSpace = svgViewport.append("g")
    .attr("class", "inner_space")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);

// Draw Axis
innerSpace.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

innerSpace.append("g")
    .attr("class", "y axis")
    .call(yAxis);

// HTML Printout To Tell Us What Is Going ON
d3.select("body").append("div").attr("id", "v_scale").text("D3 Zoom Scale: ");
d3.select("#v_scale").append("span").attr("id", "v_scale_val");

// Zoom Function Event Listener
function zoomFunction() {
  
    // Pan Vector
    var panVector = d3.event.translate;
    var panX = panVector[0];
    var panY = panVector[1];

    // Scaling Multiplier
    var scaleMultiplier = d3.event.scale;

    // Tell us in HTML what is going on
    d3.select("#v_scale_val").text(scaleMultiplier);

    // Redraw the Axis
    innerSpace.select(".x.axis").call(xAxis);
    innerSpace.select(".y.axis").call(yAxis);
    
}


This web page has the D3 library imported from the d3js.org website.

We have recreated the example without the circle in the middle.

We have added HTML that tells us the Zoom scale we are currently at as well as the pan x and y coordinate translations we are seeing.


Let's start by clicking on the x axis and moving it to the right.

BROWSER: click on X axis 100 and move it to the right until it hits the end and then leave it there.

You can see that I panned the chart so that the 100 x axis point is now at the far right end of the x axis.

The Pan X translate tells us how many pixels we moved to the right.


We can move it back to the left as well.

BROWSER: click on X Axis 100 and move it to the left until it hits the origin and then leave it there.

You can see that I panned the chart so that the 100 x axis point is now at what far left end of the x axis.

The Pan X translate tells us how many pixels we moved to the left.

In this case, we moved 100 pixels.


We can also do this for the Y Axis and move it towards the top of the computer screen.

BROWSER: click on Y Axis 100 and move it to the top of the screen until it hits the end and then leave it there.

You can see that I panned the chart so that the 100 y axis point is now at the top of the y axis.

The Pan Y translate tells us how many pixels we moved up.

Did you notice that this is a negative number?

This is because the SVG Coordinate space is inverted along the Y Axis.


Let's move the Y axis back down.

BROWSER: click on Y Axis 100 and move it to the bottom of the screen until it hits the end and then leave it there.

You can see that as we move it down the Pan Y Translate number gets bigger in the positive direction.


We can also do a combo move where we can move in both the X and Y directions at the same time.

BROWSER: click on the X 100 and move it 45 degrees north east. Then move it in a circle.

You can see that the pan is able to update the X and Y numbers at the same time.


Lastly, let's zoom in by a factor of 2 by double clicking and then try the pan.

BROWSER double click and then do the pan.

You can see that the pan is able to update the X and Y numbers at the same time as we are zoomed in by a factor of 2.

Note that the X and Y translate still use the number of pixels across the drawing space.


So far we have covered zooming in and out as well as being able to pan and what that means in X and Y coordinate translations.


The next step in understanding the d3 zoom behavior is to explore the actual zoom event and how it works.



D3 Zoom Event Listener


Thus far we have covered how to construct a new zoom behavior that allows us to zoom and pan.

var zoom = d3.behavior.zoom()

// zoom.on(type, listener)

What we have not covered is how to register the event listener that listens for a zoom event as well as what is available to us within the listener function.


The drag behavior has three different types of events that are supported - the drag start, drag and drag end.

// drag
// => "dragstart"
// => "drag"
// => "dragend"

// zoom => "zoom"

Currently, the zoom behavior has only one type of event that is supported - the zoom event.

This simplifies our life as we only have to write one function to listen to and react to this event.


When the zoom event is fired, the listener function will be called.

zoom.on(type, function(...) {
    d3.event.scale
    d3.event.translate
})

Within this function, D3 provides for us two different properties within the d3 dot event object.

These properties are the ones we have been talking about.

First is the zoom scale.

Second is the translate vector.

The translate vector is a vector because it has to carry information about the X coordinate translation and the Y coordinate translation.


The scale is the current zoom scale.

zoom.on(type, function(...) {
    d3.event.scale                   // ** HIGHLIGHT **
    d3.event.translate
})

If the zoom behavior was defined with a scaleExtent, then this will also be limited by the scale extent.

This will be very useful when we go over how to resize elements when zooming in or out.


The translate vector is a two-element JavaScript array that represents the current X coordinate and Y coordinate translations.

zoom.on(type, listener() {
    d3.event.scale
    d3.event.translate               // ** HIGHLIGHT **
})

The first element is the X coordinate.

The second element is the Y coordinate.


Here within the Event listener function is where the magic happens related to resizing the SVG objects when a zoom event occurs.

zoom.on(type, function(...) {

    // magic happens

})

For instance - lets think about a circle, rectangle and ellipse.

For a circle, when a zoom happens, we need to change the cx, the cy and the radius attributes.

For a rectangle, when a zoom happens, we need to change the x, y, width and height attributes.

For an ellipse, when a zoom happens, we need to change the cx, cy, rx and ry attributes.

This video will go over the thinking behind the resizing of a circle.

From this you should be able to figure out the resizing of other SVG basic shapes.

Let's dig into the full example code for the explanation.



Example Code Explanation


First, we define the height and width of the SVG Container.

var svgWidth  = 400,
    svgHeight = 400,    
    originalCircle = {"cx": 100, "cy": 100, "radius": 20},
    margin = {"top": 25, "right": 25, "bottom": 50, "left": 50},
    width  = svgWidth - margin.left - margin.right,       
    height = svgHeight - margin.top - margin.bottom;

We also define the data for the circle.

We also define the D3 Margin Convention and use it to create the width and height for the Inner Drawing Space.


Next, we append the SVG Viewport to the HTML body and define it's width, height and border.

var svgViewport = d3.select("body")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .style("border", "2px solid");

This will serve to give us a sense of where the SVG Viewport is.


Next, we define the X and Y D3 Linear Scales.

var xAxisScale = d3.scale.linear()
    .domain([0, width])
    .range([0, width]);

var yAxisScale = d3.scale.linear()
    .domain([0, height])
    .range([height, 0]);

The domains are setup so they go from zero to the respective height or width.

The range for the x axis goes from zero to the width of the inner drawing space.

The range for the y axis goes from the height of the inner drawing space to zero as the Y axis in the SVG Coordinate Space is inverted.


Next, we use the X and Y linear scaling functions to define the D3 SVG Axis functions.

var xAxis = d3.svg.axis()
    .scale(xAxisScale)
    .orient("bottom")
    .ticks(5);

var yAxis = d3.svg.axis()
    .scale(yAxisScale)
    .orient("left")
    .ticks(5);

We give each axis an orientation as well as the number of ticks that we would like them to have.

In both cases, we would like 5 ticks.


Next, we define the zoomFunction zoom event listener function that gets executed when the zoom event is triggered.

function zoomFunction() {
  
    // Select All Circles
    var circles = d3.select("svg").selectAll("circle");

    // Pan Vector
    var panVector = d3.event.translate;
    var panX = panVector[0];
    var panY = panVector[1];

    // Scaling Multiplier
    var scaleMultiplier = d3.event.scale;

    // Tell us in HTML what is going on
    d3.select("#pan_x_span").text(panX);
    d3.select("#pan_y_span").text(panY);
    d3.select("#v_scale_val").text(scaleMultiplier);

    // Redraw the Axis
    innerSpace.select(".x.axis").call(xAxis);
    innerSpace.select(".y.axis").call(yAxis);

    // Redraw the Circle
    circles
        .attr("cx", function(d, i) { return xAxisScale(d.cx); })
        .attr("cy", function(d, i) { return yAxisScale(d.cy); })
        .attr("r",  function(d, i) { return (d.radius * scaleMultiplier); });    
}

We are defining this now because we are going to run this section by section in the JavaScript Console.

If we were running it in one file or as a single contiguous block of code, we could count on JavaScript function hoisting.

Since we are not doing that, this has to go near the top of the commands.

The big picture over view of this function is that it figures out what zoom scale we are on as well as redraws the x and y axis as well as the circles.

Let's go through it step by step.


This is self-explanatory.

// Select All Circles
var circles = d3.select("svg").selectAll("circle");

We create a selection of all the circles inside of the SVG Viewport.

We will use this selection to update the attributes later in this function.


This gets the pan vector or as it's also called the translate vector.

// Pan Vector
var panVector = d3.event.translate;
var panX = panVector[0];
var panY = panVector[1];

As the translate vector is a two element array we have to extract each element.

The first element is the X translation and the second element the Y translation.

These get assigned to separate variables because we later use them to write to the HTML elements what the zoom behavior is doing.


This gets the zoom level we are in.

// Scaling Multiplier
var scaleMultiplier = d3.event.scale;

Though we haven't yet defined the specific zoom behavior, if the zoom behavior has a Scale Extent defined, the definition will show up here as well.


These lines of code select specific HTML elements and write to them text that specifies the current Pan X, Pan Y and scale multiplier.

// Tell us in HTML what is going on
d3.select("#pan_x_span").text(panX);
d3.select("#pan_y_span").text(panY);
d3.select("#v_scale_val").text(scaleMultiplier);

Though this isn't always necessary for visualizations, I like to add this in order to keep track of data and to give a better sense of what is happening.


We mentioned this earlier.

The D3 zoom behavior allows us to designate the x scales and y scales to the x and y scale helper functions that help redefine the domain of each scale.

// Redraw the Axis
innerSpace.select(".x.axis").call(xAxis);
innerSpace.select(".y.axis").call(yAxis);

In turn, these updated scales are available within the listener function.

To redraw the scales, it is necessary to select all the SVG elements for each axis.

Then we call the updated xAxis and yAxis scales.

This ensures that the visual x and y axis will show the correct numbers on a zoom and pan.


This is where the magic happens in regards to redrawing slash updating the circle on a zoom event.

// Redraw the Circle
circles
    .attr("cx", function(d, i) { return xAxisScale(d.cx); })
    .attr("cy", function(d, i) { return yAxisScale(d.cy); })
    .attr("r",  function(d, i) { return (d.radius * scaleMultiplier); });

Let's go over this line by line.


The key thing to note here is that the zoom behavior has changed the xAxisScale domain for us.

circles
    .attr("cx", function(d, i) { return xAxisScale(d.cx); })

It has done the hard work with the math to figure out what the new x linear scale domain should be.

So all that we have to do is to pass the original cx data from the circle to the updated scale and it will figure out what the right cx number should be.

Why do we scale it?

Imagine that we didn't zoom and just panned in the positive x direction.

By panning in the positive x direction it means we are moving the camera in the positive x direction.

Which means that our circle should be moving towards the negative x direction.

If we move the camera to the right everything in the picture should move to the left.

This is where the new scale domain becomes important.

The scale domain is the moving of the camera and the number it returns once we pass in the cx should have moved it to the left.

Note - this will work the exact same way if we have zoomed in or zoomed out.

For the cx, we only care about the linear scaling function to make sure that the cx is correctly scaled in relation to the rest of the visualization.


The key thing to note here is that the zoom behavior has changed the yAxisScale domain for us.

circles
    .attr("cy", function(d, i) { return yAxisScale(d.cy); })

It has done the hard work with the math to figure out what the new y linear scale domain should be.

So all we have to do is to pass the original cy data from the circle to the updated scale and it will figure out what the right cy number should be.

Why do we scale it?

For the same reason as the cx.

As we pan in the positive Y direction it means the camera is moving in the positive y direction.

Which in SVG Coordinate space means moving the camera down.

As the camera moves down, everything in the frame should be moving up.

So the scale domain is the moving of the camera and the number it returns once we pass in the cy should have moved it towards the top of the page.

Note - this will work the exact same way if we have zoomed in or zoomed out.

For the cy, we only care about the linear scaling function to make sure the cy is correctly scaled in relation to the rest of the visualization.


The key thing to think about here is how you would expect the radius of a circle to behave if we zoomed in or zoomed out.

circles
    .attr("r",  function(d, i) { return (d.radius * scaleMultiplier); });

If we zoomed in, then you would expect the circle to become bigger.

If we zoomed out, then you would expect the circle to become smaller.

D3 gives us the current scale we are in.

If we are zoomed in a scale of 2, then everything will look twice as big.

If we are zoomed out a scale of one half, then everything will look twice as small.

So for the circle what we want to do is to multiply the radius by the zoom scale.

As we zoom in the zoom scale will get bigger so the radius will be bigger.

As we zoom out the zoom scale will get smaller so the radius will be smaller.


Going back to the full scaling and panning of the circle, you can see that it will work regardless of what zoom level we are in.

circles
    .attr("cx", function(d, i) { return xAxisScale(d.cx); })
    .attr("cy", function(d, i) { return yAxisScale(d.cy); })
    .attr("r",  function(d, i) { return (d.radius * scaleMultiplier); });

The zoom behavior function will recalculate the domain of the scaling functions for us and tell us the zoom scale.

So we don't have to specify different scenarios for different levels of zooming.


Going back to the rest of the code, this is where we define the D3 Zoom Behavior.

var zoom = d3.behavior.zoom()
    .x(xAxisScale)
    .y(yAxisScale)
    .scaleExtent([0.2, 10])
    .on("zoom", zoomFunction);

We pass in the xAxisScale to the x axis scale helper which will redefine the x scale domain for us.

We pass in the yAxisScale to the y axis scale helper which will redefine the y scale domain for us.

We define the extent of the zoom scale - to go from 0.2 to 10.

Lastly, we define the event we want to listen for, which is the zoom event, as well as what function to call when the zoom event is triggered.

The zoomFunction is the function we just got done defining and going over.


Then we define the inner drawing space.

var innerSpace = svgViewport.append("g")
    .attr("class", "inner_space")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);                     // ** HIGHLIGHT **

This will hold the axes as well as circle.

The important thing to note here is that we call the zoom behavior on this SVG Group Element.

This gives this element and it's children elements the D3 Zoom Behavior.


Next we draw the X and Y axis.

innerSpace.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

innerSpace.append("g")
    .attr("class", "y axis")
    .call(yAxis);

The x axis is transform translated the height of the inner drawing space to make sure it is at the bottom of the inner drawing space.


Then we use the D3 pattern to create an SVG circle through the binding of data and using the enter selection.

var circle = innerSpace.selectAll("circle")
    .data([originalCircle])
  .enter().append("circle")
    .attr("cx", function(d) { return xAxisScale(d.cx); })
    .attr("cy", function(d) { return yAxisScale(d.cy); })
    .attr("r",  function(d) { return d.radius; })
    .style("fill", "green");

Note that even before we zoom, we are already using the scaling functions to properly place the cx and cy points of the circle.


Lastly, we create HTML Divs and Spans to allow us to programmatically update the x and y translations as well as the current zoom level.

d3.select("body").append("div").attr("id", "pan_x_div").text("Pan X Translate: ");
d3.select("body").append("div").attr("id", "pan_y_div").text("Pan Y Translate: ");
d3.select("body").append("div").attr("id", "v_scale").text("D3 Zoom Scale: ");

d3.select("#pan_x_div").append("span").attr("id", "pan_x_span");
d3.select("#pan_y_div").append("span").attr("id", "pan_y_span");
d3.select("#v_scale").append("span").attr("id", "v_scale_val");

These are updated by the zoomFunction we defined earlier.

And that is the last of the code.

Let's now do the JavaScript Console Walk Through.



JavaScript Console Walk Through


This web page has the D3 library imported from the d3js.org website.


We have opened the Chrome Developer Tools and are in the Console Section.


We start by defining the variables used for the height and width of the SVG Viewport as well as the D3 margins and the SVG circle.

var svgWidth  = 400,
    svgHeight = 400,    
    originalCircle = {"cx": 100, "cy": 100, "radius": 20},
    margin = {"top": 25, "right": 25, "bottom": 50, "left": 50},
    width  = svgWidth - margin.left - margin.right,       
    height = svgHeight - margin.top  - margin.bottom;


Next, we define the SVG Viewport

var svgViewport = d3.select("body").append("svg")
    .attr("width", width   + margin.left + margin.right)
    .attr("height", height + margin.top  + margin.bottom)
    .style("border", "2px solid");

Note - that we add a border style to make it easier to see.

In production environments you do not want to apply a border to SVG elements as they are not supposed to render anything directly by themselves.

That said, for this video, we use the border style to make sure we visually see what we have coded up.


Next, we define the xAxisScale and yAxisScale

var xAxisScale = d3.scale.linear()
    .domain([0, width])
    .range([0, width]);

var yAxisScale = d3.scale.linear()
    .domain([0, height])
    .range([height, 0]);

Note that we are using a 1 to 1 mapping for the x axis.

This is for ease of exposition.

For the Y axis it is an inverse 1 to 1 mapping because of the inverted SVG Y Axis.


Next, we define the D3 SVG Axis Functions.

var xAxis = d3.svg.axis()
    .scale(xAxisScale)
    .orient("bottom")
    .ticks(5);
var yAxis = d3.svg.axis() .scale(yAxisScale) .orient("left") .ticks(5);

This should be familiar to you by now.

We pass in the scale we want for the axis, choose an orientation and then detail how many ticks we want on the axis.


Next, because we are pasting code into the JavaScript console and cannot use JavaScript Function Hoisting, we define the D3 Zoom Behavior Event Listener Function.

function zoomFunction() {
  
    var circles = d3.select("svg").selectAll("circle");

    var panVector = d3.event.translate;
    var panX = panVector[0];
    var panY = panVector[1];

    var scaleMultiplier = d3.event.scale;

    d3.select("#pan_x_span").text(panX);
    d3.select("#pan_y_span").text(panY);
    d3.select("#v_scale_val").text(scaleMultiplier);

    innerSpace.select(".x.axis").call(xAxis);
    innerSpace.select(".y.axis").call(yAxis);

    circles
        .attr("cx", function(d, i) { return xAxisScale(d.cx); })
        .attr("cy", function(d, i) { return yAxisScale(d.cy); })
        .attr("r",  function(d, i) { return (d.radius * scaleMultiplier); });

}

This function selects the circles we are moving, figures out what translation has occurred from the d3 dot event dot translate as well as what zoom scale we are in.

It writes these numbers to HTML so that we can understand what is happening.

It then calls the xAxis and yAxis functions on the already drawn X and Y visible axis elements to update them with the newly updated scales.

Remember - the D3 Zoom behavior updates these scales for us.

Lastly, we update the circle attributes to take into account the new scales for X and Y coordinates as well as the zoom level for the circle radius.


Now that we have defined the event listener function, we define the D3 Zoom Behavior function.

var zoom = d3.behavior.zoom()
    .x(xAxisScale)
    .y(yAxisScale)
    .scaleExtent([0.2, 10])
    .on("zoom", zoomFunction);

Remember that the scaleExtent limits the zoom out and zoom in levels.


With the D3 Zoom behavior and event listener function defined, let's create the rest of the visualization.


We create the Inner Drawing Space

var innerSpace = svgViewport.append("g")
    .attr("class", "inner_space")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(zoom);

Remember that it is here where we give the SVG Group Element the D3 Zoom Behavior by calling the zoom function on it.


Then we draw the X and Y axis on the screen.

innerSpace.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

innerSpace.append("g")
    .attr("class", "y axis")
    .call(yAxis);


Then we create the SVG Circle we will use to visually help us understand the zoom and pan behaviors.

var circle = innerSpace.selectAll("circle")
    .data([originalCircle])
  .enter().append("circle")
    .attr("cx", function(d) { return xAxisScale(d.cx); })
    .attr("cy", function(d) { return yAxisScale(d.cy); })
    .attr("r",  function(d) { return d.radius; })
    .style("fill", "green");


Lastly, we create the HTML Div and Span elements that will hold the key information regarding what the zoom behavior is doing as we zoom in and zoom out.


First we define the Divs

d3.select("body").append("div").attr("id", "pan_x_div").text("Pan X Translate: ");
d3.select("body").append("div").attr("id", "pan_y_div").text("Pan Y Translate: ");
d3.select("body").append("div").attr("id", "v_scale").text("D3 Zoom Scale: ");

You can see that we now have text labels for the Pan X Translate, Pan Y Translate and the D3 Zoom Scale numbers.


Then we define the Spans as child elements of the HTML Div elements.

d3.select("#pan_x_div").append("span").attr("id", "pan_x_span");
d3.select("#pan_y_div").append("span").attr("id", "pan_y_span");
d3.select("#v_scale").append("span").attr("id", "v_scale_val");

We use a span with a distinct id to be able to programmatically change the text from inside of the zoomFunction function.


And there we go, we have now entered all of the code.


Let's now play with the panning of the visualization to get a feel for how it works.

BROWSER: - drag the circle around for a while.

BROWSER: - move it off of the screen (leave it there and then bring it back)

BROWSER: - move it over the axis

As we press the mouse button down and pan the camera, you can see the circle moves along the x and y coordinates.

You can also see that we can move the circle off of the screen.

You can also see that we can move the circle on top of the Axis Elements.

This is because the circle was the last thing drawn in SVG so it will be the top thing in the visualization.

Because we can use the zoom behavior on axis elements, you can see that we can loose the circle and then later bring it back by using the axis.


Let's now play with the zooming of the visualization to get a feel for how it works.

BROWSER: - zoom all the way in and then zoom all the way out.

BROWSER: - And do some panning in between.

As we zoom in an out you can see the D3 zoom scale move with us.

As we zoom in, it grows all the way up to 10.

As we zoom out, it decreases until we are at 0.2.

Also, notice that the panning still works at all the different types of zoom levels.


And with that we have covered the basics of thinking about, creating and using the D3 Zoom Behavior.


We covered how the translate pan works as well as how the zoom works.


We created an example with a green circle to showcase what is possible at the most basic level.


This technique will be useful in regular data visualizations, force layout diagrams as well as in Geographic Visualizations.

<< Back To D3 Screencast and Written Tutorials Index