Skip to content

Commit 759ee7c

Browse files
authored
perf(composeMatrix): 25% improv by restoring v5 implementation (#9851)
1 parent 938eae8 commit 759ee7c

File tree

3 files changed

+128
-18
lines changed

3 files changed

+128
-18
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

33
## [next]
4+
5+
- fix(util): restore old composeMatrix code for performances improvement [#9851](https://github.com/fabricjs/fabric.js/pull/9851)
46
- fix(Control): corner coords definition order [#9884](https://github.com/fabricjs/fabric.js/pull/9884)
57
- fix(Polyline): safeguard points arg from options [#9855](https://github.com/fabricjs/fabric.js/pull/9855)
68
- feat(IText): Adjust cursor blinking for better feedback [#9823](https://github.com/fabricjs/fabric.js/pull/9823)
+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { util } from '../../dist/index.mjs';
2+
3+
// perf(composeMatrix): 25% improv by restoring v5 implementation #9851
4+
5+
// OLD CODE FOR REFERENCE AND IMPLEMENTATION TEST
6+
7+
const util2 = { ...util };
8+
9+
util2.calcDimensionsMatrix = ({
10+
scaleX = 1,
11+
scaleY = 1,
12+
flipX = false,
13+
flipY = false,
14+
skewX = 0,
15+
skewY = 0,
16+
}) => {
17+
return util2.multiplyTransformMatrixArray(
18+
[
19+
util2.createScaleMatrix(
20+
flipX ? -scaleX : scaleX,
21+
flipY ? -scaleY : scaleY
22+
),
23+
skewX && util2.createSkewXMatrix(skewX),
24+
skewY && util2.createSkewYMatrix(skewY),
25+
],
26+
true
27+
);
28+
};
29+
30+
util2.composeMatrix = ({
31+
translateX = 0,
32+
translateY = 0,
33+
angle = 0,
34+
...otherOptions
35+
}) => {
36+
return util2.multiplyTransformMatrixArray([
37+
util2.createTranslateMatrix(translateX, translateY),
38+
angle && util2.createRotateMatrix({ angle }),
39+
util2.calcDimensionsMatrix(otherOptions),
40+
]);
41+
};
42+
43+
// END OF OLD CODE
44+
45+
const benchmark = (callback) => {
46+
const start = Date.now();
47+
callback();
48+
return Date.now() - start;
49+
};
50+
51+
const optionsComplex = {
52+
skewY: 10,
53+
skewX: 4,
54+
scaleX: 5,
55+
scaleY: 4,
56+
angle: 20,
57+
flipY: true,
58+
};
59+
60+
const simpleCase = {
61+
scaleX: 5,
62+
scaleY: 4,
63+
angle: 20,
64+
};
65+
66+
const complexOld = benchmark(() => {
67+
for (let i = 0; i < 1_000_000; i++) {
68+
util2.composeMatrix(optionsComplex);
69+
}
70+
});
71+
72+
const complexNew = benchmark(() => {
73+
for (let i = 0; i < 1_000_000; i++) {
74+
util.composeMatrix(optionsComplex);
75+
}
76+
});
77+
78+
console.log({ complexOld, complexNew });
79+
80+
const simpleOld = benchmark(() => {
81+
for (let i = 0; i < 1_000_000; i++) {
82+
util2.composeMatrix(simpleCase);
83+
}
84+
});
85+
86+
const simpleNew = benchmark(() => {
87+
for (let i = 0; i < 1_000_000; i++) {
88+
util.composeMatrix(simpleCase);
89+
}
90+
});
91+
92+
console.log({ simpleOld, simpleNew });
93+
94+
/**
95+
* On Node 18.17
96+
* { complexOld: 749, complexNew: 627 }
97+
* { simpleOld: 537, simpleNew: 374 }
98+
*/
99+
100+
/**
101+
* After removing the spread operator
102+
* { complexOld: 761, complexNew: 446 }
103+
* { simpleOld: 526, simpleNew: 271 }
104+
*/

src/util/misc/matrix.ts

+22-18
Original file line numberDiff line numberDiff line change
@@ -277,20 +277,24 @@ export const calcDimensionsMatrix = ({
277277
skewX = 0 as TDegree,
278278
skewY = 0 as TDegree,
279279
}: TScaleMatrixArgs) => {
280-
return multiplyTransformMatrixArray(
281-
[
282-
createScaleMatrix(flipX ? -scaleX : scaleX, flipY ? -scaleY : scaleY),
283-
skewX && createSkewXMatrix(skewX),
284-
skewY && createSkewYMatrix(skewY),
285-
],
286-
true
280+
let matrix = createScaleMatrix(
281+
flipX ? -scaleX : scaleX,
282+
flipY ? -scaleY : scaleY
287283
);
284+
if (skewX) {
285+
matrix = multiplyTransformMatrices(matrix, createSkewXMatrix(skewX), true);
286+
}
287+
if (skewY) {
288+
matrix = multiplyTransformMatrices(matrix, createSkewYMatrix(skewY), true);
289+
}
290+
return matrix;
288291
};
289292

290293
/**
291294
* Returns a transform matrix starting from an object of the same kind of
292295
* the one returned from qrDecompose, useful also if you want to calculate some
293296
* transformations from an object that is not enlived yet
297+
* Before changing this function look at: src/benchmarks/calcTransformMatrix.mjs
294298
* @param {Object} options
295299
* @param {Number} [options.angle]
296300
* @param {Number} [options.scaleX]
@@ -303,15 +307,15 @@ export const calcDimensionsMatrix = ({
303307
* @param {Number} [options.translateY]
304308
* @return {Number[]} transform matrix
305309
*/
306-
export const composeMatrix = ({
307-
translateX = 0,
308-
translateY = 0,
309-
angle = 0 as TDegree,
310-
...otherOptions
311-
}: TComposeMatrixArgs): TMat2D => {
312-
return multiplyTransformMatrixArray([
313-
createTranslateMatrix(translateX, translateY),
314-
angle && createRotateMatrix({ angle }),
315-
calcDimensionsMatrix(otherOptions),
316-
]);
310+
export const composeMatrix = (options: TComposeMatrixArgs): TMat2D => {
311+
const { translateX = 0, translateY = 0, angle = 0 as TDegree } = options;
312+
let matrix = createTranslateMatrix(translateX, translateY);
313+
if (angle) {
314+
matrix = multiplyTransformMatrices(matrix, createRotateMatrix({ angle }));
315+
}
316+
const scaleMatrix = calcDimensionsMatrix(options);
317+
if (!isIdentityMatrix(scaleMatrix)) {
318+
matrix = multiplyTransformMatrices(matrix, scaleMatrix);
319+
}
320+
return matrix;
317321
};

0 commit comments

Comments
 (0)