├── .gitignore
├── .jshintrc
├── Makefile
├── README.md
├── build.json
├── examples.html
├── integration
├── ender.js
├── ender.min.js
└── integration.html
├── morpheus.js
├── morpheus.min.js
├── package.json
├── src
├── copyright.js
├── easings.js
├── ender.js
├── morpheus.js
└── rtltr.js
└── tests
└── tests.html
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "predef": ["assert", "refute", "define", "self"]
3 | , "boss": true
4 | , "shadow": true
5 | , "trailing": true
6 | , "latedef": true
7 | , "forin": false
8 | , "curly": false
9 | , "debug": true
10 | , "devel": false
11 | , "evil": true
12 | , "regexp": false
13 | , "undef": true
14 | , "sub": true
15 | , "white": false
16 | , "asi": true
17 | , "laxbreak": true
18 | , "eqnull": true
19 | , "browser": true
20 | , "node": true
21 | , "laxcomma": true
22 | , "proto": true
23 | , "expr": true
24 | , "es5": true
25 | , "strict": false
26 | }
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # npm install smoosh -g
2 | boosh:
3 | node_modules/smoosh/bin/smoosh make ./build.json
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | _ _ ____ ____ ___ _ _ ____ _ _ ____
2 | |\/| | | |__/ |__] |__| |___ | | [__
3 | | | |__| | \ | | | |___ |__| ___]
4 | -----
5 | A Brilliant Animator.
6 |
7 | Morpheus lets you "tween anything" in parallel on multiple elements; from colors to integers of any unit (px, em, %, etc), with easing transitions and bezier curves, including CSS3 [transforms](http://www.w3.org/TR/css3-2d-transforms/) (roate, scale, skew, & translate) -- all in a single high-performant loop utilizing the CPU-friendly [requestAnimationFrame](http://webstuff.nfshost.com/anim-timing/Overview.html) standard.
8 |
9 | It looks like this:
10 |
11 | ``` js
12 | var anim = morpheus(elements, {
13 | // CSS
14 | left: -50
15 | , top: 100
16 | , width: '+=50'
17 | , height: '-=50px'
18 | , fontSize: '30px'
19 | , color: '#f00'
20 | , transform: 'rotate(30deg) scale(+=3)'
21 | , "background-color": '#f00'
22 |
23 | // API
24 | , duration: 500
25 | , easing: easings.easeOut
26 | , bezier: [[100, 200], [200, 100]]
27 | , complete: function () {
28 | console.log('done')
29 | }
30 | })
31 |
32 | // stop an animation
33 | anim.stop()
34 |
35 | // jump to the end of an animation and run 'complete' callback
36 | anim.stop(true)
37 | ```
38 |
39 | General Tweening
40 | ------
41 |
42 | ``` js
43 | morpheus.tween(1000,
44 | function (position) {
45 | // do stuff with position...
46 | // like for example, use bezier curve points :)
47 | var xy = morpheus.bezier([[startX, startY], <[n control points]>, [endX, endY]], position)
48 | },
49 | function () {
50 | console.log('done')
51 | },
52 | easings.bounce,
53 | 100, // start
54 | 300 // end
55 | )
56 | ```
57 |
58 | API
59 | ---
60 |
61 | ``` js
62 | /**
63 | * morpheus:
64 | * @param element(s): HTMLElement(s)
65 | * @param options: mixed bag between CSS Style properties & animation options
66 | * - {n} CSS properties|values
67 | * - value can be strings, integers,
68 | * - or callback function that receives element to be animated. method must return value to be tweened
69 | * - relative animations start with += or -= followed by integer
70 | * - duration: time in ms - defaults to 1000(ms)
71 | * - easing: a transition method - defaults to an 'easeOut' algorithm
72 | * - complete: a callback method for when all elements have finished
73 | * - bezier: array of arrays containing x|y coordinates that define the bezier points. defaults to none
74 | * - this may also be a function that receives element to be animated. it must return a value
75 | * @return animation instance
76 | */
77 | ```
78 |
79 | See the live examples
80 |
81 | Language LTR - RTL support
82 | ---------------
83 | For those who run web services that support languages spanning from LTR to RTL, you can use the drop-in plugin filed called rtltr.js found in the src directory which will automatically mirror all animations without having to change your implementation. It's pretty rad.
84 |
85 | Browser support
86 | -----------
87 | Grade A & C Browsers according to Yahoo's [Graded Browser Support](http://developer.yahoo.com/yui/articles/gbs/). CSS3 transforms are only supported in browsers that support the transform specification.
88 |
89 | Ender integration
90 | --------
91 | Got [Ender](http://ender.jit.su)? No? Get it.
92 |
93 | $ npm install ender -g
94 |
95 | Add Morpheus to your existing Ender build
96 |
97 | $ ender add morpheus
98 |
99 | Write code like a boss:
100 |
101 | ``` js
102 | $('#content .boosh').animate({
103 | left: 911,
104 | complete: function () {
105 | console.log('boosh')
106 | }
107 | })
108 | ```
109 |
110 | Usage Notes
111 | -----------
112 |
113 |
Color
114 | If you're serious about *color animation*, there's a few precautions you'll need to take ahead of time. In order to morph *from* one color to another, you need to make sure the elements you're animating *have an inherited color style* to start with. Furthermore, those styles need to be represented in rgb, or hex, and not a named color (like red, or orange) -- that is unless you want to write code to map the [color conversion](http://www.w3schools.com/css/css_colornames.asp) yourself.
115 |
116 | Therefore, at minimum, you need to set a color before animating.
117 |
118 | ``` js
119 | element.style.color = '#ff0';
120 | morpheus(element, {
121 | color: '#000'
122 | })
123 | ```
124 |
125 | With [Bonzo](https://github.com/ded/bonzo) installed in [Ender](http://ender.no.de).
126 |
127 | ``` js
128 | $('div.things').css('color', '#ff0').animate({
129 | color: '#000'
130 | })
131 | ```
132 |
133 |
Units
134 | If you're considering animating by a CSS unit of measurement like em, pt, or %, like-wise to color animation, you must set the size ahead of time before animating:
135 |
136 | ``` js
137 | $('div.intro')
138 | .css({
139 | fontSize: '2em'
140 | , width: '50%'
141 | })
142 | .animate({
143 | fontSize: '+=1.5em'
144 | , width: '100%'
145 | })
146 | ```
147 |
148 | You also get two other fancy fading hooks
149 |
150 | ``` js
151 | $('p').fadeIn(250, function () {
152 | console.log('complete')
153 | })
154 |
155 | $('p').fadeOut(500, function () {
156 | console.log('complete')
157 | })
158 | ```
159 |
160 |
Transforms
161 | Transforms can be animated in browsers that support them (IE9, FF, Chrome, Safari, Opera). morpheus.transform provides a shortcut to the correct style property for the browser (webkitTransform, MozTransform, etc). Like animating on units or color, you must set the property ahead of time before animating:
162 |
163 | ``` js
164 | element.style[morpheus.transform] = 'rotate(30deg) scale(1)'
165 | morpheus(element, {
166 | transform: 'rotate(0deg) scale(+=3)'
167 | })
168 | ```
169 |
170 | AMD Support
171 | ----------
172 |
173 | ``` js
174 | require('morpheus.js', function (morpheus) {
175 | morpheus(elements, config)
176 | })
177 |
178 | or as usual with ender
179 |
180 | var morpheus = require('morpheus')
181 |
182 | ```
183 |
184 | ## Developers
185 |
186 | If you're looking to contribute. Add your changes to `src/morpheus.js` Then run the following
187 |
188 | ``` sh
189 | npm install .
190 | make
191 | open tests/tests.html
192 | ```
193 |
194 | Morpheus (c) Dustin Diaz 2011 - License MIT
195 |
196 | **Happy Morphing!**
197 |
--------------------------------------------------------------------------------
/build.json:
--------------------------------------------------------------------------------
1 | {
2 | "JAVASCRIPT": {
3 | "DIST_DIR": "./"
4 | , "morpheus": [
5 | "./src/copyright.js"
6 | , "./src/morpheus.js"
7 | ]
8 | }
9 | , "JSHINT_OPTS": {
10 | "boss": true
11 | , "forin": false
12 | , "curly": false
13 | , "debug": false
14 | , "devel": false
15 | , "evil": false
16 | , "regexp": false
17 | , "undef": false
18 | , "sub": true
19 | , "white": false
20 | , "indent": 2
21 | , "asi": true
22 | , "laxbreak": true
23 | , "shadow": true
24 | , "laxcomma": true
25 | }
26 | }
--------------------------------------------------------------------------------
/examples.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Morpheus Examples
6 |
53 |
54 |
55 |
56 |
61 |
62 |
63 |
64 |
Morpheus Examples
65 |
66 |
67 |
General
68 |
69 |
70 |
82 |
83 |
84 |
85 |
Color
86 |
87 |
88 |
101 |
102 |
103 |
104 |
Motion + Color
105 |
106 |
107 |
124 |
125 |
126 |
127 |
Alternative units
128 |
hello world
129 |
130 |
143 |
144 |
145 |
146 |
Bezier Curves
147 |
148 |
149 |
164 |
165 |
166 |
167 |
Multiple elements
168 |
169 |
170 |
171 |
172 |
173 |
207 |
208 |
209 |
210 |
stopping animations
211 |
212 |
241 |
242 |
243 |
244 |
Transform
245 |
scale
246 |
rotate
247 |
skew
248 |
translate
249 |
250 |
251 |
279 |
280 |
281 |
282 |
283 |
284 |
--------------------------------------------------------------------------------
/integration/ender.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * =============================================================
3 | * Ender: open module JavaScript framework (https://ender.no.de)
4 | * Build: ender build domready qwery bonzo bowser
5 | * =============================================================
6 | */
7 |
8 | /*!
9 | * Ender-JS: open module JavaScript framework (client-lib)
10 | * copyright Dustin Diaz & Jacob Thornton 2011 (@ded @fat)
11 | * https://ender.no.de
12 | * License MIT
13 | */
14 | !function (context) {
15 |
16 | // a global object for node.js module compatiblity
17 | // ============================================
18 |
19 | context['global'] = context;
20 |
21 | // Implements simple module system
22 | // losely based on CommonJS Modules spec v1.1.1
23 | // ============================================
24 |
25 | var modules = {};
26 |
27 | function require (identifier) {
28 | var module = modules[identifier] || window[identifier];
29 | if (!module) throw new Error("Requested module '" + identifier + "' has not been defined.");
30 | return module;
31 | }
32 |
33 | function provide (name, what) {
34 | return modules[name] = what;
35 | }
36 |
37 | context['provide'] = provide;
38 | context['require'] = require;
39 |
40 | // Implements Ender's $ global access object
41 | // =========================================
42 |
43 | function aug(o, o2) {
44 | for (var k in o2) {
45 | k != 'noConflict' && k != '_VERSION' && (o[k] = o2[k]);
46 | }
47 | return o;
48 | }
49 |
50 | function boosh(s, r, els) {
51 | // string || node || nodelist || window
52 | if (ender._select && (typeof s == 'string' || s.nodeName || s.length && 'item' in s || s == window)) {
53 | els = ender._select(s, r);
54 | els.selector = s;
55 | } else {
56 | els = isFinite(s.length) ? s : [s];
57 | }
58 | return aug(els, boosh);
59 | }
60 |
61 | function ender(s, r) {
62 | return boosh(s, r);
63 | }
64 |
65 | aug(ender, {
66 | _VERSION: '0.2.5',
67 | ender: function (o, chain) {
68 | aug(chain ? boosh : ender, o);
69 | },
70 | fn: context.$ && context.$.fn || {} // for easy compat to jQuery plugins
71 | });
72 |
73 | aug(boosh, {
74 | forEach: function (fn, scope, i) {
75 | // opt out of native forEach so we can intentionally call our own scope
76 | // defaulting to the current item and be able to return self
77 | for (i = 0, l = this.length; i < l; ++i) {
78 | i in this && fn.call(scope || this[i], this[i], i, this);
79 | }
80 | // return self for chaining
81 | return this;
82 | },
83 | $: ender // handy reference to self
84 | });
85 |
86 | var old = context.$;
87 | ender.noConflict = function () {
88 | context.$ = old;
89 | return this;
90 | };
91 |
92 | (typeof module !== 'undefined') && module.exports && (module.exports = ender);
93 | // use subscript notation as extern for Closure compilation
94 | context['ender'] = context['$'] = context['ender'] || ender;
95 |
96 | }(this);
97 |
98 | !function () {
99 |
100 | var module = { exports: {} }, exports = module.exports;
101 |
102 | /*!
103 | * Qwery - A Blazing Fast query selector engine
104 | * https://github.com/ded/qwery
105 | * copyright Dustin Diaz & Jacob Thornton 2011
106 | * MIT License
107 | */
108 |
109 | !function (name, definition) {
110 | if (typeof define == 'function') define(definition)
111 | else if (typeof module != 'undefined') module.exports = definition()
112 | else this[name] = definition()
113 | }('qwery', function () {
114 | var context = this
115 | , doc = document
116 | , c, i, j, k, l, m, o, p, r, v
117 | , el, node, found, classes, item, items, token
118 | , html = doc.documentElement
119 | , id = /#([\w\-]+)/
120 | , clas = /\.[\w\-]+/g
121 | , idOnly = /^#([\w\-]+$)/
122 | , classOnly = /^\.([\w\-]+)$/
123 | , tagOnly = /^([\w\-]+)$/
124 | , tagAndOrClass = /^([\w]+)?\.([\w\-]+)$/
125 | , normalizr = /\s*([\s\+\~>])\s*/g
126 | , splitters = /[\s\>\+\~]/
127 | , splittersMore = /(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/
128 | , specialChars = /([.*+?\^=!:${}()|\[\]\/\\])/g
129 | , simple = /^([a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/
130 | , attr = /\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/
131 | , pseudo = /:([\w\-]+)(\(['"]?([\s\w\+\-]+)['"]?\))?/
132 | , dividers = new RegExp('(' + splitters.source + ')' + splittersMore.source, 'g')
133 | , tokenizr = new RegExp(splitters.source + splittersMore.source)
134 | , chunker = new RegExp(simple.source + '(' + attr.source + ')?' + '(' + pseudo.source + ')?')
135 | , walker = {
136 | ' ': function (node) {
137 | return node && node !== html && node.parentNode
138 | }
139 | , '>': function (node, contestant) {
140 | return node && node.parentNode == contestant.parentNode && node.parentNode;
141 | }
142 | , '~': function (node) {
143 | return node && node.previousSibling;
144 | }
145 | , '+': function (node, contestant, p1, p2) {
146 | if (!node) {
147 | return false;
148 | }
149 | p1 = previous(node);
150 | p2 = previous(contestant);
151 | return p1 && p2 && p1 == p2 && p1;
152 | }
153 | }
154 | function cache() {
155 | this.c = {}
156 | }
157 | cache.prototype = {
158 | g: function (k) {
159 | return this.c[k] || undefined
160 | }
161 | , s: function (k, v) {
162 | this.c[k] = v
163 | return v
164 | }
165 | }
166 |
167 | var classCache = new cache()
168 | , cleanCache = new cache()
169 | , attrCache = new cache()
170 | , tokenCache = new cache()
171 |
172 | function flatten(ar) {
173 | r = []
174 | for (i = 0, l = ar.length; i < l; i++) {
175 | if (arrayLike(ar[i])) {
176 | r = r.concat(ar[i])
177 | } else {
178 | r.push(ar[i])
179 | }
180 | }
181 | return r
182 | }
183 |
184 | function previous(n) {
185 | while (n = n.previousSibling) {
186 | if (n.nodeType == 1) {
187 | break;
188 | }
189 | }
190 | return n
191 | }
192 |
193 | function q(query) {
194 | return query.match(chunker)
195 | }
196 |
197 | // this next method expect at most these args
198 | // given => div.hello[title="world"]:foo('bar')
199 |
200 | // div.hello[title="world"]:foo('bar'), div, .hello, [title="world"], title, =, world, :foo('bar'), foo, ('bar'), bar]
201 |
202 | function interpret(whole, tag, idsAndClasses, wholeAttribute, attribute, qualifier, value, wholePseudo, pseudo, wholePseudoVal, pseudoVal) {
203 | var m, c, k;
204 | if (tag && this.tagName.toLowerCase() !== tag) {
205 | return false
206 | }
207 | if (idsAndClasses && (m = idsAndClasses.match(id)) && m[1] !== this.id) {
208 | return false
209 | }
210 | if (idsAndClasses && (classes = idsAndClasses.match(clas))) {
211 | for (i = classes.length; i--;) {
212 | c = classes[i].slice(1)
213 | if (!(classCache.g(c) || classCache.s(c, new RegExp('(^|\\s+)' + c + '(\\s+|$)'))).test(this.className)) {
214 | return false
215 | }
216 | }
217 | }
218 | if (pseudo && qwery.pseudos[pseudo] && !qwery.pseudos[pseudo](this, pseudoVal)) {
219 | return false
220 | }
221 | if (wholeAttribute && !value) {
222 | o = this.attributes
223 | for (k in o) {
224 | if (Object.prototype.hasOwnProperty.call(o, k) && (o[k].name || k) == attribute) {
225 | return this
226 | }
227 | }
228 | }
229 | if (wholeAttribute && !checkAttr(qualifier, this.getAttribute(attribute) || '', value)) {
230 | return false
231 | }
232 | return this
233 | }
234 |
235 | function clean(s) {
236 | return cleanCache.g(s) || cleanCache.s(s, s.replace(specialChars, '\\$1'))
237 | }
238 |
239 | function checkAttr(qualify, actual, val) {
240 | switch (qualify) {
241 | case '=':
242 | return actual == val
243 | case '^=':
244 | return actual.match(attrCache.g('^=' + val) || attrCache.s('^=' + val, new RegExp('^' + clean(val))))
245 | case '$=':
246 | return actual.match(attrCache.g('$=' + val) || attrCache.s('$=' + val, new RegExp(clean(val) + '$')))
247 | case '*=':
248 | return actual.match(attrCache.g(val) || attrCache.s(val, new RegExp(clean(val))))
249 | case '~=':
250 | return actual.match(attrCache.g('~=' + val) || attrCache.s('~=' + val, new RegExp('(?:^|\\s+)' + clean(val) + '(?:\\s+|$)')))
251 | case '|=':
252 | return actual.match(attrCache.g('|=' + val) || attrCache.s('|=' + val, new RegExp('^' + clean(val) + '(-|$)')))
253 | }
254 | return 0
255 | }
256 |
257 | function _qwery(selector) {
258 | var r = [], ret = [], i, j = 0, k, l, m, p, token, tag, els, root, intr, item, children
259 | , tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr))
260 | , dividedTokens = selector.match(dividers), dividedToken
261 | tokens = tokens.slice(0) // this makes a copy of the array so the cached original is not effected
262 |
263 | if (!tokens.length) return r
264 |
265 | token = tokens.pop()
266 | root = tokens.length && (m = tokens[tokens.length - 1].match(idOnly)) ? doc.getElementById(m[1]) : doc
267 |
268 | if (!root) return r
269 |
270 | intr = q(token)
271 | els = dividedTokens && /^[+~]$/.test(dividedTokens[dividedTokens.length - 1]) ? function (r) {
272 | while (root = root.nextSibling) {
273 | root.nodeType == 1 && (intr[1] ? intr[1] == root.tagName.toLowerCase() : 1) && r.push(root)
274 | }
275 | return r
276 | }([]) :
277 | root.getElementsByTagName(intr[1] || '*')
278 | for (i = 0, l = els.length; i < l; i++) if (item = interpret.apply(els[i], intr)) r[j++] = item
279 | if (!tokens.length) return r
280 |
281 | // loop through all descendent tokens
282 | for (j = 0, l = r.length, k = 0; j < l; j++) {
283 | p = r[j]
284 | // loop through each token backwards crawling up tree
285 | for (i = tokens.length; i--;) {
286 | // loop through parent nodes
287 | while (p = walker[dividedTokens[i]](p, r[j])) {
288 | if (found = interpret.apply(p, q(tokens[i]))) break;
289 | }
290 | }
291 | found && (ret[k++] = r[j])
292 | }
293 | return ret
294 | }
295 |
296 | function isNode(el) {
297 | return (el && el.nodeType && (el.nodeType == 1 || el.nodeType == 9))
298 | }
299 |
300 | function uniq(ar) {
301 | var a = [], i, j;
302 | label:
303 | for (i = 0; i < ar.length; i++) {
304 | for (j = 0; j < a.length; j++) {
305 | if (a[j] == ar[i]) {
306 | continue label;
307 | }
308 | }
309 | a[a.length] = ar[i]
310 | }
311 | return a
312 | }
313 |
314 | function arrayLike(o) {
315 | return (typeof o === 'object' && isFinite(o.length))
316 | }
317 |
318 | function normalizeRoot(root) {
319 | if (!root) return doc
320 | if (typeof root == 'string') return qwery(root)[0]
321 | if (arrayLike(root)) return root[0]
322 | return root
323 | }
324 |
325 | function qwery(selector, _root) {
326 | var root = normalizeRoot(_root)
327 |
328 | if (!root || !selector) return []
329 | if (selector === window || isNode(selector)) {
330 | return !_root || (selector !== window && isNode(root) && isAncestor(selector, root)) ? [selector] : []
331 | }
332 | if (selector && arrayLike(selector)) return flatten(selector)
333 | if (m = selector.match(idOnly)) return (el = doc.getElementById(m[1])) ? [el] : []
334 | if (m = selector.match(tagOnly)) return flatten(root.getElementsByTagName(m[1]))
335 | return select(selector, root)
336 | }
337 |
338 | var isAncestor = 'compareDocumentPosition' in html ?
339 | function (element, container) {
340 | return (container.compareDocumentPosition(element) & 16) == 16;
341 | } : 'contains' in html ?
342 | function (element, container) {
343 | container = container == doc || container == window ? html : container
344 | return container !== element && container.contains(element)
345 | } :
346 | function (element, container) {
347 | while (element = element.parentNode) if (element === container) return 1
348 | return 0
349 | },
350 |
351 | supportsCSS3 = function () {
352 | if (!doc.querySelector || !doc.querySelectorAll) return false
353 |
354 | try { return (doc.querySelectorAll(':nth-of-type(1)').length > 0) }
355 | catch (e) { return false }
356 | }(),
357 |
358 | select = supportsCSS3 ?
359 | function (selector, root) {
360 | if (doc.getElementsByClassName && (m = selector.match(classOnly))) {
361 | return flatten((root).getElementsByClassName(m[1]));
362 | }
363 | return flatten((root).querySelectorAll(selector))
364 | } :
365 | function (selector, root) {
366 | selector = selector.replace(normalizr, '$1')
367 | var result = [], element, collection, collections = [], i
368 | if (m = selector.match(tagAndOrClass)) {
369 | items = root.getElementsByTagName(m[1] || '*');
370 | r = classCache.g(m[2]) || classCache.s(m[2], new RegExp('(^|\\s+)' + m[2] + '(\\s+|$)'));
371 | for (i = 0, l = items.length, j = 0; i < l; i++) {
372 | r.test(items[i].className) && (result[j++] = items[i]);
373 | }
374 | return result
375 | }
376 | for (i = 0, items = selector.split(','), l = items.length; i < l; i++) {
377 | collections[i] = _qwery(items[i])
378 | }
379 | for (i = 0, l = collections.length; i < l && (collection = collections[i]); i++) {
380 | var ret = collection
381 | if (root !== doc) {
382 | ret = []
383 | for (j = 0, m = collection.length; j < m && (element = collection[j]); j++) {
384 | // make sure element is a descendent of root
385 | isAncestor(element, root) && ret.push(element)
386 | }
387 | }
388 | result = result.concat(ret)
389 | }
390 | return uniq(result)
391 | }
392 |
393 | qwery.uniq = uniq
394 | qwery.pseudos = {}
395 |
396 | var old = context.qwery
397 | qwery.noConflict = function () {
398 | context.qwery = old
399 | return this
400 | }
401 |
402 | return qwery
403 | })
404 |
405 | provide("qwery", module.exports);
406 |
407 | !function (doc, $) {
408 | var q = require('qwery')
409 | , table = 'table'
410 | , nodeMap = {
411 | thead: table
412 | , tbody: table
413 | , tfoot: table
414 | , tr: 'tbody'
415 | , th: 'tr'
416 | , td: 'tr'
417 | , fieldset: 'form'
418 | , option: 'select'
419 | }
420 | function create(node, root) {
421 | var tag = /^<([^\s>]+)/.exec(node)[1]
422 | , el = (root || doc).createElement(nodeMap[tag] || 'div'), els = []
423 | el.innerHTML = node
424 | var nodes = el.childNodes
425 | el = el.firstChild
426 | els.push(el)
427 | while (el = el.nextSibling) (el.nodeType == 1) && els.push(el)
428 | return els
429 | }
430 |
431 | $._select = function (s, r) {
432 | return /^\s*]+)/.exec(node)
1090 | , el = doc.createElement(tag && tagMap[tag[1].toLowerCase()] || 'div'), els = []
1091 | el.innerHTML = node
1092 | var nodes = el.childNodes
1093 | el = el.firstChild
1094 | els.push(el)
1095 | while (el = el.nextSibling) (el.nodeType == 1) && els.push(el)
1096 | return els
1097 |
1098 | }() : is(node) ? [node.cloneNode(true)] : []
1099 | }
1100 |
1101 | bonzo.doc = function () {
1102 | var vp = this.viewport()
1103 | return {
1104 | width: Math.max(doc.body.scrollWidth, html.scrollWidth, vp.width)
1105 | , height: Math.max(doc.body.scrollHeight, html.scrollHeight, vp.height)
1106 | }
1107 | }
1108 |
1109 | bonzo.firstChild = function (el) {
1110 | for (var c = el.childNodes, i = 0, j = (c && c.length) || 0, e; i < j; i++) {
1111 | if (c[i].nodeType === 1) {
1112 | e = c[j = i]
1113 | }
1114 | }
1115 | return e
1116 | }
1117 |
1118 | bonzo.viewport = function () {
1119 | return {
1120 | width: ie ? html.clientWidth : self.innerWidth
1121 | , height: ie ? html.clientHeight : self.innerHeight
1122 | }
1123 | }
1124 |
1125 | bonzo.isAncestor = 'compareDocumentPosition' in html ?
1126 | function (container, element) {
1127 | return (container.compareDocumentPosition(element) & 16) == 16
1128 | } : 'contains' in html ?
1129 | function (container, element) {
1130 | return container !== element && container.contains(element);
1131 | } :
1132 | function (container, element) {
1133 | while (element = element[parentNode]) {
1134 | if (element === container) {
1135 | return true
1136 | }
1137 | }
1138 | return false
1139 | }
1140 |
1141 | var old = context.bonzo
1142 | bonzo.noConflict = function () {
1143 | context.bonzo = old
1144 | return this
1145 | }
1146 |
1147 | return bonzo
1148 | })
1149 |
1150 |
1151 | provide("bonzo", module.exports);
1152 |
1153 | !function ($) {
1154 |
1155 | var b = require('bonzo')
1156 | b.setQueryEngine($)
1157 | $.ender(b)
1158 | $.ender(b(), true)
1159 | $.ender({
1160 | create: function (node) {
1161 | return $(b.create(node))
1162 | }
1163 | })
1164 |
1165 | $.id = function (id) {
1166 | return $([document.getElementById(id)])
1167 | }
1168 |
1169 | function indexOf(ar, val) {
1170 | for (var i = 0; i < ar.length; i++) {
1171 | if (ar[i] === val) {
1172 | return i
1173 | }
1174 | }
1175 | return -1
1176 | }
1177 |
1178 | function uniq(ar) {
1179 | var a = [], i, j
1180 | label:
1181 | for (i = 0; i < ar.length; i++) {
1182 | for (j = 0; j < a.length; j++) {
1183 | if (a[j] == ar[i]) {
1184 | continue label
1185 | }
1186 | }
1187 | a[a.length] = ar[i]
1188 | }
1189 | return a
1190 | }
1191 |
1192 | $.ender({
1193 | parents: function (selector, closest) {
1194 | var collection = $(selector), j, k, p, r = []
1195 | for (j = 0, k = this.length; j < k; j++) {
1196 | p = this[j]
1197 | while (p = p.parentNode) {
1198 | if (indexOf(collection, p) !== -1) {
1199 | r.push(p)
1200 | if (closest) break;
1201 | }
1202 | }
1203 | }
1204 | return $(uniq(r))
1205 | },
1206 |
1207 | closest: function (selector) {
1208 | return this.parents(selector, true)
1209 | },
1210 |
1211 | first: function () {
1212 | return $(this[0])
1213 | },
1214 |
1215 | last: function () {
1216 | return $(this[this.length - 1])
1217 | },
1218 |
1219 | next: function () {
1220 | return $(b(this).next())
1221 | },
1222 |
1223 | previous: function () {
1224 | return $(b(this).previous())
1225 | },
1226 |
1227 | appendTo: function (t) {
1228 | return b(this.selector).appendTo(t, this)
1229 | },
1230 |
1231 | prependTo: function (t) {
1232 | return b(this.selector).prependTo(t, this)
1233 | },
1234 |
1235 | insertAfter: function (t) {
1236 | return b(this.selector).insertAfter(t, this)
1237 | },
1238 |
1239 | insertBefore: function (t) {
1240 | return b(this.selector).insertBefore(t, this)
1241 | },
1242 |
1243 | siblings: function () {
1244 | var i, l, p, r = []
1245 | for (i = 0, l = this.length; i < l; i++) {
1246 | p = this[i]
1247 | while (p = p.previousSibling) {
1248 | p.nodeType == 1 && r.push(p)
1249 | }
1250 | p = this[i]
1251 | while (p = p.nextSibling) {
1252 | p.nodeType == 1 && r.push(p)
1253 | }
1254 | }
1255 | return $(r)
1256 | },
1257 |
1258 | children: function () {
1259 | var i, el, r = []
1260 | for (i = 0, l = this.length; i < l; i++) {
1261 | if (!(el = b.firstChild(this[i]))) {
1262 | continue;
1263 | }
1264 | r.push(el);
1265 | while (el = el.nextSibling) el.nodeType == 1 && r.push(el)
1266 | }
1267 | return $(uniq(r))
1268 | },
1269 |
1270 | height: function (v) {
1271 | return dimension(v, this, 'height')
1272 | },
1273 |
1274 | width: function (v) {
1275 | return dimension(v, this, 'width')
1276 | }
1277 | }, true)
1278 |
1279 | function dimension(v, self, which) {
1280 | return v ?
1281 | self.css(which, v) :
1282 | function (r) {
1283 | r = parseInt(self.css(which), 10);
1284 | return isNaN(r) ? self[0]['offset' + which.replace(/^\w/, function (m) {return m.toUpperCase()})] : r
1285 | }()
1286 | }
1287 |
1288 | }(ender);
1289 |
1290 |
1291 | }();
1292 |
1293 | !function () {
1294 |
1295 | var module = { exports: {} }, exports = module.exports;
1296 |
1297 | /*!
1298 | * Bowser - a browser detector
1299 | * copyright Dustin Diaz 2011
1300 | * https://github.com/ded/bowser
1301 | * MIT License
1302 | */
1303 | /*!
1304 | * Bowser - a browser detector
1305 | * copyright Dustin Diaz 2011
1306 | * https://github.com/ded/bowser
1307 | * MIT License
1308 | */
1309 | !function (context) {
1310 | /**
1311 | * navigator.userAgent =>
1312 | * Chrome: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57 Safari/534.24"
1313 | * Opera: "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.7; U; en) Presto/2.7.62 Version/11.01"
1314 | * Safari: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
1315 | * IE: "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C)"
1316 | * Firefox: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0) Gecko/20100101 Firefox/4.0"
1317 | */
1318 |
1319 | var ua = navigator.userAgent,
1320 | ie = /msie/i.test(ua),
1321 | chrome = /chrome/i.test(ua),
1322 | safari = /safari/i.test(ua) && !chrome,
1323 | opera = /opera/i.test(ua),
1324 | firefox = /firefox/i.test(ua),
1325 | gecko = /gecko\//i.test(ua);
1326 |
1327 | function detect() {
1328 |
1329 | if (ie) {
1330 | return {
1331 | msie: 1,
1332 | version: ua.match(/msie (\d+(\.\d+)?);/i)[1]
1333 | };
1334 | }
1335 | if (chrome) {
1336 | return {
1337 | webkit: 1,
1338 | chrome: 1,
1339 | version: ua.match(/chrome\/(\d+(\.\d+)?)/i)[1]
1340 | };
1341 | }
1342 | if (safari) {
1343 | return {
1344 | webkit: 1,
1345 | safari: 1,
1346 | version: ua.match(/version\/(\d+(\.\d+)?)/i)[1]
1347 | };
1348 | }
1349 | if (opera) {
1350 | return {
1351 | opera: 1,
1352 | version: ua.match(/version\/(\d+(\.\d+)?)/i)[1]
1353 | };
1354 | }
1355 | if (gecko) {
1356 | var o = {
1357 | gecko: 1,
1358 | version: ua.match(/firefox\/(\d+(\.\d+)?)/i)[1]
1359 | };
1360 | if (firefox) {
1361 | o.firefox = 1;
1362 | }
1363 | return o;
1364 | }
1365 |
1366 | }
1367 |
1368 | var bowser = detect();
1369 |
1370 | // Graded Browser Support
1371 | // http://developer.yahoo.com/yui/articles/gbs
1372 | if ((bowser.msie && bowser.version >= 6) ||
1373 | (bowser.chrome && bowser.version >= 8) ||
1374 | (bowser.firefox && bowser.version >= 3.6) ||
1375 | (bowser.safari && bowser.version >= 5) ||
1376 | (bowser.opera && bowser.version >= 9.5)) {
1377 | bowser.a = true;
1378 | }
1379 |
1380 | else if ((bowser.msie && bowser.version < 6) ||
1381 | (bowser.chrome && bowser.version < 8) ||
1382 | (bowser.firefox && bowser.version < 3.6) ||
1383 | (bowser.safari && bowser.version < 5) ||
1384 | (bowser.opera && bowser.version < 9.5)) {
1385 | bowser.c = true;
1386 | } else {
1387 | bowser.x = true;
1388 | }
1389 |
1390 | typeof module !== 'undefined' && module.exports ?
1391 | (module.exports.browser = bowser) :
1392 | (context.bowser = bowser);
1393 |
1394 | }(this);
1395 |
1396 |
1397 | provide("bowser", module.exports);
1398 |
1399 | $.ender(module.exports);
1400 |
1401 | }();
--------------------------------------------------------------------------------
/integration/ender.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * =============================================================
3 | * Ender: open module JavaScript framework (https://ender.no.de)
4 | * Build: ender build domready qwery bonzo bowser
5 | * =============================================================
6 | */
7 |
8 |
9 | /*!
10 | * Ender-JS: open module JavaScript framework (client-lib)
11 | * copyright Dustin Diaz & Jacob Thornton 2011 (@ded @fat)
12 | * https://ender.no.de
13 | * License MIT
14 | */
15 | !function(a){function g(a,b){return f(a,b)}function f(a,b,c){g._select&&(typeof a=="string"||a.nodeName||a.length&&"item"in a||a==window)?(c=g._select(a,b),c.selector=a):c=isFinite(a.length)?a:[a];return e(c,f)}function e(a,b){for(var c in b)c!="noConflict"&&c!="_VERSION"&&(a[c]=b[c]);return a}function d(a,c){return b[a]=c}function c(a){var c=b[a]||window[a];if(!c)throw new Error("Requested module '"+a+"' has not been defined.");return c}a.global=a;var b={};a.provide=d,a.require=c,e(g,{_VERSION:"0.2.5",ender:function(a,b){e(b?f:g,a)},fn:a.$&&a.$.fn||{}}),e(f,{forEach:function(a,b,c){for(c=0,l=this.length;c])\s*/g,B=/[\s\>\+\~]/,C=/(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/,D=/([.*+?\^=!:${}()|\[\]\/\\])/g,E=/^([a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/,F=/\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/,G=/:([\w\-]+)(\(['"]?([\s\w\+\-]+)['"]?\))?/,H=new RegExp("("+B.source+")"+C.source,"g"),I=new RegExp(B.source+C.source),J=new RegExp(E.source+"("+F.source+")?"+"("+G.source+")?"),K={" ":function(a){return a&&a!==t&&a.parentNode},">":function(a,b){return a&&a.parentNode==b.parentNode&&a.parentNode},"~":function(a){return a&&a.previousSibling},"+":function(a,b,c,d){if(!a)return!1;c=R(a),d=R(b);return c&&d&&c==d&&c}};L.prototype={g:function(a){return this.c[a]||undefined},s:function(a,b){this.c[a]=b;return b}};var M=new L,N=new L,O=new L,P=new L,ba="compareDocumentPosition"in t?function(a,b){return(b.compareDocumentPosition(a)&16)==16}:"contains"in t?function(a,c){c=c==b||c==window?t:c;return c!==a&&c.contains(a)}:function(a,b){while(a=a.parentNode)if(a===b)return 1;return 0},bb=function(){if(!b.querySelector||!b.querySelectorAll)return!1;try{return b.querySelectorAll(":nth-of-type(1)").length>0}catch(a){return!1}}(),bc=bb?function(a,c){return b.getElementsByClassName&&(h=a.match(x))?Q(c.getElementsByClassName(h[1])):Q(c.querySelectorAll(a))}:function(a,c){a=a.replace(A,"$1");var d=[],f,i,j=[],l;if(h=a.match(z)){r=c.getElementsByTagName(h[1]||"*"),k=M.g(h[2])||M.s(h[2],new RegExp("(^|\\s+)"+h[2]+"(\\s+|$)"));for(l=0,g=r.length,e=0;l]+)/.exec(b)[1],f=(c||a).createElement(e[d]||"div"),g=[];f.innerHTML=b;var h=f.childNodes;f=f.firstChild,g.push(f);while(f=f.nextSibling)f.nodeType==1&&g.push(f);return g}var c=require("qwery"),d="table",e={thead:d,tbody:d,tfoot:d,tr:"tbody",th:"tr",td:"tr",fieldset:"form",option:"select"};b._select=function(a,b){return/^\s*]+)/.exec(a),d=c.createElement(b&&k[b[1].toLowerCase()]||"div"),e=[];d.innerHTML=a;var f=d.childNodes;d=d.firstChild,e.push(d);while(d=d.nextSibling)d.nodeType==1&&e.push(d);return e}():A(a)?[a.cloneNode(!0)]:[]},N.doc=function(){var a=this.viewport();return{width:Math.max(c.body.scrollWidth,d.scrollWidth,a.width),height:Math.max(c.body.scrollHeight,d.scrollHeight,a.height)}},N.firstChild=function(a){for(var b=a.childNodes,c=0,d=b&&b.length||0,e;c=6||k.chrome&&k.version>=8||k.firefox&&k.version>=3.6||k.safari&&k.version>=5||k.opera&&k.version>=9.5?k.a=!0:k.msie&&k.version<6||k.chrome&&k.version<8||k.firefox&&k.version<3.6||k.safari&&k.version<5||k.opera&&k.version<9.5?k.c=!0:k.x=!0,typeof a!="undefined"&&a.exports?a.exports.browser=k:b.bowser=k}(this),provide("bowser",a.exports),$.ender(a.exports)}()
--------------------------------------------------------------------------------
/integration/integration.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ender integration
6 |
66 |
67 |
68 |
69 |
70 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
mø®phéüs
145 |
146 |
--------------------------------------------------------------------------------
/morpheus.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Morpheus - A Brilliant Animator
3 | * https://github.com/ded/morpheus - (c) Dustin Diaz 2011
4 | * License MIT
5 | */
6 | !function (name, definition) {
7 | if (typeof define == 'function') define(definition)
8 | else if (typeof module != 'undefined') module.exports = definition()
9 | else this[name] = definition()
10 | }('morpheus', function () {
11 |
12 | var doc = document
13 | , win = window
14 | , perf = win.performance
15 | , perfNow = perf && (perf.now || perf.webkitNow || perf.msNow || perf.mozNow)
16 | , now = perfNow ? function () { return perfNow.call(perf) } : function () { return +new Date() }
17 | , fixTs = false // feature detected below
18 | , html = doc.documentElement
19 | , thousand = 1000
20 | , rgbOhex = /^rgb\(|#/
21 | , relVal = /^([+\-])=([\d\.]+)/
22 | , numUnit = /^(?:[\+\-]=?)?\d+(?:\.\d+)?(%|in|cm|mm|em|ex|pt|pc|px)$/
23 | , rotate = /rotate\(((?:[+\-]=)?([\-\d\.]+))deg\)/
24 | , scale = /scale\(((?:[+\-]=)?([\d\.]+))\)/
25 | , skew = /skew\(((?:[+\-]=)?([\-\d\.]+))deg, ?((?:[+\-]=)?([\-\d\.]+))deg\)/
26 | , translate = /translate\(((?:[+\-]=)?([\-\d\.]+))px, ?((?:[+\-]=)?([\-\d\.]+))px\)/
27 | // these elements do not require 'px'
28 | , unitless = { lineHeight: 1, zoom: 1, zIndex: 1, opacity: 1, transform: 1}
29 |
30 | // which property name does this browser use for transform
31 | var transform = function () {
32 | var styles = doc.createElement('a').style
33 | , props = ['webkitTransform', 'MozTransform', 'OTransform', 'msTransform', 'Transform']
34 | , i
35 | for (i = 0; i < props.length; i++) {
36 | if (props[i] in styles) return props[i]
37 | }
38 | }()
39 |
40 | // does this browser support the opacity property?
41 | var opasity = function () {
42 | return typeof doc.createElement('a').style.opacity !== 'undefined'
43 | }()
44 |
45 | // initial style is determined by the elements themselves
46 | var getStyle = doc.defaultView && doc.defaultView.getComputedStyle ?
47 | function (el, property) {
48 | property = property == 'transform' ? transform : property
49 | property = camelize(property)
50 | var value = null
51 | , computed = doc.defaultView.getComputedStyle(el, '')
52 | computed && (value = computed[property])
53 | return el.style[property] || value
54 | } : html.currentStyle ?
55 |
56 | function (el, property) {
57 | property = camelize(property)
58 |
59 | if (property == 'opacity') {
60 | var val = 100
61 | try {
62 | val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity
63 | } catch (e1) {
64 | try {
65 | val = el.filters('alpha').opacity
66 | } catch (e2) {}
67 | }
68 | return val / 100
69 | }
70 | var value = el.currentStyle ? el.currentStyle[property] : null
71 | return el.style[property] || value
72 | } :
73 | function (el, property) {
74 | return el.style[camelize(property)]
75 | }
76 |
77 | var frame = function () {
78 | // native animation frames
79 | // http://webstuff.nfshost.com/anim-timing/Overview.html
80 | // http://dev.chromium.org/developers/design-documents/requestanimationframe-implementation
81 | return win.requestAnimationFrame ||
82 | win.webkitRequestAnimationFrame ||
83 | win.mozRequestAnimationFrame ||
84 | win.msRequestAnimationFrame ||
85 | win.oRequestAnimationFrame ||
86 | function (callback) {
87 | win.setTimeout(function () {
88 | callback(+new Date())
89 | }, 17) // when I was 17..
90 | }
91 | }()
92 |
93 | frame(function(timestamp) {
94 | // feature-detect if rAF and now() are of the same scale (epoch or high-res),
95 | // if not, we have to do a timestamp fix on each frame
96 | fixTs = timestamp > 1e12 != now() > 1e12
97 | })
98 |
99 | var children = []
100 |
101 | function has(array, elem, i) {
102 | if (Array.prototype.indexOf) return array.indexOf(elem)
103 | for (i = 0; i < array.length; ++i) {
104 | if (array[i] === elem) return i
105 | }
106 | }
107 |
108 | function render(timestamp) {
109 | var i, count = children.length
110 | if (fixTs) timestamp = now()
111 | for (i = count; i--;) {
112 | children[i](timestamp)
113 | }
114 | children.length && frame(render)
115 | }
116 |
117 | function live(f) {
118 | if (children.push(f) === 1) frame(render)
119 | }
120 |
121 | function die(f) {
122 | var rest, index = has(children, f)
123 | if (index >= 0) {
124 | rest = children.slice(index + 1)
125 | children.length = index
126 | children = children.concat(rest)
127 | }
128 | }
129 |
130 | function parseTransform(style, base) {
131 | var values = {}, m
132 | if (m = style.match(rotate)) values.rotate = by(m[1], base ? base.rotate : null)
133 | if (m = style.match(scale)) values.scale = by(m[1], base ? base.scale : null)
134 | if (m = style.match(skew)) {values.skewx = by(m[1], base ? base.skewx : null); values.skewy = by(m[3], base ? base.skewy : null)}
135 | if (m = style.match(translate)) {values.translatex = by(m[1], base ? base.translatex : null); values.translatey = by(m[3], base ? base.translatey : null)}
136 | return values
137 | }
138 |
139 | function formatTransform(v) {
140 | var s = ''
141 | if ('rotate' in v) s += 'rotate(' + v.rotate + 'deg) '
142 | if ('scale' in v) s += 'scale(' + v.scale + ') '
143 | if ('translatex' in v) s += 'translate(' + v.translatex + 'px,' + v.translatey + 'px) '
144 | if ('skewx' in v) s += 'skew(' + v.skewx + 'deg,' + v.skewy + 'deg)'
145 | return s
146 | }
147 |
148 | function rgb(r, g, b) {
149 | return '#' + (1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1)
150 | }
151 |
152 | // convert rgb and short hex to long hex
153 | function toHex(c) {
154 | var m = c.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/)
155 | return (m ? rgb(m[1], m[2], m[3]) : c)
156 | .replace(/#(\w)(\w)(\w)$/, '#$1$1$2$2$3$3') // short skirt to long jacket
157 | }
158 |
159 | // change font-size => fontSize etc.
160 | function camelize(s) {
161 | return s.replace(/-(.)/g, function (m, m1) {
162 | return m1.toUpperCase()
163 | })
164 | }
165 |
166 | // aren't we having it?
167 | function fun(f) {
168 | return typeof f == 'function'
169 | }
170 |
171 | function nativeTween(t) {
172 | // default to a pleasant-to-the-eye easeOut (like native animations)
173 | return Math.sin(t * Math.PI / 2)
174 | }
175 |
176 | /**
177 | * Core tween method that requests each frame
178 | * @param duration: time in milliseconds. defaults to 1000
179 | * @param fn: tween frame callback function receiving 'position'
180 | * @param done {optional}: complete callback function
181 | * @param ease {optional}: easing method. defaults to easeOut
182 | * @param from {optional}: integer to start from
183 | * @param to {optional}: integer to end at
184 | * @returns method to stop the animation
185 | */
186 | function tween(duration, fn, done, ease, from, to) {
187 | ease = fun(ease) ? ease : morpheus.easings[ease] || nativeTween
188 | var time = duration || thousand
189 | , self = this
190 | , diff = to - from
191 | , start = now()
192 | , stop = 0
193 | , end = 0
194 |
195 | function run(t) {
196 | var delta = t - start
197 | if (delta > time || stop) {
198 | to = isFinite(to) ? to : 1
199 | stop ? end && fn(to) : fn(to)
200 | die(run)
201 | return done && done.apply(self)
202 | }
203 | // if you don't specify a 'to' you can use tween as a generic delta tweener
204 | // cool, eh?
205 | isFinite(to) ?
206 | fn((diff * ease(delta / time)) + from) :
207 | fn(ease(delta / time))
208 | }
209 |
210 | live(run)
211 |
212 | return {
213 | stop: function (jump) {
214 | stop = 1
215 | end = jump // jump to end of animation?
216 | if (!jump) done = null // remove callback if not jumping to end
217 | }
218 | }
219 | }
220 |
221 | /**
222 | * generic bezier method for animating x|y coordinates
223 | * minimum of 2 points required (start and end).
224 | * first point start, last point end
225 | * additional control points are optional (but why else would you use this anyway ;)
226 | * @param points: array containing control points
227 | [[0, 0], [100, 200], [200, 100]]
228 | * @param pos: current be(tween) position represented as float 0 - 1
229 | * @return [x, y]
230 | */
231 | function bezier(points, pos) {
232 | var n = points.length, r = [], i, j
233 | for (i = 0; i < n; ++i) {
234 | r[i] = [points[i][0], points[i][1]]
235 | }
236 | for (j = 1; j < n; ++j) {
237 | for (i = 0; i < n - j; ++i) {
238 | r[i][0] = (1 - pos) * r[i][0] + pos * r[parseInt(i + 1, 10)][0]
239 | r[i][1] = (1 - pos) * r[i][1] + pos * r[parseInt(i + 1, 10)][1]
240 | }
241 | }
242 | return [r[0][0], r[0][1]]
243 | }
244 |
245 | // this gets you the next hex in line according to a 'position'
246 | function nextColor(pos, start, finish) {
247 | var r = [], i, e, from, to
248 | for (i = 0; i < 6; i++) {
249 | from = Math.min(15, parseInt(start.charAt(i), 16))
250 | to = Math.min(15, parseInt(finish.charAt(i), 16))
251 | e = Math.floor((to - from) * pos + from)
252 | e = e > 15 ? 15 : e < 0 ? 0 : e
253 | r[i] = e.toString(16)
254 | }
255 | return '#' + r.join('')
256 | }
257 |
258 | // this retreives the frame value within a sequence
259 | function getTweenVal(pos, units, begin, end, k, i, v) {
260 | if (k == 'transform') {
261 | v = {}
262 | for (var t in begin[i][k]) {
263 | v[t] = (t in end[i][k]) ? Math.round(((end[i][k][t] - begin[i][k][t]) * pos + begin[i][k][t]) * thousand) / thousand : begin[i][k][t]
264 | }
265 | return v
266 | } else if (typeof begin[i][k] == 'string') {
267 | return nextColor(pos, begin[i][k], end[i][k])
268 | } else {
269 | // round so we don't get crazy long floats
270 | v = Math.round(((end[i][k] - begin[i][k]) * pos + begin[i][k]) * thousand) / thousand
271 | // some css properties don't require a unit (like zIndex, lineHeight, opacity)
272 | if (!(k in unitless)) v += units[i][k] || 'px'
273 | return v
274 | }
275 | }
276 |
277 | // support for relative movement via '+=n' or '-=n'
278 | function by(val, start, m, r, i) {
279 | return (m = relVal.exec(val)) ?
280 | (i = parseFloat(m[2])) && (start + (m[1] == '+' ? 1 : -1) * i) :
281 | parseFloat(val)
282 | }
283 |
284 | /**
285 | * morpheus:
286 | * @param element(s): HTMLElement(s)
287 | * @param options: mixed bag between CSS Style properties & animation options
288 | * - {n} CSS properties|values
289 | * - value can be strings, integers,
290 | * - or callback function that receives element to be animated. method must return value to be tweened
291 | * - relative animations start with += or -= followed by integer
292 | * - duration: time in ms - defaults to 1000(ms)
293 | * - easing: a transition method - defaults to an 'easeOut' algorithm
294 | * - complete: a callback method for when all elements have finished
295 | * - bezier: array of arrays containing x|y coordinates that define the bezier points. defaults to none
296 | * - this may also be a function that receives element to be animated. it must return a value
297 | */
298 | function morpheus(elements, options) {
299 | var els = elements ? (els = isFinite(elements.length) ? elements : [elements]) : [], i
300 | , complete = options.complete
301 | , duration = options.duration
302 | , ease = options.easing
303 | , points = options.bezier
304 | , begin = []
305 | , end = []
306 | , units = []
307 | , bez = []
308 | , originalLeft
309 | , originalTop
310 |
311 | if (points) {
312 | // remember the original values for top|left
313 | originalLeft = options.left;
314 | originalTop = options.top;
315 | delete options.right;
316 | delete options.bottom;
317 | delete options.left;
318 | delete options.top;
319 | }
320 |
321 | for (i = els.length; i--;) {
322 |
323 | // record beginning and end states to calculate positions
324 | begin[i] = {}
325 | end[i] = {}
326 | units[i] = {}
327 |
328 | // are we 'moving'?
329 | if (points) {
330 |
331 | var left = getStyle(els[i], 'left')
332 | , top = getStyle(els[i], 'top')
333 | , xy = [by(fun(originalLeft) ? originalLeft(els[i]) : originalLeft || 0, parseFloat(left)),
334 | by(fun(originalTop) ? originalTop(els[i]) : originalTop || 0, parseFloat(top))]
335 |
336 | bez[i] = fun(points) ? points(els[i], xy) : points
337 | bez[i].push(xy)
338 | bez[i].unshift([
339 | parseInt(left, 10),
340 | parseInt(top, 10)
341 | ])
342 | }
343 |
344 | for (var k in options) {
345 | switch (k) {
346 | case 'complete':
347 | case 'duration':
348 | case 'easing':
349 | case 'bezier':
350 | continue
351 | }
352 | var v = getStyle(els[i], k), unit
353 | , tmp = fun(options[k]) ? options[k](els[i]) : options[k]
354 | if (typeof tmp == 'string' &&
355 | rgbOhex.test(tmp) &&
356 | !rgbOhex.test(v)) {
357 | delete options[k]; // remove key :(
358 | continue; // cannot animate colors like 'orange' or 'transparent'
359 | // only #xxx, #xxxxxx, rgb(n,n,n)
360 | }
361 |
362 | begin[i][k] = k == 'transform' ? parseTransform(v) :
363 | typeof tmp == 'string' && rgbOhex.test(tmp) ?
364 | toHex(v).slice(1) :
365 | parseFloat(v)
366 | end[i][k] = k == 'transform' ? parseTransform(tmp, begin[i][k]) :
367 | typeof tmp == 'string' && tmp.charAt(0) == '#' ?
368 | toHex(tmp).slice(1) :
369 | by(tmp, parseFloat(v));
370 | // record original unit
371 | (typeof tmp == 'string') && (unit = tmp.match(numUnit)) && (units[i][k] = unit[1])
372 | }
373 | }
374 | // ONE TWEEN TO RULE THEM ALL
375 | return tween.apply(els, [duration, function (pos, v, xy) {
376 | // normally not a fan of optimizing for() loops, but we want something
377 | // fast for animating
378 | for (i = els.length; i--;) {
379 | if (points) {
380 | xy = bezier(bez[i], pos)
381 | els[i].style.left = xy[0] + 'px'
382 | els[i].style.top = xy[1] + 'px'
383 | }
384 | for (var k in options) {
385 | v = getTweenVal(pos, units, begin, end, k, i)
386 | k == 'transform' ?
387 | els[i].style[transform] = formatTransform(v) :
388 | k == 'opacity' && !opasity ?
389 | (els[i].style.filter = 'alpha(opacity=' + (v * 100) + ')') :
390 | (els[i].style[camelize(k)] = v)
391 | }
392 | }
393 | }, complete, ease])
394 | }
395 |
396 | // expose useful methods
397 | morpheus.tween = tween
398 | morpheus.getStyle = getStyle
399 | morpheus.bezier = bezier
400 | morpheus.transform = transform
401 | morpheus.parseTransform = parseTransform
402 | morpheus.formatTransform = formatTransform
403 | morpheus.animationFrame = frame
404 | morpheus.easings = {}
405 |
406 | return morpheus
407 |
408 | });
409 |
--------------------------------------------------------------------------------
/morpheus.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Morpheus - A Brilliant Animator
3 | * https://github.com/ded/morpheus - (c) Dustin Diaz 2011
4 | * License MIT
5 | */
6 | !function(e,t){typeof define=="function"?define(t):typeof module!="undefined"?module.exports=t():this[e]=t()}("morpheus",function(){function E(e,t,n){if(Array.prototype.indexOf)return e.indexOf(t);for(n=0;n=0&&(t=w.slice(n+1),w.length=n,w=w.concat(t))}function N(e,t){var n={},r;if(r=e.match(c))n.rotate=B(r[1],t?t.rotate:null);if(r=e.match(h))n.scale=B(r[1],t?t.scale:null);if(r=e.match(p))n.skewx=B(r[1],t?t.skewx:null),n.skewy=B(r[3],t?t.skewy:null);if(r=e.match(d))n.translatex=B(r[1],t?t.translatex:null),n.translatey=B(r[3],t?t.translatey:null);return n}function C(e){var t="";return"rotate"in e&&(t+="rotate("+e.rotate+"deg) "),"scale"in e&&(t+="scale("+e.scale+") "),"translatex"in e&&(t+="translate("+e.translatex+"px,"+e.translatey+"px) "),"skewx"in e&&(t+="skew("+e.skewx+"deg,"+e.skewy+"deg)"),t}function k(e,t,n){return"#"+(1<<24|e<<16|t<<8|n).toString(16).slice(1)}function L(e){var t=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return(t?k(t[1],t[2],t[3]):e).replace(/#(\w)(\w)(\w)$/,"#$1$1$2$2$3$3")}function A(e){return e.replace(/-(.)/g,function(e,t){return t.toUpperCase()})}function O(e){return typeof e=="function"}function M(e){return Math.sin(e*Math.PI/2)}function _(e,t,n,r,s,o){function d(e){var i=e-c;if(i>a||h)return o=isFinite(o)?o:1,h?p&&t(o):t(o),T(d),n&&n.apply(f);isFinite(o)?t(l*r(i/a)+s):t(r(i/a))}r=O(r)?r:j.easings[r]||M;var a=e||u,f=this,l=o-s,c=i(),h=0,p=0;return x(d),{stop:function(e){h=1,p=e,e||(n=null)}}}function D(e,t){var n=e.length,r=[],i,s;for(i=0;i15?15:s<0?0:s,r[i]=s.toString(16);return"#"+r.join("")}function H(e,t,n,r,i,s,o){if(i=="transform"){o={};for(var a in n[s][i])o[a]=a in r[s][i]?Math.round(((r[s][i][a]-n[s][i][a])*e+n[s][i][a])*u)/u:n[s][i][a];return o}return typeof n[s][i]=="string"?P(e,n[s][i],r[s][i]):(o=Math.round(((r[s][i]-n[s][i])*e+n[s][i])*u)/u,i in v||(o+=t[s][i]||"px"),o)}function B(e,t,n,r,i){return(n=f.exec(e))?(i=parseFloat(n[2]))&&t+(n[1]=="+"?1:-1)*i:parseFloat(e)}function j(e,t){var n=e?n=isFinite(e.length)?e:[e]:[],r,i=t.complete,s=t.duration,o=t.easing,u=t.bezier,f=[],c=[],h=[],p=[],d,v;u&&(d=t.left,v=t.top,delete t.right,delete t.bottom,delete t.left,delete t.top);for(r=n.length;r--;){f[r]={},c[r]={},h[r]={};if(u){var b=y(n[r],"left"),w=y(n[r],"top"),E=[B(O(d)?d(n[r]):d||0,parseFloat(b)),B(O(v)?v(n[r]):v||0,parseFloat(w))];p[r]=O(u)?u(n[r],E):u,p[r].push(E),p[r].unshift([parseInt(b,10),parseInt(w,10)])}for(var S in t){switch(S){case"complete":case"duration":case"easing":case"bezier":continue}var x=y(n[r],S),T,k=O(t[S])?t[S](n[r]):t[S];if(typeof k=="string"&&a.test(k)&&!a.test(x)){delete t[S];continue}f[r][S]=S=="transform"?N(x):typeof k=="string"&&a.test(k)?L(x).slice(1):parseFloat(x),c[r][S]=S=="transform"?N(k,f[r][S]):typeof k=="string"&&k.charAt(0)=="#"?L(k).slice(1):B(k,parseFloat(x)),typeof k=="string"&&(T=k.match(l))&&(h[r][S]=T[1])}}return _.apply(n,[s,function(e,i,s){for(r=n.length;r--;){u&&(s=D(p[r],e),n[r].style.left=s[0]+"px",n[r].style.top=s[1]+"px");for(var o in t)i=H(e,h,f,c,o,r),o=="transform"?n[r].style[m]=C(i):o=="opacity"&&!g?n[r].style.filter="alpha(opacity="+i*100+")":n[r].style[A(o)]=i}},i,o])}var e=document,t=window,n=t.performance,r=n&&(n.now||n.webkitNow||n.msNow||n.mozNow),i=r?function(){return r.call(n)}:function(){return+(new Date)},s=!1,o=e.documentElement,u=1e3,a=/^rgb\(|#/,f=/^([+\-])=([\d\.]+)/,l=/^(?:[\+\-]=?)?\d+(?:\.\d+)?(%|in|cm|mm|em|ex|pt|pc|px)$/,c=/rotate\(((?:[+\-]=)?([\-\d\.]+))deg\)/,h=/scale\(((?:[+\-]=)?([\d\.]+))\)/,p=/skew\(((?:[+\-]=)?([\-\d\.]+))deg, ?((?:[+\-]=)?([\-\d\.]+))deg\)/,d=/translate\(((?:[+\-]=)?([\-\d\.]+))px, ?((?:[+\-]=)?([\-\d\.]+))px\)/,v={lineHeight:1,zoom:1,zIndex:1,opacity:1,transform:1},m=function(){var t=e.createElement("a").style,n=["webkitTransform","MozTransform","OTransform","msTransform","Transform"],r;for(r=0;r1e12!=i()>1e12});var w=[];return j.tween=_,j.getStyle=y,j.bezier=D,j.transform=m,j.parseTransform=N,j.formatTransform=C,j.animationFrame=b,j.easings={},j})
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "morpheus",
3 | "description": "A Brilliant Animator",
4 | "version": "0.7.2",
5 | "homepage": "https://github.com/ded/morpheus",
6 | "author": "Dustin Diaz (http://dustindiaz.com)",
7 | "keywords": [
8 | "ender",
9 | "animation",
10 | "motion",
11 | "css",
12 | "colors",
13 | "morph",
14 | "tween",
15 | "curve",
16 | "bezier",
17 | "transform",
18 | "skew",
19 | "rotate"
20 | ],
21 | "main": "./morpheus.js",
22 | "ender": "./src/ender.js",
23 | "repository": {
24 | "type": "git",
25 | "url": "https://github.com/ded/morpheus.git"
26 | },
27 | "devDependencies": {
28 | "sink-test": "1.x.x",
29 | "smoosh": "0.4.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/copyright.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Morpheus - A Brilliant Animator
3 | * https://github.com/ded/morpheus - (c) Dustin Diaz 2011
4 | * License MIT
5 | */
--------------------------------------------------------------------------------
/src/easings.js:
--------------------------------------------------------------------------------
1 | /* The equations defined here are open source under BSD License.
2 | * http://www.robertpenner.com/easing_terms_of_use.html (c) 2003 Robert Penner
3 | * Adapted to single time-based by
4 | * Brian Crescimanno
5 | * Ken Snyder
6 | */
7 | var easings = {
8 | easeOut: function (t) {
9 | return Math.sin(t * Math.PI / 2);
10 | }
11 |
12 | , easeOutStrong: function (t) {
13 | return (t == 1) ? 1 : 1 - Math.pow(2, -10 * t);
14 | }
15 |
16 | , easeIn: function (t) {
17 | return t * t;
18 | }
19 |
20 | , easeInStrong: function (t) {
21 | return (t == 0) ? 0 : Math.pow(2, 10 * (t - 1));
22 | }
23 |
24 | , easeOutBounce: function(pos) {
25 | if ((pos) < (1/2.75)) {
26 | return (7.5625*pos*pos);
27 | } else if (pos < (2/2.75)) {
28 | return (7.5625*(pos-=(1.5/2.75))*pos + .75);
29 | } else if (pos < (2.5/2.75)) {
30 | return (7.5625*(pos-=(2.25/2.75))*pos + .9375);
31 | } else {
32 | return (7.5625*(pos-=(2.625/2.75))*pos + .984375);
33 | }
34 | }
35 |
36 | , easeInBack: function(pos){
37 | var s = 1.70158;
38 | return (pos)*pos*((s+1)*pos - s);
39 | }
40 |
41 | , easeOutBack: function(pos){
42 | var s = 1.70158;
43 | return (pos=pos-1)*pos*((s+1)*pos + s) + 1;
44 | }
45 |
46 | , bounce: function (t) {
47 | if (t < (1 / 2.75)) {
48 | return 7.5625 * t * t;
49 | }
50 | if (t < (2 / 2.75)) {
51 | return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
52 | }
53 | if (t < (2.5 / 2.75)) {
54 | return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
55 | }
56 | return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
57 | }
58 |
59 | , bouncePast: function (pos) {
60 | if (pos < (1 / 2.75)) {
61 | return (7.5625 * pos * pos);
62 | } else if (pos < (2 / 2.75)) {
63 | return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);
64 | } else if (pos < (2.5 / 2.75)) {
65 | return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);
66 | } else {
67 | return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);
68 | }
69 | }
70 |
71 | , swingTo: function(pos) {
72 | var s = 1.70158;
73 | return (pos -= 1) * pos * ((s + 1) * pos + s) + 1;
74 | }
75 |
76 | , swingFrom: function (pos) {
77 | var s = 1.70158;
78 | return pos * pos * ((s + 1) * pos - s);
79 | }
80 |
81 | , elastic: function(pos) {
82 | return -1 * Math.pow(4, -8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1;
83 | }
84 |
85 | , spring: function(pos) {
86 | return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
87 | }
88 |
89 | , blink: function(pos, blinks) {
90 | return Math.round(pos*(blinks||5)) % 2;
91 | }
92 |
93 | , pulse: function(pos, pulses) {
94 | return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
95 | }
96 |
97 | , wobble: function(pos) {
98 | return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
99 | }
100 |
101 | , sinusoidal: function(pos) {
102 | return (-Math.cos(pos*Math.PI)/2) + 0.5;
103 | }
104 |
105 | , flicker: function(pos) {
106 | var pos = pos + (Math.random()-0.5)/5;
107 | return easings.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);
108 | }
109 |
110 | , mirror: function(pos) {
111 | if (pos < 0.5)
112 | return easings.sinusoidal(pos*2);
113 | else
114 | return easings.sinusoidal(1-(pos-0.5)*2);
115 | }
116 |
117 | };
--------------------------------------------------------------------------------
/src/ender.js:
--------------------------------------------------------------------------------
1 | var morpheus = require('morpheus')
2 | !function ($) {
3 | $.ender({
4 | animate: function (options) {
5 | return morpheus(this, options)
6 | }
7 | , fadeIn: function (d, fn) {
8 | return morpheus(this, {
9 | duration: d
10 | , opacity: 1
11 | , complete: fn
12 | })
13 | }
14 | , fadeOut: function (d, fn) {
15 | return morpheus(this, {
16 | duration: d
17 | , opacity: 0
18 | , complete: fn
19 | })
20 | }
21 | }, true)
22 | $.ender({
23 | tween: morpheus.tween
24 | })
25 | }(ender)
--------------------------------------------------------------------------------
/src/morpheus.js:
--------------------------------------------------------------------------------
1 | !function (name, definition) {
2 | if (typeof define == 'function') define(definition)
3 | else if (typeof module != 'undefined') module.exports = definition()
4 | else this[name] = definition()
5 | }('morpheus', function () {
6 |
7 | var doc = document
8 | , win = window
9 | , perf = win.performance
10 | , perfNow = perf && (perf.now || perf.webkitNow || perf.msNow || perf.mozNow)
11 | , now = perfNow ? function () { return perfNow.call(perf) } : function () { return +new Date() }
12 | , fixTs = false // feature detected below
13 | , html = doc.documentElement
14 | , thousand = 1000
15 | , rgbOhex = /^rgb\(|#/
16 | , relVal = /^([+\-])=([\d\.]+)/
17 | , numUnit = /^(?:[\+\-]=?)?\d+(?:\.\d+)?(%|in|cm|mm|em|ex|pt|pc|px)$/
18 | , rotate = /rotate\(((?:[+\-]=)?([\-\d\.]+))deg\)/
19 | , scale = /scale\(((?:[+\-]=)?([\d\.]+))\)/
20 | , skew = /skew\(((?:[+\-]=)?([\-\d\.]+))deg, ?((?:[+\-]=)?([\-\d\.]+))deg\)/
21 | , translate = /translate\(((?:[+\-]=)?([\-\d\.]+))px, ?((?:[+\-]=)?([\-\d\.]+))px\)/
22 | // these elements do not require 'px'
23 | , unitless = { lineHeight: 1, zoom: 1, zIndex: 1, opacity: 1, transform: 1}
24 |
25 | // which property name does this browser use for transform
26 | var transform = function () {
27 | var styles = doc.createElement('a').style
28 | , props = ['webkitTransform', 'MozTransform', 'OTransform', 'msTransform', 'Transform']
29 | , i
30 | for (i = 0; i < props.length; i++) {
31 | if (props[i] in styles) return props[i]
32 | }
33 | }()
34 |
35 | // does this browser support the opacity property?
36 | var opasity = function () {
37 | return typeof doc.createElement('a').style.opacity !== 'undefined'
38 | }()
39 |
40 | // initial style is determined by the elements themselves
41 | var getStyle = doc.defaultView && doc.defaultView.getComputedStyle ?
42 | function (el, property) {
43 | property = property == 'transform' ? transform : property
44 | property = camelize(property)
45 | var value = null
46 | , computed = doc.defaultView.getComputedStyle(el, '')
47 | computed && (value = computed[property])
48 | return el.style[property] || value
49 | } : html.currentStyle ?
50 |
51 | function (el, property) {
52 | property = camelize(property)
53 |
54 | if (property == 'opacity') {
55 | var val = 100
56 | try {
57 | val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity
58 | } catch (e1) {
59 | try {
60 | val = el.filters('alpha').opacity
61 | } catch (e2) {}
62 | }
63 | return val / 100
64 | }
65 | var value = el.currentStyle ? el.currentStyle[property] : null
66 | return el.style[property] || value
67 | } :
68 | function (el, property) {
69 | return el.style[camelize(property)]
70 | }
71 |
72 | var frame = function () {
73 | // native animation frames
74 | // http://webstuff.nfshost.com/anim-timing/Overview.html
75 | // http://dev.chromium.org/developers/design-documents/requestanimationframe-implementation
76 | return win.requestAnimationFrame ||
77 | win.webkitRequestAnimationFrame ||
78 | win.mozRequestAnimationFrame ||
79 | win.msRequestAnimationFrame ||
80 | win.oRequestAnimationFrame ||
81 | function (callback) {
82 | win.setTimeout(function () {
83 | callback(+new Date())
84 | }, 17) // when I was 17..
85 | }
86 | }()
87 |
88 | frame(function(timestamp) {
89 | // feature-detect if rAF and now() are of the same scale (epoch or high-res),
90 | // if not, we have to do a timestamp fix on each frame
91 | fixTs = timestamp > 1e12 != now() > 1e12
92 | })
93 |
94 | var children = []
95 |
96 | function has(array, elem, i) {
97 | if (Array.prototype.indexOf) return array.indexOf(elem)
98 | for (i = 0; i < array.length; ++i) {
99 | if (array[i] === elem) return i
100 | }
101 | }
102 |
103 | function render(timestamp) {
104 | var i, count = children.length
105 | if (fixTs) timestamp = now()
106 | for (i = count; i--;) {
107 | children[i](timestamp)
108 | }
109 | children.length && frame(render)
110 | }
111 |
112 | function live(f) {
113 | if (children.push(f) === 1) frame(render)
114 | }
115 |
116 | function die(f) {
117 | var rest, index = has(children, f)
118 | if (index >= 0) {
119 | rest = children.slice(index + 1)
120 | children.length = index
121 | children = children.concat(rest)
122 | }
123 | }
124 |
125 | function parseTransform(style, base) {
126 | var values = {}, m
127 | if (m = style.match(rotate)) values.rotate = by(m[1], base ? base.rotate : null)
128 | if (m = style.match(scale)) values.scale = by(m[1], base ? base.scale : null)
129 | if (m = style.match(skew)) {values.skewx = by(m[1], base ? base.skewx : null); values.skewy = by(m[3], base ? base.skewy : null)}
130 | if (m = style.match(translate)) {values.translatex = by(m[1], base ? base.translatex : null); values.translatey = by(m[3], base ? base.translatey : null)}
131 | return values
132 | }
133 |
134 | function formatTransform(v) {
135 | var s = ''
136 | if ('rotate' in v) s += 'rotate(' + v.rotate + 'deg) '
137 | if ('scale' in v) s += 'scale(' + v.scale + ') '
138 | if ('translatex' in v) s += 'translate(' + v.translatex + 'px,' + v.translatey + 'px) '
139 | if ('skewx' in v) s += 'skew(' + v.skewx + 'deg,' + v.skewy + 'deg)'
140 | return s
141 | }
142 |
143 | function rgb(r, g, b) {
144 | return '#' + (1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1)
145 | }
146 |
147 | // convert rgb and short hex to long hex
148 | function toHex(c) {
149 | var m = c.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/)
150 | return (m ? rgb(m[1], m[2], m[3]) : c)
151 | .replace(/#(\w)(\w)(\w)$/, '#$1$1$2$2$3$3') // short skirt to long jacket
152 | }
153 |
154 | // change font-size => fontSize etc.
155 | function camelize(s) {
156 | return s.replace(/-(.)/g, function (m, m1) {
157 | return m1.toUpperCase()
158 | })
159 | }
160 |
161 | // aren't we having it?
162 | function fun(f) {
163 | return typeof f == 'function'
164 | }
165 |
166 | function nativeTween(t) {
167 | // default to a pleasant-to-the-eye easeOut (like native animations)
168 | return Math.sin(t * Math.PI / 2)
169 | }
170 |
171 | /**
172 | * Core tween method that requests each frame
173 | * @param duration: time in milliseconds. defaults to 1000
174 | * @param fn: tween frame callback function receiving 'position'
175 | * @param done {optional}: complete callback function
176 | * @param ease {optional}: easing method. defaults to easeOut
177 | * @param from {optional}: integer to start from
178 | * @param to {optional}: integer to end at
179 | * @returns method to stop the animation
180 | */
181 | function tween(duration, fn, done, ease, from, to) {
182 | ease = fun(ease) ? ease : morpheus.easings[ease] || nativeTween
183 | var time = duration || thousand
184 | , self = this
185 | , diff = to - from
186 | , start = now()
187 | , stop = 0
188 | , end = 0
189 |
190 | function run(t) {
191 | var delta = t - start
192 | if (delta > time || stop) {
193 | to = isFinite(to) ? to : 1
194 | stop ? end && fn(to) : fn(to)
195 | die(run)
196 | return done && done.apply(self)
197 | }
198 | // if you don't specify a 'to' you can use tween as a generic delta tweener
199 | // cool, eh?
200 | isFinite(to) ?
201 | fn((diff * ease(delta / time)) + from) :
202 | fn(ease(delta / time))
203 | }
204 |
205 | live(run)
206 |
207 | return {
208 | stop: function (jump) {
209 | stop = 1
210 | end = jump // jump to end of animation?
211 | if (!jump) done = null // remove callback if not jumping to end
212 | }
213 | }
214 | }
215 |
216 | /**
217 | * generic bezier method for animating x|y coordinates
218 | * minimum of 2 points required (start and end).
219 | * first point start, last point end
220 | * additional control points are optional (but why else would you use this anyway ;)
221 | * @param points: array containing control points
222 | [[0, 0], [100, 200], [200, 100]]
223 | * @param pos: current be(tween) position represented as float 0 - 1
224 | * @return [x, y]
225 | */
226 | function bezier(points, pos) {
227 | var n = points.length, r = [], i, j
228 | for (i = 0; i < n; ++i) {
229 | r[i] = [points[i][0], points[i][1]]
230 | }
231 | for (j = 1; j < n; ++j) {
232 | for (i = 0; i < n - j; ++i) {
233 | r[i][0] = (1 - pos) * r[i][0] + pos * r[parseInt(i + 1, 10)][0]
234 | r[i][1] = (1 - pos) * r[i][1] + pos * r[parseInt(i + 1, 10)][1]
235 | }
236 | }
237 | return [r[0][0], r[0][1]]
238 | }
239 |
240 | // this gets you the next hex in line according to a 'position'
241 | function nextColor(pos, start, finish) {
242 | var r = [], i, e, from, to
243 | for (i = 0; i < 6; i++) {
244 | from = Math.min(15, parseInt(start.charAt(i), 16))
245 | to = Math.min(15, parseInt(finish.charAt(i), 16))
246 | e = Math.floor((to - from) * pos + from)
247 | e = e > 15 ? 15 : e < 0 ? 0 : e
248 | r[i] = e.toString(16)
249 | }
250 | return '#' + r.join('')
251 | }
252 |
253 | // this retreives the frame value within a sequence
254 | function getTweenVal(pos, units, begin, end, k, i, v) {
255 | if (k == 'transform') {
256 | v = {}
257 | for (var t in begin[i][k]) {
258 | v[t] = (t in end[i][k]) ? Math.round(((end[i][k][t] - begin[i][k][t]) * pos + begin[i][k][t]) * thousand) / thousand : begin[i][k][t]
259 | }
260 | return v
261 | } else if (typeof begin[i][k] == 'string') {
262 | return nextColor(pos, begin[i][k], end[i][k])
263 | } else {
264 | // round so we don't get crazy long floats
265 | v = Math.round(((end[i][k] - begin[i][k]) * pos + begin[i][k]) * thousand) / thousand
266 | // some css properties don't require a unit (like zIndex, lineHeight, opacity)
267 | if (!(k in unitless)) v += units[i][k] || 'px'
268 | return v
269 | }
270 | }
271 |
272 | // support for relative movement via '+=n' or '-=n'
273 | function by(val, start, m, r, i) {
274 | return (m = relVal.exec(val)) ?
275 | (i = parseFloat(m[2])) && (start + (m[1] == '+' ? 1 : -1) * i) :
276 | parseFloat(val)
277 | }
278 |
279 | /**
280 | * morpheus:
281 | * @param element(s): HTMLElement(s)
282 | * @param options: mixed bag between CSS Style properties & animation options
283 | * - {n} CSS properties|values
284 | * - value can be strings, integers,
285 | * - or callback function that receives element to be animated. method must return value to be tweened
286 | * - relative animations start with += or -= followed by integer
287 | * - duration: time in ms - defaults to 1000(ms)
288 | * - easing: a transition method - defaults to an 'easeOut' algorithm
289 | * - complete: a callback method for when all elements have finished
290 | * - bezier: array of arrays containing x|y coordinates that define the bezier points. defaults to none
291 | * - this may also be a function that receives element to be animated. it must return a value
292 | */
293 | function morpheus(elements, options) {
294 | var els = elements ? (els = isFinite(elements.length) ? elements : [elements]) : [], i
295 | , complete = options.complete
296 | , duration = options.duration
297 | , ease = options.easing
298 | , points = options.bezier
299 | , begin = []
300 | , end = []
301 | , units = []
302 | , bez = []
303 | , originalLeft
304 | , originalTop
305 |
306 | if (points) {
307 | // remember the original values for top|left
308 | originalLeft = options.left;
309 | originalTop = options.top;
310 | delete options.right;
311 | delete options.bottom;
312 | delete options.left;
313 | delete options.top;
314 | }
315 |
316 | for (i = els.length; i--;) {
317 |
318 | // record beginning and end states to calculate positions
319 | begin[i] = {}
320 | end[i] = {}
321 | units[i] = {}
322 |
323 | // are we 'moving'?
324 | if (points) {
325 |
326 | var left = getStyle(els[i], 'left')
327 | , top = getStyle(els[i], 'top')
328 | , xy = [by(fun(originalLeft) ? originalLeft(els[i]) : originalLeft || 0, parseFloat(left)),
329 | by(fun(originalTop) ? originalTop(els[i]) : originalTop || 0, parseFloat(top))]
330 |
331 | bez[i] = fun(points) ? points(els[i], xy) : points
332 | bez[i].push(xy)
333 | bez[i].unshift([
334 | parseInt(left, 10),
335 | parseInt(top, 10)
336 | ])
337 | }
338 |
339 | for (var k in options) {
340 | switch (k) {
341 | case 'complete':
342 | case 'duration':
343 | case 'easing':
344 | case 'bezier':
345 | continue
346 | }
347 | var v = getStyle(els[i], k), unit
348 | , tmp = fun(options[k]) ? options[k](els[i]) : options[k]
349 | if (typeof tmp == 'string' &&
350 | rgbOhex.test(tmp) &&
351 | !rgbOhex.test(v)) {
352 | delete options[k]; // remove key :(
353 | continue; // cannot animate colors like 'orange' or 'transparent'
354 | // only #xxx, #xxxxxx, rgb(n,n,n)
355 | }
356 |
357 | begin[i][k] = k == 'transform' ? parseTransform(v) :
358 | typeof tmp == 'string' && rgbOhex.test(tmp) ?
359 | toHex(v).slice(1) :
360 | parseFloat(v)
361 | end[i][k] = k == 'transform' ? parseTransform(tmp, begin[i][k]) :
362 | typeof tmp == 'string' && tmp.charAt(0) == '#' ?
363 | toHex(tmp).slice(1) :
364 | by(tmp, parseFloat(v));
365 | // record original unit
366 | (typeof tmp == 'string') && (unit = tmp.match(numUnit)) && (units[i][k] = unit[1])
367 | }
368 | }
369 | // ONE TWEEN TO RULE THEM ALL
370 | return tween.apply(els, [duration, function (pos, v, xy) {
371 | // normally not a fan of optimizing for() loops, but we want something
372 | // fast for animating
373 | for (i = els.length; i--;) {
374 | if (points) {
375 | xy = bezier(bez[i], pos)
376 | els[i].style.left = xy[0] + 'px'
377 | els[i].style.top = xy[1] + 'px'
378 | }
379 | for (var k in options) {
380 | v = getTweenVal(pos, units, begin, end, k, i)
381 | k == 'transform' ?
382 | els[i].style[transform] = formatTransform(v) :
383 | k == 'opacity' && !opasity ?
384 | (els[i].style.filter = 'alpha(opacity=' + (v * 100) + ')') :
385 | (els[i].style[camelize(k)] = v)
386 | }
387 | }
388 | }, complete, ease])
389 | }
390 |
391 | // expose useful methods
392 | morpheus.tween = tween
393 | morpheus.getStyle = getStyle
394 | morpheus.bezier = bezier
395 | morpheus.transform = transform
396 | morpheus.parseTransform = parseTransform
397 | morpheus.formatTransform = formatTransform
398 | morpheus.animationFrame = frame
399 | morpheus.easings = {}
400 |
401 | return morpheus
402 |
403 | });
404 |
--------------------------------------------------------------------------------
/src/rtltr.js:
--------------------------------------------------------------------------------
1 | !function (context) {
2 | var m = context.morpheus,
3 | map = {
4 | 'padding-left': 1
5 | , 'paddingLeft': 1
6 | , 'padding-right': 1
7 | , 'paddingRight': 1
8 | , 'margin-left': 1
9 | , 'marginLeft': 1
10 | , 'margin-right': 1
11 | , 'marginRight': 1
12 | , 'border-left-width': 1
13 | , 'borderLeftWidth': 1
14 | , 'border-right-width': 1
15 | , 'borderRightWidth': 1
16 | , 'left': 1
17 | , 'right': 1
18 | }
19 | context.morpheus = function (elements, options, k, i, v) {
20 | if (context.morpheus.normal) {
21 | return m(elements, options)
22 | }
23 | for (k in options) {
24 | if (options.hasOwnProperty(k) && map[k]) {
25 | v = options[k]
26 | delete options[k]
27 | options[k.replace(/left|right/ig, function (m) {
28 | return /left/i.exec(m) ? 'Right' : 'Left'
29 | })] = v
30 | }
31 | }
32 | return m(elements, options)
33 | }
34 | }(this);
--------------------------------------------------------------------------------
/tests/tests.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Morpheus Tests
5 |
6 |
17 |
18 |
19 |
20 |
21 |
22 |