jQuery pendulum. Animation around a pivot point

12 August, 2012 by Tom Elliott

If you want to get straight to a working demo showing animation around a pivot point, view the jQuery pendulum animation here

The key to rotating an object element around a pivot point, such as a basic pendulum, is to setup your object (DIV element, or multiple DIVS) within a container element. The container acts as the pivot object that we animate and the child element(s) are offset to the location of the pivot centre. In this example I’ve used a single image as the child object – the ball and string – and absolutely positioned the top part of the pendulum to the centre of the container DIV.

The HTML and CSS setup for pendulum setup are as follows:

#pendulum-child {
	width:105px;
	height:623px;
	background-image:url(pendulum.png);
	position:absolute;
	left:-41px;
	top:10px;
}

#pendulum-parent {
	width:22px;
	height:22px;
	background-image:url(pendulum-pivot.png);
}

 

<div id="demo-container">
	<div id="pendulum-parent">
    	<div id="pendulum-child"></div>
    </div>
</div>

As you can see the layout is very simple; two divs for the pendulum object – one acting as the object itself and a container div acting as the pivot point.

Next we create the animation in jQuery and all we need are three jQuery files. jQuery (obviously), ‘jquery css transform’ which allows us to do basic CSS3 transforms including translate, rotate and scale and the ‘css transform animation’ which, as the name suggests, allows for these transformations to be animated:

  1. jQuery
  2. jQuery css transform plugin
  3. jQuery css transform animation plugin

Using the regular jQuery ‘animate’ command, combined with the ‘rotate’ property, we can animate and rotate a html element as follows:

$('#divname').animate({rotate: 20},2000, "swing");

Where “20” is the degrees to rotate the div by (positive or negative), “2000” is the time in milliseconds and “swing” is the easing mode. jQuery has two animation easing modes. Linear and Swing, with swing being the default. Swing easing – or “slow fast slow” – is ideal for pendulum motion. The pendulum starts moving slow at the start of its swing, is fastest halfway through and slows down towards the end of the swing.

The full jQuery code for the pendulum animation is below and only a few lines are required.

<script type="text/javascript">
(function($) {
        $(document).ready(function() {
			var rotation = 30;
			var swingtime = 1600;

			function init() {
				$('#pendulum-parent').animate({rotate: rotation}, 0, function () {
					$('#pendulum-parent').css("display", "block");
					rotation *= -1;
					pendulumswing();
				});
			}

			function pendulumswing() {
				$('#pendulum-parent').animate({rotate: rotation},swingtime, "swing", function(){
					 rotation *= -1;
					 pendulumswing();
				});
			}

			init();
	});
})(jQuery);
</script>

There’s two variables; ‘rotation’ which sets how high the pendulum should swing and ‘swingtime’ which is the length it takes to complete one swing. The init function sets the initial position of the pendulum by instantly rotating it to it’s start position (before displaying it) and the swing function which is called at the start of each swing, reversing the direction of the rotation as it does so.

Important to note that the rotation transformation is not compatible with Internet Explorer 8 and below or really old versions of Safari and FireFox. As these older browsers are declining in market share, I’m seeing more of these kinds of transformations being used. One of the best examples for pivot point animation is how Apple use CSS3 transformations on their iPhone page to create great transitions, which uses plenty of images rotating around pivot points. If you try this in IE 8 however, a standard slider appears instead.

Update: FireFox 16 handles JS transformations differently, so if your jQuery animated rotations are greatly exaggerated, you should try updating to the latest version of the plugin: https://github.com/zachstronaut/jquery-animate-css-rotate-scale

Update 2: A strange bug has sometimes been causing the pendulum to freeze occasionally mid-swing. This can be fixed by changing the ‘swningtime’ variable to an odd number – e.g. 1603 instead of 1600. Not 100% sure why this occurs but probably has something to do with the rotational calculations being set to zero between the positive and negative rotational swing.

Update 3: Added a ‘swings’ variable to get the pendulum to come to a rest after a certain number of swings.



