应用缩放后,确定地图上以点为单位的lat / lng中的坐标

时间:2014-11-12 02:32:50

标签: d3.js zoom geo

我尝试使用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]);

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

1 个答案:

答案 0 :(得分:0)

在应用缩放后,我还没有找到从像素点到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 ];
}