How to rotate image when time changes? - javascript

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)";
}
}

Related

Forcing If Condition Within Function to Run Every Time

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>

Will this method of spinning an SVG in IE9 cause a performance hit?

I have a task to make an SVG rotate in IE9.
I found the FakeSmile library which makes it rotate, but after the whole DOM is ready, which is not the behavior I want. I made an attempt to do it manually with JavaScript and ended with this code:
//init an array with values from 0 to 360 for degrees
var degrees = [];
for(var i = 0; i <= 360; i++) {
degress.push(i);
}
// function to rotate it, after it's fetched from the DOM
var rotate = function() {
var deg = degrees.shift();
element.style.msTransform = "rotate(" + deg + "deg)";
degrees.push(deg);
}
setInterval(rotate, 7);
Though it is working, I am worried if any performance hit will occur. Also if there is a better solution. Any suggestions are welcomed.
A creator function and organized objects would be a good start. Remember you shouldn't pollute the global namespace if you can avoid it.
Also de-bounce request and animation. A request every 7 millisecond is two request per frame on a 60fps screen (the most common) and there is no need to calculate and throw away frames the user never sees.
In my example i use requestAnimationFrame because that will synchronize with the screens refreshrate. On every request i check if the handle is already drawing a frame and if it isn't i schedule a frame drawing.
Notice that you can still set JavaScript variables every 7 millisecond. It's just the DOM that's slows.
EDIT 1 - No requestAnimationFrame in IE9
My mistake about requestAnimationFrame, but de-bounce is still a good idea. With de-bounce, several factors can request a change and it will still only render when relevant.
I have replaced requestAnimationFrame with setTimeout(.... 1000/60) for close to 60 fps animation.
function createRotator(element) {
var rotator;
rotator = {
degrees: 0,
element: element,
eventHandle: false,
rotate: function rotate() {
rotator.degrees = (rotator.degrees + 1) % 360;
if (rotator.eventHandle === false)
rotator.eventHandle = setTimeout(function() {
rotator.element.style.transform = "rotate(" + rotator.degrees + "deg)";
rotator.element.style.msTransform = "rotate(" + rotator.degrees + "deg)";
rotator.eventHandle = false;
}, 1000 / 60);
}
};
return rotator;
}
//TEST
var nodes = 0;
var handle;
handle = setInterval(function() {
nodes++;
if (nodes > 10) {
clearInterval(handle);
}
var testNode = document.body.appendChild(document.createElement("p"));
testNode.innerHTML = "Hello dear World!";
testNode.style.width = "115px";
testNode.style.cssFloat = "left";
testNode.style.marginTop = "100px";
var rotator = createRotator(testNode);
setInterval(rotator.rotate, 3);
}, 1000 / 4);
Yeah, with IE9, you're out of luck on CSS animations. My only suggestion would be a memory optimization
//init a variable to store the current angle
let angle = 0;
// function to rotate it
function rotate() {
angle = (++angle)%360;
element.style.msTransform = "rotate(" + angle+ "deg)";
}
setInterval(rotate, 7);
This design change also lets you change the speed of the rotation on the fly without changing the interval length. All you would change is ++angle to angle + w where w is the angular velocity.
What is also unfortunate is that you can't use requestAnimationFrame instead of an interval. Oh well. It's not the end of the world.
EDIT:
It was bugging me that the function was relying so heavily on global variables. So, here is a slightly "better", though heavier, way of doing it.
/** Takes in an element, an angular velocity, and an interval, and makes the element spin in IE9
PARAMS:
element : Element - The element we are spinning
da : Number - The angular velocity in degrees per interval
interval : Number - The number of milliseconds per interval
RETURNS:
Number - The ID of the interval that is created
**/
function makeRotate(element, da, interval){
// Variable to store angle
let a = 0;
// If da isn't provided, make it 1
da = da || 1;
// If interval isn't provided, make it 7
interval = interval || 7;
// Get the ID and make the interval
let id = window.setInterval(() => {
// Increment the angle by the angular velocity, but wrap around 360
a = (a + da)%360;
// Apply the transform to the element
element.style.msTransform = "rotate(" + a + "deg)";
}, interval);
// Return the ID of the interval
return id;
}
const intervalId = makeRotate(element, 1, 7);
Also, I made sure to return the interval id because it is always handy to be able to cancel those suckers! window.clearInterval(intervalId);

How to use variable parameters for rotation of a picture

