Allow easing functions
Please allow easing functions. For instance I use this set:
function B1(t) { return t*t*t }
function B2(t) { return 3*t*t*(1-t) }
function B3(t) { return 3*t*(1-t)*(1-t) }
function B4(t) { return (1-t)*(1-t)*(1-t) }
export function getBezier(percent,x2,y2,x3,y3) {
var pos = {x:0, y:0};
pos.x = 0*B1(percent) + x2*B2(percent) + x3*B3(percent) + 1*B4(percent);
pos.y = 0*B1(percent) + y2*B2(percent) + y3*B3(percent) + 1*B4(percent);
return pos;
}
Then I calculate timing and values. I actually had my own scroll function, but came to yours and loved it. Just missing these easing functions.
This was my scroll to function:
export const scrollIntoView = async function(domel, {duration=500, align='top', behavior='smooth', needed=0.5, smooth='ease'}={}) {
// domel can be element or string, if string starts with space, dot, hash then it users querySelector
// only does Y right now
// duration - ms
// align - top, none
// bheavior - smooth, instant
// needed - is the if needed part. portion of the domel that should be visible. with respect to align. its a decimal percent. so align=top and portion=0.5 means top 50% shoudl be visible at least. if it is not then scrolling is done
// smooth - css smoothing - accepts: ease, linear, ease-in, ease-out, ease-in-out, or array of 4 numbers
if (!domel) throw new Error('scrollIntoView: domel does not exist');
if (typeof(domel) == 'string') {
let selector = domel;
let method = [' ', '.', '#'].includes(domel[0]) ? 'querySelector' : 'getElementById';
domel = await retry(async () => {
let domel = document[method](selector);
if (!domel) throw new Error('retry');
return domel;
}, { interval:50, sec:1 });
}
if (!Array.isArray(smooth)) {
let special_smooth = {
ease: [.25,.1,.25,1],
linear: [0,0,1,1],
'ease-in': [.42,0,1,1],
'ease-out': [0,0,.58,1],
'ease-in-out': [.42,0,.58,1]
};
smooth = special_smooth[smooth];
}
let scroll = getScroll();
let domel_ytop = parseInt(getElementScrollPosition(domel).y);
if (align === 'top') {
if (behavior === 'smooth') {
let end = domel_ytop;
let start = scroll.y;
let steps = [];
let lasttime = -10000000;
const MIN_TIME_GAP = 10; // ms
for (let i=0; i<101; i++) {
let scale = getBezier((100-i)/100, ...smooth);
let cur_val = Math.round((scale.y * (end - start)) + start);
if (!steps.length || steps[steps.length-1].val !== cur_val) {
let cur_time = Math.round(scale.x * duration);
if (cur_time - lasttime >= MIN_TIME_GAP) {
lasttime = cur_time;
steps.push({time:cur_time,val:cur_val});
}
}
}
// console.log('steps:', steps);
// let timeouts = [];
steps.forEach(step => {
// timeouts.push( setTimeout(()=>window.scrollTo(scroll.x, step.val), step.time) );
setTimeout(()=>window.scrollTo(scroll.x, step.val), step.time);
});
} else {
// behavior == 'instant'
window.scrollTo(scroll.x, domel_ytop);
}
}
}
Other features in my function that might be cool here are:
- Pass in element id or querySelector string
- If passed in string, then it will keep trying every 50ms to getElementById/querySelector - and only after then it will continue - maybe we can extend this to
ref. if ref is null then wait till it becomes non-null.
- If passed in string, then it will keep trying every 50ms to getElementById/querySelector - and only after then it will continue - maybe we can extend this to
Actually I already added the ease . Could you check that with the latest demo page?
@Noitidart Thanks for your advices. I will try to imeplement it later but let's make sure the function is simple and easy to use. I will backlog this issue now.
Thanks @flyingant ! The equations above allow us to use it just like we use CSS transitions. So it offers not only ease, but familiarity. We can specify: linear, ease, ease-in, ease-out, ease-in-out. Or supply an array, this is the same way you provide a CSS cubic-bezier. So we can use regular CSS tools in the browser to get a easing function like http://cubic-bezier.com/#.17,.67,.83,.67 - and I can plug this (.17,.67,.83,.67) straight into the function as an array.