admin管理员组文章数量:1394544
Using setInterval or RequestAnimationFrame, I'd like to get the progression value from lerping between X and Y. Assuming that X is 0 and Y is 1, I want to have 0 when it starts, 0.5 in the half, and 1 when finished.
I'd like this to happen in a given timeframe, let's say 5 seconds. Meaning that the half value 0.5 would happen when the setInterval/RequestAnimationFrame reaches 2.5seconds.
Finally, I'd like it to pingPong, so when it reaches the 5 seconds the values are decreasing and not increasing, such as 0.9, 0.8, 0.7, etc and then start again from 0, 0.1, 0.2...
Here is my code so far:
/*
function lerp(start, end, time) {
return start * (1.0 - time) + end * time;
}
*/
function lerp (start, end, amt){
return (1-amt)*start+amt*end;
}
function repeat(t, len) {
console.log('t: ' + t + ', len: ' + len);
return t - Math.floor(t / len) * len;
}
function pingPong(t, len) {
t = repeat(t, len * 2);
return len - Math.abs(t-len);
}
var transitionDuration = 1;
var startTime = Date.now()/1000;
var startPos = 0;
var endPos = 1;
setInterval(function () {
var currentTime = Date.now()/1000;
console.log('currentTime:', currentTime);
var adjustedTime = pingPong(currentTime-startTime, transitionDuration);
var x = lerp(startPos, endPos, adjustedTime);
console.log(Math.abs(x.toFixed(2)));
}, 100);
How can I do this?
Using setInterval or RequestAnimationFrame, I'd like to get the progression value from lerping between X and Y. Assuming that X is 0 and Y is 1, I want to have 0 when it starts, 0.5 in the half, and 1 when finished.
I'd like this to happen in a given timeframe, let's say 5 seconds. Meaning that the half value 0.5 would happen when the setInterval/RequestAnimationFrame reaches 2.5seconds.
Finally, I'd like it to pingPong, so when it reaches the 5 seconds the values are decreasing and not increasing, such as 0.9, 0.8, 0.7, etc and then start again from 0, 0.1, 0.2...
Here is my code so far:
/*
function lerp(start, end, time) {
return start * (1.0 - time) + end * time;
}
*/
function lerp (start, end, amt){
return (1-amt)*start+amt*end;
}
function repeat(t, len) {
console.log('t: ' + t + ', len: ' + len);
return t - Math.floor(t / len) * len;
}
function pingPong(t, len) {
t = repeat(t, len * 2);
return len - Math.abs(t-len);
}
var transitionDuration = 1;
var startTime = Date.now()/1000;
var startPos = 0;
var endPos = 1;
setInterval(function () {
var currentTime = Date.now()/1000;
console.log('currentTime:', currentTime);
var adjustedTime = pingPong(currentTime-startTime, transitionDuration);
var x = lerp(startPos, endPos, adjustedTime);
console.log(Math.abs(x.toFixed(2)));
}, 100);
How can I do this?
Share Improve this question edited Jan 29, 2020 at 8:57 halfer 20.4k19 gold badges109 silver badges202 bronze badges asked Nov 25, 2015 at 12:10 punkbitpunkbit 7,71710 gold badges57 silver badges95 bronze badges 3- 1 Did you try something? Where did you got stuck? – Aramil Rey Commented Nov 25, 2015 at 12:15
- 1 To elaborate on what @AramilRey asked; what have you tried? What research have you done? Can you provide snippets to demonstrate that you've actually tried to solve the problem yourself? (A simple google search would have provided you with the knowledge needed to tackle this question.) You shouldn't be relying on the SO munity to do your work for you. – arkon Commented Jan 23, 2016 at 18:33
- jsbin./picuwe/2/edit?js,output – punkbit Commented Jan 25, 2016 at 12:32
2 Answers
Reset to default 5The basic formula for linear interpolation would be something like
InterpolatedValue = X*t + Y*(1-t)
where X
and Y
are the values to be interpolated between and t
is a parameter between 0
and 1
determining the degree of interpolation; 0
yields X
and 1
yields Y
. Furthermore, you would like to have some periodic movement with a period length of 5
, alternating the direction of interpolation; this can be achieved as follows. If t
is a nonnegative number growing over time, calculate
t' = t - t / 10
to remove all previous periods which have occured and
t'' = t' : t' in [0,5)
5 - t' : t' in [5,10)
and afterwards set
t''' = t' / 5
to normalize the parameter into [0,1]
and use the basic interpolation formula from the beginning.
Note that linear interpolation and various other methods are collected here.
From your description, at any given frame there are 6 pieces of state:
- Start time of current lerp
- Lerp timespan
- Current direction
- Current time
- Start value
- End value
From these you can calculate the required progress value, say:
function progressValue(startTime, lerpSpanSeconds, dir,
currentTime X, Y, dir, currentTime) {
// lerp
return 0.42;
}
For requestAnimationFrame, you need a simple callback to pass in. That is, the function has to know everything it needs except what it can acquire when it runs. Here, when it runs it just needs to get the current time and work the rest out from there.
function animableThing() {
var startTime = 7;
var lerpSpanSeconds = 3;
var dir = +1;
var X = 0;
var Y = 1;
var currentTime = GetCurrentUnicornTime();
var thingToAnimate = document.getElementById('myAnimableElement');
var progress = progressValue(startTime, lerpSpanSeconds, dir,
currentTime, X, Y, dir, currentTime);
// reverse when we hit the end
if(progress > Y) {
dir *= -1;
startTime = currentTime;
progress = Y;
}
DrawAnimationThing(thingToAnimate, progress);
// continue the animation
window.requestAnimationFrame(animableThing);
}
But there's a problem; if you want to be able to set up the animation using values from the script or inputs from the screen, or up-to-date information about the elements on the screen, then you need to be able to make an animableThing
callback fresh when you have new values. Behold, the mother:
function MotherOfAnimableThings(startTime, lerpSpanSeconds, dir, X, Y,
thingToAnimate)
{
// Passed in variables have scope outside the animableThing, these
// will be private to the animableThing function.
// Consider defaulting or validation here
// Construct a new function freshly each time the Mother is called,
// and return it to the caller. Note that we assign a variable here
// so that we can re-call RequestAnimationFrame to continue the loop
var callback = (function() {
var currentTime = GetCurrentUnicornTime();
var progress = progressValue(startTime, lerpSpanSeconds, dir,
currentTime, X, Y, dir, currentTime);
// reverse when we hit the end
if(progress > Y) {
dir *= -1;
startTime = currentTime;
progress = Y;
}
DrawAnimationThing(thingToAnimate, progress);
window.requestAnimationFrame(callback);
});
return callback;
}
We could go further, and make this general for other types of thing by letting the caller pass in a progressValue function to call, or in fact a callback, so that you could take any element, Draw function and setup function and make a thing that animates, but this is a reasonable starting point.
With the above, we just need to call Mother to create an animableThing
function and call RequestAnimationFrame with that. From then on, it calls RequestAnimationFrame internally to continue the cycle.
Now, having done that, you will want to make it stop, so add in a variable in the callback which it can check, so that you can do
var animableThing = MotherOfAnimableThings(...);
window.requestAnimationFrame(animableThing);
// ... later
animableThing.stop = true; // it should stop on the next frame
本文标签: javascriptHow to lerp back and forth between two values XY in a loopStack Overflow
版权声明:本文标题:javascript - How to lerp back and forth between two values X,Y in a loop? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744100785a2590863.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论