Why does my minimap viewport rectangle pan while zooming?
<p>I created a CodePen to illustrate my problem:</p>

See the CodePen <a href="https://codepen.io/StephanT/pen/GZzPaX/" rel="nofollow">Simple Minimap dashed Viewport</a>.</p>



<p>I'm part of a small team, my job is (among others) to do the minimap.
The code in the pen is a boiled-down version of our code regarding the minimap.
I'm new to d3js, so I'm happy to hear anything which could be improved about it.</p>

<p>I'm stuck with the bug regarding the dashed rectangle, which is supposed to show what part of the big map we can see.
Panning works, zooming might be finished - the (in my eyes) only technical problem remaining is that the dashed rectangle also pans when you zoom.
The zoom-panning amount is dependant on the mouse position - if the mouse is in the top-left corner, panning is minimal. The further the mouse moves to bottom or right (or both), the more this bug becomes apparent.</p>

<p>I'm using d3.event to get information about pan &amp; zoom amount, and noticed that even if you do not pan at all, if you only zoom, d3.event.translate[0/1] contains values != zero.
Is my approach wrong? Being a new member of the team, I cannot change much of the code, but I can change everything regarding the minimap.</p>

<p>I need to capture pan and zoom events from</p>

<pre><code>    var rect = svg.append("rect")
        ...   
        .style("pointer-events", "all");
</code></pre>

<p>Can anyone tell me what I'm doing wrong? I'm stuck on that problem for days now, any help would be appreciated a lot. Thanks in advance!</p>

<p>HTML:</p>

<pre><code>&lt;div class="canvas" id="canvas"&gt;&lt;/div&gt;
</code></pre>

<p>CSS:</p>

<pre><code>body
{
  background-color: #fcfcfc;
}

.canvas
{
  position: absolute;
  border-radius: 7px;
  background-color: #ddd;
  left: 7%;
  top: 10%;
}

.minimap {  
    position: absolute;
    border-radius: 8px;
    border: 2px solid #c2d1f0;
    bottom: 2%;
    right: 2%;
}
</code></pre>

<p>JS:</p>

<pre><code>var width = 800;
var height = 500;

var canvas = d3.select("#canvas")
  .attr("width", width)
  .attr("height", height);

var zoom = d3.behavior.zoom()
    .scaleExtent([0.1, 10])
    .on("zoom", zoomed);

var svg = canvas.append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .call(zoom);

// invisible rectangle to handle mouse interaction
var rect = svg.append("rect")
  .attr("width", width)
  .attr("height", height)
  .style("fill", "none")
  .style("pointer-events", "all");

var group = svg.append("g");


function zoomed() {
  group.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");

  // update the minimap whenever pan or zoom have happened
  updateMinimap();
}

// an array of circles just to have something to look at and as orientation
var circles = [
  {x: 150, y: 100}, 
  {x: 50, y: 50}, 
  {x: 80, y: 350},
  {x: 200, y: 150},
  {x: 350, y: 200},
  {x: 140, y: 300},
  {x: 230, y: 280}
];

// draw those circles
group.selectAll("circle")
  .data(circles)
  .enter()
  .append("circle")
  .attr("r", 5)
  .attr("fill", "red")
  .attr("cx", function(d) {return d.x;})  
  .attr("cy", function(d) {return d.y;})

var minimapScale = 1 / 3;   // size of big map times this = size of minimap
var minimapWidth = width * minimapScale;
var minimapHeight = height * minimapScale;

var minimap = canvas.append("svg")
  .attr("class", "minimap")
  .attr("width", minimapWidth)
  .attr("height", minimapHeight);

// run it once so we can see it even if no action was done
updateMinimap();

function updateMinimap() {
  // clear outdated objects from minimap
  minimap.selectAll("*").remove();

  // set default values
  var scale = 1;
  var dx = 0;
  var dy = 0;

  if (d3.event) { // overwrite those values when necessary
    scale = d3.event.scale;
    dx = -d3.event.translate[0] * minimapScale;
    dy = -d3.event.translate[1] * minimapScale;
  }

  // debug output
  //console.log("scale: " + scale + ", dx: " + dx + ", dy: " + dy);

  // repaint objects on minimap
  group.selectAll("*").each(function (circle) {
    var cx = circle.x * minimapScale;
    var cy = circle.y * minimapScale;
    minimap.append("circle")
      .attr("r", 2)
      .attr("fill", "blue")
      .attr("cx", cx)
      .attr("cy", cy);
  });

  // draw the dashed rectangle, indicating where we are on the big map
  drawDashedRectangle(scale, dx, dy);
}

function drawDashedRectangle(scale, dx, dy) {
  minimap.append("rect")
    .attr("x", dx)
    .attr("y", dy)
    .attr("width", minimapWidth / scale)
    .attr("height", minimapHeight / scale)
    .style("stroke-dasharray", (10, 5))
    .style("stroke-width", 2)
    .style("stroke", "gray")
    .style("fill", "none");
}
</code></pre>

<p>We'd like to have <a href="http://www.billdwhite.com/wordpress/2013/11/26/d3-minimap-pan-and-zoom-demo/" rel="nofollow">something like that</a>, though we don't need pan/zoom interaction on the minimap. We only need it on the big map, and the minimap should only reflect those changes.</p>