4

I have a circle and in it a percentage text, starts with 0%. Once I hover the circle it goes from 0 to 100% (with another effect around the circle). As for now, the percentage goes from 0 to 100 directly and I want it to show the progress (0,1,2...,99,100) but I can't manage to make JQuery wait between each for iteration.

This is what I've tried: JSFiddle demo.

Note: My code works with chrome for now.

That's one iteration:

function actions(i){
    var box = $('#box');
    box.css('transform','rotate(' + i + ' deg)');
    box.css('-ms-transform','rotate(' + i + 'deg)');
    box.css('-webkit-transform','rotate(' + i + 'deg)');
    prec = (100*(i + 135))/360;
    $("div.prec").delay(100).html(Math.round(prec)+"%");
}

I understand that delay() needs to be queued and html() is not queued so I already tried setTimeout, but that it didn't work either. I also tried setInterval - see the next code snippet:

setInterval(function () {
    $("div.prec").html(Math.round(prec)+"%");
},100);

To be more clear, I want the percentage to fit the effect progress - if the triangle that goes around travels half of the way, the percentage should be 50, and so, when I'm not hovering the circle anymore it should gradually go back to 0.

Tomas
  • 57,621
  • 49
  • 238
  • 373
Itay Gal
  • 10,706
  • 6
  • 36
  • 75

3 Answers3

6

First, remove the surplus transition: all 1s css rule! This is making trouble in all the solutions.

1. Educational - using setTimeout

The for loop will not work as you expect, javascript is not build for active-wait loop like this:

for (var i = -135; i < 225; i++){
    actions(i);
    sleep(some time);      
}

You have to use timeout and callbacks. Disable the .delay function call and rewrite your for loop to iterative setTimeout callback as shown here:

function loopit(dir, i){
    if (typeof i == "undefined") 
        i = -135;
    if (i >= 225)
        return;
    actions(i);
    setTimeout(function () {
        loopit(dir, i + 1);
    }, 1);
}

The back-rotation would be written analogically - you can write it yourself as a homework :-)

http://jsfiddle.net/NNq3z/10/

2. Easy - using jQuery .animate()

The easiest way is to use jQuery .animate() function, that will do the animation "loop" with timing for you. To animate the percent text, use progress callback. Animating rotation is tricky though, you need to use special trick:

$({ deg: deg_from } ).animate({
    deg: deg_to
}, {
    duration: 1000,
    progress: function (animation, progress) {
        $("div.prec").html(Math.round(progress*100)+"%");
    },
    step: function(now) {
        $('#box').css({
            transform: 'rotate(' + now + 'deg)'
        });
    }
});

http://jsfiddle.net/q9VXC/1/

Community
  • 1
  • 1
Tomas
  • 57,621
  • 49
  • 238
  • 373
  • 1
    You're right, javascript wont execute line by line. and your code is still buggy – Kirk Jan 18 '14 at 10:05
  • Thanks, but it's not doing the trick for me. I updated the question to be more clear about what I'm trying to achieve. – Itay Gal Jan 18 '14 at 10:10
  • @ItayGal the problem was caused by the `transition: all 1s` css rule. I removed it and works great now. I updated my solution and added even easier one using jquery `.animate()`. – Tomas Jan 18 '14 at 10:32
  • @Kirk don't now which bug you meant but I guess it's allright now? – Tomas Jan 18 '14 at 10:33
  • 1
    Yes, previous case when i hover, it starts increase the number upto 100 then only arrow moves. Now you're Absolutely Prefect – Kirk Jan 18 '14 at 10:57
  • 1
    @Kirk yes - that was fixed by removing the cursed `transition: all 1s` css rule. I wasn't expecting it could be broken by css at all :) – Tomas Jan 18 '14 at 10:59
3

http://jsfiddle.net/NNq3z/13/

var i = -135,box = $("#box"),prec;
setTimeout(function(){
if($("#circle").is(":hover"))
   loopit("c");
else
    loopit("nc");
},1);
function loopit(dir){
if (dir=="c")
    i++;        
else
    i--;
if(i<-135)
    i=-135;
if(i>225)
    i=225;
prec = (100*(i + 135))/360;   
$(".prec").html(Math.round(prec)+"%");
box.css("transform","rotate("+i+"deg)")
.css("-ms-transform","rotate("+i+"deg)")
.css("-moz-transform","rotate("+i+"deg)")
.css("-webkit-transform","rotate("+i+"deg)");
setTimeout(function(){
if($("#circle").is(":hover"))
   loopit("c");
else
    loopit("nc");
},1);
}

Removed transition:all 1s. In your code, the percentage of the box immediately change to 100% because you use for loop. For loop will be executed very fast as if it immediately change to 100% so it is not recommended.

  • 1
    It's often not a good idea to reference other answers by direction. Depending on votes and accepted answers, the order can change. If you need to reference a specific answer, you are better off putting a link to the answer instead. Also, "The above code still have some bug" doesn't really explain much. This would be a much better answer if you provided some explanation, and specifically what bugs you fixed and why. – psubsee2003 Jan 18 '14 at 14:07
  • Can you add an explanation. For now, your solution is better but it lack a proper explanation. Although I understand it, it's not a "good" stackoverflow answer. – Itay Gal Jan 18 '14 at 18:41
  • This is a plagiation - you took my fiddle from my answer and only slightly updated it with trivial changes!! @ItayGal, why did you accept this? – Tomas Jan 22 '14 at 15:29
  • It's actually not that similar and it works while your suggested solution doesn't. Your answer contains better explanation (voted up for you) but the examples you provided have bugs - For example, if I hover the circle and then not hovering it before it got to 100% the animation starts the count down from 100% instead of the percentage it got so far. Also see: http://meta.stackexchange.com/questions/216655/which-answer-should-i-accept – Itay Gal Jan 22 '14 at 16:17
-1

You should use setInterval, and you have to increment percentage each time:

var percentage = 0;
var timer = setInterval(function() {
    percentage++;
    if (percentage > 100) {
        clearInterval(timer);
    } else {
        $("div.prec").html(percentage + "%");
    }
}

You could also call actions() inside there.

Barmar
  • 741,623
  • 53
  • 500
  • 612