1 | <p align="center">
|
2 | <img width="120"src="https://jlmak.es/logos/svg/rematrix.svg?v=2">
|
3 | </p>
|
4 | <p align="center">Matrix transformation made easy.</p>
|
5 | <p align="center">
|
6 | <a href="https://travis-ci.org/jlmakes/rematrix"><img src="https://img.shields.io/travis/jlmakes/rematrix.svg" alt="Travis CI latest build status"></a>
|
7 | <a href="https://coveralls.io/github/jlmakes/rematrix"><img src="https://img.shields.io/coveralls/jlmakes/rematrix.svg" alt="Code coverage as an up-to-date percentage"></a>
|
8 | <a href="https://www.npmjs.com/package/rematrix"><img src="https://img.shields.io/npm/v/rematrix.svg" alt="Latest version released on Node Package Manager"></a>
|
9 | <img src="https://img.shields.io/badge/min+gzip-1.15KB-blue.svg" alt="">
|
10 | <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/npm/l/rematrix.svg" alt="MIT License"></a>
|
11 | </p>
|
12 | <p align="center">
|
13 | <a href="https://saucelabs.com/u/rematrix">
|
14 | <img src="https://saucelabs.com/browser-matrix/rematrix.svg" alt="MIT License">
|
15 | </a>
|
16 | </p>
|
17 |
|
18 | <br>
|
19 |
|
20 | <br>
|
21 |
|
22 | # Introduction
|
23 |
|
24 | Imagine a HTML element that may have a CSS transform applied. If we want to add 45° of Z-rotation, we have no way to handle this safely in CSS—we’d just risk overwriting an existing transform. So we decide to use JavaScript, and check the current transform...
|
25 |
|
26 | `getComputedStyle(element)` returns the computed styles, and inspecting the `transform` property shows:
|
27 |
|
28 | ```js
|
29 | 'matrix3d(0.707107, 0.707107, 0, 0, -0.707107, 0.707107, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)'
|
30 | ```
|
31 |
|
32 | It’s here we discover that browsers actually use [transformation matrices](https://en.wikipedia.org/wiki/Transformation_matrix) under the hood to describe rotation, translation, scale and shear. This means if we wish to manage CSS transforms with JavaScript (without overwriting existing transformations), we’re stuck working with matrices.
|
33 |
|
34 | **Rematrix** is an easy way to create and combine matrix transformations that work seamlessly with CSS.
|
35 |
|
36 | <br>
|
37 |
|
38 | # Installation
|
39 |
|
40 | ## Browser
|
41 |
|
42 | You can paste this snippet for the minified distribution directly into your page:
|
43 |
|
44 | ```html
|
45 | <script src="https://unpkg.com/rematrix/dist/rematrix.min.js"></script>
|
46 | ```
|
47 |
|
48 | This will create the global variable `Rematrix`.
|
49 |
|
50 | ## Module
|
51 |
|
52 | ```bash
|
53 | npm install rematrix --save
|
54 | ```
|
55 |
|
56 | #### CommonJS
|
57 |
|
58 | ```bash
|
59 | const Rematrix = require('rematrix')
|
60 | ```
|
61 |
|
62 | #### ES2015
|
63 |
|
64 | ```bash
|
65 | import * as Rematrix from 'rematrix'
|
66 | ```
|
67 |
|
68 | <br>
|
69 |
|
70 | # Guide
|
71 |
|
72 | <br>
|
73 |
|
74 | ## Creating Transforms
|
75 |
|
76 | Most API methods look a lot like CSS, so for example, in CSS if we would write `transform: rotateZ(45deg)`, we can create the same transformation in JavaScript using Rematrix like this:
|
77 |
|
78 | ```js
|
79 | Rematrix.rotateZ(45)
|
80 | ```
|
81 |
|
82 | This returns a 45° rotation along the Z-axis, represented as an array of 16 values:
|
83 |
|
84 | ```js
|
85 | [0.707107, 0.707107, 0, 0, -0.707107, 0.707107, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
86 | ```
|
87 |
|
88 | These 16 values represent our **transformation matrix** in [column-major order](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d).
|
89 |
|
90 | <br>
|
91 |
|
92 | ## Combining Transforms (Using Multiplication)
|
93 |
|
94 | Where Rematrix really outshines CSS, is the ability to combine transforms — using **matrix multiplication**. We’ll recreate the same 45° rotation along the Z-axis, but using separate matrices this time:
|
95 |
|
96 | ```js
|
97 | var r1 = Rematrix.rotateZ(20)
|
98 | var r2 = Rematrix.rotateZ(25)
|
99 |
|
100 | var product = Rematrix.multiply(r1, r2)
|
101 | ```
|
102 |
|
103 | Here `product` describes the same array of 16 values (seen above):
|
104 |
|
105 | ```js
|
106 | [0.707107, 0.707107, 0, 0, -0.707107, 0.707107, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
107 | ```
|
108 |
|
109 | #### Better Multiplication (Using Reduce)
|
110 |
|
111 | There’s a good chance we’ll need to multiply quite a few matrices together, so its helpful to store them in an array in order to use `Array.prototype.reduce` to multiply them all in one line:
|
112 |
|
113 | ```js
|
114 | var r1 = Rematrix.rotateZ(20)
|
115 | var r2 = Rematrix.rotateZ(65)
|
116 | var r3 = Rematrix.rotateZ(-40)
|
117 |
|
118 | var product = [r1, r2, r3].reduce(Rematrix.multiply)
|
119 | ```
|
120 |
|
121 | > Order is very important. For example, rotating 45° along the Z-axis, followed by translating 500 pixels along the Y-axis... is not the same as translating 500 pixels along the Y-axis, followed by rotating 45° along on the Z-axis.
|
122 |
|
123 | ## Preserving Transforms
|
124 |
|
125 | Before applying any of our transforms, we should capture the existing transform of our element using the `Rematrix.parse()` method:
|
126 |
|
127 | ```js
|
128 | var element = document.querySelector('#example')
|
129 | var style = getComputedStyle(element)['transform']
|
130 |
|
131 | var transform = Rematrix.parse(style)
|
132 |
|
133 | var r1 = Rematrix.rotateZ(20)
|
134 | var r2 = Rematrix.rotateZ(65)
|
135 | var r3 = Rematrix.rotateZ(-40)
|
136 |
|
137 | var product = [transform, r1, r2, r3].reduce(Rematrix.multiply)
|
138 | ```
|
139 |
|
140 | By simply passing the computed transform styles to `Rematrix.parse()`, we create a matrix of the existing transform. We can now factor this into our multiplication.
|
141 |
|
142 | > The existing transformation has been *deliberately* placed at the start of the array to ensure the computed transform is the foundation for the succeeding transformations.
|
143 |
|
144 |
|
145 | ## Applying Transforms
|
146 |
|
147 | We need only to turn our matrix back into a string of CSS:
|
148 |
|
149 | ```js
|
150 | var css = 'transform: matrix3d(' + product.join(', ') + ');'
|
151 | ```
|
152 |
|
153 | From here it’s up to you how to use the CSS, but for simplicity’s sake here, we’ll just apply it inline to our element:
|
154 |
|
155 | ```js
|
156 | element.setAttribute('style', css)
|
157 | ```
|
158 |
|
159 | #### _And that concludes this introduction to Rematrix. Please explore the finished [Live Demo on JSFiddle](https://jsfiddle.net/a8j2oyy5/)._
|
160 |
|
161 | <br>
|
162 |
|
163 | <a name="module_Rematrix"></a>
|
164 |
|
165 | # API Reference
|
166 |
|
167 | * [Rematrix](#module_Rematrix)
|
168 | * [.format(source)](#module_Rematrix.format)
|
169 | * [.identity()](#module_Rematrix.identity)
|
170 | * [.inverse(source)](#module_Rematrix.inverse)
|
171 | * [.multiply(m, x)](#module_Rematrix.multiply)
|
172 | * [.parse(source)](#module_Rematrix.parse)
|
173 | * [.rotateX(angle)](#module_Rematrix.rotateX)
|
174 | * [.rotateY(angle)](#module_Rematrix.rotateY)
|
175 | * [.rotateZ(angle)](#module_Rematrix.rotateZ)
|
176 | * [.scale(scalarX, [scalarY])](#module_Rematrix.scale)
|
177 | * [.scaleX(scalar)](#module_Rematrix.scaleX)
|
178 | * [.scaleY(scalar)](#module_Rematrix.scaleY)
|
179 | * [.scaleZ(scalar)](#module_Rematrix.scaleZ)
|
180 | * [.skew(angleX, [angleY])](#module_Rematrix.skew)
|
181 | * [.skewX(angle)](#module_Rematrix.skewX)
|
182 | * [.skewY(angle)](#module_Rematrix.skewY)
|
183 | * [.translate(distanceX, [distanceY])](#module_Rematrix.translate)
|
184 | * [.translateX(distance)](#module_Rematrix.translateX)
|
185 | * [.translateY(distance)](#module_Rematrix.translateY)
|
186 | * [.translateZ(distance)](#module_Rematrix.translateZ)
|
187 |
|
188 | <a name="module_Rematrix.format"></a>
|
189 |
|
190 | <br>
|
191 |
|
192 | ### Rematrix.format(source) ⇒ <code>array</code>
|
193 | Transformation matrices in the browser come in two flavors:
|
194 |
|
195 | - `matrix` using 6 values (short)
|
196 | - `matrix3d` using 16 values (long)
|
197 |
|
198 | This utility follows this [conversion guide](https://goo.gl/EJlUQ1)
|
199 | to expand short form matrices to their equivalent long form.
|
200 |
|
201 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
202 |
|
203 | | Param | Type | Description |
|
204 | | --- | --- | --- |
|
205 | | source | <code>array</code> | Accepts both short and long form matrices. |
|
206 |
|
207 | <a name="module_Rematrix.identity"></a>
|
208 |
|
209 | <br>
|
210 |
|
211 | ### Rematrix.identity() ⇒ <code>array</code>
|
212 | Returns a matrix representing no transformation. The product of any matrix
|
213 | multiplied by the identity matrix will be the original matrix.
|
214 |
|
215 | > **Tip:** Similar to how `5 * 1 === 5`, where `1` is the identity number.
|
216 |
|
217 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
218 | <a name="module_Rematrix.inverse"></a>
|
219 |
|
220 | <br>
|
221 |
|
222 | ### Rematrix.inverse(source) ⇒ <code>array</code>
|
223 | Returns a matrix describing the inverse transformation of the source
|
224 | matrix. When a transformation is combined with its inverse, the product
|
225 | is the identity matrix (ie. no transformation).
|
226 |
|
227 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
228 |
|
229 | | Param | Type | Description |
|
230 | | --- | --- | --- |
|
231 | | source | <code>array</code> | Accepts both short and long form matrices. |
|
232 |
|
233 | <a name="module_Rematrix.multiply"></a>
|
234 |
|
235 | <br>
|
236 |
|
237 | ### Rematrix.multiply(m, x) ⇒ <code>array</code>
|
238 | Returns a 4x4 matrix describing the combined transformations
|
239 | of both arguments.
|
240 |
|
241 | > **Note:** Order is very important. For example, rotating 45°
|
242 | along the Z-axis, followed by translating 500 pixels along the
|
243 | Y-axis... is not the same as translating 500 pixels along the
|
244 | Y-axis, followed by rotating 45° along on the Z-axis.
|
245 |
|
246 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
247 |
|
248 | | Param | Type | Description |
|
249 | | --- | --- | --- |
|
250 | | m | <code>array</code> | Accepts both short and long form matrices. |
|
251 | | x | <code>array</code> | Accepts both short and long form matrices. |
|
252 |
|
253 | <a name="module_Rematrix.parse"></a>
|
254 |
|
255 | <br>
|
256 |
|
257 | ### Rematrix.parse(source) ⇒ <code>array</code>
|
258 | Attempts to return a 4x4 matrix describing the CSS transform matrix passed
|
259 | in, but will return the identity matrix as a fallback.
|
260 |
|
261 | **Tip:** In virtually all cases, this method is used to convert a CSS matrix
|
262 | (retrieved as a string from computed styles) to its equivalent array format.
|
263 |
|
264 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
265 |
|
266 | | Param | Type | Description |
|
267 | | --- | --- | --- |
|
268 | | source | <code>string</code> | String containing a valid CSS `matrix` or `matrix3d` property. |
|
269 |
|
270 | <a name="module_Rematrix.rotateX"></a>
|
271 |
|
272 | <br>
|
273 |
|
274 | ### Rematrix.rotateX(angle) ⇒ <code>array</code>
|
275 | Returns a 4x4 matrix describing X-axis rotation.
|
276 |
|
277 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
278 |
|
279 | | Param | Type | Description |
|
280 | | --- | --- | --- |
|
281 | | angle | <code>number</code> | Measured in degrees. |
|
282 |
|
283 | <a name="module_Rematrix.rotateY"></a>
|
284 |
|
285 | <br>
|
286 |
|
287 | ### Rematrix.rotateY(angle) ⇒ <code>array</code>
|
288 | Returns a 4x4 matrix describing Y-axis rotation.
|
289 |
|
290 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
291 |
|
292 | | Param | Type | Description |
|
293 | | --- | --- | --- |
|
294 | | angle | <code>number</code> | Measured in degrees. |
|
295 |
|
296 | <a name="module_Rematrix.rotateZ"></a>
|
297 |
|
298 | <br>
|
299 |
|
300 | ### Rematrix.rotateZ(angle) ⇒ <code>array</code>
|
301 | Returns a 4x4 matrix describing Z-axis rotation.
|
302 |
|
303 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
304 |
|
305 | | Param | Type | Description |
|
306 | | --- | --- | --- |
|
307 | | angle | <code>number</code> | Measured in degrees. |
|
308 |
|
309 | <a name="module_Rematrix.scale"></a>
|
310 |
|
311 | <br>
|
312 |
|
313 | ### Rematrix.scale(scalarX, [scalarY]) ⇒ <code>array</code>
|
314 | Returns a 4x4 matrix describing 2D scaling. The first argument
|
315 | is used for both X and Y-axis scaling, unless an optional
|
316 | second argument is provided to explicitly define Y-axis scaling.
|
317 |
|
318 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
319 |
|
320 | | Param | Type | Description |
|
321 | | --- | --- | --- |
|
322 | | scalarX | <code>number</code> | Decimal multiplier. |
|
323 | | [scalarY] | <code>number</code> | Decimal multiplier. |
|
324 |
|
325 | <a name="module_Rematrix.scaleX"></a>
|
326 |
|
327 | <br>
|
328 |
|
329 | ### Rematrix.scaleX(scalar) ⇒ <code>array</code>
|
330 | Returns a 4x4 matrix describing X-axis scaling.
|
331 |
|
332 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
333 |
|
334 | | Param | Type | Description |
|
335 | | --- | --- | --- |
|
336 | | scalar | <code>number</code> | Decimal multiplier. |
|
337 |
|
338 | <a name="module_Rematrix.scaleY"></a>
|
339 |
|
340 | <br>
|
341 |
|
342 | ### Rematrix.scaleY(scalar) ⇒ <code>array</code>
|
343 | Returns a 4x4 matrix describing Y-axis scaling.
|
344 |
|
345 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
346 |
|
347 | | Param | Type | Description |
|
348 | | --- | --- | --- |
|
349 | | scalar | <code>number</code> | Decimal multiplier. |
|
350 |
|
351 | <a name="module_Rematrix.scaleZ"></a>
|
352 |
|
353 | <br>
|
354 |
|
355 | ### Rematrix.scaleZ(scalar) ⇒ <code>array</code>
|
356 | Returns a 4x4 matrix describing Z-axis scaling.
|
357 |
|
358 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
359 |
|
360 | | Param | Type | Description |
|
361 | | --- | --- | --- |
|
362 | | scalar | <code>number</code> | Decimal multiplier. |
|
363 |
|
364 | <a name="module_Rematrix.skew"></a>
|
365 |
|
366 | <br>
|
367 |
|
368 | ### Rematrix.skew(angleX, [angleY]) ⇒ <code>array</code>
|
369 | Returns a 4x4 matrix describing shear. The first argument as
|
370 | is used for both X and Y-axis shearing, unless an optional
|
371 | second argument is provided to explicitly define Y-axis shearing.
|
372 |
|
373 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
374 |
|
375 | | Param | Type | Description |
|
376 | | --- | --- | --- |
|
377 | | angleX | <code>number</code> | Measured in degrees. |
|
378 | | [angleY] | <code>number</code> | Measured in degrees. |
|
379 |
|
380 | <a name="module_Rematrix.skewX"></a>
|
381 |
|
382 | <br>
|
383 |
|
384 | ### Rematrix.skewX(angle) ⇒ <code>array</code>
|
385 | Returns a 4x4 matrix describing X-axis shear.
|
386 |
|
387 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
388 |
|
389 | | Param | Type | Description |
|
390 | | --- | --- | --- |
|
391 | | angle | <code>number</code> | Measured in degrees. |
|
392 |
|
393 | <a name="module_Rematrix.skewY"></a>
|
394 |
|
395 | <br>
|
396 |
|
397 | ### Rematrix.skewY(angle) ⇒ <code>array</code>
|
398 | Returns a 4x4 matrix describing Y-axis shear.
|
399 |
|
400 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
401 |
|
402 | | Param | Type | Description |
|
403 | | --- | --- | --- |
|
404 | | angle | <code>number</code> | Measured in degrees |
|
405 |
|
406 | <a name="module_Rematrix.translate"></a>
|
407 |
|
408 | <br>
|
409 |
|
410 | ### Rematrix.translate(distanceX, [distanceY]) ⇒ <code>array</code>
|
411 | Returns a 4x4 matrix describing 2D translation. The first argument
|
412 | is used for both X and Y-axis translation, unless an optional
|
413 | second argument is provided to explicitly define Y-axis translation.
|
414 |
|
415 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
416 |
|
417 | | Param | Type | Description |
|
418 | | --- | --- | --- |
|
419 | | distanceX | <code>number</code> | Measured in pixels. |
|
420 | | [distanceY] | <code>number</code> | Measured in pixels. |
|
421 |
|
422 | <a name="module_Rematrix.translateX"></a>
|
423 |
|
424 | <br>
|
425 |
|
426 | ### Rematrix.translateX(distance) ⇒ <code>array</code>
|
427 | Returns a 4x4 matrix describing X-axis translation.
|
428 |
|
429 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
430 |
|
431 | | Param | Type | Description |
|
432 | | --- | --- | --- |
|
433 | | distance | <code>number</code> | Measured in pixels. |
|
434 |
|
435 | <a name="module_Rematrix.translateY"></a>
|
436 |
|
437 | <br>
|
438 |
|
439 | ### Rematrix.translateY(distance) ⇒ <code>array</code>
|
440 | Returns a 4x4 matrix describing Y-axis translation.
|
441 |
|
442 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
443 |
|
444 | | Param | Type | Description |
|
445 | | --- | --- | --- |
|
446 | | distance | <code>number</code> | Measured in pixels. |
|
447 |
|
448 | <a name="module_Rematrix.translateZ"></a>
|
449 |
|
450 | <br>
|
451 |
|
452 | ### Rematrix.translateZ(distance) ⇒ <code>array</code>
|
453 | Returns a 4x4 matrix describing Z-axis translation.
|
454 |
|
455 | **Kind**: static method of <code>[Rematrix](#module_Rematrix)</code>
|
456 |
|
457 | | Param | Type | Description |
|
458 | | --- | --- | --- |
|
459 | | distance | <code>number</code> | Measured in pixels. |
|