From 1fd27a6c73497c7154f1856fa26184ad333f2878 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Mon, 7 Mar 2016 13:50:04 +0100 Subject: [PATCH 01/20] rewrite using Class, add registerEasing method --- README.md | 36 +++-- examples/index.html | 10 +- examples/js/storyboard.json | 40 ------ examples/js/storyline.js | 167 ---------------------- examples/minimal.html | 34 ++--- examples/storyboard.json | 40 ++++++ src/storyline.js | 269 ++++++++++++++++++------------------ 7 files changed, 218 insertions(+), 378 deletions(-) delete mode 100644 examples/js/storyboard.json delete mode 100644 examples/js/storyline.js create mode 100644 examples/storyboard.json diff --git a/README.md b/README.md index f6cf224..caf758d 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ There's two parts: Storyline.js is the parser and player, and then a storyboard "value2": [ "0 cut to 0", - "4 ease to 1", - "6 ease to 0" + "4 easeinout to 1", + "6 easeinout to 0" ] } ``` @@ -37,7 +37,11 @@ The actions are: - *cut to* instanteously changes to {value} - *linear to* will linearly interpolate from the last defined value to {value} -- *ease to* will ease in-out from the last defined value to {value} +- *easein to* will ease in from the last defined value to {value} +- *easeout to* will ease out from the last defined value to {value} +- *easeinout to* will ease in and out from the last defined value to {value} + +and you can register your own easing with the "registerEasing" method. #### Minimal example #### @@ -54,8 +58,8 @@ var storyline = STORYLINE.parseStoryline( { "value1": [ "0 cut to 0", - "5 ease to 1", - "10 ease to 0" + "5 easeinout to 1", + "10 easeinout to 0" ] } ); @@ -75,15 +79,15 @@ update(); Simply export the storyline into its own file, and include it like a normal script. ```js -var storyline = STORYLINE.parseStoryline( { +var storyline = new Storyline({ "value1": [ "0 cut to 0", - "5 ease to 1", - "10 ease to 0" + "5 easeinout to 1", + "10 easeinout to 0" ] -} ); +}); ``` Or load the content with AJAX and parse it when it's loaded: @@ -91,13 +95,23 @@ Or load the content with AJAX and parse it when it's loaded: ```js var oReq = new XMLHttpRequest(); oReq.onload = function() { - storyline = STORYLINE.parseStoryline( this.responseText ); + storyline = new Storyboard(this.responseText); /* ready to use */ }; -oReq.open( 'get', 'storyboard.json', true); +oReq.open('get', 'storyboard.json', true); oReq.send(); ``` +#### Register an easing function #### + +```js +Storyline.registerEasing("easingname", function( elapsed, duration ){ + + return elaped / duration; // linear easing + +}); +``` + ### Status #### This is the first release. Next steps are to add syntax to control the easing functions, probably something like: diff --git a/examples/index.html b/examples/index.html index 5eebcdc..a50e67e 100644 --- a/examples/index.html +++ b/examples/index.html @@ -47,7 +47,7 @@

Storyboard

Fork me on GitHub - + - - - + \ No newline at end of file diff --git a/examples/js/storyboard.json b/examples/js/storyboard.json deleted file mode 100644 index dfe3165..0000000 --- a/examples/js/storyboard.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - - "y": [ - "0 cut to 0", - "2 linear to .5", - "4 ease to 0", - "5 ease to .25", - "6 ease to .5", - "7 ease to .75", - "8 linear to 1", - "10 ease to 0" - ], - - "x": [ - "0 cut to -1", - "2 ease to 1", - "4 ease to 0", - "6 ease to -1", - "8 ease to 1", - "10 ease to -1" - ], - - "angle": [ - "0 cut to 0", - "3 ease to 80", - "6 ease to -70", - "8 ease to 20", - "10 ease to 0" - ], - - "scale": [ - "0 cut to 1", - "2 ease to 1.5", - "4 ease to .5", - "6 ease to 2", - "8 ease to .25", - "10 ease to 10" - ] - -} diff --git a/examples/js/storyline.js b/examples/js/storyline.js deleted file mode 100644 index 35ad541..0000000 --- a/examples/js/storyline.js +++ /dev/null @@ -1,167 +0,0 @@ -( function() { - -var ACTIONS = { - CUT: 0, - EASE: 1, - LINEAR: 2 -} - -function Event() { - this.start = null; - this.end = null; - this.action = null; - this.from = 0; - this.to = 0; - this.duration = 0; -} - -function Storyline() { - - this.points = {}; - - this.get = function( id, t ) { - return averageData( this.points, t, id ); - } - -} - -function parseStoryline( story ) { - - var s = new Storyline(); - - for( var v in story ) { - if( story.hasOwnProperty( v ) ) { - - var storyboard = []; - - story[ v ].forEach( function( e ) { - var start = e.match( /([^\s]+)/ ); - var event = new Event(); - if( e.indexOf( 'cut to' ) != -1 ) { - event.start = parseFloat( start[ 1 ] ); - event.action = ACTIONS.CUT; - var v = e.match( /[^\s]+ cut to ([^\s]+)/ ); - event.from = parseFloat( v[ 1 ] ); - event.to = event.from; - event.end = event.start; - } - if( e.indexOf( 'ease to' ) != -1 ) { - event.end = parseFloat( start[ 1 ] ); - event.action = ACTIONS.EASE; - event.from = 0; - var v = e.match( /[^\s]+ ease to ([^\s]+)/ ); - event.to = parseFloat( v[ 1 ] ); - } - if( e.indexOf( 'linear to' ) != -1 ) { - event.end = parseFloat( start[ 1 ] ); - event.action = ACTIONS.LINEAR; - event.from = 0; - var v = e.match( /[^\s]+ linear to ([^\s]+)/ ); - event.to = parseFloat( v[ 1 ] ); - } - storyboard.push( event ); - } ); - - storyboard.forEach( function( e, i ) { - if( e.action === ACTIONS.EASE || e.action == ACTIONS.LINEAR ) { - e.start = storyboard[ i - 1 ].end; - e.from = storyboard[ i - 1 ].to; - } - e.duration = e.end - e.start; - } ); - - storyboard.forEach( function( e, i ) { - if( e.action === ACTIONS.CUT ) { - if( storyboard[ i + 1 ] ) { - e.end = storyboard[ i + 1 ].start; - } - } - } ); - - /*storyboard.forEach( function( e, i ) { - console.log( e.from + '(' + e.start + ')' + ' to ' + e.to + '(' + e.end + ') in ' + e.duration ); - } );*/ - - s.points[ v ] = storyboard; - - } - } - - return s; - -} - -function getPointInStoryline( storyline, t, value ) { - - if( !storyline[ value ] ) return null; - - for( var j = 0; j < storyline[ value ].length; j++ ) { - var e = storyline[ value ][ j ]; - if( e.start <= t && e.end > t ) { - return e; - } - } - - return null; - -} - -function averageData( story, t, value ) { - - if( !story[ value ] ) { - console.warn( value + ' not found on storyboard' ); - return; - } - - var p; - - if( t > story[ value ][ story[ value ].length - 1 ].end ) { - p = story[ value ][ story[ value ].length - 1 ]; - } else { - p = getPointInStoryline( story, t, value ); - } - - if( !p ) return null; - - if( p.action === ACTIONS.CUT ) { - return p.from; - } - - if( p.action === ACTIONS.EASE ) { - - var et = ( t - p.start ) / p.duration; - et = Math.max( Math.min( et, 1 ), 0 ); - var easing; - if ( ( et *= 2 ) < 1 ) easing = 0.5 * et * et; - else easing = - 0.5 * ( --et * ( et - 2 ) - 1 ); - - var v = p.from + ( easing * ( p.to - p.from ) ); - - return v; - - } - - if( p.action === ACTIONS.LINEAR ) { - - var et = ( t - p.start ) / p.duration; - et = Math.max( Math.min( et, 1 ), 0 ); - var v = p.from + ( et * ( p.to - p.from ) ); - - return v; - - } - -} - -function setValue( original, value ) { - - if( value !== null ) return value; - return original - -} - -window.STORYLINE = { - parseStoryline: parseStoryline -} - -} )(); diff --git a/examples/minimal.html b/examples/minimal.html index fd3014f..c29ae19 100644 --- a/examples/minimal.html +++ b/examples/minimal.html @@ -9,31 +9,27 @@ -

This is very minimal. Check your console!

