Click here to Skip to main content
Click here to Skip to main content

Cloud Control for ASP.NET

By , 4 Jul 2006
 
Prize winner in Competition "ASP.NET Jun 2006"

Introduction

Web sites such as del.icio.us, Technorati, and Flickr, which allow tagging of their content, depict the popularity of tags using a tag cloud. The popular items have larger font sizes. This concept can be applied to any list of items where each item has an associated weight. For example, a list of products can be displayed in a cloud weighed by the cost of a product. Using the ASP.NET server control presented in this article, you can display your own domain specific items as a cloud. The image below shows a sample cloud for articles on Ajaxian.

sample image

Using the Control

This control works only with ASP.NET 2.0. First, you need to add a reference to the control assembly or the control project to your website. In the page you need to use the control, add the following declaration:

<%@ Register Namespace="VRK.Controls" TagPrefix="vrk" Assembly="VRK.Controls" %>

This will allow you to use the control in the page using the following declaration:

<vrk:Cloud ID="c1" runat="server" />

Now, you need to add items to the control. Each item will be displayed as a hyperlink on the page. You can supply the following properties for the items you want to add:

  • Text - The text of the hyperlink.
  • Href - The URL where the user will be navigated to when he clicks the hyperlink. If this property is left blank, the control causes a postback and raises the ItemClick event.
  • Title - The tooltip text of the HTML anchor.
  • Weight - The weight determines how the item will be displayed.

You can add the items declaratively, as shown:

<vrk:Cloud ID="c1" runat="server">
<Items>
   <vrk:CloudItem Text="Item1" 
      Href="Default.aspx?tag=Item1" 
      Title="Some title" Weight="4" />
   <vrk:CloudItem Text="Item2" 
      Href="Default.aspx?tag=Item2" 
      Title="Some title" Weight="4" />
</Items>
</vrk:Cloud>

You can also add the items programmatically:

c1.Items.Add(new CloudItem("Item1", 4, 
                           "Default.aspx?tag=Item1", 
                           "Some title"
                           ));

You can also use data binding to add items. First, you need to add a data source to your page. The code example below shows an ObjectDataSource, but you can use any ASP.NET DataSourceControl such as SqlDataSource or AccessDataSource.

<asp:ObjectDataSource 
   ID="ItemsSource" 
   runat="server" 
   SelectMethod="GetItems" 
   TypeName="CloudTest.ItemsSource" 
  />

You need to indicate to the cloud control that it needs to use the ItemsSource data source control by specifying its DataSourceID.

<vrk:Cloud ID="c1" runat="server" DataSourceID="ItemsSource" .... />

Once the data source is specified, you will need to indicate how the items should be populated from the data source. The following control properties can be used to supply the information:

  • DataTextField - the name of the data field that is bound to the Text property of an item.
  • DataTextFormatString - the format string for the Text property. {0} in the string is replaced with the value of the field from the data source.
  • DataHrefField - the data field which is bound to the Href property of an item.
  • DataHrefFormatString - the format string to format the Href property value.
  • DataTitleField - the data field which is bound to the Title property of an item.
  • DataTitleFormatString - the format string for the title (tooltip) of an item.
  • DataWeightField - the field in the Data Source from where the weight of an item is to be obtained.

The control then normalizes the weight of all the items so that they fit in the range 1 to 7. You can control the display of the normalized items using the optional ItemCssClassPrefix property. If you use the ItemCssClassPrefix property, you need to add seven different CSS classes to your HTML page. For example, if you specify the property value to be "Item", you need to specify the CSS classes Item1, Item2... Item7. If you don't specify the ItemCssClassPrefix, the font size CSS attribute is set depending on the weight, as follows:

Normalized Weight Font-size
1 xx-small
2 x-small
3 small
4 medium
5 large
6 x-large
7 xx-large

Now, let's examine how the control works.

How the Control Works?

The main logic is to convert the distribution of weights into a integral range between 1 and 7. After struggling with statistics for some time, I figured out the following algorithm for normalizing the weights:

  1. Compute the mean and the standard deviation (σ) of the weights. This is done using the functions from the Statistics class similar to the Math class.
  2. private IEnumerable<double> ItemWeights
    {
      get
      {
        foreach (CloudItem item in this.Items)
        {
          yield return item.Weight;
        }
      }
    }
    
    ...
    
    double mean; 
    double stdDev = Statistics.StdDev(ItemWeights, out mean);

    The StdDev function takes an IEnumerable<double> parameter which is supplied by the ItemWeights method.

  3. The weight factor is calculated according to the following formula:
  4. factor = (weight - mean)/(stddev)
  5. The normalized weights are obtained based on the following table:
  6. Normalized Weight Condition
    1 factor <= -2*stddev
    2 -2*stddev < factor <= -1*stddev
    3 -1*stddev < factor <= -0.5*stddev
    4 -0.5*stddev < factor < 0.5*stddev
    5 0.5*stddev <= factor < 1*stddev
    6 1*stddev < = factor < 2*stddev
    7 factor >= 2 * stddev

