d3 v4 zoom button?

3,324 views
Skip to first unread message

Russell Jurney

unread,
Jul 9, 2016, 9:49:18 PM7/9/16
to d3...@googlegroups.com
I'm trying to implement a zoom button in d3 v4, but I'm having trouble, as the only example is for v3.

I get the transform for my figures, but when I print it no matter what I do in terms of zoom and pan, when I click its transform is: currentScale: translate(0,0) scale(1)

$("#zoom_in").click(function() {
    var currentScale = d3.zoomTransform(group1);
    console.log("currentScale: " + currentScale);
    var nextScale = currentScale.k + 1;
    console.log("nextScale: " + nextScale);
    zoom.scaleBy(group1, nextScale);
})

This code actually works, it will scale the figure to 2x... but when I pan or zoom from that state, it jerks back to its previous state in terms of translate and scale. Whereas I would like it to smoothly integrate with the rest of the interactions similar to http://bl.ocks.org/linssen/7352810 but in v4.

How am I supposed to do this? The docs indicate I should work on transforms on figures themselves, but I can't square that with the behavior I'm seeing and the use of a button.

Thanks!
--

Mike Bostock

unread,
Jul 9, 2016, 10:07:04 PM7/9/16
to d3...@googlegroups.com
d3.zoomTransform takes a node, not a selection.

zoom.scaleBy is relative. If you want to zoom in by one “level”, pass it a value of 2. Then you probably won’t need to retrieve the current zoom transform.
--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Russell Jurney

unread,
Jul 9, 2016, 11:15:52 PM7/9/16
to d3...@googlegroups.com
That reduces the code to:

$("#zoom_in").click(function() {
    zoom.scaleBy(group1, 2);
});

and it works!

However, if you check it out here: http://dev.relato.io/gene

The zoom button's zooming isn't connected to the rest of the zoom and pan. It does zoom in, but if you zoom or pan from there, it jumps back to the previous position. How can I have this zoom work with the existing zoom, such that the user can zoom and pan at the new zoomed in level, after pressing the zoom button? [Wow that sentence is painful :)]

Thanks!

Mike Bostock

unread,
Jul 10, 2016, 5:01:32 AM7/10/16
to d3...@googlegroups.com
Sounds like the group1 you are passing to zoom.scaleBy is different than the selection you initialized the zoom behavior on as selection.call(zoom).

Russell Jurney

unread,
Jul 10, 2016, 4:02:33 PM7/10/16
to d3...@googlegroups.com
This is true. I had to append a g to svg and alter that with zoomed, while the zoom is called on svg. This is the only way I've found to avoid problems with weirdness and bad panning when zoomed in. When I switch back to only using svg in both the .call and the callback, the zoom button instantly works. But the rest of the zoom is half broken.


When I use svg in both the zoomed() callback and I selection.call(zoom) on it, like so:

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

svg = d3.select(".chart")
    .append("svg")
    .attr("width", w)
    .attr("height", h)
    .append("g")
    .call(zoom)
    ;

// I cause choppy zoom, slow pan: http://dev.relato.io/gene

I get a weird choppy zoom, where pan doesn't work well when you zoom in: http://dev.relato.io/gene

Whereas if I use group1 in the zoomed() callback and I selection.call(zoom) on svg, like so:

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

svg = d3.select(".chart")
    .append("svg")
    .attr("width", w)
    .attr("height", h)
    .append("g")
    .call(zoom)
    ;

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

// I work well, the zoom is usable: http://staging.relato.io/gene

This zoom works great! I can actually move around and get where I want to go, from one cluster to another: http://staging.relato.io/gene

I have found reference to other people having this problem, do you have any ideas how to address it? I would prefer to use the top way to do zoom, because it makes the zoom button very easy. I think I'm probably doing this all wrong :)

Thanks!
Russ

Mike Bostock

unread,
Jul 10, 2016, 4:05:02 PM7/10/16
to d3...@googlegroups.com
Set the transform attribute of the G element, but apple the zoom behavior to a parent element, such as the SVG element.

You definitely do not want to set a transform on the same element you apply the zoom behavior to: that causes a feedback loop because it affects the perceived coordinates of the mouse by the zoom behavior.

Russell Jurney

unread,
Jul 10, 2016, 4:06:58 PM7/10/16
to d3...@googlegroups.com
Ok, thanks! I got this working. I call the zoom on the svg, zoomed() uses group1, and then I call scaleBy on svg, and it works: zoom.scaleBy(svg, 2);

jonathanfellow...@gmail.com

unread,
Dec 12, 2016, 6:26:52 AM12/12/16
to d3-js
Exclent, I'm glad you got it working.  I am having a similar issue, could you post a fully working example somewhere?

pat...@mail.usf.edu

unread,
Oct 4, 2017, 6:14:58 PM10/4/17
to d3-js
Can you please post a full working code? I am facing similar issues.
Reply all
Reply to author
Forward
0 new messages