Open davidkpiano opened 7 years ago
Thanks for the kind words @davidkpiano, I appreciate it!
"Decomposition - probably a bigger feature ask, but a way to decompose a matrix and grab specific values such as translateX, skewY, rotateZ, scaleY, etc. from it?"
Now this is 🔥 and strikes me as a very powerful addition to the API. Some cursory research has revealed it should be possible using inverse trigonometric functions.
I think this would add the most value for developers. If you’re up for it, I think it would make an outstanding contribution.
Can you show how you imagine the decomposition API, and what the method(s) return?
Sure, and for reference the W3C has a decomposing algorithm.
Potential APIs:
Calling decompose
// From an array (2d or 3d)
Rematrix.decompose([0.5, -1, 1, 0.5, 10, -20]);
Rematrix.decompose([1.4, 0, -1.4, 0, 0.3, 2, 0, 0, 0.7, 0, 0.7, 0, 11.3, 0, -11.3, 1]);
// From a string
Rematrix.decompose("matrix(0.5, -1, 1, 0.5, 10, -20)")
Rematrix.decompose("matrix3d(1.4, 0, -1.4, 0, 0.3, 2, 0, 0, 0.7, 0, 0.7, 0, 11.3, 0, -11.3, 1)")
Potential return value shapes
// hierarchical
{
translate: { x: 10, y: 0, z: 0 },
rotate: { x: 40, y: -25, z: 16 },
skew: { x: 0, y: 0 },
scale: { x: 1, y: 1, z: 1 },
perspective: 0
}
// as 3d vectors
{
translate: [10, 0, 0],
rotate: [40, -25, 16],
// ... etc.
}
// verbose
{
translateX: 10,
translateY: 0,
translateZ: 0,
// ... etc.
}
From the above, I prefer either { x, y, z }
or [x, y, z]
format. I think hierarchical is more explicit but vectors is probably more useful to use in a wider range of use cases that can just accept a vector, e.g., for translate
.
Looks great. I think I’m learning towards the verbose model, because object keys then correspond to Rematrix method names (and facilitate an elegant compose()
method)
var decomposed = Rematrix.decompose(...)
/**
* decomposed === {
* translateX: 10,
* translateY: 0,
* translateZ: 0,
* ... etc.
* }
*/
function compose(decomposed) {
return Object.keys(decomposed)
.map(key => Rematrix[key](decomposed[key]))
.reduce(Rematrix.multiply)
}
What’s your impression of this?
I think verbose is fine, you make a good point of it mapping directly to CSS property names and Rematrix methods.
Wow, I took a quick look at the W3C algorithm, and it was frightening. Also, I'm rather curious about the order of operations for composition. I'll keep looking.
The CSS string would be handy too. I thought format(array)
was about it, but it seems it isn't.
I noticed the W3C CSS Transform Module document no longer included the 3D matrix decomposition sections. But thanks to WayBackMachine....
Example of the W3 implementation: https://github.com/facebook/react-native/blob/master/Libraries/Utilities/MatrixMath.js#L572
But I think the Facebook implementation has bugs (line duplicates? double check quaternions convetation) and also it's not optimized. There are a lot of unrequired arrays spawns.
Also, probably, perspective calc can be skipped?
And algorithm for the 3d matrix decomposition is moved here: https://www.w3.org/TR/css-transforms-2/
First of all, great job with this library - the code is well-documented and clear. I was up late last night looking for a good library for manipulating CSS transforms, and was very happy to find this one!
I was wondering if you would be open to the following (small) features? I can definitely help with some of them, let me know if you are willing to accept PRs on any of these.
[x] b45c121 —
Rematrix.toString([...])
for converting a matrix array to a CSS string.[x] 574e24e —
Rematrix.rotate(...)
that defaults toRematrix.rotateZ(...)
(re: CSS spec)[ ] ~Something that allows you to specify the unit for rotation, e.g.
Rematrix.rotate(0.5, 'rad')
perhaps?~ (Moved to #2)[ ] Decomposition: probably a bigger feature ask, but a way to decompose a matrix and grab specific values such as
translateX
,skewY
,rotateZ
,scaleY
, etc. from it?[x] 0817c2d — Typescript definition file
Thanks so much for this library!