d3.js rewriting zoom example in version4

Drag and Drop Example

I am trying to rewrite part of this example above to use in my code, specifically this piece:

function centerNode(source) {
        scale = zoomListener.scale();
        x = -source.y0;
        y = -source.x0;
        x = x * scale + viewerWidth / 2;
        y = y * scale + viewerHeight / 2;
        d3.select('g').transition()
            .duration(duration)
            .attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")");
        zoomListener.scale(scale);
        zoomListener.translate([x, y]);
    }

However I am getting stuck since the v4 package has changed quite a bit. I wrote my zoomListener function to be

    var zoomListener = d3.zoom()
                 .scaleExtent([0.3,2])
                 .on("zoom", zoomed);

    function zoomed() {
       transform = d3.event.transform;
       console.log(d3.event);
         svg.attr("transform", transform);
    } 

function centerNode(source){
  t = transform;
  console.log(t);
  x = t.x*t.k; //I only want things to be centered vertically
  y = (t.y + -source.x0)*t.k + (viewerHeight)/2 ;
  svg.transition()
     .duration(duration)
     .attr("transform","translate(" + x + "," + y +")scale(" + t.k + ")");

  transform.scale(t.k); //DOES NOT WORK
  transform.translate([x, y]); //DOES NOT WORK

}

and I know that according to the doc things have changed and info are no longer are stored on what would be my zoomListener D3 V4 release note on zoom I guess I am just confused on how I am suppose to do it with the new version. The last few lines of my centerNode function don't work which has for effect that when I center the node the zooming and panning reset...

Any suggestion?

Answers:

Answer

So after much digging and trial and error I cam up with an answer that works pretty well for my purposes. Note that this code below is only the relevant part of my code not the whole code, certain variable were self explanatory so did not include them. ALSO THIS IS IN VERSION 4 of d3.js.

var zoom = d3.zoom()
             .scaleExtent([0.3,2])
             .on("zoom", zoomed);


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

var zoomer = svg.append("rect")
                .attr("width", viewerWidth)
                .attr("height", viewerHeight)
                .style("fill", "none")
                .style("pointer-events", "all")
                .call(zoom);

var g = svg.append("g");

zoomer.call(zoom.transform, d3.zoomIdentity.translate(150,0)); //This is to pad my svg by a 150px on the left hand side

function zoomed() {
  g.attr("transform", d3.event.transform);//The zoom and panning is affecting my G element which is a child of SVG
}

function centerNode(source){

  t = d3.zoomTransform(zoomer.node());
  console.log(t);

  x =  t.x;
  y = source.x0;

  y = -y *t.k + viewerHeight / 2;

  g.transition()
   .duration(duration)
   .attr("transform", "translate(" + x + "," + y + ")scale(" + t.k + ")")
   .on("end", function(){ zoomer.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(t.k))});


}

As per the examples for v4 on the d3.js page, I used a rectangle to apply the zoom to

The zoom behavior is applied to an invisible rect overlaying the SVG element; this ensures that it receives input, and that the pointer coordinates are not affected by the zoom behavior’s transform. Pan & Zoom Example

In the Center node function I am using d3.zoomTransform(zoomer.node()); to get the current transform applied to the page. The purpose of this function is only to center the collapsible tree vertically not horizontally, so I am keeping the current transform.x (here t.x) the same. The coordinate in my svg are flip hence why y= source.x0, source is a what node was clicked in my collapsible tree. ("Look to the example referenced to the top of this thread to understand what I am trying to convert to version 4)

I am apply the transformation to my G element and then I want to commit those changes to the zoom transform, to do so I use the .on("end", function(){}) otherwise it was doing weird behavior with the transition, by doing that all it does is setting the current state of the transform.

zoomer.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(t.k))

This line above is applying a translation of x and y and a scale -- that is equal to what the current state -- to the identiy matrix has to get a new transform for G, i then apply it to zoomer which is the element I called zoom on earlier.

This worked like a charm for me!

Answer

Calling transform.scale and transform.translate returns a new transform, and modifies nothing. Therefore:

transform = transform.translate([x, y]).scale(k)

svg.call(zoomListener.transform, newTransform)

(At this point zoomListener is a pretty inaccurate name for this, but regardless...)

k, x, and y can be derived from source, maybe as you show, but I'm not sure, because I don't know what source is. But to me, t.x*t.k looks suspicious, because it's multiplying the existing transforms x by its scale. Seems like it would cause a feedback loop.

For more into about the zoom in v4, check out this related StackOverflow post, or this example by mbostock demonstrating programmatic control over the zoom transform of an element (canvas in this case) and includes transitions.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.