如何使 geoAlbersUSA 投影像 geoMercator 一样是直的(不是弯的)?

问题描述 投票:1回答:1

我按照一个指南在d3js中创建一个基本的美国地图。

指南链接- http:/bl.ocks.orgmichellechandra0b2ce4923dc9b5809922。.


我已经了解了GeoJSON和地图投影的基础知识。

目前我的地图是这样的--(地图1) - 这使用 d3.geoAlbersUsa() 投影enter image description here

我希望我的地图是这样的--(地图2)。- 即上面不是弧形,而是直线的边界

联系 https:/www.worldatlas.comwebimagecountrysnamericausstatesusa50mer.htm

enter image description here

所需经费 -

  1. 我想保持阿拉斯加和夏威夷在地图上的可见性,就像在这两张图片中一样。

我已经尝试过什么了

  1. 我曾尝试使用 d3.geoMercator() 但阿拉斯加太大,无法放入视口,而且位于左上角,我不希望这样。
d3.js gis geojson
1个回答
2
投票

你不能把Albers拉直。阿尔伯斯投影是一个圆锥投影--平行线的大小不一样,因为它们是投影到圆锥上的,这意味着会有一条曲线,因为投影的长度不一样(平行线在地球仪上的长度也不一样)。

圆柱形的墨卡托投影将较短的平行线拉伸到与赤道相同的宽度,这就是为什么在墨卡托投影中平行线是直的、水平的、长度相等的原因。

我们可以滥用Albers投影来熨平一些曲线,但d3的geoAlbersUsa投影是一个复合投影,不允许进行这样的修改。它实际上只是一个投影的集合。

相反,我们可以使用 d3.geoTransform 和 d3.geoMercator 创建我们自己的复合投影。结果应该是这样的。

enter image description here

这是一个简单的d3.geoTransform:

  let projection = d3.geoTransform({
      point: function(x, y) {
          this.stream.point(x*2,y*2);
      }
    });

这只是将x和y的值乘以2, 它可以像这样传递给路径生成器: d3.geoPath(projection);

为了做一个复合投影,我们需要正确设置三个投影,然后正确地转化到地图上。我建立这些投影的时候是假设一个960x500的地图(类似于d3.geoAlbersUsa)。

  let scale = 800;
  let width = 960;
  let height = 500;

  let continental = d3.geoMercator()
    .center([-98.58,39.83])
    .translate([width*0.5,height*0.42])  // placed near center
    .scale(scale);

  let hawaii = d3.geoMercator()
    .center([-157.25,20.8])
    .scale(scale)
    .translate([width*0.35,height*0.87])  // placed near bottom, slightly left of center

  let alaska = d3.geoMercator()
    .center([-152.5,65])
    .translate([width*0.15,height*0.8])    // placed in lower left
    .scale(scale*0.3)

Mercator在移动到极端纬度的时候会夸大面积,所以阿拉斯加,在地理上已经很大了(超过德克萨斯的两倍),变成了 很多 投影时太大。我已经把它缩小了,所以它是合适的(这样一来,它的尺寸大约是其他投影尺寸的110倍)。

我们还需要选择什么时候使用什么投影,所以根据一些规则,我们可以确定一个点是在阿拉斯加,夏威夷,还是在下层48。

  let projection = d3.geoTransform({
      point: function(x, y) {
        if(y < 50 && x < -140) {  // south and west : hawaii
          this.stream.point(...hawaii([x,y]));
        }
        else if (y > 50) {       // north : alaska
          this.stream.point(...alaska([x,y]));
        }
        else {                    // otherwise, it's in the lower 48.
          this.stream.point(...continental([x,y]));
        }
      }
    });

就这样,我们有了三个投影和一个方法 来确定一个点应该使用哪一个投影。

我就把它全部捆绑为 d3.geoMercatorUsa() 以使其更加自如,我们得到。

// Composite Mercator projection for the US
d3.geoMercatorUsa = function() {
  let scale = 800;
  let width = 960;
  let height = 500;

  let continental = d3.geoMercator()
    .center([-98.58,39.83])
    .translate([width*0.5,height*0.42])
    .scale(scale);

  let hawaii = d3.geoMercator()
    .center([-157.25,20.8])
    .scale(scale)
    .translate([width*0.35,height*0.87])

  let alaska = d3.geoMercator()
    .center([-152.5,65])
    .translate([width*0.15,height*0.8])
    .scale(scale*0.3)

  let projection = d3.geoTransform({
      point: function(x, y) {
        if(y < 50 && x < -140) {
          this.stream.point(...hawaii([x,y]));
        }
        else if (y > 50) {
          this.stream.point(...alaska([x,y]));
        }
        else {
          this.stream.point(...continental([x,y]));
        }
      }
    });
    return projection;
}

// Demonstration:
let width = 960;
let height = 500;

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

let path = d3.geoPath(d3.geoMercatorUsa());  
  
d3.json("https://raw.githubusercontent.com/johan/world.geo.json/master/countries/USA.geo.json").then(function(data) {

   svg.append("path")
     .datum(data)
     .attr("d",path);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
© www.soinside.com 2019 - 2024. All rights reserved.