svg-path-simplify 0.0.8 → 0.0.9
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.
- package/README.md +25 -5
- package/dist/svg-path-simplify.esm.js +576 -494
- package/dist/svg-path-simplify.esm.min.js +1 -1
- package/dist/svg-path-simplify.js +576 -494
- package/dist/svg-path-simplify.min.js +1 -1
- package/dist/svg-path-simplify.node.js +576 -494
- package/dist/svg-path-simplify.node.min.js +1 -1
- package/index.html +86 -29
- package/package.json +1 -1
- package/src/detect_input.js +17 -10
- package/src/index.js +3 -0
- package/src/pathData_simplify_cubic.js +113 -106
- package/src/pathData_simplify_cubic_extrapolate.js +25 -11
- package/src/pathSimplify-main.js +89 -182
- package/src/svgii/geometry_flatness.js +29 -36
- package/src/svgii/pathData_analyze.js +4 -0
- package/src/svgii/pathData_convert.js +26 -17
- package/src/svgii/pathData_interpolate.js +65 -0
- package/src/svgii/pathData_parse.js +25 -9
- package/src/svgii/pathData_parse_els.js +18 -12
- package/src/svgii/pathData_remove_collinear.js +31 -28
- package/src/svgii/pathData_remove_orphaned.js +5 -4
- package/src/svgii/pathData_remove_zerolength.js +8 -4
- package/src/svgii/pathData_reorder.js +6 -2
- package/src/svgii/pathData_simplify_refineCorners.js +160 -0
- package/src/svgii/{simplify_refineExtremes.js → pathData_simplify_refineExtremes.js} +78 -43
- package/src/svgii/pathData_split.js +42 -15
- package/src/svgii/pathData_stringify.js +3 -12
- package/src/svgii/rounding.js +16 -14
- package/src/svgii/svg_cleanup.js +1 -1
- package/src/pathData_simplify_cubic_arr.js +0 -50
- package/src/svgii/simplify.js +0 -248
- package/src/svgii/simplify_bezier.js +0 -470
- package/src/svgii/simplify_linetos.js +0 -93
|
@@ -32,7 +32,7 @@ export function revertCubicQuadratic(p0 = {}, cp1 = {}, cp2 = {}, p = {}) {
|
|
|
32
32
|
let values = [cp1.x, cp1.y, cp2.x, cp2.y, p.x, p.y];
|
|
33
33
|
let comN = {type, values}
|
|
34
34
|
|
|
35
|
-
if (dist1 < threshold) {
|
|
35
|
+
if (dist1 && threshold && dist1 < threshold) {
|
|
36
36
|
cp1_Q = checkLineIntersection(p0, cp1, p, cp2, false);
|
|
37
37
|
if (cp1_Q) {
|
|
38
38
|
//renderPoint(markers, cp1_Q )
|
|
@@ -55,13 +55,19 @@ export function convertPathData(pathData, {
|
|
|
55
55
|
decimals = 3
|
|
56
56
|
} = {}) {
|
|
57
57
|
|
|
58
|
+
|
|
59
|
+
//console.log(toShorthands, toRelative, decimals);
|
|
60
|
+
|
|
58
61
|
//if(decimals>-1 && decimals<2) pathData = roundPathData(pathData, decimals);
|
|
59
62
|
if (toShorthands) pathData = pathDataToShorthands(pathData);
|
|
60
63
|
|
|
61
64
|
// pre round - before relative conversion to minimize distortions
|
|
62
|
-
pathData = roundPathData(pathData, decimals);
|
|
65
|
+
if(decimals>-1 && toRelative) pathData = roundPathData(pathData, decimals);
|
|
63
66
|
if (toRelative) pathData = pathDataToRelative(pathData);
|
|
64
67
|
if (decimals > -1) pathData = roundPathData(pathData, decimals);
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
65
71
|
return pathData
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -374,7 +380,7 @@ export function pathDataToLonghands(pathData, decimals = -1, test = true) {
|
|
|
374
380
|
* L, L, C, Q => H, V, S, T
|
|
375
381
|
* reversed method: pathDataToLonghands()
|
|
376
382
|
*/
|
|
377
|
-
export function pathDataToShorthands(pathData, decimals = -1, test =
|
|
383
|
+
export function pathDataToShorthands(pathData, decimals = -1, test = false) {
|
|
378
384
|
|
|
379
385
|
//pathData = JSON.parse(JSON.stringify(pathData))
|
|
380
386
|
//console.log('has dec', pathData);
|
|
@@ -388,29 +394,28 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
|
|
|
388
394
|
hasRel = /[astvqmhlc]/g.test(commandTokens);
|
|
389
395
|
}
|
|
390
396
|
|
|
391
|
-
pathData = test && hasRel ?
|
|
397
|
+
pathData = test && hasRel ? pathDataToAbsoluteOrRelative(pathData) : pathData;
|
|
398
|
+
|
|
399
|
+
let len = pathData.length
|
|
400
|
+
let pathDataShorts = new Array(len);
|
|
392
401
|
|
|
393
402
|
let comShort = {
|
|
394
403
|
type: "M",
|
|
395
404
|
values: pathData[0].values
|
|
396
405
|
};
|
|
397
406
|
|
|
398
|
-
|
|
399
|
-
//console.log('has dec');
|
|
400
|
-
comShort.decimals = pathData[0].decimals
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
let pathDataShorts = [comShort];
|
|
407
|
+
pathDataShorts[0] = comShort;
|
|
404
408
|
|
|
405
409
|
let p0 = { x: pathData[0].values[0], y: pathData[0].values[1] };
|
|
406
410
|
let p;
|
|
407
411
|
let tolerance = 0.01
|
|
408
412
|
|
|
409
|
-
for (let i = 1
|
|
413
|
+
for (let i = 1; i < len; i++) {
|
|
410
414
|
|
|
411
415
|
let com = pathData[i];
|
|
412
416
|
let { type, values } = com;
|
|
413
|
-
let
|
|
417
|
+
let valuesLen = values.length;
|
|
418
|
+
let valuesLast = [values[valuesLen-2], values[valuesLen-1]];
|
|
414
419
|
|
|
415
420
|
// previoius command
|
|
416
421
|
let comPrev = pathData[i - 1];
|
|
@@ -462,7 +467,8 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
|
|
|
462
467
|
if (typePrev !== 'Q') {
|
|
463
468
|
//console.log('skip T:', type, typePrev);
|
|
464
469
|
p0 = { x: valuesLast[0], y: valuesLast[1] };
|
|
465
|
-
pathDataShorts.push(com);
|
|
470
|
+
//pathDataShorts.push(com);
|
|
471
|
+
pathDataShorts[i] = com;
|
|
466
472
|
continue;
|
|
467
473
|
}
|
|
468
474
|
|
|
@@ -492,7 +498,9 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
|
|
|
492
498
|
|
|
493
499
|
if (typePrev !== 'C') {
|
|
494
500
|
//console.log('skip S', typePrev);
|
|
495
|
-
pathDataShorts.push(com);
|
|
501
|
+
//pathDataShorts.push(com);
|
|
502
|
+
pathDataShorts[i] = com;
|
|
503
|
+
|
|
496
504
|
p0 = { x: valuesLast[0], y: valuesLast[1] };
|
|
497
505
|
continue;
|
|
498
506
|
}
|
|
@@ -525,21 +533,22 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
|
|
|
525
533
|
};
|
|
526
534
|
}
|
|
527
535
|
|
|
528
|
-
|
|
529
536
|
// add decimal info
|
|
530
537
|
if (com.decimals || com.decimals === 0) {
|
|
531
538
|
comShort.decimals = com.decimals
|
|
532
539
|
}
|
|
533
540
|
|
|
534
|
-
|
|
535
541
|
// round final values
|
|
536
542
|
if (decimals > -1) {
|
|
537
543
|
comShort.values = comShort.values.map(val => { return +val.toFixed(decimals) })
|
|
538
544
|
}
|
|
539
545
|
|
|
540
546
|
p0 = { x: valuesLast[0], y: valuesLast[1] };
|
|
541
|
-
pathDataShorts
|
|
547
|
+
pathDataShorts[i] = comShort;
|
|
548
|
+
//pathDataShorts.push(comShort);
|
|
542
549
|
}
|
|
550
|
+
|
|
551
|
+
//console.log('pathDataShorts', pathDataShorts);
|
|
543
552
|
return pathDataShorts;
|
|
544
553
|
}
|
|
545
554
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export function interpolatedPathData(pathData1, pathData2, t = 0.5) {
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* linear interpolation helper (LERP)
|
|
5
|
+
* respecting non-interpolatable
|
|
6
|
+
* Boolean values – required by arc commands
|
|
7
|
+
*/
|
|
8
|
+
const interpolateValues = (values1 = [], values2 = [], t = 0) => {
|
|
9
|
+
|
|
10
|
+
// return start or end for t=0 or 1
|
|
11
|
+
if (t === 0) return values1;
|
|
12
|
+
if (t === 1) return values2;
|
|
13
|
+
|
|
14
|
+
let len = values1.length;
|
|
15
|
+
let isArc = len === 7;
|
|
16
|
+
|
|
17
|
+
// interpolated values: copy values1
|
|
18
|
+
let valuesI = values1.slice();
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < len; i++) {
|
|
21
|
+
let valI
|
|
22
|
+
|
|
23
|
+
// skip Boolean arc command values (largeArc and sweep)
|
|
24
|
+
if (isArc && (i === 3 || i === 4)) {
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// interpolate
|
|
29
|
+
valuesI[i] = (values2[i] - values1[i]) * t + values1[i];
|
|
30
|
+
}
|
|
31
|
+
return valuesI;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// interpolation impossible
|
|
36
|
+
if (pathData1.length !== pathData2.length) {
|
|
37
|
+
throw new Error("Paths are not compatible");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// interpolate command coordinates
|
|
42
|
+
let pathDataI = [];
|
|
43
|
+
pathData1.forEach((com, c) => {
|
|
44
|
+
let {
|
|
45
|
+
type,
|
|
46
|
+
values
|
|
47
|
+
} = com;
|
|
48
|
+
let [type2, values2] = [pathData2[c].type, pathData2[c].values];
|
|
49
|
+
|
|
50
|
+
// interpolate command values
|
|
51
|
+
let valuesInter = interpolateValues(values, values2, t);
|
|
52
|
+
|
|
53
|
+
pathDataI.push({
|
|
54
|
+
type: type,
|
|
55
|
+
values: valuesInter,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// serialize to "d" attribute string
|
|
60
|
+
let dInter = pathDataI.map(com => `${com.type} ${com.values.join(' ')}`).join(' ');
|
|
61
|
+
return {
|
|
62
|
+
pathData: pathDataI,
|
|
63
|
+
d: dInter
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
//import { arcToBezier, quadratic2Cubic } from './convert.js';
|
|
2
2
|
//import { getAngle, bezierhasExtreme, getDistance } from "./geometry";
|
|
3
3
|
import { pathDataToAbsoluteOrRelative, pathDataToLonghands, pathDataArcsToCubics, pathDataQuadraticToCubic } from './pathData_convert.js';
|
|
4
|
+
import { pathDataToD } from './pathData_stringify.js';
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
|
|
@@ -15,10 +16,10 @@ export function normalizePathData(pathData = [],
|
|
|
15
16
|
quadraticToCubic = false,
|
|
16
17
|
arcToCubic = false,
|
|
17
18
|
arcAccuracy = 2,
|
|
18
|
-
} = {},
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// assume we need full normalization
|
|
21
21
|
hasRelatives = true, hasShorthands = true, hasQuadratics = true, hasArcs = true, testTypes = false
|
|
22
|
+
|
|
22
23
|
} = {}
|
|
23
24
|
) {
|
|
24
25
|
|
|
@@ -71,15 +72,29 @@ export function parsePathDataNormalized(d,
|
|
|
71
72
|
) {
|
|
72
73
|
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
let
|
|
76
|
-
|
|
75
|
+
// is already array
|
|
76
|
+
let isArray = Array.isArray(d);
|
|
77
|
+
|
|
78
|
+
// normalize native pathData to regular array
|
|
79
|
+
let hasConstructor = isArray && typeof d[0] === 'object' && typeof d[0].constructor === 'function'
|
|
80
|
+
/*
|
|
81
|
+
if (hasConstructor) {
|
|
82
|
+
d = d.map(com => { return { type: com.type, values: com.values } })
|
|
83
|
+
console.log('hasConstructor', hasConstructor, (typeof d[0].constructor), d);
|
|
84
|
+
}
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
let pathDataObj = isArray ? d : parsePathDataString(d);
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
let { hasRelatives = true, hasShorthands = true, hasQuadratics = true, hasArcs = true } = pathDataObj;
|
|
91
|
+
let pathData = hasConstructor ? pathDataObj : pathDataObj.pathData;
|
|
77
92
|
|
|
78
93
|
// normalize
|
|
79
94
|
pathData = normalizePathData(pathData,
|
|
80
|
-
{ toAbsolute, toLonghands, quadraticToCubic, arcToCubic, arcAccuracy
|
|
81
|
-
|
|
82
|
-
|
|
95
|
+
{ toAbsolute, toLonghands, quadraticToCubic, arcToCubic, arcAccuracy,
|
|
96
|
+
hasRelatives, hasShorthands, hasQuadratics, hasArcs
|
|
97
|
+
},
|
|
83
98
|
)
|
|
84
99
|
|
|
85
100
|
return pathData;
|
|
@@ -450,7 +465,8 @@ export function parsePathDataString(d, debug = true) {
|
|
|
450
465
|
if (debug === 'log') {
|
|
451
466
|
console.log(feedback);
|
|
452
467
|
} else {
|
|
453
|
-
throw new Error(feedback)
|
|
468
|
+
//throw new Error(feedback)
|
|
469
|
+
console.warn(feedback)
|
|
454
470
|
}
|
|
455
471
|
}
|
|
456
472
|
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
//import { pathDataToAbsoluteOrRelative, pathDataToLonghands, cubicToArc } from './pathData_convert.js';
|
|
2
2
|
import { parsePathDataString, parsePathDataNormalized, stringifyPathData } from './pathData_parse.js';
|
|
3
3
|
|
|
4
|
-
export function shapeElToPath(el){
|
|
4
|
+
export function shapeElToPath(el) {
|
|
5
5
|
|
|
6
6
|
let nodeName = el.nodeName.toLowerCase();
|
|
7
|
-
if(nodeName==='path')return el;
|
|
7
|
+
if (nodeName === 'path') return el;
|
|
8
8
|
|
|
9
9
|
let pathData = getPathDataFromEl(el);
|
|
10
|
-
let d = pathData.map(com=>{return `${com.type} ${com.values} `}).join(' ')
|
|
11
|
-
let attributes = [...el.attributes].map(att=>att.name);
|
|
10
|
+
let d = pathData.map(com => { return `${com.type} ${com.values} ` }).join(' ')
|
|
11
|
+
let attributes = [...el.attributes].map(att => att.name);
|
|
12
12
|
|
|
13
13
|
let pathN = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
14
|
-
pathN.setAttribute('d', d
|
|
14
|
+
pathN.setAttribute('d', d);
|
|
15
15
|
|
|
16
16
|
let exclude = ['x', 'y', 'cx', 'cy', 'dx', 'dy', 'r', 'rx', 'ry', 'width', 'height', 'points']
|
|
17
17
|
|
|
18
|
-
attributes.forEach(att=>{
|
|
19
|
-
if(!exclude.includes(att)){
|
|
18
|
+
attributes.forEach(att => {
|
|
19
|
+
if (!exclude.includes(att)) {
|
|
20
20
|
let val = el.getAttribute(att);
|
|
21
21
|
pathN.setAttribute(att, val)
|
|
22
22
|
}
|
|
@@ -29,7 +29,7 @@ export function shapeElToPath(el){
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
// retrieve pathdata from svg geometry elements
|
|
32
|
-
export function getPathDataFromEl(el, stringify=false) {
|
|
32
|
+
export function getPathDataFromEl(el, stringify = false) {
|
|
33
33
|
|
|
34
34
|
let pathData = [];
|
|
35
35
|
let type = el.nodeName;
|
|
@@ -190,7 +190,9 @@ export function getPathDataFromEl(el, stringify=false) {
|
|
|
190
190
|
attNames = ['cx', 'cy', 'rx', 'ry', 'r'];
|
|
191
191
|
({ cx, cy, r, rx, ry } = getAtts(attNames));
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
let isCircle = type === 'circle';
|
|
194
|
+
|
|
195
|
+
if (isCircle) {
|
|
194
196
|
r = r;
|
|
195
197
|
rx = r
|
|
196
198
|
ry = r
|
|
@@ -199,10 +201,14 @@ export function getPathDataFromEl(el, stringify=false) {
|
|
|
199
201
|
ry = ry ? ry : r;
|
|
200
202
|
}
|
|
201
203
|
|
|
204
|
+
// simplified radii for cirecles
|
|
205
|
+
let rxS = isCircle && r>=1 ? 1 : rx;
|
|
206
|
+
let ryS = isCircle && r>=1 ? 1 : rx;
|
|
207
|
+
|
|
202
208
|
pathData = [
|
|
203
209
|
{ type: "M", values: [cx + rx, cy] },
|
|
204
|
-
{ type: "A", values: [
|
|
205
|
-
{ type: "A", values: [
|
|
210
|
+
{ type: "A", values: [rxS, ryS, 0, 1, 1, cx - rx, cy] },
|
|
211
|
+
{ type: "A", values: [rxS, ryS, 0, 1, 1, cx + rx, cy] },
|
|
206
212
|
];
|
|
207
213
|
|
|
208
214
|
break;
|
|
@@ -234,6 +240,6 @@ export function getPathDataFromEl(el, stringify=false) {
|
|
|
234
240
|
break;
|
|
235
241
|
}
|
|
236
242
|
|
|
237
|
-
return stringify ? stringifyPathData(pathData): pathData;
|
|
243
|
+
return stringify ? stringifyPathData(pathData) : pathData;
|
|
238
244
|
|
|
239
245
|
};
|
|
@@ -3,21 +3,25 @@ import { getPolygonArea } from "./geometry_area.js";
|
|
|
3
3
|
import { checkBezierFlatness, commandIsFlat } from "./geometry_flatness.js";
|
|
4
4
|
import { renderPoint } from "./visualize.js";
|
|
5
5
|
|
|
6
|
-
export function pathDataRemoveColinear(pathData,
|
|
6
|
+
export function pathDataRemoveColinear(pathData, {
|
|
7
|
+
tolerance = 1,
|
|
8
|
+
//toleranceCubics = null,
|
|
9
|
+
flatBezierToLinetos = true
|
|
10
|
+
}={}) {
|
|
7
11
|
|
|
12
|
+
//toleranceCubics = !toleranceCubics ? tolerance : toleranceCubics;
|
|
8
13
|
let pathDataN = [pathData[0]];
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
let lastType = 'L';
|
|
12
15
|
let M = { x: pathData[0].values[0], y: pathData[0].values[1] }
|
|
13
16
|
let p0 = M;
|
|
14
17
|
let p = M
|
|
15
18
|
let isClosed = pathData[pathData.length - 1].type.toLowerCase() === 'z'
|
|
16
19
|
|
|
17
20
|
for (let c = 1, l = pathData.length; c < l; c++) {
|
|
18
|
-
let comPrev = pathData[c - 1];
|
|
21
|
+
//let comPrev = pathData[c - 1];
|
|
19
22
|
let com = pathData[c];
|
|
20
23
|
let comN = pathData[c + 1] || pathData[l - 1];
|
|
24
|
+
//let p1 = comN.type.toLowerCase() === 'z' ? M : { x: comN.values[comN.values.length - 2], y: comN.values[comN.values.length - 1] }
|
|
21
25
|
let p1 = comN.type.toLowerCase() === 'z' ? M : { x: comN.values[comN.values.length - 2], y: comN.values[comN.values.length - 1] }
|
|
22
26
|
|
|
23
27
|
let { type, values } = com;
|
|
@@ -26,19 +30,18 @@ export function pathDataRemoveColinear(pathData, tolerance = 1, flatBezierToLine
|
|
|
26
30
|
|
|
27
31
|
let area = getPolygonArea([p0, p, p1], true)
|
|
28
32
|
|
|
29
|
-
let distSquare0 = getSquareDistance(p0, p)
|
|
30
|
-
let distSquare1 = getSquareDistance(p, p1)
|
|
33
|
+
//let distSquare0 = getSquareDistance(p0, p)
|
|
34
|
+
//let distSquare1 = getSquareDistance(p, p1)
|
|
31
35
|
let distSquare = getSquareDistance(p0, p1)
|
|
32
|
-
//distSquare = (distSquare0+distSquare1)
|
|
36
|
+
//distSquare = (distSquare0+distSquare1) * 0.5
|
|
33
37
|
|
|
34
|
-
let distMax = distSquare /
|
|
38
|
+
let distMax = distSquare ? distSquare / 333 * tolerance : 0
|
|
35
39
|
|
|
36
40
|
let isFlat = area < distMax;
|
|
37
41
|
let isFlatBez = false;
|
|
38
42
|
|
|
39
43
|
|
|
40
44
|
if (!flatBezierToLinetos && type === 'C') isFlat = false;
|
|
41
|
-
//let isFlat = flatBezierToLinetos && type === 'C' ? area < distMax : false
|
|
42
45
|
|
|
43
46
|
// convert flat beziers to linetos
|
|
44
47
|
if (flatBezierToLinetos && (type === 'C' || type === 'Q')) {
|
|
@@ -47,41 +50,41 @@ export function pathDataRemoveColinear(pathData, tolerance = 1, flatBezierToLine
|
|
|
47
50
|
[{ x: values[0], y: values[1] }, { x: values[2], y: values[3] }] :
|
|
48
51
|
(type === 'Q' ? [{ x: values[0], y: values[1] }] : []);
|
|
49
52
|
|
|
53
|
+
isFlatBez = commandIsFlat([p0, ...cpts, p],{tolerance});
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
isFlatBez = checkBezierFlatness(p0, cpts, p)
|
|
54
|
-
//isFlatBez = commandIsFlat([p0, ...cpts, p]).flat
|
|
55
|
-
// console.log();
|
|
56
|
-
|
|
57
|
-
//isFlatBez = areaBez < distMax * 0.25
|
|
58
|
-
//console.log('isFlatBez', isFlatBez);
|
|
59
|
-
//isFlatBez = false
|
|
60
|
-
|
|
61
|
-
//&& comPrev.type !== 'C'
|
|
62
|
-
if (isFlatBez && c < l - 1 && comPrev.type !== 'C') {
|
|
55
|
+
if (isFlatBez && c < l - 1 ) {
|
|
63
56
|
type = "L"
|
|
64
57
|
com.type = "L"
|
|
65
58
|
com.values = valsL
|
|
66
|
-
|
|
67
|
-
//renderPoint(markers, p)
|
|
59
|
+
//renderPoint(markers, p, 'cyan', '1%', '0.5')
|
|
68
60
|
}
|
|
69
|
-
|
|
70
61
|
}
|
|
71
62
|
|
|
72
|
-
// update end point
|
|
73
|
-
p0 = p;
|
|
74
63
|
|
|
75
64
|
// colinear – exclude arcs (as always =) as semicircles won't have an area
|
|
76
65
|
//&& comN.type==='L'
|
|
77
66
|
if ( isFlat && c < l - 1 && (type === 'L' || (flatBezierToLinetos && isFlatBez)) ) {
|
|
78
|
-
//console.log(area,distMax );
|
|
79
|
-
//renderPoint(markers, p)
|
|
80
67
|
|
|
68
|
+
/*
|
|
69
|
+
console.log(area, distMax );
|
|
81
70
|
//if(comN.type!=='L' ){}
|
|
71
|
+
|
|
72
|
+
if(p0.x === p.x && p0.y === p.y){
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
renderPoint(markers, p0, 'blue', '1.5%', '1')
|
|
77
|
+
renderPoint(markers, p, 'red', '1%', '1')
|
|
78
|
+
renderPoint(markers, p1, 'cyan', '0.5%', '1')
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
|
|
82
82
|
continue;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
// update end point
|
|
86
|
+
p0 = p;
|
|
87
|
+
|
|
85
88
|
|
|
86
89
|
if (type === 'M') {
|
|
87
90
|
M = p
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export function removeOrphanedM(pathData) {
|
|
2
2
|
|
|
3
|
+
let pathDataN = []
|
|
3
4
|
for (let i = 0, l = pathData.length; i < l; i++) {
|
|
4
5
|
let com = pathData[i];
|
|
5
6
|
if (!com) continue;
|
|
@@ -8,13 +9,13 @@ export function removeOrphanedM(pathData) {
|
|
|
8
9
|
if ((type === 'M' || type === 'm')) {
|
|
9
10
|
|
|
10
11
|
if (!comN || (comN && (comN.type === 'Z' || comN.type === 'z'))) {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
if(comN) i++
|
|
13
|
+
continue
|
|
13
14
|
}
|
|
14
15
|
}
|
|
16
|
+
pathDataN.push(com)
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
return pathData;
|
|
19
|
+
return pathDataN;
|
|
19
20
|
|
|
20
21
|
}
|
|
@@ -26,20 +26,24 @@ export function removeZeroLengthLinetos(pathData) {
|
|
|
26
26
|
|
|
27
27
|
for (let c = 1, l = pathData.length; c < l; c++) {
|
|
28
28
|
let com = pathData[c];
|
|
29
|
+
let comPrev = pathData[c-1]
|
|
30
|
+
let comNext = pathData[c+1] || null
|
|
29
31
|
let { type, values } = com;
|
|
30
32
|
|
|
33
|
+
// zero length segments are simetimes used in icons for dots
|
|
34
|
+
let isDot = comPrev.type.toLowerCase() ==='m' && !comNext;
|
|
35
|
+
|
|
31
36
|
let valsLen = values.length;
|
|
32
|
-
//let valsL = values.slice(-2);
|
|
33
|
-
//p = { x: valsL[0], y: valsL[1] };
|
|
34
37
|
p = { x: values[valsLen-2], y: values[valsLen-1] };
|
|
35
38
|
|
|
36
39
|
// skip lineto
|
|
37
|
-
if (type === 'L' && p.x === p0.x && p.y === p0.y) {
|
|
40
|
+
if (!isDot && type === 'L' && p.x === p0.x && p.y === p0.y) {
|
|
38
41
|
continue
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
|
|
41
45
|
// skip minified zero length
|
|
42
|
-
if (type === 'l' || type === 'v' || type === 'h') {
|
|
46
|
+
if (!isDot && (type === 'l' || type === 'v' || type === 'h')) {
|
|
43
47
|
let noLength = type === 'l' ? (values.join('') === '00') : values[0] === 0;
|
|
44
48
|
if(noLength) continue
|
|
45
49
|
}
|
|
@@ -14,6 +14,8 @@ export function pathDataToTopLeft(pathData) {
|
|
|
14
14
|
let len = pathData.length;
|
|
15
15
|
let isClosed = pathData[len - 1].type.toLowerCase() === 'z'
|
|
16
16
|
|
|
17
|
+
//return pathData;
|
|
18
|
+
|
|
17
19
|
// we can't change starting point for non closed paths
|
|
18
20
|
if (!isClosed) {
|
|
19
21
|
return pathData
|
|
@@ -54,6 +56,8 @@ export function optimizeClosePath(pathData, removeFinalLineto = true, reorder =
|
|
|
54
56
|
|
|
55
57
|
let linetos = pathData.filter(com => com.type === 'L')
|
|
56
58
|
|
|
59
|
+
//return pathData;
|
|
60
|
+
|
|
57
61
|
|
|
58
62
|
// check if order is ideal
|
|
59
63
|
let penultimateCom = pathData[len - 2];
|
|
@@ -107,7 +111,7 @@ export function optimizeClosePath(pathData, removeFinalLineto = true, reorder =
|
|
|
107
111
|
}
|
|
108
112
|
// use top most command
|
|
109
113
|
else {
|
|
110
|
-
indices = indices.sort((a, b) => +a.y.toFixed(
|
|
114
|
+
indices = indices.sort((a, b) => +a.y.toFixed(8) - +b.y.toFixed(8) || a.x - b.x);
|
|
111
115
|
newIndex = indices[0].index
|
|
112
116
|
}
|
|
113
117
|
|
|
@@ -116,7 +120,7 @@ export function optimizeClosePath(pathData, removeFinalLineto = true, reorder =
|
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
|
|
119
|
-
M = { x: +pathData[0].values[0].toFixed(8), y: +pathData[0].values[1].toFixed(
|
|
123
|
+
M = { x: +pathData[0].values[0].toFixed(8), y: +pathData[0].values[1].toFixed(8) }
|
|
120
124
|
|
|
121
125
|
len = pathData.length
|
|
122
126
|
|