-
-
Save shamansir/0ba30dc262d54d04cd7f79e03b281505 to your computer and use it in GitHub Desktop.
Parse and convert any SVG path to the list of commands with JavaScript + Regular Expressions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// svgPathToCommands('M10,10 l 5,7 C-5,7.2,.3-16,24,10 z'); | |
// | |
// produces: | |
// | |
// [ { marker: "M", values: [ 10, 10 ] }, | |
// { marker: "l", values: [ 5, 7 ] }, | |
// { marker: "C", values: [ -5, 7.2, 0.3, -16, 24, 10 ] }, | |
// { marker: "z", values: [ ] } ] | |
// | |
// commandsToSvgPath(svgPathToCommands('M10,10 l 5,7 C-5,7.2,.3-16,24,10 z')) | |
// | |
// produces: 'M 10,10 l 5,7 C -5,7.2,0.3,-16,24,10 z' | |
var markerRegEx = /[MmLlSsQqLlHhVvCcSsQqTtAaZz]/g; | |
var digitRegEx = /-?[0-9]*\.?\d+/g; | |
function svgPathToCommands(str) { | |
var results = []; | |
var match; while ((match = markerRegEx.exec(str)) !== null) { results.push(match); }; | |
return results | |
.map(function(match) { | |
return { marker: str[match.index], | |
index: match.index }; | |
}) | |
.reduceRight(function(all, cur) { | |
var chunk = str.substring(cur.index, all.length ? all[all.length - 1].index : str.length); | |
return all.concat([ | |
{ marker: cur.marker, | |
index: cur.index, | |
chunk: (chunk.length > 0) ? chunk.substr(1, chunk.length - 1) : chunk } | |
]); | |
}, []) | |
.reverse() | |
.map(function(command) { | |
var values = command.chunk.match(digitRegEx); | |
return { marker: command.marker, values: values ? values.map(parseFloat) : []}; | |
}) | |
} | |
function commandsToSvgPath(commands) { | |
return commands.map(function(command) { | |
return command.marker + ' ' + command.values.join(','); | |
}).join(' ').trim(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -------- EXAMPLE: SHIFT THE PATH VALUES TO CENTER --------- */ | |
var myCommands = svgPathToCommands('M10,10 l 5,7 C-5,7.2,.3-16,24,10 z'); | |
var minMax = myCommands.reduce(function(prev, command) { | |
return command.values.reduce(function(prev, value, i) { | |
return { minX: (i % 2) ? prev.minX : Math.min(value, prev.minX), | |
maxX: (i % 2) ? prev.maxX : Math.max(value, prev.maxX), | |
minY: (i % 2) ? Math.min(value, prev.minY) : prev.minY, | |
maxY: (i % 2) ? Math.max(value, prev.maxY) : prev.maxY }; | |
}, prev); | |
}, { minX: Infinity, maxX: 0, minY: Infinity, maxY: 0 }); | |
var center = { x: minMax.minX + ((minMax.maxX - minMax.minX) / 2), | |
y: minMax.minY + ((minMax.maxY - minMax.minY) / 2) }; | |
var result = commandsToSvgPath( | |
myCommands.map(function(command) { | |
return { marker: command.marker, | |
values: command.values.map(function(value, i) { | |
return (i % 2) ? (value - center.y) : (value - center.x); }) | |
}; | |
}) | |
); | |
console.log(minMax, center, result); | |
// -> Object {minX: -5, maxX: 24, minY: -16, maxY: 10} | |
// -> Object {x: 9.5, y: -3} | |
// -> "M 0.5,13 l -4.5,10 C -14.5,10.2,-9.2,-13,14.5,13 z" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -------- TESTS --------- */ | |
var tests = [ | |
'', | |
'M-11.11,-22 L.33-44 ac55 66 h77 M88 .99 Z', | |
'M500,500 L500,200 L800,500 z M400,600 L400,900 L100,600 z', | |
'M70.491,50.826c-2.232,1.152-6.913,2.304-12.817,2.304c-13.682,0-23.906-8.641-23.906-24.626' + | |
'c0-15.266,10.297-25.49,25.346-25.49c5.977,0,9.865,1.296,11.521,2.16l-1.584,5.112C66.747,9.134,63.363,8.27,59.33,8.27' + | |
'c-11.377,0-18.938,7.272-18.938,20.018c0,11.953,6.841,19.514,18.578,19.514c3.888,0,7.777-0.792,10.297-2.016L70.491,50.826z', | |
'M10,10', | |
'Z' | |
]; | |
tests.forEach(function(test) { | |
console.log('----'); | |
console.log('source:', test || '<empty>'); | |
console.log('encoded:'); | |
svgPathToCommands(test).forEach(function(command) { | |
console.log(command.marker, command.values); | |
}); | |
console.log('decoded:', commandsToSvgPath(svgPathToCommands(test)) || '<empty>'); | |
}); |
MmLlSsQqLlHhVvCcSsQqTtAaZz - why double the characters "Ll", "Ss" and "Qq"? Is there something I don't understand?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks !, Really useful !