【问题标题】:Determining coordinates in lat/lng of a point in pixels on a map after zoom has been applied应用缩放后确定地图上像素点的纬度/经度坐标
【发布时间】:2015-01-08 18:59:45
【问题描述】:

我正在尝试使用 d3 确定地图上像素点的坐标。最终目标是确定哪些国家目前在地图上可见。 这是我正在使用的代码:

method: function() {
    var e = $("#" + this.getView().getId());
    if (!e || e.length === 0) {
        return;
    }
    this.width = e.width();
    this.height = e.height();

    this.topojson = window.topojson;
    var width = this.width;
    var height = this.height;
    var centered;
    var d3v3 = window.d3v3;

    var projection = d3v3.geo.mercator()
        .translate([width / 2, height / 2]);

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

    var svg = d3v3.select("#" + this.byId("map").getId());

    svg.selectAll("g").remove();

    svg
        .attr("width", width)
        .attr("height", height);

    svg.append("rect")
        .attr("class", "background")
        .attr("width", width)
        .attr("height", height)
        .on("click", clicked);

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

    d3v3.json(getPath("/110m_admin_0.json"), function(us) {
          g.append("g")
              .attr("id", "states")
              .attr("class", "counties")
            .selectAll("path")
              .data(topojson.feature(us, us.objects["110m_admin_0_"]).features)
            .enter().append("path")
              .attr("d", path)
              .attr("class", function(d) { return "q"+(Math.floor((Math.random() * 9) + 0)) + "-9"; });
        });

    var zoom = d3v3.behavior.zoom()
    .on("zoom",$.proxy(function() {
        var width1 = width/2;
        var height1 = height/2;
        var xt1 = d3v3.event.translate[0];
        var yt1 = d3v3.event.translate[1];
        var x = xt1;
        var y = yt1;
        x+=width1;
        y+=height1;
        var proj = projection.invert([x,y]);
        proj[0]*=-1;
        proj[1]*=-1;
        var closestCountry = this.closestCountry(proj);

        console.log(d3v3.event.scale + " | " + [x,y] + " | " + proj + " | " + closestCountry );

        g.attr("transform","translate("+
            d3v3.event.translate.join(",")+")scale("+d3v3.event.scale+")");
        g.selectAll("path")
            .attr("d", path.projection(projection));

    },this));

    svg.call(zoom);
}

此代码在缩放级别为 1 时有效,但在缩放级别更改时立即失败。

这是我尝试过的一些变体。

1)

var x = d3v3.event.translate[0];
var y = d3v3.event.translate[1];
x+=width/2;
y+=height/2;
var proj = projection.invert([x,y]);

2)

var x = d3v3.event.translate[0]/d3v3.event.scale;
var y = d3v3.event.translate[1]/d3v3.event.scale;
x+=width/2;
y+=height/2;
var proj = projection.invert([x,y]);

3)

var x = d3v3.event.translate[0];
var y = d3v3.event.translate[1];
x+=width/2*d3v3.event.scale;
y+=height/2*d3v3.event.scale;
var proj = projection.invert([x,y]);

4)

var x = d3v3.event.translate[0]/d3v3.event.scale;
var y = d3v3.event.translate[1]/d3v3.event.scale;
x+=width/2*d3v3.event.scale;
y+=height/2*d3v3.event.scale;
var proj = projection.invert([x,y]);

我注意到的一件事是,无论缩放级别如何,针对相同 [x,y] 点(例如 [1200,600])的 projection.invert() 总是返回相同的 lng/lat。此外,我所做的任何尝试都没有设法使 [x,y] 在不同的缩放级别上保持不变,因此除了平移和缩放之外,这里还有其他东西在起作用。我怀疑它可能与投影有关,但我仍然没有弄清楚是什么。

【问题讨论】:

  • 在进行 projection.invert() 之前,您需要考虑缩放和平移作为缩放的结果。您可以从缩放对象中检索这两者,因此您应该能够除以比例并平移缩放平移的反向以转换回默认像素坐标,然后可以将其传递给 projection.invert()
  • @BenLyall 谢谢你的评论。我已根据您的评论编辑了我的问题。
  • 现在我有更多的时间来思考和调查,您可以使用投影的内置 .translate() 和 .scale() 方法来完成为你工作。您可以查看bl.ocks.org/mbostock/2206340,看看它是否适合您。您应该能够更新投影的比例并从缩放行为转换,然后使用 projection.invert() 从像素位置获取纬度/经度。

标签: d3.js zooming geo


【解决方案1】:

应用缩放后,我还没有找到从像素点到 lng/lat 坐标或从像素点到国家/地区的方法。

话虽如此,我找到了另一种效果也很好的替代方法。我有一个所有国家的列表及其在 lng/lat 中的质心。从该列表中,我以像素为单位解析它们的位置,并根据比例和平移调整它们。最后,我找到最接近中心的那个。代码如下:

closest: function() {
    var p2 = [0,0];
    var d = [width/2,height/2];
    var scale = d3v3.event.scale;
    var translate = d3v3.event.translate;
    var min = Number.MAX_VALUE;
    var minCountry = null;
    for ( var key in this.centroids) {
        var p1 = projection(this.centroids[key]);
        p1[0]*=scale;
        p1[1]*=scale;
        p1[0]+=translate[0]-d[0];
        p1[1]+=translate[1]-d[1];
        var distance = Math.sqrt(Math.pow(p2[0] - p1[0],2) + Math.pow(p2[1] - p1[1],2));
        if (distance < min) {
            min = distance;
            minCountry = key;
        }
    }
    return [ minCountry, min ];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 2016-12-09
    • 2016-02-03
    • 1970-01-01
    相关资源
    最近更新 更多