【问题标题】:D3 Topojson Circle with Radius Scaled in Miles半径以英里为单位的 D3 Topojson 圆
【发布时间】:2017-08-14 23:54:34
【问题描述】:

(假设现有的投影/topojson)

我要做的是在半径 (r) 以英里为单位的点 ([long,lat]) 创建一个圆。我知道这有一个 d3.geo 函数,但经过一番考虑,我认为它与我的特定应用程序不太兼容。

所以现在我正在寻找使用原生 svg circle 解决方案,其中 cx 和 cy 是纬度和经度,r 是以英里为单位的半径。我知道 cx 和 cy,但我不知道如何确保 r 是 15 英里。所以主要是如何确保在像素空间中绘制半径时以英里为单位。一定有办法使用projection 函数来设置半径的适当比例。但我在实践中还没有看到过。

另外我应该指出,我的投影是动态的,取决于用户事件,投影(包括比例)可以改变。因此,我不确定这是否会影响圆圈在现有投影的上下文中的缩放方式,但我认为为了安全起见,我会披露这一点。

【问题讨论】:

  • 需要考虑的几个问题:正如您所指出的,1 英里是一个可变距离(以像素为单位),具体取决于用户的位置。投影函数对于以单位为单位的基础地图的距离是天真的。您需要某种方式来告知投影函数您的 topojson 文件中的 1 英里。一种方法是将距离计算为弧度中地球周围距离的比例。见这里:bl.ocks.org/thomasthoren/6a543c4d804f35a240f9
  • 是的,我知道这个块,我在之前的研究中看到过它。然而,它与像素函数的距离有点长,他承认他的数学可能不是 100% 正确的。我希望通过提供赏金,我能够看看是否有任何更精致的替代品。

标签: javascript d3.js topojson


【解决方案1】:

为什么不使用内置的圆圈生成器d3.geoCircle()

返回一个“多边形”类型的新 GeoJSON 几何对象,该对象近似于球体表面上的一个圆,当前为 centerradiusprecision。任何参数都会传递给访问器。

剩下的唯一任务就是计算圆的半径(以度为单位)。因为地球不是一个完美的球体,所以这本身就很具有挑战性。但是对于许多应用来说,一个近似值就足够了。仅考虑 3,958 英里mean radius,计算可写为:

var EARTH_RADIUS = 3959;                         // mean radius in miles
var radiusMi     = 5;                            // radius to be drawn in miles
var radiusDeg    = radiusMi / EARTH_RADIUS * 90; // radius in degrees for circle generator

然后可以将其传递给圆生成器:

var circle = d3.geoCircle().radius(radiusDeg);

最后,圆生成器用于通过数据绑定将其输出传递到考虑投影的适当路径生成器:

svg.append("path")
  .datum(circle)
    .attr("d", path);

看看这个Block,它在全球不同的位置都有半径为 50 英里的圆圈。圆形生成器与投影相结合将控制正确的大小和正确的圆形外观。


D3 v3

如果您仍然坚持使用 D3 v3,则该示例也适用。但是,您需要相应地调整names

除此之外,圆生成器的一些方法已被重命名:

将这些调整应用于我上面链接的块,这也适用于 v3:v3 Block


当涉及到严重扭曲的异常投影时,这种方法可以发挥其优势。只需将块中的投影更改为d3.geoGnomonic(),就可以很容易地看到它。更新后的Block 的以下屏幕截图仍然显示与上述相同的圆圈,每个圆圈的半径为 50 英里:

【讨论】:

  • 很好的解释,它帮助我理解大局。让我玩弄它然后回复你。
  • 经过更多测试,我必须坚持我在帖子前几行中提到的评估。使用原生 svg 圈子会让我的生活更轻松。但是,您在这里的答案得到了很好的解释,因此我很乐观,并从怀疑中受益。我可能无法将它用于我原来的圆形应用程序(需要 svg),但我仍然尝试在 this 最小块中测试你的 d3.geo。我正在使用 d3 v3。虽然不工作。所以如果不介意加倍努力,你能解决这两个问题吗?
  • 暂时将原生 svg 圆圈放在一边。我会假设 d3.geo.circle 可以做所有原生 svg circles 可以做的事情,一旦我更了解它。不要误会我的意思,我正在为这种方法做准备,但这有点挑战性,因为管道中的东西是 svg 圆圈,我的环境需要类似的接口。例如,我需要能够动态更改半径。使用本机 svg:my_circle.attr({r:my_new_radius_value}) 但是,当我尝试my_geo_circle.angle(my_new_radius_value) 时,我没有遇到函数错误。有没有办法解决这个问题?
  • 添加后:my_geo_circle.datum(new_circle).attr(d, geo_path) 我可以动态更改半径。忍受我的学习曲线,我不是制图工具棚中最锋利的工具。无论如何,您的解决方案最终效果很好,非常感谢。我特此奖励你 50 赏金!
  • radiusMi / EARTH_RADIUS * 90 错了吗?我想你需要radiusMi / EARTH_RADIUS * 360 / (2 * Math.PI)
猜你喜欢
  • 2015-10-12
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-16
  • 2016-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多