svg-parse-path-normalized
Version:
Parse svg path data from string and normalize it to calculable value arrays
260 lines (206 loc) • 7.7 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parse pathdata</title>
<style>
body {
font-family: sans-serif;
}
svg {
width: 100%;
overflow: visible;
border: 1px solid #ccc;
}
.grd {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2em;
height: 95vh;
}
.col {
height: 100%;
display: flex;
flex-direction: column;
gap: 0;
justify-content: flex-start;
}
.col>* {
margin-top: 0;
margin-bottom: 1rem;
}
textarea {
width: 100%;
display: block;
min-height: 10em;
flex: 1 1 auto;
resize: vertical;
}
input {}
input[type="range"] {
width: 100%;
display: block;
}
input[type="checkbox"] {
margin-right: 0.5em;
}
label {
display: inline-block;
line-height: 1.4em;
margin: 0;
margin-right: 0.5em;
}
code {
background: #eee;
display: block;
padding: 0.5em;
}
#pErrors {
font-weight: 700;
color: red;
}
input[type="number"] {
width: 4em;
}
</style>
</head>
<body>
<div class="grd">
<div class="col">
<h1>Parse pathData normalized</h1>
<p>Standalone pathData parser – including normalization options: </p>
<p>See <a href="https://github.com/herrstrietzel/svg-parse-path-normalized">github
repository</a></p>
<details>
<summary>Usage example</summary>
<pre>
<code>
let options = {
toAbsolute: true,
toLonghands: true,
arcToCubic:true,
quadraticToCubic: true,
debug: false,
decimals: -1
}
let d = "M 0 0 ... z"
let pathDataAbs = parsepathDataNormalized(d, options)
</code>
</pre>
</details>
<fieldset>
<legend>Options</legend>
<label><input class="inputs" type="checkbox" id="inputtoAbsolute" checked>toAbsolute</label>
<label><input class="inputs" type="checkbox" id="inputtoLonghands" checked>toLonghands</label>
<label><input class="inputs" type="checkbox" id="inputarcToCubic" checked>arcToCubic</label>
<label><input class="inputs" type="checkbox" id="inputquadraticToCubic"
checked>quadraticToCubic</label><br>
<label><input class="inputs" type="checkbox" id="inputlineToCubic">lines to cubic (for morphing
animations)</label>
<label><input class="inputs" type="checkbox" id="inputdebug" checked>debug (shows errors in
console)</label>
<br>
<label>Round (-1 = no rounding) <input class="inputs" type="number" value="3" min="-1"
id="inputDecimals"></label><br>
<label><input class="inputs" type="checkbox" id="inputMinify">minify d output</label>
</fieldset>
</p>
<p id="pErrors"></p>
<h3>PathData string input</h3>
<textarea id="svgInput">
M+50 0
a50 50 0 110 100 50 50 0 110-100
m0 30a20 20 0 110 40 20 20 0 110-40m0-10q12.42 0 21.21 8.79t8.79 21.21-8.79 21.21-21.21 8.79-21.21-8.79-8.79-21.21 8.79-21.21 21.21-8.79m-40-20a5 5 0 110 10 5 5 0 110-10m80 0a5 5 0 110 10 5 5 0 110-10m0 2.5a2.5 2.5 0 110 5 2.5 2.5 0 110-5m-45 42.5h10v10h-10zm-5-5h20v20h-20zm10-30c22.07 0 40 17.93 40 40
s-17.93 40-40 40-40-17.93-40-40 17.93-40 40-40
</textarea>
<h3>PathData out</h3>
<textarea id="svgOut">
</textarea>
<h3>PathData string output</h3>
<textarea id="svgDOut">
</textarea>
</div>
<div class="col">
<svg id="svg" viewBox="0 0 100 100">
<path fill="none" stroke="black" d="
" />
<path id="path2" fill="none" stroke="green" stroke-width="0.5" />
</svg>
</div>
</div>
<script src="../js/pathDataParseNormalized.js"></script>
<script src="../js/pathDataConvert.js"></script>
<script>
/**
* 1. simple parsing
*/
let pathData = parsePathDataNormalized("m 0 0 .5.5.5.5a 5 10 45 1040 20")
//stringify to pathdata d string
let minify = false;
//let dNew = pathDataToD(pathData, 1, minify);
let dNew = pathData.toD(1, minify);
console.log(pathData);
console.log(dNew);
/**
* 3. Quick convert
*/
let pathDataCon = pathData.convert({arcToCubic:true, toRelative:true, decimals:0})
/**
* 4. Convert to verbose format
*/
let pathDataV = parsePathDataNormalized("m 0 0 .5.5.5.5a 5 10 45 1040 20", {normalize:false})
let pVerbose = JSON.stringify(pathDataToVerbose(pathDataV), null)
console.log(pVerbose);
/**
* 2. parsing with normalization options
*/
// init – otherwise use pathDataBB.getBBoxFromD()
let path = document.querySelector("path");
let svg = path.closest("svg");
let d = svgInput.value;
updateSVG();
svgInput.addEventListener("input", (e) => {
updateSVG();
});
let inputs = document.querySelectorAll(".inputs");
inputs.forEach((inp) => {
inp.addEventListener("input", (e) => {
updateSVG();
});
});
function updateSVG() {
d = svgInput.value;
path.setAttribute("d", d);
let options = {
toAbsolute: inputtoAbsolute.checked,
toLonghands: inputtoLonghands.checked,
arcToCubic: inputarcToCubic.checked,
quadraticToCubic: inputquadraticToCubic.checked,
lineToCubic: inputlineToCubic.checked,
decimals: +inputDecimals.value,
debug: inputdebug.checked
};
let pathData = parsePathDataNormalized(d, options);
let decimals = +inputDecimals.value;
let minify = inputMinify.checked;
let dN = pathDataToD(pathData, decimals, minify);
let errors = pathData[0].errors ? pathData[0].errors : ''
pErrors.textContent = errors
path2.setAttribute("d", dN);
svgOut.value = JSON.stringify(pathData, null, "").replaceAll('},', '},\n');
svgDOut.value = dN;
// adjust viewBox
let bb = path.getBBox();
let bbString = [bb.x, bb.y, bb.width, bb.height].join(" ");
svg.setAttribute("viewBox", bbString);
let {
x,
y,
width,
height
} = bb;
}
</script>
</body>
</html>