Gary.Wzl
2009年12月14日星期一
After Optimizing Htmlview
2009年12月11日星期五
Three Amazing Days
The author of this software build it with process v1.0,and I wrote this software with Qt.To My surprise,I just spend 3 days to achieve my embryonic work.I can't believe it .Maybe I will take visual text comparison as my dissertation.Of course,It looks like simple and I will spend much time to make this tool stronger,And here is a screenshot of My orginal work .At the same time,I will apperiate the inspiration blprnt gave me,Thank you.
2009年11月11日星期三
WVisual Search Section Four
目的就是在拖动google map的时候,可以自动更新中心点的准确位置,当地的天气情况和显示位置的最新资讯,这就是QtWebkit+Google Map v3+Google Weather+Google News的一个小应用。主要使用到了Qtwebkit网页和本地的一个混编,有了Qt网页和本地软件的界限都比较模糊了,现在又出来了QtwebClient(),再给一个web app的demo,机制大家可以看这里,类似于一个java的applet。
先说说实现的过程,初始化Google Map,当然最好有一个本地的Google Map的html本地文件,每次载入更好。在html本地文件中,增加Map的监听事件
google.maps.event.addListenner(map,"center_Changed",centerChanged);
设置一个定时器,每过一段时间去检测一次,如果现在的中心点发生了改变,那么就去解析当前的地址
geocoder.geocode({'latLng':map.get_center()},getAddressName);
地理信息解析到了之后,会自动触发getAddressNamegetAddressNmae传得是一个函数指针(我是这样认为的)
function getAddressName(results,status)
{
addresssresult = results; //addressres是我的一个全局变量
if(status ==google.maps.GeocoderStatus.OK)
{
if(status !=google.maps.GeocoderStatus.ZERO_RESULTS)
{
var c =address[0].formatted_address;
mapNews.getCityName(c);
}
else
{
mapNews.findFailed();
}
}
}
这里的mapNews是我用webkit的在html中增加的一个我的对象,具体做法连接
connect(frame,SIGNAL(javaScriptWindowObjectCleared),this,SLOT(attachObject));
void QMapNews::attachObject()
{
page()->mainFrame()->addToJavaScriptWindowObject("mapNews",this);
}
现在可能你就恍然大悟了 :-)
在我们的本地getCityName之后,对地址进行解析,然后到Google News进行爬取,网址是
http://news.google.cn/news?hl=zh-CN&ie=UTF-8&q=YourAddress
用js做一下处理,
至于天气大致相同,下面是你得到具体位置之后得到该地区天气数据的地址
http://www.google.com/ig/api?hl=zh-cn&weather=,,,%1,%2
%1 %2用该地址的纬度和经度代替,可以在html中使用
var lat =map.get_center().lat();
vat lng =map.get_center().lng();
得到
只不过你访问的时候,Google Weather会返回给你的是一个xml,用QXmlStreamReader进行一下,处理就OK了。
2009年11月4日星期三
WVisual Search Section Three
其实在我的第一篇blog中aharef: html标签可视化的qt实现过程 ,已经谈到了实现的过程,但是不经意间在网上搜到了这篇文章Websites as GraphsWe need money not art,Markavian开发出了一个remix版本,用户可以对其中的每个点hoverEnter或者hoverleave的时候,会显示标签的内容.
我现在的目标跟他相似,只不过我显示的是具体的标签,而不是标签中所以的内容,因为如果现实标签所有的内容的话,这样UI可能会有很大困难,而且我看了一下,如果打开那个applet的话,CPU就50%了,不管生成是否结束,或者网页节点为100个或者2000个,而且我的链接可以点击,并且用默认浏览器打开,实现很简单.......,有了前一篇文章,只需要简单的剔除tag和它的attribute,然后再paintevent画一下,就OK了,不仅可以拖拽节点,cpu也很稳定,这个功能重新增强了之后,已经加入到Wvisual Search中了............have Fun
2009年10月2日星期五
Thank to SearchMe
http://paranimage.com/magic-number-of-100-visualization-technology-application/,从上面了解到很多前沿的可视化应用,将其中一些经典的加入到我的Wvisual,其中
ttp://www.aharef.info/2006/05/websites_as_graphs.htm,就是其中的一部.这里主要说回到Searchme。其实我最早写Wvisual Search的时候,主要的灵感来源就是Searchme,记得我第一次知道Searchme是在csdn上,当时评选当年最新的10大技术,Searchme榜上有名,第一次进入Searchme的时候,真的是眼前一亮,当时的第一感觉就是华丽的Picture Flow,接着就是一些新奇的可视化技术,关键字定位,内嵌音乐视频播放,放大镜功能,垂直搜索…..(searchme在UI上实现的,我都用Qt在Wvisual Seachme中实现,下一篇我会介绍我的它),虽然searchme不支持中文搜索,但是我还是从Searchme上学到了很多,最重要的一点就是:做创新性的事情,然后从技术上去实现它。再在后面,我大肆在我的朋友圈子中鼓吹Seachme,Searchme也确实在一段时间内取得了相当不错业绩(当然,我有亿万分之一的功劳,),没记错的话,searchme当时的google PR值应该为7,从大概在6月份的时候,如果你输入www.searchme.com的话,那么浏览器会自动跳转到google,原因:在4月份的时候,searchme在首页推出广告业务之后,流量急剧下降,然后又缺少5100w的风投,”一夜之间”当初被喻为”google 杀手”的Searchme就只有这样无奈的”倒下”,转向了TV,还真有点黑色幽默。其实在稍早的时候,iphone等一些手机都嵌入了searchme的可视化搜索
Firefox IE也都可以嵌入插件,很难想象一个表面上无限风光的新技术在一个策略上的改变,带来的是2个月后的下线。 (Searchme 最后的 Picture Flow画面,好像还做了些改变,有了图片的远近拉伸,但是现在是什么画面都显示不出来了).
Searchme UI的3种显示方式
1. 网络原因,在当下的网络状况下,特别是在中国当前的网络状况下(当然还有GFW),实现可视化难度大,作为运营方后台强大服务器的支撑,大型的架构,文本存取和图片存取,怎样在UI和数据传输上找到平滑点,系统资源的占有。作为用户,我当时访问Searchme的时候,搜索条目多几次的话,那么Searchme主界面就会出现stackflow,,虽然说PictureFlow很华丽,但是我们不难想象一下,也有这样的可能,假如有好事者,搜索了之后,就拖动一直下拉的话,再快的网络条件我想也无法满足,而且现在象可视化为了在UI达到华丽的效果,一般会用到flash,你翻页过快的话,看看你的CPU使用率,想象一下,如果是google或者baidu,点下一页,就OK 了。一旦速度上得不到满足的话,他们只需在地址栏上输入个g.cn或者baidu就解决问题了,而不是等待你去解决服务器的问题,或者自己去删除IE中的历史记录.
2. 信息响应上的速度和信息采集上的完整性,试想一下,如果你是一名开发人员,你会选用google还是Searchme,99%的用户会选择google,为什么?原因很简单,前面提到过,1.速度,开发人员需要的是快速找到解决问题的办法,在他们看来速度是一切制胜的根本,他们不会等待一个图片载入超过5秒,5秒钟他们已经足够在地址栏输入g.cn了。
特别像是中国的程序员,做事情一般都比较急,他们是没有时间去等待你去响应的,还有就是信息采集上的完整性,比如你一段代码出现了错误,并且网上有N多人出现了这样的错误,他们或是在自己的blog上或则bbs上发表自己的观点,或者转载,但是其实这样的解决方式基本上都是大同小异,并且说基本上在content上一致的(转载>=copy),难道要为这样的关于一个网页的采集”重复”20-30(网页快照),而且这样的快照页面除了最重要的content是一样的,其他都不一样(但是这些对用户没有一点用的东西。有人说可视化搜索注重的是用户的体验,这样的体验主要是在界面上,带来的是”娱乐”的元素。所有说可视化的主旨是New and Different,而传统的搜索却是Fast and Accurate。
3 资金上,说到底Searchme下线,策略的失败上主要是没有找到盈利点,投入和收入不成比例,导致最后仍然需要大量的资金注入才能正常运营,的确是这样的,这让我想起了中国的视频网站,youku tudou,ku6……这些看似表面红火的网站不断的增加带宽和服务器带来的是中国视频网站的恶性竞争,谁都知道他们在烧钱,每年投入几千万,看谁有钱,谁能坚持到最后,谁坚持到最后,谁就是这个行业当之无愧的”王者”,其实这样玩下去,受伤的是大家,你就是坐成了最后一把交椅,请问你在几年能收回成本呢?也许Searchme广告业务开展过慢,或者说进军手机搜索业务过迟,但是现在说都于事无补了。现在这个空白应该靠谁来填补呢?
2009年9月15日星期二
Webpage 增长的可视化
关于wiki.tudelft.nl page的增长可视化,这个概念是从2004年底开始的,可以从这里Wiki Growth Over Time了解到,跟前一篇在可视化上看起来是一致的,但是在核心却有着千差万别,它是基于的是整个网络每个Node是一个web page的,Edge是hyperlink,表示了这个web page的网页流向,而前一篇Node是一个一个的tags,Edge是连接Children的生成关系。一个网页虽说是动态的,但是tag最多也不会超过3000个(个人估计,看sports sina 全部节点,不去掉js和plugins的话,有2200个左右),但是Wiki Growth却不同了,它会一直生成下去,可见wiki在这短短时间内是怎样壮大了的吧,有点象一个细菌的繁殖,还有从视频中,可以了解到节点生成的动向(Force-Directed )。
2009年9月9日星期三
aharef: html标签可视化的qt实现过程
Processing 的中文资料: http://www.douban.com/group/topic/3637024/
但是这些都是由java写成的,是生成的时候是也是调用applet来实现的。现在我要用qt实现上述功能。先给一张afaref上google的tag的生成图片
然后对比一下,主要一个优点(也可以说瓶颈的地方就是),我实现了粒子的拖拽,但是因为要遍历所有点与对其的作用力(大量的运算,因为如果其中一个点发生运动的话,想想看,如果是root tag:的话,那里对于上1000个节点来说,terrible),所以,相对google来说,还好一点,但是对于节点超过了1000个点左右的话,我的机子风扇就开始轰鸣了(我的笔记本是最老的双核 :-( )。但是没有办法,如果减少节点的话,那么对网站tag的准确性就存在问题,这对于一个真实存在的html文档来说,是不公平的,对用户来说也是不公平的,因为你的节点树实际上是有错误的。
再看看用qt实现的结果:
参考了elastic nodes里面的源码,其中计算压力的函数,很经典,用向量来表示受力情况,实现机制大致是这样的:
1.html Parse 得到网页中所有的tagName放进一个Vector
2.利用QXmlStreamWriter将vectag里面的内容写入到一个xml文件中,为得是后面动态生成的时候广度优先,这里要判断是否是前缀 后缀或者比如img、 embed(引文通常写法没有后缀结束符)
递归生成节点,广度
ParseXml(const QDomNode & domnode,Node* centerNode)
这里将生产的Node要放入QQueue
struct strNode
{
Node* m_center; //父节点指针
Node* m_tag; //this
} m_nodeline;
然后是定时器,每0.1s动态生成一个
m_Mutex.lock();
strNode strnode = m_nodeline.dequeue();
m_Mutex.unlock();
Edge *edge = new Edge(strnode.m_center,strnode.m_tag);
myscene->addItem(strnode.m_tag);
myscene->addItem(edge);
currentpoint.setX(strnode.m_center->pos().x()+Radius*(cos(TwoPi*(1.0/6.0*(i%6)))));
currentpoint.setY(strnode.m_center->pos().y()+Radius*(sin(TwoPi*(1.0/6.0*(i%6)))));
strnode.m_tag->setPos(currentpoint+QPointF(0.1,0.1));
//关键代码是从红色标记的地方开始的,因为真正的受力分析是从生成动态生成new Edge开始的,
因为,这也是代码有点"混乱"的地方
new Edge(strnode.m_center,strnode.m_tag)
edge.cpp......
strnode.m_center->addEdge(this);
strnode.m_tag->addEdge(this);
node.cpp
edgeList<
压力计算触发是在绿色标记开始的
当setpos()之后,QGraphicsItem的virtual protected函数
QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch (change) {
case ItemPositionHasChanged:
foreach (Edge *edge, edgeList)
edge->adjust();
graph->itemMoved();
break;
default:
break;
};
return QGraphicsItem::itemChange(change, value);
}
然后先求与之相连接的所有线段,调整一下长度和位置,然后graph->itemMoved()会触发计算器
//算node移动的位置的时候,启动一个定时器
void GraphWidget::itemMoved()
{
//40ms来更新位置
if (!timerId)
timerId = startTimer(1000 / 20);
}
//TimeEvent来更新位置
void GraphWidget::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event);
//遍历屏幕的所有Node
QList
foreach (QGraphicsItem *item, scene()->items()) {
if (Node *node = qgraphicsitem_cast
nodes <<>calculateForces();
//然后移动实例受力的位置
bool itemsMoved = false;
foreach (Node *node, nodes) {
if (node->advance())
itemsMoved = true;
}
if (!itemsMoved) {
killTimer(timerId);
timerId = 0;
}
}
来看看经典的压力计算函数吧
void Node::calculateForces()
{
if (!scene() scene()->mouseGrabberItem() == this) {
newPos = pos(); //如果抓住的自己的话,那么就直接返回
return;
}
//如果不是被抓到的点,求他垂直方向上合水平方向上的受力(因为所有的点都是由线来连接的,所有说每个点都对其他的任何一个在屏幕中的点有作用力)
// Sum up all forces pushing this item away
qreal xvel = 0;
qreal yvel = 0;
foreach (QGraphicsItem *item, scene()->items())
{
Node *node = qgraphicsitem_cast
if (!node node == this)
continue;
QLineF line(mapFromItem(node, 0, 0), QPointF(0, 0));
qreal dx = line.dx();
qreal dy = line.dy();
double l = 2.0 * (dx * dx + dy * dy);
if (l > 0)
{
xvel += (dx * 8.0) / l;
yvel += (dy * 8.0) / l;
}
}
//然后求与之相连的点的作用力,这样的作用力会显现的更明显
double weight = (edgeList.size() + 1) * 4.5;
foreach (Edge *edge, edgeList) {
QPointF pos;
if (edge->sourceNode() == this)
pos = mapFromItem(edge->destNode(), 0, 0);
else
pos = mapFromItem(edge->sourceNode(), 0, 0);
xvel += pos.x() / weight;
yvel += pos.y() / weight;
}
if (qAbs(xvel) < xvel =" yvel" scenerect =" scene()-">sceneRect();
newPos = pos() + QPointF(xvel, yvel);
}
OVER