【问题标题】:How to make geoAlbersUSA projection straight(not curved) like geoMercator?如何使 geoAlbersUSA 投影像 geoMercator 一样直(不弯曲)?
【发布时间】:2020-05-15 17:01:45
【问题描述】:

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

指南链接 - http://bl.ocks.org/michellechandra/0b2ce4923dc9b5809922.


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

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

我希望我的地图看起来像这样 -(地图 2) - 即不是在顶部弯曲而是在直线边界

链接https://www.worldatlas.com/webimage/countrys/namerica/usstates/usa50mer.htm

要求 -

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

我已经尝试过什么 -

  1. 我曾尝试使用d3.geoMercator() 投影,但阿拉斯加太大而无法放入视口,并且位于我不想要的左上角。

【问题讨论】:

    标签: d3.js gis geojson map-projections


    【解决方案1】:

    你不能把阿尔伯斯弄直。阿尔伯斯投影是圆锥投影 - 平行线的大小不同,因为它们被投影到圆锥上,这意味着由于投影长度不同(平行线在地球上的长度也不同),所以会有一条曲线。

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

    我们可以滥用 Albers 投影来消除某些曲线,但 d3 的 geoAlbersUsa 投影是不允许此类修改的复合投影。它实际上只是一个预测的集合。

    相反,我们可以使用 d3.geoTransform 和 d3.geoMercator 创建自己的复合投影。结果应如下所示:

    这是一个简单的 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)
    

    当一个人移动到极端纬度时,墨卡托确实夸大了尺寸,因此地理上已经很大(德克萨斯州的两倍多)的阿拉斯加在投影时变得太多太大了。我已经把它缩小了,所以它适合(这样它大约是预计大小的 1/10)。

    我们还需要选择什么时候使用什么投影,所以根据一些规则我们可以确定一个点是在阿拉斯加、夏威夷还是更低的 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);
    })
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 谢谢。这就是我想要达到的目标。谢谢你写了这么长的解释。它清除了很多东西。
    猜你喜欢
    • 2021-06-06
    • 2021-04-09
    • 2015-08-29
    • 1970-01-01
    • 2017-09-07
    • 2019-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多