comment
[matches/MCTX3420.git] / testing / MCTXWeb / public_html / static / mctx.graph.js
1 /**
2  * Graph sensor and/or actuator values
3  */
4
5 //TODO: Clean this file up, I bow to Jeremy's superior JavaScript knowledge
6
7
8 mctx.graph = {};
9 mctx.graph.api = {};
10 mctx.graph.api.sensors = mctx.api + "sensors";
11 mctx.graph.api.actuators = mctx.api + "actuators";
12 mctx.sensors = {};
13 mctx.actuators = {};
14
15 mctx.graph.devices = {};
16 mctx.graph.dependent = null;
17 mctx.graph.independent = null;
18 mctx.graph.timer = null;
19 mctx.graph.running = false;
20 mctx.graph.chart = null;
21
22 /**
23  * Helper - Calculate pairs of (dependent, independent) values
24  * Given input as (time, value) pairs for dependent and independent
25  * Appends each value pair to the result
26  * @returns result
27  */
28 /**
29  * Helper - Calculate pairs of (dependent, independent) values
30  * Given input as (time, value) pairs for dependent and independent
31  * Appends each value pair to the result
32  * @param {array[][]} dependent Dependent data to be correlated with independent
33  * @param {array[][]} independent Independent data
34  * @param {array[][]} result Storage location
35  * @returns {dataMerge.result}
36  */
37 function dataMerge(dependent, independent, result) {
38         var j = 0;
39         for (var i = 0; i < dependent.length-1; ++i) {
40                 var start = dependent[i][0];
41                 var end = dependent[i+1][0];
42                 var average = 0, n = 0;
43                 for (; j < independent.length; ++j) {
44                         if (independent[j][0] < start)
45                                 continue;
46                         else if (independent[j][0] >= end)
47                                 break;
48                         average += independent[j][1];
49                         n += 1;
50                 }
51                 if (n > 0) {
52                         average /= n;
53                         result.push([dependent[i][1], average]);
54                 }
55         }
56         return result;
57 }
58
59 /**
60  * Helper function adds the sensors and actuators to a form
61  * @param input_type is it a radio? or is it a checkbox?
62  * @param check_first determines whether the first item is checked or not
63  * @param group which group this input belongs to (name field)
64  */
65 $.fn.deployDevices = function(input_type, check_first, group) {
66   var container = this;
67   var apply = function(dict, prefix) {
68     $.each(dict, function(key, val) {
69       //Unique id (name mangling)
70       var id = container.attr('id') + "_" + prefix + "_" + val.name;
71       
72       var attributes = {
73           'type' : input_type, 'value' : key, 'alt' : val.name,
74           'class' : prefix, 'name' : group, 
75           'id' : id
76       };
77       
78       var entry = $("<input/>", attributes);
79       var label = $("<label/>", {'for' : id, 'text' : val.name}); 
80       entry.prop("checked", check_first);
81       check_first = false;
82       container.append(entry).append(label);
83     });
84   }
85   
86   apply(mctx.sensors, 'sensors');
87   apply(mctx.actuators, 'actuators');
88 };
89
90 /**
91  * Identify sensors/actuators
92  * @returns itself (Is this right?)
93  */
94 $.fn.setDevices = function() {
95   // Query for sensors and actuators
96   return $.ajax({
97     url : mctx.api + 'identify', 
98     data : {'sensors' : 1, 'actuators' : 1}
99   }).done(function (data) {
100     mctx.sensors = $.extend(mctx.sensors, data.sensors);
101     mctx.actuators = $.extend(mctx.actuators, data.actuators);
102     
103     //Always set the 'time' option to be checked
104     $("#xaxis input").prop('checked', true);  
105     $("#xaxis").deployDevices("radio", false, 'xaxis');
106     $("#yaxis").deployDevices("checkbox", true, 'yaxis');
107     $("#current_time").val(data.running_time);
108     //Add event listeners for when the
109     $(".change input").change(function () {
110       $("#graph").setGraph();
111     });
112   });
113 };
114
115 function setGraphStatus(on, failText, keep) {
116   if (on) {
117     mctx.graph.running = true;
118     $("#status-text").html("&nbsp;");
119     $("#graph-run").prop("value", "Pause");
120   } else {
121     mctx.graph.running = false;
122     if (failText) {
123       $("#status-text").text(failText).addClass("fail");
124     } else if (!keep) {
125       $("#status-text").text("Graph stopped").removeClass("fail");
126     }
127     $("#graph-run").prop("value", "Run");
128   }
129 }
130
131 function graphUpdater() {
132   var urls = {
133     'sensors' : mctx.graph.api.sensors,
134     'actuators' : mctx.graph.api.actuators
135   }
136   
137   var updater = function () {
138     var responses = [];
139     var ctime =  $("#current_time");
140     
141     var xaxis = mctx.graph.xaxis;
142     var yaxis = mctx.graph.yaxis;
143     var start_time = mctx.graph.start_time;
144     var end_time = mctx.graph.end_time;
145     var devices = mctx.graph.devices;
146     
147     if (xaxis.size() < 1 || yaxis.size() < 1) {
148       setGraphStatus(false, "No x or y axis selected.");
149       return;
150     }
151     
152     $.each(devices, function(key, val) {
153       if (val.urltype in urls) {
154         var parameters = {id : val.id};
155         if (start_time !== null) {
156           parameters.start_time = start_time;
157         }
158         if (end_time !== null) {
159           parameters.end_time = end_time;
160         }
161         responses.push($.ajax({url : urls[val.urltype], data : parameters})
162         .done(function(json) {
163           //alert("Hi from " + json.name);
164           if (!$("#status-text").checkStatus(json)) {
165             setGraphStatus(false, null, true); //Don't reset text, checkstatus just set it.
166             return;
167           }
168           
169           var dev = val.data;
170           for (var i = 0; i < json.data.length; ++i) {
171             if (dev.length <= 0 || json.data[i][0] > dev[dev.length-1][0]) {
172               dev.push(json.data[i]);
173             }
174           }
175           ctime.val(json.running_time);
176           //alert(devices[json.name].data);
177         }));
178       }
179     });
180
181     //... When the response is received, then() will happen (I think?)
182     $.when.apply(this, responses).then(function () {
183       if (mctx.graph.running) {
184         var plot_data = [];
185         
186         yaxis.each(function() {
187           var series = {};
188           series.label = $(this).attr("alt");
189           
190           //alert("Add " + $(this).val() + " to plot");
191           if (xaxis.attr("alt") === "time") {
192             //alert("Against time");
193             series.data = devices[$(this).attr("alt")].data;
194           } else {
195             var result = []
196             dataMerge(devices[xaxis.attr("alt")].data, 
197                       devices[$(this).attr("alt")].data, result);
198             series.data = result;
199           }
200           plot_data.push(series);
201         });
202         
203         if (mctx.graph.chart !== null) {
204           mctx.graph.chart.setData(plot_data);
205           mctx.graph.chart.setupGrid(); 
206           mctx.graph.chart.draw();
207         } else {
208           var options = {
209             legend : {
210               container : "#graph-legend"
211             }
212           };
213           mctx.graph.chart = $.plot("#graph", plot_data, options);
214         }
215         mctx.graph.timer = setTimeout(updater, 1000);
216       }
217     }, function () {
218       setGraphStatus("Connection issue - graph stopped.");
219       //This will always happen when a user closes the page
220       //alert("Graph crashed"); 
221     });
222   };
223   
224   setGraphStatus(true);
225   updater();
226   return this;
227 }
228
229 /**
230  * Sets the graphs to graph stuff.
231  * @returns {$.fn}
232  */
233 $.fn.setGraph = function () {
234   // Determine which actuator/sensors to plot
235   var xaxis = $("#xaxis input[name=xaxis]:checked");
236   var yaxis = $("#yaxis input[name=yaxis]:checked");
237   if (xaxis.size() < 1 || yaxis.size() < 1) {
238     //nothing to plot...
239     setGraphStatus(false, "No x or y axis selected.");
240     return;
241   }
242   
243   var start_time = $("#start_time").val();
244   var end_time = $("#end_time").val();
245   if (!$.isNumeric(start_time)) {
246     start_time = null;
247   }
248   if (!$.isNumeric(end_time)) {
249     end_time = null;
250   }
251
252   var devices = {};
253   var populateDict = function () {
254     var dict = {};
255     dict['urltype'] = $(this).attr("class");
256     dict['id'] = $(this).attr("value");
257     dict['data'] = [];
258     dict['start_time'] = start_time;
259     dict['end_time'] = end_time;
260     devices[$(this).attr("alt")] = dict;
261   };
262   xaxis.each(populateDict);
263   yaxis.each(populateDict);
264   
265   mctx.graph.xaxis = xaxis;
266   mctx.graph.yaxis = yaxis;
267   mctx.graph.start_time = start_time;
268   mctx.graph.end_time = end_time;
269   mctx.graph.devices = devices;
270   
271   if (!mctx.graph.running) {
272     $("#graph-run").val("Pause");
273     $("#status-text").text("")
274     graphUpdater();
275   }
276   
277   return this;
278 };
279
280 $.fn.runButton = function() {
281   if (mctx.graph.running) {
282     setGraphStatus(false);
283     clearTimeout(mctx.graph.timer);
284   } else {
285     $("#graph").setGraph();
286   }
287 };

UCC git Repository :: git.ucc.asn.au