<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    TWaver - 專注UI技術(shù)

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

    震撼的CSDN用戶關(guān)系圖

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

    前言

    在一次校友聚會(huì)上,一個(gè)做到世界500強(qiáng)公司高級(jí)管理層的校友說:在這個(gè)城市,要隨便找到一個(gè)人扯上關(guān)系,我最多通過三個(gè)人就能辦到。這個(gè)社會(huì)老混混語(yǔ)出驚人,其道理卻深值思考。這個(gè)社會(huì)是一個(gè)人與人組成的巨大的關(guān)系網(wǎng)絡(luò),每個(gè)人都是這個(gè)巨大網(wǎng)絡(luò)中的一個(gè)節(jié)點(diǎn)。如能充分認(rèn)識(shí)和利用這個(gè)網(wǎng)絡(luò),我們的工作和事業(yè)必將如虎添翼。

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

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

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

    繼續(xù)闡述一下程序設(shè)計(jì)思路。
    技術(shù)準(zhǔn)備
    自己最熟悉Java Swing,于是毫無疑問,用Swing來做。同時(shí)對(duì)需要圖形化呈現(xiàn),自然是用我比較熟悉的TWaver Java版。準(zhǔn)備好JDK6和Netbeans,開始干活。

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

     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}

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


    抓取網(wǎng)頁(yè)數(shù)據(jù)
    接下來,要解決如何獲取CSDN用戶信息以及好友信息的問題。觀察CSDN網(wǎng)站可以發(fā)現(xiàn),用戶的BLOG首頁(yè)是http://blog.csdn.net/+用戶名。例如我的BLOG地址是http://blog.csdn.net/solo。要看本人好友,需要看本人詳細(xì)信息頁(yè)面,這個(gè)頁(yè)面URL是:http://hi.csdn.net/solo。在這個(gè)頁(yè)面的右側(cè)有用戶好友列表。

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

     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線程造成界面卡殼,把它封裝并放在單獨(dú)的Thread或Runnable中進(jìn)行,讀取結(jié)果后,再將結(jié)果動(dòng)態(tài)放入界面即可:

     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, "無法獲得該用戶數(shù)據(jù)。");
    15        }

    16    }

    17..
    18}

    數(shù)據(jù)顯示
    數(shù)據(jù)獲得后,如何顯示是關(guān)鍵。顯示效果一定要直觀、美觀、容易理解。TWaver的拓?fù)鋱D是不二選擇,全圖形化的拓?fù)浣Y(jié)構(gòu)絕對(duì)比表格之類的東西更加直觀、討巧。然后定義圖形元素。其實(shí)只有兩個(gè)元素,一個(gè)是點(diǎn),一個(gè)是線。點(diǎn)表示用戶節(jié)點(diǎn),線表示其關(guān)系,這里只顯示一個(gè)簡(jiǎn)單的朋友關(guān)系。

    接下來就用TWaver的Node和Link定義兩個(gè)類,封裝節(jié)點(diǎn)和連線:

     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}
    試了一下自己的朋友關(guān)系,效果還不錯(cuò),可惜就是好友太少了!

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


    自動(dòng)布局
    數(shù)據(jù)復(fù)雜后,沒有很好的組織結(jié)構(gòu)是無法看出效果的。TWaver提供了不錯(cuò)的自動(dòng)布局算法,我就利用了兩個(gè):一個(gè)是環(huán)形的靜態(tài)自動(dòng)布局,布局后會(huì)靜止不動(dòng);另外一個(gè)是基于彈簧算法的動(dòng)態(tài)布局,節(jié)點(diǎn)會(huì)動(dòng)畫一樣的慢慢調(diào)整,很有意思。同時(shí)提供了兩個(gè)按鈕進(jìn)行布局切換。彈簧布局比較生動(dòng),在拖動(dòng)節(jié)點(diǎn)過程中可以呈現(xiàn)出不同的姿態(tài):

    彈簧布局的參數(shù)如下:

     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        }
    );

    繪制說明文字
    想添加一點(diǎn)說明文字,要不然大家都不知道怎么用。傳統(tǒng)文字說明太土了,自然不符合本程序的審美和風(fēng)格。要弄就弄fashion一點(diǎn)。想到了TWaver的Marker機(jī)制。這個(gè)可以在拓?fù)鋱D上面任意paint東西,符合我的要求!于是fill一個(gè)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、雙擊彩色節(jié)點(diǎn)【綠色或黃色】進(jìn)行關(guān)系展開", x, y);
    16        y += space;
    17        g.drawString("2、灰色節(jié)點(diǎn)為已探索用戶", x, y);
    18        y += space;
    19        g.drawString("3、綠色節(jié)點(diǎn)為Boy,黃色節(jié)點(diǎn)為Girl", x, y);
    20        y += space;
    21        g.drawString("4、鼠標(biāo)停留可以tooltip此人的照片和BLOG網(wǎng)址", x, y);
    22        y += space;
    23        g.drawString("5、選擇“環(huán)形布局”或“彈簧布局”進(jìn)行布局算法切換", x, y);
    24        y += space;
    25        g.drawString("6、點(diǎn)擊“隨機(jī)展開幾個(gè)”按鈕隨機(jī)對(duì)幾個(gè)節(jié)點(diǎn)自動(dòng)展開", x, y);
    26        y += space;
    27        g.drawString("7、文本框輸入其他CSDN用戶名并點(diǎn)擊按鈕“重新開始”", x, y);
    28    }

    29}

    再通過下面代碼安裝marker:

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

    效果如下:

    另外,添加了一個(gè)小功能:在鼠標(biāo)停留一個(gè)節(jié)點(diǎn)一點(diǎn)時(shí)間后,通過tooltip顯示此人的照片和URL地址。同時(shí)有個(gè)驚人的發(fā)現(xiàn):這里竟然可以支持GIF動(dòng)畫!


    最終效果
    為了展開方便,添加了一個(gè)按鈕,可以隨意展開幾個(gè)節(jié)點(diǎn),節(jié)省了不少鼠標(biāo)操作。一陣狂點(diǎn)之后,還真是看出了“人與人的關(guān)系”之復(fù)雜性了:

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


    程序及源代碼下載

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

    評(píng)論

    # re: 震撼的CSDN用戶關(guān)系圖[未登錄]  回復(fù)  更多評(píng)論   

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

    # re: 樓主做個(gè)博客園的呀  回復(fù)  更多評(píng)論   

    2010-09-07 20:57 by lexus
    嚴(yán)重同意樓上觀點(diǎn),twaver再來一個(gè)博客園的關(guān)系網(wǎng)

    # re: 震撼的CSDN用戶關(guān)系圖  回復(fù)  更多評(píng)論   

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

    # re: 震撼的CSDN用戶關(guān)系圖  回復(fù)  更多評(píng)論   

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

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: **aaaaa毛片免费| 国产成人精品无码免费看| 国产亚洲福利一区二区免费看| 国产精品亚洲一区二区三区久久| 香蕉视频在线观看免费| 成人国产精品免费视频| 在线看片免费人成视久网| 日韩毛片免费无码无毒视频观看| 国产免费AV片无码永久免费 | 久久er国产精品免费观看2| 日日麻批免费40分钟无码 | 爱丫爱丫影院在线观看免费| 最近中文字幕2019高清免费| 成人免费视频观看无遮挡| 亚洲国产精品专区在线观看 | 国产亚洲大尺度无码无码专线| 亚洲伊人久久大香线蕉苏妲己| 亚洲中文字幕无码中文| 成人a毛片视频免费看| 日本视频免费高清一本18| 日本免费网站视频www区| 免费成人午夜视频| 亚洲第一福利网站| 亚洲av综合av一区二区三区| 99在线免费观看| 免费观看成人毛片a片2008| 国产成人毛片亚洲精品| 亚洲日本香蕉视频| 午夜不卡AV免费| 亚洲精品免费网站| 国产偷窥女洗浴在线观看亚洲| 亚洲成人动漫在线观看| 一级大黄美女免费播放| 99re热免费精品视频观看| 亚洲日韩小电影在线观看| 亚洲精品V天堂中文字幕| 久久青草免费91线频观看不卡| 成人黄动漫画免费网站视频 | 久久久婷婷五月亚洲97号色| 精品亚洲av无码一区二区柚蜜| 久久这里只精品99re免费|