@emasoft/svg-matrix 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +402 -12
- package/package.json +17 -3
- package/samples/test.svg +39 -0
- package/src/index.js +26 -1
- package/src/matrix.js +263 -35
- package/src/svg-flatten.js +335 -0
- package/src/transforms2d.js +120 -2
- package/src/transforms3d.js +214 -4
- package/src/vector.js +174 -30
package/README.md
CHANGED
|
@@ -1,25 +1,415 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @emasoft/svg-matrix
|
|
2
2
|
|
|
3
3
|
Arbitrary-precision matrix, vector and affine transformation library for JavaScript using decimal.js.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Decimal-backed Matrix and Vector classes.
|
|
7
|
-
- 2D (3x3) and 3D (4x4) transform helpers.
|
|
5
|
+
## Features
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
- **Decimal-backed** Matrix and Vector classes for high-precision geometry
|
|
8
|
+
- **2D transforms** (3x3 homogeneous matrices): translation, rotation, scale, skew, reflection
|
|
9
|
+
- **3D transforms** (4x4 homogeneous matrices): translation, rotation (X/Y/Z axis), scale, reflection
|
|
10
|
+
- **SVG transform flattening**: parse transform attributes, build CTMs, flatten nested hierarchies
|
|
11
|
+
- **Linear algebra**: LU/QR decomposition, determinant, inverse, solve, matrix exponential
|
|
12
|
+
- **10^77 times better precision** than JavaScript floats for round-trip transforms
|
|
13
|
+
- Works in **Node.js** and **browsers** (via CDN)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### npm
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @emasoft/svg-matrix
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { Decimal, Matrix, Vector, Transforms2D, Transforms3D, SVGFlatten } from '@emasoft/svg-matrix';
|
|
10
25
|
```
|
|
11
|
-
|
|
26
|
+
|
|
27
|
+
### CDN (Browser)
|
|
28
|
+
|
|
29
|
+
Using esm.sh (recommended - auto-resolves dependencies):
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<script type="module">
|
|
33
|
+
import { Decimal, Matrix, Vector, Transforms2D, Transforms3D, SVGFlatten } from 'https://esm.sh/@emasoft/svg-matrix';
|
|
34
|
+
|
|
35
|
+
Decimal.set({ precision: 80 });
|
|
36
|
+
|
|
37
|
+
// Create and compose 2D transforms
|
|
38
|
+
const M = Transforms2D.translation(2, 3)
|
|
39
|
+
.mul(Transforms2D.rotate(Math.PI / 4))
|
|
40
|
+
.mul(Transforms2D.scale(1.5));
|
|
41
|
+
|
|
42
|
+
// Apply to a point
|
|
43
|
+
const [x, y] = Transforms2D.applyTransform(M, 1, 0);
|
|
44
|
+
console.log('Transformed:', x.toString(), y.toString());
|
|
45
|
+
</script>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Using Skypack:
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<script type="module">
|
|
52
|
+
import { Matrix, Vector } from 'https://cdn.skypack.dev/@emasoft/svg-matrix';
|
|
53
|
+
</script>
|
|
12
54
|
```
|
|
13
55
|
|
|
14
|
-
|
|
56
|
+
Using import maps:
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<script type="importmap">
|
|
60
|
+
{
|
|
61
|
+
"imports": {
|
|
62
|
+
"@emasoft/svg-matrix": "https://esm.sh/@emasoft/svg-matrix"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
66
|
+
<script type="module">
|
|
67
|
+
import { Matrix, Vector, Transforms2D } from '@emasoft/svg-matrix';
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage Examples
|
|
72
|
+
|
|
73
|
+
### Vector Operations
|
|
74
|
+
|
|
15
75
|
```js
|
|
16
|
-
import {
|
|
76
|
+
import { Vector, Decimal } from '@emasoft/svg-matrix';
|
|
77
|
+
|
|
17
78
|
Decimal.set({ precision: 80 });
|
|
18
79
|
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
80
|
+
const v = Vector.from([1, 2, 3]);
|
|
81
|
+
const w = Vector.from([4, 5, 6]);
|
|
82
|
+
|
|
83
|
+
// Basic operations
|
|
84
|
+
console.log('Add:', v.add(w).toNumberArray()); // [5, 7, 9]
|
|
85
|
+
console.log('Scale:', v.scale(2).toNumberArray()); // [2, 4, 6]
|
|
86
|
+
console.log('Dot:', v.dot(w).toString()); // 32
|
|
87
|
+
console.log('Cross:', v.cross(w).toNumberArray()); // [-3, 6, -3]
|
|
88
|
+
|
|
89
|
+
// Geometry
|
|
90
|
+
console.log('Norm:', v.norm().toString()); // 3.7416...
|
|
91
|
+
console.log('Normalized:', v.normalize().toNumberArray());
|
|
92
|
+
console.log('Angle:', v.angleBetween(w).toString()); // radians
|
|
93
|
+
|
|
94
|
+
// Projection
|
|
95
|
+
const proj = v.projectOnto(w);
|
|
96
|
+
console.log('Projection:', proj.toNumberArray());
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Matrix Operations
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
import { Matrix } from '@emasoft/svg-matrix';
|
|
103
|
+
|
|
104
|
+
const A = Matrix.from([[1, 2], [3, 4]]);
|
|
105
|
+
const B = Matrix.from([[5, 6], [7, 8]]);
|
|
106
|
+
|
|
107
|
+
// Basic operations
|
|
108
|
+
console.log('Multiply:', A.mul(B).toNumberArray());
|
|
109
|
+
console.log('Transpose:', A.transpose().toNumberArray());
|
|
110
|
+
console.log('Determinant:', A.determinant().toString()); // -2
|
|
111
|
+
console.log('Trace:', A.trace().toString()); // 5
|
|
112
|
+
|
|
113
|
+
// Linear algebra
|
|
114
|
+
const inv = A.inverse();
|
|
115
|
+
console.log('Inverse:', inv.toNumberArray());
|
|
116
|
+
|
|
117
|
+
// Solve Ax = b
|
|
118
|
+
const x = A.solve([1, 1]);
|
|
119
|
+
console.log('Solution:', x.toNumberArray());
|
|
120
|
+
|
|
121
|
+
// Decompositions
|
|
122
|
+
const { L, U, P } = A.lu();
|
|
123
|
+
const { Q, R } = A.qr();
|
|
124
|
+
|
|
125
|
+
// Matrix exponential
|
|
126
|
+
const expA = A.exp();
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 2D Transforms
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
import { Transforms2D } from '@emasoft/svg-matrix';
|
|
133
|
+
|
|
134
|
+
// Basic transforms
|
|
135
|
+
const T = Transforms2D.translation(10, 20);
|
|
136
|
+
const R = Transforms2D.rotate(Math.PI / 4); // 45 degrees
|
|
137
|
+
const S = Transforms2D.scale(2, 3); // non-uniform
|
|
138
|
+
const Su = Transforms2D.scale(2); // uniform
|
|
139
|
+
|
|
140
|
+
// Rotation around a point
|
|
141
|
+
const Rp = Transforms2D.rotateAroundPoint(Math.PI / 2, 5, 5);
|
|
142
|
+
|
|
143
|
+
// Skew and stretch
|
|
144
|
+
const Sk = Transforms2D.skew(0.5, 0);
|
|
145
|
+
const St = Transforms2D.stretchAlongAxis(1, 0, 2); // stretch 2x along X
|
|
146
|
+
|
|
147
|
+
// Reflections
|
|
148
|
+
const Rx = Transforms2D.reflectX(); // flip Y
|
|
149
|
+
const Ry = Transforms2D.reflectY(); // flip X
|
|
150
|
+
const Ro = Transforms2D.reflectOrigin(); // flip both
|
|
151
|
+
|
|
152
|
+
// Compose transforms (right-to-left: S first, then R, then T)
|
|
153
|
+
const M = T.mul(R).mul(S);
|
|
154
|
+
|
|
155
|
+
// Apply to point
|
|
156
|
+
const [x, y] = Transforms2D.applyTransform(M, 1, 0);
|
|
157
|
+
|
|
158
|
+
// Inverse transform
|
|
159
|
+
const Minv = M.inverse();
|
|
160
|
+
const [xBack, yBack] = Transforms2D.applyTransform(Minv, x, y);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3D Transforms
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
import { Transforms3D } from '@emasoft/svg-matrix';
|
|
167
|
+
|
|
168
|
+
// Basic transforms
|
|
169
|
+
const T = Transforms3D.translation(1, 2, 3);
|
|
170
|
+
const S = Transforms3D.scale(2, 2, 2);
|
|
171
|
+
|
|
172
|
+
// Axis rotations (radians, right-hand rule)
|
|
173
|
+
const Rx = Transforms3D.rotateX(Math.PI / 2);
|
|
174
|
+
const Ry = Transforms3D.rotateY(Math.PI / 4);
|
|
175
|
+
const Rz = Transforms3D.rotateZ(Math.PI / 6);
|
|
176
|
+
|
|
177
|
+
// Rotation around arbitrary axis
|
|
178
|
+
const Raxis = Transforms3D.rotateAroundAxis(1, 1, 0, Math.PI / 3);
|
|
179
|
+
|
|
180
|
+
// Rotation around a point
|
|
181
|
+
const Rpt = Transforms3D.rotateAroundPoint(0, 0, 1, Math.PI / 2, 5, 5, 0);
|
|
182
|
+
|
|
183
|
+
// Reflections
|
|
184
|
+
const RfXY = Transforms3D.reflectXY(); // flip Z
|
|
185
|
+
const RfXZ = Transforms3D.reflectXZ(); // flip Y
|
|
186
|
+
const RfYZ = Transforms3D.reflectYZ(); // flip X
|
|
187
|
+
const RfO = Transforms3D.reflectOrigin(); // flip all
|
|
188
|
+
|
|
189
|
+
// Compose and apply
|
|
190
|
+
const M = T.mul(Rx).mul(S);
|
|
191
|
+
const [x, y, z] = Transforms3D.applyTransform(M, 1, 0, 0);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## API Reference
|
|
195
|
+
|
|
196
|
+
### Vector
|
|
197
|
+
|
|
198
|
+
| Method | Description |
|
|
199
|
+
|--------|-------------|
|
|
200
|
+
| `Vector.from(arr)` | Create vector from array |
|
|
201
|
+
| `add(v)` | Element-wise addition |
|
|
202
|
+
| `sub(v)` | Element-wise subtraction |
|
|
203
|
+
| `scale(s)` | Scalar multiplication |
|
|
204
|
+
| `negate()` | Negate all components |
|
|
205
|
+
| `dot(v)` | Dot product |
|
|
206
|
+
| `cross(v)` | Cross product (3D only) |
|
|
207
|
+
| `outer(v)` | Outer product (returns 2D array) |
|
|
208
|
+
| `norm()` | Euclidean length |
|
|
209
|
+
| `normalize()` | Unit vector |
|
|
210
|
+
| `angleBetween(v)` | Angle in radians |
|
|
211
|
+
| `projectOnto(v)` | Vector projection |
|
|
212
|
+
| `orthogonal()` | Perpendicular vector |
|
|
213
|
+
| `distance(v)` | Euclidean distance |
|
|
214
|
+
| `equals(v, tol?)` | Equality check with optional tolerance |
|
|
215
|
+
| `toArray()` | Get Decimal array |
|
|
216
|
+
| `toNumberArray()` | Get number array |
|
|
217
|
+
| `toStringArray()` | Get string array |
|
|
218
|
+
|
|
219
|
+
### Matrix
|
|
220
|
+
|
|
221
|
+
| Method | Description |
|
|
222
|
+
|--------|-------------|
|
|
223
|
+
| `Matrix.from(arr)` | Create from 2D array |
|
|
224
|
+
| `Matrix.zeros(r, c)` | Zero matrix |
|
|
225
|
+
| `Matrix.identity(n)` | Identity matrix |
|
|
226
|
+
| `add(M)` | Element-wise addition |
|
|
227
|
+
| `sub(M)` | Element-wise subtraction |
|
|
228
|
+
| `mul(M)` | Matrix multiplication |
|
|
229
|
+
| `div(s)` | Scalar division |
|
|
230
|
+
| `negate()` | Negate all elements |
|
|
231
|
+
| `transpose()` | Transpose |
|
|
232
|
+
| `trace()` | Sum of diagonal |
|
|
233
|
+
| `determinant()` | Determinant |
|
|
234
|
+
| `inverse()` | Matrix inverse |
|
|
235
|
+
| `solve(b)` | Solve Ax = b |
|
|
236
|
+
| `lu()` | LU decomposition |
|
|
237
|
+
| `qr()` | QR decomposition |
|
|
238
|
+
| `exp()` | Matrix exponential |
|
|
239
|
+
| `applyToVector(v)` | Matrix-vector product |
|
|
240
|
+
| `equals(M, tol?)` | Equality check |
|
|
241
|
+
| `isSquare()` | Check if square |
|
|
242
|
+
| `toNumberArray()` | Get number 2D array |
|
|
243
|
+
| `toArrayOfStrings()` | Get string 2D array |
|
|
244
|
+
|
|
245
|
+
### Transforms2D
|
|
246
|
+
|
|
247
|
+
| Function | Description |
|
|
248
|
+
|----------|-------------|
|
|
249
|
+
| `translation(tx, ty)` | Translation matrix |
|
|
250
|
+
| `scale(sx, sy?)` | Scale matrix (uniform if sy omitted) |
|
|
251
|
+
| `rotate(theta)` | Rotation matrix (radians) |
|
|
252
|
+
| `rotateAroundPoint(theta, px, py)` | Rotation around point |
|
|
253
|
+
| `skew(ax, ay)` | Skew/shear matrix |
|
|
254
|
+
| `stretchAlongAxis(ux, uy, k)` | Stretch along direction |
|
|
255
|
+
| `reflectX()` | Reflect across X axis |
|
|
256
|
+
| `reflectY()` | Reflect across Y axis |
|
|
257
|
+
| `reflectOrigin()` | Reflect through origin |
|
|
258
|
+
| `applyTransform(M, x, y)` | Apply matrix to point |
|
|
259
|
+
|
|
260
|
+
### Transforms3D
|
|
261
|
+
|
|
262
|
+
| Function | Description |
|
|
263
|
+
|----------|-------------|
|
|
264
|
+
| `translation(tx, ty, tz)` | Translation matrix |
|
|
265
|
+
| `scale(sx, sy?, sz?)` | Scale matrix |
|
|
266
|
+
| `rotateX(theta)` | Rotation around X axis |
|
|
267
|
+
| `rotateY(theta)` | Rotation around Y axis |
|
|
268
|
+
| `rotateZ(theta)` | Rotation around Z axis |
|
|
269
|
+
| `rotateAroundAxis(ux, uy, uz, theta)` | Rotation around arbitrary axis |
|
|
270
|
+
| `rotateAroundPoint(ux, uy, uz, theta, px, py, pz)` | Rotation around point |
|
|
271
|
+
| `reflectXY()` | Reflect across XY plane |
|
|
272
|
+
| `reflectXZ()` | Reflect across XZ plane |
|
|
273
|
+
| `reflectYZ()` | Reflect across YZ plane |
|
|
274
|
+
| `reflectOrigin()` | Reflect through origin |
|
|
275
|
+
| `applyTransform(M, x, y, z)` | Apply matrix to point |
|
|
276
|
+
|
|
277
|
+
### SVGFlatten
|
|
278
|
+
|
|
279
|
+
| Function | Description |
|
|
280
|
+
|----------|-------------|
|
|
281
|
+
| `parseTransformFunction(func, args)` | Parse a single SVG transform function |
|
|
282
|
+
| `parseTransformAttribute(str)` | Parse a full SVG transform attribute string |
|
|
283
|
+
| `buildCTM(transformStack)` | Build CTM from array of transform strings |
|
|
284
|
+
| `applyToPoint(ctm, x, y)` | Apply CTM to a 2D point |
|
|
285
|
+
| `toSVGMatrix(ctm, precision?)` | Convert CTM back to SVG matrix() notation |
|
|
286
|
+
| `isIdentity(m, tolerance?)` | Check if matrix is effectively identity |
|
|
287
|
+
| `transformPathData(pathD, ctm)` | Transform path data coordinates |
|
|
288
|
+
| `PRECISION_INFO` | Object with precision comparison data |
|
|
289
|
+
|
|
290
|
+
## SVG Transform Flattening
|
|
291
|
+
|
|
292
|
+
The `SVGFlatten` module provides tools for parsing SVG transform attributes, building CTMs (Current Transform Matrices), and flattening nested transforms with arbitrary precision.
|
|
293
|
+
|
|
294
|
+
### Why Use SVGFlatten?
|
|
295
|
+
|
|
296
|
+
SVG elements can have deeply nested transforms through parent groups. When coordinates are transformed from local space to viewport and back using JavaScript's native 64-bit floats, precision is lost:
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
Original coordinates: (10, 10)
|
|
300
|
+
After round-trip (float): (9.9857, 9.9857) // Error: 0.0143
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
With `@emasoft/svg-matrix` using 80-digit Decimal precision:
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
Original coordinates: (10, 10)
|
|
307
|
+
After round-trip: (10.00000000000000000000000000000000000000,
|
|
308
|
+
9.999999999999999999999999999999999999999999999999999999999999999999999999999999998)
|
|
309
|
+
Round-trip error: X=0, Y=2e-79
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Improvement: 10^77 times better precision than JavaScript floats.**
|
|
313
|
+
|
|
314
|
+
### Parsing SVG Transforms
|
|
315
|
+
|
|
316
|
+
```js
|
|
317
|
+
import { SVGFlatten } from '@emasoft/svg-matrix';
|
|
318
|
+
|
|
319
|
+
// Parse individual transforms
|
|
320
|
+
const m1 = SVGFlatten.parseTransformAttribute('translate(10, 20)');
|
|
321
|
+
const m2 = SVGFlatten.parseTransformAttribute('rotate(45)');
|
|
322
|
+
const m3 = SVGFlatten.parseTransformAttribute('scale(2, 0.5)');
|
|
323
|
+
const m4 = SVGFlatten.parseTransformAttribute('skewX(15)');
|
|
324
|
+
const m5 = SVGFlatten.parseTransformAttribute('matrix(0.866, 0.5, -0.5, 0.866, 0, 0)');
|
|
325
|
+
|
|
326
|
+
// Parse chained transforms
|
|
327
|
+
const combined = SVGFlatten.parseTransformAttribute('translate(50,50) rotate(45) scale(2)');
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Building CTM from Nested Elements
|
|
331
|
+
|
|
332
|
+
```js
|
|
333
|
+
import { Decimal, SVGFlatten } from '@emasoft/svg-matrix';
|
|
334
|
+
|
|
335
|
+
Decimal.set({ precision: 80 });
|
|
336
|
+
|
|
337
|
+
// Simulate a 6-level SVG hierarchy:
|
|
338
|
+
// <svg viewBox="..."> <!-- viewBox scaling -->
|
|
339
|
+
// <g transform="translate(-13.6,-10.2)"> <!-- g1 -->
|
|
340
|
+
// <g transform="translate(-1144.8,517.6)"> <!-- g2 -->
|
|
341
|
+
// <g transform="rotate(15)"> <!-- g3 -->
|
|
342
|
+
// <g transform="scale(1.2, 0.8)"> <!-- g4 -->
|
|
343
|
+
// <path transform="matrix(...)"/> <!-- element -->
|
|
344
|
+
|
|
345
|
+
const transformStack = [
|
|
346
|
+
'scale(1.5)', // viewBox scaling
|
|
347
|
+
'translate(-13.613145,-10.209854)', // g1
|
|
348
|
+
'translate(-1144.8563,517.64642)', // g2
|
|
349
|
+
'rotate(15)', // g3
|
|
350
|
+
'scale(1.2, 0.8)', // g4
|
|
351
|
+
'matrix(0.71577068,0,0,1.3970955,0,0)' // element
|
|
352
|
+
];
|
|
353
|
+
|
|
354
|
+
// Build combined CTM
|
|
355
|
+
const ctm = SVGFlatten.buildCTM(transformStack);
|
|
356
|
+
|
|
357
|
+
// Transform a point from local to viewport coordinates
|
|
358
|
+
const local = { x: new Decimal('10'), y: new Decimal('10') };
|
|
359
|
+
const viewport = SVGFlatten.applyToPoint(ctm, local.x, local.y);
|
|
360
|
+
|
|
361
|
+
// Transform back to local coordinates
|
|
362
|
+
const inverseCTM = ctm.inverse();
|
|
363
|
+
const recovered = SVGFlatten.applyToPoint(inverseCTM, viewport.x, viewport.y);
|
|
364
|
+
|
|
365
|
+
// Verify precision
|
|
366
|
+
const errorX = recovered.x.minus(local.x).abs();
|
|
367
|
+
const errorY = recovered.y.minus(local.y).abs();
|
|
368
|
+
console.log('Round-trip error X:', errorX.toString()); // 0
|
|
369
|
+
console.log('Round-trip error Y:', errorY.toString()); // ~2e-79
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Transforming Path Data
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
import { SVGFlatten } from '@emasoft/svg-matrix';
|
|
376
|
+
|
|
377
|
+
const pathD = 'M 100 100 L 200 100 L 200 200 L 100 200 Z';
|
|
378
|
+
const ctm = SVGFlatten.parseTransformAttribute('translate(50, 50) scale(2)');
|
|
379
|
+
const transformed = SVGFlatten.transformPathData(pathD, ctm);
|
|
380
|
+
|
|
381
|
+
console.log(transformed);
|
|
382
|
+
// M 250.000000 250.000000 L 450.000000 250.000000 L 450.000000 450.000000 L 250.000000 450.000000 Z
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Flattening All Transforms
|
|
386
|
+
|
|
387
|
+
To flatten an SVG (remove all transform attributes and apply them directly to coordinates):
|
|
388
|
+
|
|
389
|
+
```js
|
|
390
|
+
import { SVGFlatten } from '@emasoft/svg-matrix';
|
|
391
|
+
|
|
392
|
+
// 1. For each element, collect transforms from root to element
|
|
393
|
+
// 2. Build CTM: const ctm = SVGFlatten.buildCTM(transformStack);
|
|
394
|
+
// 3. Transform path data: const newD = SVGFlatten.transformPathData(d, ctm);
|
|
395
|
+
// 4. Remove transform attribute, update path d attribute
|
|
396
|
+
// 5. Convert CTM back to SVG: SVGFlatten.toSVGMatrix(ctm, 6)
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### CDN Usage
|
|
400
|
+
|
|
401
|
+
```html
|
|
402
|
+
<script type="module">
|
|
403
|
+
import { Decimal, SVGFlatten } from 'https://esm.sh/@emasoft/svg-matrix';
|
|
404
|
+
|
|
405
|
+
Decimal.set({ precision: 80 });
|
|
406
|
+
|
|
407
|
+
const ctm = SVGFlatten.parseTransformAttribute('rotate(45, 100, 100)');
|
|
408
|
+
const point = SVGFlatten.applyToPoint(ctm, 50, 50);
|
|
409
|
+
console.log('Transformed:', point.x.toFixed(6), point.y.toFixed(6));
|
|
410
|
+
</script>
|
|
22
411
|
```
|
|
23
412
|
|
|
24
|
-
|
|
413
|
+
## License
|
|
25
414
|
|
|
415
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emasoft/svg-matrix",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Arbitrary-precision matrix, vector and affine transformation library for JavaScript using decimal.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -22,11 +22,25 @@
|
|
|
22
22
|
"affine",
|
|
23
23
|
"transform",
|
|
24
24
|
"svg",
|
|
25
|
-
"geometry"
|
|
25
|
+
"geometry",
|
|
26
|
+
"esm",
|
|
27
|
+
"browser",
|
|
28
|
+
"cdn",
|
|
29
|
+
"2d",
|
|
30
|
+
"3d",
|
|
31
|
+
"rotation",
|
|
32
|
+
"translation",
|
|
33
|
+
"homogeneous"
|
|
26
34
|
],
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"import": "./src/index.js",
|
|
38
|
+
"default": "./src/index.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
27
41
|
"author": "Emasoft",
|
|
28
42
|
"license": "MIT",
|
|
29
43
|
"dependencies": {
|
|
30
44
|
"decimal.js": "^10.6.0"
|
|
31
45
|
}
|
|
32
|
-
}
|
|
46
|
+
}
|
package/samples/test.svg
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<svg id="pure_smill_no_javascript" version="1.1" x="0px" y="0px" width="1037.2269" height="1486.5736" viewBox="0 0 1037.227 2892.792" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
|
3
|
+
<defs id="defs82" />
|
|
4
|
+
<defs id="defs83" />
|
|
5
|
+
<g id="g37" transform="translate(-13.613145,-10.209854)">
|
|
6
|
+
<rect style="fill:#ffffff;stroke-width:16.1377" id="rect46" width="2018.3876" height="2892.792" x="-476.96716" y="10.209854" />
|
|
7
|
+
<g id="g1" transform="translate(-1144.8563,517.64642)">
|
|
8
|
+
<path id="rect1851" style="fill:none;stroke:#fe0000;stroke-width:14.5557;stroke-dasharray:87.3339, 14.5557;stroke-dashoffset:0;stroke-opacity:1" d="m 1318.7684,284.08405 c 307.4737,-77.43295 477.4693,-79.6744 779.5799,0 132.9776,50.26731 130.7718,132.64482 0,168.79753 -297.0165,89.1289 -485.8097,78.65553 -779.5799,0 -143.454,-38.49011 -151.4589,-124.05689 0,-168.79753 z" />
|
|
9
|
+
</g>
|
|
10
|
+
<g id="g6" transform="translate(13.613181,10.209854)">
|
|
11
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:94.4263px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#808000;stroke-width:16.0447" x="535.36902" y="880.21216" id="text2"><tspan id="tspan2" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:94.4263px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#808000;stroke-width:16.0447" x="535.36902" y="880.21216">100% PURE SMIL</tspan></text>
|
|
12
|
+
</g>
|
|
13
|
+
<g id="g7" transform="translate(13.613181,10.209854)">
|
|
14
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:51.2678px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#808000;stroke-width:8.7113" x="550.46289" y="939.87573" id="text3"><tspan id="tspan3" style="font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;font-size:51.2678px;font-family:Futura;-inkscape-font-specification:'Futura, Medium Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#808000;stroke-width:8.7113" x="550.46289" y="939.87573">No javascript or css needed!</tspan></text>
|
|
15
|
+
</g>
|
|
16
|
+
<text xml:space="preserve" style="font-style:italic;font-weight:600;font-size:85.6631px;font-family:'EB Garamond', serif;-inkscape-font-specification:'EB Garamond, serif, Semi-Bold Italic';writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="388.92661" y="1477.7195" id="text37" text-anchor="middle"><tspan id="tspan1" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:85.6631px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="388.92661" y="1477.7195">100% PURE SMIL</tspan></text>
|
|
17
|
+
<text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'.New York';-inkscape-font-specification:'.New York, Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="363.31311" y="1603.9994" id="text39" text-anchor="middle"><tspan id="tspan38" style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'.New York';-inkscape-font-specification:'.New York, Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="363.31311" y="1603.9994">No javascript or css needed!</tspan></text>
|
|
18
|
+
<text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="678.02161" y="1757.4683" id="text40" transform="scale(0.71577068,1.3970955)" text-anchor="middle"><tspan id="tspan39" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.6396" x="678.02161" y="1757.4683">No javascript or css needed!</tspan></text>
|
|
19
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Luminari;-inkscape-font-specification:'Luminari, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="404.79761" y="2284.7117" id="text41" text-anchor="middle"><tspan id="tspan40" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Luminari;-inkscape-font-specification:'Luminari, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="404.79761" y="2284.7117">100% PURE SMIL</tspan></text>
|
|
20
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:85.6631px;font-family:'American Typewriter';-inkscape-font-specification:'American Typewriter, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="341.14975" y="1755.0848" id="text42" text-anchor="middle"><tspan id="tspan41" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:85.6631px;font-family:'American Typewriter';-inkscape-font-specification:'American Typewriter, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="341.14975" y="1755.0848">100% PURE SMIL</tspan></text>
|
|
21
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:85.6631px;font-family:'Comic Sans MS';-inkscape-font-specification:'Comic Sans MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="419.90002" y="1326.3029" id="text43" text-anchor="middle"><tspan id="tspan42" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:85.6631px;font-family:'Comic Sans MS';-inkscape-font-specification:'Comic Sans MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="419.90002" y="1326.3029">100% PURE SMIL</tspan></text>
|
|
22
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:'.SF Arabic Rounded';-inkscape-font-specification:'.SF Arabic Rounded, @opsz=80,wght=510';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'opsz' 80, 'wght' 510;writing-mode:lr-tb;direction:ltr;text-anchor:middle;white-space:pre;inline-size:1228.52;display:inline;fill:#000080;stroke-width:26.6984" x="1381.6643" y="1890.0889" id="text44" text-anchor="middle" transform="matrix(1.3203255,0,0,1.3203255,-1375.0262,-560.41607)"><tspan x="1381.6643" y="1890.0889" id="tspan27"><tspan style="text-align:end;text-anchor:end" id="tspan24">منتررف؛</tspan><tspan dx="212.47826" style="text-align:end;text-anchor:end" id="tspan25">٦٥</tspan><tspan dx="714.30957 -42.915234" style="text-align:end;text-anchor:end" id="tspan26">غفبممهت ورعبب</tspan><tspan y="1890.0889" id="tspan29"> </tspan></tspan><tspan x="1381.6643" y="1997.1678" id="tspan45"><tspan style="text-align:end;text-anchor:end" id="tspan30">٣٤٥٨</tspan><tspan dx="538.61511 0 0 0 0 25.01298 0 14.890675 -39.903576" style="text-align:end;text-anchor:end" id="tspan32">حخهـعنٌففڤك</tspan><tspan dx="296.26553" style="text-align:end;text-anchor:end" id="tspan33">٦</tspan><tspan dx="132.55197" style="text-align:end;text-anchor:end" id="tspan34">#</tspan><tspan dx="-47.641735" style="text-align:end;text-anchor:end" id="tspan35">٤</tspan><tspan dx="514.77338" style="text-align:end;text-anchor:end" id="tspan43">وحكهههـا؛جن</tspan></tspan></text>
|
|
23
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:67.9909px;font-family:'GohuFont 14 Nerd Font';-inkscape-font-specification:'GohuFont 14 Nerd Font, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.1905" x="604.13745" y="1147.0764" id="text45" text-anchor="middle"><tspan id="tspan44" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:67.9909px;font-family:'GohuFont 14 Nerd Font';-inkscape-font-specification:'GohuFont 14 Nerd Font, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.1905" x="604.13745" y="1147.0764">100% PURE SMIL تاكهعغفبقڤذطسببى٦٥!§|</tspan></text>
|
|
24
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:Phosphate;-inkscape-font-specification:'Phosphate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="536.83356" y="1861.4491" id="text47" transform="scale(0.71577068,1.3970955)" text-anchor="middle"><tspan id="tspan47" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:Phosphate;-inkscape-font-specification:'Phosphate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.6396" x="536.83356" y="1861.4491">No javascript or css needed!</tspan></text>
|
|
25
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:'ProFont IIx Nerd Font';-inkscape-font-specification:'ProFont IIx Nerd Font, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="747.38995" y="525.20264" id="text48" transform="matrix(0.71322166,-0.06035344,0.11780243,1.3921201,0,0)" text-anchor="middle"><tspan id="tspan48" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:'ProFont IIx Nerd Font';-inkscape-font-specification:'ProFont IIx Nerd Font, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.6396" x="747.39001" y="525.20264">No javascript or css needed!</tspan></text>
|
|
26
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Bodoni Ornaments';-inkscape-font-specification:'Bodoni Ornaments, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="472.37082" y="2838.6682" id="text49" text-anchor="middle"><tspan id="tspan49" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Bodoni Ornaments';-inkscape-font-specification:'Bodoni Ornaments, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="472.37082" y="2838.6682">No javascript or css needed!</tspan></text>
|
|
27
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="533.84888" y="530.25562" id="text50" text-anchor="middle"><tspan id="tspan50" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="533.84888" y="530.25562">No javascript or css needed!</tspan></text>
|
|
28
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Zapfino;-inkscape-font-specification:'Zapfino, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="584.37799" y="397.6167" id="text51" text-anchor="middle"><tspan id="tspan51" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Zapfino;-inkscape-font-specification:'Zapfino, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="584.37799" y="397.6167">No javascript or css needed!</tspan></text>
|
|
29
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Webdings;-inkscape-font-specification:'Webdings, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="449.30762" y="120.5267" id="text52" text-anchor="middle"><tspan id="tspan52" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Webdings;-inkscape-font-specification:'Webdings, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="449.30762" y="120.5267">No javascript or css needed!</tspan></text>
|
|
30
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Copperplate;-inkscape-font-specification:'Copperplate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="609.64258" y="246.02931" id="text53" text-anchor="middle"><tspan id="tspan53" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Copperplate;-inkscape-font-specification:'Copperplate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="609.64258" y="246.02931">No javascript or css needed!</tspan></text>
|
|
31
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Luminari;-inkscape-font-specification:'Luminari, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="450.42053" y="2729.5894" id="text54" text-anchor="middle"><tspan id="tspan54" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Sans;-inkscape-font-specification:'Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="450.42053" y="2729.5894">100% غعخيقفٌع٩ْخنتلو،حجةضصشيذزظطققثًار،منتزقُڤخهـرزلڤ</tspan></text>
|
|
32
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:302.923px;font-family:'.SF Arabic Rounded';-inkscape-font-specification:'.SF Arabic Rounded, @opsz=80,wght=510';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'opsz' 80, 'wght' 510;text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#808000;stroke-width:51.4717" x="-101.66634" y="477.18921" id="text4"><tspan id="tspan4" style="stroke-width:51.4717" x="-101.66634" y="477.18921">兛</tspan><tspan style="stroke-width:51.4717" x="-101.66634" y="864.82745" id="tspan5">瓩</tspan><tspan style="stroke-width:51.4717" x="-101.66634" y="1252.4657" id="tspan6">☞</tspan></text>
|
|
33
|
+
<path style="font-variation-settings:'opsz' 80, 'wght' 510;fill:none;stroke:#e40000;stroke-width:17.0854;stroke-dasharray:none;stroke-opacity:0.648148" d="m 1417.5151,346.27451 c -172.195,68.09973 -181.5149,120.68753 -227.2008,324.94298 -10.7474,48.04981 -1.555,122.34751 21.0816,166.07303 l 3.347,6.46516 c 40.3542,77.94932 296.6243,309.72422 275.2567,92.27938" id="path7" />
|
|
34
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;white-space:pre;fill:#000080;stroke-width:19.8645" id="text7" text-anchor="middle" transform="matrix(0.89589712,0,0,0.89589712,151.55716,65.666192)"><textPath xlink:href="#path7" startOffset="50%" id="textPath7"><tspan id="tspan7" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645">No javascript or css needed!</tspan></textPath></text>
|
|
35
|
+
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:268.424px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:2.43157;stroke-dasharray:none;stroke-opacity:0.648148" x="-50.072258" y="1466.8563" id="text8" transform="scale(0.86535508,1.155595)"><tspan id="tspan8" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:268.424px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:2.43157;stroke-dasharray:none" x="-50.072266" y="1466.8563">Λοπ</tspan></text>
|
|
36
|
+
<text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:300;font-stretch:normal;font-size:92.6956px;font-family:Superclarendon;-inkscape-font-specification:'Superclarendon, Light Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:0.839701;stroke-dasharray:none;stroke-opacity:0.648148" x="-41.03904" y="1797.0054" id="text9"><tspan id="tspan9" style="font-style:italic;font-variant:normal;font-weight:300;font-stretch:normal;font-size:92.6956px;font-family:Superclarendon;-inkscape-font-specification:'Superclarendon, Light Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:0.839701;stroke-dasharray:none" x="-41.039047" y="1797.0054">lkœtrëå</tspan></text>
|
|
37
|
+
<text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-decoration:underline;text-decoration-line:underline;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="1786.3558" y="997.44519" id="text22" transform="scale(0.71577068,1.3970955)" text-anchor="middle" text-decoration="underline"><tspan id="tspan23" x="1785.8699" y="997.44519" style="text-align:end;text-anchor:end"><tspan id="tspan22" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;text-anchor:end;fill:#000080;stroke-width:21.6396" x="1785.8699" y="997.44519">No javascript</tspan></tspan><tspan x="1785.8699" y="997.44519" id="tspan28"><tspan id="tspan36" style="text-align:end;text-anchor:end"><tspan style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;text-anchor:end;fill:#000080;stroke-width:21.6396" x="1785.8699" y="997.44519" id="tspan31"> </tspan></tspan></tspan><tspan x="1785.8699" y="1084.2356" id="tspan37">no css needed!</tspan></text>
|
|
38
|
+
</g>
|
|
39
|
+
</svg>
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @emasoft/svg-matrix - Arbitrary-precision matrix, vector and affine transformation library.
|
|
3
|
+
*
|
|
4
|
+
* This library provides Decimal-backed Matrix and Vector classes along with
|
|
5
|
+
* 2D (3x3) and 3D (4x4) transform helpers for geometry operations requiring high precision.
|
|
6
|
+
*
|
|
7
|
+
* @module @emasoft/svg-matrix
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { Decimal, Matrix, Vector, Transforms2D, Transforms3D } from '@emasoft/svg-matrix';
|
|
11
|
+
*
|
|
12
|
+
* // Set precision for all operations
|
|
13
|
+
* Decimal.set({ precision: 80 });
|
|
14
|
+
*
|
|
15
|
+
* // Create and compose 2D transforms
|
|
16
|
+
* const M = Transforms2D.translation(2, 3)
|
|
17
|
+
* .mul(Transforms2D.rotate(Math.PI / 4))
|
|
18
|
+
* .mul(Transforms2D.scale(1.5));
|
|
19
|
+
*
|
|
20
|
+
* // Apply to a point
|
|
21
|
+
* const [x, y] = Transforms2D.applyTransform(M, 1, 0);
|
|
22
|
+
* console.log('Transformed:', x.toString(), y.toString());
|
|
23
|
+
*/
|
|
24
|
+
|
|
1
25
|
import Decimal from 'decimal.js';
|
|
2
26
|
import { Matrix } from './matrix.js';
|
|
3
27
|
import { Vector } from './vector.js';
|
|
4
28
|
import * as Transforms2D from './transforms2d.js';
|
|
5
29
|
import * as Transforms3D from './transforms3d.js';
|
|
30
|
+
import * as SVGFlatten from './svg-flatten.js';
|
|
6
31
|
|
|
7
|
-
export { Decimal, Matrix, Vector, Transforms2D, Transforms3D };
|
|
32
|
+
export { Decimal, Matrix, Vector, Transforms2D, Transforms3D, SVGFlatten };
|