最近被要求去研究一下如何產生 Word/Tag Cloud, 拜完 Google 大神後找到一個不錯的 Solution - From Here
詳細的實作就不多做說明, 直接去看 JavaScript code 吧! 下面針對自己使用方便, 稍微改過上面 Solution 的 JS 代碼, 變成可以從外部讀入 JSon 資料後轉成對應 Tag Cloud. 另外上面的 Solution 有使用到 D3JS (Data-Driven Documents) 的 library, 因此需要去下載. 另外在資料的產生是使用 Java Servlet 來完成; 而 UI 的呈現則是使用 ExtJS 3.4 的 Window 來當作 Container...
Sample Code:
首先我們在後端使用 Servlet 來產生測試資料, 並以 JSON 格式包裝後再回傳到前端. 範例代碼如下:
- package servlets;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import net.sf.json.JSONObject;
- import servlets.datas.TagBean;
- import servlets.datas.TagBeanWrapper;
- /**
- * Servlet implementation class TagData
- */
- @WebServlet("/TagData")
- public class TagDataServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
- /**
- * @see HttpServlet#HttpServlet()
- */
- public TagDataServlet() {
- super();
- }
- /**
- * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
- */
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- response.setCharacterEncoding("UTF-8");
- int loop = 10;
- int max=18;
- int min=1;
- int lvl=3;
- String loopStr = request.getParameter("loop");
- try{if(loopStr!=null) loop = Integer.valueOf(loopStr);}
- catch(Exception e){}
- String maxStr = request.getParameter("max");
- try{if(maxStr!=null) max = Integer.valueOf(maxStr);}
- catch(Exception e){}
- String lvlStr = request.getParameter("lvl");
- try{if(lvlStr!=null) lvl=Integer.valueOf(lvlStr);}
- catch(Exception e){}
- System.out.printf("\t[Test] Max=%d; Loop=%d; Lvl=%d...\n", max, loop, lvl);
- TagBeanWrapper tagBeanWrapper = new TagBeanWrapper();
- Random rdm = new Random();
- int range = (int)Math.ceil(Double.valueOf(max)/lvl);
- int u=0;
- for(int i=0; i
2, i); - int unit = Math.max(loop/u, 1);
- int id=1;
- for(int i=1; i<=lvl; i++)
- {
- int r=((int)Math.pow(2, i-1))*unit;
- for(int j=0; j
- {
- String key = String.format("Test%d", id++);
- int val=Math.max(1, max-range*i+rdm.nextInt(range+1));
- tagBeanWrapper.addTagBean(
- new TagBean(key, val)
- );
- //System.out.printf("\t[Test] Add %s(%d)...\n", key, val);
- }
- }
- /*for(int i=0; i
- {
- tagBeanWrapper.addTagBean(
- new TagBean(String.format("Test%d", i+1), 1+rdm.nextInt(max))
- );
- }*/
- tagBeanWrapper.sortTagBean();
- JSONObject jsonObject = JSONObject.fromObject(tagBeanWrapper);
- System.out.printf("\t[Info] JSonObj:\n%s\n", jsonObject);
- response.getWriter().write(jsonObject.toString());
- }
- /**
- * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
- */
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- doGet(request, response);
- }
- }
- TagBean.java
- package servlets.datas;
- public class TagBean {
- private String key;
- private int value;
- public TagBean(){}
- public TagBean(String key, int val){this.key=key; this.value=val;}
- public String getKey() {
- return key;
- }
- public void setKey(String key) {
- this.key = key;
- }
- public int getValue() {
- return value;
- }
- public void setValue(int value) {
- this.value = value;
- }
- @Override
- public String toString()
- {
- return String.format("[key=%s,value=%d]", key, value);
- }
- }
- package servlets.datas;
- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.List;
- import java.util.PriorityQueue;
- public class TagBeanWrapper {
- List
tags = new ArrayList (); - int totalNum;
- int min=0;
- int max=0;
- public TagBeanWrapper(){}
- public void addTagBean(TagBean bean)
- {
- tags.add(bean);
- totalNum++;
- }
- public int getTotalNum() {
- return totalNum;
- }
- public void sortTagBean()
- {
- Comparator
cmp = new Comparator (){ - @Override
- public int compare(TagBean o1, TagBean o2) {
- return Integer.valueOf(o2.getValue()).compareTo(o1.getValue());
- }
- };
- PriorityQueue
pq = new PriorityQueue ( 10, cmp); - for(TagBean bean:tags) pq.add(bean);
- List
tmpTags = new ArrayList (); - while(!pq.isEmpty()) {
- TagBean bean = pq.poll();
- System.out.printf("\t[Test] %s\n", bean);
- tmpTags.add(bean);
- }
- tags = tmpTags;
- if(tags.size()>0)
- {
- min=tags.get(0).getValue();
- max=tags.get(tags.size()-1).getValue();
- }
- System.out.printf("\t[Test] max=%d; min=%d\n", max, min);
- }
- public List
getTags() { - return tags;
- }
- public void setTags(List
tags) { - this.tags = tags;
- }
- public int getMin() {
- return min;
- }
- public void setMin(int min) {
- this.min = min;
- }
- public int getMax() {
- return max;
- }
- public void setMax(int max) {
- this.max = max;
- }
- public void setTotalNum(int totalNum) {
- this.totalNum = totalNum;
- }
- }
- tagCloudv2.jsp
(由於代碼 post 上來會造成編輯錯誤, 請直接下載專案回去, 在 D3jsDemo\WebContent\demo\tagCloudv2.jsp 路徑下)
上面 JS 代碼有關 Tag Cloud 的部分是修改 Jason Davies 大大 的 cloud.js 而來, 所以請尊重智慧財產權了... Orz. 有關更多的說明可以參考 - How the Word Cloud Generator Works.. 上面代碼中 Tag Cloud 的資料是透過 Ajax 存取 "/D3jsDemo/TagData?loop=100&max=10&lvl=4" 路徑下的 Servlet 吐出的 JSON 資料, 事實上這就是剛剛 TagDataServlet 負責的工作.
由於 Tag Cloud 的產生是不可預期的 (字的排列與轉的角度是 random 發生), 因此在 ExtJS Window 的 Container 上我加上了按鈕 "Refresh" 讓你可以重新產生 Tag Cloud; 另外當你點擊某個 Tag 時產生的 Event, 會在方法 draw3(data, bounds) 被捕抓到. 因此你可以在下面代碼片段加入自己的程式邏輯:
- .on("click", function(d) {
- alert(d.key);
- // Define your application logic here when tag is clicked.
- })
目前這個專案是使用 Eclipse 開發, 完整的專案代碼可以在此 下載!
Supplement:
* Google Chart API 介紹
* Open Cloud - Java Library to generate tag clouds
* ExtJS 3.4 API - TabPanel
沒有留言:
張貼留言