svg-path-simplify 0.4.3 → 0.4.4
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/CHANGELOG.md +11 -0
- package/README.md +1 -0
- package/dist/svg-path-simplify.esm.js +1610 -495
- package/dist/svg-path-simplify.esm.min.js +2 -2
- package/dist/svg-path-simplify.js +1611 -494
- package/dist/svg-path-simplify.min.js +2 -2
- package/dist/svg-path-simplify.pathdata.esm.js +893 -456
- package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
- package/dist/svg-path-simplify.poly.cjs +9 -8
- package/index.html +58 -17
- package/package.json +1 -1
- package/src/constants.js +4 -0
- package/src/detect_input.js +47 -29
- package/src/index.js +8 -0
- package/src/pathData_simplify_cubic.js +26 -16
- package/src/pathData_simplify_revertToquadratics.js +0 -1
- package/src/pathSimplify-main.js +75 -20
- package/src/pathSimplify-only-pathdata.js +7 -2
- package/src/pathSimplify-presets.js +15 -4
- package/src/svg-getAttributes.js +4 -2
- package/src/svgii/convert_units.js +1 -1
- package/src/svgii/geometry.js +140 -2
- package/src/svgii/geometry_bbox_element.js +1 -1
- package/src/svgii/geometry_deduceRadius.js +116 -27
- package/src/svgii/geometry_length.js +17 -1
- package/src/svgii/pathData_analyze.js +18 -0
- package/src/svgii/pathData_convert.js +188 -88
- package/src/svgii/pathData_fix_directions.js +10 -18
- package/src/svgii/pathData_reorder.js +122 -16
- package/src/svgii/pathData_simplify_refineCorners.js +130 -35
- package/src/svgii/pathData_simplify_refine_round.js +420 -0
- package/src/svgii/rounding.js +79 -78
- package/src/svgii/svg_cleanup.js +68 -20
- package/src/svgii/svg_cleanup_convertPathLength.js +22 -15
- package/src/svgii/svg_cleanup_remove_els_and_atts.js +6 -1
- package/src/svgii/svg_el_parse_style_props.js +13 -10
- package/src/svgii/svg_validate.js +220 -0
- package/tests/testSVG.js +14 -1
- package/src/svgii/pathData_refine_round.js +0 -222
|
@@ -143,10 +143,10 @@ export function combineCubicPairs(com1, com2, {
|
|
|
143
143
|
let comS = getExtrapolatedCommand(com1, com2, t)
|
|
144
144
|
|
|
145
145
|
// test new point-at-t against original mid segment starting point
|
|
146
|
-
let
|
|
146
|
+
let ptI = pointAtT([comS.p0, comS.cp1, comS.cp2, comS.p], t)
|
|
147
147
|
|
|
148
148
|
|
|
149
|
-
let dist0 = getDistManhattan(com1.p,
|
|
149
|
+
let dist0 = getDistManhattan(com1.p, ptI)
|
|
150
150
|
let dist1 = 0, dist2 = 0;
|
|
151
151
|
let close = dist0 < maxDist;
|
|
152
152
|
let success = false;
|
|
@@ -162,32 +162,42 @@ export function combineCubicPairs(com1, com2, {
|
|
|
162
162
|
* to prevent distortions
|
|
163
163
|
*/
|
|
164
164
|
|
|
165
|
-
//
|
|
166
|
-
let
|
|
165
|
+
// 1st segment mid
|
|
166
|
+
let ptM_seg1 = pointAtT([com1.p0, com1.cp1, com1.cp2, com1.p], 0.5)
|
|
167
|
+
|
|
168
|
+
let t2 = t * 0.5;
|
|
169
|
+
// combined interpolated mid point
|
|
170
|
+
let ptI_seg1 = pointAtT([comS.p0, comS.cp1, comS.cp2, comS.p], t2)
|
|
171
|
+
dist1 = getDistManhattan(ptM_seg1, ptI_seg1)
|
|
167
172
|
|
|
168
|
-
// simplified path
|
|
169
|
-
let t3 = (1 + t) * 0.5;
|
|
170
|
-
let ptS_2 = pointAtT([comS.p0, comS.cp1, comS.cp2, comS.p], t3)
|
|
171
|
-
dist1 = getDistManhattan(pt_2, ptS_2)
|
|
172
173
|
|
|
173
174
|
error += dist1;
|
|
174
175
|
|
|
175
176
|
if (dist1 < maxDist) {
|
|
176
177
|
|
|
177
|
-
//
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// 1st segment mid
|
|
181
|
-
let pt_1 = pointAtT([com1.p0, com1.cp1, com1.cp2, com1.p], 0.5)
|
|
178
|
+
// 2nd segment mid
|
|
179
|
+
let ptM_seg2 = pointAtT([com2.p0, com2.cp1, com2.cp2, com2.p], 0.5)
|
|
182
180
|
|
|
183
|
-
|
|
184
|
-
let
|
|
185
|
-
|
|
181
|
+
// simplified path
|
|
182
|
+
let t3 = (1 + t) * 0.5;
|
|
183
|
+
let ptI_seg2 = pointAtT([comS.p0, comS.cp1, comS.cp2, comS.p], t3)
|
|
184
|
+
dist2 = getDistManhattan(ptM_seg2, ptI_seg2)
|
|
186
185
|
|
|
187
186
|
error += dist2;
|
|
188
187
|
|
|
189
188
|
if (error < maxDist) success = true;
|
|
190
189
|
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
renderPoint(markers, ptM_seg1, 'cyan')
|
|
193
|
+
renderPoint(markers, pt, 'orange', '1.5%', '1')
|
|
194
|
+
renderPoint(markers, ptM_seg2, 'orange')
|
|
195
|
+
|
|
196
|
+
renderPoint(markers, com1.p, 'green')
|
|
197
|
+
//renderPoint(markers, com2.p, 'green')
|
|
198
|
+
renderPoint(markers, ptI_seg1, 'purple')
|
|
199
|
+
*/
|
|
200
|
+
|
|
191
201
|
}
|
|
192
202
|
|
|
193
203
|
} // end 1st try
|
|
@@ -6,7 +6,6 @@ export function pathDataRevertCubicToQuadratic(pathData, tolerance=1) {
|
|
|
6
6
|
let com = pathData[c]
|
|
7
7
|
let { type, values, p0, cp1 = null, cp2 = null, p = null } = com;
|
|
8
8
|
if (type === 'C') {
|
|
9
|
-
//console.log(com);
|
|
10
9
|
let comQ = revertCubicQuadratic(p0, cp1, cp2, p, tolerance)
|
|
11
10
|
if (comQ.type === 'Q') {
|
|
12
11
|
comQ.extreme = com.extreme
|
package/src/pathSimplify-main.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { detectInputType } from './detect_input';
|
|
2
2
|
import { simplifyPathDataCubic } from './pathData_simplify_cubic';
|
|
3
|
-
import { getDistManhattan, getDistance, getPathDataVertices, interpolate, pointAtT, reducePoints, svgArcToCenterParam, toParametricAngle } from './svgii/geometry';
|
|
3
|
+
import { getDistManhattan, getDistance, getPathDataVertices, getSquareDistance, interpolate, pointAtT, reducePoints, svgArcToCenterParam, toParametricAngle } from './svgii/geometry';
|
|
4
4
|
import { getPolyBBox } from './svgii/geometry_bbox';
|
|
5
5
|
import { analyzePathData, getPathDataVerbose } from './svgii/pathData_analyze';
|
|
6
6
|
import { normalizePathData, parsePathDataNormalized, convertPathData } from './svgii/pathData_convert';
|
|
@@ -16,7 +16,7 @@ import { detectAccuracy, roundPathData, roundTo } from './svgii/rounding';
|
|
|
16
16
|
import { refineAdjacentExtremes } from './svgii/pathData_simplify_refineExtremes';
|
|
17
17
|
import { cleanUpSVG, removeEmptySVGEls } from './svgii/svg_cleanup';
|
|
18
18
|
import { refineRoundedCorners } from './svgii/pathData_simplify_refineCorners';
|
|
19
|
-
import { refineRoundSegments } from './svgii/
|
|
19
|
+
import { refineRoundSegments, simplifyAdjacentRound } from './svgii/pathData_simplify_refine_round';
|
|
20
20
|
import { refineClosingCommand } from './svgii/pathData_remove_short';
|
|
21
21
|
import { scalePathData } from './svgii/pathData_transform_scale';
|
|
22
22
|
import { getViewBox } from './svg_getViewbox';
|
|
@@ -32,7 +32,7 @@ import { normalizePoly, polyPtsToArray } from './svgii/poly_normalize';
|
|
|
32
32
|
import { simplifyPolyRD } from './simplify_poly_radial_distance';
|
|
33
33
|
import { simplifyPolyRDP, simplifyPolyRDP__, simplifyRDP_rel } from './simplify_poly_RDP';
|
|
34
34
|
import { getEllipseLengthLG, getLegendreGaussValues, getLength, waArr_global } from './svgii/geometry_length';
|
|
35
|
-
import { deg2rad } from './constants';
|
|
35
|
+
import { deg2rad, dummySVG } from './constants';
|
|
36
36
|
import { getPathDataLength } from './svgii/pathData_getLength';
|
|
37
37
|
import { stringifySVG } from './string_helpers';
|
|
38
38
|
import { presetSettings, settingsDefaults } from './pathSimplify-presets';
|
|
@@ -55,21 +55,54 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
let { getObject = false, removeComments, removeOffCanvas, unGroup, mergePaths, removeElements, removeDimensions, removeIds, removeClassNames, omitNamespace, cleanUpStrokes, addViewBox, addDimensions, removePrologue, removeHidden, removeUnused, cleanupDefs, cleanupClip, cleanupSVGAtts, removeNameSpaced, removeNameSpacedAtts, attributesToGroup, minifyRgbColors, stylesToAttributes, fixHref, legacyHref, allowMeta, allowDataAtts, allowAriaAtts,
|
|
58
|
+
let { getObject = false, removeComments, removeOffCanvas, unGroup, mergePaths, removeElements, removeDimensions, removeIds, removeClassNames, omitNamespace, cleanUpStrokes, addViewBox, addDimensions, removePrologue, removeHidden, removeUnused, cleanupDefs, cleanupClip, cleanupSVGAtts, removeNameSpaced, removeNameSpacedAtts, attributesToGroup, minifyRgbColors, stylesToAttributes, fixHref, legacyHref, allowMeta, allowDataAtts, allowAriaAtts, removeSVGAttributes, removeElAttributes, shapesToPaths, shapeConvert, convertShapes, simplifyBezier, optimizeOrder, autoClose, removeZeroLength, refineClosing, removeColinear, flatBezierToLinetos, revertToQuadratics, refineExtremes, simplifyCorners, fixDirections, keepExtremes, keepCorners, keepInflections, addExtremes, reversePath, toAbsolute, toRelative, toMixed, toShorthands, toLonghands, quadraticToCubic, arcToCubic, cubicToArc, lineToCubic, decimals, autoAccuracy, minifyD, tolerance, toPolygon, smoothPoly, polyFormat, precisionPoly, simplifyRD, simplifyRDP, harmonizeCpts, removeOrphanSubpaths, simplifyRound, simplifyQuadraticCorners, scale, scaleTo, crop, alignToOrigin, convertTransforms, keepSmaller, splitCompound, convertPathLength, toAbsoluteUnits } = settings;
|
|
59
59
|
|
|
60
60
|
//toAbsolute = !toRelative;
|
|
61
61
|
|
|
62
62
|
// clamp tolerance and scale
|
|
63
63
|
tolerance = Math.max(0.1, tolerance);
|
|
64
64
|
scale = Math.max(0.001, scale)
|
|
65
|
-
if(fixDirections) keepSmaller = false;
|
|
65
|
+
if (fixDirections) keepSmaller = false;
|
|
66
66
|
if (scale !== 1 || scaleTo || crop || alignToOrigin) {
|
|
67
67
|
convertTransforms = true;
|
|
68
68
|
settings.convertTransforms = true
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* intercept
|
|
74
|
+
* invalid inputs
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
let inputDetection = detectInputType(input);
|
|
78
|
+
let { inputType, log } = inputDetection
|
|
79
|
+
|
|
80
|
+
// invalid file
|
|
81
|
+
if (inputType === 'invalid' || input === dummySVG) {
|
|
82
|
+
// return dummy SVG to continue processing
|
|
83
|
+
//input = dummySVG;
|
|
84
|
+
//inputType = 'invalid';
|
|
85
|
+
|
|
86
|
+
//console.warn(`Input is not valid!\n ${log}`);
|
|
87
|
+
//console.log(input);
|
|
88
|
+
//return false
|
|
89
|
+
|
|
90
|
+
let report = {
|
|
91
|
+
original: 0,
|
|
92
|
+
new: 0,
|
|
93
|
+
saved: 0,
|
|
94
|
+
svgSize:0,
|
|
95
|
+
svgSizeOpt:0,
|
|
96
|
+
compression:0,
|
|
97
|
+
decimals:0,
|
|
98
|
+
invalid:true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { svg: dummySVG, d: '', polys: [], report, pathDataPlusArr: [], pathDataPlusArr_global: [], inputType: 'invalid', dOriginal: '' };
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
73
106
|
let svg = '';
|
|
74
107
|
let svgSize = 0;
|
|
75
108
|
let svgSizeOpt = 0;
|
|
@@ -81,12 +114,12 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
81
114
|
|
|
82
115
|
// pathdata superset array - containing additional data
|
|
83
116
|
let pathDataPlusArr_global = []
|
|
84
|
-
let paths = []
|
|
117
|
+
let paths = [];
|
|
85
118
|
let isPoly = false;
|
|
86
|
-
let polys = []
|
|
87
|
-
let poly = []
|
|
119
|
+
let polys = [];
|
|
120
|
+
let poly = [];
|
|
88
121
|
let dStr = '';
|
|
89
|
-
let dOriginal = ''
|
|
122
|
+
let dOriginal = '';
|
|
90
123
|
|
|
91
124
|
/**
|
|
92
125
|
* normalize input
|
|
@@ -204,10 +237,7 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
204
237
|
// convert all shapes to paths
|
|
205
238
|
if (shapesToPaths) {
|
|
206
239
|
shapeConvert = 'toPaths'
|
|
207
|
-
|
|
208
|
-
convert_ellipses = true
|
|
209
|
-
convert_poly = true
|
|
210
|
-
convert_lines = true
|
|
240
|
+
convertShapes = ['rect', 'polygon', 'polyline', 'line', 'circle', 'ellipse']
|
|
211
241
|
}
|
|
212
242
|
|
|
213
243
|
//console.log('shapesToPaths', shapesToPaths, 'shapeConvert', shapeConvert, convert_rects, convert_ellipses, convert_poly);
|
|
@@ -255,6 +285,9 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
255
285
|
}
|
|
256
286
|
//console.log('pathOptions', pathOptions);
|
|
257
287
|
|
|
288
|
+
let comCount = 0
|
|
289
|
+
let comCountS = 0
|
|
290
|
+
|
|
258
291
|
|
|
259
292
|
for (let i = 0, l = paths.length; l && i < l; i++) {
|
|
260
293
|
|
|
@@ -306,7 +339,7 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
306
339
|
}
|
|
307
340
|
|
|
308
341
|
// count commands for evaluation
|
|
309
|
-
|
|
342
|
+
comCount += pathData.length
|
|
310
343
|
|
|
311
344
|
if (!isPoly && removeOrphanSubpaths) pathData = removeOrphanedM(pathData);
|
|
312
345
|
|
|
@@ -463,7 +496,6 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
463
496
|
|
|
464
497
|
|
|
465
498
|
|
|
466
|
-
|
|
467
499
|
// simplify beziers
|
|
468
500
|
let { pathData, bb, dimA } = pathDataPlus;
|
|
469
501
|
|
|
@@ -498,12 +530,14 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
498
530
|
//pathData = removeZeroLengthLinetos(pathData);
|
|
499
531
|
|
|
500
532
|
let threshold = (bb.width + bb.height) * 0.1
|
|
501
|
-
pathData = refineRoundedCorners(pathData, { threshold, tolerance })
|
|
533
|
+
pathData = refineRoundedCorners(pathData, { threshold, tolerance, simplifyQuadraticCorners })
|
|
502
534
|
}
|
|
503
535
|
|
|
504
536
|
// refine round segment sequences
|
|
505
|
-
if (simplifyRound)
|
|
506
|
-
|
|
537
|
+
if (simplifyRound) {
|
|
538
|
+
pathData = refineRoundSegments(pathData);
|
|
539
|
+
pathData = simplifyAdjacentRound(pathData);
|
|
540
|
+
}
|
|
507
541
|
|
|
508
542
|
// simplify to quadratics
|
|
509
543
|
if (revertToQuadratics) pathData = pathDataRevertCubicToQuadratic(pathData, tolerance);
|
|
@@ -550,7 +584,25 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
550
584
|
|
|
551
585
|
// prefer top to bottom priority for portrait aspect ratios
|
|
552
586
|
if (optimizeOrder) {
|
|
587
|
+
/*
|
|
553
588
|
pathDataPlusArr = isPortrait ? pathDataPlusArr.sort((a, b) => a.bb.y - b.bb.y || a.bb.x - b.bb.x) : pathDataPlusArr.sort((a, b) => a.bb.x - b.bb.x || a.bb.y - b.bb.y)
|
|
589
|
+
*/
|
|
590
|
+
|
|
591
|
+
// add missin bbox
|
|
592
|
+
pathDataPlusArr.forEach(p => {
|
|
593
|
+
if (p.bb.x === undefined) {
|
|
594
|
+
p.bb = getPolyBBox(getPathDataVertices(p.pathData))
|
|
595
|
+
}
|
|
596
|
+
})
|
|
597
|
+
|
|
598
|
+
try {
|
|
599
|
+
pathDataPlusArr = pathDataPlusArr.sort((a, b) => +a.bb.x.toFixed(2) - (+b.bb.x.toFixed(2)) || a.bb.y - b.bb.y);
|
|
600
|
+
//console.log(pathDataPlusArr);
|
|
601
|
+
|
|
602
|
+
} catch {
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
|
|
554
606
|
}
|
|
555
607
|
|
|
556
608
|
|
|
@@ -623,7 +675,7 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
623
675
|
|
|
624
676
|
|
|
625
677
|
// compare command count
|
|
626
|
-
|
|
678
|
+
comCountS += pathData.length
|
|
627
679
|
|
|
628
680
|
let dOpt = pathDataToD(pathData, minifyD)
|
|
629
681
|
//svgSizeOpt = new Blob([dOpt]).size;
|
|
@@ -706,6 +758,9 @@ export function svgPathSimplify(input = '', settings = {}) {
|
|
|
706
758
|
|
|
707
759
|
|
|
708
760
|
report = {
|
|
761
|
+
original: comCount,
|
|
762
|
+
new: comCountS,
|
|
763
|
+
saved: comCount - comCountS,
|
|
709
764
|
svgSize,
|
|
710
765
|
svgSizeOpt,
|
|
711
766
|
compression,
|
|
@@ -13,10 +13,11 @@ import { pathDataToD } from './svgii/pathData_stringify';
|
|
|
13
13
|
import { detectAccuracy } from './svgii/rounding';
|
|
14
14
|
import { refineAdjacentExtremes } from './svgii/pathData_simplify_refineExtremes';
|
|
15
15
|
import { refineRoundedCorners } from './svgii/pathData_simplify_refineCorners';
|
|
16
|
-
import { refineRoundSegments } from './svgii/pathData_refine_round';
|
|
16
|
+
//import { refineRoundSegments } from './svgii/pathData_refine_round';
|
|
17
17
|
import { refineClosingCommand } from './svgii/pathData_remove_short';
|
|
18
18
|
import { pathDataRevertCubicToQuadratic } from './pathData_simplify_revertToquadratics';
|
|
19
19
|
import { pathDataLineToCubic } from './svgii/pathData_line_to_cubic';
|
|
20
|
+
import { refineRoundSegments } from './svgii/pathData_simplify_refine_round';
|
|
20
21
|
|
|
21
22
|
//import { installDOMPolyfills } from './dom-polyfill';
|
|
22
23
|
|
|
@@ -97,7 +98,11 @@ export function simplifyPathData(input = '', {
|
|
|
97
98
|
let yArr = []
|
|
98
99
|
|
|
99
100
|
// mode:0 – single path
|
|
100
|
-
let inputType = detectInputType(input)
|
|
101
|
+
//let inputType = detectInputType(input)
|
|
102
|
+
let inputDetection = detectInputType(input);
|
|
103
|
+
let {inputType, log} = inputDetection
|
|
104
|
+
|
|
105
|
+
|
|
101
106
|
if (inputType === 'pathDataString') {
|
|
102
107
|
d = input
|
|
103
108
|
} else if (inputType === 'polyString') {
|
|
@@ -30,6 +30,7 @@ export let settingsDefaults = {
|
|
|
30
30
|
allowAriaAtts: true,
|
|
31
31
|
//pathlength conversion
|
|
32
32
|
convertPathLength: false,
|
|
33
|
+
toAbsoluteUnits: false,
|
|
33
34
|
|
|
34
35
|
// custom removal
|
|
35
36
|
removeElements: [],
|
|
@@ -61,6 +62,7 @@ export let settingsDefaults = {
|
|
|
61
62
|
revertToQuadratics: true,
|
|
62
63
|
refineExtremes: false,
|
|
63
64
|
simplifyCorners: false,
|
|
65
|
+
simplifyQuadraticCorners: false,
|
|
64
66
|
keepExtremes: true,
|
|
65
67
|
keepCorners: true,
|
|
66
68
|
keepInflections: false,
|
|
@@ -121,7 +123,7 @@ for (let prop in settingsDefaults) {
|
|
|
121
123
|
let isArray = Array.isArray(val)
|
|
122
124
|
|
|
123
125
|
if (isBoolean) val = false
|
|
124
|
-
else if (!isArray && isNum) val = val===1 ? 1 : (prop==='decimals'? -1 : 0);
|
|
126
|
+
else if (!isArray && isNum) val = val === 1 ? 1 : (prop === 'decimals' ? -1 : 0);
|
|
125
127
|
else if (isArray) val = []
|
|
126
128
|
settingsNull[prop] = val;
|
|
127
129
|
}
|
|
@@ -153,10 +155,14 @@ export const presetSettings = {
|
|
|
153
155
|
...settingsDefaults,
|
|
154
156
|
...{
|
|
155
157
|
keepSmaller: false,
|
|
158
|
+
convertPathLength:true,
|
|
156
159
|
toRelative: true,
|
|
157
160
|
toMixed: true,
|
|
158
161
|
toShorthands: true,
|
|
159
162
|
//fixHref: true,
|
|
163
|
+
allowMeta:true,
|
|
164
|
+
allowDataAtts:true,
|
|
165
|
+
allowAriaAtts:true,
|
|
160
166
|
legacyHref: true,
|
|
161
167
|
addViewBox: true,
|
|
162
168
|
addDimensions: true,
|
|
@@ -224,19 +230,24 @@ export const presetSettings = {
|
|
|
224
230
|
high: {
|
|
225
231
|
...settingsDefaults,
|
|
226
232
|
...{
|
|
227
|
-
tolerance: 1.
|
|
233
|
+
tolerance: 1.1,
|
|
228
234
|
toMixed: true,
|
|
229
235
|
refineExtremes: true,
|
|
230
236
|
simplifyCorners: true,
|
|
237
|
+
simplifyQuadraticCorners: true,
|
|
238
|
+
removeOrphanSubpaths: true,
|
|
231
239
|
simplifyRound: true,
|
|
232
240
|
removeClassNames: true,
|
|
233
241
|
cubicToArc: true,
|
|
242
|
+
minifyD: 0,
|
|
234
243
|
removeComments: true,
|
|
235
244
|
removeHidden: true,
|
|
236
|
-
removeOffCanvas: true,
|
|
237
245
|
addViewBox: true,
|
|
238
246
|
removeDimensions: true,
|
|
239
|
-
|
|
247
|
+
removeOffCanvas: true,
|
|
248
|
+
|
|
249
|
+
/*
|
|
250
|
+
*/
|
|
240
251
|
}
|
|
241
252
|
}
|
|
242
253
|
|
package/src/svg-getAttributes.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { normalizeUnits } from "./svgii/convert_units";
|
|
2
2
|
|
|
3
3
|
export function getElementAtts(el, {x=0, y=0, width=0, height=0}={}){
|
|
4
|
-
let attributes = [...el.attributes];
|
|
4
|
+
//let attributes = [...el.attributes];
|
|
5
|
+
let attributes = [...el.attributes].map(att=>att.name);
|
|
5
6
|
|
|
6
7
|
let atts={};
|
|
7
8
|
attributes.forEach(att=>{
|
|
8
|
-
let value = normalizeUnits(att.nodeValue, {x, y, width, height});
|
|
9
|
+
//let value = normalizeUnits(att.nodeValue, {x, y, width, height});
|
|
10
|
+
let value = normalizeUnits(el.getAttribute(att), {x, y, width, height});
|
|
9
11
|
atts[att.name] = value
|
|
10
12
|
})
|
|
11
13
|
|
package/src/svgii/geometry.js
CHANGED
|
@@ -321,6 +321,7 @@ export function pointAtT(pts, t = 0.5, getTangent = false, getCpts = false, retu
|
|
|
321
321
|
let t1 = 1 - t;
|
|
322
322
|
|
|
323
323
|
// cubic beziers
|
|
324
|
+
/*
|
|
324
325
|
if (isCubic) {
|
|
325
326
|
pt = {
|
|
326
327
|
x:
|
|
@@ -336,11 +337,30 @@ export function pointAtT(pts, t = 0.5, getTangent = false, getCpts = false, retu
|
|
|
336
337
|
};
|
|
337
338
|
|
|
338
339
|
}
|
|
340
|
+
*/
|
|
341
|
+
|
|
342
|
+
if (isCubic) {
|
|
343
|
+
pt = {
|
|
344
|
+
x:
|
|
345
|
+
t1 * t1 * t1 * p0.x +
|
|
346
|
+
3 * t1 * t1 * t * cp1.x +
|
|
347
|
+
3 * t1 * t * t * cp2.x +
|
|
348
|
+
t * t * t * p.x,
|
|
349
|
+
y:
|
|
350
|
+
t1 * t1 * t1 * p0.y +
|
|
351
|
+
3 * t1 * t1 * t * cp1.y +
|
|
352
|
+
3 * t1 * t * t * cp2.y +
|
|
353
|
+
t * t * t * p.y,
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
339
359
|
// quadratic beziers
|
|
340
360
|
else {
|
|
341
361
|
pt = {
|
|
342
|
-
x: t1 * t1 * p0.x + 2 * t1 * t * cp1.x + t
|
|
343
|
-
y: t1 * t1 * p0.y + 2 * t1 * t * cp1.y + t
|
|
362
|
+
x: t1 * t1 * p0.x + 2 * t1 * t * cp1.x + t * t * p.x,
|
|
363
|
+
y: t1 * t1 * p0.y + 2 * t1 * t * cp1.y + t * t * p.y,
|
|
344
364
|
};
|
|
345
365
|
}
|
|
346
366
|
|
|
@@ -963,6 +983,124 @@ export function getBezierExtremeT(pts, { addExtremes = true, addSemiExtremes = f
|
|
|
963
983
|
* https://stackoverflow.com/questions/87734/#75031511
|
|
964
984
|
* See also: https://github.com/foo123/Geometrize
|
|
965
985
|
*/
|
|
986
|
+
|
|
987
|
+
export function getArcExtemesParam({
|
|
988
|
+
cx=0, cy=0, rx=0, ry=0,
|
|
989
|
+
p=null,
|
|
990
|
+
p0=null,
|
|
991
|
+
endAngle=0,
|
|
992
|
+
deltaAngle=0,
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
}={}) {
|
|
996
|
+
// compute point on ellipse from angle around ellipse (theta)
|
|
997
|
+
const arc = (theta, cx, cy, rx, ry, alpha) => {
|
|
998
|
+
// theta is angle in radians around arc
|
|
999
|
+
// alpha is angle of rotation of ellipse in radians
|
|
1000
|
+
var cos = Math.cos(alpha),
|
|
1001
|
+
sin = Math.sin(alpha),
|
|
1002
|
+
x = rx * Math.cos(theta),
|
|
1003
|
+
y = ry * Math.sin(theta);
|
|
1004
|
+
|
|
1005
|
+
return {
|
|
1006
|
+
x: cx + cos * x - sin * y,
|
|
1007
|
+
y: cy + sin * x + cos * y
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
//parametrize arcto data
|
|
1012
|
+
//let arcData = svgArcToCenterParam(p0.x, p0.y, values[0], values[1], values[2], values[3], values[4], values[5], values[6]);
|
|
1013
|
+
//let { rx, ry, cx, cy, endAngle, deltaAngle } = arcData;
|
|
1014
|
+
|
|
1015
|
+
// arc rotation
|
|
1016
|
+
let deg = values[2];
|
|
1017
|
+
|
|
1018
|
+
// final on path point
|
|
1019
|
+
//let p = { x: values[5], y: values[6] }
|
|
1020
|
+
|
|
1021
|
+
// collect extreme points – add end point
|
|
1022
|
+
let extremes = [p]
|
|
1023
|
+
|
|
1024
|
+
// rotation to radians
|
|
1025
|
+
let alpha = deg * Math.PI / 180;
|
|
1026
|
+
let tan = Math.tan(alpha),
|
|
1027
|
+
p1, p2, p3, p4, theta;
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* find min/max from zeroes of directional derivative along x and y
|
|
1031
|
+
* along x axis
|
|
1032
|
+
*/
|
|
1033
|
+
theta = Math.atan2(-ry * tan, rx);
|
|
1034
|
+
|
|
1035
|
+
let angle1 = theta;
|
|
1036
|
+
let angle2 = theta + Math.PI;
|
|
1037
|
+
let angle3 = Math.atan2(ry, rx * tan);
|
|
1038
|
+
let angle4 = angle3 + Math.PI;
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
// inner bounding box
|
|
1042
|
+
let xArr = [p0.x, p.x]
|
|
1043
|
+
let yArr = [p0.y, p.y]
|
|
1044
|
+
let xMin = Math.min(...xArr)
|
|
1045
|
+
let xMax = Math.max(...xArr)
|
|
1046
|
+
let yMin = Math.min(...yArr)
|
|
1047
|
+
let yMax = Math.max(...yArr)
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
// on path point close after start
|
|
1051
|
+
let angleAfterStart = endAngle - deltaAngle * 0.001
|
|
1052
|
+
let pP2 = arc(angleAfterStart, cx, cy, rx, ry, alpha);
|
|
1053
|
+
|
|
1054
|
+
// on path point close before end
|
|
1055
|
+
let angleBeforeEnd = endAngle - deltaAngle * 0.999
|
|
1056
|
+
let pP3 = arc(angleBeforeEnd, cx, cy, rx, ry, alpha);
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* expected extremes
|
|
1061
|
+
* if leaving inner bounding box
|
|
1062
|
+
* (between segment start and end point)
|
|
1063
|
+
* otherwise exclude elliptic extreme points
|
|
1064
|
+
*/
|
|
1065
|
+
|
|
1066
|
+
// right
|
|
1067
|
+
if (pP2.x > xMax || pP3.x > xMax) {
|
|
1068
|
+
// get point for this theta
|
|
1069
|
+
p1 = arc(angle1, cx, cy, rx, ry, alpha);
|
|
1070
|
+
extremes.push(p1)
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
// left
|
|
1074
|
+
if (pP2.x < xMin || pP3.x < xMin) {
|
|
1075
|
+
// get anti-symmetric point
|
|
1076
|
+
p2 = arc(angle2, cx, cy, rx, ry, alpha);
|
|
1077
|
+
extremes.push(p2)
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// top
|
|
1081
|
+
if (pP2.y < yMin || pP3.y < yMin) {
|
|
1082
|
+
// get anti-symmetric point
|
|
1083
|
+
p4 = arc(angle4, cx, cy, rx, ry, alpha);
|
|
1084
|
+
extremes.push(p4)
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// bottom
|
|
1088
|
+
if (pP2.y > yMax || pP3.y > yMax) {
|
|
1089
|
+
// get point for this theta
|
|
1090
|
+
p3 = arc(angle3, cx, cy, rx, ry, alpha);
|
|
1091
|
+
extremes.push(p3)
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
return extremes;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
966
1104
|
export function getArcExtemes(p0, values) {
|
|
967
1105
|
// compute point on ellipse from angle around ellipse (theta)
|
|
968
1106
|
const arc = (theta, cx, cy, rx, ry, alpha) => {
|