0

I am throwing an error on my implementation of Mike Bostock's zoom to bounding box II.

The error stops the zoom mid-way and locks up the map if you scroll during the zooming event.

Any ideas on fixing? The error is present on Bostock's example.

Here is a screenshot of the error:

enter image description here

The code:

var width = 500,
    height = 370,
    active = d3.select(null);

var projection = d3.geo.albersUsa()
    .scale(675)
    .translate([width / 2, height / 2]);

var path = d3.geo.path()
    .projection(projection);

var svg = d3.select(".app-map")
    .append("svg")
      .attr("width", width)
      .attr("height", height);

var g = svg.append("g")
      .attr("class", "app-counties-map");

function ready(error, us) {

  g.selectAll("path")
    .data(topojson.feature(us, us.objects.counties).features)
  .enter().append("path")
    .attr("class", "app-counties")
    .attr("d", path)
    .on("click",clicked);

  function clicked(d) {
    if (active.node() === this) return reset();
    active.classed("active", false);
    active = d3.select(this).classed("active", true);

    var bounds = path.bounds(d),
      dx = bounds[1][0] - bounds[0][0],
      dy = bounds[1][3] - bounds[0][4],
      x = (bounds[0][0] + bounds[1][0]) / 2,
      y = (bounds[0][5] + bounds[1][6]) / 2,
      scale = 3.5,
      translate = [width / 2 - scale * x, height / 2 - scale * y];

    svg.transition()
      .duration(450)
      .call(zoom.translate(translate).scale(scale).event);
  };

  function reset() {
    active.classed("active", false);
    active = d3.select(null);

    svg.transition()
      .duration(450)
      .call(zoom.translate([0, 0]).scale(1).event);
  };

  var zoom = d3.behavior.zoom()
    .translate([0, 0])
    .scale(1)
    .scaleExtent([1, 8])
    .on("zoom", zoomed);

  svg.on("click", stopped, true);

  svg
    .call(zoom)
    .call(zoom.event);

  function zoomed() {
    g.style("stroke-width", 1.5 / d3.event.scale + "px");
    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
  }

  function stopped() {
    if (d3.event.defaultPrevented) d3.event.stopPropagation();
  }

}


queue()
    .defer(d3.json, "./data/us (2).json")
    .await(ready);
Union find
  • 7,759
  • 13
  • 60
  • 111

1 Answers1

1

I believe that the problem is happening because the mouse wheel event is trying to zoom while the zoom transition animation from click event is still playing ( I didn't get the error in chrome but in IE ).

You could turn the mouse-wheel event off at the beginning of the click event and enable it back on after the animation/transition finish.

In order to wait for the transition to finish, I've used .each, but maybe .call can be used as well.

Added 20150501 8:24PM PST

I am off work now so I can explain in more detail.

jsfiddle example

1. Disabling mouse scroll zoom event

var _wheelZoomEvent = svg.on("wheel.zoom");
function clicked(d) {

        svg.on("wheel.zoom", null);

While click transition is executing, we want to prevent the mouse wheel event from triggering another zoom transition. svg.on("wheel.zoom") is returning the reference to the event handler, so that I can reattach when the transition is complete. svg.on("wheel.zoom", null) detaches the event handler from mousewheel event.

2. Adding callback at the end of transition

After the transition completes we need to re-attach the mousewheel event back to the svg object.

svg.transition()
            .duration(750)
            .call(zoom.translate([0, 0]).scale(1).event)
            .each("end", function(){ 
                  svg.on("wheel.zoom", _wheelZoomEvent);
            });

There is another transition inside reset() function, and we need to attach event back on there as well.

Andrew Yoo
  • 36
  • 5
  • Here is a linke to SO page how to use callback after transition : http://stackoverflow.com/questions/10692100/invoke-a-callback-at-the-end-of-a-transition – Andrew Yoo May 01 '15 at 22:24
  • This is really more of a comment than an answer. – Union find May 01 '15 at 23:24
  • I am trying your example (which works well in plnkr -- well done). I am unable in my own implementation to reinstate the zoom behavior. Once the zoom event detaches, it does not reinstate, even with the .each function attaching the _wheelZoomevent obj reference. – Union find May 02 '15 at 19:23