4

I am stuck at a point.There are 10 straight lines(png image).What I want is after the first line rotates by 40 deg,then the second line should start its rotaion and then the third,fourth,fifth and so on!!!

code:

<div class="hair" onclick="rotate()">
    <img src="single.png" id="1" width="10" height="40">
    <img src="single.png" id="2" width="10" height="40">
    <img src="single.png" id="3" width="10" height="40">
    <img src="single.png" id="4" width="10" height="40">
    <img src="single.png" id="5" width="10" height="40">
    <img src="single.png" id="6" width="10" height="40">
    <img src="single.png" id="7" width="10" height="40">
    <img src="single.png" id="8" width="10" height="40">
    <img src="single.png" id="9" width="10" height="40">
    <img src="single.png" id="10" width="10" height="40">
</div>

Javascript:

function rotate(){
    for(var i=1;i<11;i++)
    {
        setInterval(function(){
            document.getElementById(i).style.WebkitTransitionDuration="1s";
            document.getElementById(i).style.webkitTransform = 'rotate(40deg)';
        },100)
    }
}

4 Answers4

2

You're encountering the classic scope/closure/reference problem most people run into when using anonymous functions. I've answered this question a while back, and provided tons of info on what is actually happening (Ignore the first paragraph of my answer, the rest of the answer is applicable, though). Meanwhile, the answer to your problem is:

for(var i=1;i<11;i++)
{
    setInterval((function(myI)
    {
        return function()
        {
            document.getElementById(myI).style.WebkitTransitionDuration='1s';
            document.getElementById(myI).style.webkitTransform = 'rotate(40deg)';
        };
    }(i)),100);
}

Be aware that you're setting intervals: the callback will be called every 100ms as long as the browser window remains open.
You're not storing the interval id anywhere, so I'd either use setTimeout or create a (preferably non-global) array of id's so you can do clearInterval(intervalID[x]); when you need to.

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • but the animation is not there,all the lines are rotating at the same time,which is something that i dont want. This is what i want l l l l l l l l l l---initial position / l l l l l l l l l ---1st animation / / l l l l l l l l ---2nd animation / / / l l l l l l l ---3rd animation and so on. –  Jun 03 '13 at 09:55
  • @jayeshjain: your animation is set to take +- 1 second, yet the interval is .1 of a second. Of course they'll all appear to rotate together. Furthermore. the 10th id will rotate ~10 times faster by the end of the first second... trust me: increase the interval (from 100 to 5000 or something to get a better view of things), and use an IIFE – Elias Van Ootegem Jun 03 '13 at 09:58
  • I have already tried that,but the second line starts animating before the first line has ended its animation. And whats iife –  Jun 03 '13 at 10:04
  • @jayeshjain: Read the linked answer to find out more about IIFE's (Immediatly Invoked Function Expression). Also: the intervals won't slow the foreach loop down one bit, you know... just make a callback sequence (queue) from within your first interval callback. setup a fiddle, and I'll take a look at it after lunch if needs must – Elias Van Ootegem Jun 03 '13 at 10:12
2

There are a couple of steps to solve your problem:

An ID in HTML cannot start with a number, so rename them to something like 'hair1', 'hair2', etc.

The main problem is that because of the setInterval, by the time the function runs, i will not be the i that you were expecting. This is because of variable scope. You can get around this with an anonymous function.

Combining both of the above gives this code:

<div class="hair" onclick="rotate()">
  <img src="single.png" id="hair1" width="10" height="40">
  <img src="single.png" id="hair2" width="10" height="40">
  <!-- etc -->
</div>

// NOTE: This is not the final code listing, see below for a final answer. 
for (var i = i; i < 11; i++) {
  (function(local_i) {
    setInterval(function () {
      // use local_i instead of i inside this function for the results you expect
      document.getElementById('hair' + local_i).style.WebkitTransitionDuration='1s';
      document.getElementById('hair' + local_i).style.webkitTransform = 'rotate(40deg)';
    }, 100);
  })(i);
}

I would also recommend putting the styles into a stylesheet, then apply them using a class:

.rotate
{
  -webkit-transform: rotate(40deg);
  -webkit-transition: -webkit-transform 1s;
}

Finally, to get the elements to rotate in a row rather than all together, you need to multiply the interval by the value of i. I think that you probably mean to use setTimeout rather than setInterval (setInterval will keep running over and over again).

function rotate(){
  for(var i=1;i<11;i++) {
    (function (local_i) {
      setTimeout(function(){
        document.getElementById('hair' + local_i).classList.add('rotate');
      }, 100 * local_i);
    })(i);
  }
}

I've put together a demo here

clinton3141
  • 4,751
  • 3
  • 33
  • 46
  • The demo doesn't work.All the `div`s rotate at once which is not what the OP wants – Harsha Venkataramu Jun 03 '13 at 10:07
  • @harsha no they don't - the final code listing rotates each one in 100ms intervals. Check out the demo. – clinton3141 Jun 03 '13 at 10:08
  • The reason why I said it doesn't work is because I saw the demo and it didn't work. – Harsha Venkataramu Jun 03 '13 at 10:12
  • @jayeshjain in the demo I used index instead of local_i - sorry for the confusion - I'll update the demo code now! Classlist is like an array that contains all of the classes of an element that lets you easily add and remove classes. [More information on classlist](https://developer.mozilla.org/en-US/docs/Web/API/element.classList) – clinton3141 Jun 03 '13 at 11:13
0

I would do it like this on modern browsers, separating CSS and JS by using a class. This is my own example based on your requirements, using a common class box and modern tools and patterns:

Here's the HMTL, I'm using divs just because, but you can use images or any other element:

<div class="container">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>

Keep the CSS separate, you just need to match the transition speed with the delay:

.box {
  width: 100px;
  height: 100px;
  margin: 40px;
  background: grey;
  -webkit-transition: -webkit-transform .3s linear;
}

.box.rotate {
  -webkit-transform: rotate(45deg);
}

And the JS:

function rotate() {
  var elements = document.querySelectorAll('.box');
  [].forEach.call(elements, function(element, i) {
    setTimeout(function(){ element.classList.add('rotate'); },i*300);
  });
}

document.querySelector('.container')
        .addEventListener('click',rotate);

Here's little demo: http://jsbin.com/ofiral/1/edit

elclanrs
  • 92,861
  • 21
  • 134
  • 171
0

Not a perfect solution, but something you can start with.

Define a css3 animation and assign it using javascript.

@-webkit-keyframes rotation {
    from {
        -webkit-transform: rotate(0deg);
    }
    to {
        -webkit-transform: rotate(360deg);
    }
}
.hair {
    position:relative;
}
.hair div {
    width:40px;
    height:40px;
    border-bottom: 1px solid #000;
    position:absolute;
    -webkit-animation-duration:         1s; 
    -webkit-animation-iteration-count:  infinite;
    -webkit-animation-timing-function: linear;
}

.

function rotate() {
    for (var i = 1; i < 11; i++) {
        (function (x) {
            setInterval(function () {
                document.getElementById("d" + x).style.WebkitAnimationName = "rotation";
            }, 200 * i);
        })(i);
    }
}

rotate();

adjust the setInterval dealy and animation-duration to get the desired result.

webkit demo: http://jsfiddle.net/NQJJp/5/

Diode
  • 24,570
  • 8
  • 40
  • 51