【问题标题】:D3 Geo map zoom is not working correctly (Canvas)D3 地理地图缩放无法正常工作(画布)
【发布时间】:2018-08-10 07:18:31
【问题描述】:

我正在尝试在画布中缩放地图。

var projection = d3.geoMercator()
projection.fitExtent([[margin.left, margin.top], [width, height]], land);
var path = d3.geoPath().projection(projection).context(context);

当我将翻译和缩放应用到画布上下文时,它可以完美运行。但是当我调用var latlong = projection.invert(d3.mouse(this)); 时它没有返回正确的纬度和经度,因为投影没有相应地翻译。

var zoom = d3.zoom()
    .scaleExtent([1, Infinity])
    .on("zoom", zoomByContext);

function zoomByContext() {
    var transform = d3.event.transform;
    context.clearRect(0, 0, width, height);
    context.save();
    context.translate(transform.x, transform.y);
    context.lineWidth = 0.5 / transform.k;
    context.scale(transform.k, transform.k);
    renderFeature();
    context.restore();
}

所以我尝试像打击一样重新投影投影。但是当我使用下面的代码进行缩放时,它会转到左上角。

var zoom = d3.zoom()
    .scaleExtent([1, Infinity])
    .on("zoom", zoomByProjection);

function zoomByProjection() {
    var transform = d3.event.transform;
    projection.translate([transform.x, transform.y]);
    projection.scale(scale * transform.k);
    renderFeature();
}

我已经像这样调用了缩放

canvas.call(zoom, d3.zoomIdentity
.translate(projection.translate())
.scale(projection.scale()));

【问题讨论】:

    标签: javascript d3.js zooming


    【解决方案1】:

    对于第一种方法,您需要在将 xy 坐标反转为长纬度坐标之前反转缩放:

    var transform = d3.zoomTransform(this);
    var xy = transform.invert(d3.mouse(this));         
    var longlat = projection.invert(xy);
    

    我们以像素坐标获取鼠标位置,将其反转为缩放坐标,然后将其反转为地理坐标。

    这应该证明上述内容:

    var width = 960;
    var height = 500;
    
    var canvas = d3.select("canvas");
    var context = canvas.node().getContext("2d")
    var projection = d3.geoMercator();
    var path = d3.geoPath(projection,context);
    	
    
    d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
      if (error) throw error;
      
    renderFeature();
    
    var zoom = d3.zoom()
        .scaleExtent([1, Infinity])
        .on("zoom", zoomByContext);
    
    canvas.call(zoom);
    	
      function zoomByContext() {
        var transform = d3.event.transform;
        context.clearRect(0, 0, width, height);
        context.save();
        context.translate(transform.x, transform.y);
        context.lineWidth = 0.5 / transform.k;
        context.scale(transform.k, transform.k);
        renderFeature();
        context.restore();
      }
      function renderFeature() {
        context.beginPath();
        path(topojson.mesh(world));
        context.stroke();	
      }
      
      canvas.on("click", function() {
    	var transform = d3.zoomTransform(this);
    	var xy = transform.invert(d3.mouse(this));         
    	var longlat = projection.invert(xy);
        console.log(longlat);
      })
    
      
      
    });
    <canvas width="960" height="500"></canvas>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://unpkg.com/topojson-client@3"></script>

    第二种方法有点棘手,如果投影的翻译是[0,0],那么您的方法将起作用,但这种情况很少见。默认值为[480,250](假设画布为960x500),fitSize 和fitExtent 不通过修改旋转和居中来定位特征,而是平移。因此,您需要在修改投影时考虑初始平移(就像您对比例所做的那样):

    var transform = d3.event.transform;
    projection.translate([transform.x+translate[0]*transform.k, transform.y+translate[1]*transform.k]);
    projection.scale(scale * transform.k);
    

    这里的translate 是一个保存初始翻译值的数组

    这是一个应该演示上述内容的演示:

    var width = 960;
    var height = 500;
    
    var canvas = d3.select("canvas");
    var context = canvas.node().getContext("2d")
    var projection = d3.geoMercator().center([105,3]).scale(1200).translate([2000,0]);
    var path = d3.geoPath(projection,context);
    var scale = projection.scale();
    var translate = projection.translate();
    
    
    
    d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
      if (error) throw error;
    
    renderFeature();
      
    var zoom = d3.zoom()
        .scaleExtent([0.1, Infinity])
        .on("zoom", zoomByProjection);
    
    canvas.call(zoom);
    	
    function zoomByProjection() {
        context.clearRect(0, 0, width, height);
        var transform = d3.event.transform;
        projection.translate([transform.x+translate[0]*transform.k, transform.y+translate[1]*transform.k]);
        projection.scale(scale * transform.k);
        renderFeature();
    }
      
      function renderFeature() {
        context.beginPath();
        path(topojson.mesh(world));
        context.stroke();	
      }
    
    });
    <canvas width="960" height="500"></canvas>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://unpkg.com/topojson-client@3"></script>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-07
      • 2014-03-06
      • 2021-04-04
      • 2013-04-17
      • 1970-01-01
      • 2016-03-19
      • 1970-01-01
      相关资源
      最近更新 更多