pvdate = new Date(midnight);
+/* marker for whether we are in a redraw with new data */
+in_redraw = false;
+
/*
show a HTML heading
*/
function hide_div(divname, hidden) {
var div = document.getElementById(divname);
if (hidden) {
- writeDebug("hiding " + divname);
div.style.display = "none";
} else {
- writeDebug("unhiding " + divname);
div.style.display = "block";
}
}
if (s.search("-") != -1) {
s = s.replace("-", "/", "g");
}
- return new Date(s);
+ if (s.search("/") != -1) {
+ return new Date(s);
+ }
+ /* assume time in milliseconds since 1970 */
+ return (+s);
};
+/*
+ parse a CSV value
+ */
+function parse_value(s) {
+ if (s.substring(0,1) == '"') {
+ s = unescape(s.substring(1,s.length-1));
+ writeDebug("s="+s);
+ return s;
+ }
+ var n = new Number(s);
+ if (isNaN(n)) {
+ return s;
+ }
+ return n;
+}
+
/* keep a cache of loaded CSV files */
CSV_Cache = new Array();
if (CSV_Cache[filename].pending) {
/* its pending load by someone else. Add ourselves to the notify
queue so we are told when it is done */
- writeDebug("waiting on: " + filename);
CSV_Cache[filename].queue.push({filename:filename, callback:callback});
return;
}
data[i-1] = new Array();
data[i-1][0] = parse_date(row[0]);
for (var j=1; j<row.length; j++) {
- data[i-1][j] = parseFloat(row[j]);
+ data[i-1][j] = parse_value(row[j]);
}
}
if (caller.r.status == 200) {
load_CSV_callback(caller);
hide_div("nodata", true);
- writeDebug("got file: " + caller.filename);
} else {
/* the load failed */
- writeDebug("missed file: " + caller.filename);
hide_div("nodata", false);
queue_call(caller.callback, { filename: filename, data: null, labels: null });
while (CSV_Cache[caller.filename].queue.length > 0) {
*/
function days_csv_files() {
var list = new Array();
- writeDebug(pvdate);
for (var i=0; i<serialnums.length; i++) {
list[i] = CSV_directory +
pvdate.getFullYear() + "-" +
/* currently displayed graphs, indexed by divname */
global_graphs = new Array();
+/*
+ find a graph by divname
+ */
+function graph_find(divname) {
+ for (var i=0; i<global_graphs.length; i++) {
+ var g = global_graphs[i];
+ if (g.divname == divname) {
+ return g;
+ }
+ }
+ return null;
+}
+
+function nameAnnotation(ann) {
+ return "(" + ann.series + ", " + ann.xval + ")";
+}
+
+annotations = [];
+
+/*
+ try to save an annotation via annotation.cgi
+ */
+function save_annotation(ann) {
+ var r = new XMLHttpRequest();
+ r.open("GET",
+ "annotation.cgi?series="+escape(ann.series)+"&xval="+ann.xval+"&text="+escape(ann.text), true);
+ r.send(null);
+}
+
+/*
+ load annotations from annotations.csv
+ */
+function load_annotations(g) {
+ function callback(d) {
+ var anns_by_name = new Array();
+ annotations = []
+ for (var i=0; i<d.data.length; i++) {
+ var ann = {
+ xval: d.data[i][0],
+ series: d.data[i][1],
+ shortText: '!',
+ text: decodeURIComponent(d.data[i][2])
+ };
+ var a = anns_by_name[nameAnnotation(ann)];
+ if (a == undefined) {
+ anns_by_name[nameAnnotation(ann)] = i;
+ annotations.push(ann);
+ } else {
+ annotations[a] = ann;
+ }
+ }
+ for (var i=0; i<global_graphs.length; i++) {
+ var g = global_graphs[i];
+ g.setAnnotations(annotations);
+ }
+ }
+
+ load_CSV("../CSV/annotations.csv", callback);
+}
+
+function annotation_highlight(ann, point, dg, event) {
+ saveBg = ann.div.style.backgroundColor;
+ ann.div.style.backgroundColor = '#ddd';
+}
+
+function annotation_unhighlight(ann, point, dg, event) {
+ ann.div.style.backgroundColor = saveBg;
+}
+
+/*
+ handle annotation updates
+ */
+function annotation_click(ann, point, dg, event) {
+ ann.text = prompt("Enter annotation", ann.text);
+ for (var i=0; i<annotations.length; i++) {
+ if (annotations[i].xval == ann.xval && annotations[i].series == ann.series) {
+ annotations[i].text = ann.text;
+ if (ann.text == '') {
+ annotations.splice(i,1);
+ i--;
+ }
+ }
+ }
+ for (var i=0; i<global_graphs.length; i++) {
+ var g = global_graphs[i];
+ if (g.series_names.indexOf(ann.series) != -1) {
+ g.setAnnotations(annotations);
+ }
+ }
+ save_annotation(ann);
+}
+
+/*
+ add a new annotation to one graph
+ */
+function annotation_add_graph(g, p, ann) {
+ var anns = g.annotations();
+ if (p.annotation) {
+ /* its an update */
+ if (ann.text == '') {
+ var idx = anns.indexOf(p);
+ if (idx != -1) {
+ anns.splice(idx,1);
+ }
+ } else {
+ p.annotation.text = ann.text;
+ }
+ } else {
+ writeDebugObject(ann);
+ writeDebug(ann.xval);
+ anns.push(ann);
+ }
+ g.setAnnotations(anns);
+}
+
+/*
+ add a new annotation
+ */
+function annotation_add(event, p) {
+ var ann = {
+ series: p.name,
+ xval: p.xval,
+ shortText: '!',
+ text: prompt("Enter annotation", ""),
+ };
+ for (var i=0; i<global_graphs.length; i++) {
+ var g = global_graphs[i];
+ if (g.series_names.indexOf(p.name) != -1) {
+ annotation_add_graph(g, p, ann);
+ }
+ }
+
+ save_annotation(ann);
+}
+
+
/* default dygraph attributes */
defaultAttrs = {
width: 700,
height: 350,
rollPeriod: 1,
strokeWidth: 1,
- showRoller: true
-}
+ showRoller: true,
+ annotationMouseOverHandler: annotation_highlight,
+ annotationMouseOutHandler: annotation_unhighlight,
+ annotationClickHandler: annotation_click,
+ pointClickCallback: annotation_add
+};
+
/*
graph results from a set of CSV files:
caller.attrs['labelsDiv'] = divname + ":labels";
- if (global_graphs[divname] !== undefined) {
+ var g = graph_find(divname);
+
+ if (g != null) {
/* 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.drawGraph_(g.rawData_);
} else {
/* create a new dygraph */
- global_graphs[divname] = new Dygraph(document.getElementById(divname), d2.data, caller.attrs);
+ g = new Dygraph(document.getElementById(divname), d2.data, caller.attrs);
+ g.series_names = caller.attrs.labels;
+ g.divname = divname;
+ g.setAnnotations(annotations);
+ global_graphs.push(g);
}
loading(false);
return graph_csv_files_func(divname, filenames, [column], null, sum, attrs);
}
-/* marker for whether we are in a redraw with new data */
-in_redraw = false;
-
/*
show all the live data graphs
*/
avoidMinZero: true,
valueRange: [0, 12] });
+ load_annotations();
+
in_redraw = true;
}