44 Comments

  • Angie says:

    This was exactly what I needed. Thank you!

  • John says:

    Many thanks for this, but how might I invert the pendulum – that is move the pivot point to the bottom, so that we have an effect like flowers on stems swaying in the wind.
    Thanks

  • Tom Elliott says:

    Hi John,

    The best way to invert the pendulum and change the pivot point would be to move the child DIV in relation to the pivot point parent. In the demo above, if you change the CSS for “top” for #pendulum-child to a negative value, such as -400px, that should do the trick. You may also need to move the parent container down.

    Tom

  • John says:

    just what I needed thanks

  • Kevin says:

    Nice work, keep going!

    But i’ve a question, how can I make the time infinity?

    I tried to set this more milliseconds;
    $(‘#divname’).animate({rotate: 20},2000, “swing”);

  • Amrita says:

    Awesome… got it to work… just need to put in my own images now…
    As they say, one can never have enough. I was wondering if i could have like multiple pivot points … one pivot point per child so it could llook like parallel pendulums (i hope that makes sense) but KUDOS !!

    Thanks,
    Amrita

  • Rohit says:

    this the best one.

    but it suddenly stops swinging. in all browsers

    probably it also needs jquery easing plugin. i used it and it worked for me

    • Tom Elliott says:

      Thanks for pointing out this problem Rohit.

      I was able to replicate the bug and what fixed it for me was to change the time per swing to an odd number. I did first try and use the Easing plugin as you suggested but that didn’t work for me.

  • Dhruv says:

    Hey Tom,
    How would you stop the pendulum in the middle of its movement?
    Thanks,
    Dhruv

    • Tom Elliott says:

      Hi Dhruv,

      Good question, I would be tempted to create a couple more variables at the beggining, e.g.
      var totalswings = 10;
      var currentswing = 0;
      then to stop the pendulum swing after a certain number of swings, replace line 18 in the javascript code above with:
      currentswing++;
      if (currentswing <= totalswings) { pendulumswing(); }

  • Dhruv says:

    Hi Tom,
    Dhruv again. Thanks for answering my question, but I realized I intended to ask something else. Would it be possible to stop the pendulum in the middle of its swing, at a certain radius?
    For example:
    In my code the person presses the spacebar, and the pendulum is supposed to stop exactly at the radius it was at the time he pressed it.
    How would I do that?
    Thanks,
    Dhruv

    • Tom Elliott says:

      Hi Dhruv,
      Ah, no problem – to stop the animation of the pendulum instantly, you can use “$(‘#pendulum-parent’).stop();” – I’ve updated the code in the demo to include a button.
      Hope that helps
      Tom

  • esther says:

    Hi
    Great work! Really what I needed.
    Only one little thing I don’t know how to fix it. I would like the pendulum slows down and stops slowly automatically after appr. 5 swings.
    Can you help me?
    tnx a lot!
    Esther

  • hi tom.

    wants to control pendullum swing time on bahalf of user define value .please suggest me how i will do that .???

    • Tom Elliott says:

      Hi Anoop,

      Have you tried changing the variable of ‘swingtime’ below to a different value? This should either speed up or slow down the time it takes for the pendulum to swing.

      • Hey Tom …

        I have another problem, actually i want to start pendulum from centre(Means from pivot point). Please help me in this matter as soon as possible.

        • Tom Elliott says:

          Hi Anoop,

          Iโ€™ve updated the code in the demo above to allow the option to start the pendulum swing from the centre. Setting โ€˜startatcentre = falseโ€™ will disable this.

          Hope that helps! ๐Ÿ™‚

  • Hi Tom

    I have another problem.I want to start the movement of pendulum from the pivote point,neither from left or right.
    Please suggest me what should we do now.

  • webmistress says:

    This is awesome, Tom! Just what I’ve been looking for!

    I’m initiating the animation on hover, which works well, except the animation seems to begin at the rotation degree. Like from the side? So it jumps on mouseover straight to ninety degrees. Is there any way to start the animation from the still state, instead? So that it begins swinging up, instead of down?

    Thanks!

  • Brian says:

    Hi, I modified this so that it’s a clickable interaction with 4 different ‘spokes’. Just wondering if you knew a way to modify the code so that it could go backwards to it’s starting position? That way if I click one, the others will go back.

  • Joey says:

    Hi Tom,
    Thanks for the great plugin, works great!
    I was wondering if you can help – while navigating with my menu which also uses jquery for animation and going back to the animation (all same page) the animation gets fucked up and becomes jagged…you can try to reproduce it here:
    http://192.241.187.47/test/

    Thanks a lot,
    Joey

  • Joey says:

    Hi Brian thanks for the great plugin
    I have few problems perhaps you could help…
    http://192.241.187.47/test/

    I have duplicated the plugin to work on 7 divs, its moving and all is good
    but at the 1st few seconds there’s a jump in the motion, and also I couldnt make it loop infinite

    help please
    Joe

  • Tech Pro says:

    This was exactly what i was looking for, Thanks a lot. Great post.

  • Tech Pro says:

    I ended up using just CSS3 to get that pendulum effect. Visit my technology page and hover over the title.
    http://www.ashishdesai.com/#/tech. You can achieve it using just CSS Transform and rotations.

  • mark says:

    Awesome effect! Instead of starting the swing on $(document).ready, is there anyway i can initialize it when I hover over the container, maintaining the correct # of swings, swingtime, etc once initialized?

    Thank you!

    • Tom Elliott says:

      Hi Mark. Thanks, yeah – to start the pendulum swing on hover, you could do something like:
      $('#demo-container').hover(function(){
      init();
      });

      and then remove the init line from within document ready. ๐Ÿ™‚

      • mark says:

        Many thanks, Tom. I think I’m missing something from the “remove the init line from within document ready” …. everything I try just makes the pendulum disappear.

        If I simply remove the hover additions it will work onLoad.

  • mark says:

    Hi Tom, I finally got it working by changing the ‘display’ css of #pendulum-parent to ‘block.’

    I have no idea why this would make a difference on a hovering div, as I made no further changes to init(), but it works.

    Thank you!

  • Rakesh Shetty says:

    Hi, Can I change the direction of swing? For eg, if i want to swing the pendulum starting from right and then left what changes I have to do? Now it starts swinging from left to right.

  • Renun says:

    Is there a way to make it use mobile devices accelerometer instead of a preset swing?

  • Jimmy says:

    Hey Tom,

    Amazing work you’ve done here! I know it’s been a while since you posted this – however I was wondering if I could still get some assistance?

    I want to make this function run only whenever the user scrolls the page. I have tried ‘$(window).scroll(function(‘ with mixed, less than desirable results. I normally have someone else doing JS for me so I’m more of a beginner – any help would greatly be appreciated!

    Thanks ๐Ÿ™‚

    • Tom Elliott says:

      Hey Jimmy. Thanks! I think the issue with trying to get the swing to work on scroll would be the function that fires the pendulum would be triggered multiple times during scroll. The best way I think would be to trigger the swing function once – perhaps by adding a boolean variable within the scroll function: if (initialscroll == false) { pendulumswing(); } initialscroll = true; for example – and then after say a second has elapsed with no further scroll, stop the swing. Hope that made sense ๐Ÿ™‚

      • Jimmy says:

        Hey Tom,

        Thanks so much for your response, sir. I actually feel really embarrassed to say I’m not entirely sure how to effectively implement the boolean variable for this particular script. I have more or less used the current JS script on the demo. I set the ‘var initialscroll = false;’ and immediately below this have done ‘if (initialscroll == false) { pendulumswing(); } ‘. At what point do I add “initialscroll = true;’?

        Again apologies if this is a hassle. To be honest I LOVE what JS can do… I just find it intimidating – particularly as I haven’t had a whole lot of time to invest myself in it as of yet.

        Thanks so much for your efforts.

        • Tom Elliott says:

          Hi Jimmy, no problem – if you put the initial var initialscroll = false; variable right after the rotation and swingtime variables and then the code if (initialscroll == false) { pendulumswing(); initialscroll = true; } within the $(window).scroll(function(‘… function you already have. Hopefully that will mean the pendulumswing function will get executed once (but it’s hard to know or sure without testing). Hope that helps ๐Ÿ™‚

          • Jimmy says:

            Hi Tom,

            I cannot thank you enough for your support. I’m still having an issue however. It KIND OF works, though it’s a bit “glitchy”. I was wondering if you could check out the link below to see where I’m going wrong? I would be more than happy to pay you for your efforts!

            http://www.thebludgeoner.com/test/

            Thanks very much ๐Ÿ™‚

  • Newbie says:

    Hi Tom,

    is it possible to make on hover the pendulum swing faster?

  • alahda says:

    Awesome effect! Instead of starting the swing on $(document).ready, is there anyway i can initialize it when I hover over the container, maintaining the correct # of swings, swingtime, etc once initialized?

    Thank you!