0

I've been trying to create a Nav using jQuery, and part of it is rotating a gear PNG, and I've looked here and found someone describing how to do it without a plugin, but i modified their code so instead of changing angle every click i changed it so that it changes angle from 0 to 180 with delay between each step hence the setTimeout function. anyhow here's the code.

HTML

<!DOCTYPE html>
  <html>

  <head>
    <meta charset="utf-8">
    <script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-         16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="   crossorigin="anonymous">   </script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js" integrity="sha256-T0Vest3yCU7pafRw9r+settMBX6JkKN06dqBnpQ8d30="   crossorigin="anonymous"></script>
    <script src="main.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="mystyle.css">
  </head>

  <body>
    <div id="header">
     <div id="gear">
      <img src="gear.png">
     </div>
    </div>
  </body>

  </html>

CSS

#header {
    position: relative;
}

#gear {
    position: absolute;
    left: 50px;  
}

JS

$(document).ready(function() {

  var rotDeg = 0;
  var rotEnd = 180;

  jQuery.fn.rotate = function(degrees) {
      $(this).css({'-webkit-transform' : 'rotate('+ degrees +'deg)',
                   '-moz-transform' : 'rotate('+ degrees +'deg)',
                   '-ms-transform' : 'rotate('+ degrees +'deg)',
                   'transform' : 'rotate('+ degrees +'deg)'});
      return $(this);
  };
    $('#gear').click(function() {
      while(rotDeg <= rotEnd) {
       setTimeout(function() {
         rotDeg += 1;
         $(this).rotate(rotDeg);
       }, 34);
      }
    });
});
Mostafa Mekawy
  • 85
  • 1
  • 1
  • 4
  • 1
    I think it is `while` which is making it `freeze` – Rayon Sep 29 '16 at 05:17
  • Hi, You can also try the same by using animation classes to rotate, add the class to the element on click. Here is a sample of rotating a div with a delay. http://jsfiddle.net/3VrjE/ -Help :) – Help Sep 29 '16 at 05:23

2 Answers2

0

setTimeout will schedule a function to run after at least the given number of milliseconds, but only when no other code is running. However, your while loop will never end since rotDeg is not changed inside the loop (since the callback is never called), and since this causes an infinite loop, there's never any point where there's no other code running, and the scheduled callback can be run.

The solution is to drop the while loop, and instead do something like a recursively called function:

$('#gear').click(function() {
  var that = this; // <-- this is important, since we cannot use `this`
                   // inside an inner function, like you did in your
                   // original code

  const func = function() {
    // note that the condition here is negated, compared to the while loop
    if(rotDeg > rotEnd)
      return;

    // do stuff
    rotDeg += 1; 
    $(that).rotate(rotDeg); // <-- again, note `that` that we defined above

    // do next "iteration" after at least 34 ms
    setTimeout(func, 34);
  };

  func();
});

Note also that you cannot use this inside the inner functions here; the reasons for that are explained in detail in this answer.

Community
  • 1
  • 1
Frxstrem
  • 38,761
  • 9
  • 79
  • 119
  • who what now ??! :D so how to fix it ??! or what is the alternative because i need the other code as well. – Mostafa Mekawy Sep 29 '16 at 05:22
  • @MostafaMekawy I've updated my answer with a suggestion for a solution to the problem. – Frxstrem Sep 29 '16 at 05:26
  • what you wrote all makes sense but unfortunately it's not working :/ I've completely exchanged .click function and it's content code with yours but still no result. – Mostafa Mekawy Sep 29 '16 at 05:39
  • @MostafaMekawy I did forget to add the `func()` call at the end of my code; you could try to add that and see if that works? – Frxstrem Sep 29 '16 at 06:10
  • yes it works :D ty sir for you help my understanding of the function is now far better that before. – Mostafa Mekawy Sep 29 '16 at 06:56
0
$("#gear").click(function(){
startangle=0;
endangle=90;
 mov(this,startangle,endangle);
}
function mov(that, start, end){
if(start<end){
start++;
$(that).rotate(start);
setTimeout(()=>{mov(that,start,end)},100);
}
}

This starts the selfcalling function mov, that recalls it self every 100ms...

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151