How do I call a function every whatever seconds in Javascript? - javascript

Not sure why this is so hard to do in Javascript... Slightly frustrating LOL
Here's one of the ways I've tried to do it:
function rotateDavid() {
$("#david").css({
'transform' : 'rotate(90deg)'
});
setTimeout(rotateDavid, 10000);
};
rotateDavid();
It will do it once but doesn't repeat... I dunno...

The problem here is not how you are calling the function. This way is actually preferred over setInterval in some cases.
The issue you have is that setting the Css to 90degrees is not changing it over and over. You are setting it to the same degree value every time.
You need to update the angle on every iteration. So in this case you want to add 90 to it.
var rotation = 0;
function rotateDavid() {
rotation += 1
$("#david").css({
'transform' : 'rotate(' + (90 * rotation) + 'deg)'
});
setTimeout(rotateDavid, 1000);
};
rotateDavid();
div{
width:100px;
height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="david">Hi</div>
You can also use a mod operator to keep the number from getting huge.
'transform' : 'rotate(' + (90 * (rotation%4)) + 'deg)'

Your method, actually, is called every 10s. You can check it if you add a log to the console inside the method. However, you was setting the css property always to the same value, so you won't see any visual effect. A possible fix is shown on next example:
function rotateDavid(rot)
{
$("#david").css({
'transform': `rotate(${rot}deg)`
});
rot = rot + 90 >= 360 ? 0 : rot + 90;
setTimeout(() => rotateDavid(rot), 5000);
};
rotateDavid(0);
#david {
background: skyblue;
width: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="david">David</div>
Even more, you can get similar functionality using setInterval():
function rotateDavid(rot)
{
$("#david").css({
'transform': `rotate(${rot}deg)`
});
};
var rot = 90;
setInterval(
() => {rotateDavid(rot); rot = rot + 90 >= 360 ? 0 : rot + 90;},
5000
);
#david {
background: skyblue;
width: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="david">David</div>

Related

Plain JavaScript rotate

I would like to rotate an object exactly as the fiddle: http://jsfiddle.net/nqC6T/
however, I do not have the JQuery library available in my project.
var angle = 0;
$(document).ready(function () {
$('#rotate').click(function () {
angle += 90;
$('#div1').animate({ rotate: angle }, {
step: function (now, fx) {
$(this).css('-webkit-transform', 'rotate(' + now + 'deg)');
$(this).css('-moz-transform', 'rotate(' + now + 'deg)');
$(this).css('transform', 'rotate(' + now + 'deg)');
},
duration: 3000
}, 'linear');
});
});
Would this be possible in plain JavaScript?
Thanks!
A plain Javascript based solution is as follows:
var obj = document.getElementById("div1");
var total = 100;
var current = 0;
setInterval(function(){
if (current < total) {
current += 1;
obj.style.transform = 'rotate('+current+'deg)';
}
}, 1);
This is just an example. You can definitely improve this code further. As mentioned by Mohammad, you can also use CSS3 based animations.
You could add a 'rate of speed' and 'initial rotate position' to the element you
wish to rotate, by simply using a closure to automatically return a given rotational increase/decrease rate:
var division=document.getElementById("rotdiv");
function rotElem(startpos,rate){
return function(mult){
return division.style="transform:rotate("+ startpos+ mult*rate++ +"deg)";};
}
var rotelem = rotElem(0,1);
var atspeedof = setInterval(rotelem.bind(null),1000,10);
rotElem(0,1) You define optional start position '0' of the element before starting rotate and the self-increasing 'unit' of change return by the closure.
setInterval(rotelem.bind(null),1000,10) You call setInterval to run the closure at each second AND passing the value '10' as the multiplier for the rate speed. Changing the rightmost argument after the setInterval time, increases or decreases rotation.
var division = document.getElementById("rotdiv");
function rotElem(startpos, rate) {
return function(mult) {
return division.style = "transform:rotate(" + startpos + mult * rate++ + "deg)";
};
}
var rotelem = rotElem(0, 1);
var atspeedof = setInterval(rotelem.bind(null), 500, 10);
#rotdiv {
position: relative;
margin: auto;
top: 50px;
width: 80px;
height: 80px;
background-color: gray;
}
<div id='rotdiv'>
</div>

