/* Tim Redfern Jan 2012 tim@eclectronics.org Animated graphing - Edmund Rice School Ties see analytics.js example http://net.tutsplus.com/tutorials/javascript-ajax/an-introduction-to-the-raphael-js-library/ aim for today: have a few items that can be chosen 1) switch items - multiple lines view .. x amount of lines + 'other' 2) animate between views 3) rollover points 4) label axes */ var data,raphael,classOfRange,birthplaces,colleges,locations,fields; var graphData; var maxPaths; window.onload = function() { loadData(); createMenu(); //alert(document.getElementById("holder").offsetWidth+","+document.getElementById("holder").offsetHeight); //seems predictable, gives same result in chrome, firefox, mobile safari var graph=document.getElementById('graph'); raphael = new Raphael(graph, graph.offsetWidth, graph.offsetHeight); drawGraph(); } function graphableData(name) { //organises a range of data to graph against a variable value this.name=name; this.data={}; this.max=0; this.addElement = function(element,value) { if (element in this.data) { if (value in this.data[element]) this.data[element][value]++; else this.data[element][value]=1; } else { this.data[element]={}; this.data[element][value]=1 } if (this.data[element][value]>this.max) this.max=this.data[element][value]; } this.getElement = function(element) { if (element in this.data) return data[element]; //returns an associative array } this.summary = function() { var s= ""+name+": "+Object.keys(this.data).length+" elements, max "+this.max+"\n"; var k=Object.keys(this.data); //s+=k+":"; for (i in k) { s+=k[i]+":"; var l=Object.keys(this.data[k[i]]); for (j in l) s+=l[j]+"="+this.data[k[i]][l[j]]+","; s+="\n"; } return s+"\n"; } } function loadData() { maxPaths=8; //replace with json loader fields=["Class size","Location","Birthplace","College","Career"]; fieldNames=["classSize","location","birthplace","college","career"]; //basic { name:"Joe", surname:"Murphy",school:"Dublin",classOf:"86",location:"Ireland",email:"joem20156@gmail.com"}, //extended { name:"Joe", surname:"Murphy",school:"Dublin",classOf:"86",location:"Ireland",email:"joem20156@gmail.com",birthplace:"Ireland",college:"UCD",career:"construction",sports:["soccer","hurling"],nickname:"Virgil"}, data = [ { school:"Dublin",classOf:"86",location:"Ireland",birthplace:"Ireland",college:"UCD",career:"construction",sports:["soccer","hurling"],nickname:"Virgil"}, { school:"Dublin",classOf:"87",location:"Ireland",birthplace:"Ireland",college:"NUIG",career:"law",sports:["soccer","gaelic"],nickname:"Con"}, { school:"Dublin",classOf:"86",location:"Ireland",birthplace:"Ireland",college:"TCD",career:"teaching",sports:["gaelic","hurling"],nickname:"Morty"}, { school:"Dublin",classOf:"88",location:"USA",birthplace:"UK",college:"UL",career:"army",sports:["soccer"],nickname:"Mick"}, { school:"Dublin",classOf:"87",location:"Ireland",birthplace:"Ireland",college:"UCD",career:"law",sports:["soccer","gaelic"],nickname:"Johnjoe"}, { school:"Dublin",classOf:"86",location:"UK",birthplace:"Ireland",college:"TCD",career:"teaching",sports:["handball","hurling"],nickname:"Mossy"}, { school:"Dublin",classOf:"89",location:"USA",birthplace:"UK",college:"UL",career:"army",sports:["soccer"],nickname:"Mick"}, { school:"Dublin",classOf:"90",location:"Ireland",birthplace:"Ireland",college:"UCD",career:"law",sports:["soccer","gaelic"],nickname:"Johnjoe"}, { school:"Dublin",classOf:"88",location:"Ireland",birthplace:"Ireland",college:"UCC",career:"teaching",sports:["handball","hurling"],nickname:"Mossy"}, ]; //analyse data to populate menus etc, this may be loaded direct from corresponding server data classOfRange={}; classOfRange.start=3000; classOfRange.end=0; birthplaces={}; colleges={}; locations={}; for (var i in data) { var year = parseInt(data[i].classOf); classOfRange.start=Math.min(classOfRange.start,year); classOfRange.end=Math.max(classOfRange.end,year); if (data[i].birthplace in birthplaces) birthplaces[data[i].birthplace]++; else birthplaces[data[i].birthplace]=1; if (data[i].college in colleges) colleges[data[i].college]++; else colleges[data[i].college]=1; if (data[i].location in locations) locations[data[i].location]++; else locations[data[i].location]=1; } var numYears=(classOfRange.end-classOfRange.start); //prepare all data for graphing graphData={}; for (i in fields) graphData[fields[i]]=new graphableData(fields[i]); for (var i in data) { var yearField for (j in fields) { if (fields[j]=="Class size") { graphData[fields[j]].addElement("Class size",parseInt(data[i].classOf)); } else graphData[fields[j]].addElement(data[i][fieldNames[j]],parseInt(data[i].classOf)); } } ///* test var message="from "+classOfRange.start+" to "+classOfRange.end+"\n"; for (var i in graphData) message+=graphData[i].summary(); alert(message); //*/ } function drawGraph() { var color = "hsl(" + [.6, .5, .5] + ")"; var numYears=(classOfRange.end-classOfRange.start); var gutterX=10, gutterY=16; //draw grid var gridX=(raphael.width-(gutterX*2))/numYears; var gridY=(raphael.height-(gutterY*2)); raphael.drawGrid(gutterX, gutterY, raphael.width-(gutterX*2), raphael.height -(gutterY*2), numYears, 10, "#000"); //label axis var txt = {font: '12px Helvetica, Arial', fill: "#fff"}; for (var i=0;i<=numYears;i++) raphael.text(gutterX+(i*gridX),raphael.height-gutterY+8,classOfRange.start+i).attr(txt).toBack(); //construct graph var graph = raphael.path().attr({stroke: color, "stroke-width": 4, "stroke-linejoin": "round"}), bgGraph = raphael.path().attr({stroke: "none", opacity: .3, fill: color}); //default graph is 'Class size' //find largest class var classSize=[]; for (var i=0;i<=numYears;i++) classSize[i]=0; for (var i in data) { classSize[parseInt(data[i].classOf)-classOfRange.start]++; } var classMax=0; for (var i in classSize) classMax=Math.max(classMax,classSize[i]); var path,bgPath; var stepY=(gridY/classMax); for (var i=0;i<=numYears;i++) { var x=gutterX+(i*gridX), y=raphael.height-gutterY-(stepY*classSize[i]); if (!i) { path=["M",x,y,"C",x,y]; bgPath=["M", gutterX , raphael.height - gutterY, "L", x, y, "C", x, y]; } if (i&&i/n"; menu+="\n"; document.getElementById("menus").innerHTML=menu; } function doGraph(which){ //draw 1 or multiple graphs. animate between items //maximum number of graphs alert(fields[which]); }