I'm making some simple css3 watch and its working like this (just calculates mins, secs and hours rotation and apply it
var updateWatch = function() {
var seconds = new Date().getSeconds();
var hours = new Date().getHours();
var mins = new Date().getMinutes();
var sdegree = seconds * 6;
var srotate = "rotate(" + sdegree + "deg)";
var hdegree = hours * 30 + (mins / 2);
var hrotate = "rotate(" + hdegree + "deg)";
var mdegree = mins * 6;
var mrotate = "rotate(" + mdegree + "deg)";
$(".jquery-clock-sec").css({"-moz-transform" : srotate, "-webkit-transform" : srotate});
$(".jquery-clock-hour").css({"-moz-transform" : hrotate, "-webkit-transform" : hrotate});
$(".jquery-clock-min").css({"-moz-transform" : mrotate, "-webkit-transform" : mrotate});
}
All animations has some easing.
And all works well but when some marker makes full rotate then 360deg becomes 0deg and then marker makes all circle back. Is there any simple way to avoid it?
It is logical that the marker goes backwards when you change it from 359 deg to 0 deg.
The logical answer would be to avoid truncating the data.
I would get the time (fractionary part), convert it to seconds, convert that to degrees, and use that.
Don't worry if the resulting number is a zillion degrees, it will map to the correct position.
And it will wrap ok when going from a zillion degrees to a zillion + 1, when that happens to make a new rotation.
Just to avoid accuracy problems, as I said before, use only the time excluding the day.
Related
So, I've built a quick function to change hue values of a target element in JavaScript, and it works mostly fine now, but I do have some more questions that go beyond the initial post's scope. So I'll open a new question and post them here.
Here's the code:
document.getElementById('left').style.filter = "hue-rotate(" + 20 + "deg)";
document.getElementById('right').style.filter = "hue-rotate(" + 20 + "deg)";
document.querySelectorAll('div').forEach(occurence => {
occurence.addEventListener('click', (e) => {
const filter = e.target.style.filter;
var deg = parseInt(filter.replace(/[^0-9.]/g, ""));
deg += 40;
e.target.style.filter = "hue-rotate(" + deg + "deg)";
if (deg >= 360) {deg -= 360}
console.log(e.target.id + " is " + deg + "deg");
});
});
My main question (1) is that I've coded an if statement to log the current hue value within 360º (the hue-rotate works anyway with values over +360º, but I find it to be clearer this way). However, while the check works perfectly the first time around, it stops working after the function loops once through the 360º (on subsequent loops, it goes beyond 360º).
For clarification, the statement has been positioned after the degree value is already set (and animated) so as to sidestep the quick loop animation that happens when it goes from, say, 340 to 20º (instead of going there directly, it seems to loop back through the whole hue wheel).
Also, (2) the initial hue-rotate states are defined (at the top) within the script because the function does not work otherwise, although both DIVs do have defined CSS values.
That's it! Thanks in advance!
Since the degree value on the element is always set before limiting the degrees to 360, the 2nd time it loops subtracting 360 wont be enough.
style logged value
0 0
360 (-360) 0
720 (-360) 360
etc
To limit the logged value between [0, 360], use the % operator instead
document.querySelectorAll('div').forEach(occurence => {
occurence.addEventListener('click', (e) => {
const filter = e.target.style.filter;
var deg = parseInt(filter.replace(/[^0-9.]/g, ""));
deg += 40;
e.target.style.filter = "hue-rotate(" + deg + "deg)";
deg %= 360; // deg = deg % 360
console.log(e.target.id + " is " + deg + "deg");
});
});
For (2):
To get the style of the element from css, use getComputedStyle
occurence.addEventListener('click', (e) => {
const filter = getComputedStyle(e.target).filter;
...
});
e.target.style.filter = "hue-rotate(" + deg + "deg)";
above line should be below if condition if (deg >= 360) {deg -= 360}
document.getElementById('left').style.filter = "hue-rotate(" + 20 + "deg)";
document.getElementById('right').style.filter = "hue-rotate(" + 20 + "deg)";
document.querySelectorAll('div').forEach(occurence => {
occurence.addEventListener('click', (e) => {
const filter = e.target.style.filter;
console.log(filter);
let deg = parseInt(filter.replace(/[^0-9.]/g, ""));
deg += 40;
if (deg >= 360) {
deg -= 360
}
e.target.style.filter = "hue-rotate(" + deg + "deg)";
console.log(e.target.id + " is " + deg + "deg");
});
});
<div id="left">left</div>
<div id="right">right</div>
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 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 am trying to get results of the spinner. After 6 hours of debugging and all sorts of math attempts I can't seem to find out how to get the value of the spinner with each spin. What DIV does it land on?!
http://codepen.io/anon/pen/OMrOPe
Initially I thought the following algorithm would work.
total_rotations = Get Total Degrees in rotations (including what was done historically.
total_rotations / 360 = _total_rotations_of_a_circle
value_to_subtract = Take the absolute value of _total_rotations_of_a_circle * 360
left_over_value_in_Degree = total_rotations - value_to_subtract
left_over_value_in_Degree/60 = result.
This algorithm only works SOMETIMES. I just am not sure how to do this, any tips would help.
The aoY variable was presented by the original developer, but I don't know how to use that value to find the actual div its pointing to. What math do I need here?
$('#wheel .sec').each(function(){
var t = $(this);
var noY = 0;
var c = 0;
var n = 700;
var interval = setInterval(function () {
c++;
if (c === n) {
clearInterval(interval);
}
var aoY = t.offset().top;
$("#txt").html(aoY);
console.log(aoY);
/*23.7 is the minumum offset number that
each section can get, in a 30 angle degree.
So, if the offset reaches 23.7, then we know
that it has a 30 degree angle and therefore,
exactly aligned with the spin btn*/
if(aoY < 23.89){
console.log('<<<<<<<<');
$('#spin').addClass('spin');
setTimeout(function () {
$('#spin').removeClass('spin');
}, 100);
}
}, 10);
$('#inner-wheel').css({
'transform' : 'rotate(' + totalDegree + 'deg)'
});
noY = t.offset().top;
});
});
The formula RobG proposed is correct:
Math.ceil((( totalDegree + 30 ) % 360) / 60)
Something you also have to take into account is the fact that the offset changes for every consecutive plays. In order to deal with that, you can simply use this formula:
offset = extraDegree MOD 60
You can then replace the number 30 in the function by the offset variable:
Math.ceil((( totalDegree + offset ) % 360) / 60)
See this fiddle
I have recently made a countdown timer for a website like this! It's pretty much a combination of 2 scripts I found online.
The countdown counts down to February 1st and is pretty static. But the 'clockpicture' is supposed to rotate 6 degrees every second (please see the page source). But it turns out the clock picture will start counting/turning from the moment the page is loaded, so if you arrive there between two seconds the picture will we half a second off, compared to the countdown.
Is there any way I can 'connect' the turning of the picture to the changing of the countdown?
Any help is much appreciated!
EDIT
Based on discussion with OP, finally I found the solution. The problem was, how the browsers handle the rotations.
Ok, so, remove that anim gif, and do some animation there. Create a global variable, called var degrees = 0 at the top of your script. You need to incrase that degrees in every tick with 6. If it reach the 360, then reset it to 0.
For some reason, it not works on jsfiddle, but you can check it on my site. Live demo
Then in your tick function:
if (amount < 0) {
expired.push(idx);
}
// date is still good
else {
this.display(cnt, this.format(this.math(amount)));
if (degrees === 360) {
degrees = 0;
}
degrees += 6;
obj = document.getElementById('clock');
if (navigator.userAgent.match("Chrome")) {
obj.style.WebkitTransform = "rotate(" + degrees + "deg)";
} else if (navigator.userAgent.match("Firefox")) {
obj.style.MozTransform = "rotate(" + degrees + "deg)";
} else if (navigator.userAgent.match("MSIE")) {
obj.style.msTransform = "rotate(" + degrees + "deg)";
} else if (navigator.userAgent.match("Opera")) {
obj.style.OTransform = "rotate(" + degrees + "deg)";
} else {
obj.style.transform = "rotate(" + degrees + "deg)";
}
}