<?xml version="1.0" encoding="UTF-8"?> 
<Module> 
  <ModulePrefs title="Graphing Connections Between Related OU Courses (Protovis Demo)" 
      author="Tony Hirst (@psychemedia)"
      author_email="tiny.hirst@gmail.com"
      description="A blatant rip off of Martin Hawksey's Google Gadget port of an earlier protovis demo http://mashe.hawksey.info/2011/06/friendviz/"
      thumbnail="http://mashe.hawksey.info/wp-content/uploads/2011/06/friendviz_thumb.png" 
      screenshot="http://mashe.hawksey.info/wp-content/uploads/2011/06/friendviz_screen.png"> 
    <Require feature="idi"/> 
    <Require feature="locked-domain"/>  
    <Require feature="settitle"/>  
  </ModulePrefs> 
  <UserPref name="_ccode" display_name="Course Code" required="false"/> 
  <UserPref name="title" display_name="Gadget Title (optional)" required="false"/> 
  <UserPref name="_table_query_refresh_interval" display_name="Data refresh interval (minutes)" default_value="300" datatype="enum" required="false"> 
<EnumValue value="0" display_value="Do not refresh"/> 
<EnumValue value="60" display_value="1"/> 
<EnumValue value="300" display_value="5"/> 
<EnumValue value="1800" display_value="30"/> 
</UserPref> 
  <Content type="html"> 
  <![CDATA[
  <div id="chart" style="overflow: auto"><img src="http://www.google.com/ig/images/spinner.gif" /></div> 
  <script type="text/javascript" src="http://ouseful.open.ac.uk/protovis-3.2/protovis-r3.2.js"></script> 
 <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> 
  <script type="text/javascript" src="http://www.google.com/jsapi"></script> 
  <script type="text/javascript"> 
    _IG_RegisterOnloadHandler(init);
    
 
    var prefs = null;
 var followers={}
    function init() {
      prefs = new _IG_Prefs();
      var title = prefs.getString('title');
      if (title) {
        _IG_SetTitle(title);
      }
      var container = document.getElementById('chart');
      container.style.width = document.body.clientWidth + 'px';
      container.style.height = document.body.clientHeight + 'px';

      getCourseNet(prefs.getString('_ccode'));
    }
 
function getCourseNet(code1){

  url="http://data-gov.tw.rpi.edu/ws/sparqlproxy.php?query=PREFIX+xsd%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%23%3E%0D%0Aselect+distinct+%3Fname1+%3Fcode2+%3Fname2+%3Fcode3+%3Fname3+from+%3Chttp%3A%2F%2Fdata.open.ac.uk%2Fcontext%2Fcourse%3E+where+{%0D%0A%3Fx+a+%3Chttp%3A%2F%2Fpurl.org%2Fvocab%2Faiiso%2Fschema%23Module%3E.%0D%0A%3Fx+%3Chttp%3A%2F%2Fdata.open.ac.uk%2Fsaou%2Fontology%23courseLevel%3E+%3Chttp%3A%2F%2Fdata.open.ac.uk%2Fsaou%2Fontology%23undergraduate%3E.%0D%0A%3Fx+%3Chttp%3A%2F%2Fcourseware.rkbexplorer.com%2Fontologies%2Fcourseware%23has-title%3E+%3Fname1.%0D%0A%3Fx+%3Chttp%3A%2F%2Fpurl.org%2Fgoodrelations%2Fv1%23isSimilarTo%3E+%3Fz.%0D%0A%3Fz+%3Chttp%3A%2F%2Fcourseware.rkbexplorer.com%2Fontologies%2Fcourseware%23has-title%3E+%3Fname2.%0D%0A%3Fx+%3Chttp%3A%2F%2Fpurl.org%2Fvocab%2Faiiso%2Fschema%23code%3E+%27"+code1+"%27^^xsd%3Astring.%0D%0A%3Fz+%3Chttp%3A%2F%2Fpurl.org%2Fvocab%2Faiiso%2Fschema%23code%3E+%3Fcode2.%0D%0A%3Fz+%3Chttp%3A%2F%2Fpurl.org%2Fgoodrelations%2Fv1%23isSimilarTo%3E+%3Fzz.%0D%0A%3Fzz+%3Chttp%3A%2F%2Fcourseware.rkbexplorer.com%2Fontologies%2Fcourseware%23has-title%3E+%3Fname3.%0D%0A%3Fzz+%3Chttp%3A%2F%2Fpurl.org%2Fvocab%2Faiiso%2Fschema%23code%3E+%3Fcode3.%0D%0A}+LIMIT+100%0D%0A&output=exhibit&tqx=&default-graph-uri=&service-uri=http%3A%2F%2Fdata.open.ac.uk%2Fquery&callback=?"

  $.getJSON(url,function(json){
  code1=code1.toLowerCase()
  uniqCodes=[code1]
  userLoc={}
  userCount=1
  graph={}
    graph['nodes']=[]
    graph['nodes'].push({nodeName:code1})
    graph['links']=[]
    userLoc[code1]=0
    for (var u in json['items']) {
      code2=json['items'][u]['code2'].toLowerCase()
      code3=json['items'][u]['code3'].toLowerCase()
      if (uniqCodes.indexOf(code2) == -1) {
          graph['nodes'].push({nodeName:code2})
          uniqCodes.push(code2)
          userLoc[code2]=userCount
          graph['links'].push({source:userLoc[code1], target:userLoc[code2]})
          userCount++
        } 
        if (uniqCodes.indexOf(code3) == -1) {
          graph['nodes'].push({nodeName:code3})
          uniqCodes.push(code3)
          userLoc[code3]=userCount
          userCount++
        }
        graph['links'].push({source:userLoc[code2], target:userLoc[code3]})
    }
  followers={nodes:graph['nodes'],links:graph['links']}
 netPlot()
})
}
function netPlot(){
// This bit is taken from http://ouseful.open.ac.uk/twitter/friendviz.html
//--
// Tony Hirst got the trick for using Protovis with JQuery/AJAX calls from
// James Crook http://stackoverflow.com/users/507474/james-crook
// in answer to this question I posted on StackOverflow
// http://stackoverflow.com/questions/5289899/using-protovis-with-dynamically-loaded-data-via-jqueryvar 
      w = document.body.clientWidth,
      h = document.body.clientHeight,
      colors = pv.Colors.category19();
 
    vis = new pv.Panel().canvas("chart")
      .width(w)
      .height(h-50)
      .top(50)
      .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)
      .springConstant(0.05)
      .chargeConstant(-80)
      .springLength(150);
 
    force.link.add(pv.Line);
    force.node.add(pv.Dot)
      .size(function(d){ return 2*(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)
      .add(pv.Label).textAlign("center").text(function(n) {return n.nodeName});
      //comment out the next line to remove labels
      //.anchor("center").add(pv.Label).textAlign("center").text(function(n) n.nodeName)
  vis.render();
   
}
  </script> 
  ]]>
 </Content> 
</Module>
