【问题标题】:d3 geo projection transitions from orthographic to Xd3 地理投影从正交过渡到 X
【发布时间】:2021-01-01 20:10:25
【问题描述】:

我正在开发一个显示不同地图投影的教育地图项目。我想在选择不同的投影之间实现变形过渡。

我找到了一个很好的例子来实现它,并且我没有太多麻烦来重新创建它。不幸的是,我还需要剪辑投影的能力。这对目标状态完美无缺,但在变形投影时却不行。

在此示例中,您可以在选择“正交”作为第一个投影时看到它,例如“Equilectangular”为第二个: https://bl.ocks.org/alexmacy/082cb12c8f4d5c0d5c4445c16a3db383

剪切路径遵循较暗的线,而不是当前地图范围。有没有办法正确实现?

【问题讨论】:

  • 如果您愿意作弊,您可以将逆子午线剪裁与剪裁角度结合起来:eg,但如果没有创建新的预剪裁功能,您最好的选择可能是叠加第二组使用剪辑角度为 90 的第二个投影(也是插值)在第一个上的特征,有点 hacky,但我的链接也是如此。
  • 嘿,@AndrewReid 你是我的英雄!感谢您指出此解决方案。如果您将此添加为回复,我将接受它作为解决方案!
  • 填充球体不能解决问题吗?地图是透明的,也许我们只是因为它而看到了额外的东西。

标签: d3.js map-projections


【解决方案1】:

实现起来比看起来要复杂得多,我记得几年前看过这个。最干净的解决方案是创建一个新的预剪裁函数,该函数确定投影地球的哪些部分应位于更靠近原点的部分后面/覆盖。但事实证明,这相对难以定义 - 至少我的我 - 也很难在新的预剪裁功能中使用。

相反,我们可以作弊。有几种方法,我会提出一种几乎可以解决问题的方法——不过你仍然可以看到一些重叠。我们将使用 d3 的逆子午线预剪裁来确保没有任何特征超出逆子午线,然后我们将使用剪裁角度来移除需要移除的地球部分。

设置剪辑角度

当混合投影正交时,剪裁角很大:剪裁角在所有方向上都相同。这里应该是 90 度。

当等距矩形在混合投影中占主导地位时,不需要剪裁角度(我使用 180 度的角度,不会剪裁下方的任何东西)。这是因为整个地球应该仍然可见。

但除此之外,混合夹角在所有方向上都不相同 - 这就是为什么这不是一个完美的解决方案。但是,它确实消除了几乎所有的重叠。因此,当我们从主要是等矩形投影到完全正交投影时,我们会慢慢减小剪辑角度。

示例

从 equirectangular 投影开始并过渡到正交投影,只有在过渡到 40% 时,我们才会开始将 clipAngle 从 180 度过渡到 90 度:

function getProjection(d) {
    var clip = Math.PI;  // Starting with 180 degrees: don't clip anything.
    var projection = d3.geoProjection(project)
        .rotate([posX, posY])
        .fitExtent([[10, 10], [width - 10, height - 10]], {
          type: "Sphere"
        })
        // Apply the two pre clipping functions:
        .preclip( function(stream){
            stream = d3.geoClipAntimeridian(stream) // cut antimeridian
            return d3.geoClipCircle(clip)(stream)   // apply clip angle
        })
        
    var path = d3.geoPath(projection);

    function project(λ, φ) {
      λ *= 180 / Math.PI, 
      φ *= 180 / Math.PI;

      var p0 = projections[0]([λ, φ]), 
          p1 = projections[1]([λ, φ]);

       // Don't actually clip anything until t == 0.4
       if(t > 0.4) {          
        clip = Math.PI/2 + (0.60-(t-0.4)) * Math.PI/2
       }
      
          
      return [
        (1 - t) * p0[0] + t * p1[0], 
        (1 - t) * -p0[1] + t * -p1[1]
        ];
    }

    return path(d)
  }

这是example

【讨论】:

【解决方案2】:

很好的答案安德鲁·里德!我只是做了一个小改动。我删除了t > 0.4 if 语句并使用此剪辑转换为正射投影

clip = Math.PI/2 + (1 - t) * Math.PI/2

.. 以及用于从正交投影过渡出来的剪辑:

clip = Math.PI/2 + t * Math.PI/2

我喜欢这个,因为它稍微干净一些,是任何 t 值的“包罗万象”,并且反过来也很有用。

【讨论】:

  • 哈哈,好笑。经过数小时的反复试验,我在生成的代码中做了完全相同的事情:D
猜你喜欢
  • 1970-01-01
  • 2015-06-14
  • 1970-01-01
  • 2013-06-28
  • 2012-08-14
  • 2013-06-07
  • 2016-09-11
  • 1970-01-01
  • 2015-07-27
相关资源
最近更新 更多