Update slideIn and slideOut to use requestAnimationFrame

For smoother animations.
This commit is contained in:
JC Brand 2017-12-19 13:16:19 +00:00
parent 7ae735c4d0
commit 349d097e0a

View File

@ -73,16 +73,6 @@
}); });
}; };
function calculateSlideStep (height) {
if (height > 100) {
return 10;
} else if (height > 50) {
return 5;
} else {
return 1;
}
}
function calculateElementHeight (el) { function calculateElementHeight (el) {
/* Return the height of the passed in DOM element, /* Return the height of the passed in DOM element,
* based on the heights of its children. * based on the heights of its children.
@ -186,7 +176,7 @@
return _.includes(el.classList, className); return _.includes(el.classList, className);
}; };
u.slideOut = function (el, duration=1000) { u.slideOut = function (el, duration=250) {
/* Shows/expands an element by sliding it out of itself /* Shows/expands an element by sliding it out of itself
* *
* Parameters: * Parameters:
@ -200,10 +190,10 @@
reject(new Error(err)); reject(new Error(err));
return; return;
} }
let interval_marker = el.getAttribute('data-slider-marker'); const marker = el.getAttribute('data-slider-marker');
if (interval_marker) { if (marker) {
el.removeAttribute('data-slider-marker'); el.removeAttribute('data-slider-marker');
window.clearInterval(interval_marker); window.cancelAnimationFrame(marker);
} }
const end_height = calculateElementHeight(el); const end_height = calculateElementHeight(el);
if (window.converse_disable_effects) { // Effects are disabled (for tests) if (window.converse_disable_effects) { // Effects are disabled (for tests)
@ -217,34 +207,40 @@
return; return;
} }
const step = calculateSlideStep(end_height), const steps = duration/17; // We assume 17ms per animation which is ~60FPS
interval = end_height/duration*step; let height = 0;
let h = 0;
interval_marker = window.setInterval(function () { function draw () {
h += step; height += end_height/steps;
if (h < end_height) { if (height < end_height) {
el.style.height = h + 'px'; el.style.height = height + 'px';
el.setAttribute(
'data-slider-marker',
window.requestAnimationFrame(draw)
);
} else { } else {
// We recalculate the height to work around an apparent // We recalculate the height to work around an apparent
// browser bug where browsers don't know the correct // browser bug where browsers don't know the correct
// offsetHeight beforehand. // offsetHeight beforehand.
el.removeAttribute('data-slider-marker');
el.style.height = calculateElementHeight(el) + 'px'; el.style.height = calculateElementHeight(el) + 'px';
el.style.overflow = ""; el.style.overflow = "";
el.style.height = ""; el.style.height = "";
window.clearInterval(interval_marker);
resolve(); resolve();
} }
}, interval); }
el.style.height = '0'; el.style.height = '0';
el.style.overflow = 'hidden'; el.style.overflow = 'hidden';
el.classList.remove('hidden'); el.classList.remove('hidden');
el.classList.remove('collapsed'); el.classList.remove('collapsed');
el.setAttribute('data-slider-marker', interval_marker); el.setAttribute(
'data-slider-marker',
window.requestAnimationFrame(draw)
);
}); });
}; };
u.slideIn = function (el, duration=800) { u.slideIn = function (el, duration=250) {
/* Hides/collapses an element by sliding it into itself. */ /* Hides/collapses an element by sliding it into itself. */
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (_.isNil(el)) { if (_.isNil(el)) {
@ -258,30 +254,36 @@
el.style.height = ""; el.style.height = "";
return resolve(); return resolve();
} }
let interval_marker = el.getAttribute('data-slider-marker'); const marker = el.getAttribute('data-slider-marker');
if (interval_marker) { if (marker) {
el.removeAttribute('data-slider-marker'); el.removeAttribute('data-slider-marker');
window.clearInterval(interval_marker); window.cancelAnimationFrame(marker);
} }
let h = el.offsetHeight; const original_height = el.offsetHeight,
const step = calculateSlideStep(h), steps = duration/17; // We assume 17ms per animation which is ~60FPS
interval = h/duration*step; let height = original_height;
el.style.overflow = 'hidden'; el.style.overflow = 'hidden';
interval_marker = window.setInterval(function () { function draw () {
h -= step; height -= original_height/steps;
if (h > 0) { if (height > 0) {
el.style.height = h + 'px'; el.style.height = height + 'px';
el.setAttribute(
'data-slider-marker',
window.requestAnimationFrame(draw)
);
} else { } else {
el.removeAttribute('data-slider-marker'); el.removeAttribute('data-slider-marker');
window.clearInterval(interval_marker);
el.classList.add('collapsed'); el.classList.add('collapsed');
el.style.height = ""; el.style.height = "";
resolve(); resolve();
} }
}, interval); }
el.setAttribute('data-slider-marker', interval_marker); el.setAttribute(
'data-slider-marker',
window.requestAnimationFrame(draw)
);
}); });
}; };