D3: zoom event (or simulate a zoom event)

when I zoom in with the mouse, the following function bound to "myZoom" will execute:

myZoom.on('zoom', function() { someElement.attr('transform', 'translate(' + d3.event.translate[0] + ',' + d3.event.translate[1] + ') scale(' + d3.event.scale + ')'); .... // redraw axes, which should stay where they are at. .... } 

To simulate scaling without a mouse or any other pointing device, I can simply change the value of the 'transform' attribute above. Easy.

But the problem is in this function, I actually redraw the axes, the scale of which is automatically recounted. Refer to this official d3 documentation:

zoom.y ([y])

Specifies the y-scale whose domain should be automatically configured when scaling. If not specified, returns the current y-scale, which is null by default. If the zoom area changes programmatically, it must be reassigned to zoom mode.

I need to scale programmatically (possibly with a zoom button). How can I trigger a zoom event so that the scale of my axes is automatically recalculated?

+4
source share
4 answers

Software zoom is a daunting task in the D3 library, since D3 scaling is closely related to mouse events. A common example of software scaling is zooming in or out with the slider. Surprisingly, I could not find a single working example of how to make D3 scaling work using the slider. After some time and effort, I developed this working demo, which can be found here D3SliderZoom . The key point is to change the conversion attribute "<g>" SVGElement, embedded in the "<svg>" element, using the scale value specified by the slider.

 function zoomWithSlider(scale) { var svg = d3.select("body").select("svg"); var container = svg.select("g"); var h = svg.attr("height"), w = svg.attr("width"); // Note: works only on the <g> element and not on the <svg> element // which is a common mistake container.attr("transform", "translate(" + w/2 + ", " + h/2 + ") " + "scale(" + scale + ") " + "translate(" + (-w/2) + ", " + (-h/2) + ")"); 

}

This method should then be called from the slider change event, as shown below.

 $(function() { $( "#slider-vertical" ).slider({ orientation: "vertical", range: "min", min: 1000, max: 10000, value: 1000, slide: function( event, ui ) { zoomWithSlider(ui.value/1000); } }); 

});

This solution is much more elegant than creating a pseudo-mouse scroll.

+6
source

As a result, I calculated a new domain for a new level of scaling. With this new domain, I could redraw the two y axes. For someone who has the same problem, I submit my code. This is very specific to my project, so it can be difficult to understand. Just for your interest.

 wr.zoomSim = function(sNew) { var s = wr.zoom.scale(), tx = wr.zoom.translate()[0], ty = wr.zoom.translate()[1], sReal = sNew / s, dtx = wr.width / 2 * (1 - sReal), dty = wr.height / 2 * (1 - sReal), txNew = sReal * tx + dtx, tyNew = sReal * ty + dty, a = wr.scaleYBZoom.domain()[0], b = wr.scaleYBZoom.domain()[1], c = wr.scaleYBZoom.range()[0], d = wr.scaleYBZoom.range()[1], r = (ba)/(dc); wr.scaleYBZoom.domain([a + r * ( (c - dty) / sReal - c), a + r * ( (d - dty) / sReal - c)]); wr.zoom.scale(sNew); wr.zoom.translate([txNew, tyNew]); wr.svg2.select('g#bar') .attr('transform', 'translate(' + txNew + ',' + tyNew + ') scale(' + sNew + ')'); wr.svg2.select('g#axisl') .call(d3.svg.axis().scale(wr.scaleYBZoom).orient('left')) .selectAll('line.tick') .attr('x2', wr.width - wr.bar.left - wr.bar.right + 2 * wr.padding); wr.svg2.select('g#axisr') .call(d3.svg.axis().scale(wr.scaleYBZoom).orient('right')) .selectAll('line') .remove(); }; 
+2
source

Unfortunately, @Debasis answer didn’t work for me because I wanted to achieve this with the help of the scaling effect that I already used with my force layout . After two days of despair, I finally found a solution in this thread:

https://groups.google.com/forum/#!msg/d3-js/qu4lX5mpvWY/MnnRMLz_cnUJ

 function programmaticZoom ($svg, $zoomContainer, zoomBehavior, factor) { var width = $svg.attr('width'); var height = $svg.attr('height'); var newScale = zoomBehavior.scale() * factor; var newX = (zoomBehavior.translate()[0] - width / 2) * factor + width / 2; var newY = (zoomBehavior.translate()[1] - height / 2) * factor + height / 2; zoomBehavior .scale(newScale) .translate([newX,newY]) .event($zoomContainer); } 
+1
source

I did this using zoomListener. Worked well in simple steps for me:

  • Define zoomListener: var zoomListener = d3.behavior.zoom ();
  • Call the zoom listener d3.select (-element-what-you-need-zoom-on) .call (zoomListener);
  • Determine the zoom step. I took a step of 0.1. (Use to increase and increase 0.9 to increase).
  • Multiply the current zoom scale var newScale = zoomListener.scale () * step;
  • Set a new scale value zoomListener.scale (newScale);
0
source

Source: https://habr.com/ru/post/1444309/


All Articles