使用 Protovis 通过 JQuery 动态加载数据
我正在动态地将一些社交网络数据加载到我想要使用 protovis 进行可视化的网页中。(实际上,数据是在两遍过程中加载的 - 首先从 Twitter 获取用户名列表,然后是社交列表连接是从 Google Social API 获取的。)protovis 代码似乎在事件循环内运行,这意味着数据加载代码需要位于该循环之外。
在“打开”protovis 事件循环之前,如何将数据加载到页面中并解析它?目前,我认为存在竞争条件,protovis 试图可视化尚未加载和解析的网络数据?
<html><head><title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript" src="../protovis-3.2/protovis-r3.2.js"></script>
<script type="text/javascript">
//getNet is where we get a list of Twitter usernames
function getNet(){
url="http://search.twitter.com/search.json?q=jisc11&callback=?"
$.getJSON(url,function(json){
users=[]
uniqusers={}
for (var u in json['results']) {
uniqusers[json['results'][u]['from_user']]=1
}
for (var uu in uniqusers)
users.push(uu)
getConnections(users)
})
}
//getConnections is where we find the connections between the users identified by the list of Twitter usernames
function getConnections(users){
//Google social API limits lookup to 50 URLs; need to page this...
if (users.length>50)
users=users.slice(0,49)
str=''
for (var uic=0; uic<users.length; uic++)
str+='http://twitter.com/'+users[uic]+','
url='http://socialgraph.apis.google.com/lookup?q='+str+'&edo=1&callback=?';
$.getJSON(url,function(json){
graph={}
graph['nodes']=[]
userLoc={}
for (var uic=0; uic<users.length; uic++){
graph['nodes'].push({nodeName:users[uic]})
userLoc[users[uic]]=uic
}
graph['links']=[]
for (u in json['nodes']) {
name=u.replace('http://twitter.com/','')
for (var i in json['nodes'][u]['nodes_referenced']){
si=i.replace('http://twitter.com/','')
if ( si in userLoc ){
if (json['nodes'][u]['nodes_referenced'][i]['types'][0]=='contact')
graph['links'].push({source:userLoc[name], target:userLoc[si]})
}
}
}
followers={}
followers={nodes:graph['nodes'],links:graph['links']}
});
}
$(document).ready(function() {
users=['psychemedia','mweller','mhawksey','garethm','gconole','ambrouk']
//getConnections(users)
getNet()
})
</script>
</head>
<body>
<div id="center"><div id="fig">
<script type="text/javascript+protovis">
// This code is taken directly from the protovis example
var w = document.body.clientWidth,
h = document.body.clientHeight,
colors = pv.Colors.category19();
var vis = new pv.Panel()
.width(w)
.height(h)
.fillStyle("white")
.event("mousedown", pv.Behavior.pan())
.event("mousewheel", pv.Behavior.zoom());
var force = vis.add(pv.Layout.Force)
.nodes(followers.nodes)
.links(followers.links);
force.link.add(pv.Line);
force.node.add(pv.Dot)
.size(function(d) (d.linkDegree + 4) * Math.pow(this.scale, -1.5))
.fillStyle(function(d) d.fix ? "brown" : colors(d.group))
.strokeStyle(function() this.fillStyle().darker())
.lineWidth(1)
.title(function(d) d.nodeName)
.event("mousedown", pv.Behavior.drag())
.event("drag", force)
//comment out the next line to remove labels
//.anchor("center").add(pv.Label).textAlign("center").text(function(n) n.nodeName)
vis.render();
</script>
</div></div>
</body></html>
I am dynamically loading some social network data into a web page that I want to visualise using protovis.(Actually, the data is loaded in in a two pass process - first a list of user names is grabbed from Twitter, then a list of social connections is grabbed from the Google Social API.) The protovis code seems to run inside an event loop, which means the data loading code needs to be outside this loop.
How do I load the data into the page and parse it, before "switching on" the protovis event loop? At the moment, I think there's a race condition whereby protovis tries to visualise network data that hasn't been loaded and parsed yet?
<html><head><title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript" src="../protovis-3.2/protovis-r3.2.js"></script>
<script type="text/javascript">
//getNet is where we get a list of Twitter usernames
function getNet(){
url="http://search.twitter.com/search.json?q=jisc11&callback=?"
$.getJSON(url,function(json){
users=[]
uniqusers={}
for (var u in json['results']) {
uniqusers[json['results'][u]['from_user']]=1
}
for (var uu in uniqusers)
users.push(uu)
getConnections(users)
})
}
//getConnections is where we find the connections between the users identified by the list of Twitter usernames
function getConnections(users){
//Google social API limits lookup to 50 URLs; need to page this...
if (users.length>50)
users=users.slice(0,49)
str=''
for (var uic=0; uic<users.length; uic++)
str+='http://twitter.com/'+users[uic]+','
url='http://socialgraph.apis.google.com/lookup?q='+str+'&edo=1&callback=?';
$.getJSON(url,function(json){
graph={}
graph['nodes']=[]
userLoc={}
for (var uic=0; uic<users.length; uic++){
graph['nodes'].push({nodeName:users[uic]})
userLoc[users[uic]]=uic
}
graph['links']=[]
for (u in json['nodes']) {
name=u.replace('http://twitter.com/','')
for (var i in json['nodes'][u]['nodes_referenced']){
si=i.replace('http://twitter.com/','')
if ( si in userLoc ){
if (json['nodes'][u]['nodes_referenced'][i]['types'][0]=='contact')
graph['links'].push({source:userLoc[name], target:userLoc[si]})
}
}
}
followers={}
followers={nodes:graph['nodes'],links:graph['links']}
});
}
$(document).ready(function() {
users=['psychemedia','mweller','mhawksey','garethm','gconole','ambrouk']
//getConnections(users)
getNet()
})
</script>
</head>
<body>
<div id="center"><div id="fig">
<script type="text/javascript+protovis">
// This code is taken directly from the protovis example
var w = document.body.clientWidth,
h = document.body.clientHeight,
colors = pv.Colors.category19();
var vis = new pv.Panel()
.width(w)
.height(h)
.fillStyle("white")
.event("mousedown", pv.Behavior.pan())
.event("mousewheel", pv.Behavior.zoom());
var force = vis.add(pv.Layout.Force)
.nodes(followers.nodes)
.links(followers.links);
force.link.add(pv.Line);
force.node.add(pv.Dot)
.size(function(d) (d.linkDegree + 4) * Math.pow(this.scale, -1.5))
.fillStyle(function(d) d.fix ? "brown" : colors(d.group))
.strokeStyle(function() this.fillStyle().darker())
.lineWidth(1)
.title(function(d) d.nodeName)
.event("mousedown", pv.Behavior.drag())
.event("drag", force)
//comment out the next line to remove labels
//.anchor("center").add(pv.Label).textAlign("center").text(function(n) n.nodeName)
vis.render();
</script>
</div></div>
</body></html>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在获取数据之前,当前正在调用
vis.render()
。可能还有其他问题,但需要在getNet()
之后。编辑1:
vis.render()
现在位于getNet()
之后。我已将 protovis 强制布局创建代码放入函数内,以便我可以控制它的执行时间,并使 vis 和 followers 变量对初始化代码和createLayout
代码。Protovis,特别是力布局,对错误非常不宽容 - 例如错误的结构或节点/链接数据结构的元素计数,并且不会告诉您发生了什么,因此在开发时最好首先使用您知道的静态数据是正确的类型,然后用动态创建的数据替换。
您遇到的问题之一是使用
type="text/javascript+protovis"
通过 protovis 调用 javascript 重写。下面的代码使用
type="text/javascript"
并具有使用+protovis< 的额外
{}
和return
/code> 保存。这允许 getJSON() 和 protovis 在 Chrome 浏览器中共存,而无需重复调用 getNet() 。编辑2:
如果您有兴趣更深入地挖掘,问题来自于protovis中的这段代码:
我用来使用
“text/javascript”的技术
并避免使用"text/javascript+protovis"
既可以解决您的问题,又可以更轻松地在 Firefox 中使用 protovis 调试代码。vis.render()
is currently being called before you get the data. There may be other issues too, but it needs to be aftergetNet()
.EDIT 1:
vis.render()
is now aftergetNet()
. I've put the protovis force layout creation code inside a function so that I can control when it executes, and made thevis
andfollowers
variables visible to both the initialization code and thecreateLayout
code.Protovis, particularly the force layout, is very unforgiving about errors - e.g. wrong structure or count of elements for nodes/links datastructure, and does not tell you what is going on, so in developing it is best to first use static data that you know is of the right kind, and then later replace with dynamically created data.
One part of the problem you were having is that using
type="text/javascript+protovis"
invokes javascript rewriting by protovis. The code below uses
type="text/javascript"
and has the extra{}
s andreturn
s that using+protovis
saves. This allowsgetJSON()
and protovis to coexist in Chrome browser, withoutgetNet()
being called repeatedly.EDIT 2:
In case you are interested in digging a bit deeper, the problem comes from this code in protovis:
The technique I've used to use
"text/javascript"
and avoid using"text/javascript+protovis"
both solves your problem AND makes it easier to debug code using protovis in Firefox.干得好,James - 只需要注意一件事:如果保留
createLayout()
;在 jQuery$(document).ready()
函数中调用,您可能会发现面板出现在错误的位置...如果您希望面板出现在脚本所在的 div 中,请删除jQuery refs 一切都应该没问题。编辑:
在我写这篇文章时,我并不知道 Protovis 中的 canvas 参数 - 只需将 canvas
divid
添加到面板,再加上具有该 id 的 div,就可以完全解决定位问题。Great job James - only one thing to watch out for: If you keep the
createLayout()
; call within the jQuery$(document).ready()
function you might find your panel appearing in the wrong place... if you want the panel to appear within the div your script is in, remove the jQuery refs and all should be fine.Edit:
I wasn't aware of the canvas parameter in Protovis at the time I wrote this - simply adding canvas
divid
to the panel, plus a div with that id, takes care of positioning issues completely.