gpt4 book ai didi

d3.js - 预投影几何 v 让浏览器来做(又名效率 v 灵活性)

转载 作者:行者123 更新时间:2023-12-04 23:14:05 27 4
gpt4 key购买 nike

为了提高我的在线 map 的性能,尤其是在智能手机上,我遵循 Mike Bostock 的建议,在将地理数据上传到服务器之前尽可能多地准备地理数据(根据他的 command-line cartography)。例如,我正在投影 TopoJSON 数据,通常通过 d3.geoConicEqualArea() , 在加载 map 时,在命令行而不是让查看器的浏览器执行这些繁琐的工作。

但是,我也想使用 .scale 之类的方法, .fitSize , .fitExtent.translate动态地,这意味着我无法预先“烘焙”比例或将值转换为 TopoJSON 文件。

Bostock recommends使用 d3.geoTransform()作为预测的代理 d3.geoConicEqualArea()如果您正在处理已经投影的数据,但仍想对其进行缩放或转换。例如,要翻转 y 轴上的投影,他建议:

var reflectY = d3.geoTransform({
point: function(x, y) {
this.stream.point(x, -y);
}
}),

path = d3.geoPath()
.projection(reflectY);

我的问题:如果我使用这个D3功能,我不是还在强制浏览器的浏览器做大量的数据处理,这会恶化性能吗?预处理数据的目的是避免这种情况。还是我高估了 d3.geoTransform()所涉及的处理工作?上面的功能?

最佳答案

If I use this D3 function, aren't I still forcing the viewer's browser to do a lot of data processing, which will worsen the performance? The point of pre-processing the data is to avoid this. Or am I overestimating the processing work involved in the d3.geoTransform() function above?



简短回答:您高估了转换投影数据所需的工作量。

D3 地理投影的球形性质

d3 geoProjection 相对独特。许多平台、工具或库采用由纬度和经度对组成的点,并将它们视为在笛卡尔平面上。这在很大程度上简化了数学计算,但需要付出代价:路径遵循笛卡尔路由。

D3 将经度纬度点视为它们的本质:三维椭球上的点。这在计算上花费更多,但提供了其他好处——例如沿大圆路线路由路径段。

将坐标视为 3d 地球上的点时产生的额外计算成本 d3 是:
  • 球面数学

  • 在缩放、居中等之前先看一个简单的地理投影:
    function mercator(x, y) {
    return [x, Math.log(Math.tan(Math.PI / 4 + y / 2))];
    }

    这可能比您上面建议的转换需要更长的时间。
  • 路径

  • 在笛卡尔平面上,两点之间的线很容易,在球面上,这很难。取一条从东经 179 度延伸到西经 179 度的线 - 将它们视为在笛卡尔平面上很容易 - 在地球上画一条线。在球形地球上,这条线穿过反子午线。

    因此,在展平路径时,需要沿路线采样,点之间的大圆距离需要弯曲,因此需要额外的点。我不确定 d3 中的这个过程,但肯定会发生。

    笛卡尔平面上的点不需要额外的采样——它们已经是平的,点之间的线是直的。无需检测线是否以另一种方式环绕地球。

    操作岗位投影

    一旦投影,像 .fitSize 这样的东西将强制执行额外的工作,这本质上是你用 d3.geoTransform() 提出的:需要根据它们的投影位置和大小来转换和缩放特征。

    当自动居中特征时,这在 d3v3(在有 fitSize() 之前)中非常明显:计算涉及投影特征的 svg 范围。

    基本准科学性能比较

    使用美国人口普查局的shapefile,我创建了三个geojson文件:
  • 一个使用 WGS84(长/纬度)(文件大小:389 kb)
  • 一个在节点中使用 geoproject 和一个普通的 d3.geoAlbers 变换(文件大小:386 kb)
  • 一个在节点中使用 geoproject 与 d3.geoAlbers().fitSize([500,500],d) (文件大小 385 kb)

  • 速度的黄金标准应该是选项 3,数据根据预期的显示范围进行缩放和居中,这里不需要转换,我将使用零投影来测试它

    我继续使用以下方法将这些投影到 500x500 svg:
    //  For the unprojected data
    var projection = d3.geoAlbers()
    .fitSize([500,500],wgs84);

    var geoPath = d3.geoPath().projection(projection)


    // for the projected but unscaled and uncentered data
    var transform = d3.geoIdentity()
    .fitSize([500,500],albers);

    var projectedPath = d3.geoPath()
    .projection(transform);

    // for the projected, centered, and scaled data
    var nullProjection = d3.geoPath()

    运行数百次,我得到了以下平均渲染时间(数据已预加载):
  • 71 毫秒:WGS84
  • 33 毫秒:投影但未缩放且未居中
  • 21 毫秒:投影、缩放和居中

  • 我可以放心地说,无论数据是否真正居中和缩放,预投影数据都会带来显着的性能提升。

    注意我使用了 d3.geoIdentity()而不是 d3.geoTransform()因为它允许使用 fitSize() ,如果需要,您可以在 y 上反射(reflect): .reflectY(true);

    关于d3.js - 预投影几何 v 让浏览器来做(又名效率 v 灵活性),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47545480/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com