D3 Keep Zoom / Translate After Reset Range

I have a <svg> whose width is 100% of this container. When the container size changes, I update the linear xScale.range() to represent the new modified width of the <svg> . Apparently, I need to apply the range again to my zoom, as described in zoom.x () :

If the scale domain or range is changed programmatically, this function must be called again. Setting x-scale also resets the scale to 1 and translates to [0, 0].

Resetting scale and translate happens where I have a problem. If I previously zoomed in before resizing, I call zoom.x( xScale ) , and now d3 considers the chart scale to be 1 and the translation to 0.0, so I cannot zoom out or pan.

Is my approach to how I handle size incorrectly?

+5
source share
2 answers

It seems like the best strategy is to cache the scale and translate the reset values, and then reapply. For the record, this code (in my resize handler) roughly shows my solution:

 // Cache scale var cacheScale = zoom.scale(); // Cache translate var cacheTranslate = zoom.translate(); // Cache translate values as percentages/ratio of the full width var cacheTranslatePerc = zoom.translate().map( function( v, i, a ) { return (v * -1) / getFullWidth(); } ); // Manually reset the zoom zoom.scale( 1 ).translate( [0, 0] ); // Update range values based on resized container dimensions xScale.range( [0, myResizedContainerWidth] ); // Apply the updated xScale to the zoom zoom.x( xScale ); // Revert the scale back to our cached value zoom.scale( cacheScale ); // Overwrite the x value of cacheTranslate based on our cached percentage cacheTranslate[0] = -(getFullWidth() * cacheTranslatePerc[0]); // Finally apply the updated translate zoom.translate( cacheTranslate ); function getFullWidth() { return xScale.range()[1] * zoom.scale(); } 
+6
source

For those who stumbled upon this, looking for a v4 solution using the amazing setup from Philip above, for v3, I adapted the freely based v4 solution. I decomposed the variables to explain it the way v3 did (since that makes sense in v3). v4 is not able to force an X value similar to v3, so you need to calculate the existing X and then divide by the scale (K). (Perhaps the best way to do the final calculation + set it to scale, but the d3-zoom documentation is a bit confusing)

 let transform = d3.zoomTransform(node); let oldFullWidth = (oldWidth * transform.k); let newFullWidth = (newWidth * transform.k); // this is the result you want X to be let newX = -(newFullWidth * ((transform.x * -1) / oldFullWidth)); // this is just deducting from the existing so you can call .translate let translateBy = (newX - transform.x) / transform.k; d3.select(node).call(myZoom.transform, transform.translate(translateBy, 0)); 
+1
source

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


All Articles