A Java Tag Cloud for Wicket Bootstrap

An obvious requirement of the NixMashup Links Website I'm building in Wicket Bootstrap is a tag cloud for the individual links that comprise the NixMashup Posts.

This post is going to walk through the highlights of how I designed and built the site's Tag Cloud.

The Tags Collection: Selection And Sorting

Three primary functions had to be performed on the tags object collection after retrieving it from PostgreSQL.

  1. Select a pre-defined number of tags from the most used tags
  2. Arrange the tags alphabetically for display in the tag cloud
  3. Weight each tag based on tag count and assign it a CssClass name

The first two functions are covered in the getNixMashupTagCloud() method source below. We first create a reverseOrder Comparator “byTagCount,” then with Java Streams we filter out tags with only one link and pull a defined number from the remaining tags with the highest counts.

We next set maxTagCount and minTagCount from the Tags Object Collection for use later in weighting the tags.

The tags should appear in the TagCloud in alphabetic order so we're going to create another Comparator for the tag names and return the sorted collection.

public static List<NixMashupTag> getNixMashupTagCloud() {
	
	// @formatter:off
	
	Comparator<NixMashupTag> byTagCount = 
			Collections.reverseOrder(Comparator.comparing(NixMashupTag::getTagCount));

	List<NixMashupTag> nixMashupTags = getNixMashupTags(true)
			.stream()
			.filter(t -> t.getTagCount() > 1)
			.sorted(byTagCount)
			.limit(NixMashupConfiguration.get().tagCloudCount)
			.collect(Collectors.toList());

	maxTagCount = nixMashupTags.stream().mapToInt(i -> i.tagCount).max().getAsInt();
	minTagCount = nixMashupTags.stream().mapToInt(i -> i.tagCount).min().getAsInt();

	Comparator<NixMashupTag> byTagName = (p, o) -> p.tag.compareTo(o.tag);
	
	return nixMashupTags
			.stream()
			.sorted(byTagName)
			.collect(Collectors.toList());

	// @formatter:on
}

Weighting and Displaying the Tags

We next need to set each tag weight, or assign its CSS Style Class, based on its tag count and how it compares to other tag counts over a span of 3 ranges plus minTagCount and maxTagCount.

Before showing how we assign the CssClass, here is the Wicket Bootstrap Java backend logic. We retrieve the NixMashupTags Collection with the getNixMashupTagCloud() method we covered earlier and populate a “tagPattern” string pattern with the tag and its CssClass name. We'll get the CssClass name based on the tag count in getCssTag(tagCount).

List<NixMashupTag> nixMashupTags = NixMashupTags.getNixMashupTagCloud();
String tagPattern = "<a href='/links/tag/%s' class='%s'>%s</a>";

ListView listview = new ListView("tags", nixMashupTags)
{
    @Override
    protected void populateItem(ListItem item)
    {
    	NixMashupTag nixMashupTag = (NixMashupTag) item.getModelObject();
    	String tag = nixMashupTag.getTag();
    	String cssClass = NixMashupTags.getCssTag(nixMashupTag.getTagCount());
    	
    	item.add(new Label("tag", 
    			String.format(tagPattern,  tag, cssClass, tag)).setEscapeModelStrings(false));
    }
};

Here's getCssTag(tagCount.) The approach of creating a distribution range is straightforward, but you may want to modify the numbers based on your own display preferences. Distribution is generally diff / 2 for instance.

public static String getCssTag(int tagCount) {
	
	String cssClass = "smallTag";
	int diff = maxTagCount - minTagCount;
	int distribution = diff / 5;

	if (tagCount == maxTagCount)
		cssClass = "maxTag";
	else if (tagCount == minTagCount)
		cssClass = "minTag";
	else if (tagCount > (minTagCount + (distribution * 1.75)))
		cssClass = "largeTag";
	else if (tagCount > (minTagCount + distribution))
		cssClass = "mediumTag";

	return cssClass;
}

For the sake of completeness, here's the HTML that houses the tags we created, once again showing the simplicity of web development with Apache Wicket.

Posted June 01, 2014 11:48 AM EDT

More Like This Post