title: d3 zoom not centering on mouse position with radial tree
body: <p>I'm trying to apply fairly standard d3 drag/zoom functionality to a radial tree layout.</p>
  <p>The problem is that if I define my zoomhandler as this...</p>
  <pre><code>svg.attr(&quot;transform&quot;,&quot;translate(&quot;+d3.event.translate+&quot;)scale(&quot;+d3.event.scale+&quot;)&quot;);
  </code></pre>
  <p>...then the zoom follows the mouse perfectly but the whole radial tree starts in the wrong place on first zoom (i.e. the <code>(0,0)</code> coordinate).</p>
  <p>Whereas if I define my zoomhandler as this...</p>
  <pre><code>svg.attr(&quot;transform&quot;, &quot;translate(&quot; + (w/2 + d3.event.translate[0]) +
       &quot;,&quot; + (h/2 + d3.event.translate[1]) + &quot;)scale(&quot; + d3.event.scale + &quot;)&quot; );
  </code></pre>
  <p>...then the tree behaves correctly but the zoom doesn't follow the mouse (in fact in order to zoom in/out on the tree without moving it my mouse would need to be positioned in the 0,0 coordinate at the top-left of the screen)</p>
  <p>I appreciate that this is a topic that's been discussed before (I think most notably here: <a href="https://stackoverflow.com/questions/21100058/using-d3-can-semantic-zoom-be-applied-to-a-radial-tree">Using D3, can semantic zoom be applied to a radial tree?</a>), but I'm still unclear how to get around this problem so would hugely appreciate any input from anyone who's specifically resolved the problem of getting a radial tree to both zooms towards a mouse position, and remain anchored to the center of the screen at the same time.  Thanks!</p>
  <p>Here's the complete code in detail...</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var w = 1200;
  var h = 1000;
  
  var data = [{'parent_id' : '1', 'items_count' : '2'}
    , {'parent_id' : '2', 'items_count' : '4'}
    , {'parent_id' : '3', 'items_count' : '3'}
    , {'parent_id' : '4', 'items_count' : '2'}
    , {'parent_id' : '5', 'items_count' : '1'}
    , {'parent_id' : '6', 'items_count' : '6'}
    , {'parent_id' : '7', 'items_count' : '2'}
    , {'parent_id' : '8', 'items_count' : '4'}
    , {'parent_id' : '9', 'items_count' : '5'}
    , {'parent_id' : '10', 'items_count' : '7'}
  ];
  
  var treeRadius = 300;
  var searchCircleRadius = 60;
  
  var circleRadiusScale = d3.scale.linear()
    .domain([0, d3.max(data, function(d) { return d.items_count; })])
    .range([10, 40]);
  
  var dataTree = {
    children: data.map(function(d) { return { parent_id: d.parent_id, items_count: d.items_count}; })
  };
  
  var tree = d3.layout.tree()
    .size([360, treeRadius]);
  
  var mainSvg = d3.select("body").append("svg")
    .attr("width", w)
    .attr("height", h);
  
  var svg = mainSvg
    .append("g")
    .attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
  
  var childGroupZoom = svg.append("g");
  
  var zoomListener = d3.behavior.zoom()
    .scaleExtent([0.1, 1.75])
    .on("zoom", zoomHandler);
  
  function zoomHandler() {
    //1) for both of these, the tree starts in centre of screen, drag works nicely, but zoom doesn't follow mouse
    //childGroupZoom.attr("transform", "translate(" + (d3.event.translate[0]) + "," + (d3.event.translate[1]) + ") scale(" + d3.event.scale + ")"); 
    childGroupZoom.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
  
    //2) follows the mouse on zoom but jump to top-left on first zoom/drag (because it's applied to "svg" which already has a translate applied)...
    //svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); //follows mouse on zoom but starts at wrong place
  
    //3) same as the first category - the tree doesn't jump, but the zoom doesn't follow the mouse
    //svg.attr("transform", "translate(" + (w/2 + d3.event.translate[0]) + "," + (h/2 + d3.event.translate[1]) + ")scale(" + d3.event.scale + ")" ); //starts in centre but doesn't follow mouse!
  }
  
  zoomListener(mainSvg);
  
  var nodes = tree.nodes(dataTree);
  
  var basicNode = childGroupZoom.selectAll(".node");
  
  var node = basicNode
    .data(nodes)
    .enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) {
      return "rotate(" + (d.x - 90) + ") translate(" + d.y + ")";
    });
  
  var outlineCircles = node.append("circle")
    .attr("r", function(d,i) { if (i&lt;1) {
      return searchCircleRadius;
    } else {
      return circleRadiusScale(d.items_count);
    }})
    .attr("stroke", "#0099FF")
    .attr("stroke-width", "3")
    .attr("transform", function(d) {return "rotate(" + (-d.x + 90) + ")";});</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
      &lt;title&gt;Demo&lt;/title&gt;
      &lt;script src="http://d3js.org/d3.v3.min.js"&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;/body&gt;
  &lt;/html&gt;</code></pre>
  </div>
  </div>
  </p>