废话不多说,先看看我们最终达到的效果. 源码下载在文章最后。
Style1:

Style2:

上面的tag cloud实现思想如下:
1. Server端提供Tag的相关信息,包括TagName,Posts等,使用JSON格式传输数据
这个例子中,我使用Servlet,使用json-lib将Bean转成JSON字符串。当然Tag的相关信息这里只是演示,真实环境中可能就需要从数据库取出来再处理了。
代码如下:
import
java.io.IOException;
import
java.util.ArrayList;
import
java.util.Random;

import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;

import
net.sf.json.JSONSerializer;



public
class
TagCloudAction
extends
HttpServlet
{


private
static
String cache
=
""
;

/** */
/**
*
*/
private
static
final
long
serialVersionUID
=
-
7031695721764039045L
;

@Override
protected
void
doGet(HttpServletRequest req, HttpServletResponse resp)

throws
ServletException, IOException
{
resp.setHeader(
"
Pragma
"
,
"
no-cache
"
);
resp.addHeader(
"
Cache-Control
"
,
"
must-revalidate
"
);
resp.addHeader(
"
Cache-Control
"
,
"
no-cache
"
);
resp.addHeader(
"
Cache-Control
"
,
"
no-store
"
);
resp.setDateHeader(
"
Expires
"
,
0
);
resp.setContentType(
"
text/xml
"
);
resp.setCharacterEncoding(
"
UTF-8
"
);
if
(cache.isEmpty())

{
cache
=
getTagCloudJSONString();
}
resp.getOutputStream().write(cache.getBytes(
"
UTF-8
"
));
resp.flushBuffer();
}
private
String getTagCloudJSONString()

{
Category c
=
new
Category(
"
Name
"
,
"
This is comments
"
,
10
);
c.setCategoryID(
10
);
//
System.out.println( JSONSerializer.toJSON(c).toString() );
//
System.out.println( JSONSerializer.toJSON(c).toString(2) );
ArrayList
<
Category
>
categoriesList
=
new
ArrayList
<
Category
>
();
Random r
=
new
Random();

String[] tags
=
new
String[]
{
"
JAVA
"
,
"
Groovy
"
,
"
Servlet
"
,
"
J2EE
"
,
"
JSP
"
,
"
J2SE
"
,
"
JSON
"
,
"
AJAX
"
,
"
CaiClient
"
,
"
.NET
"
,
"
C#
"
,
"
Perl
"
,
"
Python
"
,
"
Rails
"
,
"
Ruby
"
,
"
Boss
"
,
"
Nokia
"
,
"
GPhone
"
,
"
iPhone
"
,
"
HiPhone
"
,
"
Ericsson
"
,
"
Semens
"
,
"
Novels
"
,
"
春天
"
,
"
夏天
"
,
"
秋天
"
,
"
冬天
"
,
"
节日快乐
"
,
"
破釜沉舟
"
,
"
瑞星杀毒
"
,
"
奶粉事故
"
,
"
奥运会
"
,
"
Grails
"
,
"
Google
"
,
"
Baidu
"
,
"
XiaoNei
"
,
"
开心网
"
,
"
校内网
"
,
"
海内网
"
,
"
都是垃圾
"
,
"
萨达姆
"
,
"
PK
"
,
"
网摘
"
}
;
int
len
=
tags.length
-
1
;

for
(
int
i
=
0
; i
<
100
; i
++
)
{
Category item
=
new
Category(tags[r.nextInt(len)],
"
This is comments for
"
+
i,r.nextInt(
100
));
item.setCategoryID(i);
categoriesList.add(item);
}
System.err.println( JSONSerializer.toJSON(categoriesList).toString() );
//
System.err.println( JSONSerializer.toJSON(categoriesList).toString(2) );
return
JSONSerializer.toJSON(categoriesList).toString(
2
);
}
}
2. 客户端发起XMLHttpRequest请求,取得TagCloud需要的JSON数据,进行处理,生成链接,定义样式
当然这里我们设计是将js文件,css文件,html分离了,为了更好的维护。
目录和文件结构如下:

tagCloud.html 的内容很简单,两个Button,点击之后调用获取不同Style的Tag Cloud的函数
<!
DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
>
<
html
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html; charset=UTF-8"
>
<
title
>
Tag Cloud
</
title
>
<
script
type
="text/javascript"
src
="json2.js"
></
script
>
<
script
type
="text/javascript"
src
="tagcloud.js"
></
script
>
<
link
rel
=StyleSheet
type
="text/css"
href
="tagCloud.css"
>
</
head
>
<
body
>
<
p
>
Version.1 use raw XMLHttpRequest to get JSON data from a Servlet.
</
p
>
<
input
id
="btn_getTagCloud1"
type
="button"
value
="Get tag cloud style1"
onclick
="getTagCloud();"
/>
<
div
id
="tagcloud"
></
div
>
<
input
id
="btn_getTagCloud2"
type
="button"
value
="Get tag cloud style2"
onclick
="getTagCloud2();"
/>
<
div
id
="tagcloudwithstyle2"
></
div
>
</
body
>
</
html
>
再看看我们定义的css文件,主要是字体颜色和大小的设置
@CHARSET "UTF-8";


#tagcloud,#tagcloudwithstyle2{
}{
width: 500px;

background:#FFFFFF;/**//*#FFFFCC;*/
padding: 10px;
border: 1px solid #FFE7B6;
text-align:center;
font-family:'Trebuchet MS',Arial,Verdana,sans-serif;
}


