@js-draw/math 1.3.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Mat33.d.ts +1 -14
- package/dist/cjs/Mat33.js +1 -119
- package/dist/cjs/Mat33.test.d.ts +1 -0
- package/dist/mjs/Mat33.d.ts +1 -14
- package/dist/mjs/Mat33.mjs +1 -119
- package/dist/mjs/Mat33.test.d.ts +1 -0
- package/package.json +3 -3
- package/src/Mat33.ts +1 -1
package/dist/cjs/Mat33.d.ts
CHANGED
@@ -130,22 +130,9 @@ export declare class Mat33 {
|
|
130
130
|
/**
|
131
131
|
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
132
132
|
*
|
133
|
-
* @see {@link fromCSSMatrix}
|
133
|
+
* @see {@link fromCSSMatrix}
|
134
134
|
*/
|
135
135
|
toCSSMatrix(): string;
|
136
|
-
/**
|
137
|
-
* @beta May change or even be removed between minor releases.
|
138
|
-
*
|
139
|
-
* Converts this matrix into a list of CSS transforms that attempt to preserve
|
140
|
-
* this matrix's translation.
|
141
|
-
*
|
142
|
-
* In Chrome/Firefox, translation attributes only support 6 digits (likely an artifact
|
143
|
-
* of using lower-precision floating point numbers). This works around
|
144
|
-
* that by expanding this matrix into the product of several CSS transforms.
|
145
|
-
*
|
146
|
-
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
147
|
-
*/
|
148
|
-
toSafeCSSTransformList(): string;
|
149
136
|
/**
|
150
137
|
* Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33.
|
151
138
|
*
|
package/dist/cjs/Mat33.js
CHANGED
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Mat33 = void 0;
|
7
7
|
const Vec2_1 = require("./Vec2");
|
8
8
|
const Vec3_1 = __importDefault(require("./Vec3"));
|
9
|
-
const rounding_1 = require("./rounding");
|
10
9
|
/**
|
11
10
|
* Represents a three dimensional linear transformation or
|
12
11
|
* a two-dimensional affine transformation. (An affine transformation scales/rotates/shears
|
@@ -321,128 +320,11 @@ class Mat33 {
|
|
321
320
|
/**
|
322
321
|
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
323
322
|
*
|
324
|
-
* @see {@link fromCSSMatrix}
|
323
|
+
* @see {@link fromCSSMatrix}
|
325
324
|
*/
|
326
325
|
toCSSMatrix() {
|
327
326
|
return `matrix(${this.a1},${this.b1},${this.a2},${this.b2},${this.a3},${this.b3})`;
|
328
327
|
}
|
329
|
-
/**
|
330
|
-
* @beta May change or even be removed between minor releases.
|
331
|
-
*
|
332
|
-
* Converts this matrix into a list of CSS transforms that attempt to preserve
|
333
|
-
* this matrix's translation.
|
334
|
-
*
|
335
|
-
* In Chrome/Firefox, translation attributes only support 6 digits (likely an artifact
|
336
|
-
* of using lower-precision floating point numbers). This works around
|
337
|
-
* that by expanding this matrix into the product of several CSS transforms.
|
338
|
-
*
|
339
|
-
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
340
|
-
*/
|
341
|
-
toSafeCSSTransformList() {
|
342
|
-
// Check whether it's safe to return just the CSS matrix
|
343
|
-
const translation = Vec2_1.Vec2.of(this.a3, this.b3);
|
344
|
-
const translationRoundedX = (0, rounding_1.toRoundedString)(translation.x);
|
345
|
-
const translationRoundedY = (0, rounding_1.toRoundedString)(translation.y);
|
346
|
-
const nonDigitsRegex = /[^0-9]+/g;
|
347
|
-
const translationXDigits = translationRoundedX.replace(nonDigitsRegex, '').length;
|
348
|
-
const translationYDigits = translationRoundedY.replace(nonDigitsRegex, '').length;
|
349
|
-
// Is it safe to just return the default CSS matrix?
|
350
|
-
if (translationXDigits <= 5 && translationYDigits <= 5) {
|
351
|
-
return this.toCSSMatrix();
|
352
|
-
}
|
353
|
-
// Remove the last column (the translation column)
|
354
|
-
let transform = new Mat33(this.a1, this.a2, 0, this.b1, this.b2, 0, 0, 0, 1);
|
355
|
-
const transforms = [];
|
356
|
-
let lastScale = null;
|
357
|
-
// Appends a translate() command to the list of `transforms`.
|
358
|
-
const addTranslate = (translation) => {
|
359
|
-
lastScale = null;
|
360
|
-
if (!translation.eq(Vec2_1.Vec2.zero)) {
|
361
|
-
transforms.push(`translate(${(0, rounding_1.toRoundedString)(translation.x)}px, ${(0, rounding_1.toRoundedString)(translation.y)}px)`);
|
362
|
-
}
|
363
|
-
};
|
364
|
-
// Appends a scale() command to the list of transforms, possibly merging with
|
365
|
-
// the last command, if a scale().
|
366
|
-
const addScale = (scale) => {
|
367
|
-
// Merge with the last scale
|
368
|
-
if (lastScale) {
|
369
|
-
const newScale = lastScale.scale(scale);
|
370
|
-
// Don't merge if the new scale has very large values
|
371
|
-
if (newScale.maximumEntryMagnitude() < 1e7) {
|
372
|
-
const previousCommand = transforms.pop();
|
373
|
-
console.assert(previousCommand.startsWith('scale'), 'Invalid state: Merging scale commands');
|
374
|
-
scale = newScale;
|
375
|
-
}
|
376
|
-
}
|
377
|
-
if (scale.x === scale.y) {
|
378
|
-
transforms.push(`scale(${(0, rounding_1.toRoundedString)(scale.x)})`);
|
379
|
-
}
|
380
|
-
else {
|
381
|
-
transforms.push(`scale(${(0, rounding_1.toRoundedString)(scale.x)}, ${(0, rounding_1.toRoundedString)(scale.y)})`);
|
382
|
-
}
|
383
|
-
lastScale = scale;
|
384
|
-
};
|
385
|
-
// Returns the number of digits before the `.` in the given number string.
|
386
|
-
const digitsPreDecimalCount = (numberString) => {
|
387
|
-
let decimalIndex = numberString.indexOf('.');
|
388
|
-
if (decimalIndex === -1) {
|
389
|
-
decimalIndex = numberString.length;
|
390
|
-
}
|
391
|
-
return numberString.substring(0, decimalIndex).replace(nonDigitsRegex, '').length;
|
392
|
-
};
|
393
|
-
// Returns the number of digits (positive for left shift, negative for right shift)
|
394
|
-
// required to shift the decimal to the middle of the number.
|
395
|
-
const getShift = (numberString) => {
|
396
|
-
const preDecimal = digitsPreDecimalCount(numberString);
|
397
|
-
const postDecimal = (numberString.match(/[.](\d*)/) ?? ['', ''])[1].length;
|
398
|
-
// The shift required to center the decimal point.
|
399
|
-
const toCenter = postDecimal - preDecimal;
|
400
|
-
// toCenter is positive for a left shift (adding more pre-decimals),
|
401
|
-
// so, after applying it,
|
402
|
-
const postShiftPreDecimal = preDecimal + toCenter;
|
403
|
-
// We want the digits before the decimal to have a length at most 4, however.
|
404
|
-
// Thus, right shift until this is the case.
|
405
|
-
const shiftForAtMost5DigitsPreDecimal = 4 - Math.max(postShiftPreDecimal, 4);
|
406
|
-
return toCenter + shiftForAtMost5DigitsPreDecimal;
|
407
|
-
};
|
408
|
-
const addShiftedTranslate = (translate, depth = 0) => {
|
409
|
-
const xString = (0, rounding_1.toRoundedString)(translate.x);
|
410
|
-
const yString = (0, rounding_1.toRoundedString)(translate.y);
|
411
|
-
const xShiftDigits = getShift(xString);
|
412
|
-
const yShiftDigits = getShift(yString);
|
413
|
-
const shift = Vec2_1.Vec2.of(Math.pow(10, xShiftDigits), Math.pow(10, yShiftDigits));
|
414
|
-
const invShift = Vec2_1.Vec2.of(Math.pow(10, -xShiftDigits), Math.pow(10, -yShiftDigits));
|
415
|
-
addScale(invShift);
|
416
|
-
const shiftedTranslate = translate.scale(shift);
|
417
|
-
const roundedShiftedTranslate = Vec2_1.Vec2.of(Math.floor(shiftedTranslate.x), Math.floor(shiftedTranslate.y));
|
418
|
-
addTranslate(roundedShiftedTranslate);
|
419
|
-
// Don't recurse more than 3 times -- the more times we recurse, the more
|
420
|
-
// the scaling is influenced by error.
|
421
|
-
if (!roundedShiftedTranslate.eq(shiftedTranslate) && depth < 3) {
|
422
|
-
addShiftedTranslate(shiftedTranslate.minus(roundedShiftedTranslate), depth + 1);
|
423
|
-
}
|
424
|
-
addScale(shift);
|
425
|
-
return translate;
|
426
|
-
};
|
427
|
-
const adjustTransformFromScale = () => {
|
428
|
-
if (lastScale) {
|
429
|
-
const scaledTransform = transform.rightMul(Mat33.scaling2D(lastScale));
|
430
|
-
// If adding the scale to the transform leads to large values, avoid
|
431
|
-
// doing this.
|
432
|
-
if (scaledTransform.maximumEntryMagnitude() < 1e12) {
|
433
|
-
transforms.pop();
|
434
|
-
transform = transform.rightMul(Mat33.scaling2D(lastScale));
|
435
|
-
lastScale = null;
|
436
|
-
}
|
437
|
-
}
|
438
|
-
};
|
439
|
-
addShiftedTranslate(translation);
|
440
|
-
adjustTransformFromScale();
|
441
|
-
if (!transform.eq(Mat33.identity)) {
|
442
|
-
transforms.push(transform.toCSSMatrix());
|
443
|
-
}
|
444
|
-
return transforms.join(' ');
|
445
|
-
}
|
446
328
|
/**
|
447
329
|
* Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33.
|
448
330
|
*
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/dist/mjs/Mat33.d.ts
CHANGED
@@ -130,22 +130,9 @@ export declare class Mat33 {
|
|
130
130
|
/**
|
131
131
|
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
132
132
|
*
|
133
|
-
* @see {@link fromCSSMatrix}
|
133
|
+
* @see {@link fromCSSMatrix}
|
134
134
|
*/
|
135
135
|
toCSSMatrix(): string;
|
136
|
-
/**
|
137
|
-
* @beta May change or even be removed between minor releases.
|
138
|
-
*
|
139
|
-
* Converts this matrix into a list of CSS transforms that attempt to preserve
|
140
|
-
* this matrix's translation.
|
141
|
-
*
|
142
|
-
* In Chrome/Firefox, translation attributes only support 6 digits (likely an artifact
|
143
|
-
* of using lower-precision floating point numbers). This works around
|
144
|
-
* that by expanding this matrix into the product of several CSS transforms.
|
145
|
-
*
|
146
|
-
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
147
|
-
*/
|
148
|
-
toSafeCSSTransformList(): string;
|
149
136
|
/**
|
150
137
|
* Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33.
|
151
138
|
*
|
package/dist/mjs/Mat33.mjs
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import { Vec2 } from './Vec2.mjs';
|
2
2
|
import Vec3 from './Vec3.mjs';
|
3
|
-
import { toRoundedString } from './rounding.mjs';
|
4
3
|
/**
|
5
4
|
* Represents a three dimensional linear transformation or
|
6
5
|
* a two-dimensional affine transformation. (An affine transformation scales/rotates/shears
|
@@ -315,128 +314,11 @@ export class Mat33 {
|
|
315
314
|
/**
|
316
315
|
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
317
316
|
*
|
318
|
-
* @see {@link fromCSSMatrix}
|
317
|
+
* @see {@link fromCSSMatrix}
|
319
318
|
*/
|
320
319
|
toCSSMatrix() {
|
321
320
|
return `matrix(${this.a1},${this.b1},${this.a2},${this.b2},${this.a3},${this.b3})`;
|
322
321
|
}
|
323
|
-
/**
|
324
|
-
* @beta May change or even be removed between minor releases.
|
325
|
-
*
|
326
|
-
* Converts this matrix into a list of CSS transforms that attempt to preserve
|
327
|
-
* this matrix's translation.
|
328
|
-
*
|
329
|
-
* In Chrome/Firefox, translation attributes only support 6 digits (likely an artifact
|
330
|
-
* of using lower-precision floating point numbers). This works around
|
331
|
-
* that by expanding this matrix into the product of several CSS transforms.
|
332
|
-
*
|
333
|
-
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
334
|
-
*/
|
335
|
-
toSafeCSSTransformList() {
|
336
|
-
// Check whether it's safe to return just the CSS matrix
|
337
|
-
const translation = Vec2.of(this.a3, this.b3);
|
338
|
-
const translationRoundedX = toRoundedString(translation.x);
|
339
|
-
const translationRoundedY = toRoundedString(translation.y);
|
340
|
-
const nonDigitsRegex = /[^0-9]+/g;
|
341
|
-
const translationXDigits = translationRoundedX.replace(nonDigitsRegex, '').length;
|
342
|
-
const translationYDigits = translationRoundedY.replace(nonDigitsRegex, '').length;
|
343
|
-
// Is it safe to just return the default CSS matrix?
|
344
|
-
if (translationXDigits <= 5 && translationYDigits <= 5) {
|
345
|
-
return this.toCSSMatrix();
|
346
|
-
}
|
347
|
-
// Remove the last column (the translation column)
|
348
|
-
let transform = new Mat33(this.a1, this.a2, 0, this.b1, this.b2, 0, 0, 0, 1);
|
349
|
-
const transforms = [];
|
350
|
-
let lastScale = null;
|
351
|
-
// Appends a translate() command to the list of `transforms`.
|
352
|
-
const addTranslate = (translation) => {
|
353
|
-
lastScale = null;
|
354
|
-
if (!translation.eq(Vec2.zero)) {
|
355
|
-
transforms.push(`translate(${toRoundedString(translation.x)}px, ${toRoundedString(translation.y)}px)`);
|
356
|
-
}
|
357
|
-
};
|
358
|
-
// Appends a scale() command to the list of transforms, possibly merging with
|
359
|
-
// the last command, if a scale().
|
360
|
-
const addScale = (scale) => {
|
361
|
-
// Merge with the last scale
|
362
|
-
if (lastScale) {
|
363
|
-
const newScale = lastScale.scale(scale);
|
364
|
-
// Don't merge if the new scale has very large values
|
365
|
-
if (newScale.maximumEntryMagnitude() < 1e7) {
|
366
|
-
const previousCommand = transforms.pop();
|
367
|
-
console.assert(previousCommand.startsWith('scale'), 'Invalid state: Merging scale commands');
|
368
|
-
scale = newScale;
|
369
|
-
}
|
370
|
-
}
|
371
|
-
if (scale.x === scale.y) {
|
372
|
-
transforms.push(`scale(${toRoundedString(scale.x)})`);
|
373
|
-
}
|
374
|
-
else {
|
375
|
-
transforms.push(`scale(${toRoundedString(scale.x)}, ${toRoundedString(scale.y)})`);
|
376
|
-
}
|
377
|
-
lastScale = scale;
|
378
|
-
};
|
379
|
-
// Returns the number of digits before the `.` in the given number string.
|
380
|
-
const digitsPreDecimalCount = (numberString) => {
|
381
|
-
let decimalIndex = numberString.indexOf('.');
|
382
|
-
if (decimalIndex === -1) {
|
383
|
-
decimalIndex = numberString.length;
|
384
|
-
}
|
385
|
-
return numberString.substring(0, decimalIndex).replace(nonDigitsRegex, '').length;
|
386
|
-
};
|
387
|
-
// Returns the number of digits (positive for left shift, negative for right shift)
|
388
|
-
// required to shift the decimal to the middle of the number.
|
389
|
-
const getShift = (numberString) => {
|
390
|
-
const preDecimal = digitsPreDecimalCount(numberString);
|
391
|
-
const postDecimal = (numberString.match(/[.](\d*)/) ?? ['', ''])[1].length;
|
392
|
-
// The shift required to center the decimal point.
|
393
|
-
const toCenter = postDecimal - preDecimal;
|
394
|
-
// toCenter is positive for a left shift (adding more pre-decimals),
|
395
|
-
// so, after applying it,
|
396
|
-
const postShiftPreDecimal = preDecimal + toCenter;
|
397
|
-
// We want the digits before the decimal to have a length at most 4, however.
|
398
|
-
// Thus, right shift until this is the case.
|
399
|
-
const shiftForAtMost5DigitsPreDecimal = 4 - Math.max(postShiftPreDecimal, 4);
|
400
|
-
return toCenter + shiftForAtMost5DigitsPreDecimal;
|
401
|
-
};
|
402
|
-
const addShiftedTranslate = (translate, depth = 0) => {
|
403
|
-
const xString = toRoundedString(translate.x);
|
404
|
-
const yString = toRoundedString(translate.y);
|
405
|
-
const xShiftDigits = getShift(xString);
|
406
|
-
const yShiftDigits = getShift(yString);
|
407
|
-
const shift = Vec2.of(Math.pow(10, xShiftDigits), Math.pow(10, yShiftDigits));
|
408
|
-
const invShift = Vec2.of(Math.pow(10, -xShiftDigits), Math.pow(10, -yShiftDigits));
|
409
|
-
addScale(invShift);
|
410
|
-
const shiftedTranslate = translate.scale(shift);
|
411
|
-
const roundedShiftedTranslate = Vec2.of(Math.floor(shiftedTranslate.x), Math.floor(shiftedTranslate.y));
|
412
|
-
addTranslate(roundedShiftedTranslate);
|
413
|
-
// Don't recurse more than 3 times -- the more times we recurse, the more
|
414
|
-
// the scaling is influenced by error.
|
415
|
-
if (!roundedShiftedTranslate.eq(shiftedTranslate) && depth < 3) {
|
416
|
-
addShiftedTranslate(shiftedTranslate.minus(roundedShiftedTranslate), depth + 1);
|
417
|
-
}
|
418
|
-
addScale(shift);
|
419
|
-
return translate;
|
420
|
-
};
|
421
|
-
const adjustTransformFromScale = () => {
|
422
|
-
if (lastScale) {
|
423
|
-
const scaledTransform = transform.rightMul(Mat33.scaling2D(lastScale));
|
424
|
-
// If adding the scale to the transform leads to large values, avoid
|
425
|
-
// doing this.
|
426
|
-
if (scaledTransform.maximumEntryMagnitude() < 1e12) {
|
427
|
-
transforms.pop();
|
428
|
-
transform = transform.rightMul(Mat33.scaling2D(lastScale));
|
429
|
-
lastScale = null;
|
430
|
-
}
|
431
|
-
}
|
432
|
-
};
|
433
|
-
addShiftedTranslate(translation);
|
434
|
-
adjustTransformFromScale();
|
435
|
-
if (!transform.eq(Mat33.identity)) {
|
436
|
-
transforms.push(transform.toCSSMatrix());
|
437
|
-
}
|
438
|
-
return transforms.join(' ');
|
439
|
-
}
|
440
322
|
/**
|
441
323
|
* Converts a CSS-form `matrix(a, b, c, d, e, f)` to a Mat33.
|
442
324
|
*
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@js-draw/math",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.6.0",
|
4
4
|
"description": "A math library for js-draw. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -28,7 +28,7 @@
|
|
28
28
|
"bezier-js": "6.1.3"
|
29
29
|
},
|
30
30
|
"devDependencies": {
|
31
|
-
"@js-draw/build-tool": "^1.0
|
31
|
+
"@js-draw/build-tool": "^1.4.0",
|
32
32
|
"@types/bezier-js": "4.1.0",
|
33
33
|
"@types/jest": "29.5.3",
|
34
34
|
"@types/jsdom": "21.1.1"
|
@@ -45,5 +45,5 @@
|
|
45
45
|
"svg",
|
46
46
|
"math"
|
47
47
|
],
|
48
|
-
"gitHead": "
|
48
|
+
"gitHead": "c2278b6819ca0e464e4e7d2c3c2045e3394b1fe8"
|
49
49
|
}
|
package/src/Mat33.ts
CHANGED
@@ -423,7 +423,7 @@ export class Mat33 {
|
|
423
423
|
/**
|
424
424
|
* **Note**: Assumes `this.c1 = this.c2 = 0` and `this.c3 = 1`.
|
425
425
|
*
|
426
|
-
* @see {@link fromCSSMatrix}
|
426
|
+
* @see {@link fromCSSMatrix}
|
427
427
|
*/
|
428
428
|
public toCSSMatrix(): string {
|
429
429
|
return `matrix(${this.a1},${this.b1},${this.a2},${this.b2},${this.a3},${this.b3})`;
|