diff --git a/example/index.html b/example/index.html index ccdf7c9..1b73df7 100644 --- a/example/index.html +++ b/example/index.html @@ -16,6 +16,14 @@ margin-bottom: 10px; padding: 10px; } + .section--transformed { + height: 50%; + transform: + scale(.5, 1) + translate(30px, 30%) + rotate(5deg) + skew(10deg, 30deg); + } @@ -25,7 +33,7 @@
-
+
@@ -50,7 +58,9 @@ unit, updateObject, updateStyles, - withEase + withEase, + getTransformStyle, + objectToFunctions } = A var $play = document.querySelector('.js-play') @@ -58,6 +68,23 @@ var $back = document.querySelector('.js-back') var $elastic = document.querySelector('.js-elastic') var $elasticTarget = document.querySelector('.js-elastic-target') + var $transformed = document.querySelector('.section--transformed') + + const transforms = getTransformStyle($transformed) + const transformsString = objectToFunctions(transforms) + const orginal = window.getComputedStyle($transformed, null).transform + let count = 0 + + setInterval(() => { + $transformed.style.transform = ((count + 1) % 2 === 0) + ? transformsString + : orginal + + count++ + }, 500) + + console.log(transforms) + console.log(transformsString) animate( number(0, 350), diff --git a/src/index.js b/src/index.js index 6ebfc7d..7c0879a 100644 --- a/src/index.js +++ b/src/index.js @@ -10,3 +10,7 @@ export { default as updateObject } from './update-object' export { default as updateStyles } from './update-styles' export { default as withEase } from './with-ease' export { version } from '../package.json' +export { default as decomposeMatrix } from './utils/decompose-matrix' +export * from './utils/css-functions' +export { default as getTransformStyle } from './utils/get-transform-style' +export { default as setTransformStyle } from './utils/set-transform-style' diff --git a/src/utils/css-functions.js b/src/utils/css-functions.js new file mode 100644 index 0000000..cd3785a --- /dev/null +++ b/src/utils/css-functions.js @@ -0,0 +1,29 @@ +const trim = (string) => string.trim() + +// +// (scale, [1, 2]) -> 'scale(1,2)' +// +export const formatAsFunction = (name, value) => `${name}(${value})` + +// +// { scale: [.5], translate: ['30px', '10px'], ... } +// -> 'scale(.5) translate(30px,10px) ...' +// +export const objectToFunctions = (object) => Object.keys(object) + .map((key) => formatAsFunction(key, object[key])) + .join(' ') + +// +// 'scale(.5) translate(30px, 10px) ...' +// -> { scale: [.5], translate: ['30px', '10px'], ... } +// +export const functionsToObject = (string) => string + .replace(/[()]/g, '_') + .split('_') + .map(trim) + .filter(v => v !== '') + .reduce((resultObject, key, index, source) => { + if ((index + 1) % 2 === 0) return resultObject + resultObject[key] = source[index + 1].split(',').map(trim) + return resultObject + }, {}) diff --git a/src/utils/decompose-matrix.js b/src/utils/decompose-matrix.js new file mode 100644 index 0000000..5416f7f --- /dev/null +++ b/src/utils/decompose-matrix.js @@ -0,0 +1,48 @@ +// https://github.com/d3/d3-interpolate/blob/fb86fe51be75408141dbdcb4fa38a7ff1b8c76bd/src/transform/decompose.js + +const { atan, atan2, sqrt, PI } = Math +const toDeg = (rad) => rad * (180 / PI) + +function decomposeMatrix (matrix) { + let [ a, b, c, d, e, f ] = matrix.map(v => Number(v)) + + let scaleX = sqrt(a * a + b * b) + if (scaleX) { + a /= scaleX + b /= scaleX + } + + let skewX = a * c + b * d + if (skewX) { + c -= a * skewX + d -= b * skewX + } + + let scaleY = sqrt(c * c + d * d) + if (scaleY) { + c /= scaleY + d /= scaleY + skewX /= scaleY + } + + if (a * d < b * c) { + a = -a + b = -b + skewX = -skewX + scaleX = -scaleX + } + + const rotationDeg = toDeg(atan2(b, a)) + const skewDeg = toDeg(atan(skewX)) + + return { + translateX: e + 'px', + translateY: f + 'px', + rotate: rotationDeg + 'deg', + skew: skewDeg + 'deg', + scaleX: scaleX, + scaleY: scaleY + } +} + +export default decomposeMatrix diff --git a/src/utils/get-style.js b/src/utils/get-style.js index 126607e..02c4818 100644 --- a/src/utils/get-style.js +++ b/src/utils/get-style.js @@ -1,8 +1,8 @@ import kebab from './kebab' -const getStyle = (el, prop) => { - if (prop in el.style) { - return window.getComputedStyle(el)[kebab(prop)] || 0 +const getStyle = ($el, prop) => { + if (prop in $el.style) { + return window.getComputedStyle($el, null)[kebab(prop)] || 0 } } diff --git a/src/utils/get-transform-style.js b/src/utils/get-transform-style.js new file mode 100644 index 0000000..1a6ff80 --- /dev/null +++ b/src/utils/get-transform-style.js @@ -0,0 +1,12 @@ +import decomposeMatrix from './decompose-matrix' +import { functionsToObject } from './css-functions' +import getStyle from './get-style' + +const getTransformStyle = ($el) => { + const value = getStyle($el, 'transform') + const { matrix, matrix3d } = functionsToObject(value) + if (!matrix && !matrix3d) return '' + return decomposeMatrix(matrix || matrix3d) +} + +export default getTransformStyle diff --git a/src/utils/set-style.js b/src/utils/set-style.js index 2a9539e..a5236e9 100644 --- a/src/utils/set-style.js +++ b/src/utils/set-style.js @@ -1,5 +1,5 @@ -const setStyle = (el, prop, value) => { - el.style[prop] = value +const setStyle = ($el, prop, value) => { + $el.style[prop] = value } export default setStyle diff --git a/src/utils/set-transform-style.js b/src/utils/set-transform-style.js new file mode 100644 index 0000000..c0d1fb5 --- /dev/null +++ b/src/utils/set-transform-style.js @@ -0,0 +1,32 @@ +import setStyle from './set-style' + +const TRANSFORM_KEY = 'transform' + +const INITITAL_TRANSFORM = { + rotate: '0deg', + rotateX: '0deg', + rotateY: '0deg', + rotateZ: '0deg', + skewX: '0deg', + skewY: '0deg', + scale: 1, + scaleX: 1, + scaleY: 1, + scaleZ: 1, + translate: 0, + translateX: 0, + translateY: 0, + translateZ: 0 +} + +const TRANSFORM_PROPS = Object.keys(INITITAL_TRANSFORM) + +export const isTransformProp = (prop) => (TRANSFORM_PROPS.indexOf(prop) !== -1) + +export const setTransformStyle = ($el, value, key = TRANSFORM_KEY) => { + const stringValue = value + + setStyle($el, key, stringValue) +} + +export default setTransformStyle