svg-path-simplify 0.1.3 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +10 -0
  2. package/dist/svg-path-simplify.esm.js +3905 -1533
  3. package/dist/svg-path-simplify.esm.min.js +13 -1
  4. package/dist/svg-path-simplify.js +3923 -1551
  5. package/dist/svg-path-simplify.min.js +13 -1
  6. package/dist/svg-path-simplify.min.js.gz +0 -0
  7. package/index.html +61 -31
  8. package/package.json +3 -5
  9. package/src/constants.js +3 -0
  10. package/src/index-node.js +0 -1
  11. package/src/index.js +26 -0
  12. package/src/pathData_simplify_cubic.js +74 -31
  13. package/src/pathData_simplify_cubicsToArcs.js +566 -0
  14. package/src/pathData_simplify_harmonize_cpts.js +170 -0
  15. package/src/pathData_simplify_revertToquadratics.js +21 -0
  16. package/src/pathSimplify-main.js +253 -86
  17. package/src/poly-fit-curve-schneider.js +570 -0
  18. package/src/simplify_poly_RDP.js +146 -0
  19. package/src/simplify_poly_radial_distance.js +100 -0
  20. package/src/svg_getViewbox.js +1 -1
  21. package/src/svgii/geometry.js +389 -63
  22. package/src/svgii/geometry_area.js +2 -1
  23. package/src/svgii/pathData_analyze.js +259 -212
  24. package/src/svgii/pathData_convert.js +91 -663
  25. package/src/svgii/pathData_fromPoly.js +12 -0
  26. package/src/svgii/pathData_parse.js +90 -89
  27. package/src/svgii/pathData_parse_els.js +3 -0
  28. package/src/svgii/pathData_parse_fontello.js +449 -0
  29. package/src/svgii/pathData_remove_collinear.js +44 -37
  30. package/src/svgii/pathData_reorder.js +2 -1
  31. package/src/svgii/pathData_simplify_redraw.js +343 -0
  32. package/src/svgii/pathData_simplify_refineCorners.js +18 -9
  33. package/src/svgii/pathData_simplify_refineExtremes.js +19 -78
  34. package/src/svgii/pathData_split.js +42 -45
  35. package/src/svgii/pathData_toPolygon.js +130 -4
  36. package/src/svgii/poly_analyze.js +470 -14
  37. package/src/svgii/poly_to_pathdata.js +224 -19
  38. package/src/svgii/rounding.js +55 -112
  39. package/src/svgii/svg_cleanup.js +13 -1
  40. package/src/svgii/visualize.js +8 -3
  41. package/{debug.cjs → tests/debug.cjs} +3 -0
  42. /package/{test.js → tests/test.js} +0 -0
  43. /package/{testSVG.js → tests/testSVG.js} +0 -0
@@ -0,0 +1,12 @@
1
+ export function pathDataFromPoly(pts, closed=true){
2
+
3
+ let pathData = [
4
+ { type: 'M', values: [pts[0].x, pts[0].y] },
5
+ ...pts.slice(1).map(pt => { return { type: 'L', values: [pt.x, pt.y] } })
6
+ ];
7
+
8
+ if(closed) pathData.push({type:'Z', values:[]})
9
+
10
+ return pathData
11
+
12
+ }
@@ -150,38 +150,77 @@ paramCountsArr[0x5A] = 0
150
150
  paramCountsArr[0x7A] = 0
151
151
 
152
152
 