#tagcloud a:link, #tagcloud a:visited {
}{
text-decoration:none;
color: #87A800;
}


#tagcloud a:hover, #tagcloud a:active {
}{
color: #FFFFFF;
background-color: #87A800;
}


#tagcloud span, #tagcloudwithstyle2 span{
}{
padding: 4px;
}


#tagcloudwithstyle2 a:link, #tagcloudwithstyle2 a:visited {
}{
text-decoration:none;
color: #ff4500;
}


#tagcloudwithstyle2 a:hover, #tagcloudwithstyle2 a:active {
}{
color: #FF3300;
background-color: #ffff00;
}

.smallest {
}{
font-size: 10px;
}


.small {
}{
font-size: 15px;
}


.medium {
}{
font-size: 20px;
}


.large {
}{
font-size: 25px;
}


.largest {
}{
font-size: 30px;
}来看看这里最重要的javascript文件,有些AJAX基本的东西,但是有注释应该不难看懂
var XMLHttpReq;
var maxTagPosts = 1; // 这个变量用来保存包含关联文章最多的那个Tag的文章数

// 创建XMLHttpRequest对象

function createXMLHttpRequest()
{

if (window.XMLHttpRequest)
{ // Mozilla 浏览器
XMLHttpReq = new XMLHttpRequest();

} else if (window.ActiveXObject)
{ // IE浏览器

try
{
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");

} catch (e)
{

try
{
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");

} catch (e)
{
}
}
}
}
// 发送请求函数

function sendRequest(url, callback)
{
createXMLHttpRequest();
XMLHttpReq.open("GET", url, true);
//XMLHttpReq.onreadystatechange = processResponse;// 指定响应函数
XMLHttpReq.onreadystatechange = callback;
XMLHttpReq.send(null); // 发送请求
}

// 处理返回信息函数

function processResponseStyle1()
{

if (XMLHttpReq.readyState == 4)
{ // 判断对象状态

if (XMLHttpReq.status == 200)
{ // 信息已经成功返回,开始处理信息
var tagCloud = JSON.parse( XMLHttpReq.responseText );
for(var i=0; i< tagCloud.length;i++)

{
if(tagCloud[i].relatedPosts>maxTagPosts)

{
maxTagPosts = tagCloud[i].relatedPosts;
}
}

var tagCloudHTML = "";
for(var j=0; j< tagCloud.length;j++)

{
var searchCondition = encodeURI(tagCloud[j].categoryName);
var classSize = getClass(tagCloud[j].relatedPosts);
var aTag = "<span class='"+classSize+"'><a href=\"#?search="+searchCondition
+"\" title=\"Posts: "+tagCloud[j].relatedPosts+"\">"+tagCloud[j].categoryName+"</a></span>\n";
tagCloudHTML += aTag;
}
document.getElementById("tagcloud").innerHTML = tagCloudHTML;

} else
{ // 页面不正常
window.alert("Page Exception!");
}
}
}


function processResponseStyle2()
{

if (XMLHttpReq.readyState == 4)
{

if (XMLHttpReq.status == 200)
{
var tagCloud = JSON.parse( XMLHttpReq.responseText );
for(var i=0; i< tagCloud.length;i++)

{
if(tagCloud[i].relatedPosts>maxTagPosts)

{
maxTagPosts = tagCloud[i].relatedPosts;
}
}
var tagCloudHTML = "";
for(var j=0; j< tagCloud.length;j++)

{
var searchCondition = encodeURI(tagCloud[j].categoryName);
var classSize = getClass(tagCloud[j].relatedPosts);
var aTag = "<span class='"+classSize+"'><a href='#?search="+searchCondition
+ "' title='Posts: "+tagCloud[j].relatedPosts+"'"
+ " style='color:" + getRandomColor() +"' >"
+ tagCloud[j].categoryName + "</a></span>\n";
tagCloudHTML += aTag;
}
document.getElementById("tagcloudwithstyle2").innerHTML = tagCloudHTML;

} else
{
window.alert("Page Exception!");
}
}
}

function getRandomColor()


{
var r=Math.floor((Math.random()*256)).toString(16);
var g=Math.floor((Math.random()*256)).toString(16);
var b=Math.floor((Math.random()*256)).toString(16);
var colorString="#"+r+g+b;
return colorString;
}

function getTagCloud()
{
sendRequest('getTagCloud',processResponseStyle1);
}

function getTagCloud2()
{
sendRequest('getTagCloud',processResponseStyle2);
}

function getClass(relatedPosts)


{
var presentage = Math.floor((relatedPosts/maxTagPosts)*100);
var classSize;
if(presentage<20)

{
classSize = 'smallest';
}
else if(20<=presentage && presentage <40)

{
classSize = 'small';
}
else if(40<=presentage && presentage <60)

{
classSize = 'medium';
}
else if(60<=presentage && presentage <80)

{
classSize = 'large';
}
else if(80<=presentage)

{
classSize = 'largest';
}
return classSize;
}


window.onload = function()
{
createXMLHttpRequest();
getTagCloud();
}

根据tag关联的posts的数量算出这个tag字体大小的class,第一个style的颜色是在css文件指定的,第二个style多彩文字,功劳都在getRandomColor这个函数上啦。
希望这个例子能给想DIY自己的TagCloud的朋友们一些帮助。
最后是这个Demo的Eclipse工程下载,有兴趣的同学吧。
点击下载
posted on 2008-09-28 16:10
jht 阅读(3152)
评论(3) 编辑 收藏 所属分类:
J2EE