CSS transform rotate always clockwise without exceeding 360 degrees - javascript

Im designing a clock, for the "hands" Im using a combination of JS and CSS to make an smooth animation, converting second, minutes and hours to its corresponding degree in the analog clock:
function clock() {
var t = moment(),
s = t.seconds() * 6,
a = t.minutes() * 6,
o = t.hours() % 12 / 12 * 360 + (a / 12);
$(".hour").css("transform", "rotate(" + o + "deg)");
$(".minute").css("transform", "rotate(" + a + "deg)");
$(".second").css("transform", "rotate(" + s + "deg)");
}
setInterval(clock, 1000);
The problem is, after getting to 360 degrees I don't want the variable to keep increasing forever, I just return to 0 and start again, but, CSS makes the hands turn anticlockwise making an undesired effect.
Example
I was thinking about removing the transition property using JS when im about to go from 360 to 0 and then put it in again, this may be a solution, but I wonder if there is a cleaner way.

It can't be done natively. A transition from 356 to 2 degrees will always go counter clockwise. If you don't mind the visible tick from 356 to 2 degrees, just remove the transition. But there's no reason to do that. Try to exploit the fact that rotate can take any sane value, also above 360 degrees. So instead of returning to 0, just let the clock continue to increase the value "endlessly" (the highest int value in js is 9007199254740991, so you'll have to refresh the browser after a few million years... :)).
You can keep track of rotations so far in a separate counter object outside the setInterval callback like this:
var counter = {
s: 0,
a: 0,
o: 0
};
var previous = null;
Then you want to store all values from the previous iteration somewhere, and compare the current values to the previous ones. If necessary, increase the appropriate counter by one.
if(previous){
if(s < previous.s){
counter.s += 1;
}
if(a < previous.a){
counter.a += 1;
}
if(o < previous.o){
counter.o += 1;
}
}
previous = {
s: s,
a: a,
o: o
};
Then just set the multiplied degree value in your inline css. This way you will still have access to the pure values of s etc in case you need those for something.
$(".second").css("transform", "rotate(" + (s + 360 * counter.s) + "deg)");
Working fiddle: https://jsfiddle.net/dannyjolie/tccroo1q/6/

Related

Javascript: Set variable to either 1 or -1

I'm trying to get an object that moves in a different direction when you click on it, and each time you click on it it goes faster. I have it almost functioning, but I can't get the program to exclude 0 or do only -1 or 1; I can only do a random number between -1 and 1. This means that if it hits zero, it can't progress.
(The following code is built with a Javascript engine called "Crafty". Non-javascript parts are commented as best as I can.)
Crafty.init(400,320, document.getElementById('game')); // Creates canvas
// Create variables
var speed = 10;
var min = -1;
var max = 1;
// Create a 32px by 32px red box
var square = Crafty.e('2D, Canvas, Color, Mouse, Motion')
.attr({x: 50, y: 50, w: 32, h: 32})
.color('red')
// When the red box is clicked, move it in a random direction. Make it go faster each time.
.bind('Click', function(MouseEvent){
speed *= 2;
var vel = square.velocity();
var direction = ((Math.random() * (max - min)) + min);
vel.x;
vel.y;
vel.x = (speed *= direction);
vel.y = (speed *= direction);
});
Change to this line
var direction = (Math.random()) > .5 ? 1 : -1;
It really comes down to this line:
var direction = ((Math.random() * (max - min)) + min);
If you store the acceptable values (-1 and 1) in an array, you can make the random choose one of those based on the length of the array. By storing the values in an array, you not only make the process simpler, but it is extensible because you can always add new values later, if desired.
function getRandom(){
var acceptable = [-1, 1];
// Get a random number from 0 to 1 (the length of the array, 2, will never be reached)
var direction = Math.floor(Math.random() * acceptable.length);
console.log(acceptable[direction]); // Choose either array element 0 or element 1
}
// Run this code snippet a few times and you'll see that you only get -1 and 1
getRandom();
getRandom();
getRandom();
getRandom();
You can also remove the two lines declaring the max and min variables as they are no longer needed.

