I have an analog clock in my scene that I would like to update with the current time. Right now I can make the clock keep time by calculating the rotation of each hand at 1 second intervals, but I am seeing some weird results for the minute and hour hands.
hourHand = scene.getObjectByName('Box001');
minuteHand = scene.getObjectByName('Box002');
secondHand = scene.getObjectByName('Cylinder002');
var d = new Date();
var mins = d.getMinutes();
var secs = d.getSeconds();
var hours = d.getHours();
minuteHand.rotateY((-mins / 60) * (2 * Math.PI));
secondHand.rotateY(((mins /60) + (-secs / 3600)) * (2 * Math.PI));
hourHand.rotateY(((-hours / 12) + (mins / 720)) * (2 * Math.PI));
setInterval(function(){
minuteHand.rotateY((2 * Math.PI) / -3600);
secondHand.rotateY((2 * Math.PI) / -60);
hourHand.rotateY((2 * Math.PI) / (-3600 * 12));
},1000);
The problems that I am having are:
If the time is 4:30, the hour hand is at 4 when it should be between the 4 and the 5, same problem with the minute hand
I am not sure if the math I am using is correct because I am seeing some odd problems over time that I cannot pin down.
Is there a more exact way to do this?
You have no guarantee that your interval actually fires every 1000ms, so of course over time there will accumulate error, because you have no way of "catching up" with previous delays.
I would recommend to you to base the hand rotation on a function that uses the current time as input. That way it doesn't matter when your interval / trigger / callback executes, but whenever it does it will show the correct result.
The math isn't too complicated, a clock has obviously 360 degrees, so from the top of my head that would mean
(Date.now()/1000)%60 * 6 would be your secondHand rotation in degrees (assuming 0° is top), likewise
(Date.now()/60000)%60 * 6 should be the minute rotation and
(Date.now()/3600000)%24 * 15 your hourHand.
Update silly me, set up this formula for a 24h rotation. You'd want this to be 12h for a normal clock, so this would become:
(Date.now()/3600000)%12 * 30
take those calculations with a grain of salt, didn't take the time to verify this.
Related
I was creating a Analog Clock using javascript for practice and went through a code but I am not able to understand why we need to divide second by 60, min+sec/60 and and hour+min/12 could you please make me understand how this algorithm works? my code is
const hour = document.getElementById('hour');
const minute = document.getElementById('minute');
const second = document.getElementById('second');
setInterval(updateClock,1000);
function updateClock() {
let date = new Date()
let sec = date.getSeconds()/60
let min = (date.getMinutes() + sec) / 60;
let hr = (date.getHours() + min) / 12;
hour.style.transform = "rotate(" + (hr * 360) + "deg)";
minute.style.transform ="rotate(" + (min * 360) + "deg)";
second.style.transform = "rotate(" + (sec * 360) + "deg)";
}
updateClock()
You basically divide date.getSeconds() by 60 so that you can add it easier to minutes. A better solution would be this:
const hour = document.getElementById('hour');
const minute = document.getElementById('minute');
const second = document.getElementById('second');
setInterval(updateClock);
function updateClock() {
let date = new Date()
let sec = date.getSeconds()
let min = date.getMinutes() + sec/60;
let hr = date.getHours() + min/60; // you could also add + sec/3600 but that would barely make any difference
hour.style.transform = `rotate(${hr * 30}deg)`;
minute.style.transform =`rotate(${min * 6}deg)`;
second.style.transform = `rotate(${sec * 6}deg)`;
}
This gets rid of the bad division that is actually pretty useless as it's only used once.
The multiplication at the end (hr * 30, min*6 and sec*6) are pretty straight-forward. Degrees goes from 0 to 360, but mins and secs only go from 0 to 60. So we multiply them by 6.
Hours go from 0 to 12 so we multiply them by 30.
Also you don't need to call updateClock() at the bottom as it is in the interval.
At the end you should call your interval more often than every second. You can just remove the number so it will be as fast as possible. Or use 100 to make it 1/10th of a second accurate.
Hope I could help you.
You have your circle, which has 360 degrees in total. The algorithm you have calculates how much degrees it should turn to show the correct time by dividing the current amount of seconds by the total amount of seconds in a minute. For example.
const currentSeconds = 45;
const totalSecondsInMinute = 60;
currentSeconds / totalSecondsInMinute;
// Result should be 0.75
The example here says we currently have 45 seconds, which is 0.75 or 75% of a minute. This number will indicate how much the seconds pointer on the clock must turn in degrees.
const secondHandPosition = 360 * 0.75;
// Result should be 270
So at 45 seconds the second hand position should be at 270 degrees on the clock. And the same applies to the minute and hour position.
I'm in a brain freeze here.
I have 2 times:
(int) 1815 (18:15) and (int) 1915 (19:15) and I want to calculate the amount of 15 minute blocks between them. (4). How can I approach this in a solid manner?
You could take the minutes of every value and get the delta divided by a quarter hour.
function getMin(t) {
return Math.floor(t / 100) * 60 + t % 100;
}
var a = 1815,
b = 1915,
delta = Math.round((getMin(b) - getMin(a)) / 15);
console.log(delta);
I am doing the Javascript30.com course, and we have to do a JS clock with seconds, minutes and hours. This is the code:
<div class="clock">
<div class="clock-face">
<div class="hand hour-hand"></div>
<div class="hand min-hand"></div>
<div class="hand second-hand"></div>
</div>
</div>
And the JS:
const secondHand = document.querySelector('.second-hand');
const minsHand = document.querySelector('.min-hand');
const hourHand = document.querySelector('.hour-hand');
function setDate() {
const now = new Date();
const seconds = now.getSeconds();
const secondsDegrees = ((seconds / 60) * 360) + 90;
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
const mins = now.getMinutes();
const minsDegrees = ((mins / 60) * 360) + ((seconds/60)*6) + 90;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
const hour = now.getHours();
const hourDegrees = ((hour / 12) * 360) + ((mins/60)*30) + 90;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
}
setInterval(setDate, 1000);
setDate();
The + 90 part in the setDate function is the offset - because we are making a JS clock, we transformed the arrows to be at 90 degree angle using CSS, so this is just fixing the offset.
I understand everything except the statements assigned to hourDegrees and minsDegrees.
Why is the educator adding + ((seconds/60)*6) and + ((mins/60)*30) to hourDegrees and minsDegrees?
Each 60 second prepares minute hand for its next position, and each 60 minutes tick does same for the hour hand.
Assume that time is 17:17:41
Calculate how much degrees minute hand make right now
minsDegrees = (17/60) * 360 = 102
Plus;
Calculate how much degrees the elapsed seconds made our minute hand made;
theDegreeFromSeconds = (41/60) *6= 4.1
minDegree = 102 + 4.1 = 106.1
We multiply by 6 beacuse each elapsed second made 6° on clock btw. It is same for the hour degree calculation.
TL;DR
without ((seconds/60) * 6) and ((mins/60)*30), a change in minute(ie 15min to 16min after 60s completion) and a change in hour(ie 3:00 to 4:00 - after a 60 minutes completion) will rotate their respective hand straight from one point to another and yes transition will make it smooth so that rotation movement won't be noticeable.
Adding ((seconds/60) * 6) ensures a marginal increase in the minute hand after each second count. the maximum degree the minute hand can change is 6deg calculated from 360deg/60mins. Each second count will now cause a 6/60s = 0.1deg rotation movement in the minute hand which will be equivalent to 0.1 * 60s = 6deg after 60s count. When you take a careful look at the minute hand, you will notice a subtle and marginal rotation movement in the minute hand after EACH SECOND COUNT. each small marginal movement is 0.1deg. without that, the minute hand moves straight from one point to another.
Adding ((mins/60)*30) also ensures marginal increase in the HOUR hand after each MINUTE count. the maximum degree the minute hand can rotate is 30deg calculated from 360deg/12hours.Each MINUTE COUNT not second count will now cause a 30/60mins = 0.5deg rotation movement in the hour hand which is equivalent to 0.5 * 60 mins = 30 deg. 30 deg will be the maximum rotation movement from one hour to another. ie 3:00 to 4:00. a marginal movement can be seen from the hour hand after each minute count. Each small marginal movement of the hour hand is 0.5deg. *without ((mins/60)30) which cause these small marginal movement, the minute hand will move straight away from one point to another.
I made this little function from code snippets around the net. It does what its expected to do except that it decreased by 2 seconds every countdown tick instead of one, if i refresh the page it goes back to the original time again. Can you guys see what the problem is?
jQuery.countdown = function(selector, datevalue) {
var amount = datevalue*1000;
var curdate = new Date();
curdate = curdate.getTime();
var difference = amount - curdate;
if(amount < 0 || curdate >= amount){
$(selector).html("Done");
}
else{
datevalue--;
var daysRemaining = Math.floor(difference / 1000 / 60 / 60 / 24);
var hoursRemaining = Math.floor(difference / 1000 / 60 / 60 - (24 * daysRemaining));
var minutesRemaining = Math.floor(difference / 1000 / 60 - (24 * 60 * daysRemaining) - (60 * hoursRemaining));
var secondsRemaining = Math.floor(difference / 1000 - (24 * 60 * 60 * daysRemaining) - (60 * 60 * hoursRemaining) - (60 * minutesRemaining));
$(selector).html(daysRemaining+':'+hoursRemaining+':'+minutesRemaining+':'+secondsRemaining);
setTimeout(function() {
$.countdown(selector, datevalue);
}, 1000);
}
};
$.countdown('.date', 1332239568);
Remove datevalue--;
What you're doing now is to count down to a specific epoch time datevalue. But, you are decreasing it by one second each tick. Meanwhile, current time passes in setTimeout so you are both moving in time forward and pulling the target to yourself.
Either keep the original curdate of first call, saved somewhere. Or remove datevalue--;.
There were many similar questions around but none addressed this calculation. Using javascript i it is easy to find the number of milliseconds diff b/w 2 dates for ex:
var mil = Math.floor(new Date("1/1/2012") - new Date("1/7/2012"))
mil is assigned 518400000
to get weeks i would do below
var weeks = mil / (1000*7*24*60*60);
in the above example it exactly fits 1 week. For other possible inputs i would like to get output as ex:
n Weeks, y days , z hours
So i did mil % (1000*7*24*3600) to get the modulus and from the remainder calculate number of days. but astonishingly this was answer i got from console
1 weeks , 6 days seems the week calculated before is also accounted for days again.
How should i calculate these correctly?
var seconds = (mil / 1000) | 0;
mil -= seconds * 1000;
var minutes = (seconds / 60) | 0;
seconds -= minutes * 60;
var hours = (minutes / 60) | 0;
minutes -= hours * 60;
var days = (hours / 24) | 0;
hours -= days * 24;
var weeks = (days / 7) | 0;
days -= weeks * 7;
Assuming mils is non-negative, this leaves mils in the range [0, 1000), leaves minutes and seconds in the range [0, 60), leaves hours in the range [0, 24), and leaves days in the range [0, 7).
There should be 6 days between them, not one week. Your weeks calculation needs to round down:
var weeks = Math.floor(mil / (1000 * 7 * 24 * 60 * 60));
Also, your milliseconds are negative; you want either
var mil = new Date("1/7/2012") - new Date("1/1/2012");
or
var weeks = Math.floor(Math.abs(mil) / (1000 * 7 * 24 * 60 * 60));