Creating a Wobbling 3D Carousel
We’ve all seen a carousel in one form or another. This post will show how to create a carousel with a wobbling effect, much like an unbalanced wheel.
What We’re Building
We’ll be creating a carousel with the help of the 3d Engine we built in a previous post. The idea is we’ll create a ring by plotting points in 3d space, then we’ll rotate it so it’s almost perpendicular to the viewer. Because it’s not 100% flat, it will look like it’s wobbling up and down, giving your carousel a little more flavor.
Building the Ring
If you haven’t read up on the 3d Engine just yet I recommend you do so. Creating objects for the engine isn’t overly complicated. It’s just an array of 3d points. With the ring, we’re going to use math to plot the points for us. We’re going to be creating a circle and plot it in 3d space.
Here is the JavaScript: (Ring.js)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var Ring = function (radius, numOfItems){ //Step through each point on ring. for (var i = numOfItems - 1; i >= 0; i--) { //Figure out where each point lies on the circle var angle = i * Math.PI * 2 / numOfItems; //Translate that point on the circle into x,y coordinates. var x = Math.sin(angle) * radius; var y = Math.cos(angle) * radius; var z = 0; //Add the point to the array. this.pointsArray.push(this.make3DPoint(x,y,z)); } }; //You need to inherit the DisplayObject3D. Ring.prototype = new DisplayObject3D(); |
The Ring class takes 2 parameters, the first is the radius of the ring, and the second is how many items are going to be on the ring.
We then proceed to step through all the points, and place them at equal distances around the ring.
The HTML
There isn’t much too the html. We’re simply going to create a <ul> with a bunch of words in it.
Here is the HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
The jQuery
There is not much changed from our previous post on how to create a 3d plane for jQuery 3D Engine. The only difference here is we’re going to give an initial value to the axisRotation x value. This will rotate the ring towards the viewer. Through trial and error I figured out the value that worked for me.
Then we’ll animate the axisRotation y value when the mouse moves left and right.
Here is the jQuery:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | $(document).ready(function() { //setup camera. var camera = new Camera3D(); camera.init(0,0,0,300); var container = $("#item"); //Setup 3d object holder. var item = new Object3D(container); //Add ring to 3d object holder. //The first argument for the ring is the radius. //The second argument for the ring is how many items //are on the ring. So we pass in how many items are in our list. item.addChild(new Ring(200, $("#item ul li").length)); //Create a scene. var scene = new Scene3D(); //Add 3d object holder to the scene. scene.addToScene(item); var mouseX,mouseY = 0; var offsetX = $("#item").offset().left; var offsetY = $("#item").offset().top; var speed = 6000; //Capturing mouse movements. $().mousemove(function(e){ mouseX = e.clientX - offsetX - (container.width() / 2); mouseY = e.clientY - offsetY - (container.height() / 2); }); //Rotate ring so it's almost perpendicular to the viewer. axisRotation.x = 1.5; var animateIt = function(){ if (mouseX != undefined){ //When the user moves the mouse left and right, //rotate around the ring on the y axis. axisRotation.y += (mouseX) / speed; } scene.renderCamera(camera); }; setInterval(animateIt, 20); }); |
Voila!
That’s all there is too it.
Here is all the code together:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | <html> <head> <title>3d engine</title> <style type="text/css" media="screen"> #item{ width:100px; height:100px; margin:0 auto; top:300px; position: relative; } ul{ list-style-type: none; } body{ background-color: #111; color: #69c; font-family: Arial, "MS Trebuchet", sans-serif; font-weight: bold; font-size:1em; } </style> </head> <body> <div id="item"> <ul> <li>website</li> <li>jQuery</li> <li>JavaScript</li> <li>HTML</li> <li>PHP</li> <li>3D</li> <li>Ajax</li> <li>CSS</li> <li>Design</li> <li>Flash</li> <li>Experimental</li> <li>Development</li> <li>web</li> <li>Tutorial</li> <li>ASP</li> </ul> </div> </body> <script type="text/javascript" src="jquery-1.3.2.min.js"></script> <script src="3DEngine.js" type="text/javascript" charset="utf-8"></script> <script src="Ring.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> //<![CDATA[ $(document).ready(function() { var camera = new Camera3D(); camera.init(0,0,0,300); var container = $("#item"); var item = new Object3D(container); item.addChild(new Ring(200, $("#item ul li").length)); var scene = new Scene3D(); scene.addToScene(item); var mouseX,mouseY = 0; var offsetX = $("#item").offset().left; var offsetY = $("#item").offset().top; var speed = 6000; $().mousemove(function(e){ mouseX = e.clientX - offsetX - (container.width() / 2); mouseY = e.clientY - offsetY - (container.height() / 2); }); axisRotation.x = 1.5; var animateIt = function(){ if (mouseX != undefined){ axisRotation.y += (mouseX) / speed; } scene.renderCamera(camera); }; setInterval(animateIt, 20); }); //]]> </script> </html> |
Ring.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var Ring = function (radius, numOfItems){ for (var i = numOfItems - 1; i >= 0; i--) { var angle = i * Math.PI * 2 / numOfItems; var x = Math.sin(angle) * radius; var y = Math.cos(angle) * radius; var z = 0; this.pointsArray.push(this.make3DPoint(x,y,z)); } }; Ring.prototype = new DisplayObject3D(); |
Just a small tip. If you wanted to create a carousel that doesn’t wobble, your first instinct might be to adjust the axisRotation x value until you get it. You can do it this way, it just might take a bit to get it right on the money. The easier way is to adjust the Ring.js file, and switch the y and z values. This will create a totally flat ring and you don’t have to worry about using the axisRotation x value to try and flatten it out.


















WoW!! amazing
Thanks alot
Karar
Really cool effect!
It can be used with imaged instead of a text list???
In theory it should work. I’ve never actually tried. I’m curious to see the performance.
Fantastic!
Thank you for this greatest article!
Regards,
Marcio Wesley Borges
http://www.marciowb.net
Very nice. Really amazing!
I’ll use it at our website.
Thanks.
photofunny, This carousel works with images, but not at all, because Shawn’s 3D engine don’t uses z-index values for depth effect in render time, and this causes the carousel to look weird when the elements have different colors between them.
Shawn, As I need to do something similar to a carousel (only a section will be visible, so won’t look like a carousel) but with images, I tried to implement depth, but I can’t.
I changed renderCamera (near the end), getting depth value from screenPoints item, and trying to set z-index with DOM properties and/or jQuery css(), but doesn’t works…
Can you give me a clue?
Ha, forget about it, I get it! my code was ok, the problem was float numbers on z-index, I just round them, and now it works
I changed this:
[code]
Scene3D.prototype.renderCamera = function (camera){
...
currItem._y = screenPoints[k].y;
currItem._depth = Math.floor(screenPoints[k].depth); //line added
currItem.scale = screenPoints[k].scaleFactor;
...
$(currItem).css({opacity:(currItem.scale-.5)});
$(currItem).css('z-index',(currItem._depth)); //line added
...
[/code]
Shawn, Thanks for your engine!!!
Daniel Alvarado