• RSS
  • Print this article!
  • Digg
  • del.icio.us
  • DZone
  • Facebook
  • Mixx
  • Google Bookmarks
  • Design Float
  • Reddit
  • StumbleUpon
  • Technorati
  • Live
  • TwitThis
Home > CSS, Front End Development, HTML, Javascript > How to Create a 3D Tag Cloud in jQuery

How to Create a 3D Tag Cloud in jQuery

August 10th, 2009

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.

3d tag cloud

 

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.

speed

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)

degrees

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.

3d

 

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>

 

 

  • RSS
  • Print this article!
  • Digg
  • del.icio.us
  • DZone
  • Facebook
  • Mixx
  • Google Bookmarks
  • Design Float
  • Reddit
  • StumbleUpon
  • Technorati
  • Live
  • TwitThis
Author: Shawn Categories: CSS, Front End Development, HTML, Javascript Tags: , ,
  1. August 13th, 2009 at 15:09 | #1

    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

  2. August 13th, 2009 at 19:55 | #2

    You’ll have to handle that with your back end, and have it output the list you need.

  3. August 14th, 2009 at 09:54 | #3

    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.

  4. Jon
    August 14th, 2009 at 12:13 | #4

    @Jason Denizac
    Doing this with… what?

  5. Uday
    August 14th, 2009 at 12:31 | #5

    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 :-)

  6. Kotonoha
    August 15th, 2009 at 00:25 | #6

    @Jon

    …Flash obviously

  7. August 15th, 2009 at 09:23 | #7

    @Uday
    It is possible to change shapes, it’s a little more involved though. Perhaps I’ll write a post exploring other shapes.

  8. August 16th, 2009 at 10:20 | #8

    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”) ?

  9. August 16th, 2009 at 11:12 | #9

    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.

  10. teddy
    August 26th, 2009 at 06:53 | #10

    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

  11. Kolyan
    August 26th, 2009 at 18:57 | #11

    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

  12. August 26th, 2009 at 23:36 | #12

    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.

  13. August 28th, 2009 at 07:46 | #13

    @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.

  14. August 29th, 2009 at 13:28 | #14

    @jon doing it with the [canvas] element. Apparently this comment system does not like me typing in angle brackets.

  15. teddy
    August 30th, 2009 at 22:38 | #15

    wow,.its works thanks Shawn,..
    but i wanna ask again :)
    how can i reduce the font size ?

  16. August 30th, 2009 at 22:54 | #16

    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.

  17. teddy
    August 30th, 2009 at 23:18 | #17

    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

  18. September 12th, 2009 at 12:27 | #18

    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.

  19. September 14th, 2009 at 22:04 | #19

    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.

  20. November 11th, 2009 at 12:31 | #20

    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 :)

  21. November 11th, 2009 at 12:34 | #21

    oh~~the message~

    1
    2
    3
    4
    5
    6
    <div style="height:500px"></div>
    <div id="list">
    <ul>
    <li>this's a list</li>
    </ul>
    </div>
  22. November 11th, 2009 at 13:39 | #22

    i come again~~:)

    this’s my test demo:http://naoyeye.appspot.com/themes/default/images/Test_3D_Tag_Cloud_in_jQuery.html

  23. John Kwiatecki
    November 16th, 2009 at 20:18 | #23

    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.

  24. November 23rd, 2009 at 11:43 | #24

    Nice! we’re using cumulus but might give this a try instead

  25. November 26th, 2009 at 13:18 | #25

    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

  26. November 27th, 2009 at 15:45 | #26

    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

Comments are closed.