TWaver - 專注UI技術

          http://twaver.servasoft.com/
          posts - 171, comments - 191, trackbacks - 0, articles - 2
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          震撼的CSDN用戶關系圖

          Posted on 2010-09-07 14:11 TWaver 閱讀(2955) 評論(4)  編輯  收藏

          前言

          在一次校友聚會上,一個做到世界500強公司高級管理層的校友說:在這個城市,要隨便找到一個人扯上關系,我最多通過三個人就能辦到。這個社會老混混語出驚人,其道理卻深值思考。這個社會是一個人與人組成的巨大的關系網絡,每個人都是這個巨大網絡中的一個節點。如能充分認識和利用這個網絡,我們的工作和事業必將如虎添翼。

          相信大家都有這樣的經歷,為了了解軟件行業信息或解決開發難題時,都會求搜索CSDN 或Javaeye上的專家。同樣,某些時候我們也會通過BLOG或發帖共享自己的知識點,不知不覺成為幫助別人的“專家”。而這些網站用戶之間又有“關注”關系、“好友”關系等,其實這也是一個巨大的人際網絡、知識網絡。這個網絡到底有多大,看上去又會如何呢?是否也能大到“三個人就能到達任意點”的程度呢?懷著無比的好奇心情,我萌發了一個念頭:用程序圖形化的呈現一下這個龐大的人際網絡,相信一定會have lots of fun!

          想法出來后,首先仔細觀察了一下CSDN網站的BLOG頁面結構和好友信息列表,然后用Java Swing寫了一個簡單的程序。通過近一周的修改,終于初具雛形!在此首先衷心感謝CSDN提供了這么好的數據,其次感謝博客里的朋友,是讓這個圖出來就這么好看,是你們給了我無窮的動力!

          廢話不說,先上一張最終效果圖:

          繼續闡述一下程序設計思路。
          技術準備
          自己最熟悉Java Swing,于是毫無疑問,用Swing來做。同時對需要圖形化呈現,自然是用我比較熟悉的TWaver Java版。準備好JDK6和Netbeans,開始干活。

          首先設置字體。沒辦法,我有“雅黑”強迫癥,自從聽說微軟每個雅黑漢字都花費了100美金之后,看見什么都想先弄成雅黑,這里也不例外。還用XP的朋友就不好意思了,不知道字體顯示效果如何。在Swing里面設置起來很簡單,這里偷懶挑一下,只把幾個用到的Component設置字體,然后用SwingUtilities.invokeLater啟動主窗體:

           1public static void main(String[] args) {
           2    SwingUtilities.invokeLater(new Runnable() {
           3
           4        public void run() {
           5            //setup swing fonts before start program.
           6            Font font = new Font("微軟雅黑", Font.PLAIN, 12);
           7            UIManager.put("Label.font", font);
           8            UIManager.put("Button.font", font);
           9            UIManager.put("RadioButton.font", font);
          10            UIManager.put("CheckBox.font", font);
          11            UIManager.put("TextField.font", font);
          12
          13            //show main ui.
          14            MainUI ui = new MainUI();
          15            ui.setVisible(true);
          16        }

          17    }
          );
          18}

          是我喜歡的雅黑效果,耶!


          抓取網頁數據
          接下來,要解決如何獲取CSDN用戶信息以及好友信息的問題。觀察CSDN網站可以發現,用戶的BLOG首頁是http://blog.csdn.net/+用戶名。例如我的BLOG地址是http://blog.csdn.net/solo。要看本人好友,需要看本人詳細信息頁面,這個頁面URL是:http://hi.csdn.net/solo。在這個頁面的右側有用戶好友列表。

          這樣,我們就可以用URL和流來讀取頁面,并解析其中的好友了。在瀏覽器查看HTML源碼,確定好友列表對應的HTML標志,然后通過以下代碼進行解析:

           1try {
           2            URL url = new URL(urlString);
           3            BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
           4            String line = reader.readLine();
           5            while (line != null{
           6                line = line.trim();
           7                if (line.startsWith("<div id=\"space_avatar\">")) {
           8                    line = reader.readLine().trim();
           9                    int index = line.indexOf("http");
          10                    line = line.substring(index);
          11                    index = line.indexOf("\"");
          12                    String imageURL = line.substring(0, index);
          13                    index = line.indexOf("alt=");
          14                    line = line.substring(index + 5);
          15                    if (line.contains("\"")) {
          16                        line = line.substring(0, line.indexOf("\""));
          17                    }

          18                    String tooltip = line;
          19
          20                    UserNode centerNode = addNode(null, tooltip, imageURL, null);
          21                    return centerNode;
          22                }

          23
          24                line = reader.readLine();
          25            }

          26        } catch (Exception ex) {
          27            //ex.printStackTrace();
          28        }

          此外,為了防止讀取URL的過程阻塞Swing線程造成界面卡殼,把它封裝并放在單獨的Thread或Runnable中進行,讀取結果后,再將結果動態放入界面即可:

           1public class PageExplorer implements Runnable {
           2.
           3    public void run() {
           4        try {
           5            if (parent == null{
           6                UserNode centerNode = createCenterNode();
           7                addChildrenNode(centerNode);
           8                centerNode.setExplored();
           9            }
           else {
          10                addChildrenNode(parent);
          11                parent.setExplored();
          12            }

          13        }
           catch (Exception ex) {
          14            JOptionPane.showMessageDialog(network, "無法獲得該用戶數據。");
          15        }

          16    }

          17..
          18}

          數據顯示
          數據獲得后,如何顯示是關鍵。顯示效果一定要直觀、美觀、容易理解。TWaver的拓撲圖是不二選擇,全圖形化的拓撲結構絕對比表格之類的東西更加直觀、討巧。然后定義圖形元素。其實只有兩個元素,一個是點,一個是線。點表示用戶節點,線表示其關系,這里只顯示一個簡單的朋友關系。

          接下來就用TWaver的Node和Link定義兩個類,封裝節點和連線:

           1public class UserNode extends ResizableNode {
           2
           3    private boolean male = !(TWaverUtil.getRandomInt(5== 0);
           4
           5    public UserNode() {
           6        init();
           7    }

           8
           9    private void init() {
          10        this.putBorderVisible(false);
          11
          12        this.putCustomDraw(true);
          13        this.putCustomDrawFill(true);
          14        this.putCustomDrawGradient(false);
          15        this.putCustomDrawGradient(true);
          16
          17        this.putLabelColor(Color.white);
          18        this.putLabelFont(new Font("微軟雅黑", Font.PLAIN, 12));
          19        this.putLabelYOffset(-5);
          20        this.putLabelHighlightable(false);
          21
          22        this.putLabelUnderlineColor(Color.white);
          23        if (male) {
          24            this.setSize(1010);
          25            this.putCustomDrawGradient(false);
          26            this.putCustomDrawFill3D(true);
          27            this.putCustomDrawOutline(false);
          28            this.putCustomDrawShapeFactory(TWaverConst.SHAPE_RECTANGLE);
          29            this.putCustomDrawFillColor(Color.green.darker());
          30        }
           else {
          31            this.setSize(1515);
          32            this.putCustomDrawShapeFactory(TWaverConst.SHAPE_CIRCLE);
          33            this.putCustomDrawOutline(false);
          34            this.putCustomDrawGradientFactory(TWaverConst.GRADIENT_LINE_NE);
          35            this.putCustomDrawGradientColor(Color.yellow.brighter());
          36            this.putCustomDrawFillColor(Color.orange);
          37        }

          38    }

          39..
          40}
          試了一下自己的朋友關系,效果還不錯,可惜就是好友太少了!

          順藤摸瓜
          光顯示自己的關系網自然不夠,還要能夠順藤摸瓜不斷的展開、延伸下去才行。基本思路簡單:雙擊下一個節點,再用前面的方法抓取這個人的網頁URL,并將下一層好友再次填入,不斷往復、以此類推。這樣試了一下,有點意思了:


          自動布局
          數據復雜后,沒有很好的組織結構是無法看出效果的。TWaver提供了不錯的自動布局算法,我就利用了兩個:一個是環形的靜態自動布局,布局后會靜止不動;另外一個是基于彈簧算法的動態布局,節點會動畫一樣的慢慢調整,很有意思。同時提供了兩個按鈕進行布局切換。彈簧布局比較生動,在拖動節點過程中可以呈現出不同的姿態:

          彈簧布局的參數如下:

           1//setup TWaver auto-layout algorithm parameters.
           2        network.getSpringLayouter().setForceSize(3);
           3        network.getSpringLayouter().setStepSize(40);
           4        network.getSpringLayouter().setNodeRepulsionFactor(1);
           5        network.getSpringLayouter().setLinkRepulsionFactor(30);
           6        network.getSpringLayouter().start();
           7        network.getCanvasScrollPane().setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
           8        network.getCanvasScrollPane().setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
           9
          10        //when window resized, reset the spring layout limit bounds to canvas view port size.
          11        network.addComponentListener(new ComponentAdapter() {
          12
          13            @Override
          14            public void componentResized(ComponentEvent e) {
          15                network.getSpringLayouter().setLimitBounds(network.getCanvasScrollPane().getBounds());
          16            }

          17        }
          );

          繪制說明文字
          想添加一點說明文字,要不然大家都不知道怎么用。傳統文字說明太土了,自然不符合本程序的審美和風格。要弄就弄fashion一點。想到了TWaver的Marker機制。這個可以在拓撲圖上面任意paint東西,符合我的要求!于是fill一個rectangle然后draw文字:

           1public class NoteMarker implements CanvasMarker {
           2
           3    private Color backgroundColor = new Color(020020050);
           4    private Font font = new Font("微軟雅黑", Font.BOLD, 12);
           5
           6    public void mark(Graphics2D g) {
           7        g.setColor(backgroundColor);
           8        g.fill3DRect(5050330150true);
           9        g.setFont(font);
          10        g.setColor(Color.white);
          11        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
          12        int space = 20;
          13        int x = 55;
          14        int y = 65;
          15        g.drawString("1、雙擊彩色節點【綠色或黃色】進行關系展開", x, y);
          16        y += space;
          17        g.drawString("2、灰色節點為已探索用戶", x, y);
          18        y += space;
          19        g.drawString("3、綠色節點為Boy,黃色節點為Girl", x, y);
          20        y += space;
          21        g.drawString("4、鼠標停留可以tooltip此人的照片和BLOG網址", x, y);
          22        y += space;
          23        g.drawString("5、選擇“環形布局”或“彈簧布局”進行布局算法切換", x, y);
          24        y += space;
          25        g.drawString("6、點擊“隨機展開幾個”按鈕隨機對幾個節點自動展開", x, y);
          26        y += space;
          27        g.drawString("7、文本框輸入其他CSDN用戶名并點擊按鈕“重新開始”", x, y);
          28    }

          29}

          再通過下面代碼安裝marker:

          1//display notes on network canvas with a marker.
          2network.addCanvasMarker(new NoteMarker());

          效果如下:

          另外,添加了一個小功能:在鼠標停留一個節點一點時間后,通過tooltip顯示此人的照片和URL地址。同時有個驚人的發現:這里竟然可以支持GIF動畫!


          最終效果
          為了展開方便,添加了一個按鈕,可以隨意展開幾個節點,節省了不少鼠標操作。一陣狂點之后,還真是看出了“人與人的關系”之復雜性了:

          去掉人的名字,效果如下:


          程序及源代碼下載

          老規矩,有福同享、有難同當。源代碼和可執行jar包自然會在此奉上。有興趣的朋友,可以在此基礎上,繼續完善功能。哪個哥們有精力的話,可以再做一個JavaEye版的就好了!歡迎大家就此進行討論!另外如果有時間,我還想做一個Flex版的JavaEye的例子,有興趣的朋友可以共同參與。
          可執行程序(jar包、run.bat)和源代碼(java源文件)在此處下載:
          請確保使用JDK 6編譯和運行,同時保持網絡通暢,以便到CSDN網站進行數據抓取。
          謝謝!

          評論

          # re: 震撼的CSDN用戶關系圖[未登錄]  回復  更多評論   

          2010-09-07 14:56 by 111
          樓主做個博客園的呀

          # re: 樓主做個博客園的呀  回復  更多評論   

          2010-09-07 20:57 by lexus
          嚴重同意樓上觀點,twaver再來一個博客園的關系網

          # re: 震撼的CSDN用戶關系圖  回復  更多評論   

          2010-09-08 01:38 by bonamana
          這個東西很久很久就看到了

          # re: 震撼的CSDN用戶關系圖  回復  更多評論   

          2010-09-08 09:24 by Jos
          @lexus
          hi,不知道博客園是否有相應的API公開出來啊?很想試試!

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 织金县| 三江| 甘孜县| 望奎县| 五寨县| 孟连| 阳信县| 玉树县| 苏尼特右旗| 布尔津县| 建始县| 涪陵区| 乌鲁木齐县| 锡林郭勒盟| 浮梁县| 弋阳县| 沂源县| 台安县| 鞍山市| 台湾省| 景东| 洛南县| 东源县| 和林格尔县| 右玉县| 陆良县| 石首市| 观塘区| 沈丘县| 诏安县| 杭锦后旗| 隆昌县| 怀远县| 堆龙德庆县| 定安县| 台南县| 原平市| 揭西县| 象州县| 陕西省| 鄯善县|