Once the normalized weights are obtained, it is easy to set the font sizes and the classes.

foreach (CloudItem item in Items)
{
  HtmlAnchor a = new HtmlAnchor();
  a.HRef = String.IsNullOrEmpty(item.Href) ?
  this.Page.ClientScript.GetPostBackClientHyperlink(this, index.ToString()) :
                   item.Href;
  a.InnerText = item.Text;
  a.Title = item.Title;
  int normalWeight = NormalizeWeight(item.Weight, mean, stdDev);
  if (hasCssClassPrefix)
  {
    a.Attributes["class"] = 
      this.ItemCssClassPrefix + normalWeight.ToString();
  }
  else
  {
    a.Style.Add(HtmlTextWriterStyle.FontSize, _fontSizes[normalWeight - 1]);
  }
  this.Controls.Add(a);
  this.Controls.Add(new LiteralControl(" "));
  index++;
}

The method seems to work reasonably well in most of the situations. Any suggestions to improve it further are welcome.

History

  • July 4, 2006 - First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rama Krishna Vavilala
Architect
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNice!memberSandeep Mewara27 Mar '10 - 5:03 
Its nice one!
Questionkeywords are shown in one linemembermanish_hwd11 Mar '10 - 2:23 
great thread, i am using linq to sql data source and pass weight and name through list basically i am returning list.keywords are shown in the page but it is show in one line . when i give static values from getitems() function like u are using works fine.
 
i am not able to break up the keyword line.it shows like
 
ab nn nn nn hh jj kk ll llmm ll tt ss ww aa www dd ddd ee ff gg tthh hh hh
 
not shows in second line.
Generalit's greatmemberernest_elias13 Jan '10 - 2:16 
thank you for sharing
 
-ernest

GeneralSome statisticmembermaitola7928 Jul '09 - 6:28 
Hi, thanks for the code.
 
You could actually find the factor f in another way.
First you calculate what in statistic is called the normalization factor. It is a constant that you have to multiply each element of your distribution in order to get a probability distribution, that is, sum Xi*N=1 so N=1/sum Xi
 
Then your "Factor" it just given by Fi=Xi/N
 
Bye
 
Luca
NewsSource code available onlinemembershookon30 May '09 - 16:33 
Here[^]
Generalselected tagmembersadeghhp7 Mar '09 - 22:47 
hi
how can i get selected items value or text ?
GeneralRe: selected tagmembersadeghhp12 Mar '09 - 21:55 
on itemclick event :
 
e.Item.Text
 
Poke tongue | ;-P
GeneralVisual Errormembersadeghhp30 Jan '09 - 22:55 
hi
when i use accessdata source , the width of cloud control has problem to fit!
it make the cloud in 2 line and very long line
i cant fit it in a table or panel
but with the sample datasource its worked perfect
GeneralRe: Visual ErrormemberSam Shiles27 Feb '09 - 2:40 
Each text item (the word that will be displayed) must have a trailing space. E.g. if the word you wanted to display in the cloud was "Car" the data returned from the data set must be "Car ".
 
You can fix this behavior by modifying line 402 in Cloud.cs from:
 
item.Text = DataBinder.Eval(data, this.DataTextField, this.DataTextFormatString);
to
 
item.Text = DataBinder.Eval(data, this.DataTextField, this.DataTextFormatString) + " ";
 

You will see in the test data supplied (ItmsSource.cs) that all the text is suffixed with a space, hence why when you plug your own data in you get this issue.
QuestionOnItemClickmemberMember 390410926 Sep '08 - 2:31 
Hi,
 
I have used a data table as data source for cloud, I am rendering all the contents from data table in cloud.
I am unable to get onItemClick event.
Can you plz help me out.
 
<vrk:cloud id="wordsContainer" runat="server" width="747px" önitemclick="wordsContainer_OnItemClick" height="138px" xmlns:vrk="#unknown">
 
I am unable to register to "wordsContainer_OnItemClick"