Add more degrees everytime you click

I want to add more degrees of rotation to #rad-spin every time someone clicks on #rad-btn
$(document).ready(function(){
$("#rad-btn").click(function(){
$("#rad-spin").css("transform", "rotate(90deg)");
});
});
Now it just goes one time to 90deg and if I click again it won't go further to 180deg (obviously). That's what I want.. Anyone knows how to do this?
By lexical scope, you can do this.By this, keep the outer value index.
$(document).ready(function(){
var index = 0
$("#rad-btn").click(function(){
index++
$("#rad-spin").css("transform", "rotate(" + 90 * index + "deg)");
});
});
By data- and $.data, you can save the info in the DOM.
$(document).ready(function(){
$("#rad-spin").data('index', 0)
$("#rad-btn").click(function(){
var index = $("#rad-spin").data('index')
$("#rad-spin").data('index', ++index)
$("#rad-spin").css("transform", "rotate(" + 90 * index + "deg)");
});
});
Just store the angle somewhere.
$(document).ready(function(){
var angle = 0;
$("#rad-btn").click(function(){
angle+=720;
$("#rad-spin").css("transform", "rotate("+angle+"deg)");
$(this).prop('disabled',true).delay(2000).queue(()=>$(this).prop('disabled',false).dequeue());
});
});
#rad-spin{
transition: transform 2s;
position: absolute;
top: 150px;
left: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='rad-btn'>v. rad</button>
<div id='rad-spin'>spin me round and round</div>

Looping css style with setTimeout: "in the blink of an eye"

I want to make a bar (#innerBar) to decrease 1% in width per second.
The loop doesn't seem to work. My bar drops from 100% to 0% in the blink of an eye.
function timer(){
var timer;
for(i=100;i>=0;i--){
timer = i.toString() + "%";
setTimeout(function({$('#innerBar').css("width", timer)}, ((100-i)*1000));
}
}
Note : #innerBar is a DIV with a css property (height:10px). ** + the width from timer(); **
As already said in the comments, you need to put it in the closure. Here's an example:
function timer() {
for (i = 100; i >= 0; i--) {
setTimeout(function(t) {
return function() {
var timer = t.toString() + "%";
$('#innerBar').css("width", timer);
};
}(i), ((100 - i) * 1000));
}
}
timer();
#innerBar {height: 50px; background: green; transition: width 0.2s linear}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="innerBar"></div>
EXPLANATION
So my question are: what is going throught function(t)? and why and how does }(i) work? Is it a multiplication of the fu?
Let's take the function body we're passing in to setTimeout:
function(t) {
return function() {
var timer = t.toString() + "%";
$('#innerBar').css("width", timer);
};
}(i)
Let's omit the inside part:
function(t) {
// do some stuff with t
}(i)
Looks familiar? It's like the function body is called right away and is called an IIFE, just like, say:
(function(a, b) {
return a + b;
})(2, 3) // returns 5
So back to the original function, it accepts one parameter, t, and when we're calling the function we're passing in the iterator i as an argument (so the value of i becomes t inside the function). As I said in the comment, this is necessary in order to "fetch" the current value of i instead of getting the post-loop value.
As #Shomz already posted. That is good solution. I simply want to add my solution because it does not create 100 functions. So it's slightly lighter on the memory. Also you don't have to look through the DOM for #innerBar over and over again. And I removed jQuery as a dependency.
var size = 100;
var bar = document.getElementById( "innerBar" );
function setSize() {
bar.style.width = size-- + "%";
if ( size > 0 ) setTimeout( setSize, 1000 );
}
setSize();
#innerBar {
width: 100%;
height: 50px;
background: green;
transition: width 0.2s linear;
}
<div id="innerBar"></div>
I think the following code does what you want. the input time should be 1000, which will decrease you width by 1% every second
var width = $('#innerBar').width();
function timeLoop(time){
width = width*0.99;
$('#innerBar').css("width", width);
if (width <= 0.01){
return;
}
else {
setTimeout(function() {
timeLoop(time);
}, time);
}
}

