plotboilerplate 1.18.0 → 1.20.0
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 +1 -1
- package/dist/index.esm.js +244 -63
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/plotboilerplate.browser.min.js +1 -1
- package/dist/plotboilerplate.browser.min.js.map +1 -1
- package/dist/plotboilerplate.js +243 -74
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +1 -1
- package/src/cjs/Bounds.d.ts +14 -5
- package/src/cjs/Bounds.js +18 -8
- package/src/cjs/Bounds.js.map +1 -1
- package/src/cjs/CubicBezierCurve.d.ts +20 -3
- package/src/cjs/CubicBezierCurve.js +25 -2
- package/src/cjs/CubicBezierCurve.js.map +1 -1
- package/src/cjs/Line.d.ts +46 -4
- package/src/cjs/Line.js +60 -3
- package/src/cjs/Line.js.map +1 -1
- package/src/cjs/PlotBoilerplate.d.ts +5 -2
- package/src/cjs/PlotBoilerplate.js +52 -30
- package/src/cjs/PlotBoilerplate.js.map +1 -1
- package/src/cjs/Polygon.js +1 -1
- package/src/cjs/Polygon.js.map +1 -1
- package/src/cjs/VEllipseSector.d.ts +4 -3
- package/src/cjs/VEllipseSector.js +15 -8
- package/src/cjs/VEllipseSector.js.map +1 -1
- package/src/cjs/Vector.d.ts +14 -3
- package/src/cjs/Vector.js +21 -2
- package/src/cjs/Vector.js.map +1 -1
- package/src/cjs/Vertex.d.ts +33 -1
- package/src/cjs/Vertex.js +43 -1
- package/src/cjs/Vertex.js.map +1 -1
- package/src/cjs/drawutilssvg.d.ts +2 -1
- package/src/cjs/drawutilssvg.js +7 -19
- package/src/cjs/drawutilssvg.js.map +1 -1
- package/src/cjs/entry.js +1 -0
- package/src/cjs/interfaces/additionals.d.ts +95 -0
- package/src/cjs/interfaces/additionals.js +3 -0
- package/src/cjs/interfaces/additionals.js.map +1 -0
- package/src/cjs/interfaces/core.d.ts +7 -0
- package/src/cjs/interfaces/core.js +2 -0
- package/src/cjs/interfaces/core.js.map +1 -1
- package/src/cjs/interfaces/index.d.ts +1 -0
- package/src/cjs/interfaces/index.js +1 -0
- package/src/cjs/interfaces/index.js.map +1 -1
- package/src/cjs/utils/algorithms/arrayShuffle.d.ts +8 -0
- package/src/cjs/utils/algorithms/arrayShuffle.js +15 -0
- package/src/cjs/utils/algorithms/arrayShuffle.js.map +1 -0
- package/src/cjs/utils/algorithms/detectPaths.d.ts +21 -0
- package/src/cjs/utils/algorithms/detectPaths.js +169 -0
- package/src/cjs/utils/algorithms/detectPaths.js.map +1 -0
- package/src/cjs/utils/creategui.js +7 -0
- package/src/cjs/utils/datastructures/Color.d.ts +1 -1
- package/src/cjs/utils/datastructures/Color.js +4 -2
- package/src/cjs/utils/datastructures/Color.js.map +1 -1
- package/src/cjs/utils/datastructures/GenericPath.d.ts +75 -0
- package/src/cjs/utils/datastructures/GenericPath.js +105 -0
- package/src/cjs/utils/datastructures/GenericPath.js.map +1 -0
- package/src/cjs/utils/datastructures/GirihTile.d.ts +1 -1
- package/src/cjs/utils/io/FileDrop.d.ts +11 -1
- package/src/cjs/utils/io/FileDrop.js +41 -10
- package/src/cjs/utils/io/FileDrop.js.map +1 -1
- package/src/cjs/utils/parsers/svg/parseSVGPathData.d.ts +26 -0
- package/src/cjs/utils/parsers/svg/parseSVGPathData.js +463 -0
- package/src/cjs/utils/parsers/svg/parseSVGPathData.js.map +1 -0
- package/src/cjs/utils/parsers/svg/splitSVGPathData.d.ts +20 -0
- package/src/cjs/utils/parsers/svg/splitSVGPathData.js +49 -0
- package/src/cjs/utils/parsers/svg/splitSVGPathData.js.map +1 -0
- package/src/cjs/utils/parsers/svg/types.d.ts +43 -0
- package/src/cjs/utils/parsers/svg/types.js +16 -0
- package/src/cjs/utils/parsers/svg/types.js.map +1 -0
- package/src/esm/Bounds.d.ts +14 -5
- package/src/esm/Bounds.js +18 -8
- package/src/esm/Bounds.js.map +1 -1
- package/src/esm/CubicBezierCurve.d.ts +20 -3
- package/src/esm/CubicBezierCurve.js +25 -2
- package/src/esm/CubicBezierCurve.js.map +1 -1
- package/src/esm/Line.d.ts +46 -4
- package/src/esm/Line.js +60 -3
- package/src/esm/Line.js.map +1 -1
- package/src/esm/PlotBoilerplate.d.ts +5 -2
- package/src/esm/PlotBoilerplate.js +52 -30
- package/src/esm/PlotBoilerplate.js.map +1 -1
- package/src/esm/Polygon.js +1 -1
- package/src/esm/Polygon.js.map +1 -1
- package/src/esm/VEllipseSector.d.ts +4 -3
- package/src/esm/VEllipseSector.js +15 -8
- package/src/esm/VEllipseSector.js.map +1 -1
- package/src/esm/Vector.d.ts +13 -2
- package/src/esm/Vector.js +23 -4
- package/src/esm/Vector.js.map +1 -1
- package/src/esm/Vertex.d.ts +33 -1
- package/src/esm/Vertex.js +43 -1
- package/src/esm/Vertex.js.map +1 -1
- package/src/esm/drawutilssvg.d.ts +2 -1
- package/src/esm/drawutilssvg.js +7 -19
- package/src/esm/drawutilssvg.js.map +1 -1
- package/src/esm/entry.js +1 -0
- package/src/esm/interfaces/additionals.d.ts +95 -0
- package/src/esm/interfaces/additionals.js +2 -0
- package/src/esm/interfaces/additionals.js.map +1 -0
- package/src/esm/interfaces/core.d.ts +7 -0
- package/src/esm/interfaces/core.js +2 -0
- package/src/esm/interfaces/core.js.map +1 -1
- package/src/esm/interfaces/index.d.ts +1 -0
- package/src/esm/interfaces/index.js +1 -0
- package/src/esm/interfaces/index.js.map +1 -1
- package/src/esm/utils/algorithms/arrayShuffle.d.ts +8 -0
- package/src/esm/utils/algorithms/arrayShuffle.js +11 -0
- package/src/esm/utils/algorithms/arrayShuffle.js.map +1 -0
- package/src/esm/utils/algorithms/detectPaths.d.ts +21 -0
- package/src/esm/utils/algorithms/detectPaths.js +165 -0
- package/src/esm/utils/algorithms/detectPaths.js.map +1 -0
- package/src/esm/utils/datastructures/Color.d.ts +1 -1
- package/src/esm/utils/datastructures/Color.js +4 -2
- package/src/esm/utils/datastructures/Color.js.map +1 -1
- package/src/esm/utils/datastructures/GenericPath.d.ts +75 -0
- package/src/esm/utils/datastructures/GenericPath.js +100 -0
- package/src/esm/utils/datastructures/GenericPath.js.map +1 -0
- package/src/esm/utils/datastructures/GirihTile.d.ts +1 -1
- package/src/esm/utils/io/FileDrop.d.ts +11 -1
- package/src/esm/utils/io/FileDrop.js +41 -10
- package/src/esm/utils/io/FileDrop.js.map +1 -1
- package/src/esm/utils/parsers/svg/parseSVGPathData.d.ts +26 -0
- package/src/esm/utils/parsers/svg/parseSVGPathData.js +459 -0
- package/src/esm/utils/parsers/svg/parseSVGPathData.js.map +1 -0
- package/src/esm/utils/parsers/svg/splitSVGPathData.d.ts +20 -0
- package/src/esm/utils/parsers/svg/splitSVGPathData.js +45 -0
- package/src/esm/utils/parsers/svg/splitSVGPathData.js.map +1 -0
- package/src/esm/utils/parsers/svg/types.d.ts +43 -0
- package/src/esm/utils/parsers/svg/types.js +15 -0
- package/src/esm/utils/parsers/svg/types.js.map +1 -0
- package/src/ts/Bounds.ts +19 -8
- package/src/ts/CubicBezierCurve.ts +29 -4
- package/src/ts/Line.ts +70 -6
- package/src/ts/PlotBoilerplate.ts +57 -35
- package/src/ts/Polygon.ts +1 -1
- package/src/ts/VEllipseSector.ts +22 -15
- package/src/ts/Vector.ts +24 -4
- package/src/ts/Vertex.ts +46 -1
- package/src/ts/drawutilssvg.ts +8 -19
- package/src/ts/interfaces/additionals.ts +105 -0
- package/src/ts/interfaces/core.ts +5 -0
- package/src/ts/interfaces/index.ts +1 -0
- package/src/ts/utils/algorithms/arrayShuffle.ts +11 -0
- package/src/ts/utils/algorithms/detectPaths.ts +195 -0
- package/src/ts/utils/datastructures/Color.ts +8 -4
- package/src/ts/utils/datastructures/GenericPath.ts +113 -0
- package/src/ts/utils/datastructures/GirihTile.ts +1 -1
- package/src/ts/utils/io/FileDrop.ts +51 -10
- package/src/ts/utils/parsers/svg/parseSVGPathData.ts +572 -0
- package/src/ts/utils/parsers/svg/splitSVGPathData.ts +50 -0
- package/src/ts/utils/parsers/svg/types.ts +70 -0
- package/changelog.md +0 -731
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse SVG path data strings and convert to PlotBoilerplate path objects.
|
|
3
|
+
*
|
|
4
|
+
* As this parser function does not detect all possible path data strings it should cover the most daily use-cases.
|
|
5
|
+
*
|
|
6
|
+
* For more insight see
|
|
7
|
+
* https://www.w3.org/TR/SVG/paths.html
|
|
8
|
+
*
|
|
9
|
+
* @author Ikaros Kappler
|
|
10
|
+
* @date 2022-11-06
|
|
11
|
+
* @modified 2022-12-21 (winter solstice) Porting this to Typescript.
|
|
12
|
+
* @version 0.0.1-alpha
|
|
13
|
+
**/
|
|
14
|
+
|
|
15
|
+
import { CubicBezierCurve } from "../../../CubicBezierCurve";
|
|
16
|
+
import { XYCoords } from "../../../interfaces/core";
|
|
17
|
+
import { Line } from "../../../Line";
|
|
18
|
+
import { VEllipseSector } from "../../../VEllipseSector";
|
|
19
|
+
import { Vertex } from "../../../Vertex";
|
|
20
|
+
import { splitSVGPathData } from "./splitSVGPathData";
|
|
21
|
+
import {
|
|
22
|
+
SVGPathArcToCommand,
|
|
23
|
+
SVGPathCloseCommand,
|
|
24
|
+
SVGPathCommand,
|
|
25
|
+
SVGPathCubicCurveToCommand,
|
|
26
|
+
SVGPathHorizontalLineToCommand,
|
|
27
|
+
SVGPathLineToCommand,
|
|
28
|
+
SVGPathMoveToCommand,
|
|
29
|
+
SVGPathQuadraticCurveToCommand,
|
|
30
|
+
SVGPathShorthandCubicCurveToCommand,
|
|
31
|
+
SVGPathShorthandQuadraticCurveToCommand,
|
|
32
|
+
SVGPathVerticalLineToCommand
|
|
33
|
+
} from "./types";
|
|
34
|
+
|
|
35
|
+
const DEG_TO_RAD = Math.PI / 180;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Transform the given path data (translate and scale. rotating is not intended here).
|
|
39
|
+
*
|
|
40
|
+
* @date 2022-11-06
|
|
41
|
+
*
|
|
42
|
+
* @name parseSVGPathData
|
|
43
|
+
* @static
|
|
44
|
+
* @param {string} data - The data to parse.
|
|
45
|
+
* @return An array of straight line segments (Line) or curve segments (CubicBezierCurve) representing the path.
|
|
46
|
+
*/
|
|
47
|
+
export const parseSVGPathData = (dataString: string): Array<Line | CubicBezierCurve> | null => {
|
|
48
|
+
const dataElements: Array<SVGPathCommand> | null = splitSVGPathData(dataString);
|
|
49
|
+
|
|
50
|
+
if (!dataElements) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Array<PathSegments>
|
|
55
|
+
const result: Array<Line | CubicBezierCurve> = [];
|
|
56
|
+
|
|
57
|
+
var i = 0;
|
|
58
|
+
const firstPoint = { x: NaN, y: NaN };
|
|
59
|
+
const lastPoint = { x: NaN, y: NaN };
|
|
60
|
+
const lastControlPoint = { x: NaN, y: NaN };
|
|
61
|
+
|
|
62
|
+
while (i < dataElements.length) {
|
|
63
|
+
// Could this also be SVGPathShorthandQuadraticCurveToCommand?
|
|
64
|
+
const data: SVGPathCommand = dataElements[i];
|
|
65
|
+
const cmd = data[0];
|
|
66
|
+
// console.log("cmd", cmd, "data", data);
|
|
67
|
+
switch (data[0]) {
|
|
68
|
+
case "M":
|
|
69
|
+
// MoveTo: M|m x y
|
|
70
|
+
_handleMove(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
71
|
+
break;
|
|
72
|
+
case "m":
|
|
73
|
+
// MoveTo: M|m x y
|
|
74
|
+
_handleMove(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
75
|
+
break;
|
|
76
|
+
case "L":
|
|
77
|
+
// LineTo L|l x y
|
|
78
|
+
_handleLineTo(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
79
|
+
break;
|
|
80
|
+
case "l":
|
|
81
|
+
// LineTo L|l x y
|
|
82
|
+
_handleLineTo(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
83
|
+
break;
|
|
84
|
+
case "H":
|
|
85
|
+
// HorizontalLineTo: H|h x
|
|
86
|
+
_handleHorizontalLineTo(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
87
|
+
break;
|
|
88
|
+
case "h":
|
|
89
|
+
// HorizontalLineTo: H|h x
|
|
90
|
+
_handleHorizontalLineTo(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
91
|
+
break;
|
|
92
|
+
case "V":
|
|
93
|
+
// VerticalLineTo: V|v y
|
|
94
|
+
_handleVerticalLineTo(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
95
|
+
break;
|
|
96
|
+
case "v":
|
|
97
|
+
// VerticalLineTo: V|v y
|
|
98
|
+
_handleVerticalLineTo(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
99
|
+
break;
|
|
100
|
+
case "C":
|
|
101
|
+
// CurveTo: C|c x1 y1 x2 y2 x y
|
|
102
|
+
_handleCubicBezierTo(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
103
|
+
break;
|
|
104
|
+
case "c":
|
|
105
|
+
// CurveTo: C|c x1 y1 x2 y2 x y
|
|
106
|
+
_handleCubicBezierTo(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
107
|
+
break;
|
|
108
|
+
case "S":
|
|
109
|
+
_handleShorthandCubicCurveTo(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
110
|
+
break;
|
|
111
|
+
case "s":
|
|
112
|
+
_handleShorthandCubicCurveTo(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
113
|
+
break;
|
|
114
|
+
case "Q":
|
|
115
|
+
// QuadraticCurveTo: Q|q x1 y1 x y
|
|
116
|
+
_handleQuadraticCurveTo(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
117
|
+
break;
|
|
118
|
+
case "q":
|
|
119
|
+
// QuadraticCurveTo: Q|q x1 y1 x y
|
|
120
|
+
_handleQuadraticCurveTo(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
121
|
+
break;
|
|
122
|
+
case "A":
|
|
123
|
+
// EllipticalArcTo: A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y
|
|
124
|
+
_handleArcTo(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
125
|
+
break;
|
|
126
|
+
case "a":
|
|
127
|
+
// EllipticalArcTo: A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y
|
|
128
|
+
_handleArcTo(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
129
|
+
break;
|
|
130
|
+
case "z":
|
|
131
|
+
_handleClosePath(data, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
132
|
+
break;
|
|
133
|
+
case "Z":
|
|
134
|
+
// ClosePath: Z|z (no arguments)
|
|
135
|
+
_handleClosePath(data, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
136
|
+
// i++;
|
|
137
|
+
break;
|
|
138
|
+
default:
|
|
139
|
+
if ((cmd as string) === "T") {
|
|
140
|
+
throw "T command only allowed after q command.";
|
|
141
|
+
}
|
|
142
|
+
if ((cmd as string) === "t") {
|
|
143
|
+
throw "t command only allowed after q command.";
|
|
144
|
+
}
|
|
145
|
+
throw "Unknown SVG path command found: " + cmd + ".";
|
|
146
|
+
}
|
|
147
|
+
// Safepoint: continue reading token by token until something is recognized again
|
|
148
|
+
i++;
|
|
149
|
+
} // END while
|
|
150
|
+
|
|
151
|
+
return result;
|
|
152
|
+
}; // END parseSVGPathData
|
|
153
|
+
|
|
154
|
+
// Just update the current position
|
|
155
|
+
const _handleMove = (
|
|
156
|
+
data: SVGPathMoveToCommand,
|
|
157
|
+
isRelative: boolean,
|
|
158
|
+
firstPoint: XYCoords,
|
|
159
|
+
lastPoint: XYCoords,
|
|
160
|
+
lastControlPoint: XYCoords,
|
|
161
|
+
_result: Array<Line | CubicBezierCurve>
|
|
162
|
+
) => {
|
|
163
|
+
if (data.length < 3) {
|
|
164
|
+
throw "Unsufficient params for MOVE";
|
|
165
|
+
}
|
|
166
|
+
// result.push( new)
|
|
167
|
+
if (isRelative && !isNaN(lastPoint.x) && !isNaN(lastPoint.y)) {
|
|
168
|
+
lastPoint.x += Number(data[1]);
|
|
169
|
+
lastPoint.y += Number(data[2]);
|
|
170
|
+
lastControlPoint.x = lastPoint.x;
|
|
171
|
+
lastControlPoint.y = lastPoint.y;
|
|
172
|
+
} else {
|
|
173
|
+
lastPoint.x = Number(data[1]);
|
|
174
|
+
lastPoint.y = Number(data[2]);
|
|
175
|
+
lastControlPoint.x = lastPoint.x;
|
|
176
|
+
lastControlPoint.y = lastPoint.y;
|
|
177
|
+
}
|
|
178
|
+
// console.log("AFTER MOVE", lastPoint);
|
|
179
|
+
if (isNaN(firstPoint.y)) {
|
|
180
|
+
firstPoint.x = lastPoint.x;
|
|
181
|
+
firstPoint.y = lastPoint.y;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Draw a line segment from the current position
|
|
186
|
+
const _handleLineTo = (
|
|
187
|
+
data: SVGPathLineToCommand,
|
|
188
|
+
isRelative: boolean,
|
|
189
|
+
firstPoint: XYCoords,
|
|
190
|
+
lastPoint: XYCoords,
|
|
191
|
+
lastControlPoint: XYCoords,
|
|
192
|
+
result: Array<Line | CubicBezierCurve>
|
|
193
|
+
) => {
|
|
194
|
+
// console.log("Handle LINETO", data);
|
|
195
|
+
if (data.length < 3) {
|
|
196
|
+
throw "Unsufficient params for LINETO";
|
|
197
|
+
}
|
|
198
|
+
// console.log("Y: ", Number(data[2]), "lastPoint", lastPoint);
|
|
199
|
+
// result.push( new)
|
|
200
|
+
const line = new Line(new Vertex(lastPoint), new Vertex(lastPoint));
|
|
201
|
+
if (isRelative) {
|
|
202
|
+
line.b.x += Number(data[1]);
|
|
203
|
+
line.b.y += Number(data[2]);
|
|
204
|
+
} else {
|
|
205
|
+
line.b.x = Number(data[1]);
|
|
206
|
+
line.b.y = Number(data[2]);
|
|
207
|
+
}
|
|
208
|
+
result.push(line);
|
|
209
|
+
lastPoint.x = line.b.x;
|
|
210
|
+
lastPoint.y = line.b.y;
|
|
211
|
+
lastControlPoint.x = line.b.x;
|
|
212
|
+
lastControlPoint.y = line.b.y;
|
|
213
|
+
if (isNaN(firstPoint.y)) {
|
|
214
|
+
firstPoint.x = line.a.x;
|
|
215
|
+
firstPoint.y = line.a.y;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const _handleHorizontalLineTo = (
|
|
220
|
+
data: SVGPathHorizontalLineToCommand,
|
|
221
|
+
isRelative: boolean,
|
|
222
|
+
firstPoint: XYCoords,
|
|
223
|
+
lastPoint: XYCoords,
|
|
224
|
+
lastControlPoint: XYCoords,
|
|
225
|
+
result: Array<Line | CubicBezierCurve>
|
|
226
|
+
) => {
|
|
227
|
+
// console.log("Handle HORIZONTALLINETO", data);
|
|
228
|
+
if (data.length < 2) {
|
|
229
|
+
throw "Unsufficient params for HORIZONTALLINETO";
|
|
230
|
+
}
|
|
231
|
+
// console.log("Y: ", Number(data[2]), "lastPoint", lastPoint);
|
|
232
|
+
// result.push( new)
|
|
233
|
+
const line = new Line(new Vertex(lastPoint), new Vertex(lastPoint));
|
|
234
|
+
if (isRelative) {
|
|
235
|
+
line.b.x += Number(data[1]);
|
|
236
|
+
// line.b.y += Number(data[2]);
|
|
237
|
+
} else {
|
|
238
|
+
line.b.x = Number(data[1]);
|
|
239
|
+
// line.b.y = Number(data[2]);
|
|
240
|
+
}
|
|
241
|
+
result.push(line);
|
|
242
|
+
lastPoint.x = line.b.x;
|
|
243
|
+
// lastPoint.y = line.b.y;
|
|
244
|
+
lastControlPoint.x = line.b.x;
|
|
245
|
+
if (isNaN(firstPoint.y)) {
|
|
246
|
+
firstPoint.x = line.a.x;
|
|
247
|
+
firstPoint.y = line.a.y;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const _handleVerticalLineTo = (
|
|
252
|
+
data: SVGPathVerticalLineToCommand,
|
|
253
|
+
isRelative: boolean,
|
|
254
|
+
firstPoint: XYCoords,
|
|
255
|
+
lastPoint: XYCoords,
|
|
256
|
+
lastControlPoint: XYCoords,
|
|
257
|
+
result: Array<Line | CubicBezierCurve>
|
|
258
|
+
) => {
|
|
259
|
+
// console.log("Handle VERTICALLINETO", data);
|
|
260
|
+
if (data.length < 2) {
|
|
261
|
+
throw "Unsufficient params for VERTICALLINETO";
|
|
262
|
+
}
|
|
263
|
+
// console.log("Y: ", Number(data[2]), "lastPoint", lastPoint);
|
|
264
|
+
// result.push( new)
|
|
265
|
+
const line = new Line(new Vertex(lastPoint), new Vertex(lastPoint));
|
|
266
|
+
if (isRelative) {
|
|
267
|
+
// line.b.x += Number(data[1]);
|
|
268
|
+
line.b.y += Number(data[1]);
|
|
269
|
+
} else {
|
|
270
|
+
// line.b.x = Number(data[1]);
|
|
271
|
+
line.b.y = Number(data[1]);
|
|
272
|
+
}
|
|
273
|
+
result.push(line);
|
|
274
|
+
// lastPoint.x = line.b.x;
|
|
275
|
+
lastPoint.y = line.b.y;
|
|
276
|
+
lastControlPoint.y = line.b.y;
|
|
277
|
+
if (isNaN(firstPoint.y)) {
|
|
278
|
+
firstPoint.x = line.a.x;
|
|
279
|
+
firstPoint.y = line.a.y;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// CurveTo: C|c x1 y1 x2 y2 x y
|
|
284
|
+
const _handleCubicBezierTo = (
|
|
285
|
+
data: SVGPathCubicCurveToCommand,
|
|
286
|
+
isRelative: boolean,
|
|
287
|
+
firstPoint: XYCoords,
|
|
288
|
+
lastPoint: XYCoords,
|
|
289
|
+
lastControlPoint: XYCoords,
|
|
290
|
+
result: Array<Line | CubicBezierCurve>
|
|
291
|
+
) => {
|
|
292
|
+
// console.log("Handle CUBICBEZIERTO", data);
|
|
293
|
+
if (data.length < 7) {
|
|
294
|
+
throw "Unsufficient params for CUBICBEZIERTO";
|
|
295
|
+
}
|
|
296
|
+
// console.log("Y: ", Number(data[2]), "lastPoint", lastPoint);
|
|
297
|
+
// result.push( new)
|
|
298
|
+
const curve = new CubicBezierCurve(new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint));
|
|
299
|
+
if (isRelative) {
|
|
300
|
+
curve.startControlPoint.x += Number(data[1]);
|
|
301
|
+
curve.startControlPoint.y += Number(data[2]);
|
|
302
|
+
curve.endControlPoint.x += Number(data[3]);
|
|
303
|
+
curve.endControlPoint.y += Number(data[4]);
|
|
304
|
+
curve.endPoint.x += Number(data[5]);
|
|
305
|
+
curve.endPoint.y += Number(data[6]);
|
|
306
|
+
} else {
|
|
307
|
+
curve.startControlPoint.x = Number(data[1]);
|
|
308
|
+
curve.startControlPoint.y = Number(data[2]);
|
|
309
|
+
curve.endControlPoint.x = Number(data[3]);
|
|
310
|
+
curve.endControlPoint.y = Number(data[4]);
|
|
311
|
+
curve.endPoint.x = Number(data[5]);
|
|
312
|
+
curve.endPoint.y = Number(data[6]);
|
|
313
|
+
}
|
|
314
|
+
result.push(curve);
|
|
315
|
+
lastPoint.x = curve.endPoint.x;
|
|
316
|
+
lastPoint.y = curve.endPoint.y;
|
|
317
|
+
lastControlPoint.x = curve.endControlPoint.x;
|
|
318
|
+
lastControlPoint.y = curve.endControlPoint.y;
|
|
319
|
+
if (isNaN(firstPoint.x)) {
|
|
320
|
+
firstPoint.x = curve.startPoint.x;
|
|
321
|
+
firstPoint.y = curve.startPoint.y;
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// QuadraticCurveTo: Q|q x1 y1 x y
|
|
326
|
+
const _handleQuadraticCurveTo = (
|
|
327
|
+
data: SVGPathQuadraticCurveToCommand,
|
|
328
|
+
isRelative: boolean,
|
|
329
|
+
firstPoint: XYCoords,
|
|
330
|
+
lastPoint: XYCoords,
|
|
331
|
+
lastControlPoint: XYCoords,
|
|
332
|
+
result: Array<Line | CubicBezierCurve>
|
|
333
|
+
) => {
|
|
334
|
+
// console.log("Handle QUADRATICBEZIERTO", data);
|
|
335
|
+
if (data.length < 5) {
|
|
336
|
+
throw "Unsufficient params for QUADRATICBEZIERTO";
|
|
337
|
+
}
|
|
338
|
+
// console.log("Y: ", Number(data[2]), "lastPoint", lastPoint);
|
|
339
|
+
// result.push( new)
|
|
340
|
+
const curve = new CubicBezierCurve(new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint));
|
|
341
|
+
if (isRelative) {
|
|
342
|
+
curve.startControlPoint.x += curve.startPoint.x + (Number(data[1]) - curve.startControlPoint.x); // * 0.666;
|
|
343
|
+
curve.startControlPoint.y += curve.startPoint.y + (Number(data[2]) - curve.startControlPoint.y); // * 0.666;
|
|
344
|
+
curve.endPoint.x += Number(data[3]);
|
|
345
|
+
curve.endPoint.y += Number(data[4]);
|
|
346
|
+
curve.endControlPoint.x = curve.startControlPoint.x;
|
|
347
|
+
curve.endControlPoint.y = curve.startControlPoint.y;
|
|
348
|
+
} else {
|
|
349
|
+
curve.startControlPoint.x = curve.startPoint.x + (Number(data[1]) - curve.startControlPoint.x); // * 0.666;
|
|
350
|
+
curve.startControlPoint.y = curve.startPoint.y + (Number(data[2]) - curve.startControlPoint.y); // * 0.666;
|
|
351
|
+
curve.endPoint.x = Number(data[3]);
|
|
352
|
+
curve.endPoint.y = Number(data[4]);
|
|
353
|
+
curve.endControlPoint.x = curve.startControlPoint.x;
|
|
354
|
+
curve.endControlPoint.y = curve.startControlPoint.y;
|
|
355
|
+
}
|
|
356
|
+
// var lastQuadraticControlPoint = { x: Number(data[1]), y: Number(data[2]) };
|
|
357
|
+
const lastQuadraticControlPoint = { x: curve.endControlPoint.x, y: curve.endControlPoint.y };
|
|
358
|
+
// Convert quadratic curve to cubic curve
|
|
359
|
+
curve.startControlPoint.x = curve.startPoint.x + (curve.startControlPoint.x - curve.startPoint.x) * 0.666;
|
|
360
|
+
curve.startControlPoint.y = curve.startPoint.y + (curve.startControlPoint.y - curve.startPoint.y) * 0.666;
|
|
361
|
+
curve.endControlPoint.x = curve.endPoint.x + (curve.endControlPoint.x - curve.endPoint.x) * 0.666;
|
|
362
|
+
curve.endControlPoint.y = curve.endPoint.y + (curve.endControlPoint.y - curve.endPoint.y) * 0.666;
|
|
363
|
+
|
|
364
|
+
result.push(curve);
|
|
365
|
+
lastPoint.x = curve.endPoint.x;
|
|
366
|
+
lastPoint.y = curve.endPoint.y;
|
|
367
|
+
lastControlPoint.x = curve.endControlPoint.x;
|
|
368
|
+
lastControlPoint.y = curve.endControlPoint.y;
|
|
369
|
+
if (isNaN(firstPoint.x)) {
|
|
370
|
+
firstPoint.x = curve.startPoint.x;
|
|
371
|
+
firstPoint.y = curve.startPoint.y;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// 'T' or 't' command may follow
|
|
375
|
+
if (data.length >= 8) {
|
|
376
|
+
// TODO: think about this type cast!
|
|
377
|
+
const subData: SVGPathShorthandQuadraticCurveToCommand = data.slice(5) as SVGPathShorthandQuadraticCurveToCommand;
|
|
378
|
+
// var lastQuadraticControlPoint = { x: Number(data[1]), y: Number(data[2]) };
|
|
379
|
+
if (subData[0] === "T") {
|
|
380
|
+
// _handleShorthandQuadraticCurveTo(subData, false, firstPoint, lastPoint, lastControlPoint, result);
|
|
381
|
+
_handleShorthandQuadraticCurveTo(subData, false, firstPoint, lastPoint, lastQuadraticControlPoint, result);
|
|
382
|
+
} else if (subData[0] === "t") {
|
|
383
|
+
// _handleShorthandQuadraticCurveTo(subData, true, firstPoint, lastPoint, lastControlPoint, result);
|
|
384
|
+
_handleShorthandQuadraticCurveTo(subData, true, firstPoint, lastPoint, lastQuadraticControlPoint, result);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// This is a helper function and works only in combination with Quadratic Bézier Curves
|
|
390
|
+
// T|t x y
|
|
391
|
+
const _handleShorthandQuadraticCurveTo = (
|
|
392
|
+
data: SVGPathShorthandQuadraticCurveToCommand,
|
|
393
|
+
isRelative: boolean,
|
|
394
|
+
firstPoint: XYCoords,
|
|
395
|
+
lastPoint: XYCoords,
|
|
396
|
+
lastControlPoint: XYCoords,
|
|
397
|
+
result: Array<Line | CubicBezierCurve>
|
|
398
|
+
) => {
|
|
399
|
+
// console.log("Handle SHORTHANDQUADRATICCURVETO", data);
|
|
400
|
+
if (data.length < 3) {
|
|
401
|
+
throw "Unsufficient params for SHORTHANDQUADRATICCURVETO";
|
|
402
|
+
}
|
|
403
|
+
const curve = new CubicBezierCurve(new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint));
|
|
404
|
+
if (isRelative) {
|
|
405
|
+
curve.endPoint.x += Number(data[1]);
|
|
406
|
+
curve.endPoint.y += Number(data[2]);
|
|
407
|
+
curve.startControlPoint.x += curve.startPoint.x - (lastControlPoint.x - lastPoint.x);
|
|
408
|
+
curve.startControlPoint.y += curve.startPoint.y - (lastControlPoint.y - lastPoint.y);
|
|
409
|
+
} else {
|
|
410
|
+
curve.endPoint.x = Number(data[1]);
|
|
411
|
+
curve.endPoint.y = Number(data[2]);
|
|
412
|
+
curve.startControlPoint.x = curve.startPoint.x - (lastControlPoint.x - lastPoint.x);
|
|
413
|
+
curve.startControlPoint.y = curve.startPoint.y - (lastControlPoint.y - lastPoint.y);
|
|
414
|
+
}
|
|
415
|
+
// First handle as symmetrical cubic curve
|
|
416
|
+
curve.endControlPoint.x = curve.startControlPoint.x;
|
|
417
|
+
curve.endControlPoint.y = curve.startControlPoint.y;
|
|
418
|
+
|
|
419
|
+
// Convert quadratic curve to cubic curve
|
|
420
|
+
curve.startControlPoint.x = curve.startPoint.x + (curve.startControlPoint.x - curve.startPoint.x) * 0.666;
|
|
421
|
+
curve.startControlPoint.y = curve.startPoint.y + (curve.startControlPoint.y - curve.startPoint.y) * 0.666;
|
|
422
|
+
curve.endControlPoint.x = curve.endPoint.x + (curve.endControlPoint.x - curve.endPoint.x) * 0.666;
|
|
423
|
+
curve.endControlPoint.y = curve.endPoint.y + (curve.endControlPoint.y - curve.endPoint.y) * 0.666;
|
|
424
|
+
|
|
425
|
+
// console.log("ADDING T CURVE", curve);
|
|
426
|
+
result.push(curve);
|
|
427
|
+
lastPoint.x = curve.endPoint.x;
|
|
428
|
+
lastPoint.y = curve.endPoint.y;
|
|
429
|
+
lastControlPoint.x = curve.endControlPoint.x;
|
|
430
|
+
lastControlPoint.y = curve.endControlPoint.y;
|
|
431
|
+
if (isNaN(firstPoint.x)) {
|
|
432
|
+
firstPoint.x = curve.startPoint.x;
|
|
433
|
+
firstPoint.y = curve.startPoint.y;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// The S|s x2 y2 x y
|
|
438
|
+
const _handleShorthandCubicCurveTo = (
|
|
439
|
+
data: SVGPathShorthandCubicCurveToCommand,
|
|
440
|
+
isRelative: boolean,
|
|
441
|
+
firstPoint: XYCoords,
|
|
442
|
+
lastPoint: XYCoords,
|
|
443
|
+
lastControlPoint: XYCoords,
|
|
444
|
+
result: Array<Line | CubicBezierCurve>
|
|
445
|
+
) => {
|
|
446
|
+
// console.log("Handle SHORTHANDCUBICBEZIERTO", data);
|
|
447
|
+
if (data.length < 5) {
|
|
448
|
+
throw "Unsufficient params for SHORTHANDCUBICBEZIERTO";
|
|
449
|
+
}
|
|
450
|
+
const curve = new CubicBezierCurve(new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint), new Vertex(lastPoint));
|
|
451
|
+
|
|
452
|
+
if (isRelative) {
|
|
453
|
+
curve.startControlPoint.x = lastPoint.x - (lastControlPoint.x - lastPoint.x);
|
|
454
|
+
curve.startControlPoint.y = lastPoint.y - (lastControlPoint.y - lastPoint.y);
|
|
455
|
+
curve.endControlPoint.x += Number(data[1]);
|
|
456
|
+
curve.endControlPoint.y += Number(data[2]);
|
|
457
|
+
curve.endPoint.x += Number(data[3]);
|
|
458
|
+
curve.endPoint.y += Number(data[4]);
|
|
459
|
+
} else {
|
|
460
|
+
curve.startControlPoint.x = lastPoint.x - (lastControlPoint.x - lastPoint.x);
|
|
461
|
+
curve.startControlPoint.y = lastPoint.y - (lastControlPoint.y - lastPoint.y);
|
|
462
|
+
curve.endControlPoint.x = Number(data[1]);
|
|
463
|
+
curve.endControlPoint.y = Number(data[2]);
|
|
464
|
+
curve.endPoint.x = Number(data[3]);
|
|
465
|
+
curve.endPoint.y = Number(data[4]);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
result.push(curve);
|
|
469
|
+
|
|
470
|
+
lastPoint.x = curve.endPoint.x;
|
|
471
|
+
lastPoint.y = curve.endPoint.y;
|
|
472
|
+
lastControlPoint.x = curve.endControlPoint.x;
|
|
473
|
+
lastControlPoint.y = curve.endControlPoint.y;
|
|
474
|
+
if (isNaN(firstPoint.x)) {
|
|
475
|
+
firstPoint.x = curve.startPoint.x;
|
|
476
|
+
firstPoint.y = curve.startPoint.y;
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// EllipticalArcTo: A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y
|
|
481
|
+
const _handleArcTo = (
|
|
482
|
+
data: SVGPathArcToCommand,
|
|
483
|
+
isRelative: boolean,
|
|
484
|
+
firstPoint: XYCoords,
|
|
485
|
+
lastPoint: XYCoords,
|
|
486
|
+
lastControlPoint: XYCoords,
|
|
487
|
+
result: Array<Line | CubicBezierCurve>
|
|
488
|
+
) => {
|
|
489
|
+
// console.log("Handle ARCTO", data);
|
|
490
|
+
if (data.length < 8) {
|
|
491
|
+
throw "Unsufficient params for ARCTO";
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const arcEndPoint = { x: Number(data[6]), y: Number(data[7]) };
|
|
495
|
+
if (isRelative) {
|
|
496
|
+
arcEndPoint.x += lastPoint.x;
|
|
497
|
+
arcEndPoint.y += lastPoint.y;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// console.log(
|
|
501
|
+
// "lastPoint.x",
|
|
502
|
+
// lastPoint.x, // x1
|
|
503
|
+
// "lastPoint.y",
|
|
504
|
+
// lastPoint.y, // y1
|
|
505
|
+
// "data[1]",
|
|
506
|
+
// Number(data[1]), // rx
|
|
507
|
+
// "data[2]",
|
|
508
|
+
// Number(data[2]), // ry
|
|
509
|
+
// "data[3]",
|
|
510
|
+
// Number(data[3]), // phi: number,
|
|
511
|
+
// "data[4]",
|
|
512
|
+
// Boolean(data[4]), // fa: boolean,
|
|
513
|
+
// "data[5]",
|
|
514
|
+
// Boolean(data[5]), // fs: boolean,
|
|
515
|
+
// "data[6]",
|
|
516
|
+
// arcEndPoint.x, // Number(data[6]), // x2: number,
|
|
517
|
+
// "data[7]",
|
|
518
|
+
// arcEndPoint.y // Number(data[7]) // y2: number
|
|
519
|
+
// );
|
|
520
|
+
// A 5 4 0 1 1 -10 -5
|
|
521
|
+
// TODO: respect relative/absolute here
|
|
522
|
+
const ellipseSector = VEllipseSector.ellipseSectorUtils.endpointToCenterParameters(
|
|
523
|
+
lastPoint.x,
|
|
524
|
+
lastPoint.y,
|
|
525
|
+
Number(data[1]),
|
|
526
|
+
Number(data[2]),
|
|
527
|
+
Number(data[3]) * DEG_TO_RAD,
|
|
528
|
+
Boolean(data[4]),
|
|
529
|
+
Boolean(data[5]),
|
|
530
|
+
arcEndPoint.x,
|
|
531
|
+
arcEndPoint.y // Number(data[7]) // y2: number
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
// console.log("ellipseSector", ellipseSector);
|
|
535
|
+
const curves = ellipseSector.toCubicBezier(4); // 4 segments already seems to be a good approximation
|
|
536
|
+
for (var i = 0; i < curves.length; i++) {
|
|
537
|
+
result.push(curves[i]); // Destruct!
|
|
538
|
+
}
|
|
539
|
+
// result.push(ellipseSector.ellipse);
|
|
540
|
+
if (curves.length > 0) {
|
|
541
|
+
// console.log("curves", curves);
|
|
542
|
+
const lastCurve = curves[curves.length - 1];
|
|
543
|
+
lastPoint.x = lastCurve.endPoint.x;
|
|
544
|
+
lastPoint.y = lastCurve.endPoint.y;
|
|
545
|
+
lastControlPoint.x = lastCurve.endControlPoint.x;
|
|
546
|
+
lastControlPoint.y = lastCurve.endControlPoint.y;
|
|
547
|
+
if (isNaN(firstPoint.x)) {
|
|
548
|
+
firstPoint.x = curves[0].startPoint.x;
|
|
549
|
+
firstPoint.y = curves[0].startPoint.y;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// TODO: track first/last/control point
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
const _handleClosePath = (
|
|
557
|
+
_data: SVGPathCloseCommand,
|
|
558
|
+
_isRelative: boolean,
|
|
559
|
+
firstPoint: XYCoords,
|
|
560
|
+
lastPoint: XYCoords,
|
|
561
|
+
lastControlPoint: XYCoords,
|
|
562
|
+
result: Array<Line | CubicBezierCurve>
|
|
563
|
+
) => {
|
|
564
|
+
// console.log("Handle CLOSEPATH", "lastPoint", lastPoint, "firstPoint", firstPoint);
|
|
565
|
+
const line = new Line(new Vertex(lastPoint), new Vertex(firstPoint));
|
|
566
|
+
result.push(line);
|
|
567
|
+
|
|
568
|
+
lastPoint.x = line.b.x;
|
|
569
|
+
lastPoint.y = line.b.y;
|
|
570
|
+
lastControlPoint.x = line.b.x;
|
|
571
|
+
lastControlPoint.y = line.b.y;
|
|
572
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split SVG path data `d` strings.
|
|
3
|
+
*
|
|
4
|
+
* As this helper function does not detect all possible path data strings it should cover the most daily use-cases.
|
|
5
|
+
*
|
|
6
|
+
* For more insight see
|
|
7
|
+
* https://www.w3.org/TR/SVG/paths.html
|
|
8
|
+
*
|
|
9
|
+
* @author Ikaros Kappler
|
|
10
|
+
* @date 2022-11-22
|
|
11
|
+
* @modified 2022-12-21 Ported to Typescript
|
|
12
|
+
* @version 0.0.1-alpha
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { SVGPathCommand } from "./types";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @name splitSVGPathData
|
|
19
|
+
* @static
|
|
20
|
+
* @param {string} dataString - The SVG path data to split. This should be some string
|
|
21
|
+
**/
|
|
22
|
+
export const splitSVGPathData = (dataString: string): Array<SVGPathCommand> | null => {
|
|
23
|
+
// Source
|
|
24
|
+
// https://javascript.plainenglish.io/june-3-parsing-and-validating-svg-paths-with-regex-7bd0e245115
|
|
25
|
+
const validCommand =
|
|
26
|
+
/([ml](\s?-?((\d+(\.\d+)?)|(\.\d+)))[,\s]?(-?((\d+(\.\d+)?)|(\.\d+))))|([hv](\s?-?((\d+(\.\d+)?)|(\.\d+))))|(c(\s?-?((\d+(\.\d+)?)|(\.\d+)))([,\s]?(-?((\d+(\.\d+)?)|(\.\d+)))){5})|(q(\s?-?((\d+(\.\d+)?)|(\.\d+)))([,\s]?(-?((\d+(\.\d+)?)|(\.\d+)))){3}(\s?t?(\s?-?((\d+(\.\d+)?)|(\.\d+)))[,\s]?(-?((\d+(\.\d+)?)|(\.\d+))))*)|(a(\s?-?((\d+(\.\d+)?)|(\.\d+)))([,\s]?(-?((\d+(\.\d+)?)|(\.\d+)))){2}[,\s]?[01][,\s]+[01][,\s]+([,\s]?(-?((\d+(\.\d+)?)|(\.\d+)))){2})|(s(\s?-?((\d+(\.\d+)?)|(\.\d+)))([,\s]?(-?((\d+(\.\d+)?)|(\.\d+)))){3})|z/gi;
|
|
27
|
+
|
|
28
|
+
const dataElements = dataString.match(validCommand);
|
|
29
|
+
// console.log("Splitted: ", dataElements);
|
|
30
|
+
if (!dataElements) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const result: Array<SVGPathCommand> = [];
|
|
35
|
+
|
|
36
|
+
var i = 0;
|
|
37
|
+
while (i < dataElements.length) {
|
|
38
|
+
const token = dataElements[i];
|
|
39
|
+
// Ctwheels comment was really useful here
|
|
40
|
+
// https://stackoverflow.com/questions/47801455/what-is-the-regex-that-properly-splits-svg-d-attributes-into-tokens
|
|
41
|
+
const dataRaw = token.match(/-?(?:\d*\.)?\d+|[a-z]/gi);
|
|
42
|
+
if (dataRaw) {
|
|
43
|
+
result.push(dataRaw as SVGPathCommand);
|
|
44
|
+
} else {
|
|
45
|
+
// throw Error?
|
|
46
|
+
}
|
|
47
|
+
i++;
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}; // END splitSVGPathData
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defining some basic SVG command types.
|
|
3
|
+
*
|
|
4
|
+
* As these types do not define all very possible path data strings they should cover the most daily use-cases.
|
|
5
|
+
*
|
|
6
|
+
* For more insight see
|
|
7
|
+
* https://www.w3.org/TR/SVG/paths.html
|
|
8
|
+
*
|
|
9
|
+
*
|
|
10
|
+
* @author Ikaros Kappler
|
|
11
|
+
* @date 2022-12-21 (winter solstice night – yes the days & nights are dark and I have nothing else to do)
|
|
12
|
+
* @version 0.0.1-alpha
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export type NumericString = `${number}`;
|
|
16
|
+
export type BooleanString = "0" | "1" | `${boolean}`;
|
|
17
|
+
|
|
18
|
+
// Example: 'M', -10, -7.5,
|
|
19
|
+
export type SVGPathMoveToCommand = ["M" | "m", NumericString, NumericString];
|
|
20
|
+
// Example: 'L', 0, -10,
|
|
21
|
+
export type SVGPathLineToCommand = ["L" | "l", NumericString, NumericString];
|
|
22
|
+
// Example: 'V', -10,
|
|
23
|
+
export type SVGPathVerticalLineToCommand = ["V" | "v", NumericString];
|
|
24
|
+
// Example: 'H', 10,
|
|
25
|
+
export type SVGPathHorizontalLineToCommand = ["H" | "h", NumericString];
|
|
26
|
+
// Example: 'Q', 5, 5, 0, 0,
|
|
27
|
+
// Example2: 'Q', 5, 5, 0, 0, 'T', -10, 0,
|
|
28
|
+
export type SVGPathQuadraticCurveToCommand =
|
|
29
|
+
| ["Q" | "q", NumericString, NumericString, NumericString, NumericString]
|
|
30
|
+
| ["Q" | "q", NumericString, NumericString, NumericString, NumericString, "T" | "t", NumericString, NumericString];
|
|
31
|
+
// Example: 'C', -5, -15, 10, -15, 5, -10,
|
|
32
|
+
export type SVGPathCubicCurveToCommand = [
|
|
33
|
+
"C" | "c",
|
|
34
|
+
NumericString,
|
|
35
|
+
NumericString,
|
|
36
|
+
NumericString,
|
|
37
|
+
NumericString,
|
|
38
|
+
NumericString,
|
|
39
|
+
NumericString
|
|
40
|
+
];
|
|
41
|
+
// Example: 'S', 15, 0, 10, 0,
|
|
42
|
+
export type SVGPathShorthandCubicCurveToCommand = ["S" | "s", NumericString, NumericString, NumericString, NumericString];
|
|
43
|
+
// Example: 'A', 5, 4, 0, 1, 1, -10, -5,
|
|
44
|
+
export type SVGPathArcToCommand = [
|
|
45
|
+
"A" | "a",
|
|
46
|
+
NumericString,
|
|
47
|
+
NumericString,
|
|
48
|
+
NumericString,
|
|
49
|
+
BooleanString,
|
|
50
|
+
BooleanString,
|
|
51
|
+
NumericString,
|
|
52
|
+
NumericString
|
|
53
|
+
];
|
|
54
|
+
// Example: 'Z'
|
|
55
|
+
export type SVGPathCloseCommand = ["Z" | "z"];
|
|
56
|
+
|
|
57
|
+
// NOTE: this is not a standalone command. It is only valid in combination with the Q|q command!
|
|
58
|
+
// Example2: 'T', -10, 0,
|
|
59
|
+
export type SVGPathShorthandQuadraticCurveToCommand = ["T" | "t", NumericString, NumericString];
|
|
60
|
+
|
|
61
|
+
export type SVGPathCommand =
|
|
62
|
+
| SVGPathMoveToCommand
|
|
63
|
+
| SVGPathLineToCommand
|
|
64
|
+
| SVGPathVerticalLineToCommand
|
|
65
|
+
| SVGPathHorizontalLineToCommand
|
|
66
|
+
| SVGPathQuadraticCurveToCommand
|
|
67
|
+
| SVGPathCubicCurveToCommand
|
|
68
|
+
| SVGPathShorthandCubicCurveToCommand
|
|
69
|
+
| SVGPathArcToCommand
|
|
70
|
+
| SVGPathCloseCommand;
|