Search code examples
javascriptsvgd3.jszoomingpan

D3 geometric zoom when there is no SVG element under the cursor


I am implementing a geometric zoom behaviour as seen in this example

force directed graph

The problem is that if the cursor is on a white spot outside the green overlay rect or any other SVG element (line, circle etc.) the mousewheel event gets intercepted by the browser and scrolls down the page.

I would like to be able to freely zoom independently of where I am on the visualisation.

Here is a simplified jsFiddle recreating the problem.

var width = 300,
    height = 300;

var randomX = d3.random.normal(width / 2, 80),
    randomY = d3.random.normal(height / 2, 80);

var data = d3.range(2000).map(function() {
  return [
    randomX(),
    randomY()
  ];
});

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .call(d3.behavior.zoom().scaleExtent([-8, 8]).on("zoom", zoom))
  .append("g");

svg.append("rect")
    .attr("class", "overlay")
    .attr("width", width)
    .attr("height", height);

svg.selectAll("circle")
    .data(data)
  .enter().append("circle")
    .attr("r", 2.5)
    .attr("transform", function(d) { return "translate(" + d + ")"; });

function zoom() {
  svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}

Solution

  • Hope this isn't too late, I missed this question the first time around.

    The reason it isn't working under Chrome is because Chrome hasn't yet implemented the standard CSS transform on html elements -- and as strange as it is to understand, the outermost <svg> tag on an SVG element embedded in a webpage is treated as an HTML element for layout purposes.

    You have two options:

    1. Use Chrome's custom transform syntax, -webkit-transform in addition to the regular transform syntax:

      http://jsfiddle.net/aW9xC/5/

      Kind of jumpy, since you are transforming the entire SVG and readjusting the page layout accordingly. For reasons I don't understand neither the CSS/webkit transform nor the SVG attribute transform work when applied to the "innerSVG" element.

    2. Replace the nested SVG structure with an SVG <g> group element, which Chrome has no problem transforming:

      http://jsfiddle.net/aW9xC/4/