Do something after every 180 degrees

I have a div with some text which I would like to rotate 360 degrees for x amount of times but I would also like to modify the text every 180 degrees. how can I achieve this in Jquery or Javascript?
So far, I am stuck on this as I don't know of a way to monitor the rotation.
$('.pie_chart').css({'transform' : 'rotate(2000deg)'});
I looked at this post thinking that I could utilize the solution but it didn't work for me, or I might be just using it wrong: CSS rotation cross browser with jquery.animate()
This is very imprecise but it gets the idea across and should be enough to get you on the right track
function AnimateRotate(angle) {
// caching the object for performance reasons
var $elem = $('#square');
var texts = ['text', 'another thing', 'one more thing', 'finally']
var maxRotations = Math.floor(angle / 180);
var rotations = 0;
var lastRotation = 0;
// we use a pseudo object for the animation
// (starts from `0` to `angle`), you can name it as you want
$({deg: 0}).animate({deg: angle}, {
duration: 2000,
step: function(now) {
// in the step-callback (that is fired each step of the animation),
// you can use the `now` paramter which contains the current
// animation-position (`0` up to `angle`)
$elem.css({
transform: 'rotate(' + now + 'deg)'
});
// Here we must allow ourselves some margin for error
// We are making 4 rotations in 2 seconds, so in theory
// The box will be at the 180 degrees every half a second
// but in actuality it never is at exactly 180 degree except at the star and end
// Trial and error has shown that +6 degrees is more or less accurate,
// you could do some math to get a better precision
// We don't want to update the text at 0 degrees
if(now % 180 <= 6 && rotations > 0) {
// Shift off the first text and use that for the new text
$("#text").html(texts.shift());
rotations++;
} else if(now % 180 >= 177) {
$("#text").html(texts.shift());
rotations++;
}
}
})
};
AnimateRotate(720);

Turning objects so they reset their y-rotation in Three.js

