title: d3 circles shifting position on click-to-zoom
body: <p>I'm trying to implement zooming on a d3 graphic with a bunch of data as circles. The data is made up of 1 large circle and many smaller circles plotted inside it.  I want to click on the smaller circles and zoom to them.  I'm using a variation of the zoom from the <a href="http://bl.ocks.org/mbostock/7607535" rel="nofollow">zoomable circle packing demo</a>. I don't want to use the demo code directly but I've got it mostly working.  </p>
  
  <p>Initially all the circles are in their correct positions.  However when I click on the smaller circles, they shift position right before the zoom.  When I click on the white circle to zoom back, you can see they are now permanently shifted.  And when it does zoom, the circles don't zoom into the center of the viewport, like they do in the demo.  </p>
  
  <p>I've noticed that when I comment out the transform line    </p>
  
  <pre><code>    node.attr("transform", function(d) { return "translate(" + (xscale(d.cx) - v[0]) * k + "," + (yscale(d.cy) - v[1]) * k + ")"; });
  </code></pre>
  
  <p>the circles now remain in their correct positions.  Their sizes scale up as they should, but now they just merge into one another as they get bigger, because I'm no longer translating them.  So the problem must be something in my transform attribute, but I can't figure out what it is.  Or maybe it's something with my initial view? When I uncomment the zoomTo(view) the circles immediately move to the incorrect positions.  </p>
  
  <p>How do I get their positions to remain in the right positions?  And how do I get the circles to zoom to the center of the viewpoint?  I thought I followed the demo code pretty closely, but it's not quite working right.  Any ideas?  </p>
  
  <p>I'd also like the axes to zoom as well but I haven't gotten that far into my problem yet.  </p>
  
  <p>Here's my <a href="http://jsfiddle.net/havok2063/xv5333z0/" rel="nofollow">jsfiddle</a>.</p>
  
  <p>And my full javascript code</p>
  
  <pre><code>function loadPlateDesign(){
  var width = 400;
  var height = 400;
  var padding = 55;
  var plateid = 7443;
  var plateCen = {'ra': 230.99167, 'dec': 42.68736 };
  
  var data = [{'name':7443,'color': 'white', 'cx': 0.0, 'cy': 0.0, 'r': 200},
      {'color': 'red', 'cx': 8.23066, 'cy': -134.645, 'ra':231.1,'dec':42.1,'name': '1901', 'r': 10.0, 
      'children':[{'color': 'red', 'cx': 8.23066, 'cy': -134.645, 'ra':231.1,'dec':42.1,'name': 'a', 'r': 2.0}]},
      {'color': 'blue', 'cx': -167.524, 'cy': -90.009, 'name': '711', 'r': 5.0}];
  
  var xscale = d3.scale.linear().domain([330.,-330.]).range([0,400]);
  var yscale = d3.scale.linear().domain([330.,-330.]).range([0,400]);
  
  // initial focus and view
  var focus = {'name':7443,'color': 'white', 'cx': 0.0, 'cy': 0.0, 'r': 200};
  var view = [xscale(0.0),yscale(0.0),200*2];
  
  // make the main svg element    
  var svg = d3.select('#platedesign').append('svg')
      .attr('width',width+padding)
      .attr('height',height+padding);
  
  // add the plate and ifu data   
  var ifus=svg.selectAll('circle').data(data).enter().append('circle')
      .attr('id',function(d){return d.name;})
      .attr('cx',function(d,i){return xscale(d.cx);})
      .attr('cy',function(d,i){return yscale(d.cy);})
      .attr('r',function(d,i){return d.r;})
      .style('fill',function(d,i){return d.color;})
      .style('stroke','black')
      .on('click',function(d){
          if (focus != d) zoom(d), d3.event.stopPropagation();
      });
  
  // add the axes 
  var rascale = d3.scale.linear().domain([plateCen.ra+1.5,plateCen.ra-1.5]).range([0,400]);
  var decscale = d3.scale.linear().domain([plateCen.dec+1.5,plateCen.dec-1.5]).range([0,400]);
  xaxis = d3.svg.axis().scale(rascale).orient('bottom');
  yaxis = d3.svg.axis().scale(decscale).orient('right').ticks(5);
  svg.append('g').attr('class','x axis')
      .attr('transform','translate(0,'+(height+5)+')')
      .call(xaxis)
      .append('text')
      .attr('x',width/2)
      .attr('y',35)
      .style('text-anchor','middle')
      .text('RA');
  
  svg.append('g').attr('class','y axis')
      .attr('transform','translate('+(width+5)+',0)')
      .call(yaxis)
      .append('text')
      .attr('transform','rotate(90)')
      .attr('x',height/2)
      .attr('y',-35)
      .style('text-anchor','middle')
      .text('Dec');
  
  var node = svg.selectAll("circle");
  //zoomTo(view);
  
  function zoom(d){
      console.log('zooming to', d.name);
      var focus0 = focus; focus=d;
      var newview = [xscale(d.cx), yscale(d.cy), d.r*2+20];
  
      var transition = d3.transition()
          .duration(d3.event.altKey ? 7500 : 750)
          .tween('zoom', function(d){
              var i = d3.interpolateZoom(view, newview);
              return function(t) {zoomTo(i(t)); };
          });
  
  }
  
  function zoomTo(v) {
      var k = height / v[2]; view = v;
      console.log(height, v);
      node.attr("transform", function(d) { return "translate(" + (xscale(d.cx) - v[0]) * k + "," + (yscale(d.cy) - v[1]) * k + ")"; });
      ifus.attr("r", function(d) { return d.r * k; });
  }
  </code></pre>
  
  <p>}</p>