如果我使用这个D3功能,我不还是在强迫观看者的浏览器吗?
做大量的数据处理,这会让性能变差吗?这
预处理数据的目的就是为了避免这种情况。或者我是
高估了 d3.geoTransform() 涉及的处理工作
上面的函数?
简短回答:您高估了转换投影数据所需的工作量。
D3 geoProjections 的球形性质
d3 geoProjection 相对独特。许多平台、工具或库采用由纬度和经度对组成的点,并将它们视为位于笛卡尔平面上。这在很大程度上简化了数学计算,但代价是:路径遵循笛卡尔路由。
D3 按其本来面目对待经纬度点:三维椭球上的点。这需要更多的计算成本,但提供了其他好处 - 例如沿着大圆路线路由路径段。
将坐标视为 3d 地球上的点时 d3 产生的额外计算成本为:
- 球形数学
看一下简单的地理投影before缩放、居中等:
function mercator(x, y) {
return [x, Math.log(Math.tan(Math.PI / 4 + y / 2))];
}
这可能比您上面建议的转换需要更长的时间。
- Pathing
在笛卡尔平面上,两点之间的直线很容易,在球面上,这很困难。画一条从东经 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 上反映:.reflectY(true);