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));
}