前言
在一次校友聚会上,一个做到世界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启动主窗体:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//setup swing fonts before start program.
Font font = new Font("微软雅黑", Font.PLAIN, 12);
UIManager.put("Label.font", font);
UIManager.put("Button.font", font);
UIManager.put("RadioButton.font", font);
UIManager.put("CheckBox.font", font);
UIManager.put("TextField.font", font);
//show main ui.
MainUI ui = new MainUI();
ui.setVisible(true);
}
});
}
是我喜欢的雅黑效果,耶!
抓取网页数据
接下来,要解决如何获取CSDN用户信息以及好友信息的问题。观察CSDN网站可以发现,用户的BLOG首页是http://blog.csdn.net/+用户名。例如我的BLOG地址是http://blog.csdn.net/solo。要看本人好友,需要看本人详细信息页面,这个页面URL是:http://hi.csdn.net/solo。在这个页面的右侧有用户好友列表。
这样,我们就可以用URL和流来读取页面,并解析其中的好友了。在浏览器查看HTML源码,确定好友列表对应的HTML标志,然后通过以下代码进行解析:
try {
URL url = new URL(urlString);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
String line = reader.readLine();
while (line != null) {
line = line.trim();
if (line.startsWith("<div id=\"space_avatar\">")) {
line = reader.readLine().trim();
int index = line.indexOf("http");
line = line.substring(index);
index = line.indexOf("\"");
String imageURL = line.substring(0, index);
index = line.indexOf("alt=");
line = line.substring(index + 5);
if (line.contains("\"")) {
line = line.substring(0, line.indexOf("\""));
}
String tooltip = line;
UserNode centerNode = addNode(null, tooltip, imageURL, null);
return centerNode;
}
line = reader.readLine();
}
} catch (Exception ex) {
//ex.printStackTrace();
}
此外,为了防止读取URL的过程阻塞Swing线程造成界面卡壳,把它封装并放在单独的Thread或Runnable中进行,读取结果后,再将结果动态放入界面即可:
public class PageExplorer implements Runnable {
.......
public void run() {
try {
if (parent == null) {
UserNode centerNode = createCenterNode();
addChildrenNode(centerNode);
centerNode.setExplored();
} else {
addChildrenNode(parent);
parent.setExplored();
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(network, "无法获得该用户数据。");
}
}
..............
}
数据显示
数据获得后,如何显示是关键。显示效果一定要直观、美观、容易理解。TWaver的拓扑图是不二选择,全图形化的拓扑结构绝对比表格之类的东西更加直观、讨巧。
然后定义图形元素。其实只有两个元素,一个是点,一个是线。点表示用户节点,线表示其关系,这里只显示一个简单的朋友关系。
接下来就用TWaver的Node和Link定义两个类,封装节点和连线:
public class UserNode extends ResizableNode {
private boolean male = !(TWaverUtil.getRandomInt(5) == 0);
public UserNode() {
init();
}
private void init() {
this.putBorderVisible(false);
this.putCustomDraw(true);
this.putCustomDrawFill(true);
this.putCustomDrawGradient(false);
this.putCustomDrawGradient(true);
this.putLabelColor(Color.white);
this.putLabelFont(new Font("微软雅黑", Font.PLAIN, 12));
this.putLabelYOffset(-5);
this.putLabelHighlightable(false);
this.putLabelUnderlineColor(Color.white);
if (male) {
this.setSize(10, 10);
this.putCustomDrawGradient(false);
this.putCustomDrawFill3D(true);
this.putCustomDrawOutline(false);
this.putCustomDrawShapeFactory(TWaverConst.SHAPE_RECTANGLE);
this.putCustomDrawFillColor(Color.green.darker());
} else {
this.setSize(15, 15);
this.putCustomDrawShapeFactory(TWaverConst.SHAPE_CIRCLE);
this.putCustomDrawOutline(false);
this.putCustomDrawGradientFactory(TWaverConst.GRADIENT_LINE_NE);
this.putCustomDrawGradientColor(Color.yellow.brighter());
this.putCustomDrawFillColor(Color.orange);
}
}
..............
}
试了一下自己的朋友关系,效果还不错,可惜就是好友太少了!
顺藤摸瓜
光显示自己的关系网自然不够,还要能够顺藤摸瓜不断的展开、延伸下去才行。基本思路简单:双击下一个节点,再用前面的方法抓取这个人的网页URL,并将下一层好友再次填入,不断往复、以此类推。这样试了一下,有点意思了:
自动布局
数据复杂后,没有很好的组织结构是无法看出效果的。TWaver提供了不错的自动布局算法,我就利用了两个:一个是环形的静态自动布局,布局后会静止不动;另外一个是基于弹簧算法的动态布局,节点会动画一样的慢慢调整,很有意思。同时提供了两个按钮进行布局切换。弹簧布局比较生动,在拖动节点过程中可以呈现出不同的姿态:
弹簧布局的参数如下:
//setup TWaver auto-layout algorithm parameters.
network.getSpringLayouter().setForceSize(3);
network.getSpringLayouter().setStepSize(40);
network.getSpringLayouter().setNodeRepulsionFactor(1);
network.getSpringLayouter().setLinkRepulsionFactor(30);
network.getSpringLayouter().start();
network.getCanvasScrollPane().setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
network.getCanvasScrollPane().setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//when window resized, reset the spring layout limit bounds to canvas view port size.
network.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
network.getSpringLayouter().setLimitBounds(network.getCanvasScrollPane().getBounds());
}
});
绘制说明文字
想添加一点说明文字,要不然大家都不知道怎么用。传统文字说明太土了,自然不符合本程序的审美和风格。要弄就弄fashion一点。想到了TWaver的Marker机制。这个可以在拓扑图上面任意paint东西,符合我的要求!于是fill一个rectangle然后draw文字:
public class NoteMarker implements CanvasMarker {
private Color backgroundColor = new Color(0, 200, 200, 50);
private Font font = new Font("微软雅黑", Font.BOLD, 12);
public void mark(Graphics2D g) {
g.setColor(backgroundColor);
g.fill3DRect(50, 50, 330, 150, true);
g.setFont(font);
g.setColor(Color.white);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int space = 20;
int x = 55;
int y = 65;
g.drawString("1、双击彩色节点【绿色或黄色】进行关系展开", x, y);
y += space;
g.drawString("2、灰色节点为已探索用户", x, y);
y += space;
g.drawString("3、绿色节点为Boy,黄色节点为Girl", x, y);
y += space;
g.drawString("4、鼠标停留可以tooltip此人的照片和BLOG网址", x, y);
y += space;
g.drawString("5、选择“环形布局”或“弹簧布局”进行布局算法切换", x, y);
y += space;
g.drawString("6、点击“随机展开几个”按钮随机对几个节点自动展开", x, y);
y += space;
g.drawString("7、文本框输入其他CSDN用户名并点击按钮“重新开始”", x, y);
}
}
再通过下面代码安装marker:
//display notes on network canvas with a marker.
network.addCanvasMarker(new NoteMarker());
效果如下:
另外,添加了一个小功能:在鼠标停留一个节点一点时间后,通过tooltip显示此人的照片和URL地址。同时有个惊人的发现:这里竟然可以支持GIF动画!
最终效果
为了展开方便,添加了一个按钮,可以随意展开几个节点,节省了不少鼠标操作。一阵狂点之后,还真是看出了“人与人的关系”之复杂性了:
程序及源代码下载
老规矩,有福同享、有难同当。源代码和可执行jar包自然会在此奉上。有兴趣的朋友,可以在此基础上,继续完善功能。哪个哥们有精力的话,可以再做一个JavaEye版的就好了!欢迎大家就此进行讨论!另外如果有时间,我还想做一个Flex版的JavaEye的例子,有兴趣的朋友可以共同参与。
可执行程序(jar包、run.bat)和源代码(java源文件)在此处下载:
请确保使用JDK 6编译和运行,同时保持网络通畅,以便到CSDN网站进行数据抓取。
谢谢!
- 大小: 506 KB
- 大小: 31.8 KB
- 大小: 199.3 KB
- 大小: 541.3 KB
- 大小: 384.9 KB
- 大小: 50.6 KB
- 大小: 263.8 KB
- 大小: 1 MB
- 大小: 660.8 KB
分享到:
相关推荐
csdn csdn csdn csdn
人工智能-项目实践-用户画像-csdn用户画像的源码 人工智能-项目实践-用户画像-csdn用户画像的源码
csdn图片资源没啥用图
csdn首页csdn首页csdn首页csdn首页csdn首页
CSDN 表情 CSDN 表情 CSDN 表情CSDN 表情 CSDN 表情 CSDN 表情CSDN 表情 CSDN 表情 CSDN 表情CSDN 表情 CSDN 表情 CSDN 表情
CSDN Share 是一款出色的Android阅读工具,阅读由 CSDN社区用户分享的技术文档。 通过CSDN Share可以在线阅读或离线下载CSDN 举办的各类技术活动的精彩讲义,以及来自CSDN下载社区由用户分享的技术文档。 马上下载...
7、生成的pdf、doc文件支持图片 8、支持进度显示 #################################################### 制作时间:2012年07月17日 - 2012年07月18日 制 作:w397090770 个人博客:...
Bootstrap仿制CSDN用户主页页面
CSDN_封面_CSDN_封面
CSDN博客分类专栏图标,编辑修改分类专栏配图可以变成静态图片,图片共15张,多种颜色,图片主体都为大写字母C,非常好看
大家好 今天教大家“如何通过CSDN网站赚钱” https://blog.csdn.net/weixin_45085185?spm=1011.2124.3001.5343 这个是CSDN网站地址 首先要注册个CSDN账号 这个就不演示了 很简单 CSDN主要是通过上传资源赚钱 我...
CSDN 博客导出工具, 用于将 CSDN 博客导出为 Markdown / PDF 格式
csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试csdn 测试...
ping community.csdn.net 的结果图
CSDN的商业模式分析 详细介绍了csdn的发展历史,盈利方式,发展路线
本人收藏的类似CSDN首页上图片翻转得效果 感觉还不错,大家分享
一款C#编写CSDN博客导出工具,导出为MarkDown文档 炒鸡简单~~~~~~~~~~~~ 一款C#编写CSDN博客导出工具,导出为MarkDown文档 炒鸡简单~~~~~~~~~~~~
CSDN积分获取方法
该文件为CSDN对应等级图标,有需要做论坛网站需要用到的可以下载1111111111111111111111111111
CSDN博客下载器,根据csdn的用户名得到用户的文章