@cryptotaxi247 / netdata-1 / commits / 8d1f0c2a1

finalized new main chart with adaptive explorer on the chart

Costa Tsaousis (ktsaou) committed Apr 24, 2014 at 02:18 UTC 8d1f0c2a1127b6eed0add0186417503fd18828bf
2 files changed +203 -142
netdata.c
+23 -34
@@ -1103,14 +1103,12 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1103 if(group_count < 1) group_count = 1;
1104 // if(group_count > st->entries / 20) group_count = st->entries / 20;
1105
1106 - size_t printed = 0; // the lines of JSON data we have generated so far
1106 + long printed = 0; // the lines of JSON data we have generated so far
1107
1108 - size_t current_entry = st->current_entry;
1109 - size_t t, lt; // t = the current entry, lt = the lest entry of data
1108 + long stop_entry, current_entry = st->current_entry;
1109
1111 - RRD_DIMENSION *rd;
1112 - size_t c = 0; // counter for dimension loops
1113 - size_t dimensions = 0; // the total number of dimensions present
1110 + int c = 0; // counter for dimension loops
1111 + int dimensions = 0; // the total number of dimensions present
1112
1113 unsigned long long usec = 0;// usec between the entries
1114 char dtm[201]; // temp variable for storing dates
@@ -1118,6 +1116,7 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1116 int we_need_totals = 0; // if set, we should calculate totals for all dimensions
1117
1118 // find how many dimensions we have
1119 + RRD_DIMENSION *rd;
1120 for( rd = st->dimensions ; rd ; rd = rd->next) {
1121 dimensions++;
1122 if(rd->type == RRD_DIMENSION_PCENT_OVER_DIFF_TOTAL || rd->type == RRD_DIMENSION_PCENT_OVER_ROW_TOTAL) we_need_totals++;
@@ -1141,11 +1140,14 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1140 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
1141 group_values[c] = group_counts[c] = 0;
1142
1143 + // print the labels
1144 wb->bytes += sprintf(&wb->buffer[wb->bytes], "{\n %scols%s:\n [\n", kq, kq);
1145 wb->bytes += sprintf(&wb->buffer[wb->bytes], " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
1146 wb->bytes += sprintf(&wb->buffer[wb->bytes], " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
1147 wb->bytes += sprintf(&wb->buffer[wb->bytes], " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
1148
1149 + // print the header for each dimension
1150 + // and update the print_hidden array for the dimensions that should be hidden
1151 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1152 if(rd->hidden)
1153 print_hidden[c] = 1;
@@ -1155,6 +1157,7 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1157 }
1158 }
1159
1160 + // print the begin of row data
1161 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ],\n %srows%s:\n [\n", kq, kq);
1162
1163 // make sure current_entry is within limits
@@ -1162,14 +1165,10 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1165 if(before == 0) before = st->times[current_entry].tv_sec;
1166
1167 // find the oldest entry of the round-robin
1165 - t = rrd_stats_first_entry(st);
1166 - lt = t;
1167 - size_t stop_entry = t;
1168 + stop_entry = rrd_stats_first_entry(st);
1169
1170 // skip the oldest, to have incremental data
1170 - t++;
1171 - if(t >= st->entries) t = 0;
1172 - if(after == 0) after = st->times[t].tv_sec;
1171 + if(after == 0) after = st->times[stop_entry].tv_sec;
1172
1173 // the minimum line length we expect
1174 int line_size = 4096 + (dimensions * 200);
@@ -1182,43 +1181,31 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1181 int normal_annotation_len = snprintf(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1182 normal_annotation[200] = '\0';
1183
1185 - // count down of the entries examined so far
1186 - long count = ((before - after) / update_every) + 1;
1187 -
1184 // to allow grouping on the same values, we need a pad
1185 long pad = before % group_count;
1186
1187 // checks for debuging
1188 if(before < after)
1193 - error("WARNING: The newest value in the database (%lu) is earlier than the oldest (%lu)", before, after);
1189 + debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%lu) is earlier than the oldest (%lu)", st->name, before, after);
1190
1191 if((before - after) > st->entries * update_every)
1196 - error("WARNING: The time difference between the oldest and the newest entries (%lu) is higher than the capacity of the database (%lu)", before - after, st->entries * update_every);
1197 -
1198 - // we need these at the end for debugging
1199 - long count_start = count;
1200 - size_t t_start = t;
1192 + debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%lu) is higher than the capacity of the database (%lu)", st->name, before - after, st->entries * update_every);
1193
1202 - // the loop in dimension data
1194 + // loop in dimension data
1195 int annotate_reset = 0;
1204 - for ( ; t != stop_entry && count >= 0 ; lt = t++) {
1196 + long t = current_entry, lt = current_entry - 1, count; // t = the current entry, lt = the last entry of data
1197 + if(lt < 0) lt = st->entries - 1;
1198 + for (count = printed = 0; t != stop_entry ; t = lt--) {
1199 int print_this = 0;
1200
1207 - if(t >= st->entries) t = 0;
1201 + if(lt < 0) lt = st->entries - 1;
1202
1203 // make sure we return data in the proper time range
1204 if(st->times[t].tv_sec < after || st->times[t].tv_sec > before) continue;
1211 - count--;
1212 -
1213 - // check if we may exceed the buffer provided
1214 - web_buffer_increase(wb, line_size);
1215 -
1216 - // prefer the most recent last entries
1217 - if(((count - pad) / group_count) >= entries_to_show) continue;
1205 + count++;
1206
1207 // ok. we will use this entry!
1208 // find how much usec since the previous entry
1221 -
1209 usec = usecdiff(&st->times[t], &st->times[lt]);
1210
1211 if(((count - pad) % group_count) == 0) {
@@ -1227,6 +1214,9 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1214 break;
1215 }
1216
1217 + // check if we may exceed the buffer provided
1218 + web_buffer_increase(wb, line_size);
1219 +
1220 // generate the local date time
1221 struct tm *tm = localtime(&st->times[t].tv_sec);
1222 if(!tm) { error("localtime() failed."); continue; }
@@ -1327,8 +1317,7 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1317 if(printed) wb->bytes += sprintf(&wb->buffer[wb->bytes], "]}");
1318 wb->bytes += sprintf(&wb->buffer[wb->bytes], "\n ]\n}\n");
1319
1330 - if(!printed)
1331 - error("WARNING: NOTHING PRINTED: %s, after = %lu, before = %lu, diff = %lu, pad = %ld, count = %ld, entries_to_show = %lu, group_count = %lu, current_entry = %lu, t = %lu", st->name, after, before, before - after, pad, count_start, entries_to_show, group_count, current_entry, t_start);
1320 + debug(D_RRD_STATS, "RRD_STATS_JSON: %s Generated %ld rows, total %ld bytes", st->name, printed, wb->bytes);
1321
1322 pthread_mutex_unlock(&st->mutex);
1323 return last_timestamp;
web/index.html
+180 -108
@@ -30,14 +30,15 @@
30 // Set a callback to run when the Google Visualization API is loaded.
31 google.setOnLoadCallback(initCharts);
32
33 - var TARGET_THUMB_GRAPH_WIDTH = 500; // chart width will range from 0.5 to 1.5 of that
34 - var MINIMUM_THUMB_GRAPH_WIDTH = 400; // chart will generally try to be wider than that
35 - var TARGET_THUMB_GRAPH_HEIGHT = 220;
36 - var MAINCHART_MAX_TIME_TO_SHOW = 600;
37 - var THUMBS_MAX_TIME_TO_SHOW = 600;
38 - var MAINCHART_CONTROL_HEIGHT = 100;
39 - var MAINCHART_CONTROL_DIVISOR = 1;
40 - var MAINCHART_POINTS_DIVISOR = 5;
33 + var TARGET_THUMB_GRAPH_WIDTH = 500; // thumb charts width will range from 0.5 to 1.5 of that
34 + var MINIMUM_THUMB_GRAPH_WIDTH = 400; // thumb chart will generally try to be wider than that
35 + var TARGET_THUMB_GRAPH_HEIGHT = 220; // the height of the thumb charts
36 + var THUMBS_MAX_TIME_TO_SHOW = 600; // how much time the thumb charts will present?
37 +
38 + var MAINCHART_MAX_TIME_TO_SHOW = 600; // how much time the main chart will present by default?
39 + var MAINCHART_POINTS_DIVISOR = 10; // how much detailed will the main chart be by default? 1 = finest, higher is faster
40 + var MAINCHART_CONTROL_HEIGHT = 75; // how tall the control chart will be
41 + var MAINCHART_CONTROL_DIVISOR = 2; // how much detailed will the control chart be? 1 = finest, higher is faster
42
43 var MODE_THUMBS = 1;
44 var MODE_MAIN = 2;
@@ -54,11 +55,11 @@
55 // ------------------------------------------------------------------------
56 // common HTML generation
57
57 - function chartIsLoadingHTML(width, height) { return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\" style=\"vertical-align:middle\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>loading chart<br/><br/><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>"; }
58 + function chartIsLoadingHTML(name, width, height) { return "<table><tr><td align=\"center\" width=\"" + width + "\" height=\"" + height + "\" style=\"vertical-align:middle\"><h4><span class=\"glyphicon glyphicon-refresh\"></span><br/><br/>loading " + name + "<br/><br/><span class=\"label label-default\">Please wait...</span></h4></td></tr></table>"; }
59
59 - function showChartIsLoading(id, width, height) {
60 + function showChartIsLoading(id, name, width, height) {
61 //mylog('adding loading chart html in div with id ' + id);
61 - document.getElementById(id).innerHTML = chartIsLoadingHTML(width, height);
62 + document.getElementById(id).innerHTML = chartIsLoadingHTML(name, width, height);
63 }
64
65 function thumbChartActions(i, c, nogroup) {
@@ -119,36 +120,43 @@
120 var dt = before - after;
121 if(dt > c.entries * c.update_every) dt = c.entries * c.update_every;
122
122 - if(maxtime && dt > maxtime) dt = maxtime;
123 + if(maxtime) dt = maxtime;
124
124 - var data_points = dt / c.update_every;
125 + var data_points = Math.round(dt / c.update_every);
126 var screen_points = Math.round(c.chartOptions.width / divisor);
127 + //mylog('screen = ' + screen_points + ', data = ' + data_points + ', divisor = ' + divisor);
128
127 - if(!group) {
129 + if(group <= 0) {
130 if(screen_points > data_points) {
131 c.group = 1;
132 c.points_to_show = data_points;
133 + //mylog("rendering at full detail");
134 }
135 else {
136 c.group = Math.round(data_points / screen_points);
137
135 - if(c.group > 60) c.group = 60;
136 - else if(c.group > 45) c.group = 45;
137 - else if(c.group > 30) c.group = 30;
138 - else if(c.group > 20) c.group = 20;
139 - else if(c.group > 15) c.group = 15;
140 - else if(c.group > 10) c.group = 10;
141 - else if(c.group > 5) c.group = 5;
142 - else if(c.group > 2) c.group = 2;
143 - else c.group = 1;
138 + if(group >= 0) {
139 + if(c.group > 60) c.group = 60;
140 + else if(c.group > 45) c.group = 45;
141 + else if(c.group > 30) c.group = 30;
142 + else if(c.group > 20) c.group = 20;
143 + else if(c.group > 15) c.group = 15;
144 + else if(c.group > 10) c.group = 10;
145 + else if(c.group > 5) c.group = 5;
146 + else if(c.group > 2) c.group = 2;
147 + else c.group = 1;
148 + }
149
150 c.points_to_show = Math.round(data_points / c.group);
151 + //mylog("rendering adaptive");
152 }
153 }
154 else {
155 c.group = group;
156 c.points_to_show = Math.round(data_points / group);
157 + //mylog("rendering with given group");
158 }
159 + //mylog('group = ' + c.group + ', points = ' + c.points_to_show);
160
161 if(mainchart.chartType == 'LineChart') {
162 if(mainchart.group <= 2) mainchart.chartOptions.lineWidth = 1;
@@ -162,21 +170,26 @@
170 if(mainchart) cleanThisChart(mainchart);
171
172 mainchart = $.extend(true, {}, c);
165 - var tempchart = $.extend(true, {}, mainchart);
166 -
173 + mainchart.refreshCount = 0;
174 + mainchart.last_updated = 0;
175 + mainchart.chartOptions.explorer = null;
176 mainchart.chart = null;
177 +
178 mainchart.chartOptions.width = screenWidth();
179 mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
180 if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;
181 + //mainchart.chartOptions.chartArea = {'width': '80%'};
182
183 mainchart.div = 'maingraph';
173 - mainchart.last_updated = 0;
174 -
184 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, MAINCHART_MAX_TIME_TO_SHOW, 0);
176 - mainchart.chartOptions.explorer = null;
185 +
186 + // copy it to the hidden chart
187 + mainchart.hiddenchart = $.extend(true, {}, mainchart);
188 + mainchart.hiddenchart.chartOptions.height = MAINCHART_CONTROL_HEIGHT;
189 + mainchart.hiddenchart.div = 'maingraph_control';
190
191 // initialize the div
179 - showChartIsLoading(mainchart.div, mainchart.chartOptions.width, mainchart.chartOptions.height);
192 + showChartIsLoading(mainchart.div, mainchart.name, mainchart.chartOptions.width, mainchart.chartOptions.height);
193
194 // set the radio buttons
195 setMainChartGroupMethod(mainchart.group_method, 'no-refresh');
@@ -185,48 +198,76 @@
198 $('#group' + mainchart.group).trigger('click');
199 setMainChartGroup(mainchart.group, 'no-refresh');
200
188 - var controlopts = $.extend(true, {}, mainchart.chartOptions, {
189 - lineWidth: 1,
190 - height: MAINCHART_CONTROL_HEIGHT,
191 - chartArea: {'width': '90%'},
192 - hAxis: {'baselineColor': 'none'},
193 - vAxis: {'title': null},
194 - });
201 + switchToMainGraph();
202 + }
203
196 - mainchart.dashboard = new google.visualization.Dashboard(document.getElementById('maingraph_dashboard'));
197 - mainchart.control = new google.visualization.ControlWrapper({
198 - controlType: 'ChartRangeFilter',
199 - containerId: 'maingraph_control',
200 - options: {
201 - filterColumnIndex: 0,
202 - ui: {
203 - chartType: mainchart.chartType,
204 - chartOptions: controlopts,
205 - minRangeSize: MAINCHART_MAX_TIME_TO_SHOW * mainchart.update_every / MAINCHART_POINTS_DIVISOR * 1000,
206 - }
207 - },
208 - });
209 - mainchart.hiddenchart = new google.visualization.ChartWrapper({
210 - chartType: mainchart.chartType,
211 - containerId: 'maingraph_hidden',
212 - options: {
213 - isStacked: mainchart.chartOptions.isStacked,
214 - width: mainchart.chartOptions.width,
215 - height: mainchart.chartOptions.height,
216 - //chartArea: {'height': '80%', 'width': '100%'},
217 - //hAxis: {'slantedText': false},
218 - //legend: {'position': 'none'}
219 - },
220 - });
204 + function refreshHiddenChart(doNext) {
205 + if(refresh_mode == REFRESH_PAUSED && mainchart.hiddenchart.last_updated != 0) {
206 + if(typeof doNext == "function") doNext();
207 + return;
208 + }
209 +
210 + // is it too soon for a refresh?
211 + var now = new Date().getTime();
212 + if((now - mainchart.hiddenchart.last_updated) < (mainchart.hiddenchart.group * mainchart.hiddenchart.update_every * 1000)) {
213 + if(typeof doNext == "function") doNext();
214 + return;
215 + }
216
222 - // load the data for the control and the hidden chart
223 - calculateChartGroup(tempchart, MAINCHART_CONTROL_DIVISOR, 0, 0);
224 - // alert("diff = " + (tempchart.before - tempchart.after) + ", group = " + tempchart.group);
217 + if(mainchart.dashboard && mainchart.hiddenchart.refreshCount > 50) {
218 + mainchart.dashboard.clear();
219 + mainchart.control_wrapper.clear();
220 + mainchart.hidden_wrapper.clear();
221
226 - switchToMainGraph();
222 + mainchart.dashboard = null;
223 + mainchart.control_wrapper = null;
224 + mainchart.hidden_wrapper = null;
225 + }
226 +
227 + if(!mainchart.dashboard) {
228 + var controlopts = $.extend(true, {}, mainchart.chartOptions, {
229 + lineWidth: 1,
230 + height: mainchart.hiddenchart.chartOptions.height,
231 + chartArea: {'width': '98%'},
232 + hAxis: {'baselineColor': 'none'},
233 + vAxis: {'title': null},
234 + });
235 +
236 + mainchart.dashboard = new google.visualization.Dashboard(document.getElementById('maingraph_dashboard'));
237 + mainchart.control_wrapper = new google.visualization.ControlWrapper({
238 + controlType: 'ChartRangeFilter',
239 + containerId: 'maingraph_control',
240 + options: {
241 + filterColumnIndex: 0,
242 + ui: {
243 + chartType: mainchart.chartType,
244 + chartOptions: controlopts,
245 + minRangeSize: (MAINCHART_MAX_TIME_TO_SHOW * 1000 * mainchart.update_every) / MAINCHART_POINTS_DIVISOR,
246 + }
247 + },
248 + });
249 + mainchart.hidden_wrapper = new google.visualization.ChartWrapper({
250 + chartType: mainchart.chartType,
251 + containerId: 'maingraph_hidden',
252 + options: {
253 + isStacked: mainchart.chartOptions.isStacked,
254 + width: mainchart.hiddenchart.chartOptions.width,
255 + height: mainchart.hiddenchart.chartOptions.height,
256 + //chartArea: {'height': '80%', 'width': '100%'},
257 + //hAxis: {'slantedText': false},
258 + //legend: {'position': 'none'}
259 + },
260 + });
261 +
262 + mainchart.hiddenchart.refreshCount = 0;
263 + }
264 +
265 + // load the data for the control and the hidden wrappers
266 + // calculate the group and points to show for the control chart
267 + calculateChartGroup(mainchart.hiddenchart, MAINCHART_CONTROL_DIVISOR, 0, -1);
268
269 $.ajax({
229 - url: generateChartURL(tempchart),
270 + url: generateChartURL(mainchart.hiddenchart),
271 dataType:"json",
272 cache: false
273 })
@@ -235,30 +276,44 @@
276
277 mainchart.control_data = new google.visualization.DataTable(jsondata);
278
238 - google.visualization.events.addListener(mainchart.control, 'ready', mainchartControlReadyEvent);
239 - mainchart.dashboard.bind(mainchart.control, mainchart.hiddenchart);
279 + if(mainchart.hiddenchart.last_updated == 0) {
280 + google.visualization.events.addListener(mainchart.control_wrapper, 'ready', mainchartControlReadyEvent);
281 + mainchart.dashboard.bind(mainchart.control_wrapper, mainchart.hidden_wrapper);
282 + }
283 + if(refresh_mode != REFRESH_PAUSED)
284 + mainchart.control_wrapper.setState({range: {
285 + start: new Date((Math.round(new Date().getTime() / 1000) - MAINCHART_MAX_TIME_TO_SHOW) * 1000),
286 + end: new Date()
287 + }});
288 +
289 mainchart.dashboard.draw(mainchart.control_data);
290 + mainchart.hiddenchart.last_updated = new Date().getTime();
291 + mainchart.hiddenchart.refreshCount++;
292 + })
293 + .always(function() {
294 + if(typeof doNext == "function") doNext();
295 });
296 }
297
298 function mainchartControlReadyEvent() {
245 - google.visualization.events.addListener(mainchart.control, 'statechange', mainchartControlStateHandler);
299 + google.visualization.events.addListener(mainchart.control_wrapper, 'statechange', mainchartControlStateHandler);
300 + //mylog(mainchart);
301 }
302
303 function mainchartControlStateHandler() {
304 // setMainChartPlay('pause');
305
251 - var state = mainchart.control.getState();
306 + var state = mainchart.control_wrapper.getState();
307 mainchart.after = Math.round(state.range.start.getTime() / 1000);
308 mainchart.before = Math.round(state.range.end.getTime() / 1000);
309
310 calculateChartGroup(mainchart, MAINCHART_POINTS_DIVISOR, 0, 0);
256 - console.log('group = ' + mainchart.group + ', points_to_show = ' + mainchart.points_to_show + ', dt = ' + (mainchart.before - mainchart.after));
311 + //mylog('group = ' + mainchart.group + ', points_to_show = ' + mainchart.points_to_show + ', dt = ' + (mainchart.before - mainchart.after));
312
313 $('#group' + mainchart.group).trigger('click');
314 mainchart.last_updated = 0;
315
261 - if(refresh_mode != REFRESH_ZOOMED) zoomGraphs();
316 + if(refresh_mode != REFRESH_PAUSED) pauseGraphs();
317 }
318
319 function initMainChartIndex(i) {
@@ -308,7 +363,6 @@
363
364 if(!norefresh) {
365 mainchart.last_updated = 0;
311 - if(refresh_mode == REFRESH_PAUSED) playGraphs();
366 }
367 }
368
@@ -327,7 +381,6 @@
381
382 if(!norefresh) {
383 mainchart.last_updated = 0;
330 - if(refresh_mode == REFRESH_PAUSED) playGraphs();
384 }
385
386 last_main_chart_avg = g;
@@ -415,8 +468,13 @@
468
469 if(mainchart) {
470 mainchart.chartOptions.width = width;
418 - mainchart.chartOptions.height = $(window).height() - 200;
471 + mainchart.chartOptions.height = $(window).height() - 150 - MAINCHART_CONTROL_HEIGHT;
472 mainchart.last_updated = 0;
473 +
474 + mainchart.hidden_wrapper.setOption('width', width);
475 + mainchart.control_wrapper.setOption('ui.chartOptions.width', width);
476 + mainchart.hiddenchart.chartOptions.width = width;
477 + mainchart.hiddenchart.last_updated = 0;
478 }
479
480 width = thumbWidth();
@@ -424,7 +482,7 @@
482 if(c.enabled && c.chartOptions.width != width) {
483 cleanThisChart(c);
484 c.chartOptions.width = width;
427 - showChartIsLoading(c.div, c.chartOptions.width, c.chartOptions.height);
485 + showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
486 c.last_updated = 0;
487 }
488 });
@@ -436,7 +494,7 @@
494 cleanThisChart(c);
495 c.chartOptions.width = sizes.width;
496 c.chartOptions.height = sizes.height;
439 - showChartIsLoading(c.div, c.chartOptions.width, c.chartOptions.height);
497 + showChartIsLoading(c.div, c.name, c.chartOptions.width, c.chartOptions.height);
498 c.last_updated = 0;
499 }
500 });
@@ -453,62 +511,55 @@
511
512 var REFRESH_PAUSED = 0;
513 var REFRESH_ALWAYS = 1;
456 - var REFRESH_ZOOMED = 2;
514
515 var refresh_mode = REFRESH_PAUSED;
516 var last_refresh = 0;
517 function playGraphs() {
461 - if(refresh_mode != REFRESH_PAUSED) {
462 - // check if the thread died due to a javascript error
463 - var now = new Date().getTime();
464 - if((now - last_refresh) > 5000) {
465 - // it died!
466 - //mylog('It seems the refresh thread died. Restarting it.');
467 - chartsRefresh();
468 - }
469 - return;
470 - }
518 + if(refresh_mode == REFRESH_ALWAYS) return;
519
520 + //mylog('PlayGraphs()');
521 refresh_mode = REFRESH_ALWAYS;
522 $('.mainchart_play_button').button('play');
474 - chartsRefresh();
523 +
524 + // check if the thread died due to a javascript error
525 + var now = new Date().getTime();
526 + if((now - last_refresh) > 5000) {
527 + // it died or never started
528 + //mylog('It seems the refresh thread died. Restarting it.');
529 + chartsRefresh();
530 + }
531 }
532
533 function pauseGraphs() {
534 if(refresh_mode == REFRESH_PAUSED) return;
535
536 + //mylog('PauseGraphs()');
537 refresh_mode = REFRESH_PAUSED;
538 $('.mainchart_play_button').button('pause');
539 }
540
484 - function zoomGraphs() {
485 - if(refresh_mode == REFRESH_ZOOMED) return;
486 -
487 - refresh_mode = REFRESH_ZOOMED;
488 - $('.mainchart_play_button').button('pause');
489 - }
490 -
541 // refresh the proper chart
542 // this is an internal function.
543 // never call it directly, or new javascript threads will be spawn
544 var timeout;
495 - var refresh_count = 0;
545 function chartsRefresh() {
497 - refresh_count++;
498 -
546 if(resize_request) {
547 resizeCharts();
548 resize_request = false;
502 - refresh_mode = REFRESH_ALWAYS;
549 + // refresh_mode = REFRESH_ALWAYS;
550 }
551
552 + last_refresh = new Date().getTime();
553 +
554 if(refresh_mode == REFRESH_PAUSED) {
506 - //mylog("stop refresh");
555 + if(mode == MODE_MAIN && mainchart.last_updated == 0)
556 + mainChartRefresh();
557 + else
558 + timeout = setTimeout(chartsRefresh, 500);
559 +
560 return;
561 }
562
510 - last_refresh = new Date().getTime();
511 -
563 if(mode == MODE_THUMBS) thumbChartsRefresh();
564 else if(mode == MODE_GROUP_THUMBS) groupChartsRefresh();
565 else if(mode == MODE_MAIN) mainChartRefresh();
@@ -519,7 +570,7 @@
570 // this is an internal function.
571 // never call it directly, or new javascript threads will be spawn
572 function triggerRefresh() {
522 - //mylog('triggerRefresh(' + refresh_count + ')');
573 + //mylog('triggerRefresh()');
574
575 // cleanup has to take place when the charts are not refreshed
576 // since the refreshing thread is in this function, it means
@@ -542,8 +593,12 @@
593 return;
594 }
595
545 - if(!refreshChart(mainchart, triggerRefresh))
546 - triggerRefresh();
596 + if(!refreshChart(mainchart, hiddenChartRefresh))
597 + hiddenChartRefresh();
598 + }
599 +
600 + function hiddenChartRefresh() {
601 + refreshHiddenChart(triggerRefresh);
602 }
603
604 function roundRobinRefresh(charts, startat) {
@@ -639,6 +694,23 @@
694 function cleanThisChart(chart, emptydivs) {
695 //mylog('cleanThisChart(' + chart.name + ', ' + emptydivs +')');
696
697 + if(chart.dashboard) {
698 + chart.dashboard.clear();
699 + chart.dashboard = null;
700 +
701 + if(chart.control_wrapper) {
702 + chart.control_wrapper.clear();
703 + chart.control_wrapper = null;
704 + }
705 +
706 + if(chart.hidden_wrapper) {
707 + chart.hidden_wrapper.clear();
708 + chart.hidden_wrapper = null;
709 + }
710 +
711 + chart.control_data = null;
712 + }
713 +
714 if(chart.chart) chart.chart.clearChart();
715 chart.chart = null;
716
@@ -794,7 +866,7 @@
866 c.chartOptions.width = sizes.width;
867 c.chartOptions.height = sizes.height;
868
797 - groupbody += "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">" + thumbChartActions(i, c, 'nogroup') + "</td></tr></table></div>";
869 + groupbody += "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.name, c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">" + thumbChartActions(i, c, 'nogroup') + "</td></tr></table></div>";
870 });
871 groupbody += "";
872
@@ -858,7 +930,7 @@
930
931 if(c.enabled) {
932 var j;
861 - var h = "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">"
933 + var h = "<div class=\"thumbgraph\" id=\"" + c.div + "_parent\"><table><tr><td><div class=\"thumbgraph\" id=\"" + c.div + "\">" + chartIsLoadingHTML(c.name, c.chartOptions.width, c.chartOptions.height) + "</div></td></tr><tr><td align=\"center\">"
934 + thumbChartActions(i, c)
935 + "</td></tr></table></div>";
936