10

我创建了nycMap,一个使用 angularJS (MVC)、yeoman (build)、d3 (mapping) 和 geoJSON (geo data) 的项目。

一切都很好,但我确实必须花费相当多的时间来获得正确的比例和翻译。我想知道如何自动确定地图将以什么比例显示其最佳状态以及翻译中的 x 和 y 值?

'use strict';

japanAndCo2App.controller('MainCtrl', function($scope) {

 function makeJapanAll(){
    var path, vis, xy;

    xy = d3.geo.mercator().scale(16000).translate([-5600,2200]);
    path = d3.geo.path().projection(xy);
    vis = d3.select("#japanAll").append("svg:svg").attr("width", 1024).attr("height", 700);
    d3.json("data/JPN_geo4.json", function(json) {
      return vis.append("svg:g")
          .attr("class", "tracts")
          .selectAll("path")
          .data(json.features).enter()
          .append("svg:path")
          .attr("d", path)
          .attr("fill",function(d,i){ return d.properties.color || "transparent"});
    });
  }
  makeJapanAll();
});

(如果您对代码感兴趣,它都在 github 上。地图的代码在scripts/controllers/main.js中,与上图相同。)

4

3 回答 3

15

我有同样的问题。但是当你有一个边界框时,这很容易做到,这可以从 GeoJSON 中确定(就像 meetamit 说的那样),或者在创建 GeoJson 时。以及所需 SVG 的宽度。

我将从变量lattop, lonleft, lonright, widthheightgeojson 的边界框和图像的尺寸开始。我还没有忙于根据纬度差异计算一个合适的高度。所以高度只是估计足够大以适合图像。其余的应该从代码中清楚:

var xym = d3.geo.mercator();

// Coordinates of Flanders
var lattop = 51.6;
var lonleft = 2.4;
var lonright = 7.7;
var width = 1500;
var height =1000;

// make the scale so that the difference of longitude is 
// exactly the width of the image
var scale = 360*width/(lonright-lonleft);
xym.scale(scale);

// translate the origin of the map to [0,0] as a start, 
// not to the now meaningless default of [480,250]
xym.translate([0,0]);

// check where your top left coordinate is projected
var trans = xym([lonleft,lattop]);
// translate your map in the negative direction of that result
xym.translate([-1*trans[0],-1*trans[1]]);


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

var svg = d3.select("body").append("svg").attr("width",width).attr("height",height);

请注意,如果您越过日期变更线(180 度),则必须将溢出考虑在内。

于 2012-11-18T10:03:28.083 回答
8

鉴于这种:

xy = d3.geo.mercator().scale(someScale).translate([0, 0]);

someScale是使用墨卡托投影进行投影时整个世界的像素宽度。所以,如果你的 json 数据有整个世界的轮廓——从 lat/lng -180,90 到 latLng 180,-90——如果是 1024,那么世界将被绘制成完全适合 1024x1024 像素正方形。这就是您在此 Google 地图视图中看到的内容(嗯……有点……不完全……请继续阅读……)。someScale

但这还不够。当世界以 1024px 绘制时,没有任何平移,lat/lng 0,0(即世界的“中间”)将位于投影地图的 0,0 像素(即左上角)。在这些条件下,整个北半球和西半球的 x 或 y 值为负,因此落在绘制区域之外。此外,在这些条件下,世界的右下角(即 lat/lng -90, 180)将位于 1024x1024 正方形的正中间(即像素 512,512)。

因此,为了使世界在此处描述的正方形中居中,您需要translate将地图在 X 和 Y 方向上缩小一半宽度。即你需要

xy = d3.geo.mercator().scale(1024).translate([512, 512]);

这将为您提供我链接到的谷歌地图视图。

如果您的 json 数据只有世界的一部分(例如,纽约市或纽约州),则使用此 xy 投影绘制它会将轮廓呈现在相对于整个 1024x1024 跨世界区域的正确地理位置。所以它看起来很小,有很多空白。

挑战在于如何缩放和平移投影,以使相关区域充满 1024x1024 正方形。而且......到目前为止,我还没有回答这个问题,但我希望这个解释能够为您指明正确的方向来弄清楚这个数学。当我有更多时间时,我也会尝试继续回答。:/

于 2012-11-07T19:56:16.313 回答
0

这里有一个例子,它从 geojson 获取国家的边界​​,然后缩放并将地图转换到那个国家。代码有点难看;但是,将来会努力使这更容易(请参阅thisthis issue)。

于 2012-11-07T19:12:19.733 回答