153
+ const SPECIAL_SPACES = new Set([
154
+ 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
155
+ 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF
156
+ ]);
157
+
158
+
159
+ const isSpace = (ch) => {
160
+ return (ch === 0x20) || (ch === 0x002C) || // White spaces or comma
161
+ (ch === 0x0A) || (ch === 0x0D) || // nl cr
162
+ (ch === 0x2028) || (ch === 0x2029) || // Line terminators
163
+ (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
164
+ (ch >= 0x1680 && SPECIAL_SPACES.has(ch));
165
+ }
166
+
167
+
168
+ const sanitizeArc = (val='', valueIndex=0) => {
169
+ let valLen = val.length;
170
+
171
+ // large arc and sweep
172
+ if (valueIndex === 3 && valLen === 2) {
173
+ //console.log('large arc sweep combined', val, +val[0], +val[1]);
174
+ val = [+val[0], +val[1]];
175
+ valueIndex++
176
+ }
177
+
178
+ // sweep and final
179
+ else if (valueIndex === 4 && valLen > 1) {
180
+ //console.log('sweep and final', val, val[0], val[1]);
181
+ val = [+val[0], +val.substring(1)];
182
+ valueIndex++
183
+ }
184
+
185
+ // large arc, sweep and final pt combined
186
+ else if (valueIndex === 3 && valLen >= 3) {
187
+ //console.log('large arc, sweep and final pt combined', val);
188
+ val = [+val[0], +val[1], +val.substring(2)];
189
+ valueIndex += 2
190
+ }
191
+ else{
192
+ val = [+val]
193
+ }
194
+
195
+ //console.log('val arc', val);
196
+ return {val,valueIndex} ;
197
+
198
+ }
199
+
200
+
153
201
 
154
202
  export function parsePathDataString(d, debug = true) {
155
203
  d = d.trim();
156
204
 
157
- if (d === '') {
158
- return {
159
- pathData: [],
160
- hasRelatives: false,
161
- hasShorthands: false,
162
- hasQuadratics: false,
163
- hasArcs: false
164
- }
205
+ let pathDataObj = {
206
+ pathData: [],
207
+ hasRelatives: false,
208
+ hasShorthands: false,
209
+ hasArcs: false,
210
+ hasQuadratics: false,
211
+ isPolygon: false,
212
+ log:[]
165
213
  }
166
214
 
167
- const SPECIAL_SPACES = new Set([
168
- 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
169
- 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF
170
- ]);
171
-
172
215
 
173
- const isSpace = (ch) => {
174
- return (ch === 0x20) || (ch === 0x002C) || // White spaces or comma
175
- (ch === 0x0A) || (ch === 0x0D) || // nl cr
176
- (ch === 0x2028) || (ch === 0x2029) || // Line terminators
177
- (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
178
- (ch >= 0x1680 && SPECIAL_SPACES.has(ch));
216
+ if (d === '') {
217
+ return pathDataObj
179
218
  }
180
219
 
181
220
 
182
221
  let i = 0, len = d.length;
183
222
  let lastCommand = "";
184
- let pathData = [];
223
+ //let pathData = [];
185
224
  let itemCount = -1;
186
225
  let val = '';
187
226
  let wasE = false;
@@ -193,7 +232,7 @@ export function parsePathDataString(d, debug = true) {
193
232
 
194
233
 
195
234
  // collect errors
196
- let log = [];
235
+ //let log = [];
197
236
  let feedback;
198
237
 
199
238
  const addSeg = () => {
@@ -204,7 +243,7 @@ export function parsePathDataString(d, debug = true) {
204
243
  if (lastCommand === 'M') lastCommand = 'L';
205
244
  else if (lastCommand === 'm') lastCommand = 'l';
206
245
 
207
- pathData.push({ type: lastCommand, values: [] });
246
+ pathDataObj.pathData.push({ type: lastCommand, values: [] });
208
247
 
209
248
  itemCount++;
210
249
  valueIndex = 0;
@@ -221,11 +260,11 @@ export function parsePathDataString(d, debug = true) {
221
260
  if (debug && itemCount === -1) {
222
261
 
223
262
  feedback = 'Pathdata must start with M command'
224
- log.push(feedback)
263
+ pathDataObj.log.push(feedback)
225
264
 
226
265
  // add M command to collect subsequent errors
227
266
  lastCommand = 'M'
228
- pathData.push({ type: lastCommand, values: [] });
267
+ pathDataObj.pathData.push({ type: lastCommand, values: [] });
229
268
  maxParams = 2;
230
269
  valueIndex = 0
231
270
  itemCount++
@@ -233,17 +272,17 @@ export function parsePathDataString(d, debug = true) {
233
272
  }
234
273
 
235
274
  if (lastCommand === 'A' || lastCommand === 'a') {
236
- val = sanitizeArc()
275
+ ({val,valueIndex} = sanitizeArc(val, valueIndex));
237
276
  //console.log('arc', val);
238
- pathData[itemCount].values.push(...val);
277
+ pathDataObj.pathData[itemCount].values.push(...val);
239
278
 
240
279
  } else {
241
280
  // error: leading zeroes
242
281
  if (debug && val[1] && val[1] !== '.' && val[0] === '0') {
243
282
  feedback = `${itemCount}. command: Leading zeros not valid: ${val}`
244
- log.push(feedback)
283
+ pathDataObj.log.push(feedback)
245
284
  }
246
- pathData[itemCount].values.push(+val);
285
+ pathDataObj.pathData[itemCount].values.push(+val);
247
286
  }
248
287
 
249
288
  valueIndex++;
@@ -256,54 +295,21 @@ export function parsePathDataString(d, debug = true) {
256
295
  }
257
296
  }
258
297
 
259
- const sanitizeArc = () => {
260
-
261
- let valLen = val.length;
262
- let arcSucks = false;
263
-
264
- // large arc and sweep
265
- if (valueIndex === 3 && valLen === 2) {
266
- //console.log('large arc sweep combined', val, +val[0], +val[1]);
267
- val = [+val[0], +val[1]];
268
- arcSucks = true
269
- valueIndex++
270
- }
271
-
272
- // sweep and final
273
- else if (valueIndex === 4 && valLen > 1) {
274
- //console.log('sweep and final', val, val[0], val[1]);
275
- val = [+val[0], +val[1]];
276
- arcSucks = true
277
- valueIndex++
278
- }
279
-
280
- // large arc, sweep and final pt combined
281
- else if (valueIndex === 3 && valLen >= 3) {
282
- //console.log('large arc, sweep and final pt combined', val);
283
- val = [+val[0], +val[1], +val.substring(2)];
284
- arcSucks = true
285
- valueIndex += 2
286
- }
287
-
288
- //console.log('val arc', val);
289
- return !arcSucks ? [+val] : val;
290
-
291
- }
292
298
 
293
299
  const validateCommand = () => {
294
300
 
295
301
  if (itemCount > 0) {
296
- let lastCom = pathData[itemCount];
302
+ let lastCom = pathDataObj.pathData[itemCount];
297
303
  let valLen = lastCom.values.length;
298
304
 
299
305
  if ((valLen && valLen < maxParams) || (valLen && valLen > maxParams) || ((lastCommand === 'z' || lastCommand === 'Z') && valLen > 0)) {
300
306
  let diff = maxParams - valLen;
301
307
  feedback = `${itemCount}. command of type "${lastCommand}": ${diff} values too few - ${maxParams} expected`;
302
308
 
303
- let prevFeedback = log[log.length - 1];
309
+ let prevFeedback = pathDataObj.log[pathDataObj.log.length - 1];
304
310
 
305
311
  if (prevFeedback !== feedback) {
306
- log.push(feedback)
312
+ pathDataObj.log.push(feedback)
307
313
  }
308
314
  }
309
315
  }
@@ -313,12 +319,11 @@ export function parsePathDataString(d, debug = true) {
313
319
  let isE = false;
314
320
  let isMinusorPlus = false;
315
321
  let isDot = false;
316
-
322
+ let charCode='';
317
323
 
318
324
  while (i < len) {
319
325
 
320
- let charCode = d.charCodeAt(i);
321
-
326
+ charCode = d.charCodeAt(i);
322
327
 
323
328
  let isDigit = (charCode > 47 && charCode < 58);
324
329
  if (!isDigit) {
@@ -399,7 +404,7 @@ export function parsePathDataString(d, debug = true) {
399
404
 
400
405
  if (!isValid) {
401
406
  feedback = `${itemCount}. command "${d[i]}" is not a valid type`;
402
- log.push(feedback);
407
+ pathDataObj.log.push(feedback);
403
408
  i++
404
409
  continue
405
410
  }
@@ -407,7 +412,7 @@ export function parsePathDataString(d, debug = true) {
407
412
 
408
413
  // command is concatenated without whitespace
409
414
  if (val !== '') {
410
- pathData[itemCount].values.push(+val);
415
+ pathDataObj.pathData[itemCount].values.push(+val);
411
416
  valueIndex++;
412
417
  val = '';
413
418
  }
@@ -419,18 +424,18 @@ export function parsePathDataString(d, debug = true) {
419
424
  lastCommand = d[i];
420
425
  maxParams = paramCountsArr[charCode];
421
426
  let isM = lastCommand === 'M' || lastCommand === 'm'
422
- let wasClosePath = itemCount > 0 && (pathData[itemCount].type === 'z' || pathData[itemCount].type === 'Z')
427
+ let wasClosePath = itemCount > 0 && (pathDataObj.pathData[itemCount].type === 'z' || pathDataObj.pathData[itemCount].type === 'Z')
423
428
 
424
429
  foundCommands.add(lastCommand);
425
430
 
426
431
  // add omitted M command after Z
427
432
  if (wasClosePath && !isM) {
428
- pathData.push({ type: 'm', values: [0, 0] });
433
+ pathDataObj.pathData.push({ type: 'm', values: [0, 0] });
429
434
  itemCount++;
430
435
  }
431
436
 
432
437
  // init new command
433
- pathData.push({ type: lastCommand, values: [] });
438
+ pathDataObj.pathData.push({ type: lastCommand, values: [] });
434
439
  itemCount++;
435
440
 
436
441
  // reset counters
@@ -446,7 +451,7 @@ export function parsePathDataString(d, debug = true) {
446
451
  // exceptions - prevent infinite loop
447
452
  if (!isDigit) {
448
453
  feedback = `${itemCount}. ${d[i]} is not a valid separarator or token`;
449
- log.push(feedback);
454
+ pathDataObj.log.push(feedback);
450
455
  val = '';
451
456
  }
452
457
 
@@ -460,8 +465,8 @@ export function parsePathDataString(d, debug = true) {
460
465
 
461
466
 
462
467
  // return error log
463
- if (debug && log.length) {
464
- feedback = 'Invalid path data:\n' + log.join('\n')
468
+ if (debug && pathDataObj.log.length) {
469
+ feedback = 'Invalid path data:\n' + pathDataObj.log.join('\n')
465
470
  if (debug === 'log') {
466
471
  console.log(feedback);
467
472
  } else {
@@ -470,7 +475,7 @@ export function parsePathDataString(d, debug = true) {
470
475
  }
471
476
  }
472
477
 
473
- pathData[0].type = 'M'
478
+ pathDataObj.pathData[0].type = 'M'
474
479
 
475
480
  /**
476
481
  * check if absolute/relative or
@@ -479,19 +484,15 @@ export function parsePathDataString(d, debug = true) {
479
484
  */
480
485
  //check types relative arcs or quadratics
481
486
  let commands = Array.from(foundCommands).join('');
482
- let hasRelatives = /[lcqamts]/g.test(commands);
483
- let hasShorthands = /[vhst]/gi.test(commands);
484
- let hasArcs = /[a]/gi.test(commands);
485
- let hasQuadratics = /[qt]/gi.test(commands);
486
-
487
-
488
- return {
489
- pathData,
490
- hasRelatives,
491
- hasShorthands,
492
- hasQuadratics,
493
- hasArcs
494
- }
487
+
488
+ pathDataObj.hasRelatives = /[lcqamtsvh]/g.test(commands);
489
+ pathDataObj.hasShorthands = /[vhst]/gi.test(commands);
490
+ pathDataObj.hasArcs = /[a]/gi.test(commands);
491
+ pathDataObj.hasQuadratics = /[qt]/gi.test(commands);
492
+ pathDataObj.isPolygon = /[cqats]/gi.test(commands) ? false : true;
493
+
494
+ return pathDataObj
495
+
495
496
 
496
497
  }
497
498
 
@@ -163,6 +163,9 @@ export function getPathDataFromEl(el, stringify = false) {
163
163
  ];
164
164
  } else {
165
165
 
166
+ rx=rx? rx : ry;
167
+ ry=ry ? ry : rx;
168
+
166
169
  if (rx > width / 2) {
167
170
  rx = width / 2;
168
171
  }