- - - + diff --git a/examples/storyboard.json b/examples/storyboard.json new file mode 100644 index 0000000..cbde7de --- /dev/null +++ b/examples/storyboard.json @@ -0,0 +1,40 @@ +{ + + "y": [ + "0 cut to 0", + "2 linear to .5", + "4 easeinout to 0", + "5 easeinout to .25", + "6 easeinout to .5", + "7 easeinout to .75", + "8 linear to 1", + "10 easeinout to 0" + ], + + "x": [ + "0 cut to -1", + "2 easeinout to 1", + "4 easeinout to 0", + "6 easeinout to -1", + "8 easeinout to 1", + "10 easeinout to -1" + ], + + "angle": [ + "0 cut to 0", + "3 easeinout to 80", + "6 easeinout to -70", + "8 easeinout to 20", + "10 easeinout to 0" + ], + + "scale": [ + "0 cut to 1", + "2 easeinout to 1.5", + "4 easeinout to .5", + "6 easeinout to 2", + "8 easeinout to .25", + "10 easeinout to 10" + ] + +} diff --git a/src/storyline.js b/src/storyline.js index 35ad541..b09f579 100644 --- a/src/storyline.js +++ b/src/storyline.js @@ -1,167 +1,166 @@ -( function() { +(function( self ){ -var ACTIONS = { - CUT: 0, - EASE: 1, - LINEAR: 2 -} + var easings = new Array(); -function Event() { - this.start = null; - this.end = null; - this.action = null; - this.from = 0; - this.to = 0; - this.duration = 0; -} + var Storyline = function( story, duration ){ -function Storyline() { + return Storyline.methods.initialize(story, duration); - this.points = {}; + }; - this.get = function( id, t ) { - return averageData( this.points, t, id ); - } + Storyline.methods = Storyline.prototype = { + constructor: Storyline, + initialize: function( story, duration ){ -} - -function parseStoryline( story ) { - - var s = new Storyline(); - - for( var v in story ) { - if( story.hasOwnProperty( v ) ) { - - var storyboard = []; - - story[ v ].forEach( function( e ) { - var start = e.match( /([^\s]+)/ ); - var event = new Event(); - if( e.indexOf( 'cut to' ) != -1 ) { - event.start = parseFloat( start[ 1 ] ); - event.action = ACTIONS.CUT; - var v = e.match( /[^\s]+ cut to ([^\s]+)/ ); - event.from = parseFloat( v[ 1 ] ); - event.to = event.from; - event.end = event.start; - } - if( e.indexOf( 'ease to' ) != -1 ) { - event.end = parseFloat( start[ 1 ] ); - event.action = ACTIONS.EASE; - event.from = 0; - var v = e.match( /[^\s]+ ease to ([^\s]+)/ ); - event.to = parseFloat( v[ 1 ] ); - } - if( e.indexOf( 'linear to' ) != -1 ) { - event.end = parseFloat( start[ 1 ] ); - event.action = ACTIONS.LINEAR; - event.from = 0; - var v = e.match( /[^\s]+ linear to ([^\s]+)/ ); - event.to = parseFloat( v[ 1 ] ); - } - storyboard.push( event ); - } ); - - storyboard.forEach( function( e, i ) { - if( e.action === ACTIONS.EASE || e.action == ACTIONS.LINEAR ) { - e.start = storyboard[ i - 1 ].end; - e.from = storyboard[ i - 1 ].to; - } - e.duration = e.end - e.start; - } ); - - storyboard.forEach( function( e, i ) { - if( e.action === ACTIONS.CUT ) { - if( storyboard[ i + 1 ] ) { - e.end = storyboard[ i + 1 ].start; - } - } - } ); - - /*storyboard.forEach( function( e, i ) { - console.log( e.from + '(' + e.start + ')' + ' to ' + e.to + '(' + e.end + ') in ' + e.duration ); - } );*/ - - s.points[ v ] = storyboard; + this.storyboard = new Object(); - } - } + this.duration = (parseFloat(duration) || 1); + + for( var key in story ){ + + for( var step in story[key] ){ + + var parameters = story[key][step].split(/\s+/); + var time = parseFloat(parameters[0]); + var easing = Storyline.getEasing(parameters[1]); + var value = parseFloat(parameters[3]); + + this.set(key, time, easing, value); + + }; + + }; + + return this; + + }, + set: function( key, time, easing, value ){ + + if( this.storyboard[key] == undefined ){ + + this.storyboard[key] = new Array(); + + }; - return s; + this.storyboard[key].push([(time * this.duration), easing, value]); -} - -function getPointInStoryline( storyline, t, value ) { - - if( !storyline[ value ] ) return null; + this.storyboard[key].sort(function( before, after ){ + + return before[0] - after[0]; + + }); + + return this; + + }, + get: function( key, now ){ + + if( this.storyboard[key] != undefined ){ + + for( var stepMax = this.storyboard[key].length - 1, step = stepMax; step >= 0; step-- ){ + + if( this.storyboard[key][step][0] <= now ){ + + var timeDestination = this.storyboard[key][Math.min(step + 1, stepMax)][0]; + var easingDestination = this.storyboard[key][Math.min(step + 1, stepMax)][1]; + var valueDestination = this.storyboard[key][Math.min(step + 1, stepMax)][2]; + var valueDifference = valueDestination - this.storyboard[key][step][2]; + var elapsedTime = Math.min((now - this.storyboard[key][step][0]) / (timeDestination - this.storyboard[key][step][0]) || 0, 1); + + return this.storyboard[key][step][2] + (easings[easingDestination][1](elapsedTime, 1) * valueDifference); + + }; + + }; + + }; + + return null; - for( var j = 0; j < storyline[ value ].length; j++ ) { - var e = storyline[ value ][ j ]; - if( e.start <= t && e.end > t ) { - return e; } - } + }; - return null; + Storyline.registerEasing = function( name, easingFunction ){ -} + easings.push([name.toLowerCase(), easingFunction]); -function averageData( story, t, value ) { + }; - if( !story[ value ] ) { - console.warn( value + ' not found on storyboard' ); - return; - } + Storyline.getEasing = function( name ){ - var p; + name = name.toLowerCase(); - if( t > story[ value ][ story[ value ].length - 1 ].end ) { - p = story[ value ][ story[ value ].length - 1 ]; - } else { - p = getPointInStoryline( story, t, value ); - } + for( var easing = 0, length = easings.length; easing < length; easing++ ){ - if( !p ) return null; + if( name == easings[easing][0] ){ - if( p.action === ACTIONS.CUT ) { - return p.from; - } + return easing; - if( p.action === ACTIONS.EASE ) { - - var et = ( t - p.start ) / p.duration; - et = Math.max( Math.min( et, 1 ), 0 ); - var easing; - if ( ( et *= 2 ) < 1 ) easing = 0.5 * et * et; - else easing = - 0.5 * ( --et * ( et - 2 ) - 1 ); + }; - var v = p.from + ( easing * ( p.to - p.from ) ); + }; - return v; + return null; - } + }; - if( p.action === ACTIONS.LINEAR ) { - - var et = ( t - p.start ) / p.duration; - et = Math.max( Math.min( et, 1 ), 0 ); - var v = p.from + ( et * ( p.to - p.from ) ); + Storyline.registerEasing("cut", function( elapsed, duration ){ - return v; + return (elapsed < 1 ? 0 : 1); - } + }); + + Storyline.registerEasing("linear", function( elapsed, duration ){ + + return (elapsed / duration); + + }); + + Storyline.registerEasing("easein", function( elapsed, duration ){ + + return elapsed * elapsed * elapsed; + + }); + + Storyline.registerEasing("easeout", function( elapsed, duration ){ + + return (elapsed -= 1) * elapsed * elapsed + 1; + + }); -} + Storyline.registerEasing("easeinout", function( elapsed, duration ){ -function setValue( original, value ) { + if( (elapsed /= duration / 2) < 1 ){ - if( value !== null ) return value; - return original + return 0.5 * elapsed * elapsed * elapsed; + + } + else { + + return 0.5 * ((elapsed -= 2) * elapsed * elapsed + 2); + + }; + + }); + + if( typeof define !== "undefined" && define instanceof Function && define.amd != undefined ){ + + define(function(){ + + return Storyline; + + }); + + } + else if( typeof module !== "undefined" && module.exports ){ + + module.exports = Storyline; + + } + else if( self != undefined ){ -} + self.Storyline = Storyline; -window.STORYLINE = { - parseStoryline: parseStoryline -} + }; -} )(); +})(self || {}); \ No newline at end of file From 7268fc7ab8180e07ee64654500461461158d4a7d Mon Sep 17 00:00:00 2001 From: JordanDelcros Date: Wed, 9 Mar 2016 11:11:12 +0100 Subject: [PATCH 02/20] add cubic() and quadratic() easing capabilities, review example --- examples/index.html | 238 +++++++++++++++---------------- examples/minimal.html | 38 ----- examples/storyboard.json | 40 ------ src/storyline.js => storyline.js | 65 +++++++-- 4 files changed, 164 insertions(+), 217 deletions(-) delete mode 100644 examples/minimal.html delete mode 100644 examples/storyboard.json rename src/storyline.js => storyline.js (51%) diff --git a/examples/index.html b/examples/index.html index a50e67e..c0ec52d 100644 --- a/examples/index.html +++ b/examples/index.html @@ -1,151 +1,141 @@ - - - -Storyline.js - + + - - - - - - -

Storyline.js demo

-

This is a demo of a storyboard that defines values in time that are applied to the CSS 2D transform of a div.

-
-
-

Animation playback speed:

- -
-
- -
- -
-

Storyboard

-

Try changing the values. You can use:

-
    -
  • [time] cut to [value]
  • -
  • [time] linear to [value]
  • -
  • [time] ease to [value]
  • -
- - - -
- - Fork me on GitHub - - - - + + + \ No newline at end of file diff --git a/examples/minimal.html b/examples/minimal.html deleted file mode 100644 index c29ae19..0000000 --- a/examples/minimal.html +++ /dev/null @@ -1,38 +0,0 @@ - - -Storyline.js - - - - - - -

This is very minimal. Check your console!

- - - - - - diff --git a/examples/storyboard.json b/examples/storyboard.json deleted file mode 100644 index cbde7de..0000000 --- a/examples/storyboard.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - - "y": [ - "0 cut to 0", - "2 linear to .5", - "4 easeinout to 0", - "5 easeinout to .25", - "6 easeinout to .5", - "7 easeinout to .75", - "8 linear to 1", - "10 easeinout to 0" - ], - - "x": [ - "0 cut to -1", - "2 easeinout to 1", - "4 easeinout to 0", - "6 easeinout to -1", - "8 easeinout to 1", - "10 easeinout to -1" - ], - - "angle": [ - "0 cut to 0", - "3 easeinout to 80", - "6 easeinout to -70", - "8 easeinout to 20", - "10 easeinout to 0" - ], - - "scale": [ - "0 cut to 1", - "2 easeinout to 1.5", - "4 easeinout to .5", - "6 easeinout to 2", - "8 easeinout to .25", - "10 easeinout to 10" - ] - -} diff --git a/src/storyline.js b/storyline.js similarity index 51% rename from src/storyline.js rename to storyline.js index b09f579..3b7d19e 100644 --- a/src/storyline.js +++ b/storyline.js @@ -1,5 +1,10 @@ (function( self ){ + var KEY_TIME = 0; + var KEY_EASING = 1; + var KEY_OPTIONS = 2; + var KEY_VALUE = 3; + var easings = new Array(); var Storyline = function( story, duration ){ @@ -22,10 +27,14 @@ var parameters = story[key][step].split(/\s+/); var time = parseFloat(parameters[0]); - var easing = Storyline.getEasing(parameters[1]); + var easing = story[key][step].match(/([a-z]+)(?:\((.*)\))?/); + var easingMode = Storyline.getEasing(easing[1]); + var easingOptions = (easing[2] || "").split(/\,/g); var value = parseFloat(parameters[3]); - this.set(key, time, easing, value); + var time = parseFloat(story[key][step].match(/^([0-9]+\.?[0-9]*)/g)[0]); + + this.set(key, time, easingMode, easingOptions, value); }; @@ -34,7 +43,7 @@ return this; }, - set: function( key, time, easing, value ){ + set: function( key, time, easing, options, value ){ if( this.storyboard[key] == undefined ){ @@ -42,7 +51,7 @@ }; - this.storyboard[key].push([(time * this.duration), easing, value]); + this.storyboard[key].push([(time * this.duration), easing, options, value]); this.storyboard[key].sort(function( before, after ){ @@ -61,13 +70,16 @@ if( this.storyboard[key][step][0] <= now ){ - var timeDestination = this.storyboard[key][Math.min(step + 1, stepMax)][0]; - var easingDestination = this.storyboard[key][Math.min(step + 1, stepMax)][1]; - var valueDestination = this.storyboard[key][Math.min(step + 1, stepMax)][2]; - var valueDifference = valueDestination - this.storyboard[key][step][2]; - var elapsedTime = Math.min((now - this.storyboard[key][step][0]) / (timeDestination - this.storyboard[key][step][0]) || 0, 1); + var timeDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_TIME]; + var easingDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_EASING]; + var optionsDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_OPTIONS]; + var valueDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_VALUE]; + + var valueDifference = valueDestination - this.storyboard[key][step][KEY_VALUE]; + + var elapsedTime = Math.min(((now - this.storyboard[key][step][KEY_TIME]) / (timeDestination - this.storyboard[key][step][KEY_TIME]) || 0), 1); - return this.storyboard[key][step][2] + (easings[easingDestination][1](elapsedTime, 1) * valueDifference); + return this.storyboard[key][step][KEY_VALUE] + (easings[easingDestination][KEY_EASING](elapsedTime, 1, optionsDestination) * valueDifference); }; @@ -104,31 +116,31 @@ }; - Storyline.registerEasing("cut", function( elapsed, duration ){ + Storyline.registerEasing("cut", function( elapsed, duration, options ){ return (elapsed < 1 ? 0 : 1); }); - Storyline.registerEasing("linear", function( elapsed, duration ){ + Storyline.registerEasing("linear", function( elapsed, duration, options ){ return (elapsed / duration); }); - Storyline.registerEasing("easein", function( elapsed, duration ){ + Storyline.registerEasing("easein", function( elapsed, duration, options ){ return elapsed * elapsed * elapsed; }); - Storyline.registerEasing("easeout", function( elapsed, duration ){ + Storyline.registerEasing("easeout", function( elapsed, duration, options ){ return (elapsed -= 1) * elapsed * elapsed + 1; }); - Storyline.registerEasing("easeinout", function( elapsed, duration ){ + Storyline.registerEasing("easeinout", function( elapsed, duration, options ){ if( (elapsed /= duration / 2) < 1 ){ @@ -143,6 +155,29 @@ }); + Storyline.registerEasing("quadratic", function( elapsed, duration, options ){ + + var invertedElapsed = 1 - elapsed; + var point1 = parseFloat(options[0]); + var point2 = parseFloat(options[1]); + var point3 = parseFloat(options[2]); + + return invertedElapsed * invertedElapsed * point1 + 2 * invertedElapsed * elapsed * point2 + elapsed * elapsed * point3; + + }); + + Storyline.registerEasing("cubic", function( elapsed, duration, options ){ + + var invertedElapsed = 1 - elapsed; + var point1 = parseFloat(options[0]); + var point2 = parseFloat(options[1]); + var point3 = parseFloat(options[2]); + var point4 = parseFloat(options[3]); + + return invertedElapsed * invertedElapsed * invertedElapsed * point1 + 3 * invertedElapsed * invertedElapsed * elapsed * point2 + 3 * invertedElapsed * elapsed * elapsed * point3 + elapsed * elapsed * elapsed * point4; + + }); + if( typeof define !== "undefined" && define instanceof Function && define.amd != undefined ){ define(function(){ From 1664fd7e7b2f82699a9648ecacae4bc22b512622 Mon Sep 17 00:00:00 2001 From: JordanDelcros Date: Wed, 9 Mar 2016 20:16:15 +0100 Subject: [PATCH 03/20] some updates to set(), add vectors support --- examples/index.html | 84 +++++++++++++++++++++++++++++++++++---------- storyline.js | 52 ++++++++++++++++++---------- 2 files changed, 100 insertions(+), 36 deletions(-) diff --git a/examples/index.html b/examples/index.html index c0ec52d..3a9f27c 100644 --- a/examples/index.html +++ b/examples/index.html @@ -33,6 +33,14 @@ "0 cut to 0", "1000 linear to 1" ], + cut: [ + "0 cut to 0", + "1000 cut to 1" + ], + linear: [ + "0 cut to 0", + "1000 linear to 1" + ], easein: [ "0 cut to 0", "1000 easein to 1" @@ -46,54 +54,76 @@ "1000 easeinout to 1" ], quadraticX: [ - "0.5 cut to 0", - "1000 quadratic(0,0,1) to 1" + "0 cut to 0", + "1000 quadratic(0," + Math.random() + ",1) to 1" ], quadraticY: [ - "0.5 cut to 0", - "1000 quadratic(0,1,1) to 1" + "0 cut to 0", + "1000 quadratic(0," + Math.random() + ",1) to 1" ], cubicX: [ - "0.5 cut to 0", - "1000 cubic(0,1,1,1) to 1" + "0 cut to 0", + "1000 cubic(0," + Math.random() + "," + Math.random() + ",1) to 1" ], cubicY: [ - "0.5 cut to 0", - "1000 cubic(0,0.25,0.75,1) to 1" + "0 cut to 0", + "1000 cubic(0," + Math.random() + "," + Math.random() + ",1) to 1" + ], + vec3: [ + "0 cut to vec3(0,0,0)", + "1000 easein to vec3(1,0.5,0.25)" ] }); + var cutCurve = new CanvasCurve(200); + var linearCurve = new CanvasCurve(200); var easeinCurve = new CanvasCurve(200); var easeoutCurve = new CanvasCurve(200); var easeinoutCurve = new CanvasCurve(200); var quadraticCurve = new CanvasCurve(200); - var cubicCurve = new CanvasCurve(200); + var cubicCurve = new CanvasCurve(200); + var vec3Curve = new CanvasCurve(200); + + var delay = 0; + var now = 0; - function update( now ){ + function update( updateNow ){ window.requestAnimationFrame(update); + now = updateNow - delay; + var time = storyline.get("time", now); + var cut = storyline.get("cut", now); + cutCurve.drawEasing(time, cut); + + var linear = storyline.get("linear", now); + linearCurve.drawEasing(time, linear); + var easein = storyline.get("easein", now); - easeinCurve.drawPoint(time, easein); + easeinCurve.drawEasing(time, easein); var easeout = storyline.get("easeout", now); - easeoutCurve.drawPoint(time, easeout); + easeoutCurve.drawEasing(time, easeout); var easeinout = storyline.get("easeinout", now); - easeinoutCurve.drawPoint(time, easeinout); + easeinoutCurve.drawEasing(time, easeinout); var quadraticX = storyline.get("quadraticX", now); var quadraticY = storyline.get("quadraticY", now); - quadraticCurve.drawPoint(quadraticX, quadraticY); + quadraticCurve.drawEasing(quadraticX, quadraticY); var cubicX = storyline.get("cubicX", now); var cubicY = storyline.get("cubicY", now); - cubicCurve.drawPoint(cubicX, cubicY); + cubicCurve.drawEasing(cubicX, cubicY); + + var vec3 = storyline.get("vec3", now); + vec3Curve.drawVector3(time, vec3, ["#F00", "#0F0", "#00F"]); }; + delay = window.performance.now(); window.requestAnimationFrame(update); }, false); @@ -121,14 +151,32 @@ return this; }, - drawPoint: function( time, value ){ + drawEasing: function( time, value, color ){ - var x = (time * this.size); + var x = (time * this.size) - 1; var y = this.size - (value * this.size) - 1; - this.context.fillStyle = "#FFFFFF"; + this.context.fillStyle = (color || "#FFF"); this.context.fillRect(x, y, 2, 2); + }, + drawVector3: function( time, vector, colors ){ + + var t = (time * this.size) - 1; + + var x = this.size - (vector[0] * this.size) - 1; + var y = this.size - (vector[1] * this.size) - 1; + var z = this.size - (vector[2] * this.size) - 1; + + this.context.fillStyle = (colors[0] || "#FFF"); + this.context.fillRect(t, x, 2, 2); + + this.context.fillStyle = (colors[1] || "#FFF"); + this.context.fillRect(t, y, 2, 2); + + this.context.fillStyle = (colors[2] || "#FFF"); + this.context.fillRect(t, z, 2, 2); + } }; diff --git a/storyline.js b/storyline.js index 3b7d19e..cf6eb83 100644 --- a/storyline.js +++ b/storyline.js @@ -1,9 +1,11 @@ (function( self ){ - var KEY_TIME = 0; - var KEY_EASING = 1; - var KEY_OPTIONS = 2; - var KEY_VALUE = 3; + var KEY = { + TIME: 0, + EASING: 1, + OPTIONS: 2, + VALUE: 3 + }; var easings = new Array(); @@ -24,15 +26,19 @@ for( var key in story ){ for( var step in story[key] ){ + + var time = parseFloat(story[key][step].match(/^\s*([0-9]+\.?[0-9]*)/g)[0]); - var parameters = story[key][step].split(/\s+/); - var time = parseFloat(parameters[0]); var easing = story[key][step].match(/([a-z]+)(?:\((.*)\))?/); var easingMode = Storyline.getEasing(easing[1]); - var easingOptions = (easing[2] || "").split(/\,/g); - var value = parseFloat(parameters[3]); + var easingOptions = (easing[2] != undefined ? easing[2].split(/\,/g) : null); + + var extractedValue = story[key][step].match(/(?:([0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0].match(/([0-9]+\.?[0-9]*)/g); + var value = extractedValue.map(function( number ){ + + return parseFloat(number); - var time = parseFloat(story[key][step].match(/^([0-9]+\.?[0-9]*)/g)[0]); + }); this.set(key, time, easingMode, easingOptions, value); @@ -70,16 +76,26 @@ if( this.storyboard[key][step][0] <= now ){ - var timeDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_TIME]; - var easingDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_EASING]; - var optionsDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_OPTIONS]; - var valueDestination = this.storyboard[key][Math.min(step + 1, stepMax)][KEY_VALUE]; - - var valueDifference = valueDestination - this.storyboard[key][step][KEY_VALUE]; - - var elapsedTime = Math.min(((now - this.storyboard[key][step][KEY_TIME]) / (timeDestination - this.storyboard[key][step][KEY_TIME]) || 0), 1); + var destinationTime = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.TIME]; + var destinationEasing = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.EASING]; + var destinationOptions = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.OPTIONS]; + var destinationValues = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.VALUE]; + + var fromValues = this.storyboard[key][step][KEY.VALUE]; + + var values = new Array(); + + for( var valueIndex = 0, length = destinationValues.length; valueIndex < length; valueIndex++ ){ + + var difference = destinationValues[valueIndex] - fromValues[valueIndex]; + + var elapsed = Math.min(((now - fromValues[valueIndex]) / (destinationTime - fromValues[valueIndex]) || 0), 1); + + values[valueIndex] = fromValues[valueIndex] + (easings[destinationEasing][KEY.EASING](elapsed, 1, destinationOptions) * difference); + + }; - return this.storyboard[key][step][KEY_VALUE] + (easings[easingDestination][KEY_EASING](elapsedTime, 1, optionsDestination) * valueDifference); + return (values.length == 1 ? values[0] : values); }; From dccb613efa13835991c9fdc22fda9556518482c6 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 10 Mar 2016 10:50:45 +0100 Subject: [PATCH 04/20] fix class 'new this' problem --- .npmignore | 1 + package.json | 27 +++++++++++++++++++++++++++ storyline.js | 4 +++- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .npmignore create mode 100644 package.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..56bef8c --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +examples/ \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..f1b8e36 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "storyline.js", + "version": "1.1.2", + "description": "javascript animation sequencer", + "main": "storyline.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/JordanDelcros/Storyline.js.git" + }, + "keywords": [ + "javascript", + "animation", + "sequencer", + "scenario", + "story", + "frame" + ], + "author": "Jordan Delcros", + "license": "MIT", + "bugs": { + "url": "https://github.com/JordanDelcros/Storyline.js/issues" + }, + "homepage": "https://github.com/JordanDelcros/Storyline.js#readme" +} diff --git a/storyline.js b/storyline.js index cf6eb83..28b7dac 100644 --- a/storyline.js +++ b/storyline.js @@ -11,7 +11,7 @@ var Storyline = function( story, duration ){ - return Storyline.methods.initialize(story, duration); + return new Storyline.methods.initialize(story, duration); }; @@ -108,6 +108,8 @@ } }; + Storyline.methods.initialize.prototype = Storyline.methods; + Storyline.registerEasing = function( name, easingFunction ){ easings.push([name.toLowerCase(), easingFunction]); From 18b55066d211076f1dcdfd7f904a9bf53ca007fc Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 10 Mar 2016 11:22:05 +0100 Subject: [PATCH 05/20] add support of negative value, fix returning null if key exist -> return index 0 if time is negative --- examples/index.html | 2 ++ storyline.js | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/index.html b/examples/index.html index 3a9f27c..8a5dc97 100644 --- a/examples/index.html +++ b/examples/index.html @@ -121,6 +121,8 @@ var vec3 = storyline.get("vec3", now); vec3Curve.drawVector3(time, vec3, ["#F00", "#0F0", "#00F"]); + console.log( storyline.get("test", now) ); + }; delay = window.performance.now(); diff --git a/storyline.js b/storyline.js index 28b7dac..96cca61 100644 --- a/storyline.js +++ b/storyline.js @@ -33,7 +33,7 @@ var easingMode = Storyline.getEasing(easing[1]); var easingOptions = (easing[2] != undefined ? easing[2].split(/\,/g) : null); - var extractedValue = story[key][step].match(/(?:([0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0].match(/([0-9]+\.?[0-9]*)/g); + var extractedValue = story[key][step].match(/(?:(\-?\s*[0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0].match(/(\-?\s*[0-9]+\.?[0-9]*)/g); var value = extractedValue.map(function( number ){ return parseFloat(number); @@ -97,6 +97,13 @@ return (values.length == 1 ? values[0] : values); + } + else if( step == 0 ){ + + var values = this.storyboard[key][step][KEY.VALUE]; + + return (values.length == 1 ? values[0] : values); + }; }; From e819123ed57fdf5f3faa5af8a932129bdc3a181b Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 10 Mar 2016 11:22:36 +0100 Subject: [PATCH 06/20] publish nam 1.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f1b8e36..3eaf249 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.1.2", + "version": "1.1.3", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { From 4873757662833b6f7d56ad55f030147a853a5059 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 10 Mar 2016 12:37:44 +0100 Subject: [PATCH 07/20] fix get() that fail if delta start > 0 --- storyline.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/storyline.js b/storyline.js index 96cca61..85a6e35 100644 --- a/storyline.js +++ b/storyline.js @@ -3,7 +3,7 @@ var KEY = { TIME: 0, EASING: 1, - OPTIONS: 2, + OPTION: 2, VALUE: 3 }; @@ -74,24 +74,21 @@ for( var stepMax = this.storyboard[key].length - 1, step = stepMax; step >= 0; step-- ){ - if( this.storyboard[key][step][0] <= now ){ + if( this.storyboard[key][step][KEY.TIME] <= now ){ - var destinationTime = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.TIME]; - var destinationEasing = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.EASING]; - var destinationOptions = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.OPTIONS]; - var destinationValues = this.storyboard[key][Math.min(step + 1, stepMax)][KEY.VALUE]; - - var fromValues = this.storyboard[key][step][KEY.VALUE]; + var from = this.storyboard[key][step]; + var to = this.storyboard[key][Math.min(step + 1, stepMax)]; var values = new Array(); - for( var valueIndex = 0, length = destinationValues.length; valueIndex < length; valueIndex++ ){ + for( var valueIndex = 0, length = to[KEY.VALUE].length; valueIndex < length; valueIndex++ ){ - var difference = destinationValues[valueIndex] - fromValues[valueIndex]; + var difference = to[KEY.VALUE][valueIndex] - from[KEY.VALUE][valueIndex]; + var duration = to[KEY.TIME] - from[KEY.TIME]; - var elapsed = Math.min(((now - fromValues[valueIndex]) / (destinationTime - fromValues[valueIndex]) || 0), 1); + var elapsed = Math.min((((now - from[KEY.TIME]) / duration) || 0), 1) - values[valueIndex] = fromValues[valueIndex] + (easings[destinationEasing][KEY.EASING](elapsed, 1, destinationOptions) * difference); + values[valueIndex] = from[KEY.VALUE][valueIndex] + (easings[to[KEY.EASING]][KEY.EASING](elapsed, 1, to[KEY.OPTION]) * difference); }; From 4a9636ca2beb19fcd6968516d6de7f261584d348 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 10 Mar 2016 12:38:18 +0100 Subject: [PATCH 08/20] publish 1.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3eaf249..654511d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.1.3", + "version": "1.1.4", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { From 35ebf64e69cada47ca9520e1fbbe7e18ed8713b0 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Mon, 14 Mar 2016 13:16:31 +0100 Subject: [PATCH 09/20] add types to filter values output (like vec3 or int) --- examples/index.html | 56 +++++++++++---------- storyline.js | 117 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 123 insertions(+), 50 deletions(-) diff --git a/examples/index.html b/examples/index.html index 8a5dc97..95fcdf1 100644 --- a/examples/index.html +++ b/examples/index.html @@ -43,15 +43,15 @@ ], easein: [ "0 cut to 0", - "1000 easein to 1" + "1000 easeIn to 1" ], easeout: [ "0 cut to 0", - "1000 easeout to 1" + "1000 easeOut to 1" ], easeinout: [ "0 cut to 0", - "1000 easeinout to 1" + "1000 easeInOut to 1" ], quadraticX: [ "0 cut to 0", @@ -71,7 +71,7 @@ ], vec3: [ "0 cut to vec3(0,0,0)", - "1000 easein to vec3(1,0.5,0.25)" + "1000 easeIn to vec3(1,0.5,0.25)" ] }); @@ -93,35 +93,37 @@ now = updateNow - delay; - var time = storyline.get("time", now); + if( now <= storyline.duration ){ - var cut = storyline.get("cut", now); - cutCurve.drawEasing(time, cut); + var time = storyline.get("time", now); - var linear = storyline.get("linear", now); - linearCurve.drawEasing(time, linear); + var cut = storyline.get("cut", now); + cutCurve.drawEasing(time, cut); - var easein = storyline.get("easein", now); - easeinCurve.drawEasing(time, easein); + var linear = storyline.get("linear", now); + linearCurve.drawEasing(time, linear); - var easeout = storyline.get("easeout", now); - easeoutCurve.drawEasing(time, easeout); + var easein = storyline.get("easein", now); + easeinCurve.drawEasing(time, easein); - var easeinout = storyline.get("easeinout", now); - easeinoutCurve.drawEasing(time, easeinout); + var easeout = storyline.get("easeout", now); + easeoutCurve.drawEasing(time, easeout); - var quadraticX = storyline.get("quadraticX", now); - var quadraticY = storyline.get("quadraticY", now); - quadraticCurve.drawEasing(quadraticX, quadraticY); + var easeinout = storyline.get("easeinout", now); + easeinoutCurve.drawEasing(time, easeinout); - var cubicX = storyline.get("cubicX", now); - var cubicY = storyline.get("cubicY", now); - cubicCurve.drawEasing(cubicX, cubicY); + var quadraticX = storyline.get("quadraticX", now); + var quadraticY = storyline.get("quadraticY", now); + quadraticCurve.drawEasing(quadraticX, quadraticY); - var vec3 = storyline.get("vec3", now); - vec3Curve.drawVector3(time, vec3, ["#F00", "#0F0", "#00F"]); + var cubicX = storyline.get("cubicX", now); + var cubicY = storyline.get("cubicY", now); + cubicCurve.drawEasing(cubicX, cubicY); - console.log( storyline.get("test", now) ); + var vec3 = storyline.get("vec3", now); + vec3Curve.drawVector3(time, vec3, ["#F00", "#0F0", "#00F"]); + + }; }; @@ -166,9 +168,9 @@ var t = (time * this.size) - 1; - var x = this.size - (vector[0] * this.size) - 1; - var y = this.size - (vector[1] * this.size) - 1; - var z = this.size - (vector[2] * this.size) - 1; + var x = this.size - (vector.x * this.size) - 1; + var y = this.size - (vector.y * this.size) - 1; + var z = this.size - (vector.z * this.size) - 1; this.context.fillStyle = (colors[0] || "#FFF"); this.context.fillRect(t, x, 2, 2); diff --git a/storyline.js b/storyline.js index 85a6e35..997859c 100644 --- a/storyline.js +++ b/storyline.js @@ -4,35 +4,40 @@ TIME: 0, EASING: 1, OPTION: 2, - VALUE: 3 + VALUE: 3, + TYPE: 4 }; + var types = new Array(); var easings = new Array(); - var Storyline = function( story, duration ){ + var Storyline = function( story, timeScale ){ - return new Storyline.methods.initialize(story, duration); + return new Storyline.methods.initialize(story, timeScale); }; Storyline.methods = Storyline.prototype = { constructor: Storyline, - initialize: function( story, duration ){ + initialize: function( story, timeScale ){ this.storyboard = new Object(); - this.duration = (parseFloat(duration) || 1); + this.timeScale = (parseFloat(timeScale) || 1); + + this.duration = 0; for( var key in story ){ for( var step in story[key] ){ - + var time = parseFloat(story[key][step].match(/^\s*([0-9]+\.?[0-9]*)/g)[0]); - var easing = story[key][step].match(/([a-z]+)(?:\((.*)\))?/); + var easing = story[key][step].match(/([a-z]+)(?:\((.*)\))?/i); var easingMode = Storyline.getEasing(easing[1]); var easingOptions = (easing[2] != undefined ? easing[2].split(/\,/g) : null); + var type = Storyline.getType((story[key][step].match(/([a-z0-9]+)\([^\)]+\)$/) || "")[1]); var extractedValue = story[key][step].match(/(?:(\-?\s*[0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0].match(/(\-?\s*[0-9]+\.?[0-9]*)/g); var value = extractedValue.map(function( number ){ @@ -40,7 +45,7 @@ }); - this.set(key, time, easingMode, easingOptions, value); + this.set(key, time, easingMode, easingOptions, value, type); }; @@ -49,7 +54,11 @@ return this; }, - set: function( key, time, easing, options, value ){ + set: function( key, time, easing, options, value, type ){ + + time *= this.timeScale; + + this.duration = Math.max(this.duration, time); if( this.storyboard[key] == undefined ){ @@ -57,7 +66,7 @@ }; - this.storyboard[key].push([(time * this.duration), easing, options, value]); + this.storyboard[key].push([time, easing, options, value, type]); this.storyboard[key].sort(function( before, after ){ @@ -72,39 +81,50 @@ if( this.storyboard[key] != undefined ){ + var type = null; + var values = new Array(); + for( var stepMax = this.storyboard[key].length - 1, step = stepMax; step >= 0; step-- ){ + type = (types[this.storyboard[key][step][KEY.TYPE]] || null); + if( this.storyboard[key][step][KEY.TIME] <= now ){ var from = this.storyboard[key][step]; var to = this.storyboard[key][Math.min(step + 1, stepMax)]; - var values = new Array(); - for( var valueIndex = 0, length = to[KEY.VALUE].length; valueIndex < length; valueIndex++ ){ var difference = to[KEY.VALUE][valueIndex] - from[KEY.VALUE][valueIndex]; var duration = to[KEY.TIME] - from[KEY.TIME]; - var elapsed = Math.min((((now - from[KEY.TIME]) / duration) || 0), 1) + var elapsed = Math.min((((now - from[KEY.TIME]) / duration) || 0), 1); - values[valueIndex] = from[KEY.VALUE][valueIndex] + (easings[to[KEY.EASING]][KEY.EASING](elapsed, 1, to[KEY.OPTION]) * difference); + values[valueIndex] = from[KEY.VALUE][valueIndex] + (easings[to[KEY.EASING]][1](elapsed, 1, to[KEY.OPTION]) * difference); }; - return (values.length == 1 ? values[0] : values); + break; } else if( step == 0 ){ - var values = this.storyboard[key][step][KEY.VALUE]; + values = this.storyboard[key][step][KEY.VALUE]; - return (values.length == 1 ? values[0] : values); + break; }; }; + if( type != null ){ + + values = type[1](values); + + }; + + return (values.length == 1 ? values[0] : values); + }; return null; @@ -114,16 +134,67 @@ Storyline.methods.initialize.prototype = Storyline.methods; + Storyline.registerType = function( name, typeFunction ){ + + types.push([name, typeFunction]); + + }; + + Storyline.getType = function( name ){ + + for( var type = 0, length = types.length; type < length; type++ ){ + + if( name == types[type][0] ){ + + return type; + + }; + + }; + + return null; + + }; + + Storyline.registerType("int", function( options ){ + + for( var option = 0, length = options.length; option < length; option++ ){ + + options[option] = parseInt(options[option]); + + }; + + return options; + + }); + + Storyline.registerType("vec2", function( options ){ + + options.x = options[0]; + options.y = options[1]; + + return options; + + }); + + Storyline.registerType("vec3", function( options ){ + + options.x = options[0]; + options.y = options[1]; + options.z = options[2]; + + return options; + + }); + Storyline.registerEasing = function( name, easingFunction ){ - easings.push([name.toLowerCase(), easingFunction]); + easings.push([name, easingFunction]); }; Storyline.getEasing = function( name ){ - name = name.toLowerCase(); - for( var easing = 0, length = easings.length; easing < length; easing++ ){ if( name == easings[easing][0] ){ @@ -150,19 +221,19 @@ }); - Storyline.registerEasing("easein", function( elapsed, duration, options ){ + Storyline.registerEasing("easeIn", function( elapsed, duration, options ){ return elapsed * elapsed * elapsed; }); - Storyline.registerEasing("easeout", function( elapsed, duration, options ){ + Storyline.registerEasing("easeOut", function( elapsed, duration, options ){ return (elapsed -= 1) * elapsed * elapsed + 1; }); - Storyline.registerEasing("easeinout", function( elapsed, duration, options ){ + Storyline.registerEasing("easeInOut", function( elapsed, duration, options ){ if( (elapsed /= duration / 2) < 1 ){ From 96116494e9665bbeab8eb5b273356fd7009ad861 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Mon, 14 Mar 2016 16:33:57 +0100 Subject: [PATCH 10/20] add bool() type (return true if value is upper or equal to 1), publish 1.2.0 --- examples/index.html | 9 +++++++++ package.json | 2 +- storyline.js | 12 ++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/examples/index.html b/examples/index.html index 95fcdf1..d08f0a6 100644 --- a/examples/index.html +++ b/examples/index.html @@ -72,6 +72,11 @@ vec3: [ "0 cut to vec3(0,0,0)", "1000 easeIn to vec3(1,0.5,0.25)" + ], + bool: [ + "0 cut to bool(0)", + "500 linear to bool(1)", + "1000 linear to bool(2)" ] }); @@ -83,6 +88,7 @@ var quadraticCurve = new CanvasCurve(200); var cubicCurve = new CanvasCurve(200); var vec3Curve = new CanvasCurve(200); + var boolCurve = new CanvasCurve(200); var delay = 0; var now = 0; @@ -123,6 +129,9 @@ var vec3 = storyline.get("vec3", now); vec3Curve.drawVector3(time, vec3, ["#F00", "#0F0", "#00F"]); + var bool = storyline.get("bool", now); + boolCurve.drawEasing(time, linear, (bool ? "#0F0" : "#F00")); + }; }; diff --git a/package.json b/package.json index 654511d..9a925a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.1.4", + "version": "1.2.0", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { diff --git a/storyline.js b/storyline.js index 997859c..7fdf822 100644 --- a/storyline.js +++ b/storyline.js @@ -168,6 +168,18 @@ }); + Storyline.registerType("bool", function( options ){ + + for( var option = 0, length = options.length; option < length; option++ ){ + + options[option] = (parseInt(options[option]) ? true : false); + + }; + + return options; + + }); + Storyline.registerType("vec2", function( options ){ options.x = options[0]; From 2952f1a561d6d818437ec8612485116a8b846c9a Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 17 Mar 2016 13:50:12 +0100 Subject: [PATCH 11/20] Rewrite readme --- README.md | 224 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 88 deletions(-) diff --git a/README.md b/README.md index caf758d..80563ff 100644 --- a/README.md +++ b/README.md @@ -1,135 +1,183 @@ -# Storyline.js - Multi-purpose sequencer +# Storyline.js - JavaScript Animation Sequencer **Storyline.js** is a library to help define a storyboard using natural language. -This is the refined and polished version of the sytem created for [BEYOND](http://b-e-y-o-n-d.com/) and [cru·ci·form](http://www.clicktorelease.com/code/cruciform/). +[Check all the demos](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point) -Check out the example to see it in action: [Storyline.js with CSS 2D transforms](http://www.clicktorelease.com/tools/storylinejs/). +### How to? -[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/mQVU3Lb0D-w/0.jpg)](http://www.youtube.com/watch?v=mQVU3Lb0D-w) +The Storyline class only come with two options : + - storyboard: a simple object containing all keyframes. + - timescale: (optional) multiply all key's time with it. -#### Using Storyline.js #### - -There's two parts: Storyline.js is the parser and player, and then a storyboard source object that defines the story. A storyline source has this format: +```javascript + var storyline = new Storyline(storyboard [, timescale]); +``` -```json -{ - "value1": [ - "0 cut to 10", - "2 linear to 3" - ], - - "value2": [ - "0 cut to 0", - "4 easeinout to 1", - "6 easeinout to 0" - ] -} +#### Storyboard hierarchy + + - name: the name of the animation. + - time: the begining of the current value to the next one in milliseconds. + - easing: the easing to use. + - value: the value(s) to animate (multiple values are between parenthesis). + +```javascript + { + {name}: [ + "{time} {easing} to {value}", + "{time} {easing} to {value}", + "{time} {easing} to {value}" + ], + {name}: [ + "{time} {easing} to ({value}, {value}, {value})", + "{time} {easing} to ({value}, {value}, {value})" + ] + } ``` -This source object is a map of keys (each key is a value that you will be using in your code *x*, *angle*, *power*, etc.), and each key contains an array of entries. Each entry defines a point in time, and a storyline action, and has the following syntax: +#### Timing + +Each key times are in milliseconds. + +```javascript + var storyline = new Storyline({ + key1: [ + "0 cut to 0", + "500 linear to 1", + "1000 linear to 2" + ] + }); ``` -{time in seconds} {action to perform} {value of action} + +You may need to create animations with a limited duration, you can use the `timescale` option to do that. +Each time will be multiplied by the `timescale`. + +```javascript + + var duration = 5000; // timescale of 5s + + var storyline = new Storyline({ + key1: [ + "0 cut to 0", + "0.3 linear to 3", + "1 linear to 4" + ] + }, duration); ``` -The actions are: -- *cut to* instanteously changes to {value} -- *linear to* will linearly interpolate from the last defined value to {value} -- *easein to* will ease in from the last defined value to {value} -- *easeout to* will ease out from the last defined value to {value} -- *easeinout to* will ease in and out from the last defined value to {value} +#### Easing + +There is already some basic easings: + - cut: immediately switch to the value if the time is upper or equal to the key. + - linear: linearly interpolate to the value. + - easeIn: ease in from the previous value to the key value. + - easeOut: ease out from the previous value to the key value. + - easeInOut: ease in and out from the previous value to the key value. + - quadratic(from,c,to): get value along a qaudratic bezier curve (see [stackoverflow explainations](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point)). + - cubic(from,cx,cy,to): get value along a cubic bezier curve (see [stackoverflow explainations](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point)). -and you can register your own easing with the "registerEasing" method. +But you can also register your own easings: -#### Minimal example #### +```javascript + Storyline.registerEasing(customEasingName, function( elapsed, duration, options ){ -Include Storyline.js + return (elapsed / duration); // Linear easing -```html - + }); ``` -Create a storyline from a structured storyboard source. By calling storyline.get you can get the updated value: + - elpsed: normalized elpased time (between 0 and 1). + - duration: normalized duration (always 1...) + - options: array of values, only if the easing take options (parenthesis with parameters). -```js -var storyline = STORYLINE.parseStoryline( { - "value1": [ - "0 cut to 0", - "5 easeinout to 1", - "10 easeinout to 0" - ] - -} ); +#### Type -function update() { - - requestAnimationFrame( update ); - console.log( storyline.get( 'value1', ( Date.now() / 1000 ) % 10 ) ); - -} +You can animate one or many values in each keys but you can also use types: +int: only returns integers. +bool: return true if the value is upper or equal to 1, else return false. +vec2: return the values with `.x` and `.y` getters. +vec3: return the values with `.x`, `.y` and `.z` getters. -update(); -``` +But you can also register your own types: + +```javascript + Storyline.registerType("invert", function( options ){ -#### External storyboard example #### + for( var option = 0, length = options.length; option < length; option++ ){ -Simply export the storyline into its own file, and include it like a normal script. + options[option] = (options[option] * -1); -```js -var storyline = new Storyline({ + }; - "value1": [ + return options; + + }); +``` + +### Examples + +#### Simple + +```javascript + var storyline = new Storyline({ + key1: [ "0 cut to 0", - "5 easeinout to 1", - "10 easeinout to 0" + "500 easeIn to 360", + "1000 linear to 180" + ], + key2: [ + "500 cut to 180", + "1000 lienar to 0" ] - -}); -``` + }); -Or load the content with AJAX and parse it when it's loaded: + function update( now ){ -```js -var oReq = new XMLHttpRequest(); -oReq.onload = function() { - storyline = new Storyboard(this.responseText); - /* ready to use */ -}; -oReq.open('get', 'storyboard.json', true); -oReq.send(); -``` + window.requestAnimationFrame(update); -#### Register an easing function #### + var key1 = storyline.get("key1", now); + var key2 = storyline.get("key2", now); -```js -Storyline.registerEasing("easingname", function( elapsed, duration ){ - - return elaped / duration; // linear easing + }; -}); + window.requestAnimationFrame(update); ``` -### Status #### +#### With fixed duration -This is the first release. Next steps are to add syntax to control the easing functions, probably something like: +```javascript + var storyline = new Storyline({ + key1: [ + "0 cut to 0", + "0.5 easeIn to 360", + "1 linear to 180" + ], + key2: [ + "0.5 cut to 180", + "1 lienar to 0" + ] + }, 1000); -``` -{time} ease to {value} { [ set of easing control points] } -``` + function update( now ){ -Also, support specific functions to simplify animations: + window.requestAnimationFrame(update); -``` -{time} {wiggle|shake} {extent} + var key1 = storyline.get("key1", now); + var key2 = storyline.get("key2", now); + + }; + + window.requestAnimationFrame(update); ``` -As always: forks, pull requests and code critiques are welcome! +[Check all the demos/examples](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point) -#### License #### +#### License MIT licensed -Copyright (C) 2015 Jaume Sanchez Elias, http://www.clicktorelease.com \ No newline at end of file +Original idea from [Jaume Sanchez Elias](http://www.clicktorelease.com) +Entirely rewrited by [Jordan Delcros](http://www.jordan-delcros.com) \ No newline at end of file From 6dbb7d74cdb67eec9cbec632c03428bf9c7f0d05 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 17 Mar 2016 13:51:07 +0100 Subject: [PATCH 12/20] publish update on npm --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9a925a9..7eb711b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.2.0", + "version": "1.2.1", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { From dc8832ad17cb2da20f63c18c1e43a9bfc4e5e1b0 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Thu, 17 Mar 2016 16:25:33 +0100 Subject: [PATCH 13/20] fix readme --- README.md | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 80563ff..3ecb1b1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Storyline.js** is a library to help define a storyboard using natural language. -[Check all the demos](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point) +[Check all the demos](http://jordandelcros.github.io/Storyline.js/) ### How to? @@ -96,10 +96,10 @@ But you can also register your own easings: #### Type You can animate one or many values in each keys but you can also use types: -int: only returns integers. -bool: return true if the value is upper or equal to 1, else return false. -vec2: return the values with `.x` and `.y` getters. -vec3: return the values with `.x`, `.y` and `.z` getters. + - int: only returns integers. + - bool: return true if the value is upper or equal to 1, else return false. + - vec2: return the values with `.x` and `.y` getters. + - vec3: return the values with `.x`, `.y` and `.z` getters. But you can also register your own types: @@ -173,7 +173,7 @@ But you can also register your own types: window.requestAnimationFrame(update); ``` -[Check all the demos/examples](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point) +[Check all the demos/examples](http://jordandelcros.github.io/Storyline.js/) #### License diff --git a/package.json b/package.json index 7eb711b..89a717b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.2.1", + "version": "1.2.2", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { From f7fe2d0b81c4c4384f6801bad638062640ac57a3 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Fri, 18 Mar 2016 11:15:39 +0100 Subject: [PATCH 14/20] add ease In/Out/inOut - Elastic/Bounce, add color type support --- examples/index.html | 68 ++++++++++++ storyline.js | 257 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 316 insertions(+), 9 deletions(-) diff --git a/examples/index.html b/examples/index.html index d08f0a6..170c2c8 100644 --- a/examples/index.html +++ b/examples/index.html @@ -53,6 +53,30 @@ "0 cut to 0", "1000 easeInOut to 1" ], + easeinelastic: [ + "0 cut to 0", + "1000 easeInElastic to 1" + ], + easeoutelastic: [ + "0 cut to 0", + "1000 easeOutElastic to 1" + ], + easeinoutelastic: [ + "0 cut to 0", + "1000 easeInOutElastic to 1" + ], + easeinbounce: [ + "0 cut to 0", + "1000 easeInBounce to 1" + ], + easeoutbounce: [ + "0 cut to 0", + "1000 easeOutBounce to 1" + ], + easeinoutbounce: [ + "0 cut to 0", + "1000 easeInOutBounce to 1" + ], quadraticX: [ "0 cut to 0", "1000 quadratic(0," + Math.random() + ",1) to 1" @@ -77,6 +101,10 @@ "0 cut to bool(0)", "500 linear to bool(1)", "1000 linear to bool(2)" + ], + color: [ + "0 cut to color(0xFF0000)", + "1000 linear to color(0x00FF00)" ] }); @@ -85,10 +113,17 @@ var easeinCurve = new CanvasCurve(200); var easeoutCurve = new CanvasCurve(200); var easeinoutCurve = new CanvasCurve(200); + var easeinelasticCurve = new CanvasCurve(200); + var easeoutelasticCurve = new CanvasCurve(200); + var easeinoutelasticCurve = new CanvasCurve(200); + var easeinbounceCurve = new CanvasCurve(200); + var easeoutbounceCurve = new CanvasCurve(200); + var easeinoutbounceCurve = new CanvasCurve(200); var quadraticCurve = new CanvasCurve(200); var cubicCurve = new CanvasCurve(200); var vec3Curve = new CanvasCurve(200); var boolCurve = new CanvasCurve(200); + var colorCurve = new CanvasCurve(200); var delay = 0; var now = 0; @@ -118,6 +153,24 @@ var easeinout = storyline.get("easeinout", now); easeinoutCurve.drawEasing(time, easeinout); + var easeinelastic = storyline.get("easeinelastic", now); + easeinelasticCurve.drawEasing(time, easeinelastic); + + var easeoutelastic = storyline.get("easeoutelastic", now); + easeoutelasticCurve.drawEasing(time, easeoutelastic); + + var easeinoutelastic = storyline.get("easeinoutelastic", now); + easeinoutelasticCurve.drawEasing(time, easeinoutelastic); + + var easeinbounce = storyline.get("easeinbounce", now); + easeinbounceCurve.drawEasing(time, easeinbounce); + + var easeoutbounce = storyline.get("easeoutbounce", now); + easeoutbounceCurve.drawEasing(time, easeoutbounce); + + var easeinoutbounce = storyline.get("easeinoutbounce", now); + easeinoutbounceCurve.drawEasing(time, easeinoutbounce); + var quadraticX = storyline.get("quadraticX", now); var quadraticY = storyline.get("quadraticY", now); quadraticCurve.drawEasing(quadraticX, quadraticY); @@ -132,6 +185,9 @@ var bool = storyline.get("bool", now); boolCurve.drawEasing(time, linear, (bool ? "#0F0" : "#F00")); + var color = storyline.get("color", now); + colorCurve.drawColor(time, linear, color.hexString); + }; }; @@ -190,6 +246,18 @@ this.context.fillStyle = (colors[2] || "#FFF"); this.context.fillRect(t, z, 2, 2); + }, + drawColor: function( time, value, color ){ + + var x = (time * this.size) - 1; + var y = this.size - (value * this.size) - 1; + + this.context.fillStyle = (color || "#FFF"); + this.context.fillRect(x, 0, 1, this.size); + + this.context.fillStyle = "#FFF"; + this.context.fillRect(x, y, 2, 2); + } }; diff --git a/storyline.js b/storyline.js index 7fdf822..d142fe3 100644 --- a/storyline.js +++ b/storyline.js @@ -38,14 +38,26 @@ var easingOptions = (easing[2] != undefined ? easing[2].split(/\,/g) : null); var type = Storyline.getType((story[key][step].match(/([a-z0-9]+)\([^\)]+\)$/) || "")[1]); - var extractedValue = story[key][step].match(/(?:(\-?\s*[0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0].match(/(\-?\s*[0-9]+\.?[0-9]*)/g); - var value = extractedValue.map(function( number ){ + var extractedValue = story[key][step].match(/(?:(\-?\s*[0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0].match(/(\-?\s*(?:0x)?[0-9A-F]+\.?[0-9]*)/gi); - return parseFloat(number); + var values = null; - }); + if( type != undefined && types[type] != undefined && types[type][2] != undefined ){ - this.set(key, time, easingMode, easingOptions, value, type); + values = types[type][2](extractedValue); + + } + else { + + values = extractedValue.map(function( number ){ + + return parseFloat(number); + + }); + + }; + + this.set(key, time, easingMode, easingOptions, values, type); }; @@ -54,7 +66,7 @@ return this; }, - set: function( key, time, easing, options, value, type ){ + set: function( key, time, easing, options, values, type ){ time *= this.timeScale; @@ -66,7 +78,7 @@ }; - this.storyboard[key].push([time, easing, options, value, type]); + this.storyboard[key].push([time, easing, options, values, type]); this.storyboard[key].sort(function( before, after ){ @@ -134,9 +146,9 @@ Storyline.methods.initialize.prototype = Storyline.methods; - Storyline.registerType = function( name, typeFunction ){ + Storyline.registerType = function( name, getFunction, setFunction ){ - types.push([name, typeFunction]); + types.push([name, getFunction, setFunction]); }; @@ -199,6 +211,52 @@ }); + Storyline.registerType("color", function( options ){ + + options.r = options[0]; + options.g = options[1]; + options.b = options[2]; + options.a = options[3]; + + options.hex = (options[0] * 255) << 16 ^ (options[1] * 255) << 8 ^ (options[2] * 255) << 0; + options.hexString = "#" + ("000000" + options.hex.toString(16)).slice(-6); + + return options; + + }, function( options ){ + + if( /^0x[0-9A-F]+/i.test(options[0]) == true ){ + + var hexadecimal = parseInt(options[0]); + + options[0] = ((hexadecimal >> 16 & 255) / 255); + options[1] = ((hexadecimal >> 8 & 255) / 255); + options[2] = ((hexadecimal & 255) / 255); + options[3] = 1; + + } + else if( options.length == 3 ){ + + options[3] = 1; + + }; + + return options.map(function( number ){ + + number = parseFloat(number); + + if( number > 1 ){ + + number /= 255; + + }; + + return number; + + }); + + }); + Storyline.registerEasing = function( name, easingFunction ){ easings.push([name, easingFunction]); @@ -260,6 +318,187 @@ }); + Storyline.registerEasing("easeInElastic", function( elapsed, duration, options ){ + + if( elapsed == 0 ){ + + return 0; + + } + else if( (elapsed /= duration) == 1 ){ + + return 1; + + } + else { + + return -(1 * Math.pow(2, 10 * (elapsed -= 1)) * Math.sin((elapsed * duration - ((duration * 0.3) / (2 * Math.PI) * Math.asin(1))) * (2 * Math.PI) / (duration * 0.3))); + + }; + + }); + + Storyline.registerEasing("easeOutElastic", function( elapsed, duration, options ){ + + if( elapsed == 0 ){ + + return 0; + + } + else if( (elapsed /= duration) == 1 ){ + + return 1; + + } + else { + + return Math.pow(2, -10 * elapsed) * Math.sin((elapsed * duration - ((duration * 0.3) / (2 * Math.PI) * Math.asin(1))) * (2 * Math.PI) / (duration * 0.3)) + 1; + + }; + + }); + + Storyline.registerEasing("easeInOutElastic", function( elapsed, duration, options ){ + + if( elapsed === 0){ + + return 0; + + } + else if( (elapsed /= duration / 2) === 2 ){ + + return 1; + + } + else { + + var progress = (duration * (0.3 * 1.5)); + var speed = ((duration * (0.3 * 1.5)) / (2 * Math.PI) * Math.asin(1)); + + if( elapsed < 1 ){ + + return -0.5 * (1 * Math.pow(2, 10 * (elapsed -= 1)) * Math.sin((elapsed * duration - ((duration * (0.3 * 1.5)) / (2 * Math.PI) * Math.asin(1))) * (2 * Math.PI) / (duration * (0.3 * 1.5)))); + + } + else { + + return Math.pow(2, -10 * (elapsed -= 1)) * Math.sin((elapsed * duration - ((duration * (0.3 * 1.5)) / (2 * Math.PI) * Math.asin(1))) * (2 * Math.PI) / (duration * (0.3 * 1.5))) * 0.5 + 1; + + }; + + }; + + }); + + Storyline.registerEasing("easeInBounce", function( elapsed, duration, options ){ + + elapsed = (duration - elapsed); + + if( (elapsed /= duration) < (1 / 2.75) ){ + + return 1 - (1 * (7.5625 * elapsed * elapsed)); + + } + else if( elapsed < (2 / 2.75) ){ + + return 1 - (1 * (7.5625 * (elapsed -= (1.5 / 2.75)) * elapsed + 0.75)); + + } + else if( elapsed < (2.5 / 2.75) ){ + + return 1 - (1 * (7.5625 * (elapsed -= (2.25 / 2.75)) * elapsed + 0.9375)); + + } + else { + + return 1 - (1 * (7.5625 * (elapsed -= (2.625 / 2.75)) * elapsed + 0.984375)); + + }; + + }); + + Storyline.registerEasing("easeOutBounce", function( elapsed, duration, options ){ + + if( (elapsed /= duration) < (1 / 2.75) ){ + + return (1 * (7.5625 * elapsed * elapsed)); + + } + else if( elapsed < (2 / 2.75) ){ + + return (1 * (7.5625 * (elapsed -= (1.5 / 2.75)) * elapsed + 0.75)); + + } + else if( elapsed < (2.5 / 2.75) ){ + + return (1 * (7.5625 * (elapsed -= (2.25 / 2.75)) * elapsed + 0.9375)); + + } + else { + + return (1 * (7.5625 * (elapsed -= (2.625 / 2.75)) * elapsed + 0.984375)); + + }; + + }); + + Storyline.registerEasing("easeInOutBounce", function( elapsed, duration, options ){ + + if( elapsed < (duration / 2) ){ + + elapsed = (duration - (elapsed * 2)); + + if( (elapsed /= duration) < (1 / 2.75) ){ + + return ((1 - (1 * (7.5625 * elapsed * elapsed))) * 0.5); + + } + else if( elapsed < (2 / 2.75) ){ + + return ((1 - (1 * (7.5625 * (elapsed -= (1.5 / 2.75)) * elapsed + 0.75))) * 0.5); + + } + else if( elapsed < (2.5 / 2.75) ){ + + return ((1 - (1 * (7.5625 * (elapsed -= (2.25 / 2.75)) * elapsed + 0.9375))) * 0.5); + + } + else { + + return ((1 - (1 * (7.5625 * (elapsed -= (2.625 / 2.75)) * elapsed + 0.984375))) * 0.5); + + }; + + } + else { + + elapsed = ((elapsed * 2) - duration); + + if( (elapsed /= duration) < (1 / 2.75) ){ + + return (1 * (7.5625 * elapsed * elapsed)) * 0.5 + 1 * 0.5; + + } + else if( elapsed < (2 / 2.75) ){ + + return (1 * (7.5625 * (elapsed -= (1.5 / 2.75)) * elapsed + 0.75)) * 0.5 + 1 * 0.5; + + } + else if( elapsed < (2.5 / 2.75) ){ + + return (1 * (7.5625 * (elapsed -= (2.25 / 2.75)) * elapsed + 0.9375)) * 0.5 + 1 * 0.5; + + } + else { + + return (1 * (7.5625 * (elapsed -= (2.625 / 2.75)) * elapsed + 0.984375)) * 0.5 + 1 * 0.5; + + }; + + }; + + }); + Storyline.registerEasing("quadratic", function( elapsed, duration, options ){ var invertedElapsed = 1 - elapsed; From 7120c0d3afdd60b46a626a054b9716eee049e08c Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Fri, 18 Mar 2016 11:22:21 +0100 Subject: [PATCH 15/20] publish npm 1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 89a717b..792c292 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.2.2", + "version": "1.3.0", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { From 9575e84abc3a4bbb6bb66c4e6341073351f76120 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Fri, 18 Mar 2016 18:13:17 +0100 Subject: [PATCH 16/20] update readme --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3ecb1b1..a9ccaf9 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ The Storyline class only come with two options : } ``` - #### Timing Each key times are in milliseconds. @@ -66,7 +65,6 @@ Each time will be multiplied by the `timescale`. }, duration); ``` - #### Easing There is already some basic easings: @@ -75,6 +73,12 @@ There is already some basic easings: - easeIn: ease in from the previous value to the key value. - easeOut: ease out from the previous value to the key value. - easeInOut: ease in and out from the previous value to the key value. + - easeInElastic: ease in elastic from the previous value to the key value. + - easeOutElastic: ease out elastic from the previous value to the key value. + - easeInOutElastic: ease in and out elastic from the previous value to the key value. + - easeInBounce: ease in bounce from the previous value to the key value. + - easeOutBounce: ease out bounce from the previous value to the key value. + - easeInOutBounce: ease in and out bounce from the previous value to the key value. - quadratic(from,c,to): get value along a qaudratic bezier curve (see [stackoverflow explainations](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point)). - cubic(from,cx,cy,to): get value along a cubic bezier curve (see [stackoverflow explainations](http://stackoverflow.com/questions/5634460/quadratic-bezier-curve-calculate-point)). @@ -92,7 +96,6 @@ But you can also register your own easings: - duration: normalized duration (always 1...) - options: array of values, only if the easing take options (parenthesis with parameters). - #### Type You can animate one or many values in each keys but you can also use types: @@ -100,6 +103,7 @@ You can animate one or many values in each keys but you can also use types: - bool: return true if the value is upper or equal to 1, else return false. - vec2: return the values with `.x` and `.y` getters. - vec3: return the values with `.x`, `.y` and `.z` getters. + - color: return the values with `.r`, `.g`, `.b`, `hex` and `hexString` getters. But you can also register your own types: From fced4242c98919b8f17918e0fb487e28c118d238 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Fri, 18 Mar 2016 18:14:02 +0100 Subject: [PATCH 17/20] publish npm 1.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 792c292..adc9ae5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.3.0", + "version": "1.3.1", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { From ea5b3cb78986174d22baf7cf4d55e07e5eec5218 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Tue, 29 Mar 2016 14:43:03 +0200 Subject: [PATCH 18/20] add origins options/values to registertype() to make more powerfull things --- storyline.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/storyline.js b/storyline.js index d142fe3..a31edb9 100644 --- a/storyline.js +++ b/storyline.js @@ -38,13 +38,14 @@ var easingOptions = (easing[2] != undefined ? easing[2].split(/\,/g) : null); var type = Storyline.getType((story[key][step].match(/([a-z0-9]+)\([^\)]+\)$/) || "")[1]); - var extractedValue = story[key][step].match(/(?:(\-?\s*[0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0].match(/(\-?\s*(?:0x)?[0-9A-F]+\.?[0-9]*)/gi); + var givenValue = story[key][step].match(/(?:(\-?\s*[0-9]+\.?[0-9]*)|\(([^\)]+)\))$/g)[0]; + var extractedValue = givenValue.match(/(\-?\s*(?:(?:0x)[0-9A-F]+|[0-9]+)\.?[0-9]*)/gi); var values = null; if( type != undefined && types[type] != undefined && types[type][2] != undefined ){ - values = types[type][2](extractedValue); + values = types[type][2](extractedValue, givenValue); } else { @@ -121,7 +122,7 @@ } else if( step == 0 ){ - values = this.storyboard[key][step][KEY.VALUE]; + values = this.storyboard[key][step][KEY.VALUE].slice(0); break; @@ -131,7 +132,7 @@ if( type != null ){ - values = type[1](values); + values = type[1](values, this.storyboard[key][step][KEY.VALUE]); }; @@ -168,7 +169,7 @@ }; - Storyline.registerType("int", function( options ){ + Storyline.registerType("int", function( options, originString ){ for( var option = 0, length = options.length; option < length; option++ ){ @@ -180,7 +181,7 @@ }); - Storyline.registerType("bool", function( options ){ + Storyline.registerType("bool", function( options, originString ){ for( var option = 0, length = options.length; option < length; option++ ){ @@ -192,7 +193,7 @@ }); - Storyline.registerType("vec2", function( options ){ + Storyline.registerType("vec2", function( options, originString ){ options.x = options[0]; options.y = options[1]; @@ -201,7 +202,7 @@ }); - Storyline.registerType("vec3", function( options ){ + Storyline.registerType("vec3", function( options, originString ){ options.x = options[0]; options.y = options[1]; @@ -211,7 +212,7 @@ }); - Storyline.registerType("color", function( options ){ + Storyline.registerType("color", function( options, originString ){ options.r = options[0]; options.g = options[1]; @@ -223,7 +224,7 @@ return options; - }, function( options ){ + }, function( options, originOptions ){ if( /^0x[0-9A-F]+/i.test(options[0]) == true ){ From 460df61d007aa60b311796c6a870ca20b1823219 Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Tue, 29 Mar 2016 14:46:54 +0200 Subject: [PATCH 19/20] update readme and npm publish --- README.md | 11 +++++++++-- package.json | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a9ccaf9..9e1c2b5 100644 --- a/README.md +++ b/README.md @@ -107,18 +107,25 @@ You can animate one or many values in each keys but you can also use types: But you can also register your own types: +`Storyline.registerType(name, getter, setter)` + ```javascript - Storyline.registerType("invert", function( options ){ + Storyline.registerType("invert", function( options, originOptions ){ for( var option = 0, length = options.length; option < length; option++ ){ - options[option] = (options[option] * -1); + options[option] *= -1; }; return options; + }, function( options, originString ){ + + return options; + }); + ``` ### Examples diff --git a/package.json b/package.json index adc9ae5..d6c3736 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.3.1", + "version": "1.4.0", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { From 53f89930d8d09fdf11a57c726353caafa55f196b Mon Sep 17 00:00:00 2001 From: Jordan Delcros Date: Wed, 27 Apr 2016 18:37:52 +0200 Subject: [PATCH 20/20] fix support of negative time --- package.json | 2 +- storyline.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d6c3736..2781b9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "storyline.js", - "version": "1.4.0", + "version": "1.4.1", "description": "javascript animation sequencer", "main": "storyline.js", "scripts": { diff --git a/storyline.js b/storyline.js index a31edb9..a04dba8 100644 --- a/storyline.js +++ b/storyline.js @@ -31,7 +31,7 @@ for( var step in story[key] ){ - var time = parseFloat(story[key][step].match(/^\s*([0-9]+\.?[0-9]*)/g)[0]); + var time = parseFloat(story[key][step].match(/^\s*(\-\s*)?([0-9]+\.?[0-9]*)/g)[0]); var easing = story[key][step].match(/([a-z]+)(?:\((.*)\))?/i); var easingMode = Storyline.getEasing(easing[1]);