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

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