| /* |
| Copyright (c) 2004-2006, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/community/licensing.shtml |
| */ |
| |
| dojo.provide("dojo.widget.Chart"); |
| |
| dojo.require("dojo.widget.*"); |
| dojo.require("dojo.gfx.color"); |
| dojo.require("dojo.gfx.color.hsl"); |
| |
| dojo.declare( |
| "dojo.widget.Chart", |
| null, |
| function(){ |
| // summary: Base class for svg and vml implementations of Chart |
| this.series = []; |
| }, |
| { |
| isContainer: false, |
| |
| assignColors: function(){ |
| // summary |
| // Assigns/generates a color for a data series. |
| var hue=30; |
| var sat=120; |
| var lum=120; |
| var steps = Math.round(330/this.series.length); |
| |
| for(var i=0; i<this.series.length; i++){ |
| var c=dojo.gfx.color.hsl2rgb(hue,sat,lum); |
| if(!this.series[i].color){ |
| this.series[i].color = dojo.gfx.color.rgb2hex(c[0],c[1],c[2]); |
| } |
| hue += steps; |
| } |
| }, |
| parseData: function(table){ |
| var thead=table.getElementsByTagName("thead")[0]; |
| var tbody=table.getElementsByTagName("tbody")[0]; |
| if(!(thead&&tbody)) dojo.raise("dojo.widget.Chart: supplied table must define a head and a body."); |
| |
| // set up the series. |
| var columns=thead.getElementsByTagName("tr")[0].getElementsByTagName("th"); // should be <tr><..> |
| |
| // assume column 0 == X |
| for (var i=1; i<columns.length; i++){ |
| var key="column"+i; |
| var label=columns[i].innerHTML; |
| var plotType=columns[i].getAttribute("plotType")||"line"; |
| var color=columns[i].getAttribute("color"); |
| var ds=new dojo.widget.Chart.DataSeries(key,label,plotType,color); |
| this.series.push(ds); |
| } |
| |
| // ok, get the values. |
| var rows=tbody.rows; |
| var xMin=Number.MAX_VALUE,xMax=Number.MIN_VALUE; |
| var yMin=Number.MAX_VALUE,yMax=Number.MIN_VALUE; |
| var ignore = [ |
| "accesskey","align","bgcolor","class", |
| "colspan","height","id","nowrap", |
| "rowspan","style","tabindex","title", |
| "valign","width" |
| ]; |
| |
| for(var i=0; i<rows.length; i++){ |
| var row=rows[i]; |
| var cells=row.cells; |
| var x=Number.MIN_VALUE; |
| for (var j=0; j<cells.length; j++){ |
| if (j==0){ |
| x=parseFloat(cells[j].innerHTML); |
| xMin=Math.min(xMin, x); |
| xMax=Math.max(xMax, x); |
| } else { |
| var ds=this.series[j-1]; |
| var y=parseFloat(cells[j].innerHTML); |
| yMin=Math.min(yMin,y); |
| yMax=Math.max(yMax,y); |
| var o={x:x, value:y}; |
| var attrs=cells[j].attributes; |
| for(var k=0; k<attrs.length; k++){ |
| var attr=attrs.item(k); |
| var bIgnore=false; |
| for (var l=0; l<ignore.length; l++){ |
| if (attr.nodeName.toLowerCase()==ignore[l]){ |
| bIgnore=true; |
| break; |
| } |
| } |
| if(!bIgnore) o[attr.nodeName]=attr.nodeValue; |
| } |
| ds.add(o); |
| } |
| } |
| } |
| return { x:{ min:xMin, max:xMax}, y:{ min:yMin, max:yMax} }; |
| } |
| }); |
| |
| dojo.declare( |
| "dojo.widget.Chart.DataSeries", |
| null, |
| function(key, label, plotType, color){ |
| // summary: |
| // Every chart has a set of data series; this is the series. Note that each |
| // member of value is an object and in the minimum has 2 properties: .x and |
| // .value. |
| // |
| this.id = "DataSeries"+dojo.widget.Chart.DataSeries.count++; |
| this.key = key; |
| this.label = label||this.id; |
| this.plotType = plotType||"line"; // let line be the default. |
| this.color = color; |
| this.values = []; |
| }, |
| { |
| add: function(v){ |
| if(v.x==null||v.value==null){ |
| dojo.raise("dojo.widget.Chart.DataSeries.add: v must have both an 'x' and 'value' property."); |
| } |
| this.values.push(v); |
| }, |
| |
| clear: function(){ |
| this.values=[]; |
| }, |
| |
| createRange: function(len){ |
| var idx = this.values.length-1; |
| var length = (len||this.values.length); |
| return { "index": idx, "length": length, "start":Math.max(idx-length,0) }; |
| }, |
| |
| // trend values |
| getMean: function(len){ |
| var range = this.createRange(len); |
| if(range.index<0){ return 0; } |
| var t = 0; |
| var c = 0; |
| for(var i=range.index; i>=range.start; i--){ |
| var n = parseFloat(this.values[i].value); |
| if(!isNaN(n)){ t += n; c++; } |
| } |
| t /= Math.max(c,1); |
| return t; |
| }, |
| |
| getMovingAverage: function(len){ |
| var range = this.createRange(len); |
| if(range.index<0){ return 0; } |
| var t = 0; |
| var c = 0; |
| for(var i=range.index; i>=range.start; i--){ |
| var n = parseFloat(this.values[i].value); |
| if(!isNaN(n)){ t += n; c++; } |
| } |
| t /= Math.max(c,1); |
| return t; |
| }, |
| |
| getVariance: function(len){ |
| var range = this.createRange(len); |
| if(range.index < 0){ return 0; } |
| var t = 0; // FIXME: for tom: wtf are t, c, and s? |
| var s = 0; |
| var c = 0; |
| for(var i=range.index; i>=range.start; i--){ |
| var n = parseFloat(this.values[i].value); |
| if(!isNaN(n)){ |
| t += n; |
| s += Math.pow(n,2); |
| c++; |
| } |
| } |
| return (s/c)-Math.pow(t/c,2); |
| }, |
| |
| getStandardDeviation: function(len){ |
| return Math.sqrt(this.getVariance(len)); |
| }, |
| |
| getMax: function(len){ |
| var range = this.createRange(len); |
| if(range.index < 0){ return 0; } |
| var t = 0; |
| for (var i=range.index; i>=range.start; i--){ |
| var n=parseFloat(this.values[i].value); |
| if (!isNaN(n)){ |
| t=Math.max(n,t); |
| } |
| } |
| return t; |
| }, |
| |
| getMin: function(len){ |
| var range=this.createRange(len); |
| if(range.index < 0){ return 0; } |
| var t = 0; |
| for(var i=range.index; i>=range.start; i--){ |
| var n = parseFloat(this.values[i].value); |
| if(!isNaN(n)){ |
| t=Math.min(n,t); |
| } |
| } |
| return t; |
| }, |
| |
| getMedian: function(len){ |
| var range = this.createRange(len); |
| |
| if(range.index<0){ return 0; } |
| |
| var a = []; |
| for (var i=range.index; i>=range.start; i--){ |
| var n=parseFloat(this.values[i].value); |
| if (!isNaN(n)){ |
| var b=false; |
| for(var j=0; j<a.length&&!b; j++){ |
| if (n==a[j]) b=true; |
| } |
| if(!b){ a.push(n); } |
| } |
| } |
| a.sort(); |
| if(a.length>0){ return a[Math.ceil(a.length/2)]; } |
| return 0; |
| }, |
| |
| getMode: function(len){ |
| var range=this.createRange(len); |
| if(range.index<0){ return 0; } |
| var o = {}; |
| var ret = 0 |
| var m = 0; |
| for(var i=range.index; i>=range.start; i--){ |
| var n=parseFloat(this.values[i].value); |
| if(!isNaN(n)){ |
| if (!o[this.values[i].value]) o[this.values[i].value] = 1; |
| else o[this.values[i].value]++; |
| } |
| } |
| for(var p in o){ |
| if(m<o[p]){ m=o[p]; ret=p; } |
| } |
| return parseFloat(ret); |
| } |
| }); |
| |
| dojo["requireIf"](dojo.render.svg.capable, "dojo.widget.svg.Chart"); |
| dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.widget.vml.Chart"); |