datamake

D3 zoom manual

A concise zoom and pan recipe - dangling off the Missing Zoom tutorial

‘1895 Firemans Ladder Patent — Blueprint’ by Aged Pixel

This is a summary of the article D3 Zoom: The Missig Manual. It’s 5 simple synchronous steps to get your D3 zooming and panning up and running.

Some terminology first

We also distinguish between two types of zoom:

The manual:

  1. Build your static visual first

    In order to zoom into a visual, you will need a visual.

  2. Identify your zoom base and your zoom targets

    1. Choose your zoom base element first. You can attach the zoom to an svg, g, rect or any other element that your mouse has access to. Note here, that g elements can only register events where they have children with a fill. So, if you have a large g element with a circle of radius 1, your zoom gestures will only work on that tiny circle. Best is often to set-up a dedicated SVG rectangle (rect) with fill but 0 opacity and pointer-events set to all to register the zoom listener on. You might have to unset pointer events of ascendant elements.
    2. Identify your target elements and write them down. Which elements do you want to move? Make a list of all elements that will move.
    3. For each target identify if you want to use geometric or semantic zoom. Best is to note down which properties for each target you want to change.

      Here’s an example table you might end up with:

    Function Element Zoom Type Scale props
    Zoom base rect#listener-rect - -
    Zoom target circle.planet semantic only circle radius
    Zoom target x axis tick lines semantic no
    Zoom target x axis tick labels semantic no

  3. Set up the zoom behaviour

    1. Create the zoom behaviour with at least:

      
        var zoom = d3.zoom().on(‘zoom’, zoomed);
              

      Check out the D3 API reference for d3.zoom() for helper methods like scaleExtent and translateExtent.

    2. Call the zoom behaviour on your base element like"

      
        zoomBaseElement.call(zoom)
                

  4. Write the handler
    1. The first thing you want to do is capture the transform object passed into the handler by the listener at every user interaction (wheel or mouse):

      
        var transform = d3.event.transform;
              

      Now you have all 3 values, you need to do whatever you want with it: tx, ty and the scale k.

    2. If you want to only administer geometric zoom, you just call

      
        zoomTargetElement.attr(‘transform’, ‘translate(‘ + transform.x + ‘, ‘ + transform.y + ‘) scale(‘ + transform.k + ‘)’);
              

      or

      
        zoomTargetElement.attr(‘transform’, transform.toString());
              

      which is exactly the same. This assumes you want to apply all transform values. You can also focus on tx, ty or only the scale kof course.

    3. If you want semantic zoom you need to rescale.

      Assuming all your data values went through a scale to be translated from data to screen space, this translation changes on zoom. If your data point x = 10 was translated to pixel space 50 before zoom, the zoom will move it to a different point.

      Assuming you translate the x by 5 and scale by 2, the new position will be

      x2 = x1 × k + tx     or
      x2 = 50 × 2 + 5 = 105.

      Luckily you don’t have to produce these calculations yourself (you could now) but you can rescale your scale on each zoom and apply it to the target properties you want to change. Including axes or circles or rects or whatever target shapes and components you have.

      Assuming you have a scale called xScale, you can use the sugar function .rescaleX() and apply it like so:

      
        var updatedScale = transform.rescaleX(xScale);
              

      Now you can use updatedScale in your zoomed function for all the elements you want to update. For example an axis:

      
        xAxis.scale(updatedScale);
        gAxis.call(xAxis);
              

      Or a set of circle x positions:

      
        circles.attr(‘cx’. function(d) { return updatedScale(d.value); })
              

  5. Do you need to programmatically move your target into a position?
    1. Calculate/determine the position and the scale
    2. Capture the new positions tx and ty and the new scale k in D3’s own transform object format by saying
      
        var t = d3.zoomIdentity.translateBy(tx, ty).scale(k);
              
    3. Store the object in the zoom base AND propagate the changes by calling your first zoom handler which will move the targets with
      
        zoomBaseElement.call(zoom.transform, t);
              
    4. Now enable user triggered zoom with
      
        zoomBaseElement.call(zoom)
              



Read the full article at D3 Zoom: The Missig Manual !