Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplifying D3js' SVG path generated string

I am trying to optimize a little bit the SVG I am generating using the amazing D3js geo module.

I am using d3.geo.path as the d attribute generator for SVG paths:

path = d3.geo.path().projection(config.projection); // projection is initialized somewhere else

and then using it to render paths like this:

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

and the kind of path strings I am getting are like this one:

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

As can be seen, some numbers are extremely long with too many decimals and not really useful at my current resolution, which clogs a little bit the DOM and makes it sluggish to debug these paths (there are also many, since it's a world map with lots of countries drawn on it).

So my first approach was creating this pathSimplified wrapper for path:

// Path simplified: take some decimals out of the 'd' string
pathSimplified = function (d) {
        return path(d).replace(/(\.\d{4})\d+/g, '$1');
    };

and then use it instead of path:

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

That works and now I get only 4 decimals for each value on the path string. Like this:

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

My question is: can it be done in a better, less hackish way? It doesn't feel right to tweak the string after it's spit out by D3js's path function and it would be nice to specify the rounding at some point on the path itself or the projection...

like image 417
Óscar Gómez Alcañiz Avatar asked Mar 31 '16 13:03

Óscar Gómez Alcañiz


1 Answers

Your idea is good, simplifying a polyline helps, but you can certainly do it better than just truncating coordinates: algorithms for polyline semplification exist and might give you nicer results.

For example, take a look at the Ramer-Douglas-Peucker algorithm. It is implemented in libraries like Simplify.js(check the demo on that page out), which also allows you to adjust it with tolerance. You'll have to pass the line as an array of x/y coords, but I trust that isn't too complicated to do.

I also noticed that d3 geo projections allow for a precision parameter (like here), maybe there's something like that that you overlooked? In any case, simplifying coordinates on your own with simplify.js is usually always possible.

like image 139
Sosdoc Avatar answered Sep 24 '22 14:09

Sosdoc