Last active
May 29, 2017 11:09
-
-
Save Akiyamka/184c8fb470cf21933aba19a54c82d65c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<title>Made with Thimble</title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<div id="wraper"> | |
<div class="column one"> | |
1 | |
</div> | |
<div class="column two"> | |
2 | |
</div> | |
<div class="column three"> | |
3 | |
</div> | |
</div> | |
<script src="kute.js"></script> | |
<script src="script.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* KUTE.js - The Light Tweening Engine | |
* by dnp_theme | |
* Licensed under MIT-License | |
*/ | |
(function (root,factory) { | |
if (typeof define === 'function' && define.amd) { | |
define([], factory); // AMD. Register as an anonymous module. | |
} else if (typeof exports == 'object') { | |
module.exports = factory(); // Node, not strict CommonJS | |
} else { | |
root.KUTE = factory(); | |
} | |
}(this, function () { | |
"use strict"; | |
// set a custom scope for KUTE.js | |
var g = typeof global !== 'undefined' ? global : window, time = g.performance, | |
body = document.body, tweens = [], tick = null, // tick must be null!! | |
// strings | |
length = 'length', | |
split = 'split', | |
indexOf = 'indexOf', | |
replace = 'replace', | |
offsetWidth = 'offsetWidth', | |
offsetHeight = 'offsetHeight', | |
options = 'options', | |
valuesStart = 'valuesStart', | |
valuesEnd = 'valuesEnd', | |
valuesRepeat = 'valuesRepeat', | |
element = 'element', | |
playing = 'playing', | |
duration = 'duration', | |
delay = 'delay', | |
offset = 'offset', | |
repeat = 'repeat', | |
repeatDelay = 'repeatDelay', | |
yoyo = 'yoyo', | |
easing = 'easing', | |
chain = 'chain', | |
keepHex = 'keepHex', | |
style = 'style', | |
dataTweening = 'data-tweening', | |
getElementsByTagName = 'getElementsByTagName', | |
addEventListener = 'addEventListener', | |
removeEventListener = 'removeEventListener'; | |
//supported properties | |
var colorProps = ['color', 'backgroundColor'], // 'hex', 'rgb', 'rgba' '#fff' 'rgb(0,0,0)' / 'rgba(0,0,0,0)' 'red' (IE9+) | |
boxModelProps = ['top', 'left', 'width', 'height'], | |
transformFunctions = ['translate3d', 'translateX', 'translateY', 'translateZ', 'rotate', 'translate', 'rotateX', 'rotateY', 'rotateZ', 'skewX', 'skewY', 'scale'], | |
scrollProp = ['scroll'], // has no default value, it's calculated on tween start | |
opacityProp = ['opacity'], // opacity | |
coreProps = colorProps.concat( opacityProp, boxModelProps, transformFunctions), | |
defaultPropsValues = {}; | |
//populate default values object | |
for ( var propertyIndex=0, allCorePropLength = coreProps[length], coreProp; propertyIndex < allCorePropLength; propertyIndex++ ){ | |
coreProp = coreProps[propertyIndex]; | |
if (colorProps[indexOf](coreProp) !== -1){ | |
defaultPropsValues[coreProp] = 'rgba(0,0,0,0)'; // defaultPropsValues[coreProp] = {r:0,g:0,b:0,a:1}; | |
} else if ( boxModelProps[indexOf](coreProp) !== -1 ) { | |
defaultPropsValues[coreProp] = 0; | |
} else if ( coreProp === 'translate3d' ){ // px | |
defaultPropsValues[coreProp] = [0,0,0]; | |
} else if ( coreProp === 'translate' ){ // px | |
defaultPropsValues[coreProp] = [0,0]; | |
} else if ( coreProp === 'rotate' || /X|Y|Z/.test(coreProp) ){ // deg | |
defaultPropsValues[coreProp] = 0; | |
} else if ( coreProp === 'scale' || coreProp === 'opacity' ){ // unitless | |
defaultPropsValues[coreProp] = 1; | |
} | |
} | |
// default tween options, since 1.6.1 | |
var defaultOptions = { | |
duration: 700, | |
delay: 0, | |
offset: 0, | |
repeat: 0, | |
repeatDelay: 0, | |
yoyo: false, | |
easing: 'linear', | |
keepHex: false, | |
}, | |
// tools / utils | |
getPrefix = function() { //returns browser prefix | |
var prefixes = ['Moz', 'moz', 'Webkit', 'webkit', 'O', 'o', 'Ms', 'ms'], thePrefix; | |
for (var pIndex = 0, pfl = prefixes[length]; pIndex < pfl; pIndex++) { | |
if (prefixes[pIndex]+'Transform' in body[style]) { thePrefix = prefixes[pIndex]; break; } | |
} | |
return thePrefix; | |
}, | |
property = function(propertyToPrefix){ // returns prefixed property | property | |
var prefixRequired = (!(propertyToPrefix in body[style])) ? true : false, prefix = getPrefix(); // is prefix required for property | prefix | |
return prefixRequired ? prefix + (propertyToPrefix.charAt(0).toUpperCase() + propertyToPrefix.slice(1)) : propertyToPrefix; | |
}, | |
selector = function(el,multi){ // a public selector utility | |
var requestedElem; | |
if (multi){ | |
requestedElem = el instanceof Object || typeof el === 'object' ? el : document.querySelectorAll(el); | |
} else { | |
requestedElem = typeof el === 'object' ? el : document.querySelector(el); | |
} | |
if (requestedElem === null && el !== 'window') throw new TypeError('Element not found or incorrect selector: '+el); | |
return requestedElem; | |
}, | |
radToDeg = function(a) { return a*180/Math.PI; }, | |
trueDimension = function (dimValue,isAngle) { //true dimension returns { v = value, u = unit } | |
var intValue = parseInt(dimValue) || 0, mUnits = ['px','%','deg','rad','em','rem','vh','vw'], theUnit; | |
for (var mIndex=0; mIndex<mUnits[length]; mIndex++) { | |
if ( typeof dimValue === 'string' && dimValue[indexOf](mUnits[mIndex]) !== -1 ) { | |
theUnit = mUnits[mIndex]; break; | |
} | |
} | |
theUnit = theUnit !== undefined ? theUnit : (isAngle ? 'deg' : 'px'); | |
return { v: intValue, u: theUnit }; | |
}, | |
trueColor = function (colorString) { // replace transparent and transform any color to rgba()/rgb() | |
if (/rgb|rgba/.test(colorString)) { // first check if it's a rgb string | |
var vrgb = colorString[replace](/\s|\)/,'')[split]('(')[1][split](','), colorAlpha = vrgb[3] ? vrgb[3] : null; | |
if (!colorAlpha) { | |
return { r: parseInt(vrgb[0]), g: parseInt(vrgb[1]), b: parseInt(vrgb[2]) }; | |
} else { | |
return { r: parseInt(vrgb[0]), g: parseInt(vrgb[1]), b: parseInt(vrgb[2]), a: parseFloat(colorAlpha) }; | |
} | |
} else if (/^#/.test(colorString)) { | |
var fromHex = hexToRGB(colorString); return { r: fromHex.r, g: fromHex.g, b: fromHex.b }; | |
} else if (/transparent|none|initial|inherit/.test(colorString)) { | |
return { r: 0, g: 0, b: 0, a: 0 }; | |
} else if (!/^#|^rgb/.test(colorString) ) { // maybe we can check for web safe colors | |
var siteHead = document[getElementsByTagName]('head')[0]; siteHead[style].color = colorString; | |
var webColor = g.getComputedStyle(siteHead,null).color; webColor = /rgb/.test(webColor) ? webColor[replace](/[^\d,]/g, '')[split](',') : [0,0,0]; | |
siteHead[style].color = ''; return { r: parseInt(webColor[0]), g: parseInt(webColor[1]), b: parseInt(webColor[2]) }; | |
} | |
}, | |
rgbToHex = function (r, g, b) { // transform rgb to hex or vice-versa | webkit browsers ignore HEX, always use RGB/RGBA | |
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); | |
}, | |
hexToRGB = function (hex) { | |
var hexShorthand = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") | |
hex = hex[replace](hexShorthand, function (m, r, g, b) { | |
return r + r + g + g + b + b; | |
}); | |
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); | |
return result ? { | |
r: parseInt(result[1], 16), | |
g: parseInt(result[2], 16), | |
b: parseInt(result[3], 16) | |
} : null; | |
}, | |
getInlineStyle = function(el) { // get transform style for element from cssText for .to() method, the sp is for transform property | |
if (!el) return; // if the scroll applies to `window` it returns as it has no styling | |
var css = el[style].cssText[replace](/\s/g,'')[split](';'), transformObject = {}; // the cssText | the resulting transform object | |
// if we have any inline style in the cssText attribute, usually it has higher priority | |
for ( var i=0, csl = css[length]; i<csl; i++ ){ | |
if ( /transform/i.test(css[i])) { | |
var tps = css[i][split](':')[1][split](')'); //all transform properties | |
for ( var k=0, tpl = tps[length]-1; k< tpl; k++){ | |
var tpv = tps[k][split]('('), tp = tpv[0], tv = tpv[1]; //each transform property | |
if ( transformFunctions[indexOf](tp) !== -1 ){ | |
transformObject[tp] = /translate3d/.test(tp) ? tv[split](',') : tv; | |
} | |
} | |
} | |
} | |
return transformObject; | |
}, | |
getCurrentStyle = function (elem,propertyName) { // get computed style property for element for .to() method | |
var styleAttribute = elem[style], computedStyle = g.getComputedStyle(elem,null) || elem.currentStyle, | |
prefixedProp = property(propertyName), //the computed style | prefixed property | |
styleValue = styleAttribute[propertyName] && !/auto|initial|none|unset/.test(styleAttribute[propertyName]) ? styleAttribute[propertyName] : computedStyle[prefixedProp]; // s the property style value | |
if ( propertyName !== 'transform' && (prefixedProp in computedStyle || prefixedProp in styleAttribute) ) { | |
if ( styleValue ){ | |
if (prefixedProp === 'filter') { // handle IE8 opacity | |
var filterValue = parseInt(styleValue[split]('=')[1][replace](')','')); | |
return parseFloat(filterValue/100); | |
} else { | |
return styleValue; | |
} | |
} else { | |
return defaultPropsValues[propertyName]; | |
} | |
} | |
}, | |
//more internals | |
getAll = function () { return tweens; }, | |
removeAll = function () { tweens = []; }, | |
add = function (tw) { tweens.push(tw); }, | |
remove = function (tw) { var i = tweens[indexOf](tw); if (i !== -1) { tweens.splice(i, 1); }}, | |
stop = function () { if (tick) { _cancelAnimationFrame(tick); tick = null; } }, | |
canTouch = ('ontouchstart' in g || navigator && navigator.msMaxTouchPoints) || false, // support Touch? | |
touchOrWheel = canTouch ? 'touchstart' : 'mousewheel', mouseEnter = 'mouseenter', //events to prevent on scroll | |
_requestAnimationFrame = g.requestAnimationFrame || g.webkitRequestAnimationFrame || function (c) { return setTimeout(c, 16) }, | |
_cancelAnimationFrame = g.cancelAnimationFrame || g.webkitCancelRequestAnimationFrame || function (c) { return clearTimeout(c) }, | |
transformProperty = property('transform'), | |
// true scroll container | |
html = document[getElementsByTagName]('HTML')[0], | |
scrollContainer = navigator && /webkit/i.test(navigator.userAgent) || document.compatMode == 'BackCompat' ? body : html, | |
// browser detection | |
isIE = navigator && (new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) !== null) ? parseFloat( RegExp.$1 ) : false, | |
isIE8 = isIE === 8, // check IE8/IE | |
isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); // we optimize morph depending on device type | |
// KUTE.js INTERPOLATORS | |
var interpolate = g.Interpolate = {}, | |
number = interpolate.number = function(a,b,v) { // number1, number2, progress | |
a = +a; b -= a; return a + b * v; | |
}, | |
unit = interpolate.unit = function(a,b,u,v) { // number1, number2, unit, progress | |
a = +a; b -= a; return ( a + b * v ) + u; | |
}, | |
color = interpolate.color = function(a,b,v,toHex){ // rgba1, rgba2, progress, convertToHex(true/false) | |
var _c = {}, c, ep = ')', cm =',', rgb = 'rgb(', rgba = 'rgba('; | |
for (c in b) { _c[c] = c !== 'a' ? (number(a[c],b[c],v)>>0 || 0) : (a[c] && b[c]) ? (number(a[c],b[c],v) * 100 >> 0 )/100 : null; } | |
return toHex ? rgbToHex( _c.r, _c.g, _c.b ) : !_c.a ? rgb + _c.r + cm + _c.g + cm + _c.b + ep : rgba + _c.r + cm + _c.g + cm + _c.b + cm + _c.a + ep; | |
}, | |
translate = interpolate.translate = isMobile ? function (a,b,u,v){ | |
var translation = {}; | |
for (var ax in b){ | |
translation[ax] = ( a[ax]===b[ax] ? b[ax] : (a[ax] + ( b[ax] - a[ax] ) * v ) >> 0 ) + u; | |
} | |
return translation.x||translation.y ? 'translate(' + translation.x + ',' + translation.y + ')' : | |
'translate3d(' + translation.translateX + ',' + translation.translateY + ',' + translation.translateZ + ')'; | |
} : function (a,b,u,v){ | |
var translation = {}; | |
for (var ax in b){ | |
translation[ax] = ( a[ax]===b[ax] ? b[ax] : ( (a[ax] + ( b[ax] - a[ax] ) * v ) * 100 >> 0 ) / 100 ) + u; | |
} | |
return translation.x||translation.y ? 'translate(' + translation.x + ',' + translation.y + ')' : | |
'translate3d(' + translation.translateX + ',' + translation.translateY + ',' + translation.translateZ + ')'; | |
}, | |
rotate = interpolate.rotate = function (a,b,u,v){ | |
var rotation = {}; | |
for ( var rx in b ){ | |
rotation[rx] = rx === 'z' ? ('rotate('+ (((a[rx] + (b[rx] - a[rx]) * v) * 100 >> 0 ) / 100) + u + ')') | |
: (rx + '(' + (((a[rx] + (b[rx] - a[rx]) * v) * 100 >> 0 ) / 100) + u + ')'); | |
} | |
return rotation.z ? rotation.z : (rotation.rotateX||'') + (rotation.rotateY||'') + (rotation.rotateZ||''); | |
}, | |
skew = interpolate.skew = function (a,b,u,v){ | |
var skewProp = {}; | |
for ( var sx in b ){ | |
skewProp[sx] = sx + '(' + (((a[sx] + (b[sx] - a[sx]) * v) * 10 >> 0) / 10) + u + ')'; | |
} | |
return (skewProp.skewX||'') + (skewProp.skewY||''); | |
}, | |
scale = interpolate.scale = function(a,b,v){ | |
return 'scale(' + (((a + (b - a) * v) * 1000 >> 0 ) / 1000) + ')'; | |
}, | |
// KUTE.js DOM update functions | |
DOM = {}, | |
ticker = function(t) { | |
var i = 0; | |
while ( i < tweens[length] ) { | |
if ( update.call(tweens[i],t) ) { | |
i++; | |
} else { | |
tweens.splice(i, 1); | |
} | |
} | |
tick = _requestAnimationFrame(ticker); | |
}, | |
update = function(t) { | |
t = t || time.now(); | |
if ( t < this._startTime && this[playing] ) { return true; } | |
var elapsed = Math.min(( t - this._startTime ) / this[options][duration], 1), progress = this[options][easing](elapsed); // calculate progress | |
for (var tweenProp in this[valuesEnd]){ // render the DOM update | |
DOM[tweenProp](this[element],tweenProp,this[valuesStart][tweenProp],this[valuesEnd][tweenProp],progress,this[options]); | |
} | |
if (this[options].update) { this[options].update.call(); } // fire the updateCallback | |
if (elapsed === 1) { | |
if (this[options][repeat] > 0) { | |
if ( isFinite(this[options][repeat] ) ) { this[options][repeat]--; } | |
if (this[options][yoyo]) { // handle yoyo | |
this.reversed = !this.reversed; | |
reverse.call(this); | |
} | |
this._startTime = (this[options][yoyo] && !this.reversed) ? t + this[options][repeatDelay] : t; //set the right time for delay | |
return true; | |
} else { | |
if (this[options].complete) { this[options].complete.call(); } | |
scrollOut.call(this); // unbind preventing scroll when scroll tween finished | |
for (var i = 0, ctl = this[options][chain][length]; i < ctl; i++) { // start animating chained tweens | |
this[options][chain][i].start(); | |
} | |
//stop ticking when finished | |
close.call(this); | |
} | |
return false; | |
} | |
return true; | |
}, | |
// applies the transform origin and perspective | |
perspective = function () { | |
var el = this[element], ops = this[options]; | |
if ( ops.perspective !== undefined && transformProperty in this[valuesEnd] ) { // element perspective | |
this[valuesStart][transformProperty]['perspective'] = this[valuesEnd][transformProperty]['perspective']; | |
} | |
// element transform origin / we filter it out for svgTransform to fix the Firefox transformOrigin bug https://bugzilla.mozilla.org/show_bug.cgi?id=923193 | |
if ( ops.transformOrigin !== undefined && (!('svgTransform' in this[valuesEnd])) ) { el[style][property('transformOrigin')] = ops.transformOrigin; } // set transformOrigin for CSS3 transforms only | |
if ( ops.perspectiveOrigin !== undefined ) { el[style][property('perspectiveOrigin')] = ops.perspectiveOrigin; } // element perspective origin | |
if ( ops.parentPerspective !== undefined ) { el.parentNode[style][property('perspective')] = ops.parentPerspective + 'px'; } // parent perspective | |
if ( ops.parentPerspectiveOrigin !== undefined ) { el.parentNode[style][property('perspectiveOrigin')] = ops.parentPerspectiveOrigin; } // parent perspective origin | |
}, | |
// plugin connector objects | |
prepareStart = {}, // check current property value when .to() method is used | |
crossCheck = {}, // checks for differences between start and end value, try to make sure start unit and end unit are same as well as consistent, stack transforms, process SVG paths | |
// parse properties object | |
// string parsing and property specific value processing | |
parseProperty = { // we already start working on core supported properties | |
boxModel : function(tweenProp,inputValue){ | |
if (!(tweenProp in DOM)){ | |
DOM[tweenProp] = function(elem,tweenProp,a,b,v){ | |
elem[style][tweenProp] = ( v > 0.99 || v < 0.01 ? ((number(a,b,v)*10)>>0)/10 : (number(a,b,v) ) >> 0 ) + 'px'; | |
} | |
} | |
var boxValue = trueDimension(inputValue); | |
return boxValue.u === '%' ? boxValue.v * this[element][offsetWidth] / 100 : boxValue.v; | |
}, | |
transform : function(tweenProp,inputValue) { | |
if (!(transformProperty in DOM)) { | |
DOM[transformProperty] = function(elem,tweenProp,a,b,v,o){ | |
elem[style][tweenProp] = (a.perspective||'') | |
+ ('translate' in a ? translate(a.translate,b.translate,'px',v):'') | |
+ ('rotate' in a ? rotate(a.rotate,b.rotate,'deg',v):'') | |
+ ('skew' in a ? skew(a.skew,b.skew,'deg',v):'') | |
+ ('scale' in a ? scale(a.scale,b.scale,v):''); | |
} | |
} | |
// process each transform property | |
if (/translate/.test(tweenProp)) { | |
if (tweenProp === 'translate3d') { | |
var t3d = inputValue[split](','), t3d0 = trueDimension(t3d[0]), t3d1 = trueDimension(t3d[1], t3d2 = trueDimension(t3d[2])); | |
return { | |
translateX : t3d0.u === '%' ? (t3d0.v * this[element][offsetWidth] / 100) : t3d0.v, | |
translateY : t3d1.u === '%' ? (t3d1.v * this[element][offsetHeight] / 100) : t3d1.v, | |
translateZ : t3d2.u === '%' ? (t3d2.v * (this[element][offsetHeight] + this[element][offsetWidth]) / 200) : t3d2.v // to be changed with something like element and/or parent perspective | |
}; | |
} else if (/^translate(?:[XYZ])$/.test(tweenProp)) { | |
var t1d = trueDimension(inputValue), percentOffset = /X/.test(tweenProp) ? this[element][offsetWidth] / 100 : /Y/.test(tweenProp) ? this[element][offsetHeight] / 100 : (this[element][offsetWidth]+this[element][offsetHeight]) / 200; | |
return t1d.u === '%' ? (t1d.v * percentOffset) : t1d.v; | |
} else if (tweenProp === 'translate') { | |
var tv = typeof inputValue === 'string' ? inputValue[split](',') : inputValue, t2d = {}, t2dv, | |
t2d0 = trueDimension(tv[0]), t2d1 = tv[length] ? trueDimension(tv[1]) : {v: 0, u: 'px'}; | |
if (tv instanceof Array) { | |
t2d.x = t2d0.u === '%' ? (t2d0.v * this[element][offsetWidth] / 100) : t2d0.v, | |
t2d.y = t2d1.u === '%' ? (t2d1.v * this[element][offsetHeight] / 100) : t2d1.v | |
} else { | |
t2dv = trueDimension(tv); | |
t2d.x = t2dv.u === '%' ? (t2dv.v * this[element][offsetWidth] / 100) : t2dv.v, | |
t2d.y = 0 | |
} | |
return t2d; | |
} | |
} else if (/rotate|skew/.test(tweenProp)) { | |
if (/^rotate(?:[XYZ])$|skew(?:[XY])$/.test(tweenProp)) { | |
var r3d = trueDimension(inputValue,true); | |
return r3d.u === 'rad' ? radToDeg(r3d.v) : r3d.v; | |
} else if (tweenProp === 'rotate') { | |
var r2d = {}, r2dv = trueDimension(inputValue,true); | |
r2d.z = r2dv.u === 'rad' ? radToDeg(r2dv.v) : r2dv.v; | |
return r2d; | |
} | |
} else if (tweenProp === 'scale') { | |
return parseFloat(inputValue); // this must be parseFloat(v) | |
} | |
}, | |
unitless : function(tweenProp,inputValue){ // scroll | opacity | |
if (/scroll/.test(tweenProp) && !(tweenProp in DOM) ){ | |
DOM[tweenProp] = function(elem,tweenProp,a,b,v) { | |
elem.scrollTop = (number(a,b,v))>>0; | |
}; | |
} else if (tweenProp === 'opacity') { | |
if (!(tweenProp in DOM)) { | |
if (isIE8) { | |
DOM[tweenProp] = function(elem,tweenProp,a,b,v) { | |
var st = "alpha(opacity=", ep = ')'; | |
elem[style].filter = st + ((number(a,b,v) * 100)>>0) + ep; | |
}; | |
} else { | |
DOM[tweenProp] = function(elem,tweenProp,a,b,v) { | |
elem[style].opacity = ((number(a,b,v) * 100)>>0)/100; | |
}; | |
} | |
} | |
} | |
return parseFloat(inputValue); | |
}, | |
colors : function(tweenProp,inputValue){ // colors | |
if (!(tweenProp in DOM)) { | |
DOM[tweenProp] = function(elem,tweenProp,a,b,v,o) { | |
elem[style][tweenProp] = color(a,b,v,o[keepHex]); | |
}; | |
} | |
return trueColor(inputValue); | |
} | |
}, | |
// process properties for endValues and startValues or one of them | |
preparePropertiesObject = function(obj, fn) { // this, props object, type: start/end | |
var propertiesObject = fn === 'start' ? this[valuesStart] : this[valuesEnd], | |
skewObject = {}, rotateObject = {}, translateObject = {}, transformObject = {}; | |
for (var x in obj) { | |
if (transformFunctions[indexOf](x) !== -1) { // transform object gets built here | |
if ( /^translate(?:[XYZ]|3d)$/.test(x) ) { //process translate3d | |
var prepAxis = ['X', 'Y', 'Z']; //coordinates // translate[x] = pp(x, obj[x]); | |
for (var fnIndex = 0; fnIndex < 3; fnIndex++) { | |
var translateAxis = prepAxis[fnIndex]; | |
if ( /3d/.test(x) ) { | |
translateObject['translate' + translateAxis] = parseProperty.transform.call(this,'translate' + translateAxis, obj[x][fnIndex]); | |
} else { | |
translateObject['translate' + translateAxis] = ('translate' + translateAxis in obj) ? parseProperty.transform.call(this,'translate' + translateAxis, obj['translate' + translateAxis]) : 0; | |
} | |
} | |
transformObject['translate'] = translateObject; | |
} else if ( /^rotate(?:[XYZ])$|^skew(?:[XY])$/.test(x) ) { //process rotation/skew | |
var objectName = /rotate/.test(x) ? 'rotate' : 'skew', prepAxis = ['X', 'Y', 'Z'], | |
rotationOrSkew = objectName === 'rotate' ? rotateObject : skewObject; | |
for (var rIndex = 0; rIndex < 3; rIndex++) { | |
var oneAxis = prepAxis[rIndex]; | |
if ( obj[objectName+oneAxis] !== undefined && x !== 'skewZ' ) { | |
rotationOrSkew[objectName+oneAxis] = parseProperty.transform.call(this,objectName+oneAxis, obj[objectName+oneAxis]); | |
} | |
} | |
transformObject[objectName] = rotationOrSkew; | |
} else if ( /(rotate|translate|scale)$/.test(x) ) { //process 2d translation / rotation | |
transformObject[x] = parseProperty.transform.call(this, x, obj[x]); | |
} | |
propertiesObject[transformProperty] = transformObject; | |
} else { | |
if ( boxModelProps[indexOf](x) !== -1 ) { | |
propertiesObject[x] = parseProperty.boxModel.call(this,x,obj[x]); | |
} else if (opacityProp[indexOf](x) !== -1 || x === 'scroll') { | |
propertiesObject[x] = parseProperty.unitless.call(this,x,obj[x]); | |
} else if (colorProps[indexOf](x) !== -1) { | |
propertiesObject[x] = parseProperty.colors.call(this,x,obj[x]); | |
} else if (x in parseProperty) { // or any other property from css/ attr / svg / third party plugins | |
propertiesObject[x] = parseProperty[x].call(this,x,obj[x]); | |
} | |
} | |
} | |
}, | |
reverse = function () { | |
if (this[options][yoyo]) { | |
for (var reverseProp in this[valuesEnd]) { | |
var tmp = this[valuesRepeat][reverseProp]; | |
this[valuesRepeat][reverseProp] = this[valuesEnd][reverseProp]; | |
this[valuesEnd][reverseProp] = tmp; | |
this[valuesStart][reverseProp] = this[valuesRepeat][reverseProp]; | |
} | |
} | |
}, | |
close = function () { // when animation is finished reset repeat, yoyo&reversed tweens | |
if (this[repeat] > 0) { this[options][repeat] = this[repeat]; } | |
if (this[options][yoyo] && this.reversed===true) { reverse.call(this); this.reversed = false; } | |
this[playing] = false; | |
setTimeout(function(){ if (!tweens[length]) { stop(); } }, 48); // when all animations are finished, stop ticking after ~3 frames | |
}, | |
preventScroll = function (eventObj) { // prevent mousewheel or touch events while tweening scroll | |
var data = body.getAttribute(dataTweening); | |
if (data && data === 'scroll') { eventObj.preventDefault(); } | |
}, | |
scrollOut = function(){ //prevent scroll when tweening scroll | |
if ( 'scroll' in this[valuesEnd] && body.getAttribute(dataTweening)) { | |
document[removeEventListener](touchOrWheel, preventScroll, false); | |
document[removeEventListener](mouseEnter, preventScroll, false); | |
body.removeAttribute(dataTweening); | |
} | |
}, | |
scrollIn = function(){ | |
if ( 'scroll' in this[valuesEnd] && !body.getAttribute(dataTweening)) { | |
document[addEventListener](touchOrWheel, preventScroll, false); | |
document[addEventListener](mouseEnter, preventScroll, false); | |
body.setAttribute(dataTweening, 'scroll'); | |
} | |
}, | |
processEasing = function (fn) { | |
if ( typeof fn === 'function') { | |
return fn; | |
} else if ( typeof fn === 'string' ) { | |
return easingFn[fn]; // regular Robert Penner Easing Functions | |
} | |
}, | |
getStartValues = function () { // stack transform props for .to() chains | |
var startValues = {}, currentStyle = getInlineStyle(this[element]), | |
degreeProps = ['rotate','skew'], startAxis = ['X','Y','Z']; | |
for (var tweenProperty in this[valuesStart]){ | |
if ( transformFunctions[indexOf](tweenProperty) !== -1 ) { | |
var r2d = (/(rotate|translate|scale)$/.test(tweenProperty)); | |
if ( /translate/.test(tweenProperty) && tweenProperty !== 'translate' ) { | |
startValues['translate3d'] = currentStyle['translate3d'] || defaultPropsValues[tweenProperty]; | |
} else if ( r2d ) { // 2d transforms | |
startValues[tweenProperty] = currentStyle[tweenProperty] || defaultPropsValues[tweenProperty]; | |
} else if ( !r2d && /rotate|skew/.test(tweenProperty) ) { // all angles | |
for (var degIndex=0; degIndex<2; degIndex++) { | |
for (var axisIndex = 0; axisIndex<3; axisIndex++) { | |
var s = degreeProps[degIndex]+startAxis[axisIndex]; | |
if (transformFunctions[indexOf](s) !== -1 && (s in this[valuesStart]) ) { startValues[s] = currentStyle[s] || defaultPropsValues[s]; } | |
} | |
} | |
} | |
} else { | |
if ( tweenProperty !== 'scroll' ) { | |
if (tweenProperty === 'opacity' && isIE8 ) { // handle IE8 opacity | |
var currentOpacity = getCurrentStyle(this[element],'filter'); | |
startValues['opacity'] = typeof currentOpacity === 'number' ? currentOpacity : defaultPropsValues['opacity']; | |
} else { | |
if ( coreProps[indexOf](tweenProperty) !== -1 ) { | |
startValues[tweenProperty] = getCurrentStyle(this[element],tweenProperty) || d[tweenProperty]; | |
} else { // plugins register here | |
startValues[tweenProperty] = tweenProperty in prepareStart ? prepareStart[tweenProperty].call(this,tweenProperty,this[valuesStart][tweenProperty]) : 0; | |
} | |
} | |
} else { | |
startValues[tweenProperty] = this[element] === scrollContainer ? (g.pageYOffset || scrollContainer.scrollTop) : this[element].scrollTop; | |
} | |
} | |
} | |
for ( var currentProperty in currentStyle ){ // also add to startValues values from previous tweens | |
if ( transformFunctions[indexOf](currentProperty) !== -1 && (!( currentProperty in this[valuesStart] )) ) { | |
startValues[currentProperty] = currentStyle[currentProperty] || defaultPropsValues[currentProperty]; | |
} | |
} | |
this[valuesStart] = {}; | |
preparePropertiesObject.call(this,startValues,'start'); | |
if ( transformProperty in this[valuesEnd] ) { // let's stack transform | |
for ( var sp in this[valuesStart][transformProperty]) { // sp is the object corresponding to the transform function objects translate / rotate / skew / scale | |
if ( sp !== 'perspective') { | |
if ( typeof this[valuesStart][transformProperty][sp] === 'object' ) { | |
for ( var spp in this[valuesStart][transformProperty][sp] ) { // 3rd level | |
if ( typeof this[valuesEnd][transformProperty][sp] === 'undefined' ) { this[valuesEnd][transformProperty][sp] = {}; } | |
if ( typeof this[valuesStart][transformProperty][sp][spp] === 'number' && typeof this[valuesEnd][transformProperty][sp][spp] === 'undefined' ) { | |
this[valuesEnd][transformProperty][sp][spp] = this[valuesStart][transformProperty][sp][spp]; | |
} | |
} | |
} else if ( typeof this[valuesStart][transformProperty][sp] === 'number' ) { | |
if ( typeof this[valuesEnd][transformProperty][sp] === 'undefined' ) { // scale | |
this[valuesEnd][transformProperty][sp] = this[valuesStart][transformProperty][sp]; | |
} | |
} | |
} | |
} | |
} | |
}; | |
// core easing functions | |
var easingFn = g.Easing = {}; | |
easingFn.linear = function (t) { return t; }; | |
easingFn.easingSinusoidalIn = function(t) { return -Math.cos(t * Math.PI / 2) + 1; }; | |
easingFn.easingSinusoidalOut = function(t) { return Math.sin(t * Math.PI / 2); }; | |
easingFn.easingSinusoidalInOut = function(t) { return -0.5 * (Math.cos(Math.PI * t) - 1); }; | |
easingFn.easingQuadraticIn = function (t) { return t*t; }; | |
easingFn.easingQuadraticOut = function (t) { return t*(2-t); }; | |
easingFn.easingQuadraticInOut = function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t; }; | |
easingFn.easingCubicIn = function (t) { return t*t*t; }; | |
easingFn.easingCubicOut = function (t) { return (--t)*t*t+1; }; | |
easingFn.easingCubicInOut = function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; }; | |
easingFn.easingQuarticIn = function (t) { return t*t*t*t; }; | |
easingFn.easingQuarticOut = function (t) { return 1-(--t)*t*t*t; }; | |
easingFn.easingQuarticInOut = function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t; }; | |
easingFn.easingQuinticIn = function (t) { return t*t*t*t*t; }; | |
easingFn.easingQuinticOut = function (t) { return 1+(--t)*t*t*t*t; }; | |
easingFn.easingQuinticInOut = function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t; }; | |
easingFn.easingCircularIn = function(t) { return -(Math.sqrt(1 - (t * t)) - 1); }; | |
easingFn.easingCircularOut = function(t) { return Math.sqrt(1 - (t = t - 1) * t); }; | |
easingFn.easingCircularInOut = function(t) { return ((t*=2) < 1) ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); }; | |
easingFn.easingExponentialIn = function(t) { return Math.pow(2, 10 * (t - 1)) - 0.001; }; | |
easingFn.easingExponentialOut = function(t) { return 1 - Math.pow(2, -10 * t); }; | |
easingFn.easingExponentialInOut = function(t) { return (t *= 2) < 1 ? 0.5 * Math.pow(2, 10 * (t - 1)) : 0.5 * (2 - Math.pow(2, -10 * (t - 1))); }; | |
easingFn.easingBackIn = function(t) { var s = 1.70158; return t * t * ((s + 1) * t - s); }; | |
easingFn.easingBackOut = function(t) { var s = 1.70158; return --t * t * ((s + 1) * t + s) + 1; }; | |
easingFn.easingBackInOut = function(t) { var s = 1.70158 * 1.525; if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s)); return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2); }; | |
easingFn.easingElasticIn = function(t) { | |
var s, _kea = 0.1, _kep = 0.4; | |
if ( t === 0 ) return 0; if ( t === 1 ) return 1; | |
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2; | |
return - ( _kea * Math.pow( 2, 10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) ); | |
}; | |
easingFn.easingElasticOut = function(t) { | |
var s, _kea = 0.1, _kep = 0.4; | |
if ( t === 0 ) return 0; if ( t === 1 ) return 1; | |
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2 ; | |
return ( _kea * Math.pow( 2, - 10 * t) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) + 1 ); | |
}; | |
easingFn.easingElasticInOut = function(t) { | |
var s, _kea = 0.1, _kep = 0.4; | |
if ( t === 0 ) return 0; if ( t === 1 ) return 1; | |
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2 ; | |
if ( ( t *= 2 ) < 1 ) return - 0.5 * ( _kea * Math.pow( 2, 10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) ); | |
return _kea * Math.pow( 2, -10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) * 0.5 + 1; | |
}; | |
easingFn.easingBounceIn = function(t) { return 1 - easingFn.easingBounceOut( 1 - t ); }; | |
easingFn.easingBounceOut = function(t) { | |
if ( t < ( 1 / 2.75 ) ) { return 7.5625 * t * t; } | |
else if ( t < ( 2 / 2.75 ) ) { return 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75; } | |
else if ( t < ( 2.5 / 2.75 ) ) { return 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375; } | |
else {return 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375; } | |
}; | |
easingFn.easingBounceInOut = function(t) { if ( t < 0.5 ) return easingFn.easingBounceIn( t * 2 ) * 0.5; return easingFn.easingBounceOut( t * 2 - 1 ) * 0.5 + 0.5;}; | |
// single Tween object construct | |
var Tween = function (targetElement, startObject, endObject, optionsObj) { | |
this[element] = 'scroll' in endObject && (targetElement === undefined || targetElement === null) ? scrollContainer : targetElement; // element animation is applied to | |
this[playing] = false; | |
this.reversed = false; | |
this.paused = false; | |
this._startTime = null; | |
this._pauseTime = null; | |
this._startFired = false; | |
this[options] = {}; for (var o in optionsObj) { this[options][o] = optionsObj[o]; } | |
this[options].rpr = optionsObj.rpr || false; // internal option to process inline/computed style at start instead of init true/false | |
this[valuesRepeat] = {}; // internal valuesRepeat | |
this[valuesEnd] = {}; // valuesEnd | |
this[valuesStart] = {}; // valuesStart | |
preparePropertiesObject.call(this,endObject,'end'); // valuesEnd | |
if ( this[options].rpr ) { this[valuesStart] = startObject; } else { preparePropertiesObject.call(this,startObject,'start'); } // valuesStart | |
if ( this[options].perspective !== undefined && transformProperty in this[valuesEnd] ) { // element transform perspective | |
var perspectiveString = 'perspective('+parseInt(this[options].perspective)+'px)'; | |
this[valuesEnd][transformProperty].perspective = perspectiveString; | |
} | |
for ( var repeatProp in this[valuesEnd] ) { | |
if (repeatProp in crossCheck && !this[options].rpr) crossCheck[repeatProp].call(this); // this is where we do the valuesStart and valuesEnd check for fromTo() method | |
} | |
this[options][chain] = []; // chained Tweens | |
this[options][easing] = processEasing(optionsObj[easing]) || easingFn[defaultOptions[easing]] || easingFn['linear']; // you can only set a core easing function as default | |
this[options][repeat] = optionsObj[repeat] || defaultOptions[repeat]; | |
this[options][repeatDelay] = optionsObj[repeatDelay] || defaultOptions[repeatDelay]; | |
this[options][yoyo] = optionsObj[yoyo] || defaultOptions[yoyo]; | |
this[options][duration] = optionsObj[duration] || defaultOptions[duration]; // duration option | default | |
this[options][delay] = optionsObj[delay] || defaultOptions[delay]; // delay option | default | |
this[repeat] = this[options][repeat]; // we cache the number of repeats to be able to put it back after all cycles finish | |
}, | |
// tween control and chain | |
TweenProto = Tween.prototype = { | |
// queue tween object to main frame update | |
start : function (t) { // move functions that use the ticker outside the prototype to be in the same scope with it | |
scrollIn.call(this); | |
if ( this[options].rpr ) { getStartValues.apply(this); } // on start we reprocess the valuesStart for TO() method | |
perspective.apply(this); // apply the perspective and transform origin | |
for ( var endProp in this[valuesEnd] ) { | |
if (endProp in crossCheck && this[options].rpr) crossCheck[endProp].call(this); // this is where we do the valuesStart and valuesEnd check for to() method | |
this[valuesRepeat][endProp] = this[valuesStart][endProp]; | |
} | |
// now it's a good time to start | |
tweens.push(this); | |
this[playing] = true; | |
this.paused = false; | |
this._startFired = false; | |
this._startTime = t || time.now(); | |
this._startTime += this[options][delay]; | |
if (!this._startFired) { | |
if (this[options].start) { this[options].start.call(); } | |
this._startFired = true; | |
} | |
!tick && ticker(); | |
return this; | |
}, | |
play : function () { | |
if (this.paused && this[playing]) { | |
this.paused = false; | |
if (this[options].resume) { this[options].resume.call(); } | |
this._startTime += time.now() - this._pauseTime; | |
add(this); | |
!tick && ticker(); // restart ticking if stopped | |
} | |
return this; | |
}, | |
resume : function () { return this.play(); }, | |
pause : function() { | |
if (!this.paused && this[playing]) { | |
remove(this); | |
this.paused = true; | |
this._pauseTime = time.now(); | |
if (this[options].pause) { this[options].pause.call(); } | |
} | |
return this; | |
}, | |
stop : function () { | |
if (!this.paused && this[playing]) { | |
remove(this); | |
this[playing] = false; | |
this.paused = false; | |
scrollOut.call(this); | |
if (this[options].stop) { this[options].stop.call(); } | |
this.stopChainedTweens(); | |
close.call(this); | |
} | |
return this; | |
}, | |
chain : function() { this[options][chain] = arguments; return this; }, | |
stopChainedTweens : function () { | |
for (var i = 0, ctl = this[options][chain][length]; i < ctl; i++) { | |
this[options][chain][i].stop(); | |
} | |
} | |
}, | |
// the multi elements Tween constructs | |
TweensTO = function (els, vE, o) { // .to | |
this.tweens = []; var optionsObj = []; | |
for ( var i = 0, tl = els[length]; i < tl; i++ ) { | |
optionsObj[i] = o || {}; o[delay] = o[delay] || defaultOptions[delay]; | |
optionsObj[i][delay] = i>0 ? o[delay] + (o[offset]||defaultOptions[offset]) : o[delay]; | |
this.tweens.push( to(els[i], vE, optionsObj[i]) ); | |
} | |
}, | |
TweensFT = function (els, vS, vE, o) { // .fromTo | |
this.tweens = []; var optionsObj = []; | |
for ( var i = 0, l = els[length]; i < l; i++ ) { | |
optionsObj[i] = o || {}; o[delay] = o[delay] || defaultOptions[delay]; | |
optionsObj[i][delay] = i>0 ? o[delay] + (o[offset]||defaultOptions[offset]) : o[delay]; | |
this.tweens.push( fromTo(els[i], vS, vE, optionsObj[i]) ); | |
} | |
}, | |
ws = TweensTO.prototype = TweensFT.prototype = { | |
start : function(t){ | |
t = t || time.now(); | |
for ( var i = 0, tl = this.tweens[length]; i < tl; i++ ) { | |
this.tweens[i].start(t); | |
} | |
return this; | |
}, | |
stop : function(){ for ( var i = 0, tl = this.tweens[length]; i < tl; i++ ) { this.tweens[i].stop(); } return this; }, | |
pause : function(){ for ( var i = 0, tl = this.tweens[length]; i < tl; i++ ) { this.tweens[i].pause(); } return this; }, | |
chain : function(){ this.tweens[this.tweens[length]-1][options][chain] = arguments; return this; }, | |
play : function(){ for ( var i = 0, tl = this.tweens[length]; i < tl; i++ ) { this.tweens[i].play(); } return this; }, | |
resume : function() {return this.play()} | |
}, | |
// main methods | |
to = function (element, endObject, optionsObj) { | |
optionsObj = optionsObj || {}; optionsObj.rpr = true; | |
return new Tween(selector(element), endObject, endObject, optionsObj); | |
}, | |
fromTo = function (element, startObject, endObject, optionsObj) { | |
optionsObj = optionsObj || {}; | |
return new Tween(selector(element), startObject, endObject, optionsObj); | |
}, | |
// multiple elements tweening | |
allTo = function (elements, endObject, optionsObj) { | |
return new TweensTO(selector(elements,true), endObject, optionsObj); | |
}, | |
allFromTo = function (elements, startObject, endObject, optionsObj) { | |
return new TweensFT(selector(elements,true), startObject, endObject, optionsObj); | |
}; | |
return { // export core methods to public for plugins | |
property: property, getPrefix: getPrefix, selector: selector, processEasing : processEasing, // utils | |
defaultOptions : defaultOptions, // default tween options since 1.6.1 | |
to: to, fromTo: fromTo, allTo: allTo, allFromTo: allFromTo, // main methods | |
ticker : ticker, tick : tick, tweens : tweens, update: update, dom : DOM, // update | |
parseProperty: parseProperty, prepareStart: prepareStart, crossCheck : crossCheck, Tween : Tween, // property parsing & preparation | Tween | crossCheck | |
truD: trueDimension, truC: trueColor, rth: rgbToHex, htr: hexToRGB, getCurrentStyle: getCurrentStyle, // property parsing | |
}; | |
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var columnOne = document.querySelector(".column.one"); | |
var columnTwo = document.querySelector(".column.two"); | |
var columnThree = document.querySelector(".column.three"); | |
//columns animation | |
var animColumnOne = KUTE.fromTo(columnOne, | |
{ | |
height: '0' | |
}, | |
{ | |
height: '15%' | |
}, | |
{ | |
duration:5000, | |
easing: 'easingCubicInOut' | |
}); | |
var animColumnTwo = KUTE.fromTo(columnTwo, | |
{ | |
height: '0' | |
}, | |
{ | |
height: '30%' | |
}, | |
{ | |
duration:5000, | |
easing: 'easingCubicInOut' | |
}); | |
var animColumnThree = KUTE.fromTo(columnThree, | |
{ | |
height: '0' | |
}, | |
{ | |
height: '100%' | |
}, | |
{ | |
duration:5000, | |
easing: 'easingCubicInOut' | |
}); | |
animColumnOne.start(); | |
animColumnTwo.start(); | |
animColumnThree.start(); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body { | |
height: 100%; | |
margin: 0; | |
} | |
/*CLASSES*/ | |
#wraper { | |
width: 50%; | |
height: 80%; | |
margin: 0 auto; | |
display: flex; | |
align-items: flex-end; | |
justify-content: center; | |
border: 1px solid lightgray; | |
} | |
.column { | |
background-color: dodgerblue; | |
margin: 0 10px; | |
padding: 18px; | |
height: 100%; | |
color: white; | |
box-sizing: border-box; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment