Although I am not well-versed in three.js, the concept you are inquiring about can be applied to various other areas. Here is a general solution that I will outline for you. To begin with, here is a proof of concept:
https://jsfiddle.net/ibowankenobi/u4xwnLam/4/
I will start by declaring the necessary global variables and encapsulating them as needed:
var rotation = 0;
var bar = document.getElementById("bar");
var container = document.getElementById("container");
For the demonstration without three.js, a container and an object to rotate are required. In your context, the object being rotated would correspond to etaj1.rotation.z
.
The initial step involves creating a function that maps values from 0-1 to 0-1 non-linearly through interpolations. The commonly used interpolation method tends to provide a "slow in slow out" effect:
function slowInSlowOut(t){
if(2*t<<0){
return 4*(t-1)*(t-1)*(t-1)+1;
} else {
return 4*t*t*t;
}
}
To further utilize this function, another animation function needs to be written:
function changeSpeed(obj,newSpeed){
var oldSpeed = obj.__oldSpeed || 0;
var startTime;
newSpeed = newSpeed || 0;
obj.__currentFrame && window.cancelAnimationFrame(obj.__currentFrame);
obj.__currentFrame = window.requestAnimationFrame(anim);
function anim(t){
startTime = startTime || t;
var elapsed = t - startTime,
parametric = slowInSlowOut(elapsed/2000);
if(parametric>=1){
obj.__oldSpeed = newSpeed;
} else {
obj.__oldSpeed = newSpeed + (oldSpeed-newSpeed) * (1-parametric);
obj.__currentFrame = window.requestAnimationFrame(anim);
}
}
}
This function enables an object to have a custom property named __oldSpeed
. The parameter newSpeed
signifies degrees per 17ms intervals. In your case, the object would be represented by etaj1
.
In order to continuously monitor the __oldSpeed
property of the object and take relevant action, a third function is developed:
function animate(obj){
rotation += (obj.__oldSpeed || 0);
rotation = rotation % 360;
obj.style.transform = "rotate("+rotation+"deg)";
window.requestAnimationFrame(function(){animate(obj)});
}
Here, the object refers to etaj1
and the rotation corresponds to etaj1.rotation.z
. Using DOM manipulation demands the use of styles, which can be adapted according to your specific scenario.
To trigger the animation, it must be initiated:
window.requestAnimationFrame(function(){animate(bar)});
Subsequently, event listeners can be added as per your specifications:
container.addEventListener("mousedown",function(){changeSpeed(bar,0)},false);
container.addEventListener("mouseup",function(){changeSpeed(bar,12)},false);
An initial speed value is assigned to kickstart the process:
changeSpeed(bar,12);
This setup should provide you with a starting point on how to achieve the desired outcome. Users employing different technology stacks may also adapt this approach to suit their requirements.
PS:
If there is a need for a delay, slight modifications can be made to the changeSpeed
function:
function changeSpeed(obj,newSpeed,delay){
delay = delay || 0;
var oldSpeed = obj.__oldSpeed || 0;
var startTime;
newSpeed = newSpeed || 0;
obj.__currentFrame && window.cancelAnimationFrame(obj.__currentFrame);
obj.__currentFrame = window.requestAnimationFrame(anim);
function anim(t){
startTime = startTime || t;
var elapsed = t - startTime;
if(elapsed < delay) {
return obj.__currentFrame = window.requestAnimationFrame(anim);
}
var parametric = slowInSlowOut((elapsed-delay)/2000);
if(parametric>=1){
obj.__oldSpeed = newSpeed;
} else {
obj.__oldSpeed = newSpeed + (oldSpeed-newSpeed) * (1-parametric);
obj.__currentFrame = window.requestAnimationFrame(anim);
}
}
}
A sample implementation with a 2-second delay can be found in this fiddle:
https://jsfiddle.net/ibowankenobi/u4xwnLam/10/