2011-03-13 12 views
5

Estoy cargando dinámicamente algunos datos de redes sociales en una página web que quiero visualizar usando protovis. (En realidad, los datos se cargan en un proceso de dos pasos; primero una lista de usuarios) los nombres son tomados de Twitter, luego se toma una lista de conexiones sociales de la API social de Google). El código protovis parece ejecutarse dentro de un bucle de evento, lo que significa que el código de carga de datos debe estar fuera de este bucle.Uso de Protovis con datos cargados dinámicamente a través de JQuery

¿Cómo cargo los datos en la página y los analizo antes de "encender" el ciclo de eventos de protovis? Por el momento, creo que hay una condición de carrera por la cual Protovis intenta visualizar datos de red que aún no se han cargado y analizado.

<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> 
+0

¿mi respuesta actualizada resuelve su problema ahora? –

+0

He escrito un blog de una demostración usando la solución de James Crook con JQuery haciendo consultas a Twitter y API sociales de Google, y luego graficando el resultado: blog.ouseful.info/2011/04/12/using-protovis-to-visualise-connections- between-people-tweeting-a-particular-term/ – psychemedia

Respuesta

5

vis.render() se está invocando actualmente antes de obtener los datos. Puede haber otros problemas también, pero debe ser posterior al getNet().


EDIT 1:

vis.render() es ahora después de getNet(). Puse el código de creación de diseño de fuerza protovis dentro de una función para que pueda controlar cuándo se ejecuta y las variables vis y followers visibles tanto para el código de inicialización como para el código createLayout.

Protovis, en particular el diseño de fuerza, es muy implacable con los errores, p. estructura incorrecta o recuento de elementos para la estructura de datos nodos/enlaces, y no le dice qué está pasando, por lo que al desarrollarlo es mejor utilizar primero datos estáticos que sabe que son del tipo correcto y luego reemplazarlos con datos creados dinámicamente .

Una parte del problema que tenías es que al usar type="text/javascript+protovis" se invoca la reescritura de JavaScript por protovis. El siguiente código usa type="text/javascript" y tiene los {} s extra y return s que usan +protovis guarda. Esto permite que getJSON() y protovis coexistan en el navegador Chrome, sin que se llame getNet() repetidamente.

<html><head><title></title> 

<script type="text/javascript" src="jquery.js"></script> 
<script type="text/javascript" src="protovis-d3.2.js"></script> 

<body> 
<div id="center"><div id="fig"> 

<script type="text/javascript"> 
var vis; 
var followers={}; 

function createLayout(){ 
    var w = document.body.clientWidth, 
    h = document.body.clientHeight, 
    colors = pv.Colors.category19(); 

    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){ return (d.linkDegree + 4) * Math.pow(this.scale, -1.5);}) 
     .fillStyle(function(d){ return d.fix ? "brown" : colors(d.group);}) 
     .strokeStyle(function(){ return this.fillStyle().darker();}) 
     .lineWidth(1) 
     .title(function(d){return 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(); 
} 

function getNet(){ 
    // OK to have a getJSON function here. 

    followers={nodes:[{nodeName:'mweller', group:6}, 
    {nodeName:'mhawksey', group:6}, 
    {nodeName:'garethm', group:6}, 
    {nodeName:'gconole', group:6}, 
    {nodeName:'ambrouk', group:6} 
    ], 
    links:[ 
    {source:0, target:1, value:1}, 
    {source:1, target:2, value:1}, 
    {source:1, target:4, value:1}, 
    {source:2, target:3, value:1}, 
    {source:2, target:4, value:1}, 
    {source:3, target:4, value:1}]}; 
} 

$(document).ready(function() { 
    getNet(); 
    createLayout(); 
}) 
</script> 

</head> 

</div></div> 

</body></html> 

EDIT 2:

En caso de estar interesado en la excavación de un poco más profundo, el problema viene de este código en Protovis:

pv.listen(window, "load", function() { 
    pv.$ = {i:0, x:document.getElementsByTagName("script")}; 
    for (; pv.$.i < pv.$.x.length; pv.$.i++) { 
    pv.$.s = pv.$.x[pv.$.i]; 
    if (pv.$.s.type == "text/javascript+protovis") { 
     try { 
     window.eval(pv.parse(pv.$.s.text)); 
     } catch (e) { 
     pv.error(e); 
     } 
    } 
    } 
    delete pv.$; 
}); 

La técnica que he usado para use "text/javascript" y evite usar "text/javascript+protovis", ambos resuelven su problema Y hace que sea más fácil depurar código usando protovis en Firefox.

+0

Sí, y no puedo ver cómo llamar a vis.render() cuando deseo desde el código tipo = "texto/javascript" en lugar del tipo = "texto/código javascript + protovis? – psychemedia

+0

Gracias por esa edición adicional; el problema que estaba teniendo, y todavía me sale, es que si pongo una llamada $ .getJSON en la función getNet(), parece que se llama repetidamente (Chrome, OS/X 10.5.8)? ¿Mi suposición era que hay un bucle de eventos en ejecución para mantener la animación protovis en marcha, y que de alguna manera la llamada getJSON se invoca dentro de ese contexto de bucle? – psychemedia

+0

Ejemplo actualizado para evitar la reescritura de JavaScript en el navegador Chrome. –

0

Buen trabajo James: una sola cosa a tener en cuenta: si conservas el createLayout(); llamar dentro de la función jQuery $(document).ready() puede encontrar que su panel aparece en el lugar equivocado ... si desea que el panel aparezca dentro del div en el que se encuentra su script, elimine los jQuery refs y todo debería estar bien.

Editar: que no estaba al tanto del parámetro de lona en Protovis en el momento de escribir este - la simple adición de lona divid al panel, además de un div con ese id, se ocupa de los problemas de posicionamiento por completo.

Cuestiones relacionadas