D3 TopoJSON渲染神器

D3 TopoJSON rendering artifact

在我走得太远之前,我注意到我的 TopoJSON 中有一个相当奇怪的渲染工件,我无法解释。上面呈现的是在 TopoJSON World Atlas repository 上找到的官方 D3 发行版 countries-110m.json。正如您所看到的,俄罗斯北部的一部分在加拿大北部出现倒置 left/right。在我开始制定计划 B 之前,我的代码中是否有任何内容导致了此问题?

async function drawMap() {
    map_obj = await getRAWMapData(); // Map topojson
    const geojson_obj = topojson.feature(map_obj, map_obj.objects.countries);

    var projection = d3.geoIdentity().fitWidth(width, geojson_obj).reflectY(true); // Map Projection
    var path = d3.geoPath().projection(projection);

    paths = SVGmap.selectAll('path').data(geojson_obj.features).enter().append('path');

    paths
        .attr('d', path)
        .attr('fill', '#ddd')
        .attr('stroke', 'white')
        .attr('stroke-linejoin', 'round');
} 
drawMap();

问题

您正在使用球形数据并将其绘制在平面上(d3.geoIdentity),就好像数据是平面的一样。

俄罗斯在西半球有一部分领土 - 神器是路径渲染器从远东延伸到远西,然后又回来,因为绘制俄罗斯时路径数据穿过 anti-meridian .恒等变换“不知道”这应该包裹在一个球体后面——你只是获取纬度和经度并将其拉伸到屏幕上,就好像它是二维数据一样。

D3.geoIdentity() 拟合方法仅操纵数据的比例和平移 - 不考虑数据的 anti-meridian 或地理投影。

解决方案

使用投影 - D3 地理投影使用球面数学 - 它们切割穿过 anti-meridian 的特征(在本例中为 180 度 East/West)。在这种情况下,俄罗斯将由两个路径元素组成:一个在西方,一个在东方。这消除了在单个特征中连接两个部分所需的拉伸所产生的伪影。

所以,如果你想保持 plate carrée 的外观,你可以使用:

var projection = d3.geoEquirectangular().fitWidth...

任何 D3 投影都可以,d3.geoMercator 某些人在外观方面可能更熟悉。

另一种解决方案是找到已经穿过 anti-meridian 的预投影几何体 - 但此选项的灵活性远低于使用 D3 地理投影来投影数据。