svg-path-simplify 0.2.4 → 0.2.7
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 +30 -0
- package/dist/svg-path-simplify.esm.js +465 -390
- package/dist/svg-path-simplify.esm.min.js +6 -6
- package/dist/svg-path-simplify.js +465 -390
- package/dist/svg-path-simplify.min.js +6 -6
- package/dist/svg-path-simplify.min.js.gz +0 -0
- package/dist/svg-path-simplify.poly.cjs +10 -1
- package/dist/svg-path-simplify.worker.js +62 -0
- package/dist/svg-path-simplify.worker.polyfills.js +32 -0
- package/index.html +90 -17
- package/package.json +3 -2
- package/src/index-poly.js +9 -1
- package/src/index-worker.js +17 -0
- package/src/index.js +4 -1
- package/src/pathData_simplify_revertToquadratics.js +2 -2
- package/src/pathSimplify-main.js +53 -71
- package/src/svgii/geometry.js +48 -4
- package/src/svgii/pathData_analyze.js +8 -6
- package/src/svgii/pathData_convert.js +1 -1
- package/src/svgii/pathData_fix_directions.js +83 -0
- package/src/svgii/pathData_line_to_cubic.js +21 -0
- package/src/svgii/pathData_parse_els.js +7 -2
- package/src/svgii/pathData_remove_zerolength.js +0 -1
- package/src/svgii/pathData_reverse.js +0 -1
- package/src/svgii/pathData_toPolygon.js +61 -12
- package/src/svgii/rounding.js +2 -0
- package/src/svgii/svg-styles-to-attributes-const.js +2 -0
- package/src/svgii/svg_cleanup.js +92 -15
- package/tests/testSVG.js +1 -0
- package/tests/testSVG2.js +55 -0
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
* http://jsfiddle.net/justin_c_rounds/Gd2S2/light/
|
|
163
163
|
*/
|
|
164
164
|
|
|
165
|
-
function checkLineIntersection(p1 = null, p2 = null, p3 = null, p4 = null, exact = true, debug = false) {
|
|
165
|
+
function checkLineIntersection(p1 = null, p2 = null, p3 = null, p4 = null, exact = true, respectDirection = false, debug = false) {
|
|
166
166
|
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
|
|
167
167
|
let denominator, a, b, numerator1, numerator2;
|
|
168
168
|
let intersectionPoint = {};
|
|
@@ -174,7 +174,9 @@
|
|
|
174
174
|
|
|
175
175
|
try {
|
|
176
176
|
denominator = ((p4.y - p3.y) * (p2.x - p1.x)) - ((p4.x - p3.x) * (p2.y - p1.y));
|
|
177
|
-
|
|
177
|
+
|
|
178
|
+
// parallel or colinear
|
|
179
|
+
if (denominator === 0) {
|
|
178
180
|
return false;
|
|
179
181
|
}
|
|
180
182
|
} catch {
|
|
@@ -203,8 +205,13 @@
|
|
|
203
205
|
|
|
204
206
|
}
|
|
205
207
|
|
|
206
|
-
|
|
208
|
+
// direction
|
|
209
|
+
if (!exact && respectDirection && ((a > 0 && b < 0) || (a < 0 && b > 0))) {
|
|
210
|
+
intersection = false;
|
|
211
|
+
return false
|
|
212
|
+
}
|
|
207
213
|
|
|
214
|
+
if (exact && !intersection) {
|
|
208
215
|
return false;
|
|
209
216
|
}
|
|
210
217
|
|
|
@@ -213,6 +220,44 @@
|
|
|
213
220
|
return intersectionPoint;
|
|
214
221
|
}
|
|
215
222
|
|
|
223
|
+
/** Get relationship between a point and a polygon using ray-casting algorithm
|
|
224
|
+
* based on timepp's answer
|
|
225
|
+
* https://stackoverflow.com/questions/217578/how-can-i-determine-whether-a-2d-point-is-within-a-polygon#63436180
|
|
226
|
+
*/
|
|
227
|
+
function isPointInPolygon(pt, polygon, bb, skipBB = false) {
|
|
228
|
+
const between = (p, a, b) => (p >= a && p <= b) || (p <= a && p >= b);
|
|
229
|
+
let inside = false;
|
|
230
|
+
|
|
231
|
+
// not in bbox - quit || no bbox defined
|
|
232
|
+
if (!skipBB || !bb.bottom) {
|
|
233
|
+
if (bb.left > pt.x || bb.top > pt.y || bb.bottom < pt.y || bb.right < pt.x) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let l=polygon.length;
|
|
239
|
+
for (let i = l - 1, j = 0; j < l; i = j, j++) {
|
|
240
|
+
const A = polygon[i];
|
|
241
|
+
const B = polygon[j];
|
|
242
|
+
// corner cases
|
|
243
|
+
if ((pt.x == A.x && pt.y == A.y) || (pt.x == B.x && pt.y == B.y))
|
|
244
|
+
return true;
|
|
245
|
+
if (A.y == B.y && pt.y == A.y && between(pt.x, A.x, B.x)) return true;
|
|
246
|
+
if (between(pt.y, A.y, B.y)) {
|
|
247
|
+
/**
|
|
248
|
+
* if pt inside the vertical range filter out "ray pass vertex" problem
|
|
249
|
+
* by treating the line a little lower
|
|
250
|
+
*/
|
|
251
|
+
if ((pt.y == A.y && B.y >= A.y) || (pt.y == B.y && A.y >= B.y)) continue;
|
|
252
|
+
// calc cross product `ptA X ptB`, pt lays on left side of AB if c > 0
|
|
253
|
+
const c = (A.x - pt.x) * (B.y - pt.y) - (B.x - pt.x) * (A.y - pt.y);
|
|
254
|
+
if (c == 0) return true;
|
|
255
|
+
if (A.y < B.y == c > 0) inside = !inside;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return inside ? true : false;
|
|
259
|
+
}
|
|
260
|
+
|
|
216
261
|
/**
|
|
217
262
|
* Linear interpolation (LERP) helper
|
|
218
263
|
*/
|
|
@@ -2372,6 +2417,7 @@
|
|
|
2372
2417
|
}
|
|
2373
2418
|
|
|
2374
2419
|
let dim_min = dims.sort();
|
|
2420
|
+
|
|
2375
2421
|
let sliceIdx = Math.ceil(dim_min.length / 8);
|
|
2376
2422
|
dim_min = dim_min.slice(0, sliceIdx);
|
|
2377
2423
|
let minVal = dim_min.reduce((a, b) => a + b, 0) / sliceIdx;
|
|
@@ -2475,6 +2521,7 @@
|
|
|
2475
2521
|
(type === 'C' ? [p0, cp1, cp2, p] : [p0, cp1, p]) :
|
|
2476
2522
|
([p0, p]);
|
|
2477
2523
|
let thresholdLength = dimA * 0.1;
|
|
2524
|
+
let threshold = thresholdLength*0.01;
|
|
2478
2525
|
|
|
2479
2526
|
// bezier types
|
|
2480
2527
|
let isBezier = type === 'Q' || type === 'C';
|
|
@@ -2491,10 +2538,12 @@
|
|
|
2491
2538
|
let dx = type === 'C' ? Math.abs(com.cp2.x - com.p.x) : Math.abs(com.cp1.x - com.p.x);
|
|
2492
2539
|
let dy = type === 'C' ? Math.abs(com.cp2.y - com.p.y) : Math.abs(com.cp1.y - com.p.y);
|
|
2493
2540
|
|
|
2494
|
-
let horizontal = dy === 0 && dx > 0;
|
|
2495
|
-
let vertical = dx === 0 && dy > 0;
|
|
2541
|
+
let horizontal = (dy === 0 || dy<threshold ) && dx > 0;
|
|
2542
|
+
let vertical = (dx === 0 || dx<threshold ) && dy > 0;
|
|
2496
2543
|
|
|
2497
|
-
if (horizontal || vertical)
|
|
2544
|
+
if (horizontal || vertical) {
|
|
2545
|
+
hasExtremes = true;
|
|
2546
|
+
}
|
|
2498
2547
|
|
|
2499
2548
|
// is extreme relative to bounding box
|
|
2500
2549
|
if ((p.x === left || p.y === top || p.x === right || p.y === bottom)) {
|
|
@@ -2506,7 +2555,7 @@
|
|
|
2506
2555
|
let couldHaveExtremes = bezierhasExtreme(null, commandPts);
|
|
2507
2556
|
if (couldHaveExtremes) {
|
|
2508
2557
|
let tArr = getTatAngles(commandPts);
|
|
2509
|
-
if (tArr.length && (tArr[0] > 0.
|
|
2558
|
+
if (tArr.length && (tArr[0] > 0.2)) {
|
|
2510
2559
|
hasExtremes = true;
|
|
2511
2560
|
}
|
|
2512
2561
|
}
|
|
@@ -3110,7 +3159,7 @@
|
|
|
3110
3159
|
let dx1 = (p0.x - cpPrev.x);
|
|
3111
3160
|
let dy1 = (p0.y - cpPrev.y);
|
|
3112
3161
|
|
|
3113
|
-
maxDist = getDistManhattan(cpPrev, cpFirst) * 0.
|
|
3162
|
+
maxDist = getDistManhattan(cpPrev, cpFirst) * 0.025;
|
|
3114
3163
|
|
|
3115
3164
|
// reflected cp
|
|
3116
3165
|
let cpR = { x: cpPrev.x + dx1 * 2, y: cpPrev.y + dy1 * 2 };
|
|
@@ -3898,12 +3947,14 @@
|
|
|
3898
3947
|
let attributes = [...el.attributes].map(att => att.name);
|
|
3899
3948
|
|
|
3900
3949
|
let pathN = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
3950
|
+
|
|
3901
3951
|
pathN.setAttribute('d', d);
|
|
3902
3952
|
|
|
3903
|
-
let exclude = ['x', 'y', 'cx', 'cy', 'dx', 'dy', 'r', 'rx', 'ry', 'width', 'height', 'points'];
|
|
3953
|
+
let exclude = ['x', 'y', 'x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'dx', 'dy', 'r', 'rx', 'ry', 'width', 'height', 'points'];
|
|
3904
3954
|
|
|
3905
3955
|
attributes.forEach(att => {
|
|
3906
3956
|
if (!exclude.includes(att)) {
|
|
3957
|
+
|
|
3907
3958
|
let val = el.getAttribute(att);
|
|
3908
3959
|
pathN.setAttribute(att, val);
|
|
3909
3960
|
}
|
|
@@ -3917,7 +3968,7 @@
|
|
|
3917
3968
|
function getPathDataFromEl(el, stringify = false) {
|
|
3918
3969
|
|
|
3919
3970
|
let pathData = [];
|
|
3920
|
-
let type = el.nodeName;
|
|
3971
|
+
let type = el.nodeName.toLowerCase();
|
|
3921
3972
|
let atts, attNames, d, x, y, width, height, r, rx, ry, cx, cy, x1, x2, y1, y2;
|
|
3922
3973
|
|
|
3923
3974
|
// convert relative or absolute units
|
|
@@ -4540,6 +4591,125 @@
|
|
|
4540
4591
|
return pathData;
|
|
4541
4592
|
}
|
|
4542
4593
|
|
|
4594
|
+
/**
|
|
4595
|
+
* reverse pathdata
|
|
4596
|
+
* make sure all command coordinates are absolute and
|
|
4597
|
+
* shorthands are converted to long notation
|
|
4598
|
+
*/
|
|
4599
|
+
function reversePathData(pathData, {
|
|
4600
|
+
arcToCubic = false,
|
|
4601
|
+
quadraticToCubic = false,
|
|
4602
|
+
toClockwise = false,
|
|
4603
|
+
returnD = false
|
|
4604
|
+
} = {}) {
|
|
4605
|
+
|
|
4606
|
+
/**
|
|
4607
|
+
* Add closing lineto:
|
|
4608
|
+
* needed for path reversing or adding points
|
|
4609
|
+
*/
|
|
4610
|
+
const addClosePathLineto = (pathData) => {
|
|
4611
|
+
let closed = pathData[pathData.length - 1].type.toLowerCase() === "z";
|
|
4612
|
+
let M = pathData[0];
|
|
4613
|
+
let [x0, y0] = [M.values[0], M.values[1]];
|
|
4614
|
+
let lastCom = closed ? pathData[pathData.length - 2] : pathData[pathData.length - 1];
|
|
4615
|
+
let [xE, yE] = [lastCom.values[lastCom.values.length - 2], lastCom.values[lastCom.values.length - 1]];
|
|
4616
|
+
|
|
4617
|
+
if (closed && (x0 != xE || y0 != yE)) {
|
|
4618
|
+
|
|
4619
|
+
pathData.pop();
|
|
4620
|
+
pathData.push(
|
|
4621
|
+
{
|
|
4622
|
+
type: "L",
|
|
4623
|
+
values: [x0, y0]
|
|
4624
|
+
},
|
|
4625
|
+
{
|
|
4626
|
+
type: "Z",
|
|
4627
|
+
values: []
|
|
4628
|
+
}
|
|
4629
|
+
);
|
|
4630
|
+
}
|
|
4631
|
+
return pathData;
|
|
4632
|
+
};
|
|
4633
|
+
|
|
4634
|
+
// helper to rearrange control points for all command types
|
|
4635
|
+
const reverseControlPoints = (type, values) => {
|
|
4636
|
+
let controlPoints = [];
|
|
4637
|
+
let endPoints = [];
|
|
4638
|
+
if (type !== "A") {
|
|
4639
|
+
for (let p = 0; p < values.length; p += 2) {
|
|
4640
|
+
controlPoints.push([values[p], values[p + 1]]);
|
|
4641
|
+
}
|
|
4642
|
+
endPoints = controlPoints.pop();
|
|
4643
|
+
controlPoints.reverse();
|
|
4644
|
+
}
|
|
4645
|
+
// is arc
|
|
4646
|
+
else {
|
|
4647
|
+
|
|
4648
|
+
let sweep = values[4] == 0 ? 1 : 0;
|
|
4649
|
+
controlPoints = [values[0], values[1], values[2], values[3], sweep];
|
|
4650
|
+
endPoints = [values[5], values[6]];
|
|
4651
|
+
}
|
|
4652
|
+
return { controlPoints, endPoints };
|
|
4653
|
+
};
|
|
4654
|
+
|
|
4655
|
+
// start compiling new path data
|
|
4656
|
+
let pathDataNew = [];
|
|
4657
|
+
|
|
4658
|
+
let closed =
|
|
4659
|
+
pathData[pathData.length - 1].type.toLowerCase() === "z" ? true : false;
|
|
4660
|
+
if (closed) {
|
|
4661
|
+
// add lineto closing space between Z and M
|
|
4662
|
+
pathData = addClosePathLineto(pathData);
|
|
4663
|
+
// remove Z closepath
|
|
4664
|
+
pathData.pop();
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
// define last point as new M if path isn't closed
|
|
4668
|
+
let valuesLast = pathData[pathData.length - 1].values;
|
|
4669
|
+
let valuesLastL = valuesLast.length;
|
|
4670
|
+
let M = closed
|
|
4671
|
+
? pathData[0]
|
|
4672
|
+
: {
|
|
4673
|
+
type: "M",
|
|
4674
|
+
values: [valuesLast[valuesLastL - 2], valuesLast[valuesLastL - 1]]
|
|
4675
|
+
};
|
|
4676
|
+
// starting M stays the same – unless the path is not closed
|
|
4677
|
+
pathDataNew.push(M);
|
|
4678
|
+
|
|
4679
|
+
// reverse path data command order for processing
|
|
4680
|
+
pathData.reverse();
|
|
4681
|
+
for (let i = 1; i < pathData.length; i++) {
|
|
4682
|
+
let com = pathData[i];
|
|
4683
|
+
let type = com.type;
|
|
4684
|
+
let values = com.values;
|
|
4685
|
+
let comPrev = pathData[i - 1];
|
|
4686
|
+
let typePrev = comPrev.type;
|
|
4687
|
+
let valuesPrev = comPrev.values;
|
|
4688
|
+
|
|
4689
|
+
// get reversed control points and new end coordinates
|
|
4690
|
+
let controlPointsPrev = reverseControlPoints(typePrev, valuesPrev).controlPoints;
|
|
4691
|
+
let endPoints = reverseControlPoints(type, values).endPoints;
|
|
4692
|
+
|
|
4693
|
+
// create new path data
|
|
4694
|
+
let newValues = [];
|
|
4695
|
+
newValues = [controlPointsPrev, endPoints].flat();
|
|
4696
|
+
pathDataNew.push({
|
|
4697
|
+
type: typePrev,
|
|
4698
|
+
values: newValues.flat()
|
|
4699
|
+
});
|
|
4700
|
+
}
|
|
4701
|
+
|
|
4702
|
+
// add previously removed Z close path
|
|
4703
|
+
if (closed) {
|
|
4704
|
+
pathDataNew.push({
|
|
4705
|
+
type: "z",
|
|
4706
|
+
values: []
|
|
4707
|
+
});
|
|
4708
|
+
}
|
|
4709
|
+
|
|
4710
|
+
return pathDataNew;
|
|
4711
|
+
}
|
|
4712
|
+
|
|
4543
4713
|
function simplifyRDP(pts, {
|
|
4544
4714
|
quality = 0.9,
|
|
4545
4715
|
width = 0,
|
|
@@ -6290,6 +6460,8 @@
|
|
|
6290
6460
|
...textEls,
|
|
6291
6461
|
],
|
|
6292
6462
|
|
|
6463
|
+
"fill-rule": ["svg", "g", "path", "polygon", "text", "textPath"],
|
|
6464
|
+
|
|
6293
6465
|
opacity: [
|
|
6294
6466
|
"svg",
|
|
6295
6467
|
"g",
|
|
@@ -6654,26 +6826,30 @@
|
|
|
6654
6826
|
removeUnused = true,
|
|
6655
6827
|
stylesToAttributes = true,
|
|
6656
6828
|
removePrologue = true,
|
|
6829
|
+
removeIds = false,
|
|
6830
|
+
removeClassNames = false,
|
|
6831
|
+
removeDimensions = false,
|
|
6657
6832
|
fixHref = true,
|
|
6658
6833
|
mergePaths = false,
|
|
6659
6834
|
cleanupSVGAtts = true,
|
|
6660
6835
|
removeNameSpaced = true,
|
|
6661
6836
|
attributesToGroup = true,
|
|
6837
|
+
shapesToPaths = false,
|
|
6662
6838
|
decimals = -1,
|
|
6663
6839
|
excludedEls = [],
|
|
6664
6840
|
} = {}) {
|
|
6665
6841
|
|
|
6666
|
-
|
|
6842
|
+
attributesToGroup = cleanupSVGAtts ? true : false;
|
|
6667
6843
|
|
|
6668
6844
|
// replace namespaced refs
|
|
6669
6845
|
if (fixHref) svgMarkup = svgMarkup.replaceAll("xlink:href=", "href=");
|
|
6670
6846
|
|
|
6671
6847
|
let svg = new DOMParser()
|
|
6672
|
-
|
|
6673
6848
|
.parseFromString(svgMarkup, "text/html")
|
|
6674
6849
|
.querySelector("svg");
|
|
6675
6850
|
|
|
6676
6851
|
if (cleanupSVGAtts) {
|
|
6852
|
+
|
|
6677
6853
|
let allowed = ['viewBox', 'xmlns', 'width', 'height', 'id', 'class', 'fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin'];
|
|
6678
6854
|
removeExcludedAttribues(svg, allowed);
|
|
6679
6855
|
|
|
@@ -6685,11 +6861,22 @@
|
|
|
6685
6861
|
let els = svg.querySelectorAll('*');
|
|
6686
6862
|
let elProps = [];
|
|
6687
6863
|
|
|
6864
|
+
let geometryElements = ['polygon', 'polyline', 'line', 'rect', 'circle', 'ellipse'];
|
|
6865
|
+
|
|
6688
6866
|
for (let i = 0; i < els.length; i++) {
|
|
6689
6867
|
let el = els[i];
|
|
6690
6868
|
|
|
6691
6869
|
let name = el.nodeName.toLowerCase();
|
|
6692
6870
|
|
|
6871
|
+
// convert shapes
|
|
6872
|
+
if (shapesToPaths && name !== 'path' && geometryElements.includes(name)) {
|
|
6873
|
+
let path = shapeElToPath(el);
|
|
6874
|
+
el.replaceWith(path);
|
|
6875
|
+
name = 'path';
|
|
6876
|
+
el = path;
|
|
6877
|
+
|
|
6878
|
+
}
|
|
6879
|
+
|
|
6693
6880
|
// remove hidden elements
|
|
6694
6881
|
let style = el.getAttribute('style') || '';
|
|
6695
6882
|
let isHiddenByStyle = style ? style.trim().includes('display:none') : false;
|
|
@@ -6709,11 +6896,25 @@
|
|
|
6709
6896
|
}
|
|
6710
6897
|
|
|
6711
6898
|
// group styles
|
|
6712
|
-
|
|
6713
6899
|
if (attributesToGroup || mergePaths) {
|
|
6714
6900
|
moveAttributesToGroup(elProps, mergePaths);
|
|
6715
6901
|
}
|
|
6716
6902
|
|
|
6903
|
+
if (removeDimensions) {
|
|
6904
|
+
svg.removeAttribute('width');
|
|
6905
|
+
svg.removeAttribute('height');
|
|
6906
|
+
}
|
|
6907
|
+
|
|
6908
|
+
if (removeClassNames || removeIds) {
|
|
6909
|
+
let att = removeClassNames ? 'class' : 'id';
|
|
6910
|
+
let selector = `[${att}]`;
|
|
6911
|
+
let els = svg.querySelectorAll(selector);
|
|
6912
|
+
svg.removeAttribute(att);
|
|
6913
|
+
els.forEach(el => {
|
|
6914
|
+
el.removeAttribute(att);
|
|
6915
|
+
});
|
|
6916
|
+
}
|
|
6917
|
+
|
|
6717
6918
|
if (returnDom) return svg
|
|
6718
6919
|
let markup = stringifySVG(svg);
|
|
6719
6920
|
|
|
@@ -6725,11 +6926,39 @@
|
|
|
6725
6926
|
let combine = [[elProps[0]]];
|
|
6726
6927
|
let idx = 0;
|
|
6727
6928
|
let lastProps = '';
|
|
6728
|
-
|
|
6929
|
+
let l = elProps.length;
|
|
6930
|
+
let itemsWithProps = elProps.filter(item => item.propstr);
|
|
6931
|
+
let path0;
|
|
6932
|
+
|
|
6933
|
+
// merge paths without properties
|
|
6934
|
+
if (!itemsWithProps.length && mergePaths) {
|
|
6935
|
+
let item0 = elProps[0];
|
|
6936
|
+
path0 = item0.el;
|
|
6937
|
+
let dCombined = item0.propsFiltered.d;
|
|
6938
|
+
|
|
6939
|
+
for (let i = 1; i < l; i++) {
|
|
6940
|
+
let item = elProps[i];
|
|
6941
|
+
let path = item.el;
|
|
6942
|
+
|
|
6943
|
+
let d = item.propsFiltered.d;
|
|
6944
|
+
let isAbs = d.startsWith('M');
|
|
6945
|
+
let dAbs = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ');
|
|
6946
|
+
|
|
6947
|
+
dCombined += dAbs;
|
|
6948
|
+
|
|
6949
|
+
// delete path el
|
|
6950
|
+
path.remove();
|
|
6951
|
+
}
|
|
6952
|
+
|
|
6953
|
+
path0.setAttribute('d', dCombined);
|
|
6954
|
+
return
|
|
6955
|
+
}
|
|
6956
|
+
|
|
6957
|
+
// add to combine chunks
|
|
6958
|
+
for (let i = 0; i < l; i++) {
|
|
6729
6959
|
let item = elProps[i];
|
|
6730
6960
|
let props = item.propsFiltered;
|
|
6731
6961
|
let propstr = [];
|
|
6732
|
-
|
|
6733
6962
|
for (let prop in props) {
|
|
6734
6963
|
if (prop !== 'd' && prop !== 'id') {
|
|
6735
6964
|
propstr.push(`${prop}:${props[prop]}`);
|
|
@@ -6738,16 +6967,15 @@
|
|
|
6738
6967
|
propstr = propstr.join('_');
|
|
6739
6968
|
item.propstr = propstr;
|
|
6740
6969
|
|
|
6741
|
-
if (propstr === lastProps) {
|
|
6970
|
+
if (l > 1 && propstr === lastProps) {
|
|
6742
6971
|
combine[idx].push(item);
|
|
6743
6972
|
} else {
|
|
6744
|
-
if (combine[idx].length) {
|
|
6973
|
+
if (l > 1 && combine[idx].length) {
|
|
6745
6974
|
combine.push([]);
|
|
6746
6975
|
idx++;
|
|
6747
6976
|
}
|
|
6748
6977
|
}
|
|
6749
6978
|
lastProps = propstr;
|
|
6750
|
-
|
|
6751
6979
|
}
|
|
6752
6980
|
|
|
6753
6981
|
// add att groups
|
|
@@ -6785,10 +7013,15 @@
|
|
|
6785
7013
|
}
|
|
6786
7014
|
|
|
6787
7015
|
if (mergePaths) {
|
|
6788
|
-
|
|
7016
|
+
group = group.filter(Boolean);
|
|
7017
|
+
let l = group.length;
|
|
7018
|
+
// nothing to merge
|
|
7019
|
+
if (l === 1) return group[0].el;
|
|
7020
|
+
|
|
7021
|
+
path0 = group[0].el;
|
|
6789
7022
|
let dCombined = group[0].propsFiltered.d;
|
|
6790
7023
|
|
|
6791
|
-
for (let i = 1; i <
|
|
7024
|
+
for (let i = 1; i < l; i++) {
|
|
6792
7025
|
let item = group[i];
|
|
6793
7026
|
let path = item.el;
|
|
6794
7027
|
let d = item.propsFiltered.d;
|
|
@@ -6813,20 +7046,6 @@
|
|
|
6813
7046
|
|
|
6814
7047
|
}
|
|
6815
7048
|
|
|
6816
|
-
function cleanSvgPrologue(svgString) {
|
|
6817
|
-
return (
|
|
6818
|
-
svgString
|
|
6819
|
-
// Remove XML prologues like <?xml ... ?>
|
|
6820
|
-
.replace(/<\?xml[\s\S]*?\?>/gi, "")
|
|
6821
|
-
// Remove DOCTYPE declarations
|
|
6822
|
-
.replace(/<!DOCTYPE[\s\S]*?>/gi, "")
|
|
6823
|
-
// Remove comments <!-- ... -->
|
|
6824
|
-
.replace(/<!--[\s\S]*?-->/g, "")
|
|
6825
|
-
// Trim extra whitespace
|
|
6826
|
-
.trim()
|
|
6827
|
-
);
|
|
6828
|
-
}
|
|
6829
|
-
|
|
6830
7049
|
function removeExcludedAttribues(el, allowed = ['viewBox', 'xmlns', 'width', 'height', 'id', 'class']) {
|
|
6831
7050
|
let atts = [...el.attributes].map((att) => att.name);
|
|
6832
7051
|
atts.forEach((att) => {
|
|
@@ -6836,13 +7055,22 @@
|
|
|
6836
7055
|
});
|
|
6837
7056
|
}
|
|
6838
7057
|
|
|
6839
|
-
function stringifySVG(svg) {
|
|
7058
|
+
function stringifySVG(svg, omitNamespace = false) {
|
|
6840
7059
|
let markup = new XMLSerializer().serializeToString(svg);
|
|
7060
|
+
|
|
7061
|
+
if (omitNamespace) {
|
|
7062
|
+
markup = markup.replaceAll('xmlns="http://www.w3.org/2000/svg"', '');
|
|
7063
|
+
}
|
|
7064
|
+
|
|
6841
7065
|
markup = markup
|
|
6842
7066
|
.replace(/\t/g, "")
|
|
6843
7067
|
.replace(/[\n\r|]/g, "\n")
|
|
6844
7068
|
.replace(/\n\s*\n/g, '\n')
|
|
6845
|
-
.replace(/ +/g, ' ')
|
|
7069
|
+
.replace(/ +/g, ' ')
|
|
7070
|
+
|
|
7071
|
+
.replace(/> </g, '><')
|
|
7072
|
+
.trim();
|
|
7073
|
+
|
|
6846
7074
|
|
|
6847
7075
|
return markup
|
|
6848
7076
|
}
|
|
@@ -7409,296 +7637,14 @@
|
|
|
7409
7637
|
return viewBox
|
|
7410
7638
|
}
|
|
7411
7639
|
|
|
7412
|
-
function
|
|
7413
|
-
tolerance = 1
|
|
7414
|
-
|
|
7415
|
-
} = {}) {
|
|
7416
|
-
let chunks = [];
|
|
7417
|
-
let chunk = [];
|
|
7418
|
-
|
|
7419
|
-
let l = pathData.length;
|
|
7420
|
-
|
|
7421
|
-
for (let i = 1; i < l; i++) {
|
|
7422
|
-
let com = pathData[i];
|
|
7423
|
-
let { type, values, p0, cp1 = null, cp2 = null, p, extreme = null, semiExtreme = null, corner = null, directionChange } = com;
|
|
7424
|
-
|
|
7425
|
-
let comN = pathData[i + 1] || null;
|
|
7426
|
-
|
|
7427
|
-
/*
|
|
7428
|
-
if (extreme || corner || semiExtreme || directionChange) {
|
|
7429
|
-
|
|
7430
|
-
if (extreme) renderPoint(markers, com.p, 'cyan', '1%', '0.5')
|
|
7431
|
-
|
|
7432
|
-
if (semiExtreme) renderPoint(markers, com.p, 'orange', '1%', '0.5')
|
|
7433
|
-
if (corner) renderPoint(markers, com.p, 'magenta', '1.75%', '0.5')
|
|
7434
|
-
}
|
|
7435
|
-
*/
|
|
7436
|
-
|
|
7437
|
-
if (extreme || corner || (comN && comN.type !== type)) {
|
|
7438
|
-
chunk.push(com);
|
|
7439
|
-
chunks.push(chunk);
|
|
7440
|
-
chunk = [];
|
|
7441
|
-
continue
|
|
7442
|
-
}
|
|
7443
|
-
|
|
7444
|
-
chunk.push(com);
|
|
7445
|
-
|
|
7446
|
-
}
|
|
7447
|
-
|
|
7448
|
-
console.log('!!!chunks', chunks);
|
|
7449
|
-
|
|
7450
|
-
renderChunks(chunks);
|
|
7451
|
-
|
|
7452
|
-
// cleanup chunks
|
|
7453
|
-
|
|
7454
|
-
let chunksLen = chunks.length;
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
for (let c = 0; c < chunksLen; c++) {
|
|
7459
|
-
let chunk = chunks[c];
|
|
7460
|
-
let chunkN = chunks[c + 1] || null;
|
|
7461
|
-
|
|
7462
|
-
let chunkLen = chunk.length;
|
|
7463
|
-
|
|
7464
|
-
if (chunkLen === 1 && chunkN && chunkN[0].type === 'C') ;
|
|
7465
|
-
|
|
7466
|
-
}
|
|
7467
|
-
|
|
7468
|
-
chunks = chunks.filter(Boolean);
|
|
7469
|
-
|
|
7470
|
-
// test render
|
|
7471
|
-
|
|
7472
|
-
let pathDataC = [pathData[0]];
|
|
7473
|
-
|
|
7474
|
-
/**
|
|
7475
|
-
* combine chunk based
|
|
7476
|
-
*/
|
|
7477
|
-
for (let c = 0; c < chunks.length; c++) {
|
|
7478
|
-
let chunk = chunks[c];
|
|
7479
|
-
let chunkLen = chunk.length;
|
|
7480
|
-
let comChunk0 = chunk[0];
|
|
7481
|
-
let comChunk1 = chunk[chunkLen - 1];
|
|
7482
|
-
let thresh = getDistManhattan(comChunk0.p0, comChunk1.p) * 0.05;
|
|
7483
|
-
|
|
7484
|
-
// commands in chunk
|
|
7485
|
-
for (let i = 0, l = chunkLen; i < l; i++) {
|
|
7486
|
-
let com = chunk[i];
|
|
7487
|
-
chunk[i + 1];
|
|
7488
|
-
chunk[l - 1];
|
|
7489
|
-
|
|
7490
|
-
let isBezier = comChunk0.type === 'C' && comChunk1.type === 'C';
|
|
7491
|
-
|
|
7492
|
-
let { type, values, p0, cp1 = null, cp2 = null, p = null, extreme, semiExtreme = null, corner = null } = com;
|
|
7493
|
-
|
|
7494
|
-
let pI1 = null, pI2 = null;
|
|
7495
|
-
let cp1_S = null, cp2_S = null;
|
|
7496
|
-
let cp2_M = null;
|
|
7497
|
-
let cp1_M = null;
|
|
7498
|
-
let pathDataS = [];
|
|
7499
|
-
let tSplit = 0.666;
|
|
7500
|
-
let comMid = null;
|
|
7501
|
-
|
|
7502
|
-
// 0. adjust Extreme cpts
|
|
7503
|
-
if (isBezier) {
|
|
7504
|
-
let dx1 = Math.abs(comChunk0.p0.x - comChunk0.cp1.x);
|
|
7505
|
-
let dy1 = Math.abs(comChunk0.p0.y - comChunk0.cp1.y);
|
|
7506
|
-
let dx2 = Math.abs(comChunk1.p.x - comChunk1.cp2.x);
|
|
7507
|
-
let dy2 = Math.abs(comChunk1.p.y - comChunk1.cp2.y);
|
|
7508
|
-
|
|
7509
|
-
let vertical1 = dx1 < thresh && dx1 < dy1;
|
|
7510
|
-
let horizontal1 = dy1 < thresh && dx1 > dy1;
|
|
7511
|
-
|
|
7512
|
-
let vertical2 = dx2 < thresh && dx2 < dy2;
|
|
7513
|
-
let horizontal2 = dy2 < thresh && dx2 > dy2;
|
|
7514
|
-
|
|
7515
|
-
if (horizontal1) comChunk0.cp1.y = comChunk0.p0.y;
|
|
7516
|
-
if (horizontal2) comChunk1.cp2.y = comChunk1.p.y;
|
|
7517
|
-
if (vertical1) comChunk0.cp1.x = comChunk0.p0.x;
|
|
7518
|
-
if (vertical2) comChunk1.cp2.x = comChunk1.p.x;
|
|
7519
|
-
}
|
|
7520
|
-
|
|
7521
|
-
// test render - original pathdata
|
|
7522
|
-
let pathDataChunk = [
|
|
7523
|
-
{ type: 'M', values: [com.p0.x, com.p0.y] },
|
|
7524
|
-
{ type, values },
|
|
7525
|
-
];
|
|
7526
|
-
|
|
7527
|
-
pathDataToD(pathDataChunk);
|
|
7528
|
-
// renderPath(markers, d, stroke, '1%', '0.5')
|
|
7529
|
-
// continue
|
|
7530
|
-
/*
|
|
7531
|
-
|
|
7532
|
-
*/
|
|
7533
|
-
|
|
7534
|
-
// 1. only one command in chunk - nothing to simplify
|
|
7535
|
-
if (chunkLen === 1 || type !== 'C') {
|
|
7536
|
-
pathDataC.push(com);
|
|
7537
|
-
}
|
|
7538
|
-
|
|
7539
|
-
// 2. could be simplified
|
|
7540
|
-
else {
|
|
7541
|
-
// 2.1 has semi extreme - extrapolate
|
|
7542
|
-
// 2.2 has sdirection change
|
|
7543
|
-
let semiExtremes = chunk.filter(ch => ch.semiExtreme);
|
|
7544
|
-
let comsDirectionChange = chunk.filter(ch => ch.directionChange);
|
|
7545
|
-
|
|
7546
|
-
if (semiExtremes.length || comsDirectionChange.length) {
|
|
7547
|
-
|
|
7548
|
-
// semiExtreme command
|
|
7549
|
-
comMid = semiExtremes.length ? semiExtremes[0] : comsDirectionChange[0];
|
|
7550
|
-
|
|
7551
|
-
// zero length cpt vectors
|
|
7552
|
-
if (comChunk0.p0.x === comChunk0.cp1.x && comChunk0.p0.y === comChunk0.cp1.y) {
|
|
7553
|
-
comChunk0.cp1 = pointAtT([comChunk0.p0, comChunk0.cp1, comChunk0.cp2, comChunk0.p], 0.5);
|
|
7554
|
-
}
|
|
7555
|
-
else if (comChunk1.p.x === comChunk1.cp2.x && comChunk1.p.y === comChunk1.cp2.y) {
|
|
7556
|
-
comChunk1.cp2 = pointAtT([comChunk1.p0, comChunk1.cp1, comChunk1.cp2, comChunk1.p], 0.5);
|
|
7557
|
-
}
|
|
7558
|
-
|
|
7559
|
-
pI1 = checkLineIntersection(comMid.p, comMid.cp2, comChunk0.p0, comChunk0.cp1, false);
|
|
7560
|
-
pI2 = checkLineIntersection(comMid.p, comMid.cp2, comChunk1.p, comChunk1.cp2, false);
|
|
7561
|
-
|
|
7562
|
-
// intersections try to extrapolate cpts
|
|
7563
|
-
if (pI1 && pI2) {
|
|
7564
|
-
|
|
7565
|
-
cp1_S = pointAtT([comChunk0.p0, pI1], tSplit);
|
|
7566
|
-
cp2_S = pointAtT([comChunk1.p, pI2], tSplit);
|
|
7567
|
-
|
|
7568
|
-
cp2_M = pointAtT([comMid.p, pI1], tSplit);
|
|
7569
|
-
cp1_M = pointAtT([comMid.p, pI2], tSplit);
|
|
7570
|
-
|
|
7571
|
-
/*
|
|
7572
|
-
renderPoint(markers, cp1_S, 'magenta', '1%', '1' )
|
|
7573
|
-
*/
|
|
7574
|
-
|
|
7575
|
-
pathDataS = [
|
|
7576
|
-
{ type: 'M', values: [comChunk0.p0.x, comChunk0.p0.y] },
|
|
7577
|
-
{
|
|
7578
|
-
type: 'C', values: [
|
|
7579
|
-
cp1_S.x, cp1_S.y,
|
|
7580
|
-
cp2_M.x, cp2_M.y,
|
|
7581
|
-
comMid.p.x,
|
|
7582
|
-
comMid.p.y
|
|
7583
|
-
]
|
|
7584
|
-
},
|
|
7585
|
-
{
|
|
7586
|
-
type: 'C', values: [
|
|
7587
|
-
cp1_M.x, cp1_M.y,
|
|
7588
|
-
cp2_S.x, cp2_S.y,
|
|
7589
|
-
comChunk1.p.x,
|
|
7590
|
-
comChunk1.p.y,
|
|
7591
|
-
]
|
|
7592
|
-
},
|
|
7593
|
-
];
|
|
7594
|
-
pathDataToD(pathDataS);
|
|
7595
|
-
|
|
7596
|
-
pathDataC.push(
|
|
7597
|
-
{
|
|
7598
|
-
type: 'C', values: [
|
|
7599
|
-
cp1_S.x, cp1_S.y,
|
|
7600
|
-
cp2_M.x, cp2_M.y,
|
|
7601
|
-
comMid.p.x,
|
|
7602
|
-
comMid.p.y
|
|
7603
|
-
],
|
|
7604
|
-
p0: comChunk0.p0,
|
|
7605
|
-
cp1: cp1_S,
|
|
7606
|
-
cp2: cp2_M,
|
|
7607
|
-
p: comMid.p,
|
|
7608
|
-
dimA: getDistManhattan(comChunk0.p0, comMid.p)
|
|
7609
|
-
},
|
|
7610
|
-
|
|
7611
|
-
{
|
|
7612
|
-
type: 'C', values: [
|
|
7613
|
-
cp1_M.x, cp1_M.y,
|
|
7614
|
-
cp2_S.x, cp2_S.y,
|
|
7615
|
-
comChunk1.p.x,
|
|
7616
|
-
comChunk1.p.y,
|
|
7617
|
-
],
|
|
7618
|
-
p0: comMid.p,
|
|
7619
|
-
cp1: cp1_M,
|
|
7620
|
-
cp2: cp2_S,
|
|
7621
|
-
p: comChunk1.p,
|
|
7622
|
-
extreme: true,
|
|
7623
|
-
dimA: getDistManhattan(comMid.p, comChunk1.p)
|
|
7624
|
-
|
|
7625
|
-
}
|
|
7626
|
-
);
|
|
7627
|
-
break
|
|
7628
|
-
|
|
7629
|
-
}
|
|
7630
|
-
} else {
|
|
7631
|
-
pathDataC.push(com);
|
|
7632
|
-
}
|
|
7633
|
-
|
|
7634
|
-
}
|
|
7635
|
-
|
|
7636
|
-
}
|
|
7637
|
-
|
|
7638
|
-
}
|
|
7639
|
-
|
|
7640
|
-
/*
|
|
7641
|
-
// render
|
|
7642
|
-
let d = pathDataToD(pathDataC)
|
|
7643
|
-
console.log(d);
|
|
7644
|
-
renderPath(markers, d, 'red', '1%', '0.5')
|
|
7645
|
-
*/
|
|
7646
|
-
|
|
7647
|
-
return pathDataC
|
|
7648
|
-
|
|
7649
|
-
}
|
|
7650
|
-
|
|
7651
|
-
function renderChunks(chunks) {
|
|
7652
|
-
|
|
7653
|
-
console.log('chunks', chunks);
|
|
7654
|
-
|
|
7655
|
-
let stroke = 'green';
|
|
7656
|
-
|
|
7657
|
-
/**
|
|
7658
|
-
* combine chunk based
|
|
7659
|
-
*/
|
|
7660
|
-
for (let c = 0; c < chunks.length; c++) {
|
|
7661
|
-
let chunk = chunks[c];
|
|
7662
|
-
let chunkLen = chunk.length;
|
|
7663
|
-
|
|
7664
|
-
stroke = c % 2 === 0 ? 'orange' : 'green';
|
|
7665
|
-
let comChunk0 = chunk[0];
|
|
7666
|
-
let comChunk1 = chunk[chunkLen - 1];
|
|
7667
|
-
|
|
7668
|
-
let pathDataChunk = [
|
|
7669
|
-
{ type: 'M', values: [comChunk0.p0.x, comChunk0.p0.y] }
|
|
7670
|
-
];
|
|
7671
|
-
|
|
7672
|
-
// commands in chunk
|
|
7673
|
-
for (let i = 0, l = chunkLen; i < l; i++) {
|
|
7674
|
-
let com = chunk[i];
|
|
7675
|
-
chunk[i + 1];
|
|
7676
|
-
chunk[l - 1];
|
|
7677
|
-
comChunk0.type === 'C' && comChunk1.type === 'C';
|
|
7678
|
-
|
|
7679
|
-
let { type, values, p0, cp1 = null, cp2 = null, p = null, extreme, semiExtreme = null, corner = null } = com;
|
|
7680
|
-
|
|
7681
|
-
// test render - original pathdata
|
|
7682
|
-
pathDataChunk.push(
|
|
7683
|
-
{ type, values },
|
|
7684
|
-
);
|
|
7685
|
-
|
|
7686
|
-
}
|
|
7687
|
-
|
|
7688
|
-
let d = pathDataToD(pathDataChunk);
|
|
7689
|
-
renderPath(markers, d, stroke, '1%', '0.5');
|
|
7690
|
-
|
|
7691
|
-
}
|
|
7692
|
-
}
|
|
7693
|
-
|
|
7694
|
-
function pathDataRevertCubicToQuadratic(pathData) {
|
|
7640
|
+
function pathDataRevertCubicToQuadratic(pathData, tolerance=1) {
|
|
7695
7641
|
|
|
7696
7642
|
for (let c = 1, l = pathData.length; c < l; c++) {
|
|
7697
7643
|
let com = pathData[c];
|
|
7698
7644
|
let { type, values, p0, cp1 = null, cp2 = null, p = null } = com;
|
|
7699
7645
|
if (type === 'C') {
|
|
7700
7646
|
|
|
7701
|
-
let comQ = revertCubicQuadratic(p0, cp1, cp2, p);
|
|
7647
|
+
let comQ = revertCubicQuadratic(p0, cp1, cp2, p, tolerance);
|
|
7702
7648
|
if (comQ.type === 'Q') {
|
|
7703
7649
|
comQ.extreme = com.extreme;
|
|
7704
7650
|
comQ.corner = com.corner;
|
|
@@ -8213,12 +8159,59 @@
|
|
|
8213
8159
|
}
|
|
8214
8160
|
*/
|
|
8215
8161
|
|
|
8162
|
+
function getPathDataPolyPrecise(pathData = []) {
|
|
8163
|
+
|
|
8164
|
+
let poly = [];
|
|
8165
|
+
for (let i = 0; i < pathData.length; i++) {
|
|
8166
|
+
let com = pathData[i];
|
|
8167
|
+
let prev = i > 0 ? pathData[i - 1] : pathData[i];
|
|
8168
|
+
let { type, values } = com;
|
|
8169
|
+
let p0 = { x: prev.values[prev.values.length - 2], y: prev.values[prev.values.length - 1] };
|
|
8170
|
+
let p = values.length ? { x: values[values.length - 2], y: values[values.length - 1] } : '';
|
|
8171
|
+
let cp1 = values.length ? { x: values[0], y: values[1] } : '';
|
|
8172
|
+
|
|
8173
|
+
switch (type) {
|
|
8174
|
+
|
|
8175
|
+
// convert to cubic to get polygon
|
|
8176
|
+
case 'A':
|
|
8177
|
+
if (typeof arcToBezier$1 !== 'function') {
|
|
8178
|
+
|
|
8179
|
+
break;
|
|
8180
|
+
}
|
|
8181
|
+
let cubic = arcToBezier$1(p0, values);
|
|
8182
|
+
cubic.forEach(com => {
|
|
8183
|
+
let vals = com.values;
|
|
8184
|
+
let cp1 = { x: vals[0], y: vals[1] };
|
|
8185
|
+
let cp2 = { x: vals[2], y: vals[3] };
|
|
8186
|
+
let p = { x: vals[4], y: vals[5] };
|
|
8187
|
+
poly.push(cp1, cp2, p);
|
|
8188
|
+
});
|
|
8189
|
+
break;
|
|
8190
|
+
|
|
8191
|
+
case 'C':
|
|
8192
|
+
let cp2 = { x: values[2], y: values[3] };
|
|
8193
|
+
poly.push(cp1, cp2);
|
|
8194
|
+
break;
|
|
8195
|
+
case 'Q':
|
|
8196
|
+
poly.push(cp1);
|
|
8197
|
+
break;
|
|
8198
|
+
}
|
|
8199
|
+
|
|
8200
|
+
// M and L commands
|
|
8201
|
+
if (type.toLowerCase() !== 'z') {
|
|
8202
|
+
poly.push(p);
|
|
8203
|
+
}
|
|
8204
|
+
}
|
|
8205
|
+
|
|
8206
|
+
return poly;
|
|
8207
|
+
}
|
|
8208
|
+
|
|
8216
8209
|
function pathDataToPolygon(pathData, {
|
|
8217
8210
|
angles = [],
|
|
8218
8211
|
split = 0,
|
|
8219
8212
|
getPathData = true,
|
|
8220
|
-
width=0,
|
|
8221
|
-
height=0
|
|
8213
|
+
width = 0,
|
|
8214
|
+
height = 0
|
|
8222
8215
|
} = {}) {
|
|
8223
8216
|
|
|
8224
8217
|
let l = pathData.length;
|
|
@@ -8234,9 +8227,9 @@
|
|
|
8234
8227
|
|
|
8235
8228
|
split = !split ? 1 : split;
|
|
8236
8229
|
|
|
8237
|
-
if(width && height){
|
|
8238
|
-
minLength = (width+height) * 0.025 / split;
|
|
8239
|
-
}else {
|
|
8230
|
+
if (width && height) {
|
|
8231
|
+
minLength = (width + height) * 0.025 / split;
|
|
8232
|
+
} else {
|
|
8240
8233
|
|
|
8241
8234
|
let lengths = pathData.map(com => com.dimA || 0).filter(Boolean).sort();
|
|
8242
8235
|
minLength = lengths[0];
|
|
@@ -8262,8 +8255,8 @@
|
|
|
8262
8255
|
split = Math.ceil(length / minLength);
|
|
8263
8256
|
|
|
8264
8257
|
let tArr = [];
|
|
8265
|
-
for(let i=1; i<split; i++){
|
|
8266
|
-
tArr.push(1/split*i);
|
|
8258
|
+
for (let i = 1; i < split; i++) {
|
|
8259
|
+
tArr.push(1 / split * i);
|
|
8267
8260
|
}
|
|
8268
8261
|
|
|
8269
8262
|
tArr.forEach(t => {
|
|
@@ -8277,10 +8270,10 @@
|
|
|
8277
8270
|
M = p;
|
|
8278
8271
|
}
|
|
8279
8272
|
|
|
8280
|
-
p.area = com.cptArea|| 0;
|
|
8281
|
-
p.isExtreme = com.extreme|| false;
|
|
8282
|
-
p.isCorner = com.corner|| false;
|
|
8283
|
-
p.isDirChange = com.directionChange || false
|
|
8273
|
+
p.area = com.cptArea || 0;
|
|
8274
|
+
p.isExtreme = com.extreme || false;
|
|
8275
|
+
p.isCorner = com.corner || false;
|
|
8276
|
+
p.isDirChange = com.directionChange || false;
|
|
8284
8277
|
|
|
8285
8278
|
// segment end point
|
|
8286
8279
|
pts.push(p);
|
|
@@ -8294,7 +8287,7 @@
|
|
|
8294
8287
|
|
|
8295
8288
|
// reduce poly vertices
|
|
8296
8289
|
|
|
8297
|
-
pts = simplifyRD(pts, {quality:0.5, width, height});
|
|
8290
|
+
pts = simplifyRD(pts, { quality: 0.5, width, height });
|
|
8298
8291
|
|
|
8299
8292
|
/*
|
|
8300
8293
|
pts.forEach(pt => {
|
|
@@ -8307,6 +8300,103 @@
|
|
|
8307
8300
|
return getPathData ? pathDataPoly : pts;
|
|
8308
8301
|
}
|
|
8309
8302
|
|
|
8303
|
+
function pathDataLineToCubic(pathData) {
|
|
8304
|
+
|
|
8305
|
+
for (let c = 1, l = pathData.length; c < l; c++) {
|
|
8306
|
+
let com = pathData[c];
|
|
8307
|
+
let { type, values, p0, cp1 = null, cp2 = null, p = null } = com;
|
|
8308
|
+
if (type === 'L') {
|
|
8309
|
+
|
|
8310
|
+
let cp1 = interpolate(p0, p, 0.333);
|
|
8311
|
+
let cp2 = interpolate(p, p0, 0.333);
|
|
8312
|
+
|
|
8313
|
+
pathData[c].type = 'C';
|
|
8314
|
+
pathData[c].values = [cp1.x, cp1.y, cp2.x, cp2.y, p.x, p.y];
|
|
8315
|
+
pathData[c].cp1 = cp1;
|
|
8316
|
+
pathData[c].cp2 = cp2;
|
|
8317
|
+
|
|
8318
|
+
}
|
|
8319
|
+
}
|
|
8320
|
+
return pathData
|
|
8321
|
+
}
|
|
8322
|
+
|
|
8323
|
+
/**
|
|
8324
|
+
* fix sub path directions
|
|
8325
|
+
* pathdata must be be normalized to
|
|
8326
|
+
* absolute and longhand commands
|
|
8327
|
+
* toClockwise = force default direction
|
|
8328
|
+
*/
|
|
8329
|
+
|
|
8330
|
+
function fixPathDataDirections(pathDataArr = [], toClockwise = false) {
|
|
8331
|
+
|
|
8332
|
+
let polys = [];
|
|
8333
|
+
|
|
8334
|
+
pathDataArr.forEach((sub, i) => {
|
|
8335
|
+
let pathData = sub.pathData;
|
|
8336
|
+
|
|
8337
|
+
let vertices = getPathDataPolyPrecise(pathData);
|
|
8338
|
+
let area = getPolygonArea(vertices);
|
|
8339
|
+
let isClockwise = area >= 0;
|
|
8340
|
+
polys.push({ pts: vertices, bb: getPolyBBox(vertices), cw: isClockwise, index: i, inter: 0, includes: [], includedIn: [] });
|
|
8341
|
+
});
|
|
8342
|
+
|
|
8343
|
+
// check poly intersections
|
|
8344
|
+
let l = polys.length;
|
|
8345
|
+
for (let i = 0; i < l; i++) {
|
|
8346
|
+
let prev = polys[i];
|
|
8347
|
+
let bb0 = prev.bb;
|
|
8348
|
+
|
|
8349
|
+
for (let j = 0; j < l; j++) {
|
|
8350
|
+
|
|
8351
|
+
let poly = polys[j];
|
|
8352
|
+
let bb = poly.bb;
|
|
8353
|
+
|
|
8354
|
+
// skip if the same poly or parent
|
|
8355
|
+
if (i === j || poly.includes.includes(i)) continue
|
|
8356
|
+
|
|
8357
|
+
// if mid point is in previous polygon
|
|
8358
|
+
let ptMid = { x: bb.left + bb.width / 2, y: bb.top + bb.height / 2 };
|
|
8359
|
+
let inPoly = isPointInPolygon(ptMid, prev.pts, bb0);
|
|
8360
|
+
|
|
8361
|
+
if (inPoly) {
|
|
8362
|
+
polys[j].inter += 1;
|
|
8363
|
+
poly.includedIn.push(i);
|
|
8364
|
+
prev.includes.push(j);
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
}
|
|
8368
|
+
|
|
8369
|
+
// reverse paths
|
|
8370
|
+
for (let i = 0; i < l; i++) {
|
|
8371
|
+
|
|
8372
|
+
let poly = polys[i];
|
|
8373
|
+
let { cw, includedIn, includes } = poly;
|
|
8374
|
+
|
|
8375
|
+
// outer path direction to counter clockwise
|
|
8376
|
+
if (!includedIn.length && cw && !toClockwise
|
|
8377
|
+
|| !includedIn.length && !cw && toClockwise
|
|
8378
|
+
) {
|
|
8379
|
+
pathDataArr[i].pathData = reversePathData(pathDataArr[i].pathData);
|
|
8380
|
+
polys[i].cw = polys[i].cw ? false : true;
|
|
8381
|
+
cw = polys[i].cw;
|
|
8382
|
+
}
|
|
8383
|
+
|
|
8384
|
+
// reverse inner sub paths
|
|
8385
|
+
for (let j = 0; j < includes.length; j++) {
|
|
8386
|
+
let ind = includes[j];
|
|
8387
|
+
let child = polys[ind];
|
|
8388
|
+
|
|
8389
|
+
if (child.cw === cw) {
|
|
8390
|
+
pathDataArr[ind].pathData = reversePathData(pathDataArr[ind].pathData);
|
|
8391
|
+
polys[ind].cw = polys[ind].cw ? false : true;
|
|
8392
|
+
}
|
|
8393
|
+
}
|
|
8394
|
+
}
|
|
8395
|
+
|
|
8396
|
+
return pathDataArr
|
|
8397
|
+
|
|
8398
|
+
}
|
|
8399
|
+
|
|
8310
8400
|
function svgPathSimplify(input = '', {
|
|
8311
8401
|
|
|
8312
8402
|
// return svg markup or object
|
|
@@ -8334,6 +8424,12 @@
|
|
|
8334
8424
|
|
|
8335
8425
|
refineExtremes = true,
|
|
8336
8426
|
simplifyCorners = false,
|
|
8427
|
+
removeDimensions = false,
|
|
8428
|
+
removeIds = false,
|
|
8429
|
+
removeClassNames = false,
|
|
8430
|
+
omitNamespace = false,
|
|
8431
|
+
|
|
8432
|
+
fixDirections = false,
|
|
8337
8433
|
|
|
8338
8434
|
keepExtremes = true,
|
|
8339
8435
|
keepCorners = true,
|
|
@@ -8347,7 +8443,6 @@
|
|
|
8347
8443
|
toPolygon = false,
|
|
8348
8444
|
|
|
8349
8445
|
removeOrphanSubpaths = false,
|
|
8350
|
-
|
|
8351
8446
|
simplifyRound = false,
|
|
8352
8447
|
|
|
8353
8448
|
scale = 1,
|
|
@@ -8355,32 +8450,28 @@
|
|
|
8355
8450
|
crop = false,
|
|
8356
8451
|
alignToOrigin = false,
|
|
8357
8452
|
|
|
8358
|
-
// svg path optimizations
|
|
8359
8453
|
decimals = 3,
|
|
8360
8454
|
autoAccuracy = true,
|
|
8361
8455
|
|
|
8362
8456
|
minifyD = 0,
|
|
8363
8457
|
tolerance = 1,
|
|
8364
|
-
|
|
8458
|
+
reversePath = false,
|
|
8365
8459
|
|
|
8366
|
-
|
|
8367
|
-
cleanupSVGAtts=true,
|
|
8460
|
+
cleanupSVGAtts = true,
|
|
8368
8461
|
removePrologue = true,
|
|
8369
8462
|
stylesToAttributes = true,
|
|
8370
8463
|
fixHref = true,
|
|
8371
|
-
removeNameSpaced=true,
|
|
8372
|
-
attributesToGroup=false,
|
|
8464
|
+
removeNameSpaced = true,
|
|
8465
|
+
attributesToGroup = false,
|
|
8373
8466
|
mergePaths = false,
|
|
8374
8467
|
removeHidden = true,
|
|
8375
8468
|
removeUnused = true,
|
|
8376
|
-
shapesToPaths =
|
|
8469
|
+
shapesToPaths = false,
|
|
8470
|
+
lineToCubic = false,
|
|
8377
8471
|
|
|
8378
8472
|
tMin = 0,
|
|
8379
8473
|
tMax = 1,
|
|
8380
8474
|
|
|
8381
|
-
// redraw - for messed up paths
|
|
8382
|
-
redraw = false,
|
|
8383
|
-
|
|
8384
8475
|
} = {}) {
|
|
8385
8476
|
|
|
8386
8477
|
// clamp tolerance and scale
|
|
@@ -8438,14 +8529,16 @@
|
|
|
8438
8529
|
else {
|
|
8439
8530
|
|
|
8440
8531
|
let returnDom = true;
|
|
8441
|
-
svg = cleanUpSVG(input, { cleanupSVGAtts, returnDom, removeHidden, removeUnused, removeNameSpaced,
|
|
8532
|
+
svg = cleanUpSVG(input, { removeIds, removeClassNames, removeDimensions, cleanupSVGAtts, returnDom, removeHidden, removeUnused, removeNameSpaced, stylesToAttributes, removePrologue, fixHref, mergePaths, shapesToPaths }
|
|
8442
8533
|
);
|
|
8443
8534
|
|
|
8444
8535
|
if (shapesToPaths) {
|
|
8445
8536
|
let shapes = svg.querySelectorAll('polygon, polyline, line, rect, circle, ellipse');
|
|
8446
8537
|
shapes.forEach(shape => {
|
|
8447
8538
|
let path = shapeElToPath(shape);
|
|
8539
|
+
|
|
8448
8540
|
shape.replaceWith(path);
|
|
8541
|
+
|
|
8449
8542
|
});
|
|
8450
8543
|
}
|
|
8451
8544
|
|
|
@@ -8598,23 +8691,6 @@
|
|
|
8598
8691
|
// remove zero length linetos
|
|
8599
8692
|
if (removeColinear || removeZeroLength) pathDataSub = removeZeroLengthLinetos(pathDataSub);
|
|
8600
8693
|
|
|
8601
|
-
/**
|
|
8602
|
-
* try to redraw messed up paths
|
|
8603
|
-
* based on significant points suchas
|
|
8604
|
-
* extremes, semi-extremes and corners
|
|
8605
|
-
*/
|
|
8606
|
-
if (redraw) {
|
|
8607
|
-
addExtremes = true;
|
|
8608
|
-
addSemiExtremes = true;
|
|
8609
|
-
simplifyCorners = false;
|
|
8610
|
-
keepCorners = true;
|
|
8611
|
-
keepExtremes = true;
|
|
8612
|
-
optimizeOrder = true;
|
|
8613
|
-
|
|
8614
|
-
tMin = 0;
|
|
8615
|
-
tMax = 0;
|
|
8616
|
-
}
|
|
8617
|
-
|
|
8618
8694
|
// sort to top left
|
|
8619
8695
|
if (optimizeOrder) pathDataSub = pathDataToTopLeft(pathDataSub);
|
|
8620
8696
|
|
|
@@ -8624,6 +8700,11 @@
|
|
|
8624
8700
|
if (addExtremes || addSemiExtremes) pathDataSub = addExtremePoints(pathDataSub,
|
|
8625
8701
|
{ tMin, tMax, addExtremes, addSemiExtremes, angles: [30] });
|
|
8626
8702
|
|
|
8703
|
+
// reverse
|
|
8704
|
+
if(reversePath) {
|
|
8705
|
+
pathDataSub = reversePathData(pathDataSub);
|
|
8706
|
+
}
|
|
8707
|
+
|
|
8627
8708
|
// analyze pathdata to add info about signicant properties such as extremes, corners
|
|
8628
8709
|
let pathDataPlus = analyzePathData(pathDataSub, {
|
|
8629
8710
|
detectSemiExtremes: addSemiExtremes,
|
|
@@ -8636,7 +8717,7 @@
|
|
|
8636
8717
|
|
|
8637
8718
|
if (refineClosing) pathData = refineClosingCommand(pathData, { threshold: dimA * 0.001 });
|
|
8638
8719
|
|
|
8639
|
-
pathData = simplifyBezier ? simplifyPathDataCubic(pathData, { simplifyBezier, keepInflections, keepExtremes, keepCorners, extrapolateDominant, revertToQuadratics, tolerance
|
|
8720
|
+
pathData = simplifyBezier ? simplifyPathDataCubic(pathData, { simplifyBezier, keepInflections, keepExtremes, keepCorners, extrapolateDominant, revertToQuadratics, tolerance }) : pathData;
|
|
8640
8721
|
|
|
8641
8722
|
// refine extremes
|
|
8642
8723
|
if (refineExtremes) {
|
|
@@ -8645,29 +8726,6 @@
|
|
|
8645
8726
|
pathData = refineAdjacentExtremes(pathData, { threshold: thresholdEx, tolerance });
|
|
8646
8727
|
}
|
|
8647
8728
|
|
|
8648
|
-
/**
|
|
8649
|
-
* try redrawing
|
|
8650
|
-
*/
|
|
8651
|
-
|
|
8652
|
-
if (redraw) {
|
|
8653
|
-
|
|
8654
|
-
/*
|
|
8655
|
-
pathData = addExtremePoints(pathData,
|
|
8656
|
-
{ tMin: 0, tMax: 1, addExtremes: true, addSemiExtremes: true })
|
|
8657
|
-
|
|
8658
|
-
pathData = analyzePathData(pathDataSub, {
|
|
8659
|
-
detectSemiExtremes: true,
|
|
8660
|
-
detectExtremes: true,
|
|
8661
|
-
}).pathData;
|
|
8662
|
-
|
|
8663
|
-
*/
|
|
8664
|
-
|
|
8665
|
-
(bb.width + bb.height) * 0.1;
|
|
8666
|
-
|
|
8667
|
-
pathData = redrawPathData(pathData, { tolerance, threshold: dimA * 0.001 });
|
|
8668
|
-
|
|
8669
|
-
}
|
|
8670
|
-
|
|
8671
8729
|
// cubic to arcs
|
|
8672
8730
|
if (cubicToArc) pathData = pathDataCubicsToArc(pathData, { areaThreshold: 2.5 });
|
|
8673
8731
|
|
|
@@ -8687,13 +8745,14 @@
|
|
|
8687
8745
|
if (simplifyRound) pathData = refineRoundSegments(pathData);
|
|
8688
8746
|
|
|
8689
8747
|
// simplify to quadratics
|
|
8690
|
-
if (revertToQuadratics) pathData = pathDataRevertCubicToQuadratic(pathData);
|
|
8748
|
+
if (revertToQuadratics) pathData = pathDataRevertCubicToQuadratic(pathData, tolerance);
|
|
8749
|
+
|
|
8750
|
+
if (lineToCubic) pathData = pathDataLineToCubic(pathData);
|
|
8691
8751
|
|
|
8692
8752
|
// optimize close path
|
|
8693
8753
|
if (optimizeOrder) pathData = optimizeClosePath(pathData, { autoClose });
|
|
8694
8754
|
|
|
8695
8755
|
// update
|
|
8696
|
-
|
|
8697
8756
|
pathDataPlusArr.push({ pathData, bb });
|
|
8698
8757
|
|
|
8699
8758
|
} // end sup paths
|
|
@@ -8712,6 +8771,11 @@
|
|
|
8712
8771
|
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);
|
|
8713
8772
|
}
|
|
8714
8773
|
|
|
8774
|
+
// fix path directions
|
|
8775
|
+
if (fixDirections) {
|
|
8776
|
+
pathDataPlusArr = fixPathDataDirections(pathDataPlusArr);
|
|
8777
|
+
}
|
|
8778
|
+
|
|
8715
8779
|
// flatten compound paths
|
|
8716
8780
|
pathData = [];
|
|
8717
8781
|
pathDataPlusArr.forEach(sub => {
|
|
@@ -8721,11 +8785,10 @@
|
|
|
8721
8785
|
if (autoAccuracy) {
|
|
8722
8786
|
decimals = detectAccuracy(pathData);
|
|
8723
8787
|
pathOptions.decimals = decimals;
|
|
8724
|
-
|
|
8725
8788
|
}
|
|
8726
8789
|
|
|
8727
8790
|
// collect for merged svg paths
|
|
8728
|
-
mergePaths= false;
|
|
8791
|
+
mergePaths = false;
|
|
8729
8792
|
if (el && mergePaths) {
|
|
8730
8793
|
pathData_merged.push(...pathData);
|
|
8731
8794
|
}
|
|
@@ -8828,7 +8891,16 @@
|
|
|
8828
8891
|
}
|
|
8829
8892
|
}
|
|
8830
8893
|
|
|
8831
|
-
|
|
8894
|
+
// remove fill rules
|
|
8895
|
+
if (fixDirections) {
|
|
8896
|
+
let elsFill = svg.querySelectorAll('path[fill-rule], path[clip-rule]');
|
|
8897
|
+
elsFill.forEach(el => {
|
|
8898
|
+
el.removeAttribute('fill-rule');
|
|
8899
|
+
el.removeAttribute('clip-rule');
|
|
8900
|
+
});
|
|
8901
|
+
}
|
|
8902
|
+
|
|
8903
|
+
svg = stringifySVG(svg, omitNamespace);
|
|
8832
8904
|
|
|
8833
8905
|
svgSizeOpt = svg.length;
|
|
8834
8906
|
|
|
@@ -8872,6 +8944,9 @@
|
|
|
8872
8944
|
|
|
8873
8945
|
import {parsePathDataString_plus} from './svgii/pathData_parse2';
|
|
8874
8946
|
export {parsePathDataString_plus as parsePathDataString_plus}
|
|
8947
|
+
|
|
8948
|
+
import {getPathDataFromEl} from './svgii/pathData_parse_els';
|
|
8949
|
+
export{getPathDataFromEl as getPathDataFromEl};
|
|
8875
8950
|
*/
|
|
8876
8951
|
|
|
8877
8952
|
// IIFE
|