Image Rotation with Fancybox

I'm creating an interface that allows users to rotate images 90 degrees counter clockwise. I rotate the image on the page using jquery and -webkit-transform, but I also want to update the preview of image in the Fancybox slideshow.
I tried rotating the image by doing the following:
$(".fancybox").fancybox({
afterShow: function(){
fancyboxRotation();
}
});
function fancyboxRotation(){
$('.fancybox-wrap').css('webkitTransform', rotate(-90deg));
$('.fancybox-wrap').css('mozTransform', rotate(-90deg));
}
But that ended up rotating the controls as well (and also placed the close button on the top left instead of the top right):
If I just apply the rotation to the image, the white border around it has the wrong orientation:
Anyone have experience applying transformations to a fancybox image?
For fancybox 3 here is what I came up with. It uses font awesome icons, you can replace with glyphicons or whatever else you choose.
//adding custom item to fancybox menu to rotate image
$(document).on('onInit.fb', function (e, instance) {
if ($('.fancybox-toolbar').find('#rotate_button').length === 0) {
$('.fancybox-toolbar').prepend('<button id="rotate_button" class="fancybox-button" title="Rotate Image"><i class="fa fa-repeat"></i></button>');
}
var click = 1;
$('.fancybox-toolbar').on('click', '#rotate_button', function () {
var n = 90 * ++click;
$('.fancybox-image-wrap img').css('webkitTransform', 'rotate(-' + n + 'deg)');
$('.fancybox-image-wrap img').css('mozTransform', 'rotate(-' + n + 'deg)');
});
});
You can rotate the outer most div in the fancy box content, In my case it's fancybox-skin(fancybox v2 )
afterShow: function(){
var click = 1;
$('.fancybox-wrap').append('<div id="rotate_button"></div>')
.on('click', '#rotate_button', function(){
var n = 90 * ++click;
$('.fancybox-skin').css('webkitTransform', 'rotate(-' + n + 'deg)');
$('.fancybox-skin').css('mozTransform', 'rotate(-' + n + 'deg)');
});
};
With help from #Ashik I finally got this working and did not have to give up showing the title since I instead rotate .fancybox-inner and overwrite some CSS so I can keep the white border. I also initialize the fancybox from the $(document).ready() function so I had to bind the button a little different.
Finally, this is kind of a long answer so let me know if I left something out since it is entirely possible! Also, we do not need to support IE (thank the lord), so it may or may not work correctly there.
I went ahead and removed the regular arrow and close buttons so they would stay put at the top. This requires that you add the fancy box button helper CSS and JS files:
<link href="/Content/css/jquery.fancybox.css" rel="stylesheet"/>
<link href="/Content/css/jquery.fancybox-buttons.css" rel="stylesheet"/>
<script src="/Content/Scripts/fancybox/jquery.fancybox.js"></script>
<script src="/Content/Scripts/fancybox/jquery.fancybox.pack.js"></script>
<script src="/Content/Scripts/fancybox/jquery.fancybox-buttons.js"></script>
Then initializing fancy box is being done from $(document).ready(), as I said, like below (notice I remove the arrows and close buttons and add them back in using the button helper's tpl property). In that tpl property I also create a custom rotation button with an onclick and a custom data-rotation property which will hold the current rotation:
$(document).ready(function() {
$(".fancybox").fancybox({
loop : true,
helpers: {
buttons: {
position: 'top',
tpl : '<div id="fancybox-buttons"><ul><li><a class="btnPrev" title="Previous" href="javascript:;"></a></li><li><a id="fancybox-rotate-button" title="Rotate" data-rotation="0" onclick="FancyBoxRotateButton()"></a></li><li><a class="btnNext" title="Next" href="javascript:;"></a></li><li><a class="btnClose" title="Close" href="javascript:jQuery.fancybox.close();"></a></li></ul></div>'
}
},
closeBtn: false, // you will use the tpl buttons now
arrows : false // you will use the tpl buttons now
});
Here is the custom rotation button's onclick function:
window.FancyBoxRotateButton = function() {
var fancyboxInner = $('.fancybox-inner');
var fancyBoxRotateButton = $('#fancybox-rotate-button');
var currentRotation = parseInt(fancyBoxRotateButton.data("rotation"));
var rotation = 'rotate(-' + (90 * ++currentRotation) + 'deg)';
fancyboxInner.css({
'-moz-transform' : rotation,
'-webkit-transform': rotation,
'-o-transform' : rotation,
'transform' : rotation
});
fancyBoxRotateButton.data("rotation", currentRotation.toString());
}
Last but not least we need to fix the white border and then I also change the size of the custom button ul and set my custom rotation button's picture. There is probably better ways to do this (if you know of one let me know!) but I simply removed .fancybox-skin's background and box shadow and added it to .fancybox-inner:
#fancybox-buttons ul{
width: 130px;
}
#fancybox-buttons #fancybox-rotate-button {
background-image: url('/Content/images/fancybox_rotate.png')
}
.fancybox-skin {
background: none !important;
}
.fancybox-opened .fancybox-skin {
-webkit-box-shadow: none !important;
-moz-box-shadow : none !important;
box-shadow : none !important;
}
.fancybox-inner {
border-radius : 4px;
border : 2px solid white;
padding : 10px;
background : white none repeat scroll 0 0;
-webkit-box-shadow: 0 10px 25px #000000;
-webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
-moz-box-shadow : 0 10px 25px #000000;
-moz-box-shadow : 0 10px 25px rgba(0, 0, 0, 0.5);
box-shadow : 0 10px 25px #000000;
box-shadow : 0 10px 25px rgba(0, 0, 0, 0.5);
}
Hope it helps someone!
You can rotate your image by applying the css style -webkit-transform: rotate(-90deg); only to the '.fancybox-inner' class element instead of the '.fancybox-wrap' so that it will rotate only the image and not the whole container that includes the controls and descriptions.
My solution was to remove the arrows and close button from the fancybox and fade in the fancybox slideshow after the rotation was applied to the entire fancybox-wrap. To do this, I set the display of the fancybox-wrap to none in the "beforeShow", and then on "AfterShow", I fade in the image. Here's my code:
$(".fancybox").fancybox({
helpers: {
overlay: {
locked: false
}
},
arrows: false,
closeBtn: false,
beforeShow: function(){
if($('.fancybox-image').length>0){
$('.fancybox-wrap').css('display', 'none');
var imageID = getFancyboxImageID();
var rotation = getFancyboxRotation(imageID);
if(rotation!=0){
fancyboxRotate(rotation);
}
}
},
afterShow: function(){
if($('.fancybox-image').length>0){
$('.fancybox-wrap').fadeIn();
}
}
});
I wanted to keep the close button and the caption so I did a little magic trick with CSS3 transform:
afterShow: function() {
var click = 0, deg;
$('.fancybox-inner')
.append('<img id="rotate_button" src="https://cdn0.iconfinder.com/data/icons/super-mono-sticker/icons/button-rotate-cw_sticker.png" title="Rotate 90° CW">')
.on('click', '#rotate_button', function() {
click = (++click % 4 === 0) ? 0 : click;
deg = 90 * click;
$('.fancybox-wrap').css('transform', 'rotate(' + deg + 'deg)');
$('#rotate_button').css('transform', 'rotate(-' + deg + 'deg)');
sessionStorage.setItem('prev_rotated_image', $('.fancybox-image').prop('src'));
sessionStorage.setItem($('.fancybox-image').prop('src'), deg);
// move the close button and rotate the label
switch (deg) {
case 90:
$('.fancybox-close').css('transform', 'translate(-' + $('.fancybox-wrap').width() + 'px, 0px)');
$('.fancybox-title').find('span.child').css('transform', 'translate(' + ($('.fancybox-wrap').width() / 2 + $('.fancybox-title').height() / 2 + 8) + 'px, -' + ($('.fancybox-wrap').height() / 2) + 'px) rotate(-' + deg + 'deg)');
break;
case 180:
$('.fancybox-close').css('transform', 'translate(-' + $('.fancybox-wrap').width() + 'px, ' + $('.fancybox-wrap').height() + 'px)');
$('.fancybox-title').find('span.child').css('transform', 'translate(0px, -'+ ($('.fancybox-wrap').height() + $('.fancybox-title').height() + 16) +'px) rotate(-' + deg + 'deg)');
break;
case 270:
$('.fancybox-close').css('transform', 'translate(0px, ' + $('.fancybox-wrap').height() + 'px)');
$('.fancybox-title').find('span.child').css('transform', 'translate(-' + ($('.fancybox-wrap').width() / 2 + $('.fancybox-title').height() / 2 + 8) + 'px, -' + ($('.fancybox-wrap').height() / 2) + 'px) rotate(-' + deg + 'deg)');
break;
case 0:
case 360:
default:
$('.fancybox-close').css('transform', 'translate(0px, 0px)');
$('.fancybox-title').find('span.child').css('transform', 'translate(0px, 0px) rotate(0deg)');
}
});
}
Thanks, #Paul for a great snippet, I have added some class changes (current slide) and CSS property that worked for my version of fancybox3. Might help someone.
Note: you can replace the "Rotate" text with an icon.
//adding custom item to fancybox menu to rotate image
$(document).on('onInit.fb', function (e, instance) {
if ($('.fancybox-toolbar').find('#rotate_button').length === 0) {
$('.fancybox-toolbar').prepend('<button id="rotate_button" class="fancybox-button" title="Rotate Image">Rotate</button>');
}
var click = 1;
$('.fancybox-toolbar').on('click', '#rotate_button', function () {
var n = 90 * ++click;
$('.fancybox-slide--current img').css('webkitTransform', 'rotate(-' + n + 'deg)');
$('.fancybox-slide--current img').css('mozTransform', 'rotate(-' + n + 'deg)');
$('.fancybox-slide--current img').css('transform', 'rotate(-' + n + 'deg)');
});
});
See this issue on Github: https://github.com/fancyapps/fancybox/issues/1100
Code of user seltix5 is working in fancybox v3. I tested it myself.
You just need to append his/her code to your fancybox.js file. It simply extends fancybox object with rotate functionality after event "onInit.fb". It also adds rotate buttons to top menu and smooth rotate animation.

Rotating DIV spins slowly on second click

I think I overlooked something. This is a very simple spin-the-bottle game.
Javascript/jQuery
$('.bottle').on('click', function(e) {
this.removeAttribute('style');
var deg = 3000 + Math.round(Math.random() * 500);
var css = '-webkit-transform: rotate(' + deg + 'deg);';
this.setAttribute(
'style', css
);
});
CSS:
.bottle {
width: 200px;
height: 200px;
background-image: url(img/bottle.png);
-webkit-transition: -webkit-transform 6s ease-out;
}
HTML:
<div class="bottle"></div>
This works perfectly on the first click of the bottle. But starting from the second click, the spin is very very slow?
Try this : http://jsfiddle.net/sMcAN/
var i = 1;
$('.bottle').on('click', function(e) {
this.removeAttribute('style');
var deg = 3000 + Math.round(Math.random() * 500);
deg = ((-1) ^ i) * deg;
var css = '-webkit-transform: rotate(' + deg + 'deg);';
this.setAttribute('style', css);
i++;
});​
Another update : http://jsfiddle.net/sMcAN/2/
This is because at first, you are going from 0 to a value over 3000. But then, the value is always within 3000 - so the difference is not big enough and it still takes the 6 seconds you have defined.
One solution would be to make sure that you offset the value and make it different by few thousand each time.
var i = 0, offset = [2000, 4000, 6000, 3000, 5000, 1000];
$('.bottle').on('click', function(e) {
this.removeAttribute('style');
var deg = offset[i] + Math.round(Math.random() * 500);
i++;
if (i > 5) {
i = 0;
}
var css = '-webkit-transform: rotate(' + deg + 'deg);';
this.setAttribute(
'style', css
);
});​
math.round(math.random() * 1000);
Try that

Categories