Read previous entries:
Last article give you recommendation that the number of tags shown in a tag cloud should be limited. However, some people might have difficulty to adjust this number of tags. They probably deal with a fixed space, where the tag cloud has to be adequate in the space. If I may say, other tag cloud providers just forget about this problem and change their site design so that they don’t have to deal with this problem.
So what they actually do? Most of the cases they will let the height to be variable, while the width can be exactly defined. Take two examples from Technorati and Flickr:
All of the above solutions doesn’t have to do with fixed space. However, some rare cases might have to deal with this problem. Let we examine why this is not easy…
- We don’t know how big is the tag cloud before it is rendered to the screen, because the size of the words in the tag clouds are also undetermined until they are displayed.
- If we pick too small value, the space will be looked like empty, but if we pick too big value, it will break the design.
- Removing one tag may change the whole structure of tag cloud, since the maximum value and minimum value of occurence can be changed. Thus… the size of every tags hav to be recalculated.
I have a solution for this, it has been tested and it works pretty good. See the screenshot below for a teaser. The actual number of tags available send by the server is bigger than what is shows.
Here is my solution:
- Prepare the space. Set the width as you want and set the minimum height as you want. This is important, I will explain the reason later…
- Now, render the tag cloud in the space.
- After the tag cloud is rendered correctly to the screen, check the offset height by getting it from JavaScript. This is why we need to set the minimum height, and not the height. We can’t easiliy detect that overflow happens if we just set the height.
- If it is too big, re-render the tag cloud, but decrease the number of tags until it fit the space.*
The step marked by * will probably take some times if the algorithm is not right. One good solution for this is by using search algorithm for ordered list so called “divide-and-conquer”. You probably can find better algorithm for this.
The algorithm is pretty complicated and you have to code it with JavaScript (because it is done in the user screen). Otherwise, you can use Google Web Toolkit and code the solution with Java. This is my Google Web Toolkit solution (one remark: tags is ordered by its occurences):
package i5.prolearn.calp.ple.client;
import java.util.Collections;
import java.util.HashMap;
import java.util.Vector;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
public class TagCloud extends Composite {
private FlowPanel panel;
private String[] tags;
private int[] occur;
private HashMap tagOccur = new HashMap();
private Vector tagLeft = new Vector();
private int minSize;
private int maxSize;
public TagCloud(String[] tags, int[] occur, int minSize, int maxSize) {
this.tags = tags;
this.occur = occur;
this.minSize = minSize;
this.maxSize = maxSize;
if (tags.length != occur.length) {
System.err.println("Error");
return;
}
panel = new FlowPanel();
for (int i = 0; i < tags.length; i++) {
HTML tag = new HTML(tags[i] + " ");
tag.setStyleName("ple-HtmlTagCloud");
panel.add(tag);
}
initWidget(panel);
}
protected void onAttach() {
super.onAttach();
int nbOfTags = tags.length / 2;
int minRange = 0;
int maxRange = tags.length;
int j = 0;
do {
computeTagCloud(tags, occur, nbOfTags);
panel.clear();
for (int i = 0; i < tagLeft.size(); i++) {
HTML tag = new HTML(
"<a style=’font-size:"
+ (((Integer) tagOccur.get(tagLeft.get(i)))
.intValue() + minSize) + ";’>"
+ tagLeft.get(i) + " </a> ");
tag.setStyleName("ple-HtmlTagCloud");
panel.add(tag);
}
if (getParent().getOffsetHeight() > 250) {
maxRange = nbOfTags;
} else {
minRange = nbOfTags;
}
if (maxRange - minRange <= 1) {
break;
} else {
nbOfTags = minRange + ((maxRange - minRange) / 2);
}
j++;
} while (j < 6);
}
private void computeTagCloud(String[] tags, int[] occur, int length) {
int max = 0;
int min = 10000;
for (int i = 0; i < length && i < tags.length; i++) {
if (occur[i] > max) {
max = occur[i];
}
if (occur[i] < min) {
min = occur[i];
}
}
int[] size = new int[maxSize - minSize + 1];
for (int i = 1; i < maxSize - minSize + 1; i++) {
size[maxSize - minSize + 1 - i] = max
- (((max - min) * i) / (maxSize - minSize + 1));
}
size[0] = min;
tagOccur = new HashMap();
tagLeft = new Vector();
for (int i = 0; i < length && i < tags.length; i++) {
for (int j = maxSize - minSize; j >= 0; j–) {
if (occur[i] >= size[j]) {
tagOccur.put(tags[i], new Integer(j));
tagLeft.add(tags[i]);
break;
}
}
}
Collections.sort(tagLeft);
}
}
[continue to the next section (not available yet)]

I tried it but only the first tag showed up, could you give us a sample set of parameters?
Uhm … there still a problem though. What if there are not enough tags to fill all of the predefined space? The tagcloud still look kinda empty.
Ken: then make the predefined space smaller
Is there something specific required to get this to work. I created this class within my client package and tried to instantiating the TagCloud tc = new TagCloud(a[], y[], b, c);
But when GWT loads up in hosted mode it throws an error saying TagCloud cannot be resolved.
Hello
I am Lucy, I have found your website while searching for some info at Google. Your site has helped me in a big way.
Bye
I have the same problem. only 1 tag shown. Still experimenting with the parameters and css too. No luck.