zhangjinzhou
zhangjinzhou

Reputation: 2701

d3 update old scale when pan and zoom

I am new to d3. When do pan and zoom with d3v4, I noticed we always have to create new scale based on the d3.event.transform and apply the new scale to everything rather than replace the old scale with new and apply the old scale again. For example, this zoom function works perfect:

function zoomFunction(){
  // create new scale ojects based on event
  var new_xScale = d3.event.transform.rescaleX(xAxisScale)
  var new_yScale = d3.event.transform.rescaleY(yAxisScale)
  console.log(d3.event.transform)

  // update axes
  gX.call(xAxis.scale(new_xScale));
  gY.call(yAxis.scale(new_yScale));

  // update circle
  circles.attr("transform", d3.event.transform)
};

This zoom function screws everything:

function zoomFunction(){
  // create new scale ojects based on event
  var new_xScale = d3.event.transform.rescaleX(xAxisScale)
  var new_yScale = d3.event.transform.rescaleY(yAxisScale)
  xAxisScale = new_xScale;
  yAxisScale = new_yScale;
  console.log(d3.event.transform)

  // update axes
  gX.call(xAxis.scale(xAxisScale));
  gY.call(yAxis.scale(yAxisScale));

  // update circle
  circles.attr("transform", d3.event.transform)
};

The full example is here: https://bl.ocks.org/rutgerhofste/5bd5b06f7817f0ff3ba1daa64dee629d

The reason I want to use the new scale to replace the old one is that in my case a lot of parts of svg are related to scale. If I simply change the old scale, those binded events will work perfectly. I don't want to reclaim everything in my zoomFunction.

Upvotes: 3

Views: 1032

Answers (1)

Cyril Cherian
Cyril Cherian

Reputation: 32327

So you wish to change

xAxisScale = new_xScale; yAxisScale = new_yScale;

inside the zoom function for some reason.

If you do it the rescale will not work as expected.

  var new_xScale = d3.event.transform.rescaleX(xAxisScale)
  var new_yScale = d3.event.transform.rescaleY(yAxisScale)

Reason: xAxisScale andyAxisScale should be the original, because the rescale is calculated based/relative to the original scale value.

One way to get around this would be to make a copy of the original x and y scale.

// create scale objects
var xAxisScale =d3.scaleLinear()
  .domain([-200,-100])
  .range([0,width]);

var yAxisScale = d3.scaleLinear()
  .domain([-10,-20])
  .range([height,0]);

//make a copy of the scales
var copyX = xAxisScale.copy();  
var copyY = yAxisScale.copy();  
// create axis objects

Next in your zoomFunction do :

function zoomFunction(){
  // create new scale ojects based on event
  var new_xScale = d3.event.transform.rescaleX(copyX)
  var new_yScale = d3.event.transform.rescaleY(copyY)
  //changing scale due to some reason.
  xAxisScale = new_xScale;
  yAxisScale = new_yScale;

  // update axes
  gX.call(xAxis.scale(xAxisScale));
  gY.call(yAxis.scale(yAxisScale));

  // update circle
  circles.attr("transform", d3.event.transform)
};

working code here

Upvotes: 5

Related Questions