From 2d925f8fa09f6f879b7f5e5d451bd0d113e6638d Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Fri, 15 Aug 2014 12:29:17 -0400 Subject: [PATCH 1/6] Always use CSS transitions when available This makes a huge difference in perceptual animation quality from ~10-20 FPS on a 1.7Ghz Core i7 to 60FPS in Chrome, Safari, Firefox, IE11. --- source/js/Core/Core/VMM.Browser.js | 34 ++++++++++++++++++++++++++---- source/js/Core/Core/VMM.Library.js | 10 ++++----- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/source/js/Core/Core/VMM.Browser.js b/source/js/Core/Core/VMM.Browser.js index d26940a..a04aaf0 100644 --- a/source/js/Core/Core/VMM.Browser.js +++ b/source/js/Core/Core/VMM.Browser.js @@ -12,12 +12,17 @@ if(typeof VMM != 'undefined' && typeof VMM.Browser == 'undefined') { this.OS = this.searchString(this.dataOS) || "an unknown OS"; this.device = this.searchDevice(navigator.userAgent); this.orientation = this.searchOrientation(window.orientation); + this.features = { + css: { + transitions: this.cssTransitionSupport() + } + }; }, searchOrientation: function(orientation) { var orient = ""; - if ( orientation == 0 || orientation == 180) { + if ( orientation == 0 || orientation == 180) { orient = "portrait"; - } else if ( orientation == 90 || orientation == -90) { + } else if ( orientation == 90 || orientation == -90) { orient = "landscape"; } else { orient = "normal"; @@ -155,8 +160,29 @@ if(typeof VMM != 'undefined' && typeof VMM.Browser == 'undefined') { subString: "Linux", identity: "Linux" } - ] + ], + cssTransitionSupport: function () { + // See https://gist.github.com/jackfuchs/556448 + var b = document.body || document.documentElement, + s = b.style, + p = 'transition'; + + if (typeof s[p] == 'string') { + return true; + } + + // Tests for vendor specific prop + var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms']; + p = p.charAt(0).toUpperCase() + p.substr(1); + + for (var i=0; i Date: Fri, 15 Aug 2014 17:16:29 -0400 Subject: [PATCH 2/6] Use the slow jQuery path to animate scrollTop This might be worth either splitting animate() into one for DOM properties and one for pure-CSS or replacing the scrollTop animation with something like margin or, better yet, transform. --- source/js/Core/Core/VMM.Library.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/js/Core/Core/VMM.Library.js b/source/js/Core/Core/VMM.Library.js index 0031626b..ceb1809 100644 --- a/source/js/Core/Core/VMM.Library.js +++ b/source/js/Core/Core/VMM.Library.js @@ -427,9 +427,10 @@ if(typeof VMM != 'undefined') { jQuery(element).stop(); } }, - + + // TODO: Consider removing this as it's referenced by one commented line delay_animate: function(delay, element, duration, ease, att, callback_function) { - if (VMM.Browser.features.css.transitions) { + if (VMM.Browser.features.css.transitions && !('scrollTop' in _att)) { var _tdd = Math.round((duration/1500)*10)/10, __duration = _tdd + 's'; @@ -478,9 +479,7 @@ if(typeof VMM != 'undefined') { _att = {opacity: 0} } - - if (VMM.Browser.features.css.transitions) { - + if (VMM.Browser.features.css.transitions && !('scrollTop' in _att)) { var _tdd = Math.round((_duration/1500)*10)/10, __duration = _tdd + 's'; From facd6fa7db1ea7f88e517f93dc564cbcfea95aa6 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Fri, 15 Aug 2014 17:55:23 -0400 Subject: [PATCH 3/6] Fix VMM.Library.prop and VMM.Library.attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prop() previously had a version check for jQuery’s prop() function which failed, causing it to never return values for e.g. scrollHeight. attribute() previously always hit the setter path because it didn’t check for value being undefined so it always called jQuery using the two argument form. --- source/js/Core/Core/VMM.Library.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/source/js/Core/Core/VMM.Library.js b/source/js/Core/Core/VMM.Library.js index ceb1809..0191c46 100644 --- a/source/js/Core/Core/VMM.Library.js +++ b/source/js/Core/Core/VMM.Library.js @@ -280,28 +280,27 @@ if(typeof VMM != 'undefined') { } } }, - + prop: function(element, aName, value) { - if (typeof jQuery == 'undefined' || !/[1-9]\.[3-9].[1-9]/.test(jQuery.fn.jquery)) { - VMM.Lib.attribute(element, aName, value); + if (typeof jQuery == 'undefined' || !('prop' in jQuery.fn)) { + return VMM.Lib.attribute(element, aName, value); + } else if (typeof value != 'undefined') { + return jQuery(element).prop(aName, value); } else { - jQuery(element).prop(aName, value); + return jQuery(element).prop(aName); } }, - + attribute: function(element, aName, value) { - - if (value != null && value != "") { - if( typeof( jQuery ) != 'undefined' ){ - jQuery(element).attr(aName, value); - } - } else { - if( typeof( jQuery ) != 'undefined' ){ + if (typeof(jQuery) != 'undefined') { + if (typeof(value) != 'undefined' && value != null && value != "") { + return jQuery(element).attr(aName, value); + } else { return jQuery(element).attr(aName); } } }, - + visible: function(element, show) { if (show != null) { if( typeof( jQuery ) != 'undefined' ){ From 5c4edc9502d282da0b2b5bd1cdec95764dcfa53c Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Fri, 15 Aug 2014 18:05:26 -0400 Subject: [PATCH 4/6] =?UTF-8?q?VMM.Library.animate():=20don=E2=80=99t=20ch?= =?UTF-8?q?urn=20object=20copies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids declaring an object unless we didn’t receive one --- source/js/Core/Core/VMM.Library.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/js/Core/Core/VMM.Library.js b/source/js/Core/Core/VMM.Library.js index 0191c46..ebcb6c2 100644 --- a/source/js/Core/Core/VMM.Library.js +++ b/source/js/Core/Core/VMM.Library.js @@ -452,8 +452,8 @@ if(typeof VMM != 'undefined') { var _ease = "easein", _que = false, _duration = 1000, - _att = {}; - + _att; + if (duration != null) { if (duration < 1) { _duration = 1; @@ -473,9 +473,9 @@ if(typeof VMM != 'undefined') { if (att != null) { - _att = att + _att = att; } else { - _att = {opacity: 0} + _att = {opacity: 0}; } if (VMM.Browser.features.css.transitions && !('scrollTop' in _att)) { From cadd7574692e4bba6c7188e717947c3848f8cc56 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Fri, 22 Aug 2014 15:59:33 -0400 Subject: [PATCH 5/6] placeholder for future optimization --- source/js/Core/Slider/VMM.Slider.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/js/Core/Slider/VMM.Slider.js b/source/js/Core/Slider/VMM.Slider.js index 8b49267..fcb8c4d 100644 --- a/source/js/Core/Slider/VMM.Slider.js +++ b/source/js/Core/Slider/VMM.Slider.js @@ -689,6 +689,8 @@ if(typeof VMM != 'undefined' && typeof VMM.Slider == 'undefined') { } else { VMM.Lib.css(layout, "overflow-y", "hidden" ); var scroll_height = 0; + + // FIXME: Chrome cannot optimize this try/catch block, which appears to be unnecessary – see https://github.com/NUKnightLab/TimelineJS/pull/681#issuecomment-52365420 try { scroll_height = VMM.Lib.prop(layout, "scrollHeight"); VMM.Lib.animate(layout, _duration, _ease, {scrollTop: scroll_height - VMM.Lib.height(layout) }); From cabe8f42e63151a8ca5a6d47a5751e28a3f97fd9 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Fri, 22 Aug 2014 16:01:54 -0400 Subject: [PATCH 6/6] =?UTF-8?q?Allow=20Chrome=20to=20optimize=20for?= =?UTF-8?q?=E2=80=A6in=20loop=20in=20animate()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Making this a local variable allows Chrome to optimize the loop, which is called frequently while scrolling --- source/js/Core/Core/VMM.Library.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/js/Core/Core/VMM.Library.js b/source/js/Core/Core/VMM.Library.js index ebcb6c2..e684115 100644 --- a/source/js/Core/Core/VMM.Library.js +++ b/source/js/Core/Core/VMM.Library.js @@ -484,7 +484,7 @@ if(typeof VMM != 'undefined') { _ease = " cubic-bezier(0.33, 0.66, 0.66, 1)"; //_ease = " ease-in-out"; - for (x in _att) { + for (var x in _att) { if (Object.prototype.hasOwnProperty.call(_att, x)) { trace(x + " to " + _att[x]); VMM.Lib.css(element, '-webkit-transition', x + ' ' + __duration + _ease);