svg-path-commander 2.0.3 → 2.0.5
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/cypress/e2e/svg-path-commander.spec.ts +49 -6
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.d.ts +6 -5
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +551 -322
- package/dist/svg-path-commander.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +2 -0
- package/src/interface.ts +5 -5
- package/src/util/isPathArray.ts +7 -2
- package/src/util/isValidPath.ts +1 -1
- package/src/util/shapeParams.ts +16 -0
- package/src/util/shapeToPath.ts +19 -147
- package/src/util/shapeToPathArray.ts +179 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "svg-path-commander",
|
|
3
3
|
"author": "thednp",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "2.0.
|
|
5
|
+
"version": "2.0.5",
|
|
6
6
|
"description": "Modern TypeScript tools for SVG",
|
|
7
7
|
"source": "./src/index.ts",
|
|
8
8
|
"main": "./dist/svg-path-commander.js",
|
|
@@ -73,6 +73,6 @@
|
|
|
73
73
|
"vite": "^4.2.0"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@thednp/dommatrix": "^2.0.
|
|
76
|
+
"@thednp/dommatrix": "^2.0.4"
|
|
77
77
|
}
|
|
78
78
|
}
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,7 @@ import isAbsoluteArray from './util/isAbsoluteArray';
|
|
|
29
29
|
import isRelativeArray from './util/isRelativeArray';
|
|
30
30
|
import isCurveArray from './util/isCurveArray';
|
|
31
31
|
import isNormalizedArray from './util/isNormalizedArray';
|
|
32
|
+
import shapeToPathArray from './util/shapeToPathArray';
|
|
32
33
|
import shapeToPath from './util/shapeToPath';
|
|
33
34
|
|
|
34
35
|
import roundPath from './process/roundPath';
|
|
@@ -79,6 +80,7 @@ class SVGPathCommander {
|
|
|
79
80
|
public static isCurveArray = isCurveArray;
|
|
80
81
|
public static isNormalizedArray = isNormalizedArray;
|
|
81
82
|
public static shapeToPath = shapeToPath;
|
|
83
|
+
public static shapeToPathArray = shapeToPathArray;
|
|
82
84
|
public static parsePathString = parsePathString;
|
|
83
85
|
public static roundPath = roundPath;
|
|
84
86
|
public static splitPath = splitPath;
|
package/src/interface.ts
CHANGED
|
@@ -42,8 +42,8 @@ export interface EllipseAttr {
|
|
|
42
42
|
cx: number;
|
|
43
43
|
cy: number;
|
|
44
44
|
rx: number;
|
|
45
|
-
ry
|
|
46
|
-
[key: string]: string | number;
|
|
45
|
+
ry?: number;
|
|
46
|
+
[key: string]: string | number | undefined;
|
|
47
47
|
}
|
|
48
48
|
export interface RectAttr {
|
|
49
49
|
type: 'rect';
|
|
@@ -51,9 +51,9 @@ export interface RectAttr {
|
|
|
51
51
|
height: number;
|
|
52
52
|
x: number;
|
|
53
53
|
y: number;
|
|
54
|
-
rx
|
|
55
|
-
ry
|
|
56
|
-
[key: string]: string | number;
|
|
54
|
+
rx?: number;
|
|
55
|
+
ry?: number;
|
|
56
|
+
[key: string]: string | number | undefined;
|
|
57
57
|
}
|
|
58
58
|
export interface GlyphAttr {
|
|
59
59
|
type: 'glyph';
|
package/src/util/isPathArray.ts
CHANGED
|
@@ -12,8 +12,13 @@ const isPathArray = (path: unknown): path is PathArray => {
|
|
|
12
12
|
Array.isArray(path) &&
|
|
13
13
|
path.every((seg: PathSegment) => {
|
|
14
14
|
const lk = seg[0].toLowerCase() as RelativeCommand;
|
|
15
|
-
return
|
|
16
|
-
|
|
15
|
+
return (
|
|
16
|
+
paramsCount[lk] === seg.length - 1 &&
|
|
17
|
+
'achlmqstvz'.includes(lk) &&
|
|
18
|
+
(seg.slice(1) as unknown[]).every(Number.isFinite)
|
|
19
|
+
);
|
|
20
|
+
}) &&
|
|
21
|
+
path.length > 0
|
|
17
22
|
);
|
|
18
23
|
};
|
|
19
24
|
export default isPathArray;
|
package/src/util/isValidPath.ts
CHANGED
|
@@ -10,7 +10,7 @@ import PathParser from '../parser/pathParser';
|
|
|
10
10
|
* @returns the path string validity
|
|
11
11
|
*/
|
|
12
12
|
const isValidPath = (pathString: string) => {
|
|
13
|
-
if (typeof pathString !== 'string') {
|
|
13
|
+
if (typeof pathString !== 'string' || !pathString.length) {
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ShapeParams } from '../interface';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supported shapes and their specific parameters.
|
|
5
|
+
*/
|
|
6
|
+
const shapeParams: ShapeParams = {
|
|
7
|
+
line: ['x1', 'y1', 'x2', 'y2'],
|
|
8
|
+
circle: ['cx', 'cy', 'r'],
|
|
9
|
+
ellipse: ['cx', 'cy', 'rx', 'ry'],
|
|
10
|
+
rect: ['width', 'height', 'x', 'y', 'rx', 'ry'],
|
|
11
|
+
polygon: ['points'],
|
|
12
|
+
polyline: ['points'],
|
|
13
|
+
glyph: ['d'],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default shapeParams;
|
package/src/util/shapeToPath.ts
CHANGED
|
@@ -1,130 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { ShapeParams } from '../interface';
|
|
2
|
+
import type { ShapeOps, ShapeTypes } from '../types';
|
|
3
3
|
import pathToString from '../convert/pathToString';
|
|
4
4
|
import defaultOptions from '../options/options';
|
|
5
5
|
import error from '../parser/error';
|
|
6
6
|
import isValidPath from './isValidPath';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* Supported shapes and their specific parameters.
|
|
10
|
-
*/
|
|
11
|
-
const shapeParams: ShapeParams = {
|
|
12
|
-
line: ['x1', 'y1', 'x2', 'y2'],
|
|
13
|
-
circle: ['cx', 'cy', 'r'],
|
|
14
|
-
ellipse: ['cx', 'cy', 'rx', 'ry'],
|
|
15
|
-
rect: ['width', 'height', 'x', 'y', 'rx', 'ry'],
|
|
16
|
-
polygon: ['points'],
|
|
17
|
-
polyline: ['points'],
|
|
18
|
-
glyph: ['d'],
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Returns a new `pathArray` from line attributes.
|
|
23
|
-
*
|
|
24
|
-
* @param attr shape configuration
|
|
25
|
-
* @returns a new line `pathArray`
|
|
26
|
-
*/
|
|
27
|
-
export const getLinePath = (attr: LineAttr): PathArray => {
|
|
28
|
-
const { x1, y1, x2, y2 } = attr;
|
|
29
|
-
return [
|
|
30
|
-
['M', x1, y1],
|
|
31
|
-
['L', x2, y2],
|
|
32
|
-
];
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Returns a new `pathArray` like from polyline/polygon attributes.
|
|
37
|
-
*
|
|
38
|
-
* @param attr shape configuration
|
|
39
|
-
* @return a new polygon/polyline `pathArray`
|
|
40
|
-
*/
|
|
41
|
-
export const getPolyPath = (attr: PolyAttr): PathArray => {
|
|
42
|
-
const pathArray = [] as PathSegment[];
|
|
43
|
-
const points = (attr.points || '')
|
|
44
|
-
.trim()
|
|
45
|
-
.split(/[\s|,]/)
|
|
46
|
-
.map(Number);
|
|
47
|
-
|
|
48
|
-
let index = 0;
|
|
49
|
-
while (index < points.length) {
|
|
50
|
-
pathArray.push([index ? 'L' : 'M', points[index], points[index + 1]]);
|
|
51
|
-
index += 2;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return (attr.type === 'polygon' ? [...pathArray, ['z']] : pathArray) as PathArray;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Returns a new `pathArray` from circle attributes.
|
|
59
|
-
*
|
|
60
|
-
* @param attr shape configuration
|
|
61
|
-
* @return a circle `pathArray`
|
|
62
|
-
*/
|
|
63
|
-
export const getCirclePath = (attr: CircleAttr): PathArray => {
|
|
64
|
-
const { cx, cy, r } = attr;
|
|
65
|
-
|
|
66
|
-
return [
|
|
67
|
-
['M', cx - r, cy],
|
|
68
|
-
['a', r, r, 0, 1, 0, 2 * r, 0],
|
|
69
|
-
['a', r, r, 0, 1, 0, -2 * r, 0],
|
|
70
|
-
];
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Returns a new `pathArray` from ellipse attributes.
|
|
75
|
-
*
|
|
76
|
-
* @param attr shape configuration
|
|
77
|
-
* @return an ellipse `pathArray`
|
|
78
|
-
*/
|
|
79
|
-
export const getEllipsePath = (attr: EllipseAttr): PathArray => {
|
|
80
|
-
const { cx, cy, rx, ry } = attr;
|
|
81
|
-
|
|
82
|
-
return [
|
|
83
|
-
['M', cx - rx, cy],
|
|
84
|
-
['a', rx, ry, 0, 1, 0, 2 * rx, 0],
|
|
85
|
-
['a', rx, ry, 0, 1, 0, -2 * rx, 0],
|
|
86
|
-
];
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Returns a new `pathArray` like from rect attributes.
|
|
91
|
-
*
|
|
92
|
-
* @param attr object with properties above
|
|
93
|
-
* @return a new `pathArray` from `<rect>` attributes
|
|
94
|
-
*/
|
|
95
|
-
export const getRectanglePath = (attr: RectAttr): PathArray => {
|
|
96
|
-
const x = +attr.x || 0;
|
|
97
|
-
const y = +attr.y || 0;
|
|
98
|
-
const w = +attr.width;
|
|
99
|
-
const h = +attr.height;
|
|
100
|
-
let rx = +attr.rx;
|
|
101
|
-
let ry = +attr.ry;
|
|
102
|
-
|
|
103
|
-
// Validity checks from http://www.w3.org/TR/SVG/shapes.html#RectElement:
|
|
104
|
-
if (rx || ry) {
|
|
105
|
-
rx = !rx ? ry : rx;
|
|
106
|
-
ry = !ry ? rx : ry;
|
|
107
|
-
|
|
108
|
-
/* istanbul ignore else */
|
|
109
|
-
if (rx * 2 > w) rx -= (rx * 2 - w) / 2;
|
|
110
|
-
/* istanbul ignore else */
|
|
111
|
-
if (ry * 2 > h) ry -= (ry * 2 - h) / 2;
|
|
112
|
-
|
|
113
|
-
return [
|
|
114
|
-
['M', x + rx, y],
|
|
115
|
-
['h', w - rx * 2],
|
|
116
|
-
['s', rx, 0, rx, ry],
|
|
117
|
-
['v', h - ry * 2],
|
|
118
|
-
['s', 0, ry, -rx, ry],
|
|
119
|
-
['h', -w + rx * 2],
|
|
120
|
-
['s', -rx, 0, -rx, -ry],
|
|
121
|
-
['v', -h + ry * 2],
|
|
122
|
-
['s', 0, -ry, rx, -ry],
|
|
123
|
-
];
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return [['M', x, y], ['h', w], ['v', h], ['H', x], ['Z']];
|
|
127
|
-
};
|
|
7
|
+
import shapeToPathArray from './shapeToPathArray';
|
|
8
|
+
import shapeParams from './shapeParams';
|
|
128
9
|
|
|
129
10
|
/**
|
|
130
11
|
* Returns a new `<path>` element created from attributes of a `<line>`, `<polyline>`,
|
|
@@ -133,7 +14,7 @@ export const getRectanglePath = (attr: RectAttr): PathArray => {
|
|
|
133
14
|
* `document` browser page, if you want to use in server-side using `jsdom`, you can
|
|
134
15
|
* pass the `jsdom` `document` to `ownDocument`.
|
|
135
16
|
*
|
|
136
|
-
* It can also work with an options object,
|
|
17
|
+
* It can also work with an options object, see the type below
|
|
137
18
|
*
|
|
138
19
|
* @see ShapeOps
|
|
139
20
|
*
|
|
@@ -153,21 +34,25 @@ const shapeToPath = (
|
|
|
153
34
|
const doc = ownerDocument || document;
|
|
154
35
|
const win = doc.defaultView || /* istanbul ignore next */ window;
|
|
155
36
|
const supportedShapes = Object.keys(shapeParams) as (keyof ShapeParams)[];
|
|
156
|
-
const
|
|
157
|
-
const tagName =
|
|
37
|
+
const targetIsElement = element instanceof win.SVGElement;
|
|
38
|
+
const tagName = targetIsElement ? element.tagName : null;
|
|
158
39
|
|
|
159
|
-
if (tagName
|
|
160
|
-
|
|
161
|
-
}
|
|
40
|
+
if (tagName === 'path') throw TypeError(`${error}: "${tagName}" is already SVGPathElement`);
|
|
41
|
+
if (tagName && supportedShapes.every(s => tagName !== s)) throw TypeError(`${error}: "${tagName}" is not SVGElement`);
|
|
162
42
|
|
|
163
43
|
const path = doc.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
164
|
-
const type = (
|
|
44
|
+
const type = (targetIsElement ? tagName : element.type) as ShapeOps['type'];
|
|
165
45
|
const shapeAttrs = shapeParams[type] as string[];
|
|
166
46
|
const config = { type } as Record<string, string>;
|
|
167
47
|
|
|
168
|
-
|
|
48
|
+
// set d
|
|
49
|
+
const round = defaultOptions.round as number;
|
|
50
|
+
const pathArray = shapeToPathArray(element, doc);
|
|
51
|
+
const description = pathArray && pathArray.length ? pathToString(pathArray, round) : '';
|
|
52
|
+
|
|
53
|
+
if (targetIsElement) {
|
|
169
54
|
shapeAttrs.forEach(p => {
|
|
170
|
-
|
|
55
|
+
config[p] = element.getAttribute(p) as string;
|
|
171
56
|
});
|
|
172
57
|
// set no-specific shape attributes: fill, stroke, etc
|
|
173
58
|
Object.values(element.attributes).forEach(({ name, value }) => {
|
|
@@ -186,24 +71,10 @@ const shapeToPath = (
|
|
|
186
71
|
});
|
|
187
72
|
}
|
|
188
73
|
|
|
189
|
-
// set d
|
|
190
|
-
let description = '';
|
|
191
|
-
const round = defaultOptions.round as number;
|
|
192
|
-
|
|
193
|
-
/* istanbul ignore else */
|
|
194
|
-
if (type === 'circle') description = pathToString(getCirclePath(config as unknown as CircleAttr), round);
|
|
195
|
-
else if (type === 'ellipse') description = pathToString(getEllipsePath(config as unknown as EllipseAttr), round);
|
|
196
|
-
else if (['polyline', 'polygon'].includes(type))
|
|
197
|
-
description = pathToString(getPolyPath(config as unknown as PolyAttr), round);
|
|
198
|
-
else if (type === 'rect') description = pathToString(getRectanglePath(config as unknown as RectAttr), round);
|
|
199
|
-
else if (type === 'line') description = pathToString(getLinePath(config as unknown as LineAttr), round);
|
|
200
|
-
else if (type === 'glyph')
|
|
201
|
-
description = elementIsElement ? (element.getAttribute('d') as string) : (element as GlyphAttr).d;
|
|
202
|
-
|
|
203
74
|
// replace target element
|
|
204
75
|
if (isValidPath(description)) {
|
|
205
76
|
path.setAttribute('d', description);
|
|
206
|
-
if (replace &&
|
|
77
|
+
if (replace && targetIsElement) {
|
|
207
78
|
element.before(path, element);
|
|
208
79
|
element.remove();
|
|
209
80
|
}
|
|
@@ -211,4 +82,5 @@ const shapeToPath = (
|
|
|
211
82
|
}
|
|
212
83
|
return false;
|
|
213
84
|
};
|
|
85
|
+
|
|
214
86
|
export default shapeToPath;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { CircleAttr, EllipseAttr, GlyphAttr, LineAttr, PolyAttr, RectAttr, ShapeParams } from '../interface';
|
|
2
|
+
import type { PathArray, PathSegment, ShapeOps, ShapeTypes } from '../types';
|
|
3
|
+
import error from '../parser/error';
|
|
4
|
+
import parsePathString from '../parser/parsePathString';
|
|
5
|
+
import shapeParams from './shapeParams';
|
|
6
|
+
import isPathArray from './isPathArray';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns a new `pathArray` from line attributes.
|
|
10
|
+
*
|
|
11
|
+
* @param attr shape configuration
|
|
12
|
+
* @returns a new line `pathArray`
|
|
13
|
+
*/
|
|
14
|
+
export const getLinePath = (attr: LineAttr): PathArray => {
|
|
15
|
+
let { x1, y1, x2, y2 } = attr;
|
|
16
|
+
[x1, y1, x2, y2] = [x1, y1, x2, y2].map(a => +a);
|
|
17
|
+
return [
|
|
18
|
+
['M', x1, y1],
|
|
19
|
+
['L', x2, y2],
|
|
20
|
+
];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns a new `pathArray` like from polyline/polygon attributes.
|
|
25
|
+
*
|
|
26
|
+
* @param attr shape configuration
|
|
27
|
+
* @return a new polygon/polyline `pathArray`
|
|
28
|
+
*/
|
|
29
|
+
export const getPolyPath = (attr: PolyAttr): PathArray => {
|
|
30
|
+
const pathArray = [] as PathSegment[];
|
|
31
|
+
const points = (attr.points || '')
|
|
32
|
+
.trim()
|
|
33
|
+
.split(/[\s|,]/)
|
|
34
|
+
.map(a => +a);
|
|
35
|
+
|
|
36
|
+
let index = 0;
|
|
37
|
+
while (index < points.length) {
|
|
38
|
+
pathArray.push([index ? 'L' : 'M', points[index], points[index + 1]]);
|
|
39
|
+
index += 2;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (attr.type === 'polygon' ? [...pathArray, ['z']] : pathArray) as PathArray;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns a new `pathArray` from circle attributes.
|
|
47
|
+
*
|
|
48
|
+
* @param attr shape configuration
|
|
49
|
+
* @return a circle `pathArray`
|
|
50
|
+
*/
|
|
51
|
+
export const getCirclePath = (attr: CircleAttr): PathArray => {
|
|
52
|
+
let { cx, cy, r } = attr;
|
|
53
|
+
[cx, cy, r] = [cx, cy, r].map(a => +a);
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
['M', cx - r, cy],
|
|
57
|
+
['a', r, r, 0, 1, 0, 2 * r, 0],
|
|
58
|
+
['a', r, r, 0, 1, 0, -2 * r, 0],
|
|
59
|
+
];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns a new `pathArray` from ellipse attributes.
|
|
64
|
+
*
|
|
65
|
+
* @param attr shape configuration
|
|
66
|
+
* @return an ellipse `pathArray`
|
|
67
|
+
*/
|
|
68
|
+
export const getEllipsePath = (attr: EllipseAttr): PathArray => {
|
|
69
|
+
let { cx, cy } = attr;
|
|
70
|
+
let rx = attr.rx || 0;
|
|
71
|
+
let ry = attr.ry || rx;
|
|
72
|
+
[cx, cy, rx, ry] = [cx, cy, rx, ry].map(a => +a);
|
|
73
|
+
|
|
74
|
+
return [
|
|
75
|
+
['M', cx - rx, cy],
|
|
76
|
+
['a', rx, ry, 0, 1, 0, 2 * rx, 0],
|
|
77
|
+
['a', rx, ry, 0, 1, 0, -2 * rx, 0],
|
|
78
|
+
];
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Returns a new `pathArray` like from rect attributes.
|
|
83
|
+
*
|
|
84
|
+
* @param attr object with properties above
|
|
85
|
+
* @return a new `pathArray` from `<rect>` attributes
|
|
86
|
+
*/
|
|
87
|
+
export const getRectanglePath = (attr: RectAttr): PathArray => {
|
|
88
|
+
const x = +attr.x || 0;
|
|
89
|
+
const y = +attr.y || 0;
|
|
90
|
+
const w = +attr.width;
|
|
91
|
+
const h = +attr.height;
|
|
92
|
+
let rx = +(attr.rx || 0);
|
|
93
|
+
let ry = +(attr.ry || rx);
|
|
94
|
+
|
|
95
|
+
// Validity checks from http://www.w3.org/TR/SVG/shapes.html#RectElement:
|
|
96
|
+
if (rx || ry) {
|
|
97
|
+
// rx = !rx ? ry : rx;
|
|
98
|
+
// ry = !ry ? rx : ry;
|
|
99
|
+
|
|
100
|
+
/* istanbul ignore else */
|
|
101
|
+
if (rx * 2 > w) rx -= (rx * 2 - w) / 2;
|
|
102
|
+
/* istanbul ignore else */
|
|
103
|
+
if (ry * 2 > h) ry -= (ry * 2 - h) / 2;
|
|
104
|
+
|
|
105
|
+
return [
|
|
106
|
+
['M', x + rx, y],
|
|
107
|
+
['h', w - rx * 2],
|
|
108
|
+
['s', rx, 0, rx, ry],
|
|
109
|
+
['v', h - ry * 2],
|
|
110
|
+
['s', 0, ry, -rx, ry],
|
|
111
|
+
['h', -w + rx * 2],
|
|
112
|
+
['s', -rx, 0, -rx, -ry],
|
|
113
|
+
['v', -h + ry * 2],
|
|
114
|
+
['s', 0, -ry, rx, -ry],
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return [['M', x, y], ['h', w], ['v', h], ['H', x], ['Z']];
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Returns a new `pathArray` created from attributes of a `<line>`, `<polyline>`,
|
|
123
|
+
* `<polygon>`, `<rect>`, `<ellipse>`, `<circle>`, <path> or `<glyph>`.
|
|
124
|
+
*
|
|
125
|
+
* The default `ownerDocument` is your current `document` browser page,
|
|
126
|
+
* if you want to use in server-side using `jsdom`, you can pass the
|
|
127
|
+
* `jsdom` `document` to `ownDocument`.
|
|
128
|
+
*
|
|
129
|
+
* It can also work with an options object, see the type below
|
|
130
|
+
*
|
|
131
|
+
* @see ShapeOps
|
|
132
|
+
*
|
|
133
|
+
* @param element target shape
|
|
134
|
+
* @param ownerDocument document for create element
|
|
135
|
+
* @return the newly created `<path>` element
|
|
136
|
+
*/
|
|
137
|
+
const shapeToPathArray = (element: ShapeTypes | ShapeOps, ownerDocument?: Document): PathArray | false => {
|
|
138
|
+
const doc = ownerDocument || document;
|
|
139
|
+
const win = doc.defaultView || /* istanbul ignore next */ window;
|
|
140
|
+
const supportedShapes = Object.keys(shapeParams) as (keyof ShapeParams)[];
|
|
141
|
+
const targetIsElement = element instanceof win.SVGElement;
|
|
142
|
+
const tagName = targetIsElement ? element.tagName : null;
|
|
143
|
+
|
|
144
|
+
if (tagName && [...supportedShapes, 'path'].every(s => tagName !== s)) {
|
|
145
|
+
throw TypeError(`${error}: "${tagName}" is not SVGElement`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const type = (targetIsElement ? tagName : element.type) as ShapeOps['type'];
|
|
149
|
+
const shapeAttrs = shapeParams[type] as string[];
|
|
150
|
+
const config = { type } as Record<string, string>;
|
|
151
|
+
|
|
152
|
+
if (targetIsElement) {
|
|
153
|
+
shapeAttrs.forEach(p => {
|
|
154
|
+
config[p] = element.getAttribute(p) as string;
|
|
155
|
+
});
|
|
156
|
+
} else {
|
|
157
|
+
Object.assign(config, element);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// set d
|
|
161
|
+
let pathArray = [] as unknown as PathArray;
|
|
162
|
+
|
|
163
|
+
/* istanbul ignore else */
|
|
164
|
+
if (type === 'circle') pathArray = getCirclePath(config as unknown as CircleAttr);
|
|
165
|
+
else if (type === 'ellipse') pathArray = getEllipsePath(config as unknown as EllipseAttr);
|
|
166
|
+
else if (['polyline', 'polygon'].includes(type)) pathArray = getPolyPath(config as unknown as PolyAttr);
|
|
167
|
+
else if (type === 'rect') pathArray = getRectanglePath(config as unknown as RectAttr);
|
|
168
|
+
else if (type === 'line') pathArray = getLinePath(config as unknown as LineAttr);
|
|
169
|
+
else if (['glyph', 'path'].includes(type)) {
|
|
170
|
+
pathArray = parsePathString(targetIsElement ? element.getAttribute('d') || '' : (element as GlyphAttr).d || '');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// replace target element
|
|
174
|
+
if (isPathArray(pathArray) && pathArray.length) {
|
|
175
|
+
return pathArray;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
};
|
|
179
|
+
export default shapeToPathArray;
|