Template:GraphHeader/GraphCreator.js


var loaded = 0;

function onLoadCallback() {

 loaded++;
 if (loaded==2) {
   loadGraphs();
 }

}

google.load('visualization', '1', {}); google.setOnLoadCallback(onLoadCallback);

dojo.require("dojox.charting.Chart2D"); dojo.require("dojox.charting.widget.Legend"); dojo.addOnLoad(onLoadCallback);


function loadGraphs() {

 var graphs = dojo.query('.graph');
 for(var g=0; g<graphs.length; g++) {
   loadGraph(graphs[g]);
 }

}

function loadGraph(graph) {

 var links = dojo.query('a',graph);
 if (links.length!=1) return; // TODO: Nicer error handling?
 dojo.xhrGet( {
   url: links[0].href.replace(/\#.*/,),
   content: {action: 'raw', templates: 'expand'},
   preventCache: true,
   handleAs: "json",
   load: function(responseObject, ioArgs) {
     createGraph(graph, responseObject);
   },
   error: function(responseObject, ioArgs) {
     graph.innerHTML = ;
     graph.appendChild(document.createTextNode('Error loading '));
     graph.appendChild(links[0]);
     graph.appendChild(document.createTextNode('!'));
     graph.appendChild(document.createElement('br'));
     graph.appendChild(document.createTextNode(responseObject.message));
   }
 });

}


var onDataSourceFetched = {}; var cachedDataSource = {}; var tableId = 0;

function createGraph(graph, desc) {

 // Some layout stuff
 graph.innerHTML = ;
 // Create div's for graph
 var chartDiv = document.createElement('div');
 graph.appendChild(chartDiv); // Has to be appended here so we can determine width/height later on.
 var autoWidth  = graph.style.width ===undefined || graph.style.width ===null || graph.style.width ==0 || graph.style.width == || graph.style.width =='auto';
 var autoHeight = graph.style.height===undefined || graph.style.height===null || graph.style.height==0 || graph.style.height== || graph.style.height=='auto';
 if (autoWidth && autoHeight) {
   chartDiv.style.width = desc.width;
   chartDiv.style.height = desc.height;
 } else if (autoWidth) {
   chartDiv.style.width = desc.width;
   chartDiv.style.height = desc.height;
   var graphSize = dojo.contentBox(graph);
   var chartSize = dojo.contentBox(chartDiv);
   chartDiv.style.width = (graphSize.h*chartSize.w/chartSize.h) + 'px'
   chartDiv.style.height = graph.style.height;
 } else if (autoHeight) {
   chartDiv.style.width = desc.width;
   chartDiv.style.height = desc.height;
   var graphSize = dojo.contentBox(graph);
   var chartSize = dojo.contentBox(chartDiv);
   chartDiv.style.width = graph.style.width;
   chartDiv.style.height = (graphSize.w*chartSize.h/chartSize.w) + 'px'
 } else {
   chartDiv.style.width = graph.style.width;
   chartDiv.style.height = graph.style.height;
 }
 graph.style.width = chartDiv.style.width;
 graph.style.height = 'auto'; // The legend may take extra space.
 chartDiv.style.textAlign = 'left';
 var legendCenter = document.createElement('center');
 graph.appendChild(legendCenter);
 var legendDiv = document.createElement('div');
 legendCenter.appendChild(legendDiv);
 // Create chart and legend
 var chart = new dojox.charting.Chart2D(chartDiv);
 for(var a in desc.axes) {
   chart.addAxis(a, desc.axes[a]);
 }
 for(var p in desc.plots) {
   chart.addPlot(p, desc.plots[p]);
 }
 var legend = new dojox.charting.widget.Legend({chart: chart}, legendDiv);
 if (desc.datasource!=undefined) {
   graph.refresh = function() {
     // Query spreadsheet (if necessary) and let result be drawn
     if (!cachedDataSource[desc.datasource] && !onDataSourceFetched[desc.datasource]) {
       onDataSourceFetched[desc.datasource] = [function(response) {
         cachedDataSource[desc.datasource]=response;
         drawDataGraph(desc,chart,legend,response);
       }];
       var query = new google.visualization.Query(desc.datasource);
       query.send(function(response){
         for(var i=0; i<onDataSourceFetched[desc.datasource].length; i++) {
           onDataSourceFetched[desc.datasource][i](response);
         }
       });
     } else if (!cachedDataSource[desc.datasource]) {
       onDataSourceFetched[desc.datasource].push(function(response) {
         drawDataGraph(desc,chart,legend,response);
       });
     } else {
       drawDataGraph(desc,chart,legend,cachedDataSource[desc.datasource]);
     }
   };
 } else if (desc.datatable!=undefined) {
   var urlComponents = desc.datatable.split('#',1);
   var iframeId = "graphDataTableIframe-" + urlComponents[0];
   graph.refresh = function() {
     var doc = window.frames[iframeId];
     if (doc==undefined) {
       if (onDataSourceFetched[urlComponents[0]]) {
         onDataSourceFetched[urlComponents[0]].push(function(fetchedDoc) {
           drawTableGraph(desc,chart,legend,fetchedDoc,urlComponents[1]);
         });
       } else {
         onDataSourceFetched[urlComponents[0]] = [function(fetchedDoc) {
           drawTableGraph(desc,chart,legend,fetchedDoc,urlComponents[1]);
         }];
         dojo.xhrGet( {
           url: urlComponents[0],
           content: {action: 'render'},
           preventCache: true,
           handleAs: "text",
           load: function(responseObject, ioArgs) {
             var iframeId = "graphDataTableIframe-" + urlComponents[0];
             var iframe = document.createElement('iframe');
             iframe.id = iframeId;
             iframe.name = iframeId;
             iframe.style.display = 'none';
             graph.appendChild(iframe);
             var doc = window.frames[iframeId].document;
             doc.write(responseObject);
             for(var i=0; i<onDataSourceFetched[urlComponents[0]].length; i++) {
               onDataSourceFetched[urlComponents[0]][i](doc);
             }
           },
           error: function(responseObject, ioArgs) {
             graph.innerHTML = ;
             graph.appendChild(document.createTextNode('Error loading data table ' + desc.datatable + '!'));
             graph.appendChild(document.createElement('br'));
             graph.appendChild(document.createTextNode(responseObject.message));
           }
         });
       }
     } else {
       drawTableGraph(desc,chart,legend,doc.document,urlComponents[1]);
     }
   };
 } else if (desc.script!=undefined) {
   graph.refresh = function() {
     try {
       drawGraph(desc,chart,legend,eval(desc.script));
     } catch(err) {
       alert('Error drawing graph:\n'+err.message);
     }
   };
 }
 if (graph.refresh!=undefined) graph.refresh();

}

function drawDataGraph(desc,chart,legend,response) {

 if (response.isError()) {
   alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
   return;
 }  
 var data = response.getDataTable();
 var series = dojoSeriesFromDataTable(data,desc.series);
 drawGraph(desc,chart,legend,series);

}

function drawTableGraph(desc,chart,legend,doc,id) {

 if (id==null) {
   var table = doc.getElementsByTagName('table')[0];
 } else {
   var table = doc.getElementById(id);
 }
 // Read table
 var cols = table.rows[0].cells;
 var headers = [], columns = [];
 for(var c=0; c<cols.length; c++) {
   headers.push(cols[c].innerHTML.replace(/^\s*/,).replace(/\s*$/,));
   columns.push([]);
 }
 for(var r=1; r<table.rows.length; r++) {
   var cols = table.rows[r].cells;
   for(var c=0; c<cols.length; c++) {
     var v = cols[c].innerHTML.replace(/^\s*/,).replace(/\s*$/,);
     if (isFinite(v)) v = Number(v);
     columns[c].push(v);
   }
   for(var c=cols.length; c<headers.length; c++) {
     columns[c].push(undefined);
   }
 }
 // Draw graph
 var dataTable = {
   getNumberOfRows: function() { return table.rows.length-1; },
   getNumberOfColumns: function() { return headers.length; },
   getColumnLabel: function(c) { return headers[c]; },
   getValue: function(r,c) { return columns[c][r]; }
 };
 var series = dojoSeriesFromDataTable(dataTable,desc.series);
 drawGraph(desc,chart,legend,series);

}

function drawGraph(desc,chart,legend,series) {

 if (chart.series.length==0) {
   for(var i=0; i<series.length; i++) {
     chart.addSeries(series[i].title, series[i].data, series[i].args);
   }
 } else {
   for(var i=0; i<series.length; i++) {
     chart.updateSeries(series[i].title, series[i].data, series[i].args);
   }
 }
 chart.render();
 for(var a in desc.axes) { // This works around axis titles not being supported!!!
   if (desc.axes[a].title!=undefined) setAxisTitle(chart, a, desc.axes[a].title, 10);
 }
 legend.refresh();

}

function dojoSeriesFromDataTable(dataTable,series) {

 var dojoSeriesArray = [];
 var numrows = dataTable.getNumberOfRows();
 for(var s=0; s<series.length; s++) {
   if (series[s]==null) continue;
   var xc = series[s].x, xf = series[s].xf, yc = series[s].y, yf = series[s].yf, textc = series[s].text, colorc = series[s].color, fontcolorc = series[s].fontColor;
   var dojoSeries = [];
   if (xc==undefined && xf==undefined && textc==undefined && colorc==undefined && fontcolorc==undefined) {
     // Just an ordinary list of values
     for(var r=0; r<numrows; r++) {
       dojoSeries.push(dataTable.getValue(r,yc));
     }
   } else {
     // An object
     var r;
     var cell = function(c,ro) {
       if (r+ro<0 || r+ro>=numrows) return undefined;
       return dataTable.getValue(r+ro,c);
     }
     for(r=0; r<numrows; r++) {
       if (yf!=undefined) {
         var v = {y: eval(yf)};
         if (!isFinite(v.y)) continue;
       } else {
         var v = {y: dataTable.getValue(r,yc)};
       }
       if (xf!=undefined) {
         v['x'] = eval(xf);
         if (!isFinite(v.x)) continue;
       } else if (xc!=undefined) {
         v['x'] = dataTable.getValue(r,xc);
       } 
       if (textc!=undefined) v['text'] = dataTable.getValue(r,textc);
       if (colorc!=undefined) v['color'] = dataTable.getValue(r,colorc);
       if (fontcolorc!=undefined) v['fontColor'] = dataTable.getValue(r,fontcolorc);
       dojoSeries.push(v);
     }
   }
   dojoSeriesArray.push({title: series[s].title===undefined && yc!=undefined ?
                                  dataTable.getColumnLabel(yc) : series[s].title,
                         data: dojoSeries,
                         args: getSeriesArgs(series[s])});
 }
 return dojoSeriesArray;

}

function getSeriesArgs(series) {

 var args = {};
 for(var p in series) {
   if (p=='title' || p=='x' || p=='y' || p=='text' || p=='color' || p=='fontColor') continue;
   args[p] = series[p];
 }
 return args;

}

// Code from http://trac.dojotoolkit.org/ticket/7746 var setAxisTitle=function(chart, axisname, title, fontsizept) {

   var axis = chart.axes[axisname];
   var dim = chart.dim;
   var offsets=chart.offsets;
   var ta = chart.theme.axis;
   var taFont = "font" in axis.opt ? axis.opt.font : ta.font;
   var x;
   var y;
   var label;
   var rotate=0;
   if(axis.vertical && axis.opt.leftBottom) {
       rotate=270;
       label = title;
       y=dim.height/2  - offsets.b/2 + offsets.t/2;
       x=0+2*fontsizept;
   } else if(axis.vertical && !axis.leftBottom) {
       rotate=90;
       label = title;
       y=dim.height/2  - offsets.b/2 + offsets.t/2;
       x=dim.width-2*fontsizept;
   } else {
       label = title;
       x=dim.width/2 + offsets.l/2 - offsets.r/2;
       y=dim.height-fontsizept/2;
   }
   var m = dojox.gfx.matrix;
   var elem = axis.group.createText({x:x, y:y, text:label, align: "middle"});
   elem.setFont({family:taFont.family, size: fontsizept+"pt", weight: "bold"});
   elem.setFill('grey');
   elem.setTransform(m.rotategAt(rotate, x,y));

}