I was looking for the answer to this, but it seems D3 has already evolved a couple of versions.

Although Majkl and cjds's answers helped me solve my problem, I thought it would help to leave more up to date information, since it was hard finding v5.4 examples out there, until I found Observable at least.

// Applies event transformation to the Group element's attribute
const zoom_action = () => g.attr("transform", d3.event.transform)

// Create the zoom handler
const zoom = d3
        .on("zoom", zoom_action)

// Get SVG element and apply zoom behaviour
var svg = d3

// Create Group that will be zoomed
var g = svg.append("g")

// Create circle
  .attr("r", 5)

// Set initial scale and translation
zoom.scaleBy(svg, 5)
zoom.translateBy(svg, 50, 50)    
<script src=""></script>

<svg height="100px" width="100px"></svg>


That is a problem with the zoom function itself. I would suggest zooming the children as opposed to the parent if that would work

var zoom = d3.behavior.zoom().on("zoom",function(){
  var t = d3.event.translate;
  var s = d3.event.scale;
  svg.selectAll("rect").attr("transform","translate("+t[0]+","+t[1]+") scale("+s+")")  


The problem with the above code is that d3.js does not register the transformation or initial state of the SVG. This problem runs deeper. As d3 does not keep track of the SVG transformations and just executes them. It only keeps track of transformations you've run on the library in a variable called __chart__.

So when the zoom function is run it just interpolates the variables and gives the output. As no functions have been run on this yet the __chart__ variable has not been set and causing the jerky start from (x=0, y=0, k=1).


  1. Run this code before the zoom transformation to set the initial chart manually

        this.__chart__={x:25,y:25,k:0.25}; //or you can pick those values using attr
  2. Zoom the svg programmatically to 25,25,0.25 first before any other function. (this is why your workaround works as the __chart__ variable gets set)


To set the initial value of the zoom, try something like this:

// Init zoom
var zoom = d3.behavior.zoom().on("zoom", function () {
                svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");

// Get SVG element
var svg ="svg")

// Create circle
  .attr("r", 5);

// Create init value
var scale = 5;
var translate = [50, 50];

// Set init value

// Call zoom event; 
// or svg.transition().call(zoom.event);
<script src=""></script>

<svg height="100px" width="100px"></svg>

Related Query

More Query from same tag