Using three.js, I'm creating a game with cars that move in a specific direction, depending on their y-rotation. An example would be 90 degrees. I use object.translateZ() to move them forward but I've run into a problem.
I'm using physijs to simulate the cars. Cars that run into each other may change their y-rotation (because of the crash) and I want to find a way for the cars to slowly change their rotation back to the original rotation like they are turning to get back on the road. Without this my city is very chaotic.
Here's the code that I'm already using (this is just part of it):
var targetRotation = 90
var rotation = car.mesh.rotation.y * 180 / Math.PI //to convert to degrees
I want to find a way to slowly change the car's rotation so it's the same as the target rotation.
Any help is appreciated! (but some sort of function would be perfect)
I've done stuff like this before in other systems (2D, not Three.js), and essentially all you want to do is gradually increment the angle until you reach something close enough to the target angle. Usually this means the float is less than the turning speed you're incrementing by (so you don't "overshoot" the value).
The amount of the increment depends on how quickly you want them to turn.
You also want to check if it's better to increase the angle or decrease (do you turn clockwise or counterclockwise) depending on if you're closer to 360 or 0. This prevents the car from turning the "long way" around. You can find this out by seeing if the difference is greater/less than 180.
We can use the modulus operator to get the "real" angle between -360/360.
var currentAngle = car.mesh.rotation.y * 180 / Math.PI; //car's angle in degrees
var targetAngle = 90; //preferred angle *this time* ;)
var turningSpeed = 1; //one degree per update (wayyy to high for real stuff, usually)
currentAngle = currentAngle % 360; //get the 0-360 remainder
if ( Math.abs(targetAngle - currentAngle) >= turningSpeed) {
var addto = 0
if (targetAngle - currentAngle < 0) {
addto = 360
}
if ( targetAngle - currentAngle + addto <= 180 ) {
currentAngle += turningSpeed;
}
else {
currentAngle -= turningSpeed;
}
}
else { currentAngle = targetAngle; } //we're close enough to just set it
car.mesh.rotation.y = ( currentAngle * Math.PI ) / 180; // back to radians!

How can I get the current amount of daylight given only the local date/time? (like flux does)

My plan is to give a slight tint to a web page based on the current local time (from javascript). I don't need something as specific as current lumens or anything, but I'd like to get the approximate time for peak sunlight, sunrise, sunset, and mid-night +-2 hours or so. I realize the exact times would vary greatly based on latitude & longitude and also timezone data, which I could potentially have access to. But to start off, I was wondering if there were just a formula for something like [northern] hemisphere and current local time.
How does f.lux do it?
Update 1: Most of my searches have just returned daylight savings related info, which isn't very helpful. I did find this JS: http://www.esrl.noaa.gov/gmd/grad/solcalc/main.js (from here http://www.esrl.noaa.gov/gmd/grad/solcalc/) but it is laden with unexplained magic constants. For example:
function calcGeomMeanLongSun(t)
{
var L0 = 280.46646 + t * (36000.76983 + t*(0.0003032))
while(L0 > 360.0)
{
L0 -= 360.0
}
while(L0 < 0.0)
{
L0 += 360.0
}
return L0 // in degrees
}
function calcGeomMeanAnomalySun(t)
{
var M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
return M; // in degrees
}
function calcEccentricityEarthOrbit(t)
{
var e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
return e; // unitless
}
Update 2: I think the "cost" of determining a locale of the user via gps or whatever is too great (especially since this is purely for cosmetic reasons and serves no other functional purpose), so I'm probably just going to stick with the 12am-6am-12pm-6pm cycle of whatever the local time is via javascript.
Update 3: I just went with a slightly modified sine-wave with a small preference towards day-time:
var x, fx, hour,
// starting hsl value for midnight:
h = 220,
s = 42,
l = 75;
for (hour = 0; hour < 24; hour++) {
// 0 for midnight, up to 12 for noon
x = 12 - Math.abs(hour - 12);
// 0.0 to 1.0
fx = x / 12;
// factor of pi, shift x axis by 1 half pi
fx = (Math.PI * (fx - (1 / 2)));
// sine function
fx = Math.sin(fx);
// +1 to start at 0, take half to max out at one
fx = (fx + 1) / 2;
// skew the values just slightly for daytime
fx = Math.pow(fx, 0.75);
// change range back to top out at 12
fx = fx * 12;
// base of 220 degrees, 18.25 provided a nice color rage from bluish to yellowish
h = Math.floor((220 + (18.25 * fx)));
// rotate on 360 degrees
while (h >= 360) {
h = h - 360;
}
// base of 42% saturated, multiplied x for a linear slope up to 100%
s = Math.floor(42 + (5.5 * x));
// 100 max
if (s > 100) {
s = 100;
}
// base of 75% lightness, 1.85 factor was a nice linear slope stopping short of 100%
l = Math.floor(75 + (1.85 * x));
// 100 max
if (l > 100) {
l = 100;
}
// "style='background-color: hsl(" + h + ", " + s + "%, " + l + "%);'"
}
Here it is on JSBin. I may play around with getting the actual amount in the future, but this gets me close enough for now.
Is not this equation from Wikipedia enough:
http://en.wikipedia.org/wiki/Sunrise_equation
There is no magic in it, just a bit of math.
Or do you need something more?

Animation with Initial Velocity

I've been trying to solve this problem for a number of days now but I must be missing something.
Known Variables:
vi = Initial Velocity
t = Animation Duration
d = Distance.
end velocity should always be zero
The function I'm trying to create: D(0...t) = the current distance for a given time
Using this information I want to be able to create a smooth animation curve with varying velocity (ease-in/ease-out).
The animation must be able ease-in from an initial velocity.
The animation must be exactly t seconds and must be travel exactly d units.
The curve should lean towards the average velocity with acceleration occurring at the beginning and the end portions of the curve.
I'm open to extra configuration variables.
The best I've been able to come up with is something that doesn't factor in the initial velocity. I'm hoping someone smarter can help me out. ;)
Thank you!
p.s. I'm working with an ECMAScript variant
Here is a different solution, where there isn't any time interval where the velocity is constant. Instead, velocity as a function of time is a second-order polynomial, and the acceleration is linear in time (positive at the beginning, and negative at the end). Maybe you can try it.
Let me rename your variables a bit. Let
T = final time = animation duration
V = initial velocity (>0)
D = total distance (>0)
We are searching for a smooth function v(t) (velocity as a function of time) such that:
v(0) = V
v(T) = 0
the integral from 0 to T of v(t)dt is D
With a (concave) second-order polynomial we can satisfy all the three constraints. Hence, let
v(t) := at^2 + bt + c
and let's solve for a, b, c. The first constraint v(0) = V gives immediately c = V.
The second constraint reads
aT^2 + bT + V = 0
On the other hand, the integral of v(t) is d(t) = 1/3 a t^3 + 1/2 b t^2 + Vt (this is the distance covered up to time t), hence the third constraint reads
d(T) = 1/3 a T^3 + 1/2 b T^2 + VT = D
The last two equations seem messy, but they are just two linear equations in the two unknowns a, b, and they should be easily solvable. If I did my computations correctly, the final result is
a = 3V/T^2 - 6D/T^3, b = 6D/T^2 - 4V/T
If you substitute a, b, c in the expression of d(t), you obtain the covered distance as a function of time.
I believe you want to solve your problem in 3 parts.
First, you need to solve for the minimum velocity necessary to complete the distance in time T.
This would be pretty simple (D/t) = v(min)
It assumes instantaneous acceleration from v(initial) to v(min) and again deceleration over a time period of 0s at the beginning and end.
so for example say your v(i) is 5px/s.
you want a 100px movement over 10 seconds.
v(min) = 100px/10s = 10px/s
Second, you want a smooth acceleration from v(initial) to v(min). this will take some period of time t(acc). Assuming the acceleration and deceleration will be equal, then you can just figure for one of them, then multiply by 2.
We can call the function that describes the distance travelled during accelleration D(accel).
Lets keep it easy to start and say we want the duration of accelleration to be 1s
so your equation for total distance travelled is going to be
D(total) = D(accel) + D(v(max) )
When you know that D(accel) is for 2s total, you can calculate
D(accel) = ( V(ini) + V(max) ) /2) * (2seconds)
and
D(v(max)) = V(max) * 8s
solving for V(max) we get
100px = D(accel) + D(v(max))
100px = ( 5px/s + VMax) /2 *(2s)) + VMax *8s
100px = 5px + (Vmax * 1s) + Vmax *8s
95px = 9Vmax *s
VMax = 95px/9s
VMax = 10.556px/s
You can now go back and replace your 1s acceleration window with a formula that defines the acceleration window as a % of the overall time period or some other thing.
Also note that for animation purposes, you will have to break 10.556px/s down into per frame px movements and account for time appropriately.
abustin, since you don't like the 3 segment solution, you may want to try looking at Bezier curves to solve this problem. Bezier curve can be utilized to interpolate time as well as distance, so you can define a few control points near the ends of your motion to generate acceleration, where the middle "segment" will be defined such that the velocity is close to constant. Utilizing splines is a possibility too.
Using constant accelerations:
Definitions:
Vi - Initial velocity
Va - Average velocity
Vo - Ending velocity
D - Total distance to be traveled
T - Total time for travel
t1 - Acceleration time from beginning to Va
t2 - Acceleration time from Va to Vo
The equation to solve is:
(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D
You should decide how much time the initial acceleration (t1) and the final acceleration (t2) takes and then you are left with only one unknown -> Va, which can be easily solved.
EDIT: find the distance as a function of time:
Well, now that you know the velocities, it is easy to figure out the distance traveled:
D(t) = Vi*t + 0.5*t^2*(Va-Vi)/t1 {0<t<t1}
D(t) = Va*(t-t1) + D1 {t1<t<t3}
D(t) = Va*(t-t3)+0.5*(t-t3)^2*(Vo-Va)/t2 + D2 {t3<t<T}
where t3=(T-t2), D1 and D2 are the distance traveled at the end of the first and second segments, which can be found from the respective functions:
D1 = 0.5*(Va+Vi)*t1
D2 = D1 + Va*(t3-t1)
EDIT 2: Solving for Va:
(Vi+Va)/2*t1 + Va*(T-t2-t1) + (Va+Vo)/2*t2 = D
Remember that t1 and t2 are the problem parameters that you choose. You decide what fraction of the movement the object accelerates and decelerates. Let's say t1=t2=0.1*T. Substitution then gives:
(Vi+Va)/2*(0.1T) + Va*(T-(0.1T)-(0.1T)) + (Va+Vo)/2*(0.1T) = D
Va*(0.1T/2 + T-0.1T-0.1T + 0.1T/2) + Vi*(0.1T)/2 + Vo*(0.1T)/2 = D
Va*(0.9T) + Vi*(0.05T) + Vo*(0.05T) = D
Va*(0.9T) = D - Vi*(0.05T) + Vo*(0.05T)
Va = (D - (Vi + Vo)*(0.05T)) / (0.9T)
Got it?
Federico's solution is a nice one, but I found the acceleration of a linear acceleration solution a bit too abrupt, and I ended up forging ahead with a double parabola solution where the acceleration is constant, first in one direction and then in the other, until the object ends at 1 with a velocity 0. (I did try solving it with variable starts and ends, but it was too difficult. Instead, my implementation just scales the inputs and outputs before passing them through the function.)
The math was high school stuff, but I'll go over it for completeness' sake.
given v, the initial velocity, we have two parabolas, the left and the right
ly = m(t - ax)^2 + ay, where t is the time input, ranging from 0 to 1, and ax, ay, and m are constants we need to find, given v.
ry = -m(t - 1)^2 + 1
Note, they both take m as their steepness, because they accelerate at the same rate. ry uses -m because it accelerates in the other direction.
We have a number of constraints to solve for
ly(0) = 0, the value is 0 at t = 0
ly'(0) = v, the differential of the equation(the velocity) is v(the initial velocity, given) at t = 0
ly(h) = ry(h), the two parabolas connect at some given halfway point (which is not actually halfway unless v = 0)
ly'(h) = ry'(h), the velocity is the same at that halfway point, no sudden jerks
I went through a number of approaches from here on out, but in the end it seemed that the only way was to solve for m in terms of v. We arrive at the formula mm + m(v - 2) - (vv)/4. Applying the quadratic formula, we get m = ((2 - v) ± sqrt(2vv - 4v + 4))/2
Meaning that either
m = ((2 - v) + sqrt(2v*v - 4v + 4))/2
or
m = ((2 - v) - sqrt(2v*v - 4v + 4))/2
And we find that we can decide which it is by looking at the initial velocity,
let sqrt_part = Math.sqrt(2*sq(initial_velocity) - 4*initial_velocity + 4)
let m = (2 - initial_velocity + (initial_velocity < 2 ? sqrt_part : -sqrt_part))/2
from there, the rest of the variables (ax, ay and h) are quite easy to work out.
There is a rust implementation of the formulai here https://gist.github.com/makoConstruct/df173c3a4e0854b535869fdc2acdeeb1
Rust's syntax is pretty ordinary, so you wont have much trouble translating that to JS. Feel free to post your port in the comments.

Categories