SVG path conversion tool
by Danny Engelman
HTML
<script src="http://cdn.jsdelivr.net/snap.svg/0.3.0/snap.svg.js"></script>
<h2>
Convert SVG path
</h2>
<form id=convert>
org viewBox:<input id=orgVB value=512 size=3 />
<br>
best viewBox:<input id=bestVB value=96 size=3 />
<br>
Multiplier: <input id=multiplier value=1 size=3 type=number />
<br>
Precision: <input id=precision value=0 size=3 type=number />
<br>
fill-rule: <input id=fillRule value="evenodd" size=10 type=text />
<hr>
<div id=paths>
<section>
<label>path: <span></span><textarea id="org">M48 24v12l16-16-16-16v12c-17.68 0-32 14.32-32 32 0 6.28 2.4 12.12 4.96 17.04L26.8 60A23.48 23.48 0 0 1 24 48c0-13.24 10.76-24 24-24zm24 4L69.2 36.8c1.76 3.36 2.8 7.16 2.8 11.2 0 13.24-10.76 24-24 24v-12l-16 16 16 16v-12c17.68 0 32-14.32 32-32 0-6.28-1.84-12.12-4.96-16z</textarea></label>
<svg>
<path id="orgPath" fill="red" d="" />
</svg>
</section>
<section>
relative: <span></span><textarea id="rel"></textarea>
<svg>
<path id="relPath" fill="green" d="" />
</svg>
</section>
<section>
absolute: <span></span><textarea id="abs"></textarea>
<svg>
<path id="absPath" fill="blue" d="" />
</svg>
</section>
<section>
multiplied*: <span></span><textarea id="mul"></textarea>
<svg>
<path id="mulPath" fill="hotpink" d="" />
</svg>
</section>
</div>
</form>
<footer>
</footer>
CSS
body {
font: 100%/1.5 Helvetica Neue, sans-serif;
margin: 1em;
}
input{
margin-left:1em;
font-size:100%;
}
#paths {
display:grid;
grid-template-columns: repeat(auto-fit,minmax(50px,1fr));
grid-gap:1em;
width: 100%;
}
textarea {
width: 100%;
height: 50vh;
}
svg{
width:100%;
background:lightgrey;
}
JavaScript
window.onload = () => {
const sanitize = (s, p = precision.value, m = 1) => {
return String(s).replace(/[0-9]*\.[0-9]*/g, x => {
let val = (+x) * Number(m);
val = +val.toFixed(Number(p));
if(p==1) return Math.round(val*2)/2;
else return val;
}).replace(/,/g, " ").replace(/ -/g,"-");
}
const setViewBox = (svg, v) => svg.parentNode.setAttribute('viewBox', `0 0 ${v} ${v}`);
const setSVG = (ta, svg, path) => {
svg.setAttribute('d', path);
svg.setAttribute('fill-rule', `${String(fillRule.value)}`);
setViewBox(svg, orgVB.value * (svg == mulPath ? multiplier.value : 1));
ta.innerText = path;
ta.previousSibling.innerText = path.length + " bytes";
}
const recalc = (path = org.value) => {
localStorage.setItem("path", path);
setSVG(org, orgPath, path);
setSVG(mul, mulPath, sanitize(path, precision.value, multiplier.value));
setSVG(rel, relPath, sanitize(Snap.path.toRelative(path)));
setSVG(abs, absPath, sanitize(Snap.path.toAbsolute(path)));
}
convert.oninput = (evt) => {
store(evt.target.id, evt.target.value);
recalc();
}
const store = (name, value = false) => localStorage[(value ? "set" : value == undefined ? "remove" : "get") + "Item"]("svgedit_"+name, value);
const restore = (name, val = "") => document.getElementById(name).value = store(name) || val;
restore("orgVB", 24);
restore("bestVB", 96);
restore("bestVB", 1);
restore("bestVB", 0);
restore("multiplier", 1);
restore("precision", 0);
restore("fillRule")
recalc(localStorage.getItem("path") || undefined);
// org.onfocus = rel.onfocus = abs.onfocus = (evt)=>evt.target.select();
// if (org.value) org.oninput();
}