svg-path-commander 2.0.0 → 2.0.2
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/.eslintrc.cjs +224 -0
- package/.lgtm.yml +9 -0
- package/.prettierrc.json +15 -0
- package/README.md +3 -2
- package/cypress/e2e/svg-path-commander.spec.ts +825 -0
- package/cypress/fixtures/shapeObjects.js +11 -0
- package/cypress/fixtures/shapes.js +104 -0
- package/cypress/fixtures/simpleShapes.js +75 -0
- package/cypress/plugins/esbuild-istanbul.ts +50 -0
- package/cypress/plugins/tsCompile.ts +34 -0
- package/cypress/support/commands.ts +37 -0
- package/cypress/support/e2e.ts +21 -0
- package/cypress/test.html +36 -0
- package/cypress.config.ts +29 -0
- package/dist/svg-path-commander.cjs +1 -1
- package/dist/svg-path-commander.cjs.map +1 -1
- package/dist/svg-path-commander.js +1 -1
- package/dist/svg-path-commander.js.map +1 -1
- package/dist/svg-path-commander.mjs +325 -276
- package/dist/svg-path-commander.mjs.map +1 -1
- package/dts.config.ts +15 -0
- package/package.json +8 -18
- package/tsconfig.json +28 -0
- package/vite.config.ts +38 -0
|
@@ -0,0 +1,825 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
import SVGPathCommander from '../../src/index';
|
|
4
|
+
import invalidPathValue from '../../src/parser/invalidPathValue';
|
|
5
|
+
import error from '../../src/parser/error';
|
|
6
|
+
|
|
7
|
+
import shapes from '../fixtures/shapes';
|
|
8
|
+
import simpleShapes from '../fixtures/simpleShapes';
|
|
9
|
+
import shapeObjects from '../fixtures/shapeObjects';
|
|
10
|
+
import { CurveArray, NormalArray, PathArray, ShapeTypes, ShapeOps } from '../../src/types';
|
|
11
|
+
|
|
12
|
+
describe('SVGPathCommander Class Test', () => {
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
cy.visit('cypress/test.html')
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('Test init with no parameter / empty throws error', () => {
|
|
19
|
+
try {
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
new SVGPathCommander();
|
|
22
|
+
} catch (er) {
|
|
23
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
24
|
+
expect(er).to.have.property('message', `${error}: "pathValue" is undefined`);
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
new SVGPathCommander('');
|
|
28
|
+
} catch (er) {
|
|
29
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
30
|
+
expect(er).to.have.property('message', `${error}: "pathValue" is empty`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('Test init with invalid path value throws error', () => {
|
|
35
|
+
try {
|
|
36
|
+
new SVGPathCommander('M04 36.9a23.5 23');
|
|
37
|
+
} catch (er) {
|
|
38
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
39
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} at index 1, "0" illegal number`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
new SVGPathCommander('M4 36.9efa23.5 23');
|
|
44
|
+
} catch (er) {
|
|
45
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
46
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} at index 8, "f" invalid integer exponent`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
new SVGPathCommander('M4 .ea23.5 23');
|
|
51
|
+
} catch (er) {
|
|
52
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
53
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} at index 4, "e" invalid float exponent`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
new SVGPathCommander('M4 36.9a23.5 23');
|
|
58
|
+
} catch (er) {
|
|
59
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
60
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} at index 15, "pathValue" is missing param`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
new SVGPathCommander('M2 0a2 2 0 00-2 2 12');
|
|
65
|
+
} catch (er) {
|
|
66
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
67
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} at index 20, "pathValue" is missing param`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
new SVGPathCommander('M2 0aa 2 0 00-2 2 12');
|
|
72
|
+
} catch (er) {
|
|
73
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
74
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} at index 5, "a" is not a number`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
new SVGPathCommander('M2 0a2 2 0 21-2 2 12');
|
|
79
|
+
} catch (er) {
|
|
80
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
81
|
+
expect(er).to.have.property('message', `${error}: invalid Arc flag "2", expecting 0 or 1 at index 11`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
new SVGPathCommander('M2 0a2 2 0 03-2 2 12');
|
|
86
|
+
} catch (er) {
|
|
87
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
88
|
+
expect(er).to.have.property('message', `${error}: invalid Arc flag "3", expecting 0 or 1 at index 12`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
new SVGPathCommander('2 0a2 2 0 00-2 2');
|
|
93
|
+
} catch (er) {
|
|
94
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
95
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} "2" is not a path command`);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('Test init with valid path value works', () => {
|
|
100
|
+
const rect = new SVGPathCommander(
|
|
101
|
+
`M 2 0,
|
|
102
|
+
a2,2 0 00-2 2
|
|
103
|
+
v12
|
|
104
|
+
a2 2 0 002 2
|
|
105
|
+
h12
|
|
106
|
+
a2 2 0 0 0 2-2
|
|
107
|
+
V2
|
|
108
|
+
a2 2 0 0 0-2-2
|
|
109
|
+
H2
|
|
110
|
+
z`
|
|
111
|
+
);
|
|
112
|
+
cy.log(`We also test all kinds of value separation: comma, line-break and spaces.`)
|
|
113
|
+
.wrap(rect).as('path')
|
|
114
|
+
.get('@path').its('segments').should('have.length', 10)
|
|
115
|
+
.get('@path').its('origin').should('deep.equal', [8,8,24])
|
|
116
|
+
.get('@path').its('round').should('equal', 4)
|
|
117
|
+
.get('#test-svg path').then((svg) => {
|
|
118
|
+
svg[0].setAttribute('d', rect.toString());
|
|
119
|
+
expect(svg[0].getAttribute('d')).to.equal(rect.toString())
|
|
120
|
+
})
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('Test overloaded moveTo', () => {
|
|
124
|
+
const star = new SVGPathCommander(
|
|
125
|
+
`M12.774 14.5111 8.0167 12.292 3.4918 14.9529 4.1321 9.7428 0.2031 6.2615 5.3562 5.2604 7.4528 0.4479 9.9972 5.0393 15.222 5.5463 11.6414 9.3851Z`,
|
|
126
|
+
{round: 2}
|
|
127
|
+
);
|
|
128
|
+
const star1 = new SVGPathCommander(
|
|
129
|
+
`m12.774 14.5111 -4.7573 -2.2191 -4.5249 2.6609 0.6403 -5.2101 -3.929 -3.4813 5.1531 -1.0011 2.0966 -4.8125 2.5444 4.5914 5.2248 0.507 -3.5806 3.8388z`,
|
|
130
|
+
{round: 2}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
cy.wrap(star).as('path')
|
|
134
|
+
.wrap(star1).as('path1')
|
|
135
|
+
.get('@path').its('segments').should('have.length', 11)
|
|
136
|
+
.get('@path1').its('segments').should('have.length', 11)
|
|
137
|
+
.get('path').then((svg) => {
|
|
138
|
+
svg[0].setAttribute('d', star.toString());
|
|
139
|
+
expect(svg[0].getAttribute('d')).to.equal(star.toString())
|
|
140
|
+
})
|
|
141
|
+
.wait(100)
|
|
142
|
+
.get('path').then((svg) => {
|
|
143
|
+
svg[0].setAttribute('d', star1.toString());
|
|
144
|
+
expect(svg[0].getAttribute('d')).to.equal(star1.toString())
|
|
145
|
+
})
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('Test rounding `auto`, `off`, and [0-5]', () => {
|
|
149
|
+
cy.log('**round**: auto').then(() => {
|
|
150
|
+
const rect = new SVGPathCommander('M2 0C0.8954304997175604 -8.780183295920349e-10 -1.3527075029566811e-16 0.8954304997175604 0 2C0 2 0 9.875 0 14C1.3527075029566811e-16 15.10456950028244 0.8954304997175604 16.000000000878018 2 16C8 16 10.25 16 14 16C15.104569499040734 15.999999999121982 16 15.104569499040734 16 14C16 8 16 5.75 16 2C16 0.8954305009592662 15.104569499040734 8.780185991465076e-10 14 0C8 0 5.75 0 2 0', {round: 'auto'});
|
|
151
|
+
cy.wrap(rect).as('path')
|
|
152
|
+
.get('@path').its('round').should('equal', 2)
|
|
153
|
+
.get('path').should((svg) => {
|
|
154
|
+
svg[0].setAttribute('d', rect.toString());
|
|
155
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0C0.9 0 0 0.9 0 2C0 2 0 9.88 0 14C0 15.1 0.9 16 2 16C8 16 10.25 16 14 16C15.1 16 16 15.1 16 14C16 8 16 5.75 16 2C16 0.9 15.1 0 14 0C8 0 5.75 0 2 0')
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
cy.log('**round**: auto').then(() => {
|
|
160
|
+
const rect1 = new SVGPathCommander('M7.94 7.92C7.928954 7.92 7.92 7.928954 7.92 7.94C7.92 7.94 7.92 8.01875 7.92 8.06C7.92 8.071046 7.928954 8.08 7.94 8.08C8 8.08 8.0225 8.08 8.06 8.08C8.071046 8.08 8.08 8.071046 8.08 8.06C8.08 8 8.08 7.9775 8.08 7.94C8.08 7.928954 8.071046 7.92 8.06 7.92C8 7.92 7.9775 7.92 7.94 7.92', {round: 'auto'});
|
|
161
|
+
cy.wrap(rect1).as('path1')
|
|
162
|
+
.get('@path1').its('round').should('equal', 3)
|
|
163
|
+
.get('path').should((svg) => {
|
|
164
|
+
svg[0].setAttribute('d', rect1.toString());
|
|
165
|
+
expect(svg[0].getAttribute('d')).to.equal('M7.94 7.92C7.929 7.92 7.92 7.929 7.92 7.94C7.92 7.94 7.92 8.019 7.92 8.06C7.92 8.071 7.929 8.08 7.94 8.08C8 8.08 8.023 8.08 8.06 8.08C8.071 8.08 8.08 8.071 8.08 8.06C8.08 8 8.08 7.978 8.08 7.94C8.08 7.929 8.071 7.92 8.06 7.92C8 7.92 7.978 7.92 7.94 7.92')
|
|
166
|
+
})
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
cy.log('**round**: auto').then(() => {
|
|
170
|
+
const rect2 = new SVGPathCommander('M895.02 5.12C963.38 5.12 1018.88 60.62 1018.88 128.98V895.03C1018.88 963.39 963.38 1018.89 895.02 1018.89H128.98C60.62 1018.88 5.12 963.38 5.12 895.02V128.98C5.12 60.62 60.62 5.12 128.98 5.12H895.03Z', {round: 'auto'});
|
|
171
|
+
cy.wrap(rect2).as('path2')
|
|
172
|
+
.get('@path2').its('round').should('equal', 0)
|
|
173
|
+
.get('path').should((svg) => {
|
|
174
|
+
svg[0].setAttribute('d', rect2.toString());
|
|
175
|
+
expect(svg[0].getAttribute('d')).to.equal('M895 5C963 5 1019 61 1019 129V895C1019 963 963 1019 895 1019H129C61 1019 5 963 5 895V129C5 61 61 5 129 5H895Z')
|
|
176
|
+
})
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const roundSample = 'M2 0C0.8954304997175604 -8.780183295920349e-10 -1.3527075029566811e-16 0.8954304997175604 0 2C0 2 0 9.875 0 14C1.3527075029566811e-16 15.10456950028244 0.8954304997175604 16.000000000878018 2 16C8 16 10.25 16 14 16C15.104569499040734 15.999999999121982 16 15.104569499040734 16 14C16 8 16 5.75 16 2C16 0.8954305009592662 15.104569499040734 8.780185991465076e-10 14 0C8 0 5.75 0 2 0';
|
|
180
|
+
cy.log('**round**: off').then(() => {
|
|
181
|
+
const rect3 = new SVGPathCommander(roundSample, {round: 'off'});
|
|
182
|
+
cy.wrap(rect3).as('path3')
|
|
183
|
+
.get('@path3').its('round').should('equal', 'off')
|
|
184
|
+
.get('path').should((svg) => {
|
|
185
|
+
svg[0].setAttribute('d', rect3.toString());
|
|
186
|
+
expect(svg[0].getAttribute('d')).to.equal(roundSample)
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
cy.log('**round**: 0').then(() => {
|
|
191
|
+
const rect4 = new SVGPathCommander(roundSample, {round: 0});
|
|
192
|
+
cy.wrap(rect4).as('path4')
|
|
193
|
+
.get('@path4').its('round').should('equal', 0)
|
|
194
|
+
.get('path').should((svg) => {
|
|
195
|
+
svg[0].setAttribute('d', rect4.toString());
|
|
196
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0C1 0 0 1 0 2C0 2 0 10 0 14C0 15 1 16 2 16C8 16 10 16 14 16C15 16 16 15 16 14C16 8 16 6 16 2C16 1 15 0 14 0C8 0 6 0 2 0')
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
cy.log('**round**: 5').then(() => {
|
|
201
|
+
const rect5 = new SVGPathCommander(roundSample, {round: 5});
|
|
202
|
+
cy.wrap(rect5).as('path5')
|
|
203
|
+
.get('@path5').its('round').should('equal', 5)
|
|
204
|
+
.get('path').should((svg) => {
|
|
205
|
+
svg[0].setAttribute('d', rect5.toString());
|
|
206
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0C0.89543 0 0 0.89543 0 2C0 2 0 9.875 0 14C0 15.10457 0.89543 16 2 16C8 16 10.25 16 14 16C15.10457 16 16 15.10457 16 14C16 8 16 5.75 16 2C16 0.89543 15.10457 0 14 0C8 0 5.75 0 2 0')
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('Test getBBox', () => {
|
|
212
|
+
cy.log('Using the SVGPathCommander').then(() => {
|
|
213
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z').getBBox();
|
|
214
|
+
expect(rect).to.deep.equal({cx: 8, cy: 8, cz: 24, height: 16, width: 16, x: 0, x2: 16, y: 0, y2: 16});
|
|
215
|
+
})
|
|
216
|
+
cy.log('Using the static method').then(() => {
|
|
217
|
+
expect(SVGPathCommander.getPathBBox('')).to.deep.equal({cx: 0, cy: 0, cz: 0, height: 0, width: 0, x: 0, x2: 0, y: 0, y2: 0});
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('Test getTotalLength', () => {
|
|
222
|
+
const len = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z').getTotalLength();
|
|
223
|
+
expect(Math.round(len)).to.equal(61);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('Test getPointAtLength', () => {
|
|
227
|
+
const pt = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z').getPointAtLength(25);
|
|
228
|
+
expect(pt).to.deep.equal({ x: 8.716821870196814, y: 16 });
|
|
229
|
+
|
|
230
|
+
const pt1 = new SVGPathCommander('M2 0A2 2 0 00 2 0').getPointAtLength(0);
|
|
231
|
+
expect(pt1).to.deep.equal({ x: 2, y: 0 });
|
|
232
|
+
|
|
233
|
+
const pt2 = new SVGPathCommander('M2 0A0 2 0 00 0 2').getPointAtLength(0.5);
|
|
234
|
+
expect(pt2).to.deep.equal({x: 1.6464466094067265, y: 0.35355339059327356});
|
|
235
|
+
|
|
236
|
+
const pt3 = new SVGPathCommander('M2 0A3 2 0 00 0 2').getPointAtLength(5);
|
|
237
|
+
expect(pt3).to.deep.equal({x: 0, y: 2});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('Test toAbsolute', () => {
|
|
241
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z').toAbsolute();
|
|
242
|
+
cy.get('#test-svg path').then((svg) => {
|
|
243
|
+
svg[0].setAttribute('d', rect.toString());
|
|
244
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0A2 2 0 0 0 0 2V14A2 2 0 0 0 2 16H14A2 2 0 0 0 16 14V2A2 2 0 0 0 14 0H2Z')
|
|
245
|
+
})
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('Test toRelative', () => {
|
|
249
|
+
const rect = new SVGPathCommander('M2 0A2 2 0 0 0 0 2V14A2 2 0 0 0 2 16H14A2 2 0 0 0 16 14V2A2 2 0 0 0 14 0H2Z').toRelative();
|
|
250
|
+
cy.get('#test-svg path').then((svg) => {
|
|
251
|
+
svg[0].setAttribute('d', rect.toString());
|
|
252
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-12z')
|
|
253
|
+
})
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('Test toCurve', () => {
|
|
257
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z', { round: 'off' }).toCurve();
|
|
258
|
+
cy.get('#test-svg path').then((svg) => {
|
|
259
|
+
svg[0].setAttribute('d', rect.toString());
|
|
260
|
+
expect(rect.round).to.equal('off')
|
|
261
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0C0.8954305003384135 2.0290612532945332e-16 -1.3527075021963556e-16 0.8954305003384133 0 2C0 8 0 14 0 14C1.3527075021963556e-16 15.104569499661586 0.8954305003384133 16 2 16C8 16 14 16 14 16C15.104569499661586 16 16 15.104569499661586 16 14C16 8 16 2 16 2C16 0.8954305003384135 15.104569499661586 6.763537510981778e-17 14 0C8 0 2 0 2 0C2 0 2 0 2 0')
|
|
262
|
+
})
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('Test normalize', () => {
|
|
266
|
+
const rect = new SVGPathCommander('M2 0A2 2 0 0 0 0 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2V2A2 2 0 0 0 14 0H2z').normalize();
|
|
267
|
+
cy.get('#test-svg path').then((svg) => {
|
|
268
|
+
svg[0].setAttribute('d', rect.toString());
|
|
269
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0A2 2 0 0 0 0 2L0 14A2 2 0 0 0 2 16L14 16A2 2 0 0 0 16 14L16 2A2 2 0 0 0 14 0L2 0Z')
|
|
270
|
+
})
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('Test optimize', () => {
|
|
274
|
+
const rect = new SVGPathCommander('M2 0A2 2 0 0 0 0 2L0 14A2 2 0 0 0 2 16L14 16A2 2 0 0 0 16 14L16 2A2 2 0 0 0 14 0L2 0Z').optimize();
|
|
275
|
+
cy.wrap(rect).as('path')
|
|
276
|
+
.get('#test-svg path').then((svg) => {
|
|
277
|
+
svg[0].setAttribute('d', rect.toString());
|
|
278
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0A2 2 0 0 0 0 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2V2A2 2 0 0 0 14 0H2z')
|
|
279
|
+
})
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('Test reverse single path', () => {
|
|
283
|
+
const rect = new SVGPathCommander('M2 0A2 2 0 0 0 0 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2V2A2 2 0 0 0 14 0H2z').reverse();
|
|
284
|
+
cy.get('#test-svg path').then((svg) => {
|
|
285
|
+
svg[0].setAttribute('d', rect.toString());
|
|
286
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0H14A2 2 0 0 1 16 2V14A2 2 0 0 1 14 16H2A2 2 0 0 1 0 14V2A2 2 0 0 1 2 0Z')
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const rect1 = new SVGPathCommander('M2 0A2 2 0 0 0 0 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2V2A2 2 0 0 0 14 0H2z').reverse(true);
|
|
290
|
+
cy.get('#test-svg path').then((svg) => {
|
|
291
|
+
svg[0].setAttribute('d', rect1.toString());
|
|
292
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0A2 2 0 0 0 0 2V14A2 2 0 0 0 2 16H14A2 2 0 0 0 16 14V2A2 2 0 0 0 14 0H2Z')
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('Test reverse composite', () => {
|
|
297
|
+
const rect = new SVGPathCommander('M2 0A2 2 0 0 0 0 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2V2A2 2 0 0 0 14 0H2zM4 4h8l-4 8z').reverse();
|
|
298
|
+
cy.wrap(rect).as('path')
|
|
299
|
+
.get('#test-svg path').then((svg) => {
|
|
300
|
+
svg[0].setAttribute('d', rect.toString());
|
|
301
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0H14A2 2 0 0 1 16 2V14A2 2 0 0 1 14 16H2A2 2 0 0 1 0 14V2A2 2 0 0 1 2 0ZM8 12L12 4H4Z')
|
|
302
|
+
})
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('Test reverse composite path with `onlySubpath`', () => {
|
|
306
|
+
const rect = new SVGPathCommander('M2 0A2 2 0 0 0 0 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2V2A2 2 0 0 0 14 0H2zM4 4h8l-4 8z').reverse(true);
|
|
307
|
+
cy.wrap(rect).as('path')
|
|
308
|
+
.get('#test-svg path').then((svg) => {
|
|
309
|
+
svg[0].setAttribute('d', rect.toString());
|
|
310
|
+
expect(svg[0].getAttribute('d')).to.equal('M2 0A2 2 0 0 0 0 2V14A2 2 0 0 0 2 16H14A2 2 0 0 0 16 14V2A2 2 0 0 0 14 0H2ZM8 12L12 4H4Z')
|
|
311
|
+
})
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('Test flipX', () => {
|
|
315
|
+
const triangle = new SVGPathCommander('M0 0L16 0 L8 16');
|
|
316
|
+
cy.wrap(triangle).as('path')
|
|
317
|
+
.get('@path').invoke('flipX').invoke('toString').should('equal', 'M16 0H0L8 16')
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('Test flipY', () => {
|
|
321
|
+
const triangle = new SVGPathCommander('M0 0L16 0 L8 16');
|
|
322
|
+
cy.wrap(triangle).as('path')
|
|
323
|
+
.get('@path').invoke('flipY').invoke('toString').should('equal', 'M0 16H16L8 0')
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('Test empty transform', () => {
|
|
327
|
+
const transform = {}
|
|
328
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z');
|
|
329
|
+
const transformed = rect.transform(transform);
|
|
330
|
+
const transformed1 = rect.transform();
|
|
331
|
+
// @ts-ignore
|
|
332
|
+
const transformed2 = rect.transform('');
|
|
333
|
+
|
|
334
|
+
expect(rect.segments).to.deep.equal(transformed.segments);
|
|
335
|
+
expect(rect.segments).to.deep.equal(transformed1.segments);
|
|
336
|
+
expect(rect.segments).to.deep.equal(transformed2.segments);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('Test transform', () => {
|
|
340
|
+
const transform = {
|
|
341
|
+
rotate: [15,15],
|
|
342
|
+
skew: [-15,15],
|
|
343
|
+
}
|
|
344
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z').transform(transform);
|
|
345
|
+
cy.wrap(rect).as('path')
|
|
346
|
+
.get('#test-svg path').then(($svg) => {
|
|
347
|
+
const [svg] = $svg.get();
|
|
348
|
+
svg.setAttribute('d', rect.toString());
|
|
349
|
+
expect(svg.getAttribute('d')).to.equal('M4.2822 -0.7292C3.2968 -1.0661 2.2579 -0.6161 1.968 0.3039L-1.818 12.3193C-2.2382 13.6528 -1.5362 14.9914 -0.2586 15.2621L12.2189 17.9057C13.2524 18.1247 14.1807 17.2742 14.3045 16.0438L15.4431 4.7255C15.5321 3.8414 14.9376 2.9137 14.1072 2.6298L4.2822 -0.7292Z')
|
|
350
|
+
})
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('Test transform with custom [x,y] origin', () => {
|
|
354
|
+
const transform = {
|
|
355
|
+
rotate: [15,15],
|
|
356
|
+
skew: [-15,15],
|
|
357
|
+
origin: [0,0]
|
|
358
|
+
}
|
|
359
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z').transform(transform);
|
|
360
|
+
cy.wrap(rect).as('path')
|
|
361
|
+
.get('#test-svg path').then(($svg) => {
|
|
362
|
+
const [svg] = $svg.get();
|
|
363
|
+
svg.setAttribute('d', rect.toString());
|
|
364
|
+
expect(svg.getAttribute('d')).to.equal('M1.803 0.5103C0.8136 0.2303 -0.1738 0.8753 -0.3942 1.9847L-3.3005 16.6188C-3.6264 18.2599 -2.8358 19.7672 -1.5474 19.9273L10.9598 21.4806C11.9895 21.6085 12.8318 20.4819 12.8569 19.0097L13.0856 5.5772C13.1033 4.5361 12.4554 3.525 11.6282 3.2909L1.803 0.5103Z')
|
|
365
|
+
})
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('Test transform with custom [x,y,z] origin option', () => {
|
|
369
|
+
const transform = {
|
|
370
|
+
rotate: [15,15],
|
|
371
|
+
skew: [-15,15]
|
|
372
|
+
}
|
|
373
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z', {origin: [8,0,24]}).transform(transform);
|
|
374
|
+
cy.wrap(rect).as('path')
|
|
375
|
+
.get('#test-svg path').then(($svg) => {
|
|
376
|
+
const [svg] = $svg.get();
|
|
377
|
+
svg.setAttribute('d', rect.toString());
|
|
378
|
+
expect(svg.getAttribute('d')).to.equal('M2.2644 -1.6232C1.1515 -1.9382 -0.0487 -1.2959 -0.4093 -0.1515L-5.2306 15.1494C-5.7788 16.8892 -5.0014 18.5047 -3.5039 18.6907L10.9116 20.4811C12.0888 20.6273 13.1574 19.4458 13.3135 17.8935L14.7232 3.8815C14.8313 2.8068 14.1803 1.7491 13.2594 1.4884L2.2644 -1.6232Z')
|
|
379
|
+
})
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('Test transform with invalid origin value/option, should use [50%,50%,50%] shape', () => {
|
|
383
|
+
cy.log('origin option');
|
|
384
|
+
const transform = {
|
|
385
|
+
rotate: [15,15],
|
|
386
|
+
skew: [-15,15],
|
|
387
|
+
scale: 1.2,
|
|
388
|
+
}
|
|
389
|
+
// @ts-ignore
|
|
390
|
+
const rect = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z', { origin: ['a','f','-8f'] }).transform(transform);
|
|
391
|
+
cy.wrap(rect).as('path')
|
|
392
|
+
.get('@path').its('origin').should('deep.equal', [8,8,24])
|
|
393
|
+
.get('#test-svg path').then(($svg) => {
|
|
394
|
+
const [svg] = $svg.get();
|
|
395
|
+
svg.setAttribute('d', rect.toString());
|
|
396
|
+
|
|
397
|
+
expect(svg.getAttribute('d')).to.equal('M3.5911 -2.3521C2.4146 -2.7667 1.158 -2.2665 0.7928 -1.1956L-4.1699 13.354C-4.7437 15.0361 -3.8887 16.7162 -2.2722 17.0327L13.1318 20.0493C14.3773 20.2932 15.4739 19.2147 15.5997 17.6963L16.7208 4.1634C16.8057 3.1381 16.1043 2.0583 15.1425 1.7193L3.5911 -2.3521Z')
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
cy.log('origin transform value');
|
|
401
|
+
const transform1 = {
|
|
402
|
+
rotate: [15,15],
|
|
403
|
+
skew: [-15,15],
|
|
404
|
+
scale: 1.2,
|
|
405
|
+
origin: ['aa5','3f','-8f']
|
|
406
|
+
}
|
|
407
|
+
// @ts-ignore
|
|
408
|
+
const rect1 = new SVGPathCommander('M2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z').transform(transform1);
|
|
409
|
+
cy.wrap(rect1).as('path1')
|
|
410
|
+
.get('@path1').its('origin').should('deep.equal', [8,8,24])
|
|
411
|
+
.get('#test-svg path').then(($svg) => {
|
|
412
|
+
const [svg] = $svg.get();
|
|
413
|
+
svg.setAttribute('d', rect1.toString());
|
|
414
|
+
|
|
415
|
+
expect(svg.getAttribute('d')).to.equal('M3.5911 -2.3521C2.4146 -2.7667 1.158 -2.2665 0.7928 -1.1956L-4.1699 13.354C-4.7437 15.0361 -3.8887 16.7162 -2.2722 17.0327L13.1318 20.0493C14.3773 20.2932 15.4739 19.2147 15.5997 17.6963L16.7208 4.1634C16.8057 3.1381 16.1043 2.0583 15.1425 1.7193L3.5911 -2.3521Z')
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
simpleShapes.initial.forEach((shape, i) => {
|
|
420
|
+
it(`Test simple shapes #${i}`, () => {
|
|
421
|
+
|
|
422
|
+
cy.log('Shape samples from [MDN docs](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#path_commands)')
|
|
423
|
+
.get('#test-svg path').then(($svg) => {
|
|
424
|
+
const svg = $svg[0] as unknown as SVGPathElement;
|
|
425
|
+
svg.ownerSVGElement?.setAttribute('viewBox', '0 0 200 100');
|
|
426
|
+
|
|
427
|
+
cy.log('**normalize**').then(() => {
|
|
428
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).normalize().toString());
|
|
429
|
+
expect(svg.getAttribute('d')).to.equal(simpleShapes.normalized[i]);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
cy.log('**transform2d**').then(() => {
|
|
433
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).transform({translate: 15, rotate: 15, scale: 0.5}).toString());
|
|
434
|
+
expect(svg.getAttribute('d')).to.equal(simpleShapes.transformed[i]);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
cy.log('**scale3d**').then(() => {
|
|
438
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).transform({scale: [0.55,0.6,0.65]}).toString());
|
|
439
|
+
expect(svg.getAttribute('d')).to.equal(simpleShapes.scaled3d[i]);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
cy.log('**skew**').then(() => {
|
|
443
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).transform({skew: 45}).toString());
|
|
444
|
+
expect(svg.getAttribute('d')).to.equal(simpleShapes.skewedX[i]);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
cy.log('**skewX**').then(() => {
|
|
448
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).transform({skew: [45,0]}).toString());
|
|
449
|
+
expect(svg.getAttribute('d')).to.equal(simpleShapes.skewedX[i]);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
cy.log('**skewY**').then(() => {
|
|
453
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).transform({skew: [0,45]}).toString());
|
|
454
|
+
expect(svg.getAttribute('d')).to.equal(simpleShapes.skewedY[i]);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
cy.log('**reverse**').then(() => {
|
|
458
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).reverse().toString());
|
|
459
|
+
expect(svg.getAttribute('d')).to.equal(simpleShapes.reversed[i]);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
cy.log('**getTotalLength**').then(() => {
|
|
464
|
+
expect(new SVGPathCommander(shape).getTotalLength()).to.equal(simpleShapes.length[i]);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
cy.log('**getPointAtLength** 0').then(() => {
|
|
468
|
+
expect(new SVGPathCommander(shape).getPointAtLength(0)).to.deep.equal(simpleShapes.pointAt0[i]);
|
|
469
|
+
});
|
|
470
|
+
cy.log('**getPointAtLength** 50').then(() => {
|
|
471
|
+
expect(new SVGPathCommander(shape).getPointAtLength(50)).to.deep.equal(simpleShapes.pointAt50[i]);
|
|
472
|
+
});
|
|
473
|
+
cy.log('**getPointAtLength** 400').then(() => {
|
|
474
|
+
expect(new SVGPathCommander(shape).getPointAtLength(400)).to.deep.equal(simpleShapes.pointAt400[i]);
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
shapes.initial.forEach((shape, i) => {
|
|
481
|
+
it(`Test composite shapes #${i}`, () => {
|
|
482
|
+
cy.get('#test-svg path').then(($svg) => {
|
|
483
|
+
const svg = $svg[0];
|
|
484
|
+
|
|
485
|
+
cy.log('**normalize**').then(() => {
|
|
486
|
+
const normalized = new SVGPathCommander(shape, { round: 2 }).normalize().toString();
|
|
487
|
+
svg.setAttribute('d', normalized);
|
|
488
|
+
expect(svg.getAttribute('d')).to.equal(shapes.normalized[i]);
|
|
489
|
+
expect(new SVGPathCommander(normalized, { round: 2}).normalize().toString()).to.equal(shapes.normalized[i]); // test path already normalized
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
cy.log('**optimize**').then(() => {
|
|
493
|
+
const optimized = new SVGPathCommander(shape, { round: 2 }).optimize().toString();
|
|
494
|
+
svg.setAttribute('d', optimized);
|
|
495
|
+
expect(svg.getAttribute('d')).to.equal(shapes.optimized[i]);
|
|
496
|
+
// skip checking for already optimized
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
cy.log('**toRelative**').then(() => {
|
|
500
|
+
const relative = new SVGPathCommander(shape, { round: 2 }).toRelative().toString();
|
|
501
|
+
svg.setAttribute('d', relative);
|
|
502
|
+
expect(svg.getAttribute('d')).to.equal(shapes.relative[i]);
|
|
503
|
+
expect(new SVGPathCommander(relative, { round: 2}).toRelative().toString()).to.equal(shapes.relative[i]);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
cy.log('**toAbsolute**').then(() => {
|
|
507
|
+
const absolute = new SVGPathCommander(shape, { round: 2 }).toAbsolute().toString();
|
|
508
|
+
svg.setAttribute('d', absolute);
|
|
509
|
+
expect(svg.getAttribute('d')).to.equal(shapes.absolute[i]);
|
|
510
|
+
expect(new SVGPathCommander(absolute, { round: 2}).toAbsolute().toString()).to.equal(shapes.absolute[i]);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
cy.log('**toCurve**').then(() => {
|
|
514
|
+
const curve = new SVGPathCommander(shape, { round: 2 }).toCurve().toString();
|
|
515
|
+
svg.setAttribute('d', curve);
|
|
516
|
+
expect(svg.getAttribute('d')).to.equal(shapes.curve[i]);
|
|
517
|
+
expect(new SVGPathCommander(curve, { round: 2}).toCurve().toString()).to.equal(shapes.curve[i]);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
cy.log('**transform** scale').then(() => {
|
|
521
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).transform({scale: 0.9}).toString());
|
|
522
|
+
expect(svg.getAttribute('d')).to.equal(shapes.scaled[i]);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
cy.log('**transform** translate').then(() => {
|
|
526
|
+
svg.setAttribute('d', new SVGPathCommander(shape, { round: 2 }).transform({translate: [1,1,0]}).toString());
|
|
527
|
+
expect(svg.getAttribute('d')).to.equal(shapes.translated[i]);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
cy.log('**getTotalLength**').then(() => {
|
|
531
|
+
expect(new SVGPathCommander(shape).getTotalLength()).to.equal(shapes.length[i]);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
cy.log('**getPointAtLength**').then(() => {
|
|
535
|
+
expect(new SVGPathCommander(shape).getPointAtLength(50)).to.deep.equal(shapes.pointAt50[i]);
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
})
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
describe('SVGPathCommander Static Methods', () => {
|
|
543
|
+
before(() => {
|
|
544
|
+
cy.log('Testing other static methods not covered by the **SVGPathCommander** constructor');
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
beforeEach(() => {
|
|
548
|
+
cy.visit('cypress/test.html')
|
|
549
|
+
.get('#test-svg').then((svg) => {
|
|
550
|
+
svg[0].setAttribute('viewBox', '0 0 182 72');
|
|
551
|
+
cy.wrap(svg[0]).as('svg');
|
|
552
|
+
})
|
|
553
|
+
.wait(200);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('Convert shape to path with incomplete values should return false', () => {
|
|
557
|
+
['line', 'circle', 'ellipse', 'rect', 'polygon', 'polyline', 'glyph'].forEach((SHAPE) => {
|
|
558
|
+
cy.log(`**${SHAPE}** with no specific attributes`).then(() => {
|
|
559
|
+
// @ts-ignore
|
|
560
|
+
expect(SVGPathCommander.shapeToPath({ type: SHAPE, fill: 'red' })).to.be.false;
|
|
561
|
+
})
|
|
562
|
+
})
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
['wombat', 'line', 'circle', 'ellipse', 'rect', 'polygon', 'polyline', 'glyph'].forEach((SHAPE) => {
|
|
566
|
+
it(`Convert <${SHAPE}> to path`, () => {
|
|
567
|
+
cy.get('@svg').invoke('prop', 'innerHTML', `<line id="line" x1="0" y1="0" x2="182" y2="72" stroke="turquoise" stroke-width="2" />
|
|
568
|
+
<circle id="circle" cx="27.5" cy="36.9" r="23.5" fill="orangered"/>
|
|
569
|
+
<ellipse id="ellipse" cx="68.3" cy="37" rx="15.1" ry="23.4" fill="darkorange"/>
|
|
570
|
+
<wombat id="wombat" fill="black"/>
|
|
571
|
+
<polygon id="polygon" points="107.4,13 113.7,28.8 127.9,31.3 117.6,43.5 120.1,60.8 107.4,52.6 94.6,60.8 97.1,43.5 86.8,31.3 101,28.8" fill="yellow"/>
|
|
572
|
+
<polyline id="polyline" points="107.39,17.78 112.43,30.42 123.79,32.42 115.55,42.18 117.55,56.02 107.39,49.46 97.15,56.02 99.15,42.18 90.91,32.42 102.27,30.42" fill="none" stroke="black" stroke-width="2"/>
|
|
573
|
+
<rect id="rect" x="131" y="13.2" width="47.5" height="47.6" rx="25" fill="yellowgreen"/>
|
|
574
|
+
<glyph id="glyph" d="M143.5 22.72H166s3 0 3 3v22.56s0 3 -3 3h-22.5s-3 0 -3 -3V25.72s0 -3 3 -3" fill="rgba(255,255,255,0.3)"/>`)
|
|
575
|
+
if (SHAPE === 'wombat') {
|
|
576
|
+
cy.get('@svg').find(SHAPE).then((shape) => {
|
|
577
|
+
try {
|
|
578
|
+
SVGPathCommander.shapeToPath(shape[0] as unknown as SVGCircleElement, true, shape[0].ownerDocument)
|
|
579
|
+
} catch (er) {
|
|
580
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
581
|
+
expect(er).to.have.property('message', `${error}: "${SHAPE}" is not SVGElement`);
|
|
582
|
+
}
|
|
583
|
+
})
|
|
584
|
+
} else {
|
|
585
|
+
cy.get('@svg').find(SHAPE).should('exist').then((shape) => {
|
|
586
|
+
SVGPathCommander.shapeToPath(shape[0] as unknown as ShapeTypes, true, shape[0].ownerDocument)
|
|
587
|
+
})
|
|
588
|
+
.get('@svg').find(SHAPE).should('not.exist')
|
|
589
|
+
.get('@svg').find(`#${SHAPE}`).should('exist')
|
|
590
|
+
.and('have.attr', 'd').and('have.length.greaterThan', 0)
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
shapeObjects.forEach((SHAPE) => {
|
|
596
|
+
it(`Convert "${SHAPE.type}" Object to path`, () => {
|
|
597
|
+
cy.get('@svg').should('exist').invoke('append', SVGPathCommander.shapeToPath(SHAPE as unknown as ShapeTypes))
|
|
598
|
+
.get(`#${SHAPE.type}`).should('exist')
|
|
599
|
+
.and('have.attr', 'd')
|
|
600
|
+
.and('have.length.greaterThan', 0)
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
simpleShapes.normalized.forEach((SHAPE, i) => {
|
|
605
|
+
it(`Can do optimizePath #${i}`, () => {
|
|
606
|
+
const path = new SVGPathCommander(SHAPE);
|
|
607
|
+
|
|
608
|
+
expect(path.optimize().toString()).to.equal(simpleShapes.initial[i]);
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
it(`Can revert back to default round option`, () => {
|
|
613
|
+
const sample = [["M",0,0],["L",181.99955,0],["L",91,72],["L",0,0],["Z"]];
|
|
614
|
+
const rounded = [["M",0,0],["L",181.9996,0],["L",91,72],["L",0,0],["Z"]];
|
|
615
|
+
|
|
616
|
+
cy.log(`-- use 4 decimals when negative number is provided`).then(() => {
|
|
617
|
+
expect(SVGPathCommander.roundPath(sample, -1)).to.deep.equal(rounded);
|
|
618
|
+
});
|
|
619
|
+
cy.log(`-- use 4 decimals when string is provided`).then(() => {
|
|
620
|
+
// @ts-ignore
|
|
621
|
+
expect(SVGPathCommander.roundPath(sample, 'wombat')).to.deep.equal(rounded);
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it(`Can do reverseCurve`, () => {
|
|
626
|
+
const path = new SVGPathCommander(simpleShapes.normalized[1]);
|
|
627
|
+
const pathReversed = new SVGPathCommander(simpleShapes.normalized[1]).reverse();
|
|
628
|
+
const reversed = [["M",170,90],["C",150,90,155,10,130,10],["C",105,10,110,90,90,90],["C",70,90,75,10,50,10],["C",25,10,30,90,10,90]];
|
|
629
|
+
|
|
630
|
+
expect(pathReversed.segments).to.deep.equal(reversed);
|
|
631
|
+
expect(SVGPathCommander.reverseCurve(pathReversed.segments as CurveArray)).to.deep.equal(path.segments);
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
it(`Can do reversePath`, () => {
|
|
635
|
+
const path = new SVGPathCommander(simpleShapes.normalized[2]);
|
|
636
|
+
const pathReversed = new SVGPathCommander(simpleShapes.normalized[2]).reverse();
|
|
637
|
+
const reversed = [["M",190,50],["Q",175,75,160,50],["Q",145,25,130,50],["Q",115,75,100,50],["Q",85,25,70,50],["Q",55,75,40,50],["Q",25,25,10,50]];
|
|
638
|
+
|
|
639
|
+
expect(pathReversed.segments).to.deep.equal(reversed);
|
|
640
|
+
expect(SVGPathCommander.reversePath(pathReversed.segments)).to.deep.equal(path.segments);
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
it(`Can transformPath with arc segments`, () => {
|
|
644
|
+
const { transformPath, pathToString, reversePath } = SVGPathCommander;
|
|
645
|
+
|
|
646
|
+
cy.log(`This test assumes **SVGPathCommander** static method can work with default
|
|
647
|
+
transform origin *{0,0,0}* when no origin is provided in the **transformObject**.
|
|
648
|
+
The test also shows how Arc segments are converted to CubicBezier for transformation.`)
|
|
649
|
+
.then(() => {
|
|
650
|
+
const path = pathToString(transformPath(simpleShapes.initial[3], { rotate: 45 }));
|
|
651
|
+
expect(path).to.equal('M-2.8284 11.3137C-6.3778 10.7769 -7.6385 14.9238 -5.0977 18.7783C-2.5569 22.6327 1.8798 23.3038 2.8884 19.9862C3.153 19.1158 3.1321 18.0645 2.8284 16.9706M-2.8284 11.3137C-3.9859 7.1438 -0.9528 4.7691 2.631 7.0393C6.2148 9.3095 7.6616 14.5219 5.2352 16.4216C4.5986 16.92 3.7596 17.1114 2.8284 16.9706M-2.8284 11.3137C-0.4208 11.6779 2.0433 14.1419 2.8284 16.9706M-2.8284 11.3137C-2.0433 14.1423 0.4208 16.6064 2.8284 16.9706');
|
|
652
|
+
|
|
653
|
+
const path1 = pathToString(transformPath(simpleShapes.initial[3], { rotate: -45 }));
|
|
654
|
+
expect(path1).to.equal('M11.3137 2.8284C10.7769 6.3778 14.9238 7.6385 18.7783 5.0977C22.6327 2.5569 23.3038 -1.8798 19.9862 -2.8884C19.1158 -3.153 18.0645 -3.1321 16.9706 -2.8284M11.3137 2.8284C7.1438 3.9859 4.7691 0.9528 7.0393 -2.631C9.3095 -6.2148 14.5219 -7.6616 16.4216 -5.2352C16.92 -4.5986 17.1114 -3.7596 16.9706 -2.8284M11.3137 2.8284C11.6779 0.4208 14.1419 -2.0433 16.9706 -2.8284M11.3137 2.8284C14.1423 2.0433 16.6064 -0.4208 16.9706 -2.8284');
|
|
655
|
+
|
|
656
|
+
const path2 = pathToString(transformPath(reversePath(simpleShapes.initial[3]), { rotate: 45 }));
|
|
657
|
+
expect(path2).to.equal('M2.8284 16.9706C0.4208 16.6064 -2.0433 14.1423 -2.8284 11.3137M2.8284 16.9706C2.0433 14.1419 -0.4208 11.6779 -2.8284 11.3137M2.8284 16.9706C6.3778 17.5074 7.6385 13.3604 5.0977 9.506C2.5569 5.6516 -1.8798 4.9805 -2.8884 8.2981C-3.153 9.1684 -3.1321 10.2198 -2.8284 11.3137M2.8284 16.9706C3.9859 21.1405 0.9528 23.5152 -2.631 21.245C-6.2148 18.9748 -7.6616 13.7624 -5.2352 11.8626C-4.5986 11.3642 -3.7596 11.1729 -2.8284 11.3137');
|
|
658
|
+
|
|
659
|
+
const path3 = pathToString(transformPath(reversePath(simpleShapes.initial[3]), { rotate: -45 }));
|
|
660
|
+
expect(path3).to.equal('M16.9706 -2.8284C16.6064 -0.4208 14.1423 2.0433 11.3137 2.8284M16.9706 -2.8284C14.1419 -2.0433 11.6779 0.4208 11.3137 2.8284M16.9706 -2.8284C17.5074 -6.3778 13.3604 -7.6385 9.506 -5.0977C5.6516 -2.5569 4.9805 1.8798 8.2981 2.8884C9.1684 3.153 10.2198 3.1321 11.3137 2.8284M16.9706 -2.8284C21.1405 -3.9859 23.5152 -0.9528 21.245 2.631C18.9748 6.2148 13.7624 7.6616 11.8626 5.2352C11.3642 4.5986 11.1729 3.7596 11.3137 2.8284');
|
|
661
|
+
})
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it(`Can do getPropertiesAtLength`, () => {
|
|
665
|
+
try {
|
|
666
|
+
SVGPathCommander.getPropertiesAtLength('M16.9706 -2.8284A4 6 89.5025 0 1 11.3137 2.8284M', 50);
|
|
667
|
+
} catch (er) {
|
|
668
|
+
expect(er).to.be.instanceOf(TypeError);
|
|
669
|
+
expect(er).to.have.property('message', `${error}: ${invalidPathValue} at index 48, "pathValue" is missing param`);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const props0 = SVGPathCommander.getPropertiesAtLength(simpleShapes.initial[0], 0);
|
|
673
|
+
// cy.log(props50)
|
|
674
|
+
expect(props0.index).to.equal(0)
|
|
675
|
+
expect(props0.lengthAtSegment).to.equal(0)
|
|
676
|
+
expect(props0.segment).to.deep.equal([ "M", 10, 10 ])
|
|
677
|
+
|
|
678
|
+
const props50 = SVGPathCommander.getPropertiesAtLength(simpleShapes.initial[0], 50);
|
|
679
|
+
// cy.log(props50)
|
|
680
|
+
expect(props50.index).to.equal(1)
|
|
681
|
+
expect(props50.lengthAtSegment).to.equal(0)
|
|
682
|
+
expect(props50.segment).to.deep.equal(['l', 80, 80])
|
|
683
|
+
|
|
684
|
+
const props400 = SVGPathCommander.getPropertiesAtLength(simpleShapes.initial[0], 400);
|
|
685
|
+
// cy.log(props50)
|
|
686
|
+
expect(props400.index).to.equal(3)
|
|
687
|
+
expect(props400.lengthAtSegment).to.equal(193.1370849898476)
|
|
688
|
+
expect(props400.segment).to.deep.equal([ 'H', 50 ])
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
it(`Can do getPropertiesAtPoint`, () => {
|
|
692
|
+
const { getPropertiesAtPoint } = SVGPathCommander;
|
|
693
|
+
|
|
694
|
+
cy.log('-- **getPropertiesAtPoint** first point').then(() => {
|
|
695
|
+
const propsPoint0 = getPropertiesAtPoint(simpleShapes.initial[1], { "x": 10, "y": 90 });
|
|
696
|
+
expect(propsPoint0.closest).to.deep.equal({x: 10, y: 90})
|
|
697
|
+
expect(propsPoint0.distance).to.equal(0)
|
|
698
|
+
expect(propsPoint0.segment).to.deep.equal({ segment: ["M", 10, 90], index: 0, length: 0, point: {x:10, y: 90}, lengthAtSegment: 0 })
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
cy.log('-- **getPropertiesAtPoint** mid point').then(() => {
|
|
702
|
+
const propsPoint50 = getPropertiesAtPoint(simpleShapes.initial[1], {x: 30.072453006153214, y: 41.42818552481854});
|
|
703
|
+
expect(propsPoint50.closest).to.deep.equal({x: 30.072453006153214, y: 41.42818552481854})
|
|
704
|
+
expect(propsPoint50.distance).to.equal(0)
|
|
705
|
+
expect(propsPoint50.segment).to.deep.equal({ segment: ['C', 30, 90, 25, 10, 50, 10], index: 1, length: 94.75680906732815, lengthAtSegment: 0 })
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
cy.log('-- **getPropertiesAtPoint** last point').then(() => {
|
|
709
|
+
const propsPoint400 = getPropertiesAtPoint(simpleShapes.initial[1], { "x": 50, "y": 10 });
|
|
710
|
+
expect(propsPoint400.closest).to.deep.equal({x: 50.243177049793694, y: 10.00259849715006})
|
|
711
|
+
expect(propsPoint400.distance).to.equal(0.24319093267184844)
|
|
712
|
+
expect(propsPoint400.segment).to.deep.equal({ segment: ['s', 20, 80, 40, 80], index: 2, length: 94.75680906732818, lengthAtSegment: 94.75680906732815 })
|
|
713
|
+
})
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it(`Can do getSegmentAtLength`, () => {
|
|
717
|
+
const { getSegmentAtLength } = SVGPathCommander;
|
|
718
|
+
cy.log('-- **getSegmentAtLength** undefined').then(() => {
|
|
719
|
+
expect(getSegmentAtLength(simpleShapes.initial[1])).to.deep.equal(['M', 10, 90]);
|
|
720
|
+
});
|
|
721
|
+
cy.log('-- **getSegmentAtLength** 0').then(() => {
|
|
722
|
+
expect(getSegmentAtLength(simpleShapes.initial[1], 0)).to.deep.equal(['M', 10, 90]);
|
|
723
|
+
});
|
|
724
|
+
cy.log('-- **getSegmentAtLength** 15').then(() => {
|
|
725
|
+
expect(getSegmentAtLength(simpleShapes.initial[3], 15)).to.deep.equal(['a', 6, 4, 10, 1, 0, 8, 0]);
|
|
726
|
+
});
|
|
727
|
+
cy.log('-- **getSegmentAtLength** 400').then(() => {
|
|
728
|
+
expect(getSegmentAtLength(simpleShapes.initial[3], 400)).to.deep.equal(['a', 6, 4, 10, 0, 0, 8, 0]);
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
it(`Can do getSegmentOfPoint`, () => {
|
|
733
|
+
const { getSegmentOfPoint } = SVGPathCommander;
|
|
734
|
+
cy.log('-- **getSegmentOfPoint** first point').then(() => {
|
|
735
|
+
expect(getSegmentOfPoint(simpleShapes.initial[1], { x: 10, y: 90 })).to.deep.equal({segment: ["M",10,90], index:0, length:0, point: {x:10,y:90}, lengthAtSegment: 0});
|
|
736
|
+
});
|
|
737
|
+
cy.log('-- **getSegmentOfPoint** mid point').then(() => {
|
|
738
|
+
expect(getSegmentOfPoint(simpleShapes.initial[3], { x: 9, y: 9})).to.deep.equal({segment: ["a",6,4,10,0,1,8,0], index: 5, length: 8.400632026154419, lengthAtSegment: 46.6599158251274});
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
it(`Can do getClosestPoint`, () => {
|
|
743
|
+
const { getClosestPoint } = SVGPathCommander;
|
|
744
|
+
cy.log('-- **getClosestPoint** first point').then(() => {
|
|
745
|
+
expect(getClosestPoint(simpleShapes.initial[1], { x: 10, y: 90 })).to.deep.equal({x: 10, y: 90});
|
|
746
|
+
});
|
|
747
|
+
cy.log('-- **getClosestPoint** mid point').then(() => {
|
|
748
|
+
expect(getClosestPoint(simpleShapes.initial[3], { x: 9, y: 9})).to.deep.equal({ x: 9.123926246784901, y: 8.941790467688946});
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
it(`Can do isPointInStroke`, () => {
|
|
753
|
+
const { isPointInStroke } = SVGPathCommander;
|
|
754
|
+
cy.log('-- **isPointInStroke** first point').then(() => {
|
|
755
|
+
expect(isPointInStroke(simpleShapes.initial[1], { x: 10, y: 90 })).to.be.true;
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
cy.log('-- **isPointInStroke** mid point').then(() => {
|
|
759
|
+
expect(isPointInStroke(simpleShapes.initial[1], { x: 28.94438057441916, y: 46.29922469345143})).to.be.true;
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
cy.log('-- **isPointInStroke**({ x: 10, y: 10 })').then(() => {
|
|
763
|
+
expect(isPointInStroke(simpleShapes.initial[1], { x: 10, y: 10 })).to.be.false;
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
cy.log('-- **isPointInStroke**({ x: 45.355339, y: 45.355339 })').then(() => {
|
|
767
|
+
expect(isPointInStroke(simpleShapes.initial[1], { x: 45.355339, y: 45.355339 })).to.be.false;
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
cy.log('-- **isPointInStroke**({ x: 50, y: 10 })').then(() => {
|
|
771
|
+
expect(isPointInStroke(simpleShapes.initial[1], { x: 50, y: 10 })).to.be.false;
|
|
772
|
+
});
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
it(`Can do getDrawDirection`, () => {
|
|
776
|
+
const { getDrawDirection } = SVGPathCommander;
|
|
777
|
+
|
|
778
|
+
cy.log('-- **getDrawDirection** should be true').then(() => {
|
|
779
|
+
expect(getDrawDirection(simpleShapes.reversed[1])).to.be.true;
|
|
780
|
+
});
|
|
781
|
+
cy.log('-- **getDrawDirection** should be false').then(() => {
|
|
782
|
+
expect(getDrawDirection(simpleShapes.initial[1])).to.be.false;
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
it(`Can do splitCubic`, () => {
|
|
788
|
+
const { splitCubic } = SVGPathCommander;
|
|
789
|
+
expect(splitCubic([70, 60, 70, 80, 110, 80, 110, 60])).to.deep.equal([
|
|
790
|
+
['C', 70, 70, 80, 75, 90, 75],
|
|
791
|
+
['C', 100, 75, 110, 70, 110, 60],
|
|
792
|
+
]);
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
it(`Can do polygonLength`, () => {
|
|
796
|
+
const { polygonLength } = SVGPathCommander;
|
|
797
|
+
expect(polygonLength([[100,100], [150,25], [150,75], [200,0]])).to.equal(230.27756377319946);
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
it(`Can do polygonArea`, () => {
|
|
801
|
+
const { polygonArea } = SVGPathCommander;
|
|
802
|
+
expect(polygonArea([[107.4,13], [113.7,28.8], [127.9,31.3], [117.6,43.5], [120.1,60.8], [107.4,52.6], [94.6,60.8], [97.1,43.5], [86.8,31.3], [101,28.8]])).to.equal(-836.69);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
it(`Can do transformPath with empty object`, () => {
|
|
806
|
+
const { transformPath, pathToString } = SVGPathCommander;
|
|
807
|
+
|
|
808
|
+
cy.log('-- **transformObject** is *undefined*').then(() => {
|
|
809
|
+
const path = pathToString(transformPath(simpleShapes.normalized[0] as string));
|
|
810
|
+
expect(path).to.equal(simpleShapes.normalized[0]);
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
cy.log('-- **transformObject** is *empty*').then(() => {
|
|
814
|
+
// @ts-ignore
|
|
815
|
+
const path = pathToString(transformPath(simpleShapes.normalized[0], {}));
|
|
816
|
+
expect(path).to.equal(simpleShapes.normalized[0]);
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
cy.log('-- **transformObject** has only *origin*').then(() => {
|
|
820
|
+
const path = pathToString(transformPath(simpleShapes.normalized[0], { origin: [0,0,0]}));
|
|
821
|
+
expect(path).to.equal(simpleShapes.normalized[0]);
|
|
822
|
+
})
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
});
|