Skip to content

Commit 3ffd004

Browse files
committed
Atoms - Pen and paper - Optimize svg path outputs
1 parent 09f1784 commit 3ffd004

File tree

1 file changed

+90
-1
lines changed

1 file changed

+90
-1
lines changed

src/atoms/PenAndPaper.vue

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,97 @@ function draw(event) {
9191
currentPath.value += ` ${x} ${y}`;
9292
}
9393
94+
function smoothPath(path) {
95+
const segments = path.trim().split(/\s+/);
96+
if (segments.length < 4) return path;
97+
const smoothedPath = [segments[0], segments[1], segments[2]]; // Keep M x y incipit
98+
for (let i = 3; i < segments.length - 2; i += 2) {
99+
const x1 = parseFloat(segments[i - 2]);
100+
const y1 = parseFloat(segments[i - 1]);
101+
const x2 = parseFloat(segments[i]);
102+
const y2 = parseFloat(segments[i + 1]);
103+
if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) {
104+
continue
105+
}
106+
const controlX = (x1 + x2) / 2;
107+
const controlY = (y1 + y2) / 2;
108+
smoothedPath.push(`Q ${x1} ${y1} ${controlX} ${controlY}`);
109+
}
110+
const lastX = segments[segments.length - 2];
111+
const lastY = segments[segments.length - 1];
112+
smoothedPath.push(`L ${lastX} ${lastY}`);
113+
return smoothedPath.join(" ");
114+
}
115+
116+
function optimizeSvgPath(path) {
117+
const commands = path.trim().split(/\s+/);
118+
let optimizedPath = '';
119+
let currentCommand = '';
120+
let currentX = null, currentY = null;
121+
for (let i = 0; i < commands.length; i += 1) {
122+
const command = commands[i];
123+
if (isNaN(command)) {
124+
currentCommand = command;
125+
if (currentCommand === 'M' || currentCommand === 'L') {
126+
currentX = parseFloat(commands[++i]);
127+
currentY = parseFloat(commands[++i]);
128+
optimizedPath += `${currentCommand}${currentX} ${currentY}`;
129+
} else if (currentCommand === 'Q') {
130+
const cx = parseFloat(commands[++i]);
131+
const cy = parseFloat(commands[++i]);
132+
const x = parseFloat(commands[++i]);
133+
const y = parseFloat(commands[++i]);
134+
135+
if (cx === currentX && cy === currentY) {
136+
// Last point shorthand
137+
optimizedPath += `t${x - currentX} ${y - currentY}`;
138+
} else {
139+
optimizedPath += `q${cx - currentX} ${cy - currentY} ${x - currentX} ${y - currentY}`;
140+
}
141+
currentX = x;
142+
currentY = y;
143+
}
144+
} else {
145+
const x = parseFloat(command);
146+
const y = parseFloat(commands[++i]);
147+
if (currentCommand === 'L') {
148+
const dx = x - currentX;
149+
const dy = y - currentY;
150+
151+
if (dx === 0) {
152+
// Vertical line
153+
optimizedPath += `v${dy}`;
154+
} else if (dy === 0) {
155+
// Horizontal line
156+
optimizedPath += `h${dx}`;
157+
} else {
158+
// Diagonal line
159+
optimizedPath += `l${dx} ${dy}`;
160+
}
161+
currentX = x;
162+
currentY = y;
163+
} else if (currentCommand === 'Q') {
164+
const cx = x;
165+
const cy = y;
166+
const nx = parseFloat(commands[++i]);
167+
const ny = parseFloat(commands[++i]);
168+
169+
if (cx === currentX && cy === currentY) {
170+
optimizedPath += `t${nx - currentX} ${ny - currentY}`;
171+
} else {
172+
optimizedPath += `q${cx - currentX} ${cy - currentY} ${nx - currentX} ${ny - currentY}`;
173+
}
174+
currentX = nx;
175+
currentY = ny;
176+
}
177+
}
178+
}
179+
return optimizedPath;
180+
}
181+
94182
function stopDrawing() {
95183
if (isDrawing.value) {
96-
stack.value.push(currentPath.value);
184+
stack.value.push(optimizeSvgPath(smoothPath(currentPath.value)));
97185
redoStack.value = [];
98186
currentPath.value = "";
99187
}
@@ -276,6 +364,7 @@ function reset() {
276364
}
277365
.vue-ui-pen-and-paper-path {
278366
stroke-linecap: round;
367+
stroke-linejoin: round;
279368
}
280369
.vue-ui-pen-and-paper-path-drawing {
281370
stroke-width: 2;

0 commit comments

Comments
 (0)