Harrison Cramer
Harrison Cramer

Reputation: 4496

D3 Zoom Settings

I am having some trouble understanding how zoom work in D3, specifically how it is called and the settings initialized. I have the following snippet of code (only the essential bits are included), which is from a Manning Textbook on D3 V4 and works fine:

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

function createMap(countries, cities) {
    var projection = d3.geoMercator()
        .scale(scale)
        .translate([width/2,height/2])

var mapZoom = d3.zoom()
    .on("zoom", zoomed)

var zoomSettings = d3.zoomIdentity
    .translate(width/2, height/2)
    .scale(scale)

svg.call(mapZoom).call(mapZoom.transform, zoomSettings) // ?!!!

function zoomed() {
        var e = d3.event
        .translate([e.transform.x, e.transform.y])
        .scale(e.transform.k)

    // I didn't include the drawing of the paths, but 
       they are appended to the SVG, and this updates their data.

    d3.selectAll("path.graticule").attr("d", geoPath)
    d3.selectAll("path.countries").attr("d", geoPath)
    d3.selectAll("circle.cities")
    .attr("cx", d => projection([d.x,d.y])[0])
    .attr("cy", d => projection([d.x,d.y])[1])
}

Why is it necessary to call the zoom function multiple times on the svg? The first time it is called, we don't pass it the "zoomSettings", and the second time we do. What is the point of this? Does it have something to do with the fact that the zoom event is working on the SVG, rather than a group holding all of my paths? I'm used to much more simple examples of zoom like this, which are called on an SVG and the elements are bound to a Group:

var zoom = d3.zoom()
    .scaleExtent([1,3])
    .on("zoom", zoomed)

function zoomed(){
    g.attr("transform", d3.event.transform)
}

var svg = d3.select("body").append("svg")
    .attr("width",width)
    .attr("height",height)
    .call(zoom)

var g = d3.select("svg").append("g")

// All elements are bound to group^

Any clarification someone could provide on this would be greatly appreciated. I find the zoom() in D3 to be incredibly confusing, despite the API.

Upvotes: 2

Views: 604

Answers (1)

Mark
Mark

Reputation: 108512

This line:

svg.call(mapZoom).call(mapZoom.transform, zoomSettings)

is doing two separate things.

First, svg.call(mapZoom) is applying the zoom behavior to the svg. The second call, .call(mapZoom.transform, zoomSettings), is programmatically setting a zoom transform to the svg. This is setting it's initial state before the user does anything to it.

So think about it like this:

  1. Create the zoom behavior (var zoom = d3.zoom())
  2. Apply it to svg element (svg.call(mapZoom))
  3. Set its initial state (.call(mapZoom.transform, zoomSettings))

Upvotes: 2

Related Questions