This question was moved from StackOverflow as suggested by some users.
I developed a function that aims to (should) provide a simple and effective method to transform a polygon <path>
from relative to absolute. The purpose of this function is to replace similar SnapSVG function from my code, since I'm not processing any other type of path commands.
I need suggestions on how improve the code. Here's the thingy:
// simple pathToAbsolute for polygons
// returns an array with ABSOLUTE points of the polygon path
var pathToAbsolute = function(p) {
var np = p.match(/(m[^l]*|l[^(l|z)]*)/gi), // we extract the segments string from path string
l = np.length, s, c, r, x = 0, y = 0;
for (var i = 0; i<l; i++){ // here we start processing each segment string
np[i] = np[i].trim(); // we trim the segment string
c = np[i][0].trim(); r = new RegExp(c); // the path command
np[i] = np[i].replace(/(^|[^,])\s*-/g, '$1,-') // fix the x,y 186.101-87.287 to -186.101,-87.287 separation
.replace(/[\s+\,|\s|\,]/g,'|') // replace any spacing and comma with another separator
.replace(r,'') // remove the path command from string
.split('|'); // split by new separator
np[i][0] === '' && np[i].shift(); // I need a way to avoid this
np[i][0] = parseFloat(np[i][0]); // make sure we do math with numbers
np[i][1] = parseFloat(np[i][1]);
if (i === 0) { x+=np[i][0]; y +=np[i][1]; } // for M, we only need it's values
if (i>0){ // for other segments
x= !!np[i-1] ? np[i-1][0] : np[0][0]; // if we have a previous point
y= !!np[i-1] ? np[i-1][1] : np[0][1]; // let's grab its x,y values for relative points
np[i][0] = c === 'l' ? np[i][0] + x : np[i][0]; // here we fix the value of any
np[i][1] = c === 'l' ? np[i][1] + y : np[i][1]; // relative point
}
}
return np; // in the end we return the newPoints array
}
// testing the function
var star = document.getElementById('star'), svg = star.parentNode,
starPoints = pathToAbsolute(star.getAttribute('d'));
var newStar = document.createElementNS('http://www.w3.org/2000/svg','path');
newStar.setAttribute('d', 'M'+starPoints.join('L')+'z');
newStar.setAttribute('fill','green');
newStar.setAttribute('transform','translate(30,30)');
svg.appendChild(newStar);
<div style="width:200px">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" >
<path id="star"
fill="#eee"
d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011z"
></path>
</svg>
</div>
As you can see, the function works pretty much as expected, but in the comments I've put some points of concerns where I'm not sure it's accurate or generally applicable.
My most concern is the way to calculate the new values for relative points now becoming absolute. Also I need a way to avoid shifting via np[0].shift()
any segment that is not properly processed before. Perhaps I can improve some RegExp, just I'm not completely sure.
So I am open to any other improvement suggestion you may have, so please jump in.
I need something that should work IE9+, Chrome 4+, Safari 5+, regardless of the fact that pathSegList
or pathDataAPI
is supported or not, just like the original functions from SnapSVG. No polyfills are acceptable.
Your suggested improved function must return same thingy: the array with absolute points, probably supporting H and V path commands. The array format is required for other functions that process the array for other uses.
m
andl
)? Because there's alsoh
andv
line commands, thea
arc-to command, and of course thec
,s
,q
andt
curve commands... \$\endgroup\$