dojo.provide("dojo.charting.Series");
dojo.require("dojo.lang.common");
dojo.require("dojo.charting.Plotters");
dojo.charting.Series = function(/* object? */kwArgs){
// summary
// Create an instance of data series for plotting.
var args = kwArgs || { length:1 };
this.dataSource = args.dataSource || null;
this.bindings = { };
this.color = args.color;
this.label = args.label;
if(args.bindings){
for(var p in args.bindings){
this.addBinding(p, args.bindings[p]);
}
}
};
dojo.extend(dojo.charting.Series, {
bind:function(/* dojo.collections.Store */src, /* object */bindings){
// summary
// Bind this series to src, with bindings.
this.dataSource = src;
this.bindings = bindings;
},
addBinding:function(/* string */name, /* string */binding){
// summary
// Bind to field "binding" using "name".
this.bindings[name] = binding;
},
evaluate:function(/* object? */kwArgs){
// summary
// Evaluate all bindings and return an array of objects describing the bind.
var ret = [];
var a = this.dataSource.getData();
var l = a.length;
var start = 0;
var end = l;
/* Allow for ranges. Can be done in one of two ways:
* 1. { from, to } as 0-based indices
* 2. { length } as num of data points to get; a negative
* value will start from the end of the data set.
* No kwArg object means the full data set will be evaluated
* and returned.
*/
if(kwArgs){
if(kwArgs.from){
start = Math.max(kwArgs.from,0);
if(kwArgs.to){
end = Math.min(kwArgs.to, end);
}
}
else if(kwArgs.length){
if(kwArgs.length < 0){
// length points from end
start = Math.max((end + length),0);
} else {
end = Math.min((start + length), end);
}
}
}
for(var i=start; i<end; i++){
var o = { src: a[i], series: this };
for(var p in this.bindings){
o[p] = this.dataSource.getField(a[i], this.bindings[p]);
}
ret.push(o);
}
// sort by the x axis, if available.
if(typeof(ret[0].x) != "undefined"){
ret.sort(function(a,b){
if(a.x > b.x) return 1;
if(a.x < b.x) return -1;
return 0;
});
}
return ret; // array
},
// trends
trends:{
createRange: function(/* array */values, /* int */len){
// summary
// Creates the data range used for all trends.
var idx = values.length-1;
var length = (len||values.length);
return { "index": idx, "length": length, "start":Math.max(idx-length,0) }; // object
},
mean: function(/* array */values, /* int */len){
// summary
// Returns the mean or average over the set of values.
var range = this.createRange(values, len);
if(range.index<0){ return 0; }
var total = 0;
var count = 0;
for(var i=range.index; i>=range.start; i--){
total += values[i].y;
count++;
}
total /= Math.max(count,1);
return total; // float
},
variance: function(/* array */values,/* int */len){
// summary
// Returns the variance of the set of values.
var range = this.createRange(values,len);
if(range.index < 0){ return 0; }
var total = 0;
var square = 0;
var count = 0;
for(var i=range.index; i>=range.start; i--){
total += values[i].y;
square += Math.pow(values[i].y, 2);
count++;
}
return (square/count)-Math.pow(total/count,2); // float
},
standardDeviation: function(/* array */values, /* int */len){
// summary
// Returns the standard deviation of the set of values.
return Math.sqrt(this.getVariance(values, len)); // float
},
max: function(/* array */values, /* int */len){
// summary
// Returns the max number in the set of values.
var range = this.createRange(values, len);
if(range.index < 0){ return 0; }
var max = Number.MIN_VALUE;
for (var i=range.index; i>=range.start; i--){
max = Math.max(values[i].y,max);
}
return max; // float
},
min: function(/* array */values, /* int */len){
// summary
// Returns the lowest number in the set of values.
var range=this.createRange(values, len);
if(range.index < 0){ return 0; }
var min = Number.MAX_VALUE;
for(var i=range.index; i>=range.start; i--){
min = Math.min(values[i].y, min);
}
return min; // float
},
median: function(/* array */values, /* int */len){
// summary
// Returns the median in the set of values (number closest to the middle of a sorted set).
var range = this.createRange(values, len);
if(range.index<0){ return 0; }
var a = [];
for (var i=range.index; i>=range.start; i--){
var b=false;
for(var j=0; j<a.length; j++){
if(values[i].y == a[j]){
b = true;
break;
}
}
if(!b){
a.push(values[i].y);
}
}
a.sort();
if(a.length > 0){
return a[Math.ceil(a.length / 2)]; // float
}
return 0; // float
},
mode: function(/* array */values, /* int */len){
// summary
// Returns the mode in the set of values
var range=this.createRange(values, len);
if(range.index<0){ return 0; }
var o = {};
var ret = 0
var median = Number.MIN_VALUE;
for(var i=range.index; i>=range.start; i--){
if (!o[values[i].y]){
o[values[i].y] = 1;
} else {
o[values[i].y]++;
}
}
for(var p in o){
if(median < o[p]){
median = o[p];
ret=p;
}
}
return ret;
}
}
});