GeneralFont Size variationmemberVijay Karla25 Jun '08 - 19:40 
A better way to vary the font size will be through pixels as it is done in flickr. Font sizes could be distributed from 12px to 38px.
GeneralCentering the cloudmembermusoswire18 Jun '08 - 4:24 
Is it possible to center all the text in the cloud somehow!? Thanks
GeneralThe data in the Tag cloud will be lost after a post back..membermiltash27 May '08 - 0:44 
How can I maintain the Tag cloud after a postback.. I tried EnableViewState property still its not working...
QuestionRe: The data in the Tag cloud will be lost after a post back..memberasamite30 Sep '09 - 14:57 
I too am having this issue and it is driving me nuts. I have a master page where the tag cloud is located and connected to a datasource. The other listview I have in the master page works just fine. When I click on the pager control in the content of the page and do the postback, the tag cloud disappears. Any help would be greatly appreciated.
GeneralRe: The data in the Tag cloud will be lost after a post back..memberDavidLieu2 Dec '09 - 12:03 
Well I put my tag cloud in a control and I was having this issue also so on the Page_Load event I took the ID of the tag cloud, say TagCloud1, and put TagCloud1.DataBind() inside the event.
Not exactly a postback.. but my tag cloud won't disappear at least Smile | :)
AnswerItemClickmemberAdrian_Star28 Apr '08 - 7:01 
I had problems with ItemClick too when DataBinding in the code behind, in my case the problem was that the RaisePostBackEvent in cloud.cs was firing before my control had been repopulated with the original data, hence selectedIndex was always less than this.Items.Count, hence no OnItemClick raised.
 
To get it working I had to repopulate the control with the original data in Page_Load.
 
Hope this helps and let me know if you get a better solution. All the best, A.
 
public void RaisePostBackEvent(string eventArgument)
{
int selectedIndex = 0;
if (Int32.TryParse(eventArgument, out selectedIndex))
{
this.RequiresDataBinding = true;
this.EnsureDataBound();
 
if (selectedIndex >= 0 && selectedIndex < this.Items.Count)
OnItemClick(new CloudItemClickEventArgs(this.Items[selectedIndex]));
}
}
GeneralDataSourcemember111qwe22221 Apr '08 - 1:11 
Hi!
Can you show me example working this code with DataBase?
I'm using C#.
GeneralOverflowmemberbobbo052115 Apr '08 - 11:57 
I put my tag cloud inside a div with a border, to essentially give it a frame and a titlebar at the top. Sometimes, the tags overflow outside the div, rather than wrapping. Any idea what causes this?
GeneralRe: Overflowmemberutkuozturk7 May '08 - 10:15 
yes, I encounter the same overflow problem. I have solved it by changing the line below in the overriden CreateChildControls() method in the "Cloud.cs".
 

protected override void CreateChildControls()
{
......
this.Controls.Add(new LiteralControl(" ")); //instead of this.Controls.Add(new LiteralControl("& nbsp;"));
......
}

 
I hope this solves your problem too. Smile | :)
 
Utku Öztürk
GeneralRe: OverflowmemberSiB5726 Sep '08 - 5:28 
THANK YOU! Solved my problem perfectly!
GeneralColors for the Tag cloudmembermavericksthrive14 Apr '08 - 20:20 
How do we add colors for the tag cloud as per the weights? i.e. more intensity of color for the tag having more weight.
GeneralRe: Colors for the Tag cloudmemberSam Shiles27 Feb '09 - 2:37 
You need to supply an ItemCssClassPrefix e.g: ItemCssClassPrefix="WordCloudSize" and then the coresponding css classes for each weight:
 
.WordCloudSize1
{
font-size: xx-small;
color: #D8FBFF;
text-decoration:none;
}
.WordCloudSize2
{
font-size: x-small;
color: #AAD9FF;
text-decoration:none;
}
 
...
.WordCloudSize7
{
font-size: xx-large;
color: #FF1632;
text-decoration:none;
}
GeneralRe: Colors for the Tag cloudmemberSteve Pieczko26 May '11 - 12:45 
Good information, but I'd like to do something slightly different...
 
I want to change the colors on the words based on a different parameter, so the words would still have size properties as usual but I want another parameter to drive the color independent of the size. Make sense? How do I do this?
 
Any insight is appreciated.
 
Thanks!
GeneralResizing Tag Cloudmembermallyajiggs11 Apr '08 - 6:10 
Hi, When i populate tag cloud it grows big horizontally even if i have fixed the hieght and width of the Tag cloud.
 
i want like 5 tags in each line(just some fixed length )... how can i do this ??
 
Please give me suggestions on Making the Tag cloud looks really funky.. like a compatible css class with it Smile | :) !!
 
thank you
GeneralRe: Resizing Tag CloudmemberEverton Molina10 Jun '08 - 10:42 
I've got the same problem a couldn't fixe the width. Does Anybody know ? Please !!!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 4 Jul 2006
Article Copyright 2006 by Rama Krishna Vavilala
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid