How to accurately zoom d3 maps which have already been translated

ぃ、小莉子 提交于 2019-12-10 18:42:30

问题


I have a map which has been translated to make it fit on the canvas properly.

I'm trying to implement a way to zoom it and it does work, but it moves away from center when you zoom in, rather than centering on the mouse or even the canvas.

This is my code:

function map(data, total_views) {
  var xy = d3.geo.mercator().scale(4350),
      path = d3.geo.path().projection(xy),
      transX = -320,
      transY = 648,
      init = true;

  var quantize = d3.scale.quantize()
    .domain([0, total_views*2/Object.keys(data).length])
    .range(d3.range(15).map(function(i) { return "map-colour-" + i; }));

  var map = d3.select("#map")
        .append("svg:g")
        .attr("id", "gb-regions")
        .attr("transform","translate("+transX+","+transY+")")
        .call(d3.behavior.zoom().on("zoom", redraw));

  d3.json(url_prefix + "map/regions.json", function(json) {
    d3.select("#regions")
        .selectAll("path")
            .data(json.features)
        .enter().append("svg:path")
            .attr("d", path)
            .attr("class", function(d) { return quantize(data[d.properties.fips]); });
  });

  function redraw() {
    var trans = d3.event.translate;
    var scale = d3.event.scale;

    if (init) {
      trans[0] += transX;
      trans[1] += transY;
      init = false;
    }
    console.log(trans);

    map.attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");
  }
}

I've found that adding the initial translation to the new translation (trans) works for the first zoom, but for all subsequent zooms it makes it worse. Any ideas?


回答1:


Here's a comprehensive starting-point: semantic zooming of force directed graph in d3

And this example helped me specifically (just rip out all the minimap stuff to make it simpler): http://codepen.io/billdwhite/pen/lCAdi?editors=001

 var zoomHandler = function(newScale) {
        if (!zoomEnabled) { return; }
        if (d3.event) {
            scale = d3.event.scale;
        } else {
            scale = newScale;
        }
        if (dragEnabled) {
            var tbound = -height * scale,
                bbound = height  * scale,
                lbound = -width  * scale,
                rbound = width   * scale;
            // limit translation to thresholds
            translation = d3.event ? d3.event.translate : [0, 0];
            translation = [
                Math.max(Math.min(translation[0], rbound), lbound),
                Math.max(Math.min(translation[1], bbound), tbound)
            ];
        }

        d3.select(".panCanvas, .panCanvas .bg")
            .attr("transform", "translate(" + translation + ")" + " scale(" + scale + ")");

        minimap.scale(scale).render();
    }; // startoff zoomed in a bit to show pan/zoom rectangle

Though I had to tweak that function a fair bit to get it working for my case, but the idea is there. Here's part of mine. (E.range(min,max,value) just limits value to be within the min/max. The changes are mostly because I'm treating 0,0 as the center of the screen in this case.

// limit translation to thresholds
            var offw = width/2*scale;
            var offh = height/2*scale;
            var sw = width*scale/2 - zoomPadding;
            var sh = height*scale/2- zoomPadding;

            translate = d3.event ? d3.event.translate : [0, 0];
            translate = [
                E.range(-sw,(width+sw), translate[0]+offw),
                E.range(-sh,(height+sh), translate[1]+offh)
            ];
        }


        var ts = [translate[0], translate[1]];
        var msvg  = [scale, 0, 0, scale, ts[0], ts[1]];


来源:https://stackoverflow.com/questions/13802218/how-to-accurately-zoom-d3-maps-which-have-already-been-translated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!