d3.geoPath() 的设置投影未按记录工作

Setting projection of d3.geoPath() not working as documented

我在 D3 中制作了很多地图,但从未遇到过输出太小以至于看不到的问题。我包含了一个小的 geojson 文件,可以使用各种其他工具轻松查看它 (e.g. here)。

似乎未使用 d3.geoPath() 正确设置投影。 The API 指定 d3.geoPath() 采用投影参数,但是当我尝试使用此方法设置投影时(如下例所示),生成的地图未正确投影。只有在我使用 d3.geoPath().projection() 方法设置投影后,我才获得正确的结果。

这是文档中的错误还是我遗漏了什么?

//setup and map parameters
var height = 300;
var width = 300;
var projection = d3.geoAlbers().scale(1000).translate([width/2, height/2]);
var path = d3.geoPath(projection);

//geoJSON data
var geojson = 
{"type":"FeatureCollection","features":[
{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-86.910592,33.536105],[-86.907192,33.542204999999996],[-86.90539199999999,33.541305],[-86.901608,33.543456],[-86.895692,33.548805],[-86.89249199999999,33.550404],[-86.888392,33.549304],[-86.879772,33.553267999999996],[-86.868549,33.553418],[-86.8651,33.557134999999995],[-86.856129,33.562064],[-86.85159499999999,33.559404],[-86.848891,33.559805],[-86.852991,33.552104],[-86.85519099999999,33.543904999999995],[-86.855694,33.538151],[-86.860817,33.53405],[-86.850509,33.535693],[-86.83124699999999,33.544767],[-86.827029,33.534708],[-86.82383999999999,33.533389],[-86.826703,33.528081],[-86.826807,33.521107],[-86.822808,33.514319],[-86.81474899999999,33.502386],[-86.81411899999999,33.500078],[-86.816041,33.496234],[-86.823825,33.488839],[-86.825743,33.485408],[-86.82772299999999,33.477393],[-86.828558,33.472626999999996],[-86.82791,33.46967],[-86.833503,33.467552999999995],[-86.839366,33.463845],[-86.841534,33.460941],[-86.842309,33.465699],[-86.849758,33.466302],[-86.861663,33.456759],[-86.869367,33.4514],[-86.87749699999999,33.449382],[-86.884293,33.445453],[-86.88948599999999,33.441072999999996],[-86.890131,33.438437],[-86.899491,33.434508],[-86.908391,33.429308],[-86.922929,33.415512],[-86.925484,33.419897999999996],[-86.93114299999999,33.422801],[-86.93749199999999,33.421608],[-86.945352,33.425982999999995],[-86.946468,33.428407],[-86.937809,33.435314],[-86.925764,33.449968999999996],[-86.920859,33.454651999999996],[-86.92215,33.456643],[-86.927679,33.453849999999996],[-86.932965,33.449332],[-86.935435,33.446132],[-86.94133699999999,33.442150999999996],[-86.941301,33.445651999999995],[-86.942842,33.450103],[-86.946817,33.45017],[-86.95131599999999,33.45181],[-86.950279,33.458104],[-86.945494,33.463234],[-86.929693,33.478538],[-86.92935299999999,33.479858],[-86.920255,33.492874],[-86.92450699999999,33.493904],[-86.93110999999999,33.496843],[-86.933543,33.494935999999996],[-86.94144999999999,33.494743],[-86.944717,33.495934],[-86.946237,33.502279],[-86.946224,33.506071],[-86.941811,33.507621],[-86.937693,33.512206],[-86.92634,33.512381999999995],[-86.917255,33.517139],[-86.915435,33.519832],[-86.908779,33.518958999999995],[-86.903385,33.516537],[-86.898659,33.520165999999996],[-86.894459,33.526136],[-86.896992,33.530504],[-86.910592,33.536105]]]},"properties":{"a":1}}
]}

var svg = d3.select("#map");
svg.selectAll("path").data(geojson.features).enter().append("path").attr("fill","red").attr("d", path);
<script src="https://d3js.org/d3.v4.min.js"></script>

<svg height="300px" width="300px" id="map"> </svg>

您需要正确设置投影参数。 1 000 的比例因子对于显示示例中的小区域来说太小了。比例因子 50 000 可能更合适。您还需要正确居中地图。

您需要在地图项的中心附近找到一个点,以使地图正确居中。您可以通过使用 google earth 或其他方法在地理坐标(不是 svg 坐标)中找到路径质心来手动执行此操作;但是,您也可以通过翻译功能找到 svg 质心来优化投影,我是不过在我的回答中没有使用这种方法。

