简化D3js的SVG路径生成字符串

7
我正在尝试优化使用令人惊叹的D3js地理模块生成的SVG。我正在使用d3.geo.path作为SVG路径的d属性生成器:
path = d3.geo.path().projection(config.projection); // projection is initialized somewhere else

然后使用它来呈现如下路径:

svg.selectAll(".country")
     .data(countries)
     .enter()
     .insert("path", ".graticule")
     .attr({
         class: "country",
         d: path
     })

我得到的路径字符串类型是这样的:

M713.601085,459.8780053259876L714.7443994399441,460.08170562468473L715.0310281028103,460.5903728431771L715.0310281028103...

可以看到,一些数字非常长,有太多小数位,在当前分辨率下并不真正有用,这会使DOM变得有点拥挤,并且调试这些路径时会变得迟钝(还有很多路径,因为这是一个绘制了许多国家的世界地图)。
因此,我的第一种方法是为path创建这个pathSimplified包装器:
// Path simplified: take some decimals out of the 'd' string
pathSimplified = function (d) {
        return path(d).replace(/(\.\d{4})\d+/g, '$1');
    };

然后使用它来替代path

    //...
    .attr({
         class: "country",
         d: pathSimplified
     })

这个方法可行,现在路径字符串中每个值只保留了四位小数。就像这样:

M713.6010,459.8780L714.7443,460.0817L715.0310,460.5903L715.0310...

我的问题是:有没有更好的方法来解决这个问题,而不是采用hackish的方法?在D3js的path函数输出字符串后对其进行微调并不合适,最好能在路径本身或投影上指定四舍五入。

1
在我的情况下,我选择了一个虚拟SVG宽度(viewBox),足够大以显示我需要的所有细节,然后我完全删除了小数部分:const path_trunc = d => path(d).replace(/\.\d+/g, '') 但我也在想,geo.path是否在某个地方隐藏了这个功能。 - Tobia
1个回答

4

你的想法很好,简化折线确实有帮助,但你可以比仅截断坐标更好地完成它:存在用于折线简化的算法,可能会给您更好的结果。

例如,看一下Ramer-Douglas-Peucker算法。它已经在像Simplify.js这样的库中实现了(请检查该页面上的演示),它还允许您通过容差进行调整。 您必须将行作为x / y坐标数组传递,但我相信这并不太复杂。

我还注意到,d3 geo投影允许使用精度参数(例如此处),也许你忽略了类似的东西?无论如何,通常都可以使用simplify.js自己简化坐标。


谢谢提供的信息,我会研究一下d3.geo中的精度参数。不过请注意,我需要的并不是简化实际多边形,因为这已经通过“topojson”实用程序解决了(所有信息在此处:https://bost.ocks.org/mike/map/)。我的意图仅仅是为了DOM的清晰度而减少小数位数。因此需要控制“path”函数的输出。 - Óscar Gómez Alcañiz
1
@ÓscarGómezAlcañiz 嗯,理想情况下有自适应重采样算法,可以在不丢失太多细节的情况下减少点数。如果你只需要截断,那么你的解决方案已经很好了,唯一能让它更好的是如果d3.geo实际上允许降低输出精度。 - Vale

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接