svg-parse-path-normalized
Version:
Parse svg path data from string and normalize it to calculable value arrays
207 lines (168 loc) • 5.71 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parse pathdata – convert plugin</title>
<style>
body {
font-family: 'Fira Sans', 'Segoe UI', 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: inline-block;
padding: 0.5em;
margin-right:0.3em;
}
#pErrors {
font-weight: 700;
color: red;
}
input[type="number"] {
width: 4em;
}
</style>
</head>
<body>
<div class="grd">
<div class="col">
<svg id="svg" viewBox="0 0 100 100">
<path id="path" fill="none" stroke="black" d="M3,7
L13,7
m-20,10
l10,0
V27
H23
v10
h10
C 33,43 38,47 43,47
c 0,5 5,10 10,10
S 63,67 63,67
s -10,10 10,10
Q 50,50 73,57
q 20,-5 0,-10
T 70,40
t 0,-15
A 5, 10 45 10 40,20
a5,5 20 01 -10,-10
Z
" />
<path id="path2" fill="none" stroke="green" stroke-width="0.5" />
</svg>
</div>
<div class="col">
<h1>Convert pathData</h1>
<h2>Parse pathdata via <a href="https://github.com/jarek-foksa/path-data-polyfill">Jarek Foksa's polyfill</a> and convert it</h2>
<p>If it ever gets implemented by natively supported <code>getpathData()</code><code>setpathData()</code> methods</p>
<textarea id="svgOut"></textarea>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/path-data-polyfill@1.0.4/path-data-polyfill.min.js"></script>
<script src="../js/pathDataConvert.js"></script>
<script>
let options = {
//normalize: true,
//optimize: true,
//toAbsolute: true,
toRelative: true,
//quadraticToCubic: true,
cubicToQuadratic: true,
cubicToQuadraticPrecision: 0.1,
lineToCubic: true,
//toLonghands: true,
toShorthands: true,
arcToCubic: true,
//arcParam: false,
arcAccuracy: 1,
decimals: 1,
}
const pathData = path.getPathData().convert(options)
path2.setPathData(pathData);
svgOut.value = pathDataToD(pathData)
/**
* serialize pathData array to
* d attribute string
*/
function pathDataToD(pathData, decimals = -1, minify = false) {
// implicit l command
if (pathData[1].type === "l" && minify) {
pathData[0].type = "m";
}
let d = `${pathData[0].type}${pathData[0].values.join(" ")}`;
for (let i = 1; i < pathData.length; i++) {
let com0 = pathData[i - 1];
let com = pathData[i];
let { type, values } = com;
// minify arctos
if (minify && type === 'A' || type === 'a') {
values = [values[0], values[1], values[2], [values[3], values[4], values[5]].join(''), values[6]]
}
// round
if (values.length && decimals > -1) {
values = values.map(val => { return typeof val === 'number' ? +val.toFixed(decimals) : val })
}
// omit type for repeated commands
type = (com0.type === com.type && com.type.toLowerCase() != 'm' && minify) ?
" " : (
(com0.type === "m" && com.type === "l") ||
(com0.type === "M" && com.type === "l") ||
(com0.type === "M" && com.type === "L")
) && minify ?
" " : com.type;
d += `${type}${values.join(" ")}`;
}
if (minify) {
d = d
.replaceAll(" 0.", " .")
.replaceAll(" -", "-")
.replaceAll("-0.", "-.")
.replaceAll("Z", "z");
}
return d;
}
</script>
</body>
</html>