What is wrong with my approach?
I would like to allow a user to enter a value of 0 to 180 degree to rotate a picture by this value.
If I use the code below it works perfect.
document.getElementById('myCanvas').setAttribute("style", "position:relative;height:1024px;width:100%; transform: rotate(45deg)" );
But, if I use variables like in the following code, no rotation is performed.
var deg = 45;
var rotation = "transform: rotate(" + deg + "deg)";
document.getElementById('myCanvas').setAttribute("style", "position:relative;height:1024px;width:100%; rotation" );
How can I manage my requirement?
Thank you in advance.
Looking at your code, I think your problem is because you have missed some concatenation. Try this:
var deg = 45;
var rotation = "transform: rotate(" + deg + "deg);"; // Note: Extra semicolon in string
var element = document.getElementById('myCanvas')
element.setAttribute("style", "position:relative;height:1024px;width:100%;" + rotation);
Going further
If you want degree to change based on user input, then I suggest adding an input element to the page, waiting for click (or change) events and then updating your picture's styles:
var number_input = document.querySelector("input[type=number]#rotation");
var element // = ...
var myExtraStyles // = ...
// Pass in extra styles, like you width and such as above.
function rotateElement(degrees, extraStyles) {
var rotation = "transform: rotate(" + deg + "deg);";
element.setAttribute("style", extraStyles + rotation);
}
number_input.addEventListener("click", function(){
rotateElement(element.value, myExtraStyles);
})

css3 transform rotate from 360deg to 0deg

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.

3D rotation effect using multiple image frames in Javascript - how to trigger element fade in/out on certain frames?

I am using Javascript to drag and simulate rotating an image by using multiple frames showing the image in 360 degrees. I am relatively new to JavaScript and am having a hard time with the script in trying to insert a trigger that would cause overlaying images to fade in and out when certain frames (degrees) of the image are displayed. For example, when I drag, rotate and reveal the front side of the image, let's say a range of frame 10 to frame 45, 4 popup labels will fade in (simultaneously) and remain visible until I drag and rotate the image away from that range of frame, causing the labels to fade out. On the backside of the image I would like to have 3 popup labels appear once any frame within the acceptable range of frames are displayed, let's say, frames 95 through 135. Is this possible? Please see the code that I have been working off of below:
/*** configuration variables ***/
var
totalFrames = 72,
frameUrlTemplate =
'images/frames/Skeleton_[#frame].jpg'
;
/*** state variables ***/
var
rotation = 0,
lastFrameNo = -1,
dragStartRotation
;
/*** create the Uize.Widget.Drag instance ***/
var rotationViewer = page.addChild (
'rotationViewer',
Uize.Widget.Drag,
{
cancelFade:{duration:2000,curve:Uize.Curve.Rubber.easeOutBounce ()},
releaseTravel:function (speed) {
var
deceleration = 2000, // measured in pixels/s/s
duration = speed / deceleration
;
return {
duration:duration,
distance:Math.round (speed * duration / 2),
curve:function (_value) {return 1 - (_value = 1 - _value) * _value}
};
},
html:function (input) {
var
htmlChunks = [],
frameNodeIdPrefix = input.idPrefix + '-frame'
;
for (var frameNo = 0; ++frameNo <= totalFrames;) {
htmlChunks.push (
'<img' +
' id="' + frameNodeIdPrefix + frameNo + '"' +
' src="' + Uize.substituteInto (frameUrlTemplate,{frame:(frameNo < 10 ? '0' : '') + frameNo}) +'"' +
'/>'
);
}
return htmlChunks.join ('');
},
built:false
}
);
/*** wire up the drag widget with events for updating rotation degree ***/
function updateRotation (newRotation) {
rotation = ((newRotation % 360) + 360) % 360;
var frameNo = 1 + Math.round (rotation / 360 * (totalFrames - 1));
if (frameNo != lastFrameNo) {
rotationViewer.showNode ('frame'+ lastFrameNo,false);
rotationViewer.showNode ('frame'+ (lastFrameNo = frameNo));
}
}
rotationViewer.wire ({
'Drag Start':function () {dragStartRotation = rotation},
'Drag Update':function (e) {updateRotation (dragStartRotation - e.source.eventDeltaPos [0] / -2.5)}
});
/*** function for animating spin ***/
function spin (degrees,duration,curve) {
Uize.Fade.fade (updateRotation,rotation,rotation + degrees,duration,{quantization:1,curve:curve});
}
/*** initialization ***/
Uize.Node.wire (window,'load',function () {spin (-360,2700,Uize.Curve.easeInOutPow (4))});
/*** wire up the page widget ***/
page.wireUi ();
I'd appreciate any advice on this. Thanks!!
-Adam
there are 3d transforms in javascrip fot html elements, even a few libaries.
if its a flat image, use that.
if its 3d you wish to simulate you already get very realistc effect with just 120 pictures.
rotation = ((newRotation % 360) + 360) % 360;
var frameNo = 1 + Math.round (rotation / 360 * (totalFrames -1));
if (frameNo > 0 && frameNo< 60 )//code to show box

Categories

Resources