├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── demo └── index.js ├── index.js ├── lib ├── mat2d-stringify.js └── stringify.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | node_modules 3 | *.log 4 | .DS_Store 5 | bundle.js 6 | test 7 | test.js 8 | demo/ 9 | .npmignore 10 | LICENSE.md -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2015 Matt DesLauriers 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 20 | OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dom-css-transform 2 | 3 | [![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) 4 | 5 | Applies a CSS `transform` to a DOM element's style, accepting a string, array matrix, or discrete components to be recomposed according to [CSS3 transform spec](http://www.w3.org/TR/css3-transforms). Also handles vendor prefixing. 6 | 7 | ```js 8 | var transform = require('dom-css-transform') 9 | 10 | var div = document.createElement('div') 11 | 12 | //typical string style 13 | transform(div, 'translateX(25px) rotateX(25deg)') 14 | 15 | //a flat mat2d (9 elements) or mat4 (16 elements) array 16 | var matrix = [0.5, 0, 0, 0.25, 0, 0] 17 | transform(div, matrix) 18 | 19 | //results in 3D "matrix3d()" 20 | transform(div, { 21 | scale: [x, y, z], 22 | translate: [x, y, z] 23 | rotate: [x, y, z] 24 | }) 25 | 26 | //results in 2D "matrix()" 27 | transform(div, { 28 | rotate: [0, 0, -Math.PI], 29 | translate: [-15, 25], 30 | scale: [0.15, 0.5] 31 | }) 32 | // result --> "matrix(-0.15, 0, 0, -0.5, -15, 25)" 33 | 34 | //reset to identity 35 | transform(div, null) 36 | // result --> "none" 37 | ``` 38 | 39 | ## Usage 40 | 41 | [![NPM](https://nodei.co/npm/dom-css-transform.png)](https://www.npmjs.com/package/dom-css-transform) 42 | 43 | #### `transform(element, opt)` 44 | 45 | Applies a CSS transform to the given DOM `element`, using the specified options. Types supported: 46 | 47 | - `string` like `"translateX(25px) rotateZ(25deg)"` or `"matrix(0.5,0,0,1,0,0)"` 48 | - array of 16 elements (4x4 matrix) or 9 elements (3x2 matrix for 2D transformations) 49 | - an object with discrete components. 50 | - null or undefined, which leads to identity transform (i.e. `"none"`) 51 | 52 | When an object is specified, the result is a 4x4 matrix composed by [css-mat4](https://github.com/mattdesl/css-mat4). Options: 53 | 54 | - `translate` an array of `[x, y]` or `[x, y, z]` in pixels 55 | - `rotate` an array of `[x, y, z]` in radians 56 | - `scale` an array of `[x, y]` or `[x, y, z]` (z component defaults to 1) 57 | - `skew` an array of `[x, y]` in radians for a combined 2D skew matrix 58 | - `skewX`, `skewY` numbers in radians to mimic the independent CSS operations by the same name 59 | - `quaternion` can be specified if `rotation` is undefined; it's an array of `[x, y, z, w]` components 60 | 61 | ## License 62 | 63 | MIT, see [LICENSE.md](http://github.com/mattdesl/dom-css-transform/blob/master/LICENSE.md) for details. 64 | -------------------------------------------------------------------------------- /demo/index.js: -------------------------------------------------------------------------------- 1 | var transform = require('../') 2 | var css = require('dom-css') 3 | var tweenr = require('tweenr')() 4 | 5 | require('domready')(function() { 6 | var card = createCard() 7 | document.body.appendChild(card.container) 8 | 9 | //some properties to transform 10 | var xform = { 11 | translate: [20, 20], 12 | rotate: [0, 0, 0] 13 | } 14 | 15 | //create a tween that updates the CSS every tick 16 | tweenr.to(xform, { 17 | duration: 2, 18 | delay: 0.75, 19 | rotate: [Math.PI/4, 0, Math.PI/4], 20 | translate: [150, 100], 21 | ease: 'expoOut' 22 | }).on('update', update) 23 | 24 | //set initial state 25 | update() 26 | 27 | function update() { 28 | transform(card.child, xform) 29 | } 30 | }) 31 | 32 | function createCard() { 33 | var container = document.createElement('div') 34 | var div = document.createElement('div') 35 | container.appendChild(div) 36 | 37 | css(container, { 38 | position: 'absolute', 39 | top: 0, 40 | left: 0, 41 | transform: 'perspective(1000px)', 42 | transformStyle: 'preserve-3d' 43 | }) 44 | css(div, { 45 | width: 100, 46 | height: 100, 47 | background: 'blue' 48 | }) 49 | 50 | return { 51 | container: container, 52 | child: div 53 | } 54 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var css = require('dom-css') 2 | var stringify = require('./lib/stringify') 3 | var compose = require('css-mat4') 4 | var isArray = require('an-array') 5 | var identity = require('gl-mat4/identity') 6 | 7 | var tmpMat4 = identity([]) 8 | 9 | module.exports = function(element, value) { 10 | //is a flat array or matrix components 11 | if (value && typeof value === 'object') { 12 | //convert to flat array 13 | value = isArray(value) 14 | ? value 15 | : compose(tmpMat4, value) 16 | //stringify 17 | value = stringify(value) 18 | } 19 | 20 | //default to identity/none 21 | if (!value) 22 | value = 'none' 23 | css(element, 'transform', value) 24 | } -------------------------------------------------------------------------------- /lib/mat2d-stringify.js: -------------------------------------------------------------------------------- 1 | var scratch = new Array(6) 2 | for (var i=0; i<6; i++) 3 | scratch[i] = 0 4 | 5 | module.exports = function stringifyMat2d(matrix) { 6 | if (!matrix) 7 | return 'none' 8 | 9 | for (var i=0; i<6; i++) 10 | scratch[i] = Math.round(matrix[i]*1e15) / 1e15 11 | return 'matrix('+Array.prototype.join.call(scratch, ', ')+')' 12 | } -------------------------------------------------------------------------------- /lib/stringify.js: -------------------------------------------------------------------------------- 1 | var mat2d = require('./mat2d-stringify') 2 | var mat4 = require('mat4-css-stringify') 3 | 4 | module.exports = function(matrix) { 5 | var len = matrix && matrix.length 6 | if (len === 16) 7 | return mat4(matrix) 8 | else if (len === 6) 9 | return mat2d(matrix) 10 | return 'none' 11 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dom-css-transform", 3 | "version": "2.0.2", 4 | "description": "transforms a DOM element by string, matrix or components", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Matt DesLauriers", 9 | "email": "dave.des@gmail.com", 10 | "url": "https://github.com/mattdesl" 11 | }, 12 | "dependencies": { 13 | "an-array": "^1.0.0", 14 | "css-mat4": "^1.0.0", 15 | "dom-css": "^1.0.6", 16 | "gl-mat4": "^1.0.2", 17 | "mat4-css-stringify": "^1.0.1" 18 | }, 19 | "devDependencies": { 20 | "browserify": "^8.1.1", 21 | "domready": "^1.0.7", 22 | "prefix-style": "^1.0.0", 23 | "smokestack": "^3.2.0", 24 | "tap-closer": "^1.0.0", 25 | "tap-spec": "^2.2.0", 26 | "tape": "^3.5.0", 27 | "tweenr": "^2.1.3", 28 | "wzrd": "^1.2.1" 29 | }, 30 | "scripts": { 31 | "demo": "wzrd demo/index.js", 32 | "test": "browserify test.js | tap-closer | smokestack | tap-spec" 33 | }, 34 | "keywords": [ 35 | "css", 36 | "transform", 37 | "dom-style", 38 | "dom-css", 39 | "style", 40 | "styling", 41 | "3d", 42 | "2d", 43 | "scale", 44 | "translate", 45 | "translation", 46 | "position", 47 | "rotation", 48 | "rotate", 49 | "skew", 50 | "perspective" 51 | ], 52 | "repository": { 53 | "type": "git", 54 | "url": "git://github.com/mattdesl/dom-css-transform.git" 55 | }, 56 | "homepage": "https://github.com/mattdesl/dom-css-transform", 57 | "bugs": { 58 | "url": "https://github.com/mattdesl/dom-css-transform/issues" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var transform = require('./') 2 | var test = require('tape') 3 | var prefix = require('prefix-style') 4 | var css = require('dom-css') 5 | var mat4 = require('gl-mat4') 6 | 7 | test('composes a CSS transform matrix from components', function(t) { 8 | var div = document.body.appendChild(document.createElement('div')) 9 | 10 | transform(div, 'translateX(25px)') 11 | t.equal(compute(div), 'matrix(1, 0, 0, 1, 25, 0)', 'string transform') 12 | css(div, 'transform', null) 13 | 14 | transform(div, 'translateX(25px)') 15 | transform(div, null) 16 | t.equal(compute(div), 'none', 'null clears style to auto') 17 | 18 | transform(div, 'translateX(25px)') 19 | transform(div, 'none') 20 | t.equal(compute(div), 'none', 'none clears style to auto') 21 | 22 | var tmpMat4 = mat4.identity([]) 23 | mat4.translate(tmpMat4, tmpMat4, [5, 10, 30]) 24 | run(div, tmpMat4) 25 | t.equal(compute(div), 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5, 10, 30, 1)', 'mat4 with translation') 26 | 27 | var tmpMat2d = [-1, 2, -2, -1, 25, 15] 28 | run(div, tmpMat2d) 29 | t.equal(compute(div), 'matrix(-1, 2, -2, -1, 25, 15)', 'mat2d with rotation translation') 30 | 31 | run(div, { 32 | translate: [5, 10, 30] 33 | }) 34 | t.equal(compute(div), 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5, 10, 30, 1)', 'obj with translation') 35 | 36 | run(div, { 37 | rotate: [0, Math.PI/2, 0] 38 | }) 39 | t.equal(compute(div), 'matrix3d(0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1)', 'obj with rotation') 40 | 41 | run(div, { 42 | quaternion: [0, 0, 1, 1], 43 | translate: [25, 15] 44 | }) 45 | t.equal(compute(div), 'matrix(-1, 2, -2, -1, 25, 15)', 'mat3 with 2D quaternion rotation translation') 46 | 47 | run(div, { 48 | quaternion: [0, 0, 1, 1], 49 | translate: [25, 15, -5] 50 | }) 51 | t.equal(compute(div), 'matrix3d(-1, 2, 0, 0, -2, -1, 0, 0, 0, 0, 1, 0, 25, 15, -5, 1)', 'adding Z will make matrix3d') 52 | 53 | run(div, { 54 | scale: [-0.25, 0.5, 1], 55 | }) 56 | t.equal(compute(div), 'matrix(-0.25, 0, 0, 0.5, 0, 0)', 'scale in 2d') 57 | 58 | run(div, { 59 | scale: [-0.25, 0.5], 60 | }) 61 | t.equal(compute(div), 'matrix(-0.25, 0, 0, 0.5, 0, 0)', 'scale in 2d with 2 components') 62 | 63 | run(div, { 64 | skew: [0.25, -0.6], 65 | }) 66 | t.equal(compute(div), 'matrix(1, -0.684136808341692, 0.255341921221036, 1, 0, 0)', 'skew in 2d') 67 | 68 | run(div, { 69 | rotate: [0, 0, -Math.PI], 70 | translate: [-15, 25], 71 | scale: [0.15, 0.5] 72 | }) 73 | t.equal(compute(div), 'matrix(-0.15, 0, 0, -0.5, -15, 25)', 'transforms in 2d') 74 | 75 | document.body.removeChild(div) 76 | t.end() 77 | }) 78 | 79 | function run(element, opt) { 80 | transform(element, null) 81 | transform(element, opt) 82 | } 83 | 84 | function compute(element) { 85 | var prop = prefix('transform') 86 | return window.getComputedStyle(element, null)[prop] 87 | } --------------------------------------------------------------------------------