How to Create a 3D Tag Cloud in jQuery
With browsers rendering JavaScript faster than ever before, it’s a great opportunity to get creative with jQuery. This tutorial will show how to create a scrolling 3D tag cloud…it’s not as difficult as you might think.
3D Tag Clouds..Oh My
What exactly will we be building? It’s somewhat like a carousel, but we’re going to have the take fade off into the distance like the lone ranger at the end of cheesy “B” western flick….very dramatic.
We’re also going to have our tag cloud interact with the users mouse. The further the mouse is away from the center, the faster it will rotate.
Simple HTML
As the sub title suggests the HTML is painfully simple. Most of the complicated stuff is in the jQuery. All we’ll need is a list of anchor tags wrapped in a div. Told you it was simple, here is the HTML.
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 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>jQuery 3D</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="list"> <ul> <li><a href="#">ajax</a></li> <li><a href="#">css</a></li> <li><a href="#">design</a></li> <li><a href="#">firefox</a></li> <li><a href="#">flash</a></li> <li><a href="#">html</a></li> <li><a href="#">Devirtuoso</a></li> <li><a href="#">jquery</a></li> <li><a href="#">PHP</a></li> <li><a href="#">SEO</a></li> <li><a href="#">usability</a></li> <li><a href="#">www</a></li> <li><a href="#">web</a></li> <li><a href="#">xhtml</a></li> </ul> </div> </body> </html> |
Styling the List
For the most part the CSS is just to make the links pretty. There are a couple of things that need to happen though. The anchor links need to have a position: absolute. This way the jQuery can give it x and y co-ordinates and the links will obey. Also we need to give a height and width of the div wrapper. The jQuery reference the dimensions of the wrapper to help layout the links. It might also be a good idea to give the wrapper a position:relative to keep the links inside the wrapper, this isn’t necessary though.
Here is the CSS:
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 | /* Set font and background for body*/ body{ font-family: Arial, "MS Trebuchet", sans-serif; background-color: #111; } /* Styles the div wrapper the important part is the width and the height */ #list{ /*Influences layout of list*/ height:600px; width:600px; background-color: #000; /* Keeps list inside of wrapper*/ position:relative; margin:0 auto; overflow:hidden; } /* Reset the list*/ #list ul, #list li{ list-style:none; margin:0; padding:0; } /* List requires an absolute position so jQuery can move the items around freely */ #list a{ position:absolute; text-decoration: none; color:#666; } #list a:hover{ color:#ccc; } |
The Fun Part (jQuery)
Now comes the trigonometry….see…your high school teacher was right, you will use this stuff in the real world. It really isn’t that bad though…3 lines of trigonometry is more than acceptable. I’m not going to go into great detail with the math. If you want to learn more about the math behind the 3D I recommend reading Kirupa.com tutorial on it. The tutorial is for flash, but you will get the gist of how it works.
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 57 58 59 60 61 62 63 64 65 66 67 68 69 | $(document).ready(function(){ //Setup variables var element = $('#list a'); // all the list elements var offset = 0; // angle offset for animation var stepping = 0.03; // how fast the list rotates var list = $('#list'); // the list wrapper var $list = $(list); /* Handles mouse movement, the closer to the center the faster the list will rotate */ $list.mousemove(function(e){ var topOfList = $list.eq(0).offset().top var listHeight = $list.height() // Sets variable that controls the speed of rotation. stepping = (e.clientY - topOfList) / listHeight * 0.2 - 0.1; }); /* Disperse elements evenly around the circle */ for (var i = element.length - 1; i >= 0; i--) { element[i].elemAngle = i * Math.PI * 2 / element.length; } // call render function over and over setInterval(render, 20); // Handles how and where each element will be rendered. function render(){ //Steps through each element... for (var i = element.length - 1; i >= 0; i--){ // offset adds degrees to where the element // is currently on the circle var angle = element[i].elemAngle + offset; // Trig to figure out the size and where the // text should go x = 120 + Math.sin(angle) * 30; y = 45 + Math.cos(angle) * 40; size = Math.round(40 - Math.sin(angle) * 40); // Centers the text, instead of being left aligned. var elementCenter = $(element[i]).width() / 2; // Figure out the x value of the element. var leftValue = (($list.width()/2) * x / 100 - elementCenter) + "px" // Apply the values to the text $(element[i]).css("fontSize", size + "pt"); $(element[i]).css("opacity",size/100); $(element[i]).css("zIndex" ,size); $(element[i]).css("left" ,leftValue); $(element[i]).css("top", y + "%"); } // Rotate the circle offset += stepping; } }); |
Just to step through what we did. First we setup the mouse event. We figure out how far the mouse is away from the center and assign it to a variable that controls the speed of the scrolling list.
After that we step through each element in our list and give each one a spot on our 3D circle. A for loop walks through each one, and evenly assigns an angle to each element. (e.g. 1st = 0 degrees, 2nd = 5 degrees, 3rd = 10 degrees…etc)
After we placed each element on our 3D circle it’s time to animate it. We use a setInterval to call our render function repeatedly. The render function steps through each element and figures out where and how it should be displayed. The trigonometry basically creates a set of numbers that if you plot it on a graph look like a wave. If you apply those numbers to the size of the text, it gives the appearance of going back and forth in space. If you also apply these numbers to the y, this will give you the appearance that the text is going around in a circle. If you don’t understand the math inside this function not to worry. I encourage you to play around with the numbers to see how each number effects the outcome.
The Finish Line
That’s all there is to it. Here is the code all together so you can have a look. Enjoy.
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <title>jQuery 3D</title> <style type="text/css" media="screen"> body{ font-family: Arial, "MS Trebuchet", sans-serif; background-color: #111; } #list{ margin:0 auto; height:600px; width:600px; overflow:hidden; position:relative; background-color: #000; } #list ul, #list li{ list-style:none; margin:0; padding:0; } #list a{ position:absolute; text-decoration: none; color:#666; } #list a:hover{ color:#ccc; } </style> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="list"> <ul> <li><a href="#">ajax</a></li> <li><a href="#">css</a></li> <li><a href="#">design</a></li> <li><a href="#">firefox</a></li> <li><a href="#">flash</a></li> <li><a href="#">html</a></li> <li><a href="#">Devirtuoso</a></li> <li><a href="#">jquery</a></li> <li><a href="#">PHP</a></li> <li><a href="#">SEO</a></li> <li><a href="#">usability</a></li> <li><a href="#">www</a></li> <li><a href="#">web</a></li> <li><a href="#">xhtml</a></li> </ul> </div> <script type="text/javascript"> $(document).ready(function(){ var element = $('#list a'); var offset = 0; var stepping = 0.03; var list = $('#list'); var $list = $(list) $list.mousemove(function(e){ var topOfList = $list.eq(0).offset().top var listHeight = $list.height() stepping = (e.clientY - topOfList) / listHeight * 0.2 - 0.1; }); for (var i = element.length - 1; i >= 0; i--) { element[i].elemAngle = i * Math.PI * 2 / element.length; } setInterval(render, 20); function render(){ for (var i = element.length - 1; i >= 0; i--){ var angle = element[i].elemAngle + offset; x = 120 + Math.sin(angle) * 30; y = 45 + Math.cos(angle) * 40; size = Math.round(40 - Math.sin(angle) * 40); var elementCenter = $(element[i]).width() / 2; var leftValue = (($list.width()/2) * x / 100 - elementCenter) + "px" $(element[i]).css("fontSize", size + "pt"); $(element[i]).css("opacity",size/100); $(element[i]).css("zIndex" ,size); $(element[i]).css("left" ,leftValue); $(element[i]).css("top", y + "%"); } offset += stepping; } }); </script> </body> </html> |


















This is great, thanks! Is there a way to dynamically use the most used words on the page instead of using a static UL?
Thanks again
You’ll have to handle that with your back end, and have it output the list you need.
Nifty plugin, for sure, and a good explanation of your thought process. However, using DOM elements for animation like this is a little choppy. Notably, you don’t get granular enough font sizing. Doing this with would result in smoother animation for modern browsers.
@Jason Denizac
Doing this with… what?
i was wondering if it is possible to change the geometry to a sphere rather than a circle?
i tried to but looks like my math is poor
@Jon
…Flash obviously
@Uday
It is possible to change shapes, it’s a little more involved though. Perhaps I’ll write a post exploring other shapes.
Great idea, great article and great plugin.
Can I translate it in italian language ad insert it into my site with a link to your (with a string similar to “Original text: xxxxxx”) ?
Hey Michel,
First off, thank you for asking, some people just go ahead and do it. I have no problem with you translating it. If it will help more people I’m all for it.
hi I like to make 3D tag cloud in 300 – 300 scale
but when my mouse begin to touch..
that LIST begin rolling crazy,..and can not stop
what should i do ?
pls help me out
Great share! Very artistic and useful.
And as usual, the question: how to make things horizontal, just like Lee Brimlow’s “3DCarusel “(http://www.gotoandlearn.com/play?id=32)?
I was looking for kinda “banner”-style, something 700×180.
Could you point in this jQuery gibberish stuff the point of Math where I could swap some numbers?
Thanks
well…in the part where it sets the css, just switch top and left. So the top is getting the x, and the left is getting the y. This will turn it on it’s side. In the render() function you’ll have to switch where ever it says width() to height(), this lines up all the elements. You’ll also have to deal with the mouse. Right now it works with your mouse moving up and down. To switch it so it’s left and right, in the mousemove function switch out offset().top to offset().left, and switch out height() with width(). You’ll still have to play around with some numbers to get it to fit in a banner, this is a good start though.
@teddy
Under the mousemove function you could probably divide the stepping variable by some number (stepping = stepping / 2) and that should reduce the sensitivity of the mouse. I haven’t tested this out, but in theory I think it should work.
@jon doing it with the [canvas] element. Apparently this comment system does not like me typing in angle brackets.
wow,.its works thanks Shawn,..
but i wanna ask again
how can i reduce the font size ?
The line : size = Math.round(40 – Math.sin(angle) * 40);
You can just change the * 40 to a lower #. So something like:
size = Math.round(40 – Math.sin(angle) * 20); Just a note, the size variable is also used for the opacity. So you might want to create a separate variable for the opacity.
YEeeesss,….done and great
only now i’ve to adjust the direction of TEXT scrolling
sometime they just wanna goes up and wont back again lol
hello shawn…:-)…i wanna ask you something about the sensibility of the mouse and the speed of rotation. how can i reduce the speed? what’s the line in jquery to change?marco from roma.
Hey Marco.
On line 18 you’ll see
stepping = (e.clientY – topOfList) / listHeight * 0.2 – 0.1;
This is the line that affects the speed. If you play around with the 0.2 – 0.1 you should be able to get it less sensitive.
hello,i’m from China~~
I found if there’s a on the top of #list,then get an error,path wrong.
try this:
ajax
css
design
firefox
flash
html
Devirtuoso
jquery
PHP
SEO
usability
www
web
xhtml
Thanks for your code
oh~~the message~
2
3
4
5
6
<div id="list">
<ul>
<li>this's a list</li>
</ul>
</div>
i come again~~:)
this’s my test demo:http://naoyeye.appspot.com/themes/default/images/Test_3D_Tag_Cloud_in_jQuery.html
I have found a completely free (including commercial websites) tag cloud script written in PHP on http://www.softwaremastercenter.com/free-tag-cloud-generator-script.html, I like it because it let’s me configure how links in the tag cloud are built and it filters out common words – if you inspect the code they provide you will see maybe a thousand of common words. For fact, I have actually added more words to it. The styling options are pretty decent. Good free stuff.
Nice! we’re using cumulus but might give this a try instead
I just want to say Thanks! A great little script. I’m learning what I can about Ajax, jQuery etc and having something like this is a great tool to help me learn: one the one hand, it works straight out of the box and will be a neat little addition to my blog/site, but your explanation is enough to sort of make me understand what’s going on, but I’ll play some and try and really understand what’s happening.
Thanks again,
Jeff
Very good plugin, I am going to use it on my website LocalBooking.com
I just fixed a small bug occurring when there is a scrollbar in the window. If you scroll down and you move the mouse down the list keeps going up. You can try it in your example by reducing the size of the window.
Just change your line 18 by adding jQuery(window).scrollTop()
stepping = (e.clientY + jQuery(window).scrollTop() – topOfList) / listHeight * 0.2 – 0.1;
Cheers
Damien