mike's web log

 

Blog Search


(Supports AND)

 

Google Ads

 

Technorati

 

Feed

Subscribe to the RSS feed for this blog.

See this post for info on full versus truncated feeds.

 

Quote

Nature is cruelly parsimonious with pleasure.

Cocaine.org



 

Navigation






<September 2010>
SMTWTFS
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789


 

25 Most-Visited Entries

 

Categories

  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
  RSS
 

Blogs I Read

 

Contact

Email me
 

Blog Statistics

Dates
First entry - 6/27/2003
Most recent entry - 8/26/2010

Totals
Posts - 2109
Comments - 2170
Hits - 1,138,425

Averages
Entries/day - 0.80
Comments/entry - 1.03
Hits/day - 434

Update every 30 minutes. Last: 6:46 PM Pacific

 
   |  Tag cloud control

posted at 11:37 PM | | [5] |

I recently decided to implement a tag cloud. I'm not quite sure why this grabbed me; I don't pay that much attention to them my own self. But the idea of how to do it interested me, so I gave it a bash as an ASP.NET custom Web server control[1]. I don't need a tag cloud control, and I bet that if you need one, you already have one. Basically, this was just a fun exercise for me.

Demo here: Tag Cloud Control Demo
Source code here: TagCloud control source code

In a tag cloud, the various tags are displayed in a font size that's proportional to how many times the tag is used. A tag that's used a lot is big; a tag that's seldom used is small. Who knew, there are various ways to calculate this spread of font sizes. I ended up using an algorithm that I think (?) I found on a PHP site, I forget exactly.

This is what it looks like. This isn't live; to see a live one, go to the demo.



The control feeds off a list of items that contain a tag name and a tag count. How this list is generated would be, as they say, left as an exercise for the reader. I wrote the code so that it expects something that can be cast to IEnumerable. I played with it two ways. One was to create instances of a TagItem class (conveniently provided by myself) and stick them into a List<T> generic list (VB: List (Of T)) or an ArrayList object, both of which worked. I also was able to successfully give it a DataView object. Beyond that, no guarantees. :-) (Note that as of yet, I didn't implement this as a control that can do normal ASP.NET data binding. That'll be a v2.0, assuming I get that far.)

Given this list, the algorithm determines a total tag count and the highest and lowest tag count values. Imagine you have three tags: aspnet, used 100 times; books, used 40 times; and movies, used 20 times. Total tag count = 160; hi = 100; lo = 20. The tag range is 80.

The code then calculates a weight for each tag item. The weight represents where on the scale of lowest to highest tag count a specific tag item lies. The, um, formula is this:

weight = (itemTagCount - tagCountLo) / tagCountRange

For the example tags:

aspnet: (100 - 20) / 80 = 1.0 (Notice that the high is conveniently always 1)
books: (40 - 20) / 80 = .25
movies: (20 - 20) / 80 = 0.0 (Notice that the low is conveniently always 0)

The weight value is then mapped to the range of font sizes that you want to use. Suppose you decided that the tag cloud would display fonts between 8 and 24 points; the font size range is therefore 16. The formula for using the weight to get the font size would be:

fontSize = (weight * fontSizeRange) + minimumFontSize

For example:

aspnet: (1.0 * 16) + 8 = 24 (look, it's the highest possible font size)
books: (.25 * 16) + 8 = 12
movies: (0.0 * 16) + 8 = 8 (look, it's the lowest possible font size)

I would not be surprised to learn that there are better ways to calculate these relative font sizes. However, I don't think it matters that much ... the important issue is to have a roughly proportional difference in the font sizes. (This is also the point where a number of people point out to me that I could actually have done this in, like, 2 lines or something.)

Since I was doing this as a control, I exposed various properties. These include:
  • TagList (IEnumerable). A list that you provide that contains objects that in turn contain the tag names and tag counts. If you're stuck for objects to use, you can use the MikesControls.TagItem class to create individual tag items.
  • MinimumFontSize, MaximumFontSize (int).
  • IsHyperlink (Boolean). true (default) to create the tags as Hyperlink controls; false to create them as Label controls.
  • HyperlinkFormat (String). A format string (e.g. "?tag={0}") that's used for the NavigateUrl property if the tag is created as a Hyperlink control.
  • HyperlinkData (enum). Specifies whether the tag display uses the tag name (default) or tag count. Probably not a useful property, much.
  • TagNamePropertyName, TagCountPropertyName (String). The names of the properties in the tag item objects that are in the tag list. The control assumes it can find the tag name in a property named "tagName" and the tag count in a property named "tagCount". But maybe you have a list of objects with different property names.
  • TagCssClass (String). Name of the CSS class that should be applied to each tag control, whether it's a Hyperlink or Label control. This avoids having the control emit a bunch of style junk.
  • DisplayFormat (enum). Whether to create a cloud (separated by spaces) or list (separated by line breaks).
So that was fun for a little while. If I get motivated, I'll reimplement it with proper data binding, which of course is more complex, but more flexible. In the meantime, I might even add this to the blog, who knows.


[1] This is, like, so 3 years ago, eh? No AJAX, no LINQ, no asynchronous nuthin'.

[categories]