├── .gitignore ├── LawsOfMotion.pdf ├── examples ├── complex.html ├── sequential.html └── simple.html ├── morphr.gif ├── morphr.js ├── morphr.min.js ├── morphr2.gif ├── package.json └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | node_modules -------------------------------------------------------------------------------- /LawsOfMotion.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goessner/morphr/72bb7cae3ea7e201a9010584d477c8e6afd7545f/LawsOfMotion.pdf -------------------------------------------------------------------------------- /examples/complex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Morphr Complex 6 | 7 | 8 | 9 |

Morphr Complex

10 |
11 | 12 | 13 | 14 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /examples/sequential.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Morphr Sequential 6 | 7 | 8 | 9 |

Morphr Sequential

10 |
11 | 12 | 13 | 14 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /examples/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Morphr Simple 6 | 7 | 8 | 9 |

Morphr Simple

10 | 11 | 12 | 13 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /morphr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goessner/morphr/72bb7cae3ea7e201a9010584d477c8e6afd7545f/morphr.gif -------------------------------------------------------------------------------- /morphr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Morphr (c) 2016 Stefan Goessner 3 | * @license 4 | * MIT License 5 | */ 6 | 7 | "use strict"; 8 | 9 | /** 10 | * `Morphr` is a tiny class for simultaneously morphing numerical object values in a given time interval. 11 | * Use case is most often parameter animation of plain javascript objects. So it works excellently with 12 | * canvas. `Morphr` depends on `requestAnimationFrame`. 13 | * 14 | * Do not use `new Morphr()`, call `Morphr.create()` instead for creating instances. 15 | * @class 16 | */ 17 | var Morphr = { 18 | /** 19 | * Create a `Morphr` instance by start time, duration and timing function for morphing. A couple of predefined 20 | * timing functions are available [s. VDI2143]: 21 | * * `linear` 22 | * * `quadratic` 23 | * * `sinoid` 24 | * * `poly5` 25 | * @returns {object} `Morphr` instance. 26 | * @param {float} [dt=2] Duration in [s]. 27 | * @param {float} [t0=0] Start time in [s] relative to first time call of `start` method. 28 | * @param {function|string} [fn="linear"] Timing function as `function` object or name of predefined function. 29 | */ 30 | create: function() { var o = Object.create(this.prototype); o.constructor.apply(o,arguments); return o; }, 31 | prototype: { 32 | constructor: function(dt,t0,fn) { 33 | this.dt = (dt || 2)*1000; // use ms ... 34 | this.t0 = (t0 || 0)*1000; // use ms ... 35 | this.fn = typeof fn === "string" && Morphr[fn] ? Morphr[fn] 36 | : typeof fn === "function" ? fn : Morphr.linear; 37 | this.handlers = []; 38 | this.animateHdl = Morphr.prototype.animate.bind(this); 39 | }, 40 | /** 41 | * Register morphing handler function. 42 | * @returns {object} this. 43 | * @param {function} hdl Callback function `hdl(q){}`, where `q` is the - via `fn` - normalized time or the boolean value `false` to reset for a new start. 44 | */ 45 | register: function(hdl) { 46 | if (hdl) { 47 | var idx = this.handlers.indexOf(hdl); 48 | if (idx === -1) // not registered, so add .. 49 | this.handlers.push(hdl); 50 | else // already registered, so remove .. 51 | this.handlers.splice(idx,1); 52 | } 53 | return this; 54 | }, 55 | /** 56 | * Start morphing process. 57 | * @returns {object} this. 58 | */ 59 | start: function() { 60 | this.tbeg = false; 61 | for (var i=this.handlers.length-1; i>=0; --i) // reset handlers ... 62 | this.handlers[i](false); 63 | this.animate(0); 64 | return this; 65 | }, 66 | /** 67 | * @private 68 | */ 69 | animate: function animate(time) { 70 | var t = 0, tbeg = this.tbeg || (this.tbeg = time) || false; 71 | if (tbeg && (t = time - tbeg - this.t0) >= 0) { 72 | var q = this.fn(t/this.dt); // get normalized value by timing function. 73 | for (var i=this.handlers.length-1; i>=0; --i) // migrate to for (.. of ..) in near future .. 74 | this.handlers[i](q); 75 | } 76 | if (t <= this.dt) 77 | requestAnimationFrame(this.animateHdl); 78 | } 79 | }, 80 | // some simple motion laws (timing functions) from cam design (VDI 2143) ... all in interval [0,1] 81 | // penner functions 82 | linear: function(q) { return q; }, 83 | inQuad: function (q) { return q*q; }, 84 | outQuad: function (q) { return 1 - (--q)*q; }, 85 | inOutQuad: function (q) { return q < 0.5 ? 2*q*q : 1 - 2*(--q)*q; }, 86 | inCubic: function (q) { return q*q*q; }, 87 | outCubic: function (q) { return 1 + (--q)*q*q; }, 88 | inOutCubic: function (q) { return q < 0.5 ? 4*q*q*q : 1 + 4*(--q)*q*q; }, 89 | inQuart: function (q) { return q*q*q*q; }, 90 | outQuart: function (q) { return 1 - (--q)*q*q*q; }, 91 | inOutQuart: function (q) { return q < 0.5 ? 8*q*q*q*q : 1 - 8*(--q)*q*q*q; }, 92 | inQuint: function (q) { return q*q*q*q*q; }, 93 | outQuint: function (q) { return 1 + (--q)*q*q*q*q; }, 94 | inOutQuint: function (q) { return q < 0.5 ? 16*q*q*q*q*q : 1 - 16*(--q)*q*q*q*q; }, 95 | easeInQuart: function (t) { return t*t*t*t }, 96 | easeOutQuart: function (t) { return 1-(--t)*t*t*t }, 97 | easeInOutQuart: function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t }, 98 | easeInQuint: function (t) { return t*t*t*t*t }, 99 | easeOutQuint: function (t) { return 1+(--t)*t*t*t*t }, 100 | easeInOutQuint: function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t }, 101 | 102 | 103 | quadratic: function(z) { return z <= 0.5 ? 2*z*z : -2*z*z + 4*z - 1; }, 104 | sinoid: function(z) { return z - Math.sin(2*Math.PI*z)/2/Math.PI; }, 105 | poly5: function(z) { return 10*z*z*z - 15*z*z*z*z +6*z*z*z*z*z; } 106 | } 107 | 108 | // see http://greweb.me/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/ 109 | -------------------------------------------------------------------------------- /morphr.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Morphr (c) 2016 Stefan Goessner 3 | * @license 4 | * MIT License 5 | */ 6 | "use strict";var Morphr={create:function(){var o=Object.create(this.prototype);o.constructor.apply(o,arguments);return o},prototype:{constructor:function(dt,t0,fn){this.dt=(dt||2)*1e3;this.t0=(t0||0)*1e3;this.fn=typeof fn==="string"&&Morphr[fn]?Morphr[fn]:typeof fn==="function"?fn:Morphr.linear;this.handlers=[];this.animateHdl=Morphr.prototype.animate.bind(this)},register:function(hdl){if(hdl){var idx=this.handlers.indexOf(hdl);if(idx===-1)this.handlers.push(hdl);else this.handlers.splice(idx,1)}return this},start:function(){this.tbeg=false;for(var i=this.handlers.length-1;i>=0;--i)this.handlers[i](false);this.animate(0);return this},animate:function animate(time){var t=0,tbeg=this.tbeg||(this.tbeg=time)||false;if(tbeg&&(t=time-tbeg-this.t0)>=0){var q=this.fn(t/this.dt);for(var i=this.handlers.length-1;i>=0;--i)this.handlers[i](q)}if(t<=this.dt)requestAnimationFrame(this.animateHdl)}},linear:function(q){return q},inQuad:function(q){return q*q},outQuad:function(q){return 1- --q*q},inOutQuad:function(q){return q<.5?2*q*q:1-2*--q*q},inCubic:function(q){return q*q*q},outCubic:function(q){return 1+--q*q*q},inOutCubic:function(q){return q<.5?4*q*q*q:1+4*--q*q*q},inQuart:function(q){return q*q*q*q},outQuart:function(q){return 1- --q*q*q*q},inOutQuart:function(q){return q<.5?8*q*q*q*q:1-8*--q*q*q*q},inQuint:function(q){return q*q*q*q*q},outQuint:function(q){return 1+--q*q*q*q*q},inOutQuint:function(q){return q<.5?16*q*q*q*q*q:1-16*--q*q*q*q*q},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return 1- --t*t*t*t},easeInOutQuart:function(t){return t<.5?8*t*t*t*t:1-8*--t*t*t*t},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return 1+--t*t*t*t*t},easeInOutQuint:function(t){return t<.5?16*t*t*t*t*t:1+16*--t*t*t*t*t},quadratic:function(z){return z<=.5?2*z*z:-2*z*z+4*z-1},sinoid:function(z){return z-Math.sin(2*Math.PI*z)/2/Math.PI},poly5:function(z){return 10*z*z*z-15*z*z*z*z+6*z*z*z*z*z}}; -------------------------------------------------------------------------------- /morphr2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goessner/morphr/72bb7cae3ea7e201a9010584d477c8e6afd7545f/morphr2.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "morphr", 3 | "version": "0.7.9", 4 | "description": "Morphr - lightweight morphing numerical object values in a given time interval", 5 | "keywords": [ 6 | "morphing", 7 | "animation", 8 | "javascript", 9 | "transition", 10 | "canvas" 11 | ], 12 | "main": "morphr.js", 13 | "scripts": { 14 | "build": "npm run minify && npm run jsdoc && npm run cpsamp", 15 | "jsdoc": "jsdoc2md ./morphr.js > ./api.md", 16 | "minify": "uglifyjs --comments -o ./morphr.min.js ./morphr.js", 17 | "cpsamp": "copyfiles -f ./examples/*.html ../goessner.github.io/morphr/examples" 18 | }, 19 | "author": "Stefan Goessner ", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/goessner/morphr.git" 23 | }, 24 | "license": "MIT", 25 | "devDependencies": { 26 | "jsdoc-to-markdown": "^1.3.2", 27 | "uglifyjs": "^2.4.10" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![License](http://img.shields.io/:license-mit-blue.svg)](https://github.com/goessner/g2/license.txt) 2 | [![npm](https://img.shields.io/npm/v/morphr.svg)](https://www.npmjs.com/package/morphr) 3 | 4 | # Morphr 5 | 6 | Morphr is a tiny and lightweight javascript class for morphing numerical values of 7 | arbitrary, mostly plain javascript objects in a given time interval `dt` along a given range `dval`. 8 | Most often you will want to use it for animation. So it works excellently in combination with Html canvas. 9 | 10 | ## Example 11 | ![Morphr Example](./morphr.gif) 12 | 13 | (animated gif) 14 | see [example](https://goessner.github.io/morphr/examples/simple.html) 15 | 16 | ```html 17 |

Morphr Example

18 | 19 | 20 | 21 | 42 | ``` 43 | Sequential morphing is easily achieved via multiple Morphr objects. DOM element attributes are morphable as well. 44 | 45 | see [sequential](https://goessner.github.io/morphr/examples/sequential.html) 46 | 47 | Here is a more complex canvas based [Crank-Rocker animation](https://goessner.github.io/morphr/examples/complex.html) using 48 | a [g2](https://github.com/goessner/g2) command queue for vector graphics. 49 | 50 | Maybe you want to learn a bit more about [Crank-Rockers](https://github.com/goessner/crocker). 51 | 52 | ## GitCDN 53 | Use the link [https://gitcdn.xyz/repo/goessner/g2/master/morphr.min.js](https://gitcdn.xyz/repo/goessner/morphr/master/morphr.min.js) 54 | for getting the latest commit as a raw file. 55 | 56 | In HTML use ... 57 | ```html 58 | 59 | ``` 60 | 61 | ## API Reference 62 | 63 | `Morphr` is a tiny class for simultaneously morphing numerical object values in a given time interval. 64 | Use case is most often parameter animation of plain javascript objects. So it works excellently with 65 | canvas. `Morphr` depends on `requestAnimationFrame`. 66 | 67 | Do not use `new Morphr()`, call `Morphr.create()` instead for creating instances. 68 | 69 | * [Morphr](#Morphr) 70 | * _static_ 71 | * [.create([dt], [t0], [fn])](#Morphr.create) ⇒ object 72 | * _instance_ 73 | * [.register(hdl)](#Morphr+register) ⇒ object 74 | * [.start()](#Morphr+start) ⇒ object 75 | 76 | 77 | ### Morphr.create([dt], [t0], [fn]) ⇒ object 78 | Create a `Morphr` instance by start time, duration and timing function for morphing. A couple of predefined 79 | timing functions are available [s. VDI2143]: 80 | * `linear` 81 | * `quadratic` 82 | * `sinoid` 83 | * `poly5` 84 | 85 | **Kind**: static method of [Morphr](#Morphr) 86 | **Returns**: object - `Morphr` instance. 87 | 88 | | Param | Type | Default | Description | 89 | | --- | --- | --- | --- | 90 | | [dt] | float | 2 | Duration in [s]. | 91 | | [t0] | float | 0 | Start time in [s] relative to first time call of `start` method. | 92 | | [fn] | function | string | "linear" | Timing function as `function` object or name of predefined function. | 93 | 94 | 95 | ### morphr.register(hdl) ⇒ object 96 | Register morphing handler function. 97 | 98 | **Kind**: instance method of [Morphr](#Morphr) 99 | **Returns**: object - this. 100 | 101 | | Param | Type | Description | 102 | | --- | --- | --- | 103 | | hdl | function | Callback function `hdl(q){}`, where `q` is the - via `fn` - normalized time or the boolean value `false` to reset for a new start. | 104 | 105 | 106 | ### morphr.start() ⇒ object 107 | Start morphing process. 108 | 109 | **Kind**: instance method of [Morphr](#Morphr) 110 | **Returns**: object - this. 111 | 112 | 113 | #Change Log 114 | 115 | All notable changes to this project will be documented here. This project adheres to Semantic Versioning. 116 | 117 | ## 0.7.0 - 2016-03-27 118 | 119 | ### First Commit to Github 120 | --------------------------------------------------------------------------------