javascript - How can I offset the initial starting position of a d3 zoom? - Stack Overflow

I'm trying to zoom in on an SVG element after having translated it's Matrix, but when I start

I'm trying to zoom in on an SVG element after having translated it's Matrix, but when I start the initial zoom, the position of the SVG resets to 0,0. I'd like the zoom and pan to start from the moved position on page load.

<svg id="#svg">
   <g id="#mainGrid>
     ....a bunch of SVG
   </g>
<svg>

<script>
var winCenterV = $(window).height()/2;
var winCenterH = $(window).width()/2;

//set mainGrid to the center of window using snap.svg
var mainGrid = Snap.select("#mainGrid");
var myMatrix = new Snap.Matrix();
myMatrix.scale(1,1);            
myMatrix.translate(winCenterH,winCenterV);
myMatrix.rotate(0); 
mainGrid.transform(myMatrix); 


//d3 zoom
var svgElement = d3.select("svg");
var gridELement = d3.select("#mainGrid");

svgElement.call(d3.zoom()
    .scaleExtent([1 / 2, 4])
    .on("zoom", zoomed));

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

</script>

the "mainGrid" SVG element zooms and pans fine, but it snaps back to it's 0,0 position (top left of browser) during the first zoom mouse click or wheel scroll instead of zooming and panning from the transformed location as set by myMatrix. How can I get the d3.event.transform to start zooming from this offset?

I'm trying to zoom in on an SVG element after having translated it's Matrix, but when I start the initial zoom, the position of the SVG resets to 0,0. I'd like the zoom and pan to start from the moved position on page load.

<svg id="#svg">
   <g id="#mainGrid>
     ....a bunch of SVG
   </g>
<svg>

<script>
var winCenterV = $(window).height()/2;
var winCenterH = $(window).width()/2;

//set mainGrid to the center of window using snap.svg
var mainGrid = Snap.select("#mainGrid");
var myMatrix = new Snap.Matrix();
myMatrix.scale(1,1);            
myMatrix.translate(winCenterH,winCenterV);
myMatrix.rotate(0); 
mainGrid.transform(myMatrix); 


//d3 zoom
var svgElement = d3.select("svg");
var gridELement = d3.select("#mainGrid");

svgElement.call(d3.zoom()
    .scaleExtent([1 / 2, 4])
    .on("zoom", zoomed));

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

</script>

the "mainGrid" SVG element zooms and pans fine, but it snaps back to it's 0,0 position (top left of browser) during the first zoom mouse click or wheel scroll instead of zooming and panning from the transformed location as set by myMatrix. How can I get the d3.event.transform to start zooming from this offset?

Share Improve this question asked Jul 19, 2019 at 20:44 sakeferretsakeferret 3151 gold badge6 silver badges16 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 9

Problem:

The d3 zoom behavior does not track or know about what transforms you've applied to an element. It is initialized with scale equal to 1 and translate equal to 0,0. So, when you use

gridELement.attr("transform", d3.event.transform);

in your zoomed function, you are zooming relative to this initial scale and translate.

Rationale

Not every d3 zoom manipulates the transform of the SVG element it is called on: you may want to have zoom interaction everywhere on a plot, but only zoom the plot area and not the margins. Many d3 zooms don't manipulate any SVG transform: they may use semantic zooming, or the zoom may be altering a canvas rather than SVG, etc. As such, a d3-zoom behavior is independent of any SVG transorm attribute on the element(s) it is called on.

Solution

If your zooming by manipulating the transform attribute of an SVG element, let D3 zoom do all of the manipulation - no need to manipulate it manually and have a zoom, this is how the zoom gets out of step.

So,

You can programmatically trigger a zoom event prior to rendering anything. The easiest way to do so is to use:

selection.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(k));

This line triggers a zoom event. We can use this prior to rendering anything and rely on the zoomed function to set the initial value of the SVG transform attribute. All subsequent zooms will be relative to this and we can proceed as normal:

var svg = d3.select("svg");

var g = svg.append("g"); 
  
// define a zoom behavior:
var zoom = d3.zoom()
  .on("zoom", zoomed);
  
// call the zoom:
svg.call(zoom)

// trigger tha initial zoom with an initial transform.
svg.call(zoom.transform,d3.zoomIdentity.scale(20).translate(-100,-100));

// draw the visualization:
var rect = g.append("rect")
  .attr("width", 5)
  .attr("height", 5)
  .attr("x", 100)
  .attr("y", 100);
  
// zoomed function:
// zoom as normal.
function zoomed() {
  g.attr("transform",d3.event.transform);
}
<script src="https://cdnjs.cloudflare./ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="500" height="300"></svg>

The above snippet applies an initial zoom (scale 20, translate -100,-100) and uses this as the starting point for the zoom interaction. The ment should help explain the process.

// It appears that you're moving #mainGrid and not #svg. So when you call zoom from svgElement it is zooming from it's 0,0 position. 

// Or it may because you don't have pound sign in d3.select
var svgElement = d3.select("#svg");

// Try changing svgElement to gridElement

gridELement.call(d3.zoom()
  .scaleExtent([1 / 2, 4])
  .on("zoom", zoomed));

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744292012a4567078.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信