|
10 | 10 | * - In half-enabled mode, transitions are still used to smooth between frames but no events are
|
11 | 11 | * available to signify the end of transitions. In this case we just use an interval to try to
|
12 | 12 | * sync the javascript CSS updates with the end of the CSS transitions - but this *can* get out
|
13 |
| - * of sync slightly which leads to |
| 13 | + * of sync slightly which leads to tearing in the animation. Fortunately this mode is unlikely |
| 14 | + * to be executed. |
14 | 15 | * - In fallback mode, we simply sample at a higher framerate to compensate for the lack of browser
|
15 | 16 | * transition support.
|
16 | 17 | *
|
|
20 | 21 | * - a sampling rate for the animation when running in CSS-enabled browsers
|
21 | 22 | * - a fallback sampling rate when transition smoothing is not available
|
22 | 23 | *
|
| 24 | + * After construction, call addElements() to append DOM elements under the control of the TransitionInterval's |
| 25 | + * animation timer. These need to be registered in order to apply the correct CSS attributes necessary for |
| 26 | + * transition timing on the elements. |
| 27 | + * |
23 | 28 | * @requires jcparallax.js
|
24 | 29 | */
|
25 | 30 | (function($) {
|
26 | 31 |
|
27 |
| -jcparallax.TransitionInterval = function(cb, framerate, doNotStart) |
| 32 | +jcparallax.TransitionInterval = function(cb, framerate, fbFramerate, extraCssAnimCheckCb) |
28 | 33 | {
|
29 |
| - this.framerate = framerate; |
30 |
| - this.callback = cb; |
31 |
| - this.frameCount = -1; |
| 34 | + this.elements = jQuery([]); |
| 35 | + this.setFramerates(framerate, fbFramerate, extraCssAnimCheckCb); |
32 | 36 |
|
33 |
| - if (!doNotStart) this.start(); |
| 37 | + this.callback = cb; |
| 38 | + this.frameCount = 0; |
34 | 39 | };
|
35 | 40 |
|
36 | 41 | $.extend(jcparallax.TransitionInterval.prototype, {
|
37 | 42 |
|
38 |
| - interval : null, |
| 43 | + _running : false, |
| 44 | + |
| 45 | + timeout : null, // frame timeout reference (fallback mode) |
| 46 | + update : null, // underlying registered timer update callback |
39 | 47 |
|
40 | 48 | start : function()
|
41 | 49 | {
|
42 | 50 | // ignore if already running
|
43 |
| - if (this.interval) { |
| 51 | + if (this._running) { |
44 | 52 | return;
|
45 | 53 | }
|
46 | 54 |
|
47 |
| - var that = this, |
48 |
| - update = function() { |
49 |
| - ++that.frameCount; |
50 |
| - that.callback.call(that); |
| 55 | + var that = this; |
| 56 | + |
| 57 | + if (jcparallax.support.transitionEndEvent) { |
| 58 | + this.update = function() { |
| 59 | + // if callback returns to flag no movement, check again at our frame interval |
| 60 | + if (!that.callback.call(that)) { |
| 61 | + clearTimeout( that.timeout ); |
| 62 | + that.timeout = setTimeout(function() { |
| 63 | + that.timeout = null; |
| 64 | + that.update(); |
| 65 | + }, that.framerate); |
| 66 | + } else { |
| 67 | + |
| 68 | + // this check is placed here to failsafe in the event that browser rendering stutters, |
| 69 | + // resulting in the transition end event never being called and the animation failing |
| 70 | + // to restart. |
| 71 | + clearTimeout( that.timeout ); |
| 72 | + that.timeout = setTimeout(function() { |
| 73 | + that.timeout = null; |
| 74 | + that.update(); |
| 75 | + }, that.framerate * 2); |
| 76 | + |
| 77 | + ++that.frameCount; |
| 78 | + } |
51 | 79 | };
|
52 | 80 |
|
53 |
| - update(); // run to first frame |
| 81 | + // bind to the first element, we only need it to run once since all framerates are the same |
| 82 | + this.elements.on(jcparallax.support.transitionEndEvent, that.update); |
| 83 | + } else { |
| 84 | + var supported = jcparallax.support.transitions && (!this.useFallbackCheckCb || (this.useFallbackCheckCb && this.useFallbackCheckCb())); |
| 85 | + |
| 86 | + this.update = function() { |
| 87 | + that.callback.call(that); |
| 88 | + that.timeout = setTimeout(that.update, supported ? that.framerate : that.fbFramerate); |
54 | 89 |
|
55 |
| - this.interval = setInterval(update, this.framerate); |
| 90 | + ++that.frameCount; |
| 91 | + }; |
| 92 | + this.timeout = setTimeout(this.update, supported ? this.framerate : this.fbFramerate); |
| 93 | + } |
| 94 | + this._running = true; |
| 95 | + |
| 96 | + this.update(); // run to first frame |
56 | 97 | },
|
57 | 98 |
|
58 | 99 | stop : function()
|
59 | 100 | {
|
60 |
| - clearInterval( this.interval ); |
61 |
| - this.interval = null; |
| 101 | + if (this._running) { |
| 102 | + if (jcparallax.support.transitionEndEvent) { |
| 103 | + this.elements.off(jcparallax.support.transitionEndEvent, this.update); |
| 104 | + } else { |
| 105 | + clearTimeout( this.timeout ); |
| 106 | + this.timeout = null; |
| 107 | + } |
| 108 | + this._running = false; |
| 109 | + } |
| 110 | + }, |
| 111 | + |
| 112 | + setFramerates : function(cssFramerate, fallbackFramerate, extraCssAnimCheckCb) |
| 113 | + { |
| 114 | + this.framerate = cssFramerate; |
| 115 | + this.fbFramerate = fallbackFramerate; |
| 116 | + this.useFallbackCheckCb = extraCssAnimCheckCb; |
| 117 | + this._applyCss(); |
| 118 | + }, |
| 119 | + |
| 120 | + addElements : function(els) |
| 121 | + { |
| 122 | + if ($.isArray(els)) { |
| 123 | + this.elements.pushStack(els); |
| 124 | + } else { |
| 125 | + this.elements = this.elements.add(els); |
| 126 | + } |
| 127 | + this._applyCss(); |
| 128 | + }, |
| 129 | + |
| 130 | + _applyCss : function() |
| 131 | + { |
| 132 | + var that = this, |
| 133 | + cssFramerate = (this.framerate / 1000) + 's'; |
| 134 | + |
| 135 | + // set transition-duration for CSS sample tweening |
| 136 | + $.each(jcparallax.cssDomPrefixes, function(i, prefix) { |
| 137 | + that.elements.css(prefix + 'transition-duration', cssFramerate); |
| 138 | + }); |
| 139 | + this.elements.css('transition-duration', cssFramerate); |
62 | 140 | }
|
63 | 141 | });
|
64 | 142 |
|
|
0 commit comments