对于阿尔伯斯投影,您应该以 y 轴为中心并在 x 轴上旋转:

var projection = d3.geoAlbers()
   .rotate([-x,0])
   .center([0,y])
   .scale(k)
   .translate([width/2,height/2])

您想使用中央子午线的负值,因为您在地图下旋转了地球。有关 Albers 参数的更多图形说明,请参阅 this answer

d3 中的 Albers 投影具有默认的中心和旋转坐标。如果您不同时使用旋转和居中设置中心坐标,地图将保留旨在显示整个美国的默认参数;这将修改预期的投影。其他投影一般默认以d3中的[0,0]为中心,也就是非洲外海。

我用 google 地球观察了一个中心坐标用于此投影。我这里使用的对中点是:

86.884 degrees West (-86.884 degrees East)
33.507 degress North

我还使用 100 000 而不是 1 000 放大了比你原来的缩放因子更远。这是显示你的数据的投影:

//setup and map parameters
var height = 300;
var width = 300;
var projection = d3.geoAlbers()
   .scale(100000)
   .translate([width/2, height/2])
   .rotate([86.884,0])
   .center([0,33.507]);
var path = d3.geoPath(projection);

//geoJSON data
var geojson = 
{"type":"FeatureCollection","features":[
{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-86.910592,33.536105],[-86.907192,33.542204999999996],[-86.90539199999999,33.541305],[-86.901608,33.543456],[-86.895692,33.548805],[-86.89249199999999,33.550404],[-86.888392,33.549304],[-86.879772,33.553267999999996],[-86.868549,33.553418],[-86.8651,33.557134999999995],[-86.856129,33.562064],[-86.85159499999999,33.559404],[-86.848891,33.559805],[-86.852991,33.552104],[-86.85519099999999,33.543904999999995],[-86.855694,33.538151],[-86.860817,33.53405],[-86.850509,33.535693],[-86.83124699999999,33.544767],[-86.827029,33.534708],[-86.82383999999999,33.533389],[-86.826703,33.528081],[-86.826807,33.521107],[-86.822808,33.514319],[-86.81474899999999,33.502386],[-86.81411899999999,33.500078],[-86.816041,33.496234],[-86.823825,33.488839],[-86.825743,33.485408],[-86.82772299999999,33.477393],[-86.828558,33.472626999999996],[-86.82791,33.46967],[-86.833503,33.467552999999995],[-86.839366,33.463845],[-86.841534,33.460941],[-86.842309,33.465699],[-86.849758,33.466302],[-86.861663,33.456759],[-86.869367,33.4514],[-86.87749699999999,33.449382],[-86.884293,33.445453],[-86.88948599999999,33.441072999999996],[-86.890131,33.438437],[-86.899491,33.434508],[-86.908391,33.429308],[-86.922929,33.415512],[-86.925484,33.419897999999996],[-86.93114299999999,33.422801],[-86.93749199999999,33.421608],[-86.945352,33.425982999999995],[-86.946468,33.428407],[-86.937809,33.435314],[-86.925764,33.449968999999996],[-86.920859,33.454651999999996],[-86.92215,33.456643],[-86.927679,33.453849999999996],[-86.932965,33.449332],[-86.935435,33.446132],[-86.94133699999999,33.442150999999996],[-86.941301,33.445651999999995],[-86.942842,33.450103],[-86.946817,33.45017],[-86.95131599999999,33.45181],[-86.950279,33.458104],[-86.945494,33.463234],[-86.929693,33.478538],[-86.92935299999999,33.479858],[-86.920255,33.492874],[-86.92450699999999,33.493904],[-86.93110999999999,33.496843],[-86.933543,33.494935999999996],[-86.94144999999999,33.494743],[-86.944717,33.495934],[-86.946237,33.502279],[-86.946224,33.506071],[-86.941811,33.507621],[-86.937693,33.512206],[-86.92634,33.512381999999995],[-86.917255,33.517139],[-86.915435,33.519832],[-86.908779,33.518958999999995],[-86.903385,33.516537],[-86.898659,33.520165999999996],[-86.894459,33.526136],[-86.896992,33.530504],[-86.910592,33.536105]]]},"properties":{"a":1}}
]}

var svg = d3.select("#map");
svg.selectAll("path").data(geojson.features).enter().append("path").attr("fill","red").attr("d", path);
<script src="https://d3js.org/d3.v4.min.js"></script>

<svg height="300px" width="300px" id="map"> </svg>