/* a global call queue */
global_queue = new Array();
+if (is_IE) {
+ /* IE is _very_ slow at digraphs, we need bigger pauses to stop
+ it complaining */
+ job_delay = 100;
+} else {
+ job_delay = 10;
+}
+
+/*
+ run the call queue
+ */
function run_queue() {
var qe = global_queue[0];
qe.callback(qe.arg);
global_queue.shift();
if (global_queue.length > 0) {
- setTimeout(run_queue, 30);
+ setTimeout(run_queue, job_delay);
}
}
+/*
+ queue a call. This is used to serialise long async operations in the
+ browser, so that you get less timeouts. It is especially needed on
+ IE, where the canvas widget is terribly slow.
+ */
function queue_call(callback, arg) {
global_queue.push( { callback: callback, arg : arg });
if (global_queue.length == 1) {
- setTimeout(run_queue, 30);
+ setTimeout(run_queue, job_delay);
}
}
/*
- date parser
+ date parser. Not completely general, but good enough
*/
function parse_date(s) {
if (s.length == 5 && s[2] == ':') {
/* maybe its in the global cache? */
if (CSV_Cache[filename] !== undefined) {
+
if (CSV_Cache[filename].pending) {
- /* it might be pending */
- var q = CSV_Cache[filename].queue.length;
- CSV_Cache[filename].queue[q] = {filename:filename, callback:callback};
+ /* its pending load by someone else. Add ourselves to the notify
+ queue so we are told when it is done */
+ CSV_Cache[filename].queue.push({filename:filename, callback:callback});
return;
}
+ /* its ready in the cache - return it via a delayed callback */
var d = { filename: CSV_Cache[filename].filename,
labels: CSV_Cache[filename].labels.slice(0),
data: CSV_Cache[filename].data.slice(0) };
return;
}
- CSV_Cache[filename] = { pending: true, queue: new Array()};
+ /* mark this one pending */
+ CSV_Cache[filename] = { filename:filename, pending: true, queue: new Array()};
/*
async callback when the CSV is loaded
*/
function load_CSV_callback(caller) {
+ /* split by lines */
var csv = caller.r.responseText.split(/\n/g);
+
/* assume first line is column labels */
var labels = csv[0].split(/,/g);
for (var i=0; i<labels.length; i++) {
labels[i] = labels[i].replace(" ", " ", "g");
}
- /* the rest is data */
+
+ /* the rest is data, we assume comma separation */
var data = new Array();
for (var i=1; i<csv.length; i++) {
var row = csv[i].split(/,/g);
}
/* save into the global cache */
- CSV_Cache[caller.filename].filename = filename;
- CSV_Cache[caller.filename].labels = labels;
- CSV_Cache[caller.filename].data = data;
+ CSV_Cache[caller.filename].labels = labels;
+ CSV_Cache[caller.filename].data = data;
+ /* give the caller a copy of the data (via slice()), as they may
+ want to modify it */
var d = { filename: CSV_Cache[filename].filename,
labels: CSV_Cache[filename].labels.slice(0),
data: CSV_Cache[filename].data.slice(0) };
queue_call(caller.callback, d);
/* fire off any pending callbacks */
- for (var q=0; q<CSV_Cache[caller.filename].queue.length; q++) {
- var d = { filename: CSV_Cache[filename].filename,
+ while (CSV_Cache[caller.filename].queue.length > 0) {
+ var qe = CSV_Cache[caller.filename].queue.shift();
+ var d = { filename: filename,
labels: CSV_Cache[filename].labels.slice(0),
data: CSV_Cache[filename].data.slice(0) };
- queue_call(CSV_Cache[caller.filename].queue[q].callback, d);
+ queue_call(qe.callback, d);
}
CSV_Cache[caller.filename].pending = false;
CSV_Cache[caller.filename].queue = null;
var caller = new Object();
caller.r = new XMLHttpRequest();
caller.callback = callback;
- caller.load_CSV_callback = load_CSV_callback;
caller.filename = filename;
/* check the status when that returns */
caller.r.onreadystatechange = function() {
if (caller.r.readyState == 4) {
if (caller.r.status == 200) {
- caller.load_CSV_callback(caller);
+ load_CSV_callback(caller);
} else {
+ /* the load failed */
queue_call(caller.callback, { filename: filename, data: null, labels: null });
- /* fire off any pending callbacks */
- for (var q=0; q<CSV_Cache[caller.filename].queue.length; q++) {
+ while (CSV_Cache[caller.filename].queue.length > 0) {
+ var qe = CSV_Cache[caller.filename].queue.shift();
var d = { filename: CSV_Cache[filename].filename,
labels: null,
data: null };
- queue_call(CSV_Cache[caller.filename].queue[q].callback, d);
+ queue_call(qe.callback, d);
}
CSV_Cache[caller.filename].pending = false;
CSV_Cache[caller.filename].queue = null;
/*
format an integer with N digits by adding leading zeros
+ javascript is so lame ...
*/
function intLength(v, N) {
var r = v + '';
return r;
}
+
/*
return the list of CSV files for the inverters for date pvdate
*/
/* currently displayed graphs, indexed by divname */
global_graphs = new Array();
+/* default dygraph attributes */
defaultAttrs = {
width: 700,
height: 350,
}
if (global_graphs[divname] !== undefined) {
- /* just update the data */
+ /* we already have the graph, just update the data */
var g = global_graphs[divname];
for (var i=0; i<d2.data.length; i++) {
+ /* the rawData_ attribute doesn't take dates */
d2.data[i][0] = d2.data[i][0].valueOf();
}
g.rawData_ = d2.data;
g.drawGraph_(g.rawData_);
} else {
+ /* create a new dygraph */
global_graphs[divname] = new Dygraph(document.getElementById(divname), d2.data, caller.attrs);
}
loading(false);
}
+ /* fire off a request to load the data */
loading(true);
graph_div(divname);
get_csv_data(caller.filenames, caller.columns, loaded_callback);
in_redraw = true;
}
+/*
+ called when the user selects a date
+ */
function set_date(e) {
var dp = datePickerController.getDatePicker("pvdate");
pvdate = dp.date;
show_graphs();
}
+/*
+ setup the datepicker widget
+ */
function setup_datepicker() {
document.getElementById("pvdate").value =
intLength(pvdate.getDate(),2) + "/" + intLength(pvdate.getMonth()+1, 2) + "/" + pvdate.getFullYear();