使用JSON和AJAX创建网站的标签云(TagCloud)
废话不多说,先看看我们最终达到的效果. 源码下载在文章最后。
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 );
}
}
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 >
< 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;
}
#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();
}
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工程下载,有兴趣的同学吧。 点击下载