move.js 运动插件是一款针对元素动画效果的插件。可以运用此插件制作出各类元素效果。
插件GitHub地址:https://github.com/visionmedia/move.js
下面整理学习心得:
一、move.js原码:
1 ;(function(){ 2 3 /** 4 * Require the module at `name`. 5 * 6 * @param {String} name 7 * @return {Object} exports 8 * @api public 9 */ 10 11 function require(name) { 12 var module = require.modules[name]; 13 if (!module) throw new Error('failed to require "' + name + '"'); 14 15 if (!('exports' in module) && typeof module.definition === 'function') { 16 module.client = module.component = true; 17 module.definition.call(this, module.exports = {}, module); 18 delete module.definition; 19 } 20 21 return module.exports; 22 } 23 24 /** 25 * Meta info, accessible in the global scope unless you use AMD option. 26 */ 27 28 require.loader = 'component'; 29 30 /** 31 * Internal helper object, contains a sorting function for semantiv versioning 32 */ 33 require.helper = {}; 34 require.helper.semVerSort = function(a, b) { 35 var aArray = a.version.split('.'); 36 var bArray = b.version.split('.'); 37 for (var i=0; i<aArray.length; ++i) { 38 var aInt = parseInt(aArray[i], 10); 39 var bInt = parseInt(bArray[i], 10); 40 if (aInt === bInt) { 41 var aLex = aArray[i].substr((""+aInt).length); 42 var bLex = bArray[i].substr((""+bInt).length); 43 if (aLex === '' && bLex !== '') return 1; 44 if (aLex !== '' && bLex === '') return -1; 45 if (aLex !== '' && bLex !== '') return aLex > bLex ? 1 : -1; 46 continue; 47 } else if (aInt > bInt) { 48 return 1; 49 } else { 50 return -1; 51 } 52 } 53 return 0; 54 } 55 56 /** 57 * Find and require a module which name starts with the provided name. 58 * If multiple modules exists, the highest semver is used. 59 * This function can only be used for remote dependencies. 60 61 * @param {String} name - module name: `user~repo` 62 * @param {Boolean} returnPath - returns the canonical require path if true, 63 * otherwise it returns the epxorted module 64 */ 65 require.latest = function (name, returnPath) { 66 function showError(name) { 67 throw new Error('failed to find latest module of "' + name + '"'); 68 } 69 // only remotes with semvers, ignore local files conataining a '/' 70 var versionRegexp = /(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/; 71 var remoteRegexp = /(.*)~(.*)/; 72 if (!remoteRegexp.test(name)) showError(name); 73 var moduleNames = Object.keys(require.modules); 74 var semVerCandidates = []; 75 var otherCandidates = []; // for instance: name of the git branch 76 for (var i=0; i<moduleNames.length; i++) { 77 var moduleName = moduleNames[i]; 78 if (new RegExp(name + '@').test(moduleName)) { 79 var version = moduleName.substr(name.length+1); 80 var semVerMatch = versionRegexp.exec(moduleName); 81 if (semVerMatch != null) { 82 semVerCandidates.push({version: version, name: moduleName}); 83 } else { 84 otherCandidates.push({version: version, name: moduleName}); 85 } 86 } 87 } 88 if (semVerCandidates.concat(otherCandidates).length === 0) { 89 showError(name); 90 } 91 if (semVerCandidates.length > 0) { 92 var module = semVerCandidates.sort(require.helper.semVerSort).pop().name; 93 if (returnPath === true) { 94 return module; 95 } 96 return require(module); 97 } 98 // if the build contains more than one branch of the same module 99 // you should not use this funciton 100 var module = otherCandidates.sort(function(a, b) {return a.name > b.name})[0].name; 101 if (returnPath === true) { 102 return module; 103 } 104 return require(module); 105 } 106 107 /** 108 * Registered modules. 109 */ 110 111 require.modules = {}; 112 113 /** 114 * Register module at `name` with callback `definition`. 115 * 116 * @param {String} name 117 * @param {Function} definition 118 * @api private 119 */ 120 121 require.register = function (name, definition) { 122 require.modules[name] = { 123 definition: definition 124 }; 125 }; 126 127 /** 128 * Define a module's exports immediately with `exports`. 129 * 130 * @param {String} name 131 * @param {Generic} exports 132 * @api private 133 */ 134 135 require.define = function (name, exports) { 136 require.modules[name] = { 137 exports: exports 138 }; 139 }; 140 require.register("component~transform-property@0.0.1", function (exports, module) { 141 142 var styles = [ 143 'webkitTransform', 144 'MozTransform', 145 'msTransform', 146 'OTransform', 147 'transform' 148 ]; 149 150 var el = document.createElement('p'); 151 var style; 152 153 for (var i = 0; i < styles.length; i++) { 154 style = styles[i]; 155 if (null != el.style[style]) { 156 module.exports = style; 157 break; 158 } 159 } 160 161 }); 162 163 require.register("component~has-translate3d@0.0.3", function (exports, module) { 164 165 var prop = require('component~transform-property@0.0.1'); 166 167 // IE <=8 doesn't have `getComputedStyle` 168 if (!prop || !window.getComputedStyle) { 169 module.exports = false; 170 171 } else { 172 var map = { 173 webkitTransform: '-webkit-transform', 174 OTransform: '-o-transform', 175 msTransform: '-ms-transform', 176 MozTransform: '-moz-transform', 177 transform: 'transform' 178 }; 179 180 // from: https://gist.github.com/lorenzopolidori/3794226 181 var el = document.createElement('div'); 182 el.style[prop] = 'translate3d(1px,1px,1px)'; 183 document.body.insertBefore(el, null); 184 var val = getComputedStyle(el).getPropertyValue(map[prop]); 185 document.body.removeChild(el); 186 module.exports = null != val && val.length && 'none' != val; 187 } 188 189 }); 190 191 require.register("yields~has-transitions@1.0.0", function (exports, module) { 192 /** 193 * Check if `el` or browser supports transitions. 194 * 195 * @param {Element} el 196 * @return {Boolean} 197 * @api public 198 */ 199 200 exports = module.exports = function(el){ 201 switch (arguments.length) { 202 case 0: return bool; 203 case 1: return bool 204 ? transitions(el) 205 : bool; 206 } 207 }; 208 209 /** 210 * Check if the given `el` has transitions. 211 * 212 * @param {Element} el 213 * @return {Boolean} 214 * @api private 215 */ 216 217 function transitions(el, styl){ 218 if (el.transition) return true; 219 styl = window.getComputedStyle(el); 220 return !! parseFloat(styl.transitionDuration, 10); 221 } 222 223 /** 224 * Style. 225 */ 226 227 var styl = document.body.style; 228 229 /** 230 * Export support. 231 */ 232 233 var bool = 'transition' in styl 234 || 'webkitTransition' in styl 235 || 'MozTransition' in styl 236 || 'msTransition' in styl; 237 238 }); 239 240 require.register("component~event@0.1.4", function (exports, module) { 241 var bind = window.addEventListener ? 'addEventListener' : 'attachEvent', 242 unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent', 243 prefix = bind !== 'addEventListener' ? 'on' : ''; 244 245 /** 246 * Bind `el` event `type` to `fn`. 247 * 248 * @param {Element} el 249 * @param {String} type 250 * @param {Function} fn 251 * @param {Boolean} capture 252 * @return {Function} 253 * @api public 254 */ 255 256 exports.bind = function(el, type, fn, capture){ 257 el[bind](prefix + type, fn, capture || false); 258 return fn; 259 }; 260 261 /** 262 * Unbind `el` event `type`'s callback `fn`. 263 * 264 * @param {Element} el 265 * @param {String} type 266 * @param {Function} fn 267 * @param {Boolean} capture 268 * @return {Function} 269 * @api public 270 */ 271 272 exports.unbind = function(el, type, fn, capture){ 273 el[unbind](prefix + type, fn, capture || false); 274 return fn; 275 }; 276 }); 277 278 require.register("ecarter~css-emitter@0.0.1", function (exports, module) { 279 /** 280 * Module Dependencies 281 */ 282 283 var events = require('component~event@0.1.4'); 284 285 // CSS events 286 287 var watch = [ 288 'transitionend' 289 , 'webkitTransitionEnd' 290 , 'oTransitionEnd' 291 , 'MSTransitionEnd' 292 , 'animationend' 293 , 'webkitAnimationEnd' 294 , 'oAnimationEnd' 295 , 'MSAnimationEnd' 296 ]; 297 298 /** 299 * Expose `CSSnext` 300 */ 301 302 module.exports = CssEmitter; 303 304 /** 305 * Initialize a new `CssEmitter` 306 * 307 */ 308 309 function CssEmitter(element){ 310 if (!(this instanceof CssEmitter)) return new CssEmitter(element); 311 this.el = element; 312 } 313 314 /** 315 * Bind CSS events. 316 * 317 * @api public 318 */ 319 320 CssEmitter.prototype.bind = function(fn){ 321 for (var i=0; i < watch.length; i++) { 322 events.bind(this.el, watch[i], fn); 323 } 324 return this; 325 }; 326 327 /** 328 * Unbind CSS events 329 * 330 * @api public 331 */ 332 333 CssEmitter.prototype.unbind = function(fn){ 334 for (var i=0; i < watch.length; i++) { 335 events.unbind(this.el, watch[i], fn); 336 } 337 return this; 338 }; 339 340 /** 341 * Fire callback only once 342 * 343 * @api public 344 */ 345 346 CssEmitter.prototype.once = function(fn){ 347 var self = this; 348 function on(){ 349 self.unbind(on); 350 fn.apply(self.el, arguments); 351 } 352 self.bind(on); 353 return this; 354 }; 355 356 357 }); 358 359 require.register("component~once@0.0.1", function (exports, module) { 360 361 /** 362 * Identifier. 363 */ 364 365 var n = 0; 366 367 /** 368 * Global. 369 */ 370 371 var global = (function(){ return this })(); 372 373 /** 374 * Make `fn` callable only once. 375 * 376 * @param {Function} fn 377 * @return {Function} 378 * @api public 379 */ 380 381 module.exports = function(fn) { 382 var id = n++; 383 384 function once(){ 385 // no receiver 386 if (this == global) { 387 if (once.called) return; 388 once.called = true; 389 return fn.apply(this, arguments); 390 } 391 392 // receiver 393 var key = '__called_' + id + '__'; 394 if (this[key]) return; 395 this[key] = true; 396 return fn.apply(this, arguments); 397 } 398 399 return once; 400 }; 401 402 }); 403 404 require.register("yields~after-transition@0.0.1", function (exports, module) { 405 406 /** 407 * dependencies 408 */ 409 410 var has = require('yields~has-transitions@1.0.0') 411 , emitter = require('ecarter~css-emitter@0.0.1') 412 , once = require('component~once@0.0.1'); 413 414 /** 415 * Transition support. 416 */ 417 418 var supported = has(); 419 420 /** 421 * Export `after` 422 */ 423 424 module.exports = after; 425 426 /** 427 * Invoke the given `fn` after transitions 428 * 429 * It will be invoked only if the browser 430 * supports transitions __and__ 431 * the element has transitions 432 * set in `.style` or css. 433 * 434 * @param {Element} el 435 * @param {Function} fn 436 * @return {Function} fn 437 * @api public 438 */ 439 440 function after(el, fn){ 441 if (!supported || !has(el)) return fn(); 442 emitter(el).bind(fn); 443 return fn; 444 }; 445 446 /** 447 * Same as `after()` only the function is invoked once. 448 * 449 * @param {Element} el 450 * @param {Function} fn 451 * @return {Function} 452 * @api public 453 */ 454 455 after.once = function(el, fn){ 456 var callback = once(fn); 457 after(el, fn = function(){ 458 emitter(el).unbind(fn); 459 callback(); 460 }); 461 }; 462 463 }); 464 465 require.register("component~emitter@1.2.0", function (exports, module) { 466 467 /** 468 * Expose `Emitter`. 469 */ 470 471 module.exports = Emitter; 472 473 /** 474 * Initialize a new `Emitter`. 475 * 476 * @api public 477 */ 478 479 function Emitter(obj) { 480 if (obj) return mixin(obj); 481 }; 482 483 /** 484 * Mixin the emitter properties. 485 * 486 * @param {Object} obj 487 * @return {Object} 488 * @api private 489 */ 490 491 function mixin(obj) { 492 for (var key in Emitter.prototype) { 493 obj[key] = Emitter.prototype[key]; 494 } 495 return obj; 496 } 497 498 /** 499 * Listen on the given `event` with `fn`. 500 * 501 * @param {String} event 502 * @param {Function} fn 503 * @return {Emitter} 504 * @api public 505 */ 506 507 Emitter.prototype.on = 508 Emitter.prototype.addEventListener = function(event, fn){ 509 this._callbacks = this._callbacks || {}; 510 (this._callbacks['$' + event] = this._callbacks['$' + event] || []) 511 .push(fn); 512 return this; 513 }; 514 515 /** 516 * Adds an `event` listener that will be invoked a single 517 * time then automatically removed. 518 * 519 * @param {String} event 520 * @param {Function} fn 521 * @return {Emitter} 522 * @api public 523 */ 524 525 Emitter.prototype.once = function(event, fn){ 526 function on() { 527 this.off(event, on); 528 fn.apply(this, arguments); 529 } 530 531 on.fn = fn; 532 this.on(event, on); 533 return this; 534 }; 535 536 /** 537 * Remove the given callback for `event` or all 538 * registered callbacks. 539 * 540 * @param {String} event 541 * @param {Function} fn 542 * @return {Emitter} 543 * @api public 544 */ 545 546 Emitter.prototype.off = 547 Emitter.prototype.removeListener = 548 Emitter.prototype.removeAllListeners = 549 Emitter.prototype.removeEventListener = function(event, fn){ 550 this._callbacks = this._callbacks || {}; 551 552 // all 553 if (0 == arguments.length) { 554 this._callbacks = {}; 555 return this; 556 } 557 558 // specific event 559 var callbacks = this._callbacks['$' + event]; 560 if (!callbacks) return this; 561 562 // remove all handlers 563 if (1 == arguments.length) { 564 delete this._callbacks['$' + event]; 565 return this; 566 } 567 568 // remove specific handler 569 var cb; 570 for (var i = 0; i < callbacks.length; i++) { 571 cb = callbacks[i]; 572 if (cb === fn || cb.fn === fn) { 573 callbacks.splice(i, 1); 574 break; 575 } 576 } 577 return this; 578 }; 579 580 /** 581 * Emit `event` with the given args. 582 * 583 * @param {String} event 584 * @param {Mixed} ... 585 * @return {Emitter} 586 */ 587 588 Emitter.prototype.emit = function(event){ 589 this._callbacks = this._callbacks || {}; 590 var args = [].slice.call(arguments, 1) 591 , callbacks = this._callbacks['$' + event]; 592 593 if (callbacks) { 594 callbacks = callbacks.slice(0); 595 for (var i = 0, len = callbacks.length; i < len; ++i) { 596 callbacks[i].apply(this, args); 597 } 598 } 599 600 return this; 601 }; 602 603 /** 604 * Return array of callbacks for `event`. 605 * 606 * @param {String} event 607 * @return {Array} 608 * @api public 609 */ 610 611 Emitter.prototype.listeners = function(event){ 612 this._callbacks = this._callbacks || {}; 613 return this._callbacks['$' + event] || []; 614 }; 615 616 /** 617 * Check if this emitter has `event` handlers. 618 * 619 * @param {String} event 620 * @return {Boolean} 621 * @api public 622 */ 623 624 Emitter.prototype.hasListeners = function(event){ 625 return !! this.listeners(event).length; 626 }; 627 628 }); 629 630 require.register("yields~css-ease@0.0.1", function (exports, module) { 631 632 /** 633 * CSS Easing functions 634 */ 635 636 module.exports = { 637 'in': 'ease-in' 638 , 'out': 'ease-out' 639 , 'in-out': 'ease-in-out' 640 , 'snap': 'cubic-bezier(0,1,.5,1)' 641 , 'linear': 'cubic-bezier(0.250, 0.250, 0.750, 0.750)' 642 , 'ease-in-quad': 'cubic-bezier(0.550, 0.085, 0.680, 0.530)' 643 , 'ease-in-cubic': 'cubic-bezier(0.550, 0.055, 0.675, 0.190)' 644 , 'ease-in-quart': 'cubic-bezier(0.895, 0.030, 0.685, 0.220)' 645 , 'ease-in-quint': 'cubic-bezier(0.755, 0.050, 0.855, 0.060)' 646 , 'ease-in-sine': 'cubic-bezier(0.470, 0.000, 0.745, 0.715)' 647 , 'ease-in-expo': 'cubic-bezier(0.950, 0.050, 0.795, 0.035)' 648 , 'ease-in-circ': 'cubic-bezier(0.600, 0.040, 0.980, 0.335)' 649 , 'ease-in-back': 'cubic-bezier(0.600, -0.280, 0.735, 0.045)' 650 , 'ease-out-quad': 'cubic-bezier(0.250, 0.460, 0.450, 0.940)' 651 , 'ease-out-cubic': 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' 652 , 'ease-out-quart': 'cubic-bezier(0.165, 0.840, 0.440, 1.000)' 653 , 'ease-out-quint': 'cubic-bezier(0.230, 1.000, 0.320, 1.000)' 654 , 'ease-out-sine': 'cubic-bezier(0.390, 0.575, 0.565, 1.000)' 655 , 'ease-out-expo': 'cubic-bezier(0.190, 1.000, 0.220, 1.000)' 656 , 'ease-out-circ': 'cubic-bezier(0.075, 0.820, 0.165, 1.000)' 657 , 'ease-out-back': 'cubic-bezier(0.175, 0.885, 0.320, 1.275)' 658 , 'ease-out-quad': 'cubic-bezier(0.455, 0.030, 0.515, 0.955)' 659 , 'ease-out-cubic': 'cubic-bezier(0.645, 0.045, 0.355, 1.000)' 660 , 'ease-in-out-quart': 'cubic-bezier(0.770, 0.000, 0.175, 1.000)' 661 , 'ease-in-out-quint': 'cubic-bezier(0.860, 0.000, 0.070, 1.000)' 662 , 'ease-in-out-sine': 'cubic-bezier(0.445, 0.050, 0.550, 0.950)' 663 , 'ease-in-out-expo': 'cubic-bezier(1.000, 0.000, 0.000, 1.000)' 664 , 'ease-in-out-circ': 'cubic-bezier(0.785, 0.135, 0.150, 0.860)' 665 , 'ease-in-out-back': 'cubic-bezier(0.680, -0.550, 0.265, 1.550)' 666 }; 667 668 }); 669 670 require.register("component~query@0.0.3", function (exports, module) { 671 function one(selector, el) { 672 return el.querySelector(selector); 673 } 674 675 exports = module.exports = function(selector, el){ 676 el = el || document; 677 return one(selector, el); 678 }; 679 680 exports.all = function(selector, el){ 681 el = el || document; 682 return el.querySelectorAll(selector); 683 }; 684 685 exports.engine = function(obj){ 686 if (!obj.one) throw new Error('.one callback required'); 687 if (!obj.all) throw new Error('.all callback required'); 688 one = obj.one; 689 exports.all = obj.all; 690 return exports; 691 }; 692 693 }); 694 695 require.register("move", function (exports, module) { 696 /** 697 * Module Dependencies. 698 */ 699 700 var Emitter = require('component~emitter@1.2.0'); 701 var query = require('component~query@0.0.3'); 702 var after = require('yields~after-transition@0.0.1'); 703 var has3d = require('component~has-translate3d@0.0.3'); 704 var ease = require('yields~css-ease@0.0.1'); 705 706 /** 707 * CSS Translate 708 */ 709 710 var translate = has3d 711 ? ['translate3d(', ', 0)'] 712 : ['translate(', ')']; 713 714 /** 715 * Export `Move` 716 */ 717 718 module.exports = Move; 719 720 /** 721 * Get computed style. 722 */ 723 724 var style = window.getComputedStyle 725 || window.currentStyle; 726 727 /** 728 * Library version. 729 */ 730 731 Move.version = '0.5.0'; 732 733 /** 734 * Export `ease` 735 */ 736 737 Move.ease = ease; 738 739 /** 740 * Defaults. 741 * 742 * `duration` - default duration of 500ms 743 * 744 */ 745 746 Move.defaults = { 747 duration: 500 748 }; 749 750 /** 751 * Default element selection utilized by `move(selector)`. 752 * 753 * Override to implement your own selection, for example 754 * with jQuery one might write: 755 * 756 * move.select = function(selector) { 757 * return jQuery(selector).get(0); 758 * }; 759 * 760 * @param {Object|String} selector 761 * @return {Element} 762 * @api public 763 */ 764 765 Move.select = function(selector){ 766 if ('string' != typeof selector) return selector; 767 return query(selector); 768 }; 769 770 /** 771 * Initialize a new `Move` with the given `el`. 772 * 773 * @param {Element} el 774 * @api public 775 */ 776 777 function Move(el) { 778 if (!(this instanceof Move)) return new Move(el); 779 if ('string' == typeof el) el = query(el); 780 if (!el) throw new TypeError('Move must be initialized with element or selector'); 781 this.el = el; 782 this._props = {}; 783 this._rotate = 0; 784 this._transitionProps = []; 785 this._transforms = []; 786 this.duration(Move.defaults.duration) 787 }; 788 789 790 /** 791 * Inherit from `EventEmitter.prototype`. 792 */ 793 794 Emitter(Move.prototype); 795 796 /** 797 * Buffer `transform`. 798 * 799 * @param {String} transform 800 * @return {Move} for chaining 801 * @api private 802 */ 803 804 Move.prototype.transform = function(transform){ 805 this._transforms.push(transform); 806 return this; 807 }; 808 809 /** 810 * Skew `x` and `y`. 811 * 812 * @param {Number} x 813 * @param {Number} y 814 * @return {Move} for chaining 815 * @api public 816 */ 817 818 Move.prototype.skew = function(x, y){ 819 return this.transform('skew(' 820 + x + 'deg, ' 821 + (y || 0) 822 + 'deg)'); 823 }; 824 825 /** 826 * Skew x by `n`. 827 * 828 * @param {Number} n 829 * @return {Move} for chaining 830 * @api public 831 */ 832 833 Move.prototype.skewX = function(n){ 834 return this.transform('skewX(' + n + 'deg)'); 835 }; 836 837 /** 838 * Skew y by `n`. 839 * 840 * @param {Number} n 841 * @return {Move} for chaining 842 * @api public 843 */ 844 845 Move.prototype.skewY = function(n){ 846 return this.transform('skewY(' + n + 'deg)'); 847 }; 848 849 /** 850 * Translate `x` and `y` axis. 851 * 852 * @param {Number} x 853 * @param {Number} y 854 * @return {Move} for chaining 855 * @api public 856 */ 857 858 Move.prototype.translate = 859 Move.prototype.to = function(x, y){ 860 return this.transform(translate.join('' 861 + x +'px, ' 862 + (y || 0) 863 + 'px')); 864 }; 865 866 /** 867 * Translate on the x axis to `n`. 868 * 869 * @param {Number} n 870 * @return {Move} for chaining 871 * @api public 872 */ 873 874 Move.prototype.translateX = 875 Move.prototype.x = function(n){ 876 return this.transform('translateX(' + n + 'px)'); 877 }; 878 879 /** 880 * Translate on the y axis to `n`. 881 * 882 * @param {Number} n 883 * @return {Move} for chaining 884 * @api public 885 */ 886 887 Move.prototype.translateY = 888 Move.prototype.y = function(n){ 889 return this.transform('translateY(' + n + 'px)'); 890 }; 891 892 /** 893 * Scale the x and y axis by `x`, or 894 * individually scale `x` and `y`. 895 * 896 * @param {Number} x 897 * @param {Number} y 898 * @return {Move} for chaining 899 * @api public 900 */ 901 902 Move.prototype.scale = function(x, y){ 903 return this.transform('scale(' 904 + x + ', ' 905 + (y || x) 906 + ')'); 907 }; 908 909 /** 910 * Scale x axis by `n`. 911 * 912 * @param {Number} n 913 * @return {Move} for chaining 914 * @api public 915 */ 916 917 Move.prototype.scaleX = function(n){ 918 return this.transform('scaleX(' + n + ')') 919 }; 920 921 /** 922 * Apply a matrix transformation 923 * 924 * @param {Number} m11 A matrix coefficient 925 * @param {Number} m12 A matrix coefficient 926 * @param {Number} m21 A matrix coefficient 927 * @param {Number} m22 A matrix coefficient 928 * @param {Number} m31 A matrix coefficient 929 * @param {Number} m32 A matrix coefficient 930 * @return {Move} for chaining 931 * @api public 932 */ 933 934 Move.prototype.matrix = function(m11, m12, m21, m22, m31, m32){ 935 return this.transform('matrix(' + [m11,m12,m21,m22,m31,m32].join(',') + ')'); 936 }; 937 938 /** 939 * Scale y axis by `n`. 940 * 941 * @param {Number} n 942 * @return {Move} for chaining 943 * @api public 944 */ 945 946 Move.prototype.scaleY = function(n){ 947 return this.transform('scaleY(' + n + ')') 948 }; 949 950 /** 951 * Rotate `n` degrees. 952 * 953 * @param {Number} n 954 * @return {Move} for chaining 955 * @api public 956 */ 957 958 Move.prototype.rotate = function(n){ 959 return this.transform('rotate(' + n + 'deg)'); 960 }; 961 962 /** 963 * Set transition easing function to to `fn` string. 964 * 965 * When: 966 * 967 * - null "ease" is used 968 * - "in" "ease-in" is used 969 * - "out" "ease-out" is used 970 * - "in-out" "ease-in-out" is used 971 * 972 * @param {String} fn 973 * @return {Move} for chaining 974 * @api public 975 */ 976 977 Move.prototype.ease = function(fn){ 978 fn = ease[fn] || fn || 'ease'; 979 return this.setVendorProperty('transition-timing-function', fn); 980 }; 981 982 /** 983 * Set animation properties 984 * 985 * @param {String} name 986 * @param {Object} props 987 * @return {Move} for chaining 988 * @api public 989 */ 990 991 Move.prototype.animate = function(name, props){ 992 for (var i in props){ 993 if (props.hasOwnProperty(i)){ 994 this.setVendorProperty('animation-' + i, props[i]) 995 } 996 } 997 return this.setVendorProperty('animation-name', name); 998 } 999 1000 /** 1001 * Set duration to `n`. 1002 * 1003 * @param {Number|String} n 1004 * @return {Move} for chaining 1005 * @api public 1006 */ 1007 1008 Move.prototype.duration = function(n){ 1009 n = this._duration = 'string' == typeof n 1010 ? parseFloat(n) * 1000 1011 : n; 1012 return this.setVendorProperty('transition-duration', n + 'ms'); 1013 }; 1014 1015 /** 1016 * Delay the animation by `n`. 1017 * 1018 * @param {Number|String} n 1019 * @return {Move} for chaining 1020 * @api public 1021 */ 1022 1023 Move.prototype.delay = function(n){ 1024 n = 'string' == typeof n 1025 ? parseFloat(n) * 1000 1026 : n; 1027 return this.setVendorProperty('transition-delay', n + 'ms'); 1028 }; 1029 1030 /** 1031 * Set `prop` to `val`, deferred until `.end()` is invoked. 1032 * 1033 * @param {String} prop 1034 * @param {String} val 1035 * @return {Move} for chaining 1036 * @api public 1037 */ 1038 1039 Move.prototype.setProperty = function(prop, val){ 1040 this._props[prop] = val; 1041 return this; 1042 }; 1043 1044 /** 1045 * Set a vendor prefixed `prop` with the given `val`. 1046 * 1047 * @param {String} prop 1048 * @param {String} val 1049 * @return {Move} for chaining 1050 * @api public 1051 */ 1052 1053 Move.prototype.setVendorProperty = function(prop, val){ 1054 this.setProperty('-webkit-' + prop, val); 1055 this.setProperty('-moz-' + prop, val); 1056 this.setProperty('-ms-' + prop, val); 1057 this.setProperty('-o-' + prop, val); 1058 return this; 1059 }; 1060 1061 /** 1062 * Set `prop` to `value`, deferred until `.end()` is invoked 1063 * and adds the property to the list of transition props. 1064 * 1065 * @param {String} prop 1066 * @param {String} val 1067 * @return {Move} for chaining 1068 * @api public 1069 */ 1070 1071 Move.prototype.set = function(prop, val){ 1072 if (typeof prop == "object") { 1073 for (var key in prop) { 1074 if (prop.hasOwnProperty(key)) { 1075 this.transition(key); 1076 this._props[key] = prop[key]; 1077 } 1078 } 1079 } else { 1080 this.transition(prop); 1081 this._props[prop] = val; 1082 } 1083 return this; 1084 }; 1085 1086 /** 1087 * Increment `prop` by `val`, deferred until `.end()` is invoked 1088 * and adds the property to the list of transition props. 1089 * 1090 * @param {String} prop 1091 * @param {Number} val 1092 * @return {Move} for chaining 1093 * @api public 1094 */ 1095 1096 Move.prototype.add = function(prop, val){ 1097 if (!style) return; 1098 var self = this; 1099 return this.on('start', function(){ 1100 var curr = parseInt(self.current(prop), 10); 1101 self.set(prop, curr + val + 'px'); 1102 }); 1103 }; 1104 1105 /** 1106 * Decrement `prop` by `val`, deferred until `.end()` is invoked 1107 * and adds the property to the list of transition props. 1108 * 1109 * @param {String} prop 1110 * @param {Number} val 1111 * @return {Move} for chaining 1112 * @api public 1113 */ 1114 1115 Move.prototype.sub = function(prop, val){ 1116 if (!style) return; 1117 var self = this; 1118 return this.on('start', function(){ 1119 var curr = parseInt(self.current(prop), 10); 1120 self.set(prop, curr - val + 'px'); 1121 }); 1122 }; 1123 1124 /** 1125 * Get computed or "current" value of `prop`. 1126 * 1127 * @param {String} prop 1128 * @return {String} 1129 * @api public 1130 */ 1131 1132 Move.prototype.current = function(prop){ 1133 return style(this.el).getPropertyValue(prop); 1134 }; 1135 1136 /** 1137 * Add `prop` to the list of internal transition properties. 1138 * 1139 * @param {String} prop 1140 * @return {Move} for chaining 1141 * @api private 1142 */ 1143 1144 Move.prototype.transition = function(prop){ 1145 if (!this._transitionProps.indexOf(prop)) return this; 1146 this._transitionProps.push(prop); 1147 return this; 1148 }; 1149 1150 /** 1151 * Commit style properties, aka apply them to `el.style`. 1152 * 1153 * @return {Move} for chaining 1154 * @see Move#end() 1155 * @api private 1156 */ 1157 1158 Move.prototype.applyProperties = function(){ 1159 for (var prop in this._props) { 1160 this.el.style.setProperty(prop, this._props[prop], ''); 1161 } 1162 return this; 1163 }; 1164 1165 /** 1166 * Re-select element via `selector`, replacing 1167 * the current element. 1168 * 1169 * @param {String} selector 1170 * @return {Move} for chaining 1171 * @api public 1172 */ 1173 1174 Move.prototype.move = 1175 Move.prototype.select = function(selector){ 1176 this.el = Move.select(selector); 1177 return this; 1178 }; 1179 1180 /** 1181 * Defer the given `fn` until the animation 1182 * is complete. `fn` may be one of the following: 1183 * 1184 * - a function to invoke 1185 * - an instanceof `Move` to call `.end()` 1186 * - nothing, to return a clone of this `Move` instance for chaining 1187 * 1188 * @param {Function|Move} fn 1189 * @return {Move} for chaining 1190 * @api public 1191 */ 1192 1193 Move.prototype.then = function(fn){ 1194 // invoke .end() 1195 if (fn instanceof Move) { 1196 this.on('end', function(){ 1197 fn.end(); 1198 }); 1199 // callback 1200 } else if ('function' == typeof fn) { 1201 this.on('end', fn); 1202 // chain 1203 } else { 1204 var clone = new Move(this.el); 1205 clone._transforms = this._transforms.slice(0); 1206 this.then(clone); 1207 clone.parent = this; 1208 return clone; 1209 } 1210 1211 return this; 1212 }; 1213 1214 /** 1215 * Pop the move context. 1216 * 1217 * @return {Move} parent Move 1218 * @api public 1219 */ 1220 1221 Move.prototype.pop = function(){ 1222 return this.parent; 1223 }; 1224 1225 /** 1226 * Reset duration. 1227 * 1228 * @return {Move} 1229 * @api public 1230 */ 1231 1232 Move.prototype.reset = function(){ 1233 this.el.style.webkitTransitionDuration = 1234 this.el.style.mozTransitionDuration = 1235 this.el.style.msTransitionDuration = 1236 this.el.style.oTransitionDuration = ''; 1237 return this; 1238 }; 1239 1240 /** 1241 * Start animation, optionally calling `fn` when complete. 1242 * 1243 * @param {Function} fn 1244 * @return {Move} for chaining 1245 * @api public 1246 */ 1247 1248 Move.prototype.end = function(fn){ 1249 var self = this; 1250 1251 // emit "start" event 1252 this.emit('start'); 1253 1254 // transforms 1255 if (this._transforms.length) { 1256 this.setVendorProperty('transform', this._transforms.join(' ')); 1257 } 1258 1259 // transition properties 1260 this.setVendorProperty('transition-properties', this._transitionProps.join(', ')); 1261 this.applyProperties(); 1262 1263 // callback given 1264 if (fn) this.then(fn); 1265 1266 // emit "end" when complete 1267 after.once(this.el, function(){ 1268 self.reset(); 1269 self.emit('end'); 1270 }); 1271 1272 return this; 1273 }; 1274 1275 }); 1276 1277 if (typeof exports == "object") { 1278 module.exports = require("move"); 1279 } else if (typeof define == "function" && define.amd) { 1280 define("move", [], function(){ return require("move"); }); 1281 } else { 1282 (this || window)["move"] = require("move"); 1283 } 1284 })()