/* 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; var graph,bgGraph; var graphs; var numYears,gutterX,gutterY,gridX,gridY; var startPath; 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 graphDiv=document.getElementById('graph'); raphael = new Raphael(graphDiv, graphDiv.offsetWidth, graphDiv.offsetHeight); gutterX=10, gutterY=16; gridX=(raphael.width-(gutterX*2))/numYears; gridY=(raphael.height-(gutterY*2)); drawGrid(); var color = "hsl(" + [.6, .5, .5] + ")"; graph = raphael.path().attr({stroke: color, "stroke-width": 4, "stroke-linejoin": "round"}); bgGraph = raphael.path().attr({stroke: "none", opacity: .3, fill: color}); maxPaths=8; graphs=[]; startPath=["M", gutterX , raphael.height - gutterY, "L", raphael.width-gutterX, raphael.height - gutterY]; for (var i=0;ithis.max) this.max=this.data[element][value]; } this.getElement = function(element) { if (element in this.data) return data[element]; //returns an associative array } this.getValue = function(element,value) { if (element in this.data) { if (value in this.data[element]) return this.data[element][value]; //returns a value else return 0; } else return 0; } 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"; } this.getKeys = function() { return Object.keys(this.data); } } 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; //prepare all data for graphing graphData={}; for (i in fields) graphData[fields[i]]=new graphableData(fields[i]); 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); 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)); } } numYears=(classOfRange.end-classOfRange.start); /* test var message="from "+classOfRange.start+" to "+classOfRange.end+"\n"; for (var i in graphData) message+=graphData[i].summary(); alert(message); */ } function drawGrid() { 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(); } function createMenu() { var menu="\n"; document.getElementById("menus").innerHTML=menu; } function drawOneGraph(which,time){ var datum=fields[which]; var datelem=graphData[datum].getKeys()[0]; //draw 1 or multiple graphs. animate between items //maximum number of graphs //construct graph var path,bgPath; var stepY=(gridY/graphData[datum].max); for (var i=0;i<=numYears;i++) { var x=gutterX+(i*gridX), y=raphael.height-gutterY-(stepY*graphData[datum].getValue(datelem,i+classOfRange.start)); if (!i) { path=["M",x,y,"C",x,y]; bgPath=["M", gutterX , raphael.height - gutterY, "L", x, y, "C", x, y]; } if (i&&i