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

Posted

技术标签:

【中文标题】简化 D3js 的 SVG 路径生成字符串【英文标题】:Simplifying D3js' SVG path generated string 【发布时间】:2016-07-19 22:59:35 【问题描述】:

我正在尝试优化我使用令人惊叹的 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(/(\.\d4)\d+/g, '$1');
    ;

然后用它代替path:

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

这行得通,现在我只得到路径字符串上每个值的 4 位小数。像这样:

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

我的问题是:能不能以一种更好、更少骇人听闻的方式来完成?在 D3js 的 path 函数吐出字符串后调整字符串感觉不对,最好在路径本身或投影的某个点指定舍入...

【问题讨论】:

在我的例子中,我选择了一个足够大的虚拟 SVG 宽度(viewBox)来显示我需要的所有细节,然后我完全删除了小数:const path_trunc = d => path(d).replace(/\.\d+/g, '') 但我也想知道 geo.path 是否有这个功能隐藏在某个地方。 【参考方案1】:

您的想法很好,简化折线会有所帮助,但您当然可以做得比仅仅截断坐标更好:存在折线采样算法并且可能会给您带来更好的结果。

例如,看看Ramer-Douglas-Peucker algorithm。它在 Simplify.js 之类的库中实现(查看该页面上的演示),它还允许您调整它的容差。 您必须将线作为 x/y 坐标数组传递,但我相信这不会太复杂。

我还注意到 d3 地理投影允许使用精度参数(例如 here),也许您忽略了类似的东西?在任何情况下,通常都可以使用 simple.js 自行简化坐标。

【讨论】:

感谢您的信息,我将查看 d3.geo 中的精度参数。无论如何,请注意我需要的不是简化实际的多边形,因为它已经使用topojson 实用程序进行了整理(此处的所有信息:bost.ocks.org/mike/map)。我的意图只是为了 DOM 的冗长而减少十进制数字。因此需要控制path函数的输出。 @ÓscarGómezAlcañiz 好吧,理想情况下,adaptive resampling 算法也会减少点数,而不会丢失太多细节。如果您只需要截断,那么您的解决方案已经很好了,唯一可以让它变得更好的是 d3.geo 是否实际上允许降低输出的精度。

以上是关于简化 D3js 的 SVG 路径生成字符串的主要内容,如果未能解决你的问题,请参考以下文章

canvas svg webgl threejs d3js 的区别

d3js:Svg元素在更改窗口大小时未调整大小

d3js shape深入理解

D3js:何时使用 .datum() 和 .data()?

d3js 画布 概念

将空值传递给 SVG 路径(使用 d3.js)以抑制丢失数据