fixed minor issues throughout the code (mainly types); dashboard has now a watermark while loading to show it downloads or renders something; a lot of code cleanup in javascript
Costa Tsaousis (ktsaou) committed
Dec 29, 2015 at 04:21 UTC
f4456c3d41da3d23520106fdb8b5d9f66267a3cb
32 files changed
+1553
-1580
src/appconfig.c
+1
-1
@@ -202,7 +202,7 @@ int load_config(char *filename, int overwrite_used)
202
continue;
203
}
204
205
- int len = strlen(s);
205
+ int len = (int) strlen(s);
206
if(*s == '[' && s[len - 1] == ']') {
207
// new section
208
s[len - 1] = '\0';
src/apps_plugin.c
+25
-26
@@ -45,8 +45,6 @@ int debug = 0;
45
int update_every = 1;
46
unsigned long long file_counter = 0;
47
48
-#define PROC_BUFFER 4096
49
-
48
// ----------------------------------------------------------------------------
49
// memory debugger
50
@@ -64,14 +62,14 @@ struct allocations {
62
void *mark_allocation(void *allocated_ptr, size_t size_without_overheads) {
63
uint32_t *real_ptr = (uint32_t *)allocated_ptr;
64
real_ptr[0] = MALLOC_MARK;
67
- real_ptr[1] = size_without_overheads;
65
+ real_ptr[1] = (uint32_t) size_without_overheads;
66
67
uint32_t *end_ptr = (uint32_t *)(allocated_ptr + MALLOC_PREFIX + size_without_overheads);
68
end_ptr[0] = MALLOC_MARK;
69
70
// fprintf(stderr, "MEMORY_POINTER: Allocated at %p, returning %p.\n", allocated_ptr, (void *)(allocated_ptr + MALLOC_PREFIX));
71
74
- return (void *)(allocated_ptr + MALLOC_PREFIX);
72
+ return allocated_ptr + MALLOC_PREFIX;
73
}
74
75
void *check_allocation(const char *file, int line, const char *function, void *marked_ptr, size_t *size_without_overheads_ptr) {
@@ -249,23 +247,23 @@ long get_pid_max(void) {
247
248
unsigned long long get_hertz(void)
249
{
252
- unsigned long long hz = 1;
250
+ unsigned long long myhz = 1;
251
252
#ifdef _SC_CLK_TCK
255
- if((hz = sysconf(_SC_CLK_TCK)) > 0) {
256
- return hz;
253
+ if((myhz = (unsigned long long int) sysconf(_SC_CLK_TCK)) > 0) {
254
+ return myhz;
255
}
256
#endif
257
258
#ifdef HZ
261
- hz = (unsigned long long)HZ; /* <asm/param.h> */
259
+ myhz = HZ; /* <asm/param.h> */
260
#else
261
/* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
262
hz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
263
#endif
264
267
- error("Unknown HZ value. Assuming %llu.", hz);
268
- return hz;
265
+ error("Unknown HZ value. Assuming %llu.", myhz);
266
+ return myhz;
267
}
268
269
@@ -650,7 +648,7 @@ int read_proc_pid_stat(struct pid_stat *p) {
648
// p->pid = atol(procfile_lineword(ff, 0, 0+i));
649
// comm is at 1
650
// p->state = *(procfile_lineword(ff, 0, 2+i));
653
- p->ppid = atol(procfile_lineword(ff, 0, 3+i));
651
+ p->ppid = (int32_t) atol(procfile_lineword(ff, 0, 3 + i));
652
// p->pgrp = atol(procfile_lineword(ff, 0, 4+i));
653
// p->session = atol(procfile_lineword(ff, 0, 5+i));
654
// p->tty_nr = atol(procfile_lineword(ff, 0, 6+i));
@@ -666,7 +664,7 @@ int read_proc_pid_stat(struct pid_stat *p) {
664
p->cstime = strtoull(procfile_lineword(ff, 0, 16+i), NULL, 10);
665
// p->priority = strtoull(procfile_lineword(ff, 0, 17+i), NULL, 10);
666
// p->nice = strtoull(procfile_lineword(ff, 0, 18+i), NULL, 10);
669
- p->num_threads = atol(procfile_lineword(ff, 0, 19+i));
667
+ p->num_threads = (int32_t) atol(procfile_lineword(ff, 0, 19 + i));
668
// p->itrealvalue = strtoull(procfile_lineword(ff, 0, 20+i), NULL, 10);
669
// p->starttime = strtoull(procfile_lineword(ff, 0, 21+i), NULL, 10);
670
// p->vsize = strtoull(procfile_lineword(ff, 0, 22+i), NULL, 10);
@@ -809,8 +807,8 @@ struct file_descriptor {
807
uint32_t hash;
808
const char *name;
809
int type;
812
- long count;
813
- long pos;
810
+ int count;
811
+ int pos;
812
} *all_files = NULL;
813
814
int all_files_len = 0;
@@ -871,7 +869,7 @@ void file_descriptor_not_used(int id)
869
return;
870
}
871
874
- if(debug) fprintf(stderr, "apps.plugin: decreasing slot %d (count = %ld).\n", id, all_files[id].count);
872
+ if(debug) fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
873
874
if(all_files[id].count > 0) {
875
all_files[id].count--;
@@ -889,7 +887,7 @@ void file_descriptor_not_used(int id)
887
else error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
888
}
889
892
-unsigned long file_descriptor_find_or_add(const char *name)
890
+int file_descriptor_find_or_add(const char *name)
891
{
892
static int last_pos = 0;
893
uint32_t hash = simple_hash(name);
@@ -899,7 +897,7 @@ unsigned long file_descriptor_find_or_add(const char *name)
897
struct file_descriptor *fd = file_descriptor_find(name, hash);
898
if(fd) {
899
// found
902
- if(debug) fprintf(stderr, "apps.plugin: >> found on slot %ld\n", fd->pos);
900
+ if(debug) fprintf(stderr, "apps.plugin: >> found on slot %d\n", fd->pos);
901
fd->count++;
902
return fd->pos;
903
}
@@ -968,7 +966,7 @@ unsigned long file_descriptor_find_or_add(const char *name)
966
967
// else we have an empty slot in 'c'
968
971
- int type = FILETYPE_OTHER;
969
+ int type;
970
if(name[0] == '/') type = FILETYPE_FILE;
971
else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
972
else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
@@ -1041,7 +1039,7 @@ int update_from_proc(void)
1039
1040
while((file = readdir(dir))) {
1041
char *endptr = file->d_name;
1044
- pid_t pid = strtoul(file->d_name, &endptr, 10);
1042
+ pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
1043
if(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0') continue;
1044
1045
p = get_pid_entry(pid);
@@ -1119,7 +1117,7 @@ int update_from_proc(void)
1117
if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
1118
1119
// check if the fds array is small
1122
- int fdid = atol(de->d_name);
1120
+ int fdid = atoi(de->d_name);
1121
if(fdid < 0) continue;
1122
if(fdid >= p->fds_size) {
1123
// it is small, extend it
@@ -1139,7 +1137,7 @@ int update_from_proc(void)
1137
// we don't know this fd, get it
1138
1139
sprintf(fdname, "/proc/%s/fd/%s", file->d_name, de->d_name);
1142
- int l = readlink(fdname, linkname, FILENAME_MAX);
1140
+ ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
1141
if(l == -1) {
1142
if(debug || (p->target && p->target->debug)) {
1143
if(!count_errors++ || debug || (p->target && p->target->debug))
@@ -1337,7 +1335,7 @@ void update_statistics(void)
1335
for (w = target_root; w ; w = w->next) {
1336
targets++;
1337
1340
- w->fds = calloc(sizeof(int), all_files_size);
1338
+ w->fds = calloc(sizeof(int), (size_t) all_files_size);
1339
if(!w->fds)
1340
error("Cannot allocate memory for fds in %s", w->name);
1341
@@ -1748,7 +1746,7 @@ void show_charts(void)
1746
for (w = target_root; w ; w = w->next) {
1747
if(w->target || (!w->processes && !w->exposed)) continue;
1748
1751
- fprintf(stdout, "DIMENSION %s '' incremental 100 %llu %s\n", w->name, (unsigned long long)(Hertz), w->hidden?"hidden,noreset":"noreset");
1749
+ fprintf(stdout, "DIMENSION %s '' incremental 100 %llu %s\n", w->name, Hertz, w->hidden ? "hidden,noreset" : "noreset");
1750
}
1751
1752
fprintf(stdout, "CHART apps.mem '' 'Apps Dedicated Memory (w/o shared)' 'MB' apps apps stacked 20003 %d\n", update_every);
@@ -1915,14 +1913,15 @@ int main(int argc, char **argv)
1913
1914
procfile_adaptive_initial_allocation = 1;
1915
1918
- unsigned long started_t = time(NULL), current_t;
1916
+ time_t started_t = time(NULL);
1917
+ time_t current_t;
1918
Hertz = get_hertz();
1919
pid_max = get_pid_max();
1920
processors = get_processors();
1921
1922
parse_args(argc, argv);
1923
1925
- all_pids = calloc(sizeof(struct pid_stat *), pid_max);
1924
+ all_pids = calloc(sizeof(struct pid_stat *), (size_t) pid_max);
1925
if(!all_pids) {
1926
error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
1927
printf("DISABLE\n");
@@ -1957,7 +1956,7 @@ int main(int argc, char **argv)
1956
if(usec < (update_every * 1000000ULL / 2)) susec = (update_every * 1000000ULL) - usec;
1957
else susec = update_every * 1000000ULL / 2;
1958
1960
- usleep(susec);
1959
+ usleep((__useconds_t) susec);
1960
bcopy(&now, &last, sizeof(struct timeval));
1961
1962
current_t = time(NULL);
src/avl.c
+2
-2
@@ -319,7 +319,7 @@ int avl_removeroot(avl_tree* t) {
319
* returns the last value returned by iterator or 0 if there were no calls
320
* Warning: a<=b must hold
321
*/
322
-int _avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl* a), avl** ret) {
322
+int _avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl*), avl** ret) {
323
int x, c = 0;
324
if (!t->root)
325
return 0;
@@ -361,7 +361,7 @@ int _avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl* a), avl** ret) {
361
return c;
362
}
363
364
-int avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl* a), avl** ret) {
364
+int avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl*), avl** ret) {
365
#ifdef AVL_LOCK_WITH_MUTEX
366
pthread_mutex_lock(&t->mutex);
367
#else
src/avl.h
+4
-4
@@ -12,11 +12,11 @@
12
* Released under GNU General Public License (GPL) version 2
13
*
14
*/
15
-#include <pthread.h>
16
-
15
#ifndef _AVL_H
16
#define _AVL_H 1
17
18
+#include <pthread.h>
19
+
20
// #define AVL_LOCK_WITH_MUTEX 1
21
22
/* Data structures */
@@ -65,13 +65,13 @@ int avl_removeroot(avl_tree* t);
65
* returns the last value returned by iterator or 0 if there were no calls
66
* Warning: a<=b must hold
67
*/
68
-int avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl* a), avl** ret);
68
+int avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl*), avl** ret);
69
70
/* Iterate through elements in t equal to a
71
* for each element calls iter(a) until it returns 0
72
* returns the last value returned by iterator or 0 if there were no calls
73
*/
74
-int avl_search(avl_tree* t, avl* a, int (*iter)(avl* a), avl** ret);
74
+int avl_search(avl_tree* t, avl* a, int (*iter)(avl*), avl** ret);
75
76
/* Initialize the avl_tree
77
*/
src/common.c
+3
-3
@@ -99,7 +99,7 @@ char *trim(char *s)
99
if(!*s || *s == '#') return NULL;
100
101
// skip tailing spaces
102
- int c = strlen(s) - 1;
102
+ long c = (long) strlen(s) - 1;
103
while(c >= 0 && isspace(s[c])) {
104
s[c] = '\0';
105
c--;
@@ -109,7 +109,7 @@ char *trim(char *s)
109
return s;
110
}
111
112
-void *mymmap(const char *filename, unsigned long size, int flags, int ksm)
112
+void *mymmap(const char *filename, size_t size, int flags, int ksm)
113
{
114
int fd;
115
void *mem = NULL;
@@ -139,7 +139,7 @@ void *mymmap(const char *filename, unsigned long size, int flags, int ksm)
139
mem = mmap(NULL, size, PROT_READ|PROT_WRITE, flags|MAP_ANONYMOUS, -1, 0);
140
if(mem) {
141
if(lseek(fd, 0, SEEK_SET) == 0) {
142
- if(read(fd, mem, size) != size)
142
+ if(read(fd, mem, size) != (ssize_t)size)
143
error("Cannot read from file '%s'", filename);
144
}
145
else
src/common.h
+2
-2
@@ -17,7 +17,7 @@ extern void strreverse(char* begin, char* end);
17
extern char *mystrsep(char **ptr, char *s);
18
extern char *trim(char *s);
19
20
-extern void *mymmap(const char *filename, unsigned long size, int flags, int ksm);
20
+extern void *mymmap(const char *filename, size_t size, int flags, int ksm);
21
extern int savememory(const char *filename, void *mem, unsigned long size);
22
23
extern int fd_is_valid(int fd);
@@ -26,7 +26,7 @@ extern char *global_host_prefix;
26
extern int enable_ksm;
27
28
/* Number of ticks per second */
29
-#define HZ hz
29
+#define HZ myhz
30
extern unsigned int hz;
31
extern void get_HZ(void);
32
src/daemon.c
+3
-3
@@ -137,7 +137,7 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
137
fflush(NULL);
138
139
// open the files before forking
140
- int input_fd = -1, output_fd = -1, error_fd = -1, dev_null = -1;
140
+ int input_fd = -1, output_fd = -1, error_fd = -1, dev_null;
141
142
if(input && *input) {
143
if((input_fd = open(input, O_RDONLY, 0666)) == -1) {
@@ -244,7 +244,7 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
244
// close all files
245
if(close_all_files) {
246
int i;
247
- for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--)
247
+ for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
248
if(
249
((access_fd && i != *access_fd) || !access_fd)
250
&& i != dev_null
@@ -300,7 +300,7 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
300
if(fd >= 0) {
301
char b[100];
302
sprintf(b, "%d\n", getpid());
303
- int i = write(fd, b, strlen(b));
303
+ ssize_t i = write(fd, b, strlen(b));
304
if(i <= 0) perror("Cannot write pid to file.");
305
close(fd);
306
}
src/dictionary.c
+16
-4
@@ -40,7 +40,10 @@ static NAME_VALUE *dictionary_name_value_create(DICTIONARY *dict, const char *na
40
debug(D_DICTIONARY, "Creating name value entry for name '%s', value '%s'.", name, value);
41
42
NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
43
- if(!nv) fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
43
+ if(!nv) {
44
+ fatal("Cannot allocate name_value of size %z", sizeof(NAME_VALUE));
45
+ exit(1);
46
+ }
47
48
nv->name = strdup(name);
49
if(!nv->name) fatal("Cannot allocate name_value.name of size %z", strlen(name));
@@ -70,7 +73,10 @@ static void dictionary_name_value_destroy(DICTIONARY *dict, NAME_VALUE *nv) {
73
else {
74
NAME_VALUE *n = dict->values;
75
while(n && n->next && n->next != nv) nv = nv->next;
73
- if(!n || n->next != nv) fatal("Cannot find name_value with name '%s' in dictionary.", nv->name);
76
+ if(!n || n->next != nv) {
77
+ fatal("Cannot find name_value with name '%s' in dictionary.", nv->name);
78
+ exit(1);
79
+ }
80
n->next = nv->next;
81
nv->next = NULL;
82
}
@@ -86,7 +92,10 @@ DICTIONARY *dictionary_create(void) {
92
debug(D_DICTIONARY, "Creating dictionary.");
93
94
DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
89
- if(!dict) fatal("Cannot allocate DICTIONARY");
95
+ if(!dict) {
96
+ fatal("Cannot allocate DICTIONARY");
97
+ exit(1);
98
+ }
99
100
avl_init(&dict->values_index, name_value_compare);
101
pthread_rwlock_init(&dict->rwlock, NULL);
@@ -115,7 +124,10 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
124
if(!nv) {
125
debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
126
nv = dictionary_name_value_create(dict, name, value, value_len);
118
- if(!nv) fatal("Cannot create name_value.");
127
+ if(!nv) {
128
+ fatal("Cannot create name_value.");
129
+ exit(1);
130
+ }
131
return nv->value;
132
}
133
else {
src/global_statistics.c
-1
@@ -3,7 +3,6 @@
3
#endif
4
#include <pthread.h>
5
6
-#include "common.h"
6
#include "global_statistics.h"
7
8
struct global_statistics global_statistics = { 0ULL, 0ULL, 0ULL, 0ULL };
src/log.c
-1
@@ -27,7 +27,6 @@ int access_log_syslog = 1;
27
int error_log_syslog = 1;
28
int output_log_syslog = 1; // debug log
29
30
-
30
void log_date(FILE *out)
31
{
32
char outstr[200];
src/main.c
+10
-11
@@ -158,7 +158,7 @@ void kill_childs()
158
if(tc_child_pid) {
159
info("Killing tc-qos-helper procees");
160
if(killpid(tc_child_pid, SIGTERM) != -1)
161
- waitid(P_PID, tc_child_pid, &info, WEXITED);
161
+ waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED);
162
}
163
tc_child_pid = 0;
164
@@ -171,7 +171,7 @@ void kill_childs()
171
if(cd->pid && !cd->obsolete) {
172
debug(D_EXIT, "killing %s plugin process", cd->id);
173
if(killpid(cd->pid, SIGTERM) != -1)
174
- waitid(P_PID, cd->pid, &info, WEXITED);
174
+ waitid(P_PID, (id_t) cd->pid, &info, WEXITED);
175
}
176
}
177
@@ -317,7 +317,6 @@ int main(int argc, char **argv)
317
318
// --------------------------------------------------------------------
319
320
- silent = 0;
320
error_log_file = config_get("global", "error log", LOG_DIR "/error.log");
321
if(strcmp(error_log_file, "syslog") == 0) {
322
error_log_syslog = 1;
@@ -326,7 +325,7 @@ int main(int argc, char **argv)
325
else if(strcmp(error_log_file, "none") == 0) {
326
error_log_syslog = 0;
327
error_log_file = NULL;
329
- silent = 1; // optimization - do not even generate debug log entries
328
+ // optimization - do not even generate debug log entries
329
}
330
else error_log_syslog = 0;
331
@@ -356,7 +355,7 @@ int main(int argc, char **argv)
355
356
// --------------------------------------------------------------------
357
359
- rrd_default_history_entries = config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
358
+ rrd_default_history_entries = (int) config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
359
if(rrd_default_history_entries < 5 || rrd_default_history_entries > RRD_HISTORY_ENTRIES_MAX) {
360
fprintf(stderr, "Invalid save lines %d given. Defaulting to %d.\n", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
361
rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
@@ -367,7 +366,7 @@ int main(int argc, char **argv)
366
367
// --------------------------------------------------------------------
368
370
- rrd_update_every = config_get_number("global", "update every", UPDATE_EVERY);
369
+ rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
370
if(rrd_update_every < 1 || rrd_update_every > 600) {
371
fprintf(stderr, "Invalid update timer %d given. Defaulting to %d.\n", rrd_update_every, UPDATE_EVERY_MAX);
372
rrd_update_every = UPDATE_EVERY;
@@ -376,9 +375,9 @@ int main(int argc, char **argv)
375
376
// let the plugins know the min update_every
377
{
379
- char buffer[50];
380
- snprintf(buffer, 50, "%d", rrd_update_every);
381
- setenv("NETDATA_UPDATE_EVERY", buffer, 1);
378
+ char buf[50];
379
+ snprintf(buf, 50, "%d", rrd_update_every);
380
+ setenv("NETDATA_UPDATE_EVERY", buf, 1);
381
}
382
383
// --------------------------------------------------------------------
@@ -398,9 +397,9 @@ int main(int argc, char **argv)
397
398
// --------------------------------------------------------------------
399
401
- listen_backlog = config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
400
+ listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
401
403
- listen_port = config_get_number("global", "port", LISTEN_PORT);
402
+ listen_port = (int) config_get_number("global", "port", LISTEN_PORT);
403
if(listen_port < 1 || listen_port > 65535) {
404
fprintf(stderr, "Invalid listen port %d given. Defaulting to %d.\n", listen_port, LISTEN_PORT);
405
listen_port = LISTEN_PORT;
src/plugin_idlejitter.c
+1
-1
@@ -28,7 +28,7 @@ void *cpuidlejitter_main(void *ptr)
28
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
29
error("Cannot set pthread cancel state to ENABLE.");
30
31
- int sleep_ms = config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
31
+ int sleep_ms = (int) config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
32
if(sleep_ms <= 0) {
33
config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
34
sleep_ms = CPU_IDLEJITTER_SLEEP_TIME_MS;
src/plugin_proc.c
+1
-1
@@ -213,7 +213,7 @@ void *proc_main(void *ptr)
213
rrdset_done(stbytes);
214
}
215
216
- usleep(susec);
216
+ usleep((useconds_t) susec);
217
218
// copy current to last
219
bcopy(&now, &last, sizeof(struct timeval));
src/plugin_proc.h
+1
@@ -16,5 +16,6 @@ extern int do_proc_net_rpc_nfsd(int update_every, unsigned long long dt);
16
extern int do_proc_sys_kernel_random_entropy_avail(int update_every, unsigned long long dt);
17
extern int do_proc_interrupts(int update_every, unsigned long long dt);
18
extern int do_proc_softirqs(int update_every, unsigned long long dt);
19
+extern int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt);
20
21
#endif /* NETDATA_PLUGIN_PROC_H */
src/plugin_tc.c
+3
-3
@@ -153,7 +153,7 @@ static void tc_device_classes_cleanup(struct tc_device *d) {
153
static int cleanup_every = 999;
154
155
if(cleanup_every > 0) {
156
- cleanup_every = -config_get_number("plugin:tc", "cleanup unused classes every", 60);
156
+ cleanup_every = (int) -config_get_number("plugin:tc", "cleanup unused classes every", 60);
157
if(cleanup_every > 0) cleanup_every = -cleanup_every;
158
if(cleanup_every == 0) cleanup_every = -1;
159
}
@@ -598,7 +598,7 @@ void *tc_main(void *ptr)
598
else if(first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0 && device && class) {
599
// debug(D_TC_LOOP, "SENT line '%s'", words[1]);
600
if(words[1] && *words[1]) {
601
- class->bytes = atoll(words[1]);
601
+ class->bytes = strtoull(words[1], NULL, 10);
602
class->updated = 1;
603
}
604
else class->bytes = 0;
@@ -673,7 +673,7 @@ void *tc_main(void *ptr)
673
return NULL;
674
}
675
676
- sleep(rrd_update_every);
676
+ sleep((unsigned int) rrd_update_every);
677
}
678
679
return NULL;
src/plugins_d.c
+6
-6
@@ -396,10 +396,10 @@ void *pluginsd_worker_thread(void *arg)
396
397
if(unlikely(!count && cd->enabled)) {
398
error("PLUGINSD: '%s' (pid %d) does not generate usefull output. Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
399
- sleep(cd->update_every * 10);
399
+ sleep((unsigned int) (cd->update_every * 10));
400
}
401
402
- if(likely(cd->enabled)) sleep(cd->update_every);
402
+ if(likely(cd->enabled)) sleep((unsigned int) cd->update_every);
403
else break;
404
}
405
@@ -421,7 +421,7 @@ void *pluginsd_main(void *ptr)
421
422
char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
423
int automatic_run = config_get_boolean("plugins", "enable running new plugins", 1);
424
- int scan_frequency = config_get_number("plugins", "check for new plugins every", 60);
424
+ int scan_frequency = (int) config_get_number("plugins", "check for new plugins every", 60);
425
DIR *dir = NULL;
426
struct dirent *file = NULL;
427
struct plugind *cd;
@@ -447,7 +447,7 @@ void *pluginsd_main(void *ptr)
447
448
if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue;
449
450
- int len = strlen(file->d_name);
450
+ int len = (int) strlen(file->d_name);
451
if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue;
452
if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
453
debug(D_PLUGINSD, "PLUGINSD: File '%s' does not end in '%s'.", file->d_name, PLUGINSD_FILE_SUFFIX);
@@ -484,7 +484,7 @@ void *pluginsd_main(void *ptr)
484
snprintf(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
485
486
cd->enabled = enabled;
487
- cd->update_every = config_get_number(cd->id, "update every", rrd_update_every);
487
+ cd->update_every = (int) config_get_number(cd->id, "update every", rrd_update_every);
488
cd->started_t = time(NULL);
489
490
char *def = "";
@@ -508,7 +508,7 @@ void *pluginsd_main(void *ptr)
508
}
509
510
closedir(dir);
511
- sleep(scan_frequency);
511
+ sleep((unsigned int) scan_frequency);
512
}
513
514
return NULL;
src/popen.c
+2
-2
@@ -78,7 +78,7 @@ FILE *mypopen(const char *command, pid_t *pidptr)
78
79
// close all files
80
int i;
81
- for(i = sysconf(_SC_OPEN_MAX) - 1; i > 0; i--)
81
+ for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
82
if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
83
84
// move the pipe to stdout
@@ -128,7 +128,7 @@ void mypclose(FILE *fp, pid_t pid) {
128
fclose(fp);
129
130
siginfo_t info;
131
- if(waitid(P_PID, pid, &info, WEXITED) != -1) {
131
+ if(waitid(P_PID, (id_t) pid, &info, WEXITED) != -1) {
132
switch(info.si_code) {
133
case CLD_EXITED:
134
error("pid %d exited with code %d.", info.si_pid, info.si_status);
src/proc_diskstats.c
+1
-4
@@ -12,10 +12,7 @@
12
#include "rrd.h"
13
#include "plugin_proc.h"
14
15
-#define RRD_TYPE_DISK "disk"
16
-#define RRD_TYPE_DISK_LEN strlen(RRD_TYPE_DISK)
17
-
18
-#define MAX_PROC_DISKSTATS_LINE 4096
15
+#define RRD_TYPE_DISK "disk"
16
17
int do_proc_diskstats(int update_every, unsigned long long dt) {
18
static procfile *ff = NULL;
src/procfile.c
+1
-2
@@ -235,7 +235,7 @@ cleanup:
235
procfile *procfile_readall(procfile *ff) {
236
debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
237
238
- ssize_t s, r = 1, x = ff->size;
238
+ ssize_t s, r = 1, x;
239
ff->len = 0;
240
241
while(likely(r > 0)) {
@@ -253,7 +253,6 @@ procfile *procfile_readall(procfile *ff) {
253
}
254
ff = new;
255
ff->size += PROCFILE_INCREMENT_BUFFER;
256
- x = PROCFILE_INCREMENT_BUFFER;
256
}
257
258
debug(D_PROCFILE, "Reading file '%s', from position %ld with length %ld", ff->filename, s, ff->size - s);
src/rrd.c
+18
-16
@@ -437,7 +437,8 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
437
st->last_collected_time.tv_usec = 0;
438
st->counter_done = 0;
439
440
- st->gap_when_lost_iterations_above = config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2;
440
+ st->gap_when_lost_iterations_above = (int) (
441
+ config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
442
443
avl_init(&st->dimensions_index, rrddim_compare);
444
@@ -598,7 +599,7 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
599
{
600
debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
601
601
- RRDDIM *i = st->dimensions, *last = NULL;
602
+ RRDDIM *i, *last = NULL;
603
for(i = st->dimensions; i && i != rd ; i = i->next) last = i;
604
605
if(!i) {
@@ -606,8 +607,9 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
607
return;
608
}
609
609
- if(last) last = i->next;
610
- else st->dimensions = i->next;
610
+ if(last) last->next = rd->next;
611
+ else st->dimensions = rd->next;
612
+ rd->next = NULL;
613
614
rrddim_index_del(st, rd);
615
@@ -709,8 +711,8 @@ RRDSET *rrdset_find_bytype(const char *type, const char *id)
711
strncpy(buf, type, RRD_ID_LENGTH_MAX - 1);
712
buf[RRD_ID_LENGTH_MAX - 1] = '\0';
713
strcat(buf, ".");
712
- int len = strlen(buf);
713
- strncpy(&buf[len], id, RRD_ID_LENGTH_MAX - len);
714
+ int len = (int) strlen(buf);
715
+ strncpy(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
716
buf[RRD_ID_LENGTH_MAX] = '\0';
717
718
return(rrdset_find(buf));
@@ -850,8 +852,8 @@ unsigned long long rrdset_done(RRDSET *st)
852
// it is not the first entry
853
// calculate the proper last_collected_time, using usec_since_last_update
854
unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
853
- st->last_collected_time.tv_sec = ut / 1000000ULL;
854
- st->last_collected_time.tv_usec = ut % 1000000ULL;
855
+ st->last_collected_time.tv_sec = (__time_t) (ut / 1000000ULL);
856
+ st->last_collected_time.tv_usec = (__suseconds_t) (ut % 1000000ULL);
857
}
858
859
// if this set has not been updated in the past
@@ -860,8 +862,8 @@ unsigned long long rrdset_done(RRDSET *st)
862
// it has never been updated before
863
// set a fake last_updated, in the past using usec_since_last_update
864
unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
863
- st->last_updated.tv_sec = ut / 1000000ULL;
864
- st->last_updated.tv_usec = ut % 1000000ULL;
865
+ st->last_updated.tv_sec = (__time_t) (ut / 1000000ULL);
866
+ st->last_updated.tv_usec = (__suseconds_t) (ut % 1000000ULL);
867
868
// the first entry should not be stored
869
store_this_entry = 0;
@@ -879,8 +881,8 @@ unsigned long long rrdset_done(RRDSET *st)
881
gettimeofday(&st->last_collected_time, NULL);
882
883
unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
882
- st->last_updated.tv_sec = ut / 1000000ULL;
883
- st->last_updated.tv_usec = ut % 1000000ULL;
884
+ st->last_updated.tv_sec = (__time_t) (ut / 1000000ULL);
885
+ st->last_updated.tv_usec = (__suseconds_t) (ut % 1000000ULL);
886
887
// the first entry should not be stored
888
store_this_entry = 0;
@@ -1049,7 +1051,7 @@ unsigned long long rrdset_done(RRDSET *st)
1051
// it is now time to interpolate values on a second boundary
1052
1053
unsigned long long first_ut = last_ut;
1052
- int iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
1054
+ long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
1055
1056
for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
1057
#ifdef NETDATA_INTERNAL_CHECKS
@@ -1061,7 +1063,7 @@ unsigned long long rrdset_done(RRDSET *st)
1063
debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
1064
}
1065
1064
- st->last_updated.tv_sec = next_ut / 1000000ULL;
1066
+ st->last_updated.tv_sec = (__time_t) (next_ut / 1000000ULL);
1067
st->last_updated.tv_usec = 0;
1068
1069
for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
@@ -1084,8 +1086,8 @@ unsigned long long rrdset_done(RRDSET *st)
1086
, st->id, rd->name
1087
, new_value
1088
, rd->calculated_value
1087
- , (unsigned long long)(next_ut - last_ut)
1088
- , (unsigned long long)(now_ut - last_ut)
1089
+ , (next_ut - last_ut)
1090
+ , (now_ut - last_ut)
1091
);
1092
1093
rd->calculated_value -= new_value;
src/rrd.h
+1
@@ -1,5 +1,6 @@
1
#include <sys/time.h>
2
#include <pthread.h>
3
+#include <stdint.h>
4
5
#include "avl.h"
6
#include "storage_number.h"
src/rrd2json.c
+10
-10
@@ -2,9 +2,9 @@
2
#include <config.h>
3
#endif
4
#include <pthread.h>
5
-#include <sys/time.h>
5
#include <stdlib.h>
6
#include <string.h>
7
+#include <stdint.h>
8
9
#include "log.h"
10
#include "common.h"
@@ -270,8 +270,8 @@ typedef struct rrdresult {
270
RRDSET *st; // the chart this result refers to
271
272
int d; // the number of dimensions
273
- int n; // the number of values in the arrays
274
- int rows; // the number of rows used
273
+ long n; // the number of values in the arrays
274
+ long rows; // the number of rows used
275
276
uint8_t *od; // the options for the dimensions
277
@@ -279,10 +279,10 @@ typedef struct rrdresult {
279
calculated_number *v; // array n x d values
280
uint8_t *o; // array n x d options
281
282
- int c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
282
+ long c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
283
284
- int group; // how many collected values were grouped for each row
285
- int update_every; // what is the suggested update frequency in seconds
284
+ long group; // how many collected values were grouped for each row
285
+ long update_every; // what is the suggested update frequency in seconds
286
287
calculated_number min;
288
calculated_number max;
@@ -449,7 +449,7 @@ uint32_t rrdr_check_options(RRDR *r, uint32_t options)
449
450
void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
451
{
452
- int rows = rrdr_rows(r);
452
+ long rows = rrdr_rows(r);
453
long c, i;
454
RRDDIM *rd;
455
@@ -629,7 +629,7 @@ void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t option
629
static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
630
{
631
//info("RRD2JSON(): %s: BEGIN", r->st->id);
632
- int row_annotations = 0, dates = JSON_DATES_JS, dates_with_new = 0;
632
+ int row_annotations = 0, dates, dates_with_new = 0;
633
char kq[2] = "", // key quote
634
sq[2] = "", // string quote
635
pre_label[101] = "", // before each label
@@ -1051,7 +1051,7 @@ inline void rrdr_done(RRDR *r)
1051
r->c = 0;
1052
}
1053
1054
-static RRDR *rrdr_create(RRDSET *st, int n)
1054
+static RRDR *rrdr_create(RRDSET *st, long n)
1055
{
1056
if(unlikely(!st)) {
1057
error("NULL value given!");
@@ -1546,7 +1546,7 @@ int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long
1546
return 200;
1547
}
1548
1549
-unsigned long rrd_stats_json(int type, RRDSET *st, BUFFER *wb, int points, int group, int group_method, time_t after, time_t before, int only_non_zero)
1549
+time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long points, long group, int group_method, time_t after, time_t before, int only_non_zero)
1550
{
1551
int c;
1552
pthread_rwlock_rdlock(&st->rwlock);
src/rrd2json.h
+1
-1
@@ -57,7 +57,7 @@ extern void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb);
57
58
extern void rrd_stats_all_json(BUFFER *wb);
59
60
-extern unsigned long rrd_stats_json(int type, RRDSET *st, BUFFER *wb, int entries_to_show, int group, int group_method, time_t after, time_t before, int only_non_zero);
60
+extern time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long entries_to_show, long group, int group_method, time_t after, time_t before, int only_non_zero);
61
62
extern int rrd2format(RRDSET *st, BUFFER *out, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp);
63
src/storage_number.c
+3
-3
@@ -76,7 +76,7 @@ storage_number pack_storage_number(calculated_number value, uint32_t flags)
76
#ifdef STORAGE_WITH_MATH
77
// without this there are rounding problems
78
// example: 0.9 becomes 0.89
79
- r += lrint(n);
79
+ r += lrint((double) n);
80
#else
81
r += (storage_number)n;
82
#endif
@@ -153,7 +153,7 @@ int print_calculated_number(char *str, calculated_number value)
153
#ifdef STORAGE_WITH_MATH
154
// without llrint() there are rounding problems
155
// for example 0.9 becomes 0.89
156
- unsigned long long uvalue = llrint(value * (calculated_number)100000);
156
+ unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
157
#else
158
unsigned long long uvalue = value * (calculated_number)100000;
159
#endif
@@ -202,5 +202,5 @@ int print_calculated_number(char *str, calculated_number value)
202
else wstr[1] = '.';
203
204
// return the buffer length
205
- return ( (wstr - str) + 2 + decimal );
205
+ return (int) ((wstr - str) + 2 + decimal );
206
}
src/web_buffer.c
+38
-45
@@ -52,7 +52,7 @@ void buffer_reset(BUFFER *wb)
52
53
const char *buffer_tostring(BUFFER *wb)
54
{
55
- buffer_need_bytes(wb, 1);
55
+ buffer_need_bytes(wb, (size_t)1);
56
wb->buffer[wb->len] = '\0';
57
58
buffer_overflow_check(wb);
@@ -77,8 +77,7 @@ void buffer_strcat(BUFFER *wb, const char *txt)
77
{
78
if(unlikely(!txt || !*txt)) return;
79
80
- if(wb->size - wb->len < 512)
81
- buffer_need_bytes(wb, 512);
80
+ buffer_need_bytes(wb, (size_t)(1));
81
82
char *s = &wb->buffer[wb->len], *end = &wb->buffer[wb->size];
83
long len = wb->len;
@@ -100,7 +99,7 @@ void buffer_strcat(BUFFER *wb, const char *txt)
99
else {
100
// terminate the string
101
// without increasing the length
103
- buffer_need_bytes(wb, 1);
102
+ buffer_need_bytes(wb, (size_t)1);
103
wb->buffer[wb->len] = '\0';
104
}
105
}
@@ -126,8 +125,9 @@ void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args)
125
{
126
if(unlikely(!fmt || !*fmt)) return;
127
128
+ buffer_need_bytes(wb, 1);
129
+
130
size_t len = wb->size - wb->len;
130
- if(unlikely(!len)) return;
131
132
wb->len += vsnprintf(&wb->buffer[wb->len], len, fmt, args);
133
@@ -140,20 +140,13 @@ void buffer_sprintf(BUFFER *wb, const char *fmt, ...)
140
{
141
if(unlikely(!fmt || !*fmt)) return;
142
143
- if(unlikely(wb->len > wb->size)) {
144
- error("web_buffer_sprintf(): already overflown length %ld, size = %ld", wb->len, wb->size);
145
- }
146
-
147
-// if(wb->size - wb->len < 512)
148
-// web_buffer_need_bytes(wb, 512);
143
+ buffer_need_bytes(wb, 1);
144
145
size_t len = wb->size - wb->len, wrote;
146
152
- buffer_need_bytes(wb, len);
153
-
147
va_list args;
148
va_start(args, fmt);
156
- wrote = vsnprintf(&wb->buffer[wb->len], len, fmt, args);
149
+ wrote = (size_t) vsnprintf(&wb->buffer[wb->len], len, fmt, args);
150
va_end(args);
151
152
if(unlikely(wrote >= len)) {
@@ -207,25 +200,25 @@ void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minu
200
b[i++]='t';
201
b[i++]='e';
202
b[i++]='(';
210
- b[i++]= 48 + year / 1000; year -= (year / 1000) * 1000;
211
- b[i++]= 48 + year / 100; year -= (year / 100) * 100;
212
- b[i++]= 48 + year / 10;
213
- b[i++]= 48 + year % 10;
203
+ b[i++]= (char) (48 + year / 1000); year -= (year / 1000) * 1000;
204
+ b[i++]= (char) (48 + year / 100); year -= (year / 100) * 100;
205
+ b[i++]= (char) (48 + year / 10);
206
+ b[i++]= (char) (48 + year % 10);
207
b[i++]=',';
215
- b[i]= 48 + month / 10; if(b[i] != '0') i++;
216
- b[i++]= 48 + month % 10;
208
+ b[i]= (char) (48 + month / 10); if(b[i] != '0') i++;
209
+ b[i++]= (char) (48 + month % 10);
210
b[i++]=',';
218
- b[i]= 48 + day / 10; if(b[i] != '0') i++;
219
- b[i++]= 48 + day % 10;
211
+ b[i]= (char) (48 + day / 10); if(b[i] != '0') i++;
212
+ b[i++]= (char) (48 + day % 10);
213
b[i++]=',';
221
- b[i]= 48 + hours / 10; if(b[i] != '0') i++;
222
- b[i++]= 48 + hours % 10;
214
+ b[i]= (char) (48 + hours / 10); if(b[i] != '0') i++;
215
+ b[i++]= (char) (48 + hours % 10);
216
b[i++]=',';
224
- b[i]= 48 + minutes / 10; if(b[i] != '0') i++;
225
- b[i++]= 48 + minutes % 10;
217
+ b[i]= (char) (48 + minutes / 10); if(b[i] != '0') i++;
218
+ b[i++]= (char) (48 + minutes % 10);
219
b[i++]=',';
227
- b[i]= 48 + seconds / 10; if(b[i] != '0') i++;
228
- b[i++]= 48 + seconds % 10;
220
+ b[i]= (char) (48 + seconds / 10); if(b[i] != '0') i++;
221
+ b[i++]= (char) (48 + seconds % 10);
222
b[i++]=')';
223
b[i]='\0';
224
@@ -248,25 +241,25 @@ void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minute
241
char *b = &wb->buffer[wb->len];
242
243
int i = 0;
251
- b[i++]= 48 + year / 1000; year -= (year / 1000) * 1000;
252
- b[i++]= 48 + year / 100; year -= (year / 100) * 100;
253
- b[i++]= 48 + year / 10;
254
- b[i++]= 48 + year % 10;
244
+ b[i++]= (char) (48 + year / 1000); year -= (year / 1000) * 1000;
245
+ b[i++]= (char) (48 + year / 100); year -= (year / 100) * 100;
246
+ b[i++]= (char) (48 + year / 10);
247
+ b[i++]= (char) (48 + year % 10);
248
b[i++]='-';
256
- b[i++]= 48 + month / 10;
257
- b[i++]= 48 + month % 10;
249
+ b[i++]= (char) (48 + month / 10);
250
+ b[i++]= (char) (48 + month % 10);
251
b[i++]='-';
259
- b[i++]= 48 + day / 10;
260
- b[i++]= 48 + day % 10;
252
+ b[i++]= (char) (48 + day / 10);
253
+ b[i++]= (char) (48 + day % 10);
254
b[i++]=' ';
262
- b[i++]= 48 + hours / 10;
263
- b[i++]= 48 + hours % 10;
255
+ b[i++]= (char) (48 + hours / 10);
256
+ b[i++]= (char) (48 + hours % 10);
257
b[i++]=':';
265
- b[i++]= 48 + minutes / 10;
266
- b[i++]= 48 + minutes % 10;
258
+ b[i++]= (char) (48 + minutes / 10);
259
+ b[i++]= (char) (48 + minutes % 10);
260
b[i++]=':';
268
- b[i++]= 48 + seconds / 10;
269
- b[i++]= 48 + seconds % 10;
261
+ b[i++]= (char) (48 + seconds / 10);
262
+ b[i++]= (char) (48 + seconds % 10);
263
b[i]='\0';
264
265
wb->len += i;
@@ -313,15 +306,15 @@ void buffer_free(BUFFER *b)
306
free(b);
307
}
308
316
-void buffer_increase(BUFFER *b, long free_size_required)
309
+void buffer_increase(BUFFER *b, size_t free_size_required)
310
{
311
buffer_overflow_check(b);
312
320
- long left = b->size - b->len;
313
+ size_t left = b->size - b->len;
314
315
if(left >= free_size_required) return;
316
324
- long increase = free_size_required - left;
317
+ size_t increase = free_size_required - left;
318
if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
319
320
debug(D_WEB_BUFFER, "Increasing data buffer from size %d to %d.", b->size, b->size + increase);
src/web_buffer.h
+4
-4
@@ -8,8 +8,8 @@
8
#define WEB_DATA_LENGTH_INCREASE_STEP 16384
9
10
typedef struct web_buffer {
11
- long size; // allocation size of buffer
12
- long len; // current data length in buffer
11
+ size_t size; // allocation size of buffer
12
+ size_t len; // current data length in buffer
13
char *buffer; // the buffer
14
int contenttype;
15
time_t date; // the date this content has been generated
@@ -35,7 +35,7 @@ typedef struct web_buffer {
35
#define buffer_strlen(wb) ((wb)->len)
36
extern const char *buffer_tostring(BUFFER *wb);
37
38
-#define buffer_need_bytes(buffer, needed_free_size) do { if(unlikely((buffer)->size - (buffer)->len < (long)(needed_free_size))) buffer_increase((buffer), (long)(needed_free_size)); } while(0)
38
+#define buffer_need_bytes(buffer, needed_free_size) do { if(unlikely((buffer)->size - (buffer)->len < (size_t)(needed_free_size))) buffer_increase((buffer), (size_t)(needed_free_size)); } while(0)
39
40
#define buffer_flush(wb) wb->buffer[wb->len = 0] = '\0'
41
extern void buffer_reset(BUFFER *wb);
@@ -48,7 +48,7 @@ extern void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, i
48
49
extern BUFFER *buffer_create(long size);
50
extern void buffer_free(BUFFER *b);
51
-extern void buffer_increase(BUFFER *b, long free_size_required);
51
+extern void buffer_increase(BUFFER *b, size_t free_size_required);
52
53
extern void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...);
54
extern void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args);
src/web_client.c
+21
-20
@@ -436,7 +436,7 @@ uint32_t web_client_api_request_v1_data_options(char *o)
436
return ret;
437
}
438
439
-int web_client_api_request_v1_data_format(char *name)
439
+uint32_t web_client_api_request_v1_data_format(char *name)
440
{
441
if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
442
return DATASOURCE_DATATABLE_JSON;
@@ -471,7 +471,7 @@ int web_client_api_request_v1_data_format(char *name)
471
return DATASOURCE_JSON;
472
}
473
474
-int web_client_api_request_v1_data_google_format(char *name)
474
+uint32_t web_client_api_request_v1_data_google_format(char *name)
475
{
476
if(!strcmp(name, "json"))
477
return DATASOURCE_DATATABLE_JSONP;
@@ -579,7 +579,8 @@ int web_client_api_request_v1_data(struct web_client *w, char *url)
579
, *after_str = NULL
580
, *points_str = NULL;
581
582
- int format = DATASOURCE_JSON, group = GROUP_MAX;
582
+ int group = GROUP_MAX;
583
+ uint32_t format = DATASOURCE_JSON;
584
uint32_t options = 0x00000000;
585
586
while(url) {
@@ -842,7 +843,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
843
char *google_out = "json";
844
char *google_responseHandler = "google.visualization.Query.setResponse";
845
char *google_outFileName = NULL;
845
- unsigned long last_timestamp_in_data = 0;
846
+ time_t last_timestamp_in_data = 0;
847
if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
848
849
w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
@@ -901,7 +902,7 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
902
}
903
904
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %lu after, %lu before).", w->id, st->name, st->id, lines, group_count, group_method, after, before);
904
- unsigned long timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, after, before, nonzero);
905
+ time_t timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, after, before, nonzero);
906
907
if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
908
if(timestamp_in_data > last_timestamp_in_data)
@@ -969,7 +970,7 @@ cleanup:
970
971
void web_client_process(struct web_client *w) {
972
int code = 500;
972
- int bytes;
973
+ ssize_t bytes;
974
975
w->wait_receive = 0;
976
@@ -1179,7 +1180,7 @@ void web_client_process(struct web_client *w) {
1180
// prepare the HTTP response header
1181
debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
1182
1182
- char *content_type_string = "";
1183
+ char *content_type_string;
1184
switch(w->response.data->contenttype) {
1185
case CT_TEXT_HTML:
1186
content_type_string = "text/html; charset=utf-8";
@@ -1243,7 +1244,7 @@ void web_client_process(struct web_client *w) {
1244
break;
1245
}
1246
1246
- char *code_msg = "";
1247
+ char *code_msg;
1248
switch(code) {
1249
case 200:
1250
code_msg = "OK";
@@ -1308,7 +1309,7 @@ void web_client_process(struct web_client *w) {
1309
if(!w->response.zoutput && (w->response.data->len || w->response.rlen))
1310
buffer_sprintf(w->response.header_output,
1311
"Content-Length: %ld\r\n"
1311
- , w->response.data->len?w->response.data->len:w->response.rlen
1312
+ , w->response.data->len? w->response.data->len: w->response.rlen
1313
);
1314
else if(!w->response.zoutput)
1315
w->keepalive = 0; // content-length is required for keep-alive
@@ -1335,7 +1336,7 @@ void web_client_process(struct web_client *w) {
1336
);
1337
1338
bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
1338
- if(bytes != buffer_strlen(w->response.header_output))
1339
+ if(bytes != (ssize_t) buffer_strlen(w->response.header_output))
1340
error("%llu: HTTP Header failed to be sent (I sent %d bytes but the system sent %d bytes)."
1341
, w->id
1342
, buffer_strlen(w->response.header_output)
@@ -1386,12 +1387,12 @@ void web_client_process(struct web_client *w) {
1387
}
1388
}
1389
1389
-long web_client_send_chunk_header(struct web_client *w, int len)
1390
+long web_client_send_chunk_header(struct web_client *w, long len)
1391
{
1392
debug(D_DEFLATE, "%llu: OPEN CHUNK of %d bytes (hex: %x).", w->id, len, len);
1393
char buf[1024];
1393
- sprintf(buf, "%X\r\n", len);
1394
- int bytes = send(w->ofd, buf, strlen(buf), MSG_DONTWAIT);
1394
+ sprintf(buf, "%lX\r\n", len);
1395
+ ssize_t bytes = send(w->ofd, buf, strlen(buf), MSG_DONTWAIT);
1396
1397
if(bytes > 0) debug(D_DEFLATE, "%llu: Sent chunk header %d bytes.", w->id, bytes);
1398
else if(bytes == 0) debug(D_DEFLATE, "%llu: Did not send chunk header to the client.", w->id);
@@ -1404,7 +1405,7 @@ long web_client_send_chunk_close(struct web_client *w)
1405
{
1406
//debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
1407
1407
- int bytes = send(w->ofd, "\r\n", 2, MSG_DONTWAIT);
1408
+ ssize_t bytes = send(w->ofd, "\r\n", 2, MSG_DONTWAIT);
1409
1410
if(bytes > 0) debug(D_DEFLATE, "%llu: Sent chunk suffix %d bytes.", w->id, bytes);
1411
else if(bytes == 0) debug(D_DEFLATE, "%llu: Did not send chunk suffix to the client.", w->id);
@@ -1417,7 +1418,7 @@ long web_client_send_chunk_finalize(struct web_client *w)
1418
{
1419
//debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
1420
1420
- int bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, MSG_DONTWAIT);
1421
+ ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, MSG_DONTWAIT);
1422
1423
if(bytes > 0) debug(D_DEFLATE, "%llu: Sent chunk suffix %d bytes.", w->id, bytes);
1424
else if(bytes == 0) debug(D_DEFLATE, "%llu: Did not send chunk suffix to the client.", w->id);
@@ -1479,7 +1480,7 @@ long web_client_send_deflate(struct web_client *w)
1480
// give the compressor all the data not passed through the compressor yet
1481
if(w->response.data->len > w->response.sent) {
1482
w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent];
1482
- w->response.zstream.avail_in = (w->response.data->len - w->response.sent);
1483
+ w->response.zstream.avail_in = (uInt) (w->response.data->len - w->response.sent);
1484
}
1485
1486
// reset the compressor output buffer
@@ -1516,7 +1517,7 @@ long web_client_send_deflate(struct web_client *w)
1517
t += web_client_send_chunk_header(w, w->response.zhave);
1518
}
1519
1519
- len = send(w->ofd, &w->response.zbuffer[w->response.zsent], w->response.zhave - w->response.zsent, MSG_DONTWAIT);
1520
+ len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
1521
if(len > 0) {
1522
w->response.zsent += len;
1523
if(t > 0) len += t;
@@ -1584,12 +1585,12 @@ long web_client_receive(struct web_client *w)
1585
long bytes;
1586
1587
if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
1587
- bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (left-1));
1588
+ bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
1589
else
1589
- bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], left-1, MSG_DONTWAIT);
1590
+ bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
1591
1592
if(likely(bytes > 0)) {
1592
- int old = w->response.data->len;
1593
+ size_t old = w->response.data->len;
1594
w->response.data->len += bytes;
1595
w->response.data->buffer[w->response.data->len] = '\0';
1596
src/web_client.h
+2
-2
@@ -33,8 +33,8 @@ struct response {
33
34
int code; // the HTTP response code
35
36
- long rlen; // if non-zero, the excepted size of ifd (input)
37
- long sent; // current data length sent to output
36
+ size_t rlen; // if non-zero, the excepted size of ifd (input)
37
+ size_t sent; // current data length sent to output
38
39
int zoutput; // if set to 1, web_client_send() will send compressed data
40
#ifdef NETDATA_WITH_ZLIB
src/web_server.c
+3
-3
@@ -49,7 +49,7 @@ static void log_allocations(void)
49
50
int create_listen_socket4(int port, int listen_backlog)
51
{
52
- int sock = -1;
52
+ int sock;
53
int sockopt = 1;
54
struct sockaddr_in name;
55
@@ -104,7 +104,7 @@ int create_listen_socket6(int port, int listen_backlog)
104
105
memset(&name, 0, sizeof(struct sockaddr_in6));
106
name.sin6_family = AF_INET6;
107
- name.sin6_port = htons (port);
107
+ name.sin6_port = htons ((uint16_t) port);
108
name.sin6_addr = in6addr_any;
109
name.sin6_scope_id = 0;
110
@@ -151,7 +151,7 @@ void *socket_listen_main(void *ptr)
151
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
152
error("Cannot set pthread cancel state to ENABLE.");
153
154
- web_client_timeout = config_get_number("global", "disconnect idle web clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
154
+ web_client_timeout = (int) config_get_number("global", "disconnect idle web clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS);
155
web_enable_gzip = config_get_boolean("global", "enable web responses gzip compression", web_enable_gzip);
156
157
if(listen_fd < 0) fatal("LISTENER: Listen socket is not ready.");
web/dashboard.css
+14
-15
@@ -50,35 +50,32 @@ html {
50
color: #DDDDDD;
51
text-align: center;
52
overflow: hidden;
53
- z-index: 11;
53
+ z-index: 20;
54
padding: 0px;
55
margin: 0px;
56
}
57
58
.netdata-message {
59
- display: none;
59
+ display: inline-block;
60
+ text-align: left;
61
+ vertical-align: top;
62
+ font-weight: bold;
63
font-size: x-small;
64
width: 100%;
62
- height: calc(100% - 10px); /* for the resize handler */
65
+ height: 100%;
66
overflow: hidden;
67
background: inherit;
65
- z-index: 10000;
68
+ z-index: 0;
69
}
70
68
-.netdata-chart-is-loading {
71
+.netdata-message.hidden {
72
display: none;
70
- font-size: x-small;
71
- width: 100%;
72
- overflow: hidden;
73
- background: white;
74
- z-index: 10000;
75
-}
76
-
77
-.netdata-error-message {
78
- background: #EEEEEE;
73
}
74
81
-.netdata-info-message {
75
+.netdata-message.icon {
76
+ color: #FAFAFA;
77
+ text-align: center;
78
+ vertical-align: middle;
79
}
80
81
.netdata-chart-legend {
@@ -256,6 +253,7 @@ html {
253
overflow: hidden;
254
width: 100%;
255
height: 100%;
256
+ z-index: 5;
257
258
/* width and height is calculated (depends on the appearance of the legend) */
259
}
@@ -269,6 +267,7 @@ html {
267
margin-right: 140px; /* --legend-width */
268
width: calc(100% - 140px); /* --legend-width */
269
height: 100%;
270
+ z-index: 5;
271
flex-grow: 1;
272
273
/* width and height is calculated (depends on the appearance of the legend) */
web/dashboard.js
+1355
-1383
@@ -354,7 +354,7 @@
354
var a = i.split('.');
355
356
if(a[0] === 'options') {
357
- if(a[1] === 'options.setOptionCallback') continue;
357
+ if(a[1] === 'setOptionCallback') continue;
358
if(typeof NETDATA.localStorage.default[i] === 'undefined') continue;
359
if(NETDATA.options.current[i] === NETDATA.localStorage.default[i]) continue;
360
@@ -386,9 +386,9 @@
386
// hidden all the not-visible charts
387
// using this little function we try to switch
388
// the charts back to visible quickly
389
- var targets = NETDATA.options.targets;
390
- var len = targets.length;
391
- while(len--) targets[len].isVisible();
389
+ //var targets = NETDATA.options.targets;
390
+ //var len = targets.length;
391
+ //while(len--) targets[len].isVisible();
392
}
393
394
// ----------------------------------------------------------------------------------------------------------------
@@ -581,6 +581,7 @@
581
// dimensions selection
582
583
// FIXME
584
+ // move color assignment to dimensions, here
585
586
dimensionStatus = function(parent, label, name_div, value_div, color) {
587
this.enabled = false;
@@ -777,17 +778,45 @@
778
779
780
// ----------------------------------------------------------------------------------------------------------------
780
- // Our state object, where all per-chart values are stored
781
+ // global selection sync
782
782
- resizeCallback = function(state) {
783
- this.state = state;
784
- this.resize = function(height) {
785
- this.state
783
+ NETDATA.globalSelectionSync = {
784
+ state: null,
785
+ dont_sync_before: 0,
786
+ last_t: 0,
787
+ slaves: [],
788
+
789
+ stop: function() {
790
+ if(this.state !== null)
791
+ this.state.globalSelectionSyncStop();
792
+ },
793
+
794
+ delay: function() {
795
+ if(this.state !== null) {
796
+ this.state.globalSelectionSyncDelay();
797
+ }
798
}
787
- }
799
+ };
800
+
801
+ // ----------------------------------------------------------------------------------------------------------------
802
+ // Our state object, where all per-chart values are stored
803
804
chartState = function(element) {
805
var self = $(element);
806
+ this.element = element;
807
+
808
+ // IMPORTANT:
809
+ // all private functions should use 'that', instead of 'this'
810
+ var that = this;
811
+
812
+ /* error() - private
813
+ * show an error instead of the chart
814
+ */
815
+ var error = function(msg) {
816
+ that.element.innerHTML = that.id + ': ' + msg;
817
+ that.enabled = false;
818
+ that.current = that.pan;
819
+ }
820
821
// GUID - a unique identifier for the chart
822
this.uuid = NETDATA.guid();
@@ -803,1725 +832,1667 @@
832
this.height = self.data('height') || NETDATA.chartDefaults.height;
833
834
if(this.settings_id !== null) {
806
- var me = this;
835
this.height = NETDATA.localStorageGet('chart_heights.' + this.settings_id, this.height, function(height) {
808
- me.resizeAndRedrawChart(height);
836
+ // this is the callback that will be called
837
+ // if and when the user resets all localStorage variables
838
+ // to their defaults
839
+
840
+ resizeChartToHeight(height);
841
});
842
}
843
812
- $.extend(this, {
813
- // string - the netdata server URL, without any path
814
- host: self.data('host') || NETDATA.chartDefaults.host,
815
-
816
- // string - the grouping method requested by the user
817
- method: self.data('method') || NETDATA.chartDefaults.method,
818
-
819
- // the time-range requested by the user
820
- after: self.data('after') || NETDATA.chartDefaults.after,
821
- before: self.data('before') || NETDATA.chartDefaults.before,
822
-
823
- // the pixels per point requested by the user
824
- pixels_per_point: self.data('pixels-per-point') || 1,
825
- points: self.data('points') || null,
826
-
827
- // the dimensions requested by the user
828
- dimensions: self.data('dimensions') || null,
829
-
830
- // the chart library requested by the user
831
- library_name: self.data('chart-library') || NETDATA.chartDefaults.library,
832
- library: null, // object - the chart library used
833
-
834
- colors: null,
835
- colors_assigned: {},
836
- colors_available: null,
837
-
838
- element: element, // the element already created by the user
839
- element_message: null,
840
- element_loading: null,
841
- element_chart: null, // the element with the chart
842
- element_chart_id: null,
843
- element_legend: null, // the element with the legend of the chart (if created by us)
844
- element_legend_id: null,
845
- element_legend_childs: {
846
- hidden: null,
847
- title_date: null,
848
- title_time: null,
849
- title_units: null,
850
- nano: null,
851
- nano_options: null,
852
- series: null
853
- },
854
-
855
- chart_url: null, // string - the url to download chart info
856
- chart: null, // object - the chart as downloaded from the server
857
-
858
- validated: false, // boolean - has the chart been validated?
859
- enabled: true, // boolean - is the chart enabled for refresh?
860
- paused: false, // boolean - is the chart paused for any reason?
861
- selected: false, // boolean - is the chart shown a selection?
862
- debug: false, // boolean - console.log() debug info about this chart
844
+ // string - the netdata server URL, without any path
845
+ this.host = self.data('host') || NETDATA.chartDefaults.host;
846
864
- dom_created: false, // boolean - is the DOM for the chart created?
865
- chart_created: false, // boolean - is the library.create() been called?
866
-
867
- updates_counter: 0, // numeric - the number of refreshes made so far
868
- updates_since_last_creation: 0,
847
+ // make sure the host does not end with /
848
+ // all netdata API requests use absolute paths
849
+ while(this.host.slice(-1) === '/')
850
+ this.host = this.host.substring(0, this.host.length - 1);
851
870
- tm: {
871
- last_info_downloaded: 0, // milliseconds - the timestamp we downloaded the chart
852
+ // string - the grouping method requested by the user
853
+ this.method = self.data('method') || NETDATA.chartDefaults.method;
854
873
- last_updated: 0, // the timestamp the chart last updated with data
855
+ // the time-range requested by the user
856
+ this.after = self.data('after') || NETDATA.chartDefaults.after;
857
+ this.before = self.data('before') || NETDATA.chartDefaults.before;
858
875
- pan_and_zoom_seq: 0, // the sequence number of the global synchronization
876
- // between chart.
877
- // Used with NETDATA.globalPanAndZoom.seq
859
+ // the pixels per point requested by the user
860
+ this.pixels_per_point = self.data('pixels-per-point') || 1;
861
+ this.points = self.data('points') || null;
862
879
- last_visible_check: 0, // the time we last checked if it is visible
863
+ // the dimensions requested by the user
864
+ this.dimensions = self.data('dimensions') || null;
865
881
- last_resized: 0, // the time the chart was resized
882
- last_hidden: 0, // the time the chart was hidden
883
- last_unhidden: 0, // the time the chart was unhidden
866
+ // the chart library requested by the user
867
+ this.library_name = self.data('chart-library') || NETDATA.chartDefaults.library;
868
885
- last_autorefreshed: 0 // the time the chart was last refreshed
886
- },
869
+ // object - the chart library used
870
+ this.library = null;
871
888
- data: null, // the last data as downloaded from the netdata server
889
- data_url: 'invalid://', // string - the last url used to update the chart
890
- data_points: 0, // number - the number of points returned from netdata
891
- data_after: 0, // milliseconds - the first timestamp of the data
892
- data_before: 0, // milliseconds - the last timestamp of the data
893
- data_update_every: 0, // milliseconds - the frequency to update the data
894
- netdata_first: 0, // milliseconds - the first timestamp in netdata
895
- netdata_last: 0, // milliseconds - the last timestamp in netdata
896
-
897
- dimensions_visibility: new dimensionsVisibility(this),
898
-
899
- current: null, // auto, pan, zoom
900
- // this is a pointer to one of the sub-classes below
901
-
902
- auto: {
903
- name: 'auto',
904
- autorefresh: true,
905
- force_update_at: 0, // the timestamp to force the update at
906
- force_before_ms: null,
907
- force_after_ms: null,
908
- requested_before_ms: null,
909
- requested_after_ms: null,
910
- },
911
- pan: {
912
- name: 'pan',
913
- autorefresh: false,
914
- force_update_at: 0, // the timestamp to force the update at
915
- force_before_ms: null,
916
- force_after_ms: null,
917
- requested_before_ms: null,
918
- requested_after_ms: null,
919
- },
920
- zoom: {
921
- name: 'zoom',
922
- autorefresh: false,
923
- force_update_at: 0, // the timestamp to force the update at
924
- force_before_ms: null,
925
- force_after_ms: null,
926
- requested_before_ms: null,
927
- requested_after_ms: null,
928
- },
872
+ // color management
873
+ this.colors = null;
874
+ this.colors_assigned = {};
875
+ this.colors_available = null;
876
930
- refresh_dt_ms: 0, // milliseconds - the time the last refresh took
931
- refresh_dt_element_name: self.data('dt-element-name') || null, // string - the element to print refresh_dt_ms
932
- refresh_dt_element: null
933
- });
877
+ // the element already created by the user
878
+ this.element_message = null;
879
935
- this.init();
936
- }
880
+ // the element with the chart
881
+ this.element_chart = null;
882
938
- // ----------------------------------------------------------------------------------------------------------------
939
- // Chart Resize
940
-
941
- // this is actual chart resize algorithm
942
- // it will:
943
- // - resize the entire container
944
- // - update the internal states
945
- // - resize the chart as the div changes height
946
- // - update the scrollbar of the legend
947
- chartState.prototype.resizeAndRedrawChart = function(h) {
948
- // console.log(h);
949
- this.element.style.height = h;
950
-
951
- if(this.settings_id !== null)
952
- NETDATA.localStorageSet('chart_heights.' + this.settings_id, h);
953
-
954
- var now = new Date().getTime();
955
- NETDATA.options.last_page_scroll = now;
956
- NETDATA.options.last_resized = now;
957
- NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.stop_updates_while_resizing;
958
-
959
- if(typeof this.library.resize === 'function' && this.element_chart !== null)
960
- this.library.resize(this);
961
-
962
- if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
963
- $(this.element_legend_childs.nano).nanoScroller();
964
- };
883
+ // the element with the legend of the chart (if created by us)
884
+ this.element_legend = null;
885
+ this.element_legend_childs = {
886
+ hidden: null,
887
+ title_date: null,
888
+ title_time: null,
889
+ title_units: null,
890
+ nano: null,
891
+ nano_options: null,
892
+ series: null
893
+ };
894
966
- chartState.prototype.resizeHandler = function(e) {
967
- e.preventDefault();
895
+ this.chart_url = null; // string - the url to download chart info
896
+ this.chart = null; // object - the chart as downloaded from the server
897
+
898
+ this.validated = false; // boolean - has the chart been validated?
899
+ this.enabled = true; // boolean - is the chart enabled for refresh?
900
+ this.paused = false; // boolean - is the chart paused for any reason?
901
+ this.selected = false; // boolean - is the chart shown a selection?
902
+ this.debug = false; // boolean - console.log() debug info about this chart
903
+
904
+ this.netdata_first = 0; // milliseconds - the first timestamp in netdata
905
+ this.netdata_last = 0; // milliseconds - the last timestamp in netdata
906
+ this.requested_after = null; // milliseconds - the timestamp of the request after param
907
+ this.requested_before = null; // milliseconds - the timestamp of the request before param
908
+
909
+ this.auto = {
910
+ name: 'auto',
911
+ autorefresh: true,
912
+ force_update_at: 0, // the timestamp to force the update at
913
+ force_before_ms: null,
914
+ force_after_ms: null
915
+ };
916
+ this.pan = {
917
+ name: 'pan',
918
+ autorefresh: false,
919
+ force_update_at: 0, // the timestamp to force the update at
920
+ force_before_ms: null,
921
+ force_after_ms: null
922
+ };
923
+ this.zoom = {
924
+ name: 'zoom',
925
+ autorefresh: false,
926
+ force_update_at: 0, // the timestamp to force the update at
927
+ force_before_ms: null,
928
+ force_after_ms: null
929
+ };
930
969
- if(typeof this.event_resize === 'undefined'
970
- || this.event_resize.chart_original_w === 'undefined'
971
- || this.event_resize.chart_original_h === 'undefined')
972
- this.event_resize = {
973
- chart_original_w: this.element.clientWidth,
974
- chart_original_h: this.element.clientHeight,
975
- last: 0
976
- };
931
+ // this is a pointer to one of the sub-classes below
932
+ // auto, pan, zoom
933
+ this.current = this.auto;
934
978
- if(e.type === 'touchstart') {
979
- this.event_resize.mouse_start_x = e.touches.item(0).pageX;
980
- this.event_resize.mouse_start_y = e.touches.item(0).pageY;
935
+ // check the requested library is available
936
+ // we don't initialize it here - it will be initialized when
937
+ // this chart will be first used
938
+ if(typeof NETDATA.chartLibraries[that.library_name] === 'undefined') {
939
+ NETDATA.error(402, that.library_name);
940
+ error('chart library "' + that.library_name + '" is not found');
941
+ return;
942
}
982
- else {
983
- this.event_resize.mouse_start_x = e.clientX;
984
- this.event_resize.mouse_start_y = e.clientY;
943
+ else if(NETDATA.chartLibraries[that.library_name].enabled === false) {
944
+ NETDATA.error(403, that.library_name);
945
+ error('chart library "' + that.library_name + '" is not enabled');
946
+ return;
947
}
948
+ else
949
+ that.library = NETDATA.chartLibraries[that.library_name];
950
987
- this.event_resize.chart_start_w = this.element.clientWidth;
988
- this.event_resize.chart_start_h = this.element.clientHeight;
989
- this.event_resize.chart_last_w = this.element.clientWidth;
990
- this.event_resize.chart_last_h = this.element.clientHeight;
951
+ // milliseconds - the time the last refresh took
952
+ this.refresh_dt_ms = 0;
953
992
- var now = new Date().getTime();
993
- if(now - this.event_resize.last <= NETDATA.options.current.double_click_speed) {
994
- // double click / double tap event
954
+ // if we need to report the rendering speed
955
+ // find the element that needs to be updated
956
+ var refresh_dt_element_name = self.data('dt-element-name') || null; // string - the element to print refresh_dt_ms
957
996
- // the optimal height of the chart
997
- // showing the entire legend
998
- var optimal = this.event_resize.chart_last_h
999
- + this.element_legend_childs.content.scrollHeight
1000
- - this.element_legend_childs.content.clientHeight;
958
+ if(refresh_dt_element_name !== null)
959
+ this.refresh_dt_element = document.getElementById(refresh_dt_element_name) || null;
960
+ else
961
+ this.refresh_dt_element = null;
962
1002
- // if we are not optimal, be optimal
1003
- if(this.event_resize.chart_last_h != optimal)
1004
- this.resizeAndRedrawChart(optimal.toString() + 'px');
963
+ this.dimensions_visibility = new dimensionsVisibility(this);
964
1006
- // else if we do not have the original height
1007
- // reset to the original height
1008
- else if(this.event_resize.chart_last_h != this.event_resize.chart_original_h)
1009
- this.resizeAndRedrawChart(this.event_resize.chart_original_h.toString() + 'px');
1010
- }
1011
- else {
1012
- this.event_resize.last = now;
1013
- var self = this;
965
+ // ============================================================================================================
966
+ // PRIVATE FUNCTIONS
967
1015
- // process movement event
1016
- document.onmousemove =
1017
- document.ontouchmove =
1018
- this.element_legend_childs.resize_handler.onmousemove =
1019
- this.element_legend_childs.resize_handler.ontouchmove =
1020
- function(e) {
1021
- var y = null;
1022
-
1023
- switch(e.type) {
1024
- case 'mousemove': y = e.clientY; break;
1025
- case 'touchmove': y = e.touches.item(e.touches - 1).pageY; break;
1026
- }
968
+ var createDOM = function() {
969
+ if(that.enabled == false) return;
970
1028
- if(y !== null) {
1029
- var newH = self.event_resize.chart_start_h + y - self.event_resize.mouse_start_y;
971
+ if(that.element_message !== null) that.element_message.innerHTML = '';
972
+ if(that.element_legend !== null) that.element_legend.innerHTML = '';
973
+ if(that.element_chart !== null) that.element_chart.innerHTML = '';
974
1031
- if(newH >= 70 && newH !== self.event_resize.chart_last_h) {
1032
- self.resizeAndRedrawChart(newH.toString() + 'px');
1033
- self.event_resize.chart_last_h = newH;
1034
- }
1035
- }
1036
- };
975
+ that.element.innerHTML = '';
976
1038
- // process end event
1039
- document.onmouseup =
1040
- document.ontouchend =
1041
- this.element_legend_childs.resize_handler.onmouseup =
1042
- this.element_legend_childs.resize_handler.ontouchend =
1043
- function(e) {
1044
- // remove all the hooks
1045
- document.onmouseup =
1046
- document.onmousemove =
1047
- document.ontouchmove =
1048
- document.ontouchend =
1049
- self.element_legend_childs.resize_handler.onmousemove =
1050
- self.element_legend_childs.resize_handler.ontouchmove =
1051
- self.element_legend_childs.resize_handler.onmouseout =
1052
- self.element_legend_childs.resize_handler.onmouseup =
1053
- self.element_legend_childs.resize_handler.ontouchend =
1054
- null;
1055
-
1056
- // allow auto-refreshes
1057
- NETDATA.options.auto_refresher_stop_until = 0;
1058
- };
1059
- }
1060
- }
977
+ that.element_message = document.createElement('div');
978
+ that.element_message.className = ' netdata-message hidden';
979
+ that.element.appendChild(that.element_message);
980
1062
-
1063
- // ----------------------------------------------------------------------------------------------------------------
1064
- // global selection sync
981
+ that.element_chart = document.createElement('div');
982
+ that.element_chart.id = that.library_name + '-' + that.uuid + '-chart';
983
+ that.element.appendChild(that.element_chart);
984
1066
- NETDATA.globalSelectionSync = {
1067
- state: null,
1068
- dont_sync_before: 0,
1069
- slaves: []
1070
- };
985
+ if(that.hasLegend() === true) {
986
+ that.element.className = "netdata-container-with-legend";
987
+ that.element_chart.className = 'netdata-chart-with-legend-right netdata-' + that.library_name + '-chart-with-legend-right';
988
1072
- // prevent to global selection sync for some time
1073
- chartState.prototype.globalSelectionSyncDelay = function(ms) {
1074
- if(NETDATA.options.current.sync_selection === false)
1075
- return;
989
+ that.element_legend = document.createElement('div');
990
+ that.element_legend.className = 'netdata-chart-legend netdata-' + that.library_name + '-legend';
991
+ that.element.appendChild(that.element_legend);
992
+ }
993
+ else {
994
+ that.element.className = "netdata-container";
995
+ that.element_chart.className = ' netdata-chart netdata-' + that.library_name + '-chart';
996
1077
- if(typeof ms === 'number')
1078
- NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + ms;
1079
- else
1080
- NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1081
- }
997
+ that.element_legend = null;
998
+ }
999
+ that.element_legend_childs.series = null;
1000
1083
- // can we globally apply selection sync?
1084
- chartState.prototype.globalSelectionSyncAbility = function() {
1085
- if(NETDATA.options.current.sync_selection === false)
1086
- return false;
1001
+ if(that.width !== 0)
1002
+ $(that.element).css('width', that.width);
1003
1088
- if(NETDATA.globalSelectionSync.dont_sync_before > new Date().getTime()) return false;
1089
- return true;
1090
- }
1004
+ if(that.height !== 0)
1005
+ $(that.element).css('height', that.height);
1006
1092
- chartState.prototype.globalSelectionSyncIsMaster = function() {
1093
- if(NETDATA.globalSelectionSync.state === this)
1094
- return true;
1095
- else
1096
- return false;
1097
- }
1007
+ if(NETDATA.chartDefaults.min_width !== null)
1008
+ $(that.element).css('min-width', NETDATA.chartDefaults.min_width);
1009
1099
- // this chart is the master of the global selection sync
1100
- chartState.prototype.globalSelectionSyncBeMaster = function() {
1101
- // am I the master?
1102
- if(this.globalSelectionSyncIsMaster()) {
1103
- if(this.debug === true)
1104
- this.log('sync: I am the master already.');
1010
+ that.tm.last_dom_created = new Date().getTime();
1011
1106
- return;
1012
+ showLoading();
1013
}
1014
1109
- if(NETDATA.globalSelectionSync.state) {
1110
- if(this.debug === true)
1111
- this.log('sync: I am not the sync master. Resetting global sync.');
1015
+ /* init() private
1016
+ * initialize state viariables
1017
+ * destroy all (possibly) created state elements
1018
+ * create the basic DOM for a chart
1019
+ */
1020
+ var init = function() {
1021
+ if(that.enabled == false) return;
1022
1113
- this.globalSelectionSyncStop();
1114
- }
1023
+ that.paused = false;
1024
+ that.selected = false;
1025
1116
- // become the master
1117
- if(this.debug === true)
1118
- this.log('sync: becoming sync master.');
1026
+ that.chart_created = false; // boolean - is the library.create() been called?
1027
+ that.updates_counter = 0; // numeric - the number of refreshes made so far
1028
+ that.updates_since_last_creation = 0;
1029
1120
- this.selected = true;
1121
- NETDATA.globalSelectionSync.state = this;
1030
+ that.tm = {
1031
+ last_initialized: 0, // milliseconds - the timestamp it was last initialized
1032
+ last_dom_created: 0, // milliseconds - the timestamp its DOM was last created
1033
+ last_mode_switch: 0, // milliseconds - the timestamp it switched modes
1034
1123
- // find the all slaves
1124
- var targets = NETDATA.options.targets;
1125
- var len = targets.length;
1126
- while(len--) {
1127
- st = targets[len];
1035
+ last_info_downloaded: 0, // milliseconds - the timestamp we downloaded the chart
1036
+ last_updated: 0, // the timestamp the chart last updated with data
1037
+ pan_and_zoom_seq: 0, // the sequence number of the global synchronization
1038
+ // between chart.
1039
+ // Used with NETDATA.globalPanAndZoom.seq
1040
+ last_visible_check: 0, // the time we last checked if it is visible
1041
+ last_resized: 0, // the time the chart was resized
1042
+ last_hidden: 0, // the time the chart was hidden
1043
+ last_unhidden: 0, // the time the chart was unhidden
1044
+ last_autorefreshed: 0 // the time the chart was last refreshed
1045
+ },
1046
1129
- if(st === this) {
1130
- if(this.debug === true)
1131
- st.log('sync: not adding me to sync');
1132
- }
1133
- else if(st.globalSelectionSyncIsEligible()) {
1134
- if(this.debug === true)
1135
- st.log('sync: adding to sync as slave');
1047
+ that.data = null; // the last data as downloaded from the netdata server
1048
+ that.data_url = 'invalid://'; // string - the last url used to update the chart
1049
+ that.data_points = 0; // number - the number of points returned from netdata
1050
+ that.data_after = 0; // milliseconds - the first timestamp of the data
1051
+ that.data_before = 0; // milliseconds - the last timestamp of the data
1052
+ that.data_update_every = 0; // milliseconds - the frequency to update the data
1053
1137
- st.globalSelectionSyncBeSlave();
1138
- }
1054
+ that.tm.last_initialized = new Date().getTime();
1055
+ createDOM();
1056
+
1057
+ that.setMode('auto');
1058
}
1059
1141
- // this.globalSelectionSyncDelay(100);
1142
- }
1060
+ var maxMessageFontSize = function() {
1061
+ // normally we want a font size, as tall as the element
1062
+ var h = that.element_message.clientHeight;
1063
1144
- // can the chart participate to the global selection sync as a slave?
1145
- chartState.prototype.globalSelectionSyncIsEligible = function() {
1146
- if(this.enabled === true
1147
- && this.library !== null
1148
- && typeof this.library.setSelection === 'function'
1149
- && this.isVisible()
1150
- && this.dom_created === true
1151
- && this.chart_created === true)
1152
- return true;
1064
+ // but give it some air, 20% let's say, or 5 pixels min
1065
+ var lost = Math.max(h * 0.2, 5);
1066
+ h -= lost;
1067
1154
- return false;
1155
- }
1068
+ // center the text, verically
1069
+ var paddingTop = (lost - 5) / 2;
1070
1157
- // this chart is a slave of the global selection sync
1158
- chartState.prototype.globalSelectionSyncBeSlave = function() {
1159
- if(NETDATA.globalSelectionSync.state !== this)
1160
- NETDATA.globalSelectionSync.slaves.push(this);
1161
- }
1071
+ // but check the width too
1072
+ // it should fit 10 characters in it
1073
+ var w = that.element_message.clientWidth / 10;
1074
+ if(h > w) {
1075
+ paddingTop += (h - w) / 2;
1076
+ h = w;
1077
+ }
1078
1163
- // sync all the visible charts to the given time
1164
- // this is to be called from the chart libraries
1165
- chartState.prototype.globalSelectionSync = function(t) {
1166
- if(this.globalSelectionSyncAbility() === false) {
1167
- if(this.debug === true)
1168
- this.log('sync: cannot sync (yet?).');
1079
+ // and don't make it too huge
1080
+ // 5% of the screen size is good
1081
+ if(h > screen.height / 20) {
1082
+ paddingTop += (h - (screen.height / 20)) / 2;
1083
+ h = screen.height / 20;
1084
+ }
1085
1170
- return;
1086
+ // set it
1087
+ that.element_message.style.fontSize = h.toString() + 'px';
1088
+ that.element_message.style.paddingTop = paddingTop.toString() + 'px';
1089
}
1090
1173
- if(this.globalSelectionSyncIsMaster() === false) {
1174
- if(this.debug === true)
1175
- this.log('sync: trying to be sync master.');
1176
-
1177
- this.globalSelectionSyncBeMaster();
1091
+ var showMessage = function(msg) {
1092
+ that.element_message.className = 'netdata-message';
1093
+ that.element_message.innerHTML = msg;
1094
+ this.element_message.style.fontSize = 'x-small';
1095
+ that.element_message.style.paddingTop = '0px';
1096
+ that.___messageHidden___ = undefined;
1097
+ }
1098
1179
- if(this.globalSelectionSyncAbility() === false) {
1180
- if(this.debug === true)
1181
- this.log('sync: cannot sync (yet?).');
1099
+ var showMessageIcon = function(icon) {
1100
+ that.element_message.innerHTML = icon;
1101
+ that.element_message.className = 'netdata-message icon';
1102
+ maxMessageFontSize();
1103
+ that.___messageHidden___ = undefined;
1104
+ }
1105
1183
- return;
1106
+ var hideMessage = function() {
1107
+ if(typeof that.___messageHidden___ === 'undefined') {
1108
+ that.___messageHidden___ = true;
1109
+ that.element_message.className = 'netdata-message hidden';
1110
}
1111
}
1112
1187
- $.each(NETDATA.globalSelectionSync.slaves, function(i, st) {
1188
- st.setSelection(t);
1189
- });
1190
- }
1191
-
1192
- // stop syncing all charts to the given time
1193
- chartState.prototype.globalSelectionSyncStop = function() {
1194
- if(NETDATA.globalSelectionSync.slaves.length) {
1195
- if(this.debug === true)
1196
- this.log('sync: cleaning up...');
1197
-
1198
- var self = this;
1199
- $.each(NETDATA.globalSelectionSync.slaves, function(i, st) {
1200
- if(st === self) {
1201
- if(self.debug === true)
1202
- st.log('sync: not adding me to sync stop');
1203
- }
1204
- else {
1205
- if(self.debug === true)
1206
- st.log('sync: removed slave from sync');
1207
-
1208
- st.clearSelection();
1209
- }
1210
- });
1113
+ var showRendering = function() {
1114
+ var icon;
1115
+ if(that.chart !== null) {
1116
+ if(that.chart.chart_type === 'line')
1117
+ icon = '<i class="fa fa-line-chart"></i>';
1118
+ else
1119
+ icon = '<i class="fa fa-area-chart"></i>';
1120
+ }
1121
+ else
1122
+ icon = '<i class="fa fa-area-chart"></i>';
1123
1212
- NETDATA.globalSelectionSync.slaves = [];
1213
- NETDATA.globalSelectionSync.state = null;
1124
+ showMessageIcon(icon + ' netdata');
1125
}
1126
1216
- // since we are the sync master, we should not call this.clearSelection()
1217
- // dygraphs is taking care of visualizing our selection.
1218
- this.selected = false;
1219
- }
1220
-
1221
- chartState.prototype.setSelection = function(t) {
1222
- if(typeof this.library.setSelection === 'function') {
1223
- if(this.library.setSelection(this, t) === true)
1224
- this.selected = true;
1225
- else
1226
- this.selected = false;
1127
+ var showLoading = function() {
1128
+ if(that.chart_created === false) {
1129
+ showMessageIcon('<i class="fa fa-refresh"></i> netdata');
1130
+ return true;
1131
+ }
1132
+ return false;
1133
}
1228
- else this.selected = true;
1134
1230
- if(this.selected === true && this.debug === true)
1231
- this.log('selection set to ' + t.toString());
1135
+ // hide the chart, when it is not visible - called from isVisible()
1136
+ var hideChart = function() {
1137
+ // no chart yet
1138
+ if(that.chart_created === false) return;
1139
1233
- return this.selected;
1234
- }
1140
+ // we should destroy it
1141
+ if(NETDATA.options.current.destroy_on_hide === true) {
1142
+ init();
1143
+ that.___chartIsHidden___ = undefined;
1144
+ return;
1145
+ }
1146
1236
- chartState.prototype.clearSelection = function() {
1237
- if(this.selected === true) {
1238
- if(typeof this.library.clearSelection === 'function') {
1239
- if(this.library.clearSelection(this) === true)
1240
- this.selected = false;
1241
- else
1242
- this.selected = true;
1147
+ // just hide it, if it is not already hidden
1148
+ if(typeof that.___chartIsHidden___ === 'undefined') {
1149
+ showRendering();
1150
+ that.element_chart.style.display = 'none';
1151
+ if(that.element_legend !== null) that.element_legend.style.display = 'none';
1152
+ that.___chartIsHidden___ = true;
1153
+ }
1154
+ }
1155
+
1156
+ // unhide the chart, when it is visible - called from isVisible()
1157
+ var unhideChart = function() {
1158
+ if(typeof that.___chartIsHidden___ !== 'undefined') {
1159
+ that.element_chart.style.display = 'inline-block';
1160
+ if(that.element_legend !== null) that.element_legend.style.display = 'inline-block';
1161
+ hideMessage();
1162
+ that.___chartIsHidden___ = undefined;
1163
+ resizeChart();
1164
}
1244
- else this.selected = false;
1245
-
1246
- if(this.selected === false && this.debug === true)
1247
- this.log('selection cleared');
1165
}
1166
1250
- this.legendReset();
1251
- return this.selected;
1252
- }
1253
-
1254
- // find if a timestamp (ms) is shown in the current chart
1255
- chartState.prototype.timeIsVisible = function(t) {
1256
- if(t >= this.data_after && t <= this.data_before)
1257
- return true;
1258
- return false;
1259
- },
1167
+ // ----------------------------------------------------------------------------------------------------------------
1168
+ // Chart Resize
1169
1261
- chartState.prototype.calculateRowForTime = function(t) {
1262
- if(this.timeIsVisible(t) === false) return -1;
1263
- return Math.floor((t - this.data_after) / this.data_update_every);
1264
- }
1170
+ // resizeChart() - private
1171
+ // to be called just before the chart library to make sure that
1172
+ // a properly sized dom is available
1173
+ var resizeChart = function() {
1174
+ if(that.isVisible() === true && that.tm.last_resized < NETDATA.options.last_resized) {
1175
+ that.tm.last_resized = new Date().getTime();
1176
+ if(that.chart_created === false) return;
1177
1266
- // ----------------------------------------------------------------------------------------------------------------
1178
+ if(that.needsRecreation())
1179
+ init();
1180
1268
- // console logging
1269
- chartState.prototype.log = function(msg) {
1270
- console.log(this.id + ' (' + this.library_name + ' ' + this.uuid + '): ' + msg);
1271
- }
1181
+ else if(typeof that.library.resize === 'function') {
1182
+ that.library.resize(that);
1183
1273
- chartState.prototype.pauseChart = function() {
1274
- if(this.paused === false) {
1275
- if(this.debug === true)
1276
- this.log('paused');
1184
+ if(that.element_legend_childs.nano !== null && that.element_legend_childs.nano_options !== null)
1185
+ $(that.element_legend_childs.nano).nanoScroller();
1186
1278
- this.paused = true;
1187
+ maxMessageFontSize();
1188
+ }
1189
+ }
1190
}
1280
- }
1281
-
1282
- chartState.prototype.unpauseChart = function() {
1283
- if(this.paused) {
1284
- if(this.debug === true)
1285
- this.log('unpaused');
1191
1287
- this.paused = false;
1288
- }
1289
- }
1192
+ // this is the actual chart resize algorithm
1193
+ // it will:
1194
+ // - resize the entire container
1195
+ // - update the internal states
1196
+ // - resize the chart as the div changes height
1197
+ // - update the scrollbar of the legend
1198
+ var resizeChartToHeight = function(h) {
1199
+ // console.log(h);
1200
+ that.element.style.height = h;
1201
1291
- chartState.prototype.resetChart = function() {
1292
- if(NETDATA.globalPanAndZoom.isMaster(this) && this.isVisible())
1293
- NETDATA.globalPanAndZoom.clearMaster();
1202
+ if(that.settings_id !== null)
1203
+ NETDATA.localStorageSet('chart_heights.' + that.settings_id, h);
1204
1295
- this.tm.pan_and_zoom_seq = 0;
1205
+ var now = new Date().getTime();
1206
+ NETDATA.options.last_page_scroll = now;
1207
+ NETDATA.options.last_resized = now;
1208
+ NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.stop_updates_while_resizing;
1209
1297
- this.clearSelection();
1210
+ // force a resize
1211
+ that.tm.last_resized = 0;
1212
+ resizeChart();
1213
+ };
1214
1299
- this.setMode('auto');
1300
- this.current.force_update_at = 0;
1301
- this.current.force_before_ms = null;
1302
- this.current.force_after_ms = null;
1303
- this.tm.last_autorefreshed = 0;
1304
- this.paused = false;
1305
- this.selected = false;
1306
- this.enabled = true;
1307
- this.debug = false;
1308
-
1309
- // do not update the chart here
1310
- // or the chart will flip-flop when it is the master
1311
- // of a selection sync and another chart becomes
1312
- // the new master
1313
- if(NETDATA.options.current.sync_pan_and_zoom === false && this.isVisible() === true)
1314
- this.updateChart();
1315
- }
1215
+ this.resizeHandler = function(e) {
1216
+ e.preventDefault();
1217
1317
- chartState.prototype.setMode = function(m) {
1318
- if(this.current) {
1319
- if(this.current.name === m) return;
1218
+ if(typeof this.event_resize === 'undefined'
1219
+ || this.event_resize.chart_original_w === 'undefined'
1220
+ || this.event_resize.chart_original_h === 'undefined')
1221
+ this.event_resize = {
1222
+ chart_original_w: this.element.clientWidth,
1223
+ chart_original_h: this.element.clientHeight,
1224
+ last: 0
1225
+ };
1226
1321
- this[m].requested_before_ms = this.current.requested_before_ms;
1322
- this[m].requested_after_ms = this.current.requested_after_ms;
1323
- }
1227
+ if(e.type === 'touchstart') {
1228
+ this.event_resize.mouse_start_x = e.touches.item(0).pageX;
1229
+ this.event_resize.mouse_start_y = e.touches.item(0).pageY;
1230
+ }
1231
+ else {
1232
+ this.event_resize.mouse_start_x = e.clientX;
1233
+ this.event_resize.mouse_start_y = e.clientY;
1234
+ }
1235
1325
- if(m === 'auto')
1326
- this.current = this.auto;
1327
- else if(m === 'pan')
1328
- this.current = this.pan;
1329
- else if(m === 'zoom')
1330
- this.current = this.zoom;
1331
- else
1332
- this.current = this.auto;
1236
+ this.event_resize.chart_start_w = this.element.clientWidth;
1237
+ this.event_resize.chart_start_h = this.element.clientHeight;
1238
+ this.event_resize.chart_last_w = this.element.clientWidth;
1239
+ this.event_resize.chart_last_h = this.element.clientHeight;
1240
1334
- this.current.force_update_at = 0;
1335
- this.current.force_before_ms = null;
1336
- this.current.force_after_ms = null;
1241
+ var now = new Date().getTime();
1242
+ if(now - this.event_resize.last <= NETDATA.options.current.double_click_speed) {
1243
+ // double click / double tap event
1244
+
1245
+ // the optimal height of the chart
1246
+ // showing the entire legend
1247
+ var optimal = this.event_resize.chart_last_h
1248
+ + this.element_legend_childs.content.scrollHeight
1249
+ - this.element_legend_childs.content.clientHeight;
1250
+
1251
+ // if we are not optimal, be optimal
1252
+ if(this.event_resize.chart_last_h != optimal)
1253
+ resizeChartToHeight(optimal.toString() + 'px');
1254
+
1255
+ // else if we do not have the original height
1256
+ // reset to the original height
1257
+ else if(this.event_resize.chart_last_h != this.event_resize.chart_original_h)
1258
+ resizeChartToHeight(this.event_resize.chart_original_h.toString() + 'px');
1259
+ }
1260
+ else {
1261
+ this.event_resize.last = now;
1262
+
1263
+ // process movement event
1264
+ document.onmousemove =
1265
+ document.ontouchmove =
1266
+ this.element_legend_childs.resize_handler.onmousemove =
1267
+ this.element_legend_childs.resize_handler.ontouchmove =
1268
+ function(e) {
1269
+ var y = null;
1270
+
1271
+ switch(e.type) {
1272
+ case 'mousemove': y = e.clientY; break;
1273
+ case 'touchmove': y = e.touches.item(e.touches - 1).pageY; break;
1274
+ }
1275
1338
- if(this.debug === true)
1339
- this.log('mode set to ' + this.current.name);
1340
- }
1276
+ if(y !== null) {
1277
+ var newH = that.event_resize.chart_start_h + y - that.event_resize.mouse_start_y;
1278
1342
- chartState.prototype.updateChartPanOrZoom = function(after, before) {
1343
- if(before < after) return false;
1279
+ if(newH >= 70 && newH !== that.event_resize.chart_last_h) {
1280
+ resizeChartToHeight(newH.toString() + 'px');
1281
+ that.event_resize.chart_last_h = newH;
1282
+ }
1283
+ }
1284
+ };
1285
+
1286
+ // process end event
1287
+ document.onmouseup =
1288
+ document.ontouchend =
1289
+ this.element_legend_childs.resize_handler.onmouseup =
1290
+ this.element_legend_childs.resize_handler.ontouchend =
1291
+ function(e) {
1292
+ // remove all the hooks
1293
+ document.onmouseup =
1294
+ document.onmousemove =
1295
+ document.ontouchmove =
1296
+ document.ontouchend =
1297
+ that.element_legend_childs.resize_handler.onmousemove =
1298
+ that.element_legend_childs.resize_handler.ontouchmove =
1299
+ that.element_legend_childs.resize_handler.onmouseout =
1300
+ that.element_legend_childs.resize_handler.onmouseup =
1301
+ that.element_legend_childs.resize_handler.ontouchend =
1302
+ null;
1303
+
1304
+ // allow auto-refreshes
1305
+ NETDATA.options.auto_refresher_stop_until = 0;
1306
+ };
1307
+ }
1308
+ }
1309
1345
- var min_duration = Math.round((this.chartWidth() / 30 * this.chart.update_every * 1000));
1310
1347
- if(this.debug === true)
1348
- this.log('requested duration of ' + ((before - after) / 1000).toString() + ' (' + after + ' - ' + before + '), minimum ' + min_duration / 1000);
1311
+ var noDataToShow = function() {
1312
+ this.legendUpdateDOM();
1313
+ that.tm.last_autorefreshed = new Date().getTime();
1314
+ that.data_update_every = 30 * 1000;
1315
+ }
1316
1350
- if((before - after) < min_duration) return false;
1317
+ // ============================================================================================================
1318
+ // PUBLIC FUNCTIONS
1319
1352
- var current_duration = this.data_before - this.data_after;
1353
- var wanted_duration = before - after;
1354
- var tolerance = this.data_update_every * 2;
1355
- var movement = Math.abs(before - this.data_before);
1320
+ this.setMode = function(m) {
1321
+ if(this.current !== null && this.current.name === m) return;
1322
1357
- if(this.debug === true)
1358
- this.log('current duration: ' + current_duration / 1000 + ', wanted duration: ' + wanted_duration / 1000 + ', movement: ' + movement / 1000 + ', tolerance: ' + tolerance / 1000);
1323
+ if(m === 'auto')
1324
+ this.current = this.auto;
1325
+ else if(m === 'pan')
1326
+ this.current = this.pan;
1327
+ else if(m === 'zoom')
1328
+ this.current = this.zoom;
1329
+ else
1330
+ this.current = this.auto;
1331
1360
- if(Math.abs(current_duration - wanted_duration) <= tolerance && movement <= tolerance) {
1361
- if(this.debug === true)
1362
- this.log('IGNORED');
1332
+ this.current.force_update_at = 0;
1333
+ this.current.force_before_ms = null;
1334
+ this.current.force_after_ms = null;
1335
1364
- return false;
1336
+ this.tm.last_mode_switch = new Date().getTime();
1337
}
1338
1367
- if(this.current.name === 'auto') {
1368
- this.setMode('pan');
1339
+ // ----------------------------------------------------------------------------------------------------------------
1340
+ // global selection sync
1341
1370
- if(this.debug === true)
1371
- this.log('updateChartPanOrZoom(): caller did not set proper mode');
1342
+ // prevent to global selection sync for some time
1343
+ this.globalSelectionSyncDelay = function(ms) {
1344
+ if(NETDATA.options.current.sync_selection === false)
1345
+ return;
1346
+
1347
+ if(typeof ms === 'number')
1348
+ NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + ms;
1349
+ else
1350
+ NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
1351
}
1352
1374
- this.current.force_update_at = new Date().getTime() + NETDATA.options.current.pan_and_zoom_delay;
1375
- this.current.force_after_ms = after;
1376
- this.current.force_before_ms = before;
1377
- NETDATA.globalPanAndZoom.setMaster(this, after, before);
1378
- return true;
1379
- }
1353
+ // can we globally apply selection sync?
1354
+ this.globalSelectionSyncAbility = function() {
1355
+ if(NETDATA.options.current.sync_selection === false)
1356
+ return false;
1357
1381
- chartState.prototype.legendFormatValue = function(value) {
1382
- if(value === null || value === 'undefined') return '-';
1383
- if(typeof value !== 'number') return value;
1358
+ if(NETDATA.globalSelectionSync.dont_sync_before > new Date().getTime())
1359
+ return false;
1360
1385
- var abs = Math.abs(value);
1386
- if(abs >= 1) return (Math.round(value * 100) / 100).toLocaleString();
1387
- if(abs >= 0.1) return (Math.round(value * 1000) / 1000).toLocaleString();
1388
- return (Math.round(value * 10000) / 10000).toLocaleString();
1389
- }
1361
+ return true;
1362
+ }
1363
+
1364
+ this.globalSelectionSyncIsMaster = function() {
1365
+ if(NETDATA.globalSelectionSync.state === this)
1366
+ return true;
1367
+ else
1368
+ return false;
1369
+ }
1370
1391
- chartState.prototype.legendSetLabelValue = function(label, value) {
1392
- var series = this.element_legend_childs.series[label];
1393
- if(typeof series === 'undefined') return;
1394
- if(series.value === null && series.user === null) return;
1371
+ // this chart is the master of the global selection sync
1372
+ this.globalSelectionSyncBeMaster = function() {
1373
+ // am I the master?
1374
+ if(this.globalSelectionSyncIsMaster()) {
1375
+ if(this.debug === true)
1376
+ this.log('sync: I am the master already.');
1377
1396
- // if the value has not changed, skip DOM update
1397
- //if(series.last === value) return;
1378
+ return;
1379
+ }
1380
1399
- var s, r;
1400
- if(typeof value === 'number') {
1401
- var v = Math.abs(value);
1402
- s = r = this.legendFormatValue(value);
1381
+ if(NETDATA.globalSelectionSync.state) {
1382
+ if(this.debug === true)
1383
+ this.log('sync: I am not the sync master. Resetting global sync.');
1384
1404
- if(typeof series.last === 'number') {
1405
- if(v > series.last) s += '<i class="fa fa-angle-up" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1406
- else if(v < series.last) s += '<i class="fa fa-angle-down" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1407
- else s += '<i class="fa fa-angle-left" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1385
+ this.globalSelectionSyncStop();
1386
}
1409
- else s += '<i class="fa fa-angle-right" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1410
- series.last = v;
1411
- }
1412
- else {
1413
- s = r = value;
1414
- series.last = value;
1415
- }
1387
1417
- if(series.value !== null) series.value.innerHTML = s;
1418
- if(series.user !== null) series.user.innerHTML = r;
1419
- }
1388
+ // become the master
1389
+ if(this.debug === true)
1390
+ this.log('sync: becoming sync master.');
1391
1421
- chartState.prototype.legendSetDate = function(ms) {
1422
- if(typeof ms !== 'number') {
1423
- this.legendShowUndefined();
1424
- return;
1425
- }
1392
+ this.selected = true;
1393
+ NETDATA.globalSelectionSync.state = this;
1394
1427
- var d = new Date(ms);
1395
+ // find the all slaves
1396
+ var targets = NETDATA.options.targets;
1397
+ var len = targets.length;
1398
+ while(len--) {
1399
+ st = targets[len];
1400
1429
- if(this.element_legend_childs.title_date)
1430
- this.element_legend_childs.title_date.innerHTML = d.toLocaleDateString();
1401
+ if(st === this) {
1402
+ if(this.debug === true)
1403
+ st.log('sync: not adding me to sync');
1404
+ }
1405
+ else if(st.globalSelectionSyncIsEligible()) {
1406
+ if(this.debug === true)
1407
+ st.log('sync: adding to sync as slave');
1408
1432
- if(this.element_legend_childs.title_time)
1433
- this.element_legend_childs.title_time.innerHTML = d.toLocaleTimeString();
1409
+ st.globalSelectionSyncBeSlave();
1410
+ }
1411
+ }
1412
1435
- if(this.element_legend_childs.title_units)
1436
- this.element_legend_childs.title_units.innerHTML = this.chart.units;
1437
- }
1413
+ // this.globalSelectionSyncDelay(100);
1414
+ }
1415
1439
- chartState.prototype.legendShowUndefined = function() {
1440
- if(this.element_legend_childs.title_date)
1441
- this.element_legend_childs.title_date.innerHTML = ' ';
1416
+ // can the chart participate to the global selection sync as a slave?
1417
+ this.globalSelectionSyncIsEligible = function() {
1418
+ if(this.enabled === true
1419
+ && this.library !== null
1420
+ && typeof this.library.setSelection === 'function'
1421
+ && this.isVisible() === true
1422
+ && this.chart_created === true)
1423
+ return true;
1424
1443
- if(this.element_legend_childs.title_time)
1444
- this.element_legend_childs.title_time.innerHTML = this.chart.name;
1425
+ return false;
1426
+ }
1427
1446
- if(this.element_legend_childs.title_units)
1447
- this.element_legend_childs.title_units.innerHTML = ' ';
1428
+ // this chart becomes a slave of the global selection sync
1429
+ this.globalSelectionSyncBeSlave = function() {
1430
+ if(NETDATA.globalSelectionSync.state !== this)
1431
+ NETDATA.globalSelectionSync.slaves.push(this);
1432
+ }
1433
1449
- if(this.data && this.element_legend_childs.series !== null) {
1450
- var labels = this.data.dimension_names;
1451
- var i = labels.length;
1452
- while(i--) {
1453
- var label = labels[i];
1434
+ // sync all the visible charts to the given time
1435
+ // this is to be called from the chart libraries
1436
+ this.globalSelectionSync = function(t) {
1437
+ if(this.globalSelectionSyncAbility() === false) {
1438
+ if(this.debug === true)
1439
+ this.log('sync: cannot sync (yet?).');
1440
1455
- if(typeof label === 'undefined') continue;
1456
- if(typeof this.element_legend_childs.series[label] === 'undefined') continue;
1457
- this.legendSetLabelValue(label, null);
1441
+ return;
1442
}
1459
- }
1460
- }
1443
1462
- chartState.prototype.legendShowLatestValues = function() {
1463
- if(this.chart === null) return;
1464
- if(this.selected) return;
1465
-
1466
- if(this.data === null || this.element_legend_childs.series === null) {
1467
- this.legendShowUndefined();
1468
- return;
1469
- }
1470
-
1471
- var show_undefined = true;
1472
- if(Math.abs(this.data.last_entry - this.data.before) <= this.data.view_update_every)
1473
- show_undefined = false;
1474
-
1475
- if(show_undefined) {
1476
- this.legendShowUndefined();
1477
- return;
1478
- }
1444
+ if(this.globalSelectionSyncIsMaster() === false) {
1445
+ if(this.debug === true)
1446
+ this.log('sync: trying to be sync master.');
1447
1480
- this.legendSetDate(this.data.before * 1000);
1448
+ this.globalSelectionSyncBeMaster();
1449
1482
- var labels = this.data.dimension_names;
1483
- var i = labels.length;
1484
- while(i--) {
1485
- var label = labels[i];
1450
+ if(this.globalSelectionSyncAbility() === false) {
1451
+ if(this.debug === true)
1452
+ this.log('sync: cannot sync (yet?).');
1453
1487
- if(typeof label === 'undefined') continue;
1488
- if(typeof this.element_legend_childs.series[label] === 'undefined') continue;
1454
+ return;
1455
+ }
1456
+ }
1457
1490
- if(show_undefined)
1491
- this.legendSetLabelValue(label, null);
1492
- else
1493
- this.legendSetLabelValue(label, this.data.view_latest_values[i]);
1458
+ NETDATA.globalSelectionSync.last_t = t;
1459
+ $.each(NETDATA.globalSelectionSync.slaves, function(i, st) {
1460
+ st.setSelection(t);
1461
+ });
1462
}
1495
- }
1463
1497
- chartState.prototype.legendReset = function() {
1498
- this.legendShowLatestValues();
1499
- }
1464
+ // stop syncing all charts to the given time
1465
+ this.globalSelectionSyncStop = function() {
1466
+ if(NETDATA.globalSelectionSync.slaves.length) {
1467
+ if(this.debug === true)
1468
+ this.log('sync: cleaning up...');
1469
1501
- // this should be called just ONCE per dimension per chart
1502
- chartState.prototype._chartDimensionColor = function(label) {
1503
- if(this.colors === null) this.chartColors();
1470
+ $.each(NETDATA.globalSelectionSync.slaves, function(i, st) {
1471
+ if(st === that) {
1472
+ if(that.debug === true)
1473
+ st.log('sync: not adding me to sync stop');
1474
+ }
1475
+ else {
1476
+ if(that.debug === true)
1477
+ st.log('sync: removed slave from sync');
1478
1505
- if(typeof this.colors_assigned[label] === 'undefined') {
1506
- if(this.colors_available.length === 0) {
1507
- for(var i = 0, len = NETDATA.colors.length; i < len ; i++)
1508
- this.colors_available.push(NETDATA.colors[i]);
1509
- }
1479
+ st.clearSelection();
1480
+ }
1481
+ });
1482
1511
- this.colors_assigned[label] = this.colors_available.shift();
1483
+ NETDATA.globalSelectionSync.last_t = 0;
1484
+ NETDATA.globalSelectionSync.slaves = [];
1485
+ NETDATA.globalSelectionSync.state = null;
1486
+ }
1487
1513
- if(this.debug === true)
1514
- this.log('label "' + label + '" got color "' + this.colors_assigned[label]);
1515
- }
1516
- else {
1517
- if(this.debug === true)
1518
- this.log('label "' + label + '" already has color "' + this.colors_assigned[label] + '"');
1488
+ // since we are the sync master, we should not call this.clearSelection()
1489
+ // dygraphs is taking care of visualizing our selection.
1490
+ this.selected = false;
1491
+ this.clearSelection();
1492
}
1493
1521
- this.colors.push(this.colors_assigned[label]);
1522
- return this.colors_assigned[label];
1523
- }
1494
+ this.setSelection = function(t) {
1495
+ if(typeof this.library.setSelection === 'function') {
1496
+ if(this.library.setSelection(this, t) === true)
1497
+ this.selected = true;
1498
+ else
1499
+ this.selected = false;
1500
+ }
1501
+ else this.selected = true;
1502
1525
- chartState.prototype.chartColors = function() {
1526
- if(this.colors !== null) return this.colors;
1503
+ if(this.selected === true && this.debug === true)
1504
+ this.log('selection set to ' + t.toString());
1505
1528
- this.colors = new Array();
1529
- this.colors_available = new Array();
1530
- // this.colors_assigned = {};
1506
+ return this.selected;
1507
+ }
1508
1532
- var c = $(this.element).data('colors');
1533
- if(typeof c !== 'undefined' && c !== null) {
1534
- if(typeof c !== 'string') {
1535
- this.log('invalid color given: ' + c + ' (give a space separated list of colors)');
1536
- }
1537
- else {
1538
- c = c.split(' ');
1539
- for(var i = 0, len = c.length; i < len ; i++)
1540
- this.colors_available.push(c[i]);
1509
+ this.clearSelection = function() {
1510
+ if(this.selected === true) {
1511
+ if(typeof this.library.clearSelection === 'function') {
1512
+ if(this.library.clearSelection(this) === true)
1513
+ this.selected = false;
1514
+ else
1515
+ this.selected = true;
1516
+ }
1517
+ else this.selected = false;
1518
+
1519
+ if(this.selected === false && this.debug === true)
1520
+ this.log('selection cleared');
1521
}
1522
+
1523
+ this.legendReset();
1524
+ return this.selected;
1525
}
1526
1544
- // push all the standard colors too
1545
- for(var i = 0, len = NETDATA.colors.length; i < len ; i++)
1546
- this.colors_available.push(NETDATA.colors[i]);
1527
+ // find if a timestamp (ms) is shown in the current chart
1528
+ this.timeIsVisible = function(t) {
1529
+ if(t >= this.data_after && t <= this.data_before)
1530
+ return true;
1531
+ return false;
1532
+ },
1533
1548
- return this.colors;
1549
- }
1534
+ this.calculateRowForTime = function(t) {
1535
+ if(this.timeIsVisible(t) === false) return -1;
1536
+ return Math.floor((t - this.data_after) / this.data_update_every);
1537
+ }
1538
1551
- chartState.prototype.legendUpdateDOM = function() {
1552
- var needed = false;
1539
+ // ----------------------------------------------------------------------------------------------------------------
1540
1554
- // check that the legend DOM is up to date for the downloaded dimensions
1555
- if(typeof this.element_legend_childs.series !== 'object' || this.element_legend_childs.series === null) {
1556
- // this.log('the legend does not have any series - requesting legend update');
1557
- needed = true;
1558
- }
1559
- else if(this.data === null) {
1560
- // this.log('the chart does not have any data - requesting legend update');
1561
- needed = true;
1541
+ // console logging
1542
+ this.log = function(msg) {
1543
+ console.log(this.id + ' (' + this.library_name + ' ' + this.uuid + '): ' + msg);
1544
}
1563
- else if(typeof this.element_legend_childs.series.labels_key === 'undefined') {
1564
- needed = true;
1565
- }
1566
- else {
1567
- var labels = this.data.dimension_names.toString();
1568
- if(labels !== this.element_legend_childs.series.labels_key) {
1569
- needed = true;
1545
1546
+ this.pauseChart = function() {
1547
+ if(this.paused === false) {
1548
if(this.debug === true)
1572
- this.log('NEW LABELS: "' + labels + '" NOT EQUAL OLD LABELS: "' + this.element_legend_childs.series.labels_key + '"');
1549
+ this.log('paused');
1550
+
1551
+ this.paused = true;
1552
}
1553
}
1554
1576
- if(needed === false) {
1577
- // make sure colors available
1578
- this.chartColors();
1579
-
1580
- // do we have to update the current values?
1581
- // we do this, only when the visible chart is current
1582
- if(Math.abs(this.data.last_entry - this.data.before) <= this.data.view_update_every) {
1555
+ this.unpauseChart = function() {
1556
+ if(this.paused) {
1557
if(this.debug === true)
1584
- this.log('chart in running... updating values on legend...');
1558
+ this.log('unpaused');
1559
1586
- //var labels = this.data.dimension_names;
1587
- //var i = labels.length;
1588
- //while(i--)
1589
- // this.legendSetLabelValue(labels[i], this.data.latest_values[i]);
1560
+ this.paused = false;
1561
}
1591
- return;
1562
}
1593
- if(this.colors === null) {
1594
- // this is the first time we update the chart
1595
- // let's assign colors to all dimensions
1596
- if(this.library.track_colors() === true)
1597
- for(var dim in this.chart.dimensions)
1598
- this._chartDimensionColor(this.chart.dimensions[dim].name);
1599
- }
1600
- // we will re-generate the colors for the chart
1601
- this.colors = null;
1563
1603
- if(this.debug === true)
1604
- this.log('updating Legend DOM');
1564
+ this.resetChart = function() {
1565
+ if(NETDATA.globalPanAndZoom.isMaster(this) && this.isVisible())
1566
+ NETDATA.globalPanAndZoom.clearMaster();
1567
1606
- // mark all dimensions as invalid
1607
- this.dimensions_visibility.invalidateAll();
1608
-
1609
- var self = $(this.element);
1610
- var genLabel = function(state, parent, name, count) {
1611
- var color = state._chartDimensionColor(name);
1568
+ this.tm.pan_and_zoom_seq = 0;
1569
1613
- var user_element = null;
1614
- var user_id = self.data('show-value-of-' + name + '-at') || null;
1615
- if(user_id !== null) {
1616
- user_element = document.getElementById(user_id) || null;
1617
- if(user_element === null)
1618
- me.log('Cannot find element with id: ' + user_id);
1619
- }
1570
+ this.clearSelection();
1571
1621
- state.element_legend_childs.series[name] = {
1622
- name: document.createElement('span'),
1623
- value: document.createElement('span'),
1624
- user: user_element,
1625
- last: null
1626
- };
1572
+ this.setMode('auto');
1573
+ this.current.force_update_at = 0;
1574
+ this.current.force_before_ms = null;
1575
+ this.current.force_after_ms = null;
1576
+ this.tm.last_autorefreshed = 0;
1577
+ this.paused = false;
1578
+ this.selected = false;
1579
+ this.enabled = true;
1580
+ this.debug = false;
1581
1628
- var label = state.element_legend_childs.series[name];
1582
+ // do not update the chart here
1583
+ // or the chart will flip-flop when it is the master
1584
+ // of a selection sync and another chart becomes
1585
+ // the new master
1586
+ if(NETDATA.options.current.sync_pan_and_zoom === false && this.isVisible() === true)
1587
+ this.updateChart();
1588
+ }
1589
1630
- // create the dimension visibility tracking for this label
1631
- var ds = state.dimensions_visibility.dimensionAdd(name, label.name, label.value, color);
1590
+ this.updateChartPanOrZoom = function(after, before) {
1591
+ if(before < after) return false;
1592
1633
- var rgb = NETDATA.colorHex2Rgb(color);
1634
- label.name.innerHTML = '<table class="netdata-legend-name-table-'
1635
- + state.chart.chart_type
1636
- + '" style="background-color: '
1637
- + 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current['color_fill_opacity_' + state.chart.chart_type] + ')'
1638
- + '"><tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr></table>'
1593
+ var min_duration = Math.round((this.chartWidth() / 30 * this.chart.update_every * 1000));
1594
1640
- var text = document.createTextNode(' ' + name);
1641
- label.name.appendChild(text);
1595
+ if(this.debug === true)
1596
+ this.log('requested duration of ' + ((before - after) / 1000).toString() + ' (' + after + ' - ' + before + '), minimum ' + min_duration / 1000);
1597
1643
- if(count > 0)
1644
- parent.appendChild(document.createElement('br'));
1598
+ if((before - after) < min_duration) return false;
1599
1646
- parent.appendChild(label.name);
1647
- parent.appendChild(label.value);
1648
- };
1600
+ var current_duration = this.data_before - this.data_after;
1601
+ var wanted_duration = before - after;
1602
+ var tolerance = this.data_update_every * 2;
1603
+ var movement = Math.abs(before - this.data_before);
1604
1650
- var content = document.createElement('div');
1651
-
1652
- if(this.hasLegend()) {
1653
- this.element_legend_childs = {
1654
- content: content,
1655
- resize_handler: document.createElement('div'),
1656
- title_date: document.createElement('span'),
1657
- title_time: document.createElement('span'),
1658
- title_units: document.createElement('span'),
1659
- nano: document.createElement('div'),
1660
- nano_options: {
1661
- paneClass: 'netdata-legend-series-pane',
1662
- sliderClass: 'netdata-legend-series-slider',
1663
- contentClass: 'netdata-legend-series-content',
1664
- enabledClass: '__enabled',
1665
- flashedClass: '__flashed',
1666
- activeClass: '__active',
1667
- tabIndex: -1,
1668
- alwaysVisible: true,
1669
- sliderMinHeight: 10
1670
- },
1671
- series: {}
1672
- };
1605
+ if(this.debug === true)
1606
+ this.log('current duration: ' + current_duration / 1000 + ', wanted duration: ' + wanted_duration / 1000 + ', movement: ' + movement / 1000 + ', tolerance: ' + tolerance / 1000);
1607
1674
- this.element_legend.innerHTML = '';
1608
+ if(Math.abs(current_duration - wanted_duration) <= tolerance && movement <= tolerance) {
1609
+ if(this.debug === true)
1610
+ this.log('IGNORED');
1611
1676
- this.element_legend_childs.resize_handler.className += " netdata-legend-resize-handler";
1677
- this.element_legend_childs.resize_handler.innerHTML = '<i class="fa fa-chevron-up"></i><i class="fa fa-chevron-down"></i>';
1678
- this.element.appendChild(this.element_legend_childs.resize_handler);
1679
- var self2 = this;
1612
+ return false;
1613
+ }
1614
1681
- // mousedown event
1682
- this.element_legend_childs.resize_handler.onmousedown =
1683
- function(e) {
1684
- self2.resizeHandler(e);
1685
- };
1615
+ if(this.current.name === 'auto') {
1616
+ this.setMode('pan');
1617
1687
- // touchstart event
1688
- this.element_legend_childs.resize_handler.addEventListener('touchstart', function(e) {
1689
- self2.resizeHandler(e);
1690
- }, false);
1618
+ if(this.debug === true)
1619
+ this.log('updateChartPanOrZoom(): caller did not set proper mode');
1620
+ }
1621
1692
- this.element_legend_childs.title_date.className += " netdata-legend-title-date";
1693
- this.element_legend.appendChild(this.element_legend_childs.title_date);
1622
+ this.current.force_update_at = new Date().getTime() + NETDATA.options.current.pan_and_zoom_delay;
1623
+ this.current.force_after_ms = after;
1624
+ this.current.force_before_ms = before;
1625
+ NETDATA.globalPanAndZoom.setMaster(this, after, before);
1626
+ return true;
1627
+ }
1628
1695
- this.element_legend.appendChild(document.createElement('br'));
1629
+ this.legendFormatValue = function(value) {
1630
+ if(value === null || value === 'undefined') return '-';
1631
+ if(typeof value !== 'number') return value;
1632
1697
- this.element_legend_childs.title_time.className += " netdata-legend-title-time";
1698
- this.element_legend.appendChild(this.element_legend_childs.title_time);
1633
+ var abs = Math.abs(value);
1634
+ if(abs >= 1) return (Math.round(value * 100) / 100).toLocaleString();
1635
+ if(abs >= 0.1) return (Math.round(value * 1000) / 1000).toLocaleString();
1636
+ return (Math.round(value * 10000) / 10000).toLocaleString();
1637
+ }
1638
1700
- this.element_legend.appendChild(document.createElement('br'));
1639
+ this.legendSetLabelValue = function(label, value) {
1640
+ var series = this.element_legend_childs.series[label];
1641
+ if(typeof series === 'undefined') return;
1642
+ if(series.value === null && series.user === null) return;
1643
1702
- this.element_legend_childs.title_units.className += " netdata-legend-title-units";
1703
- this.element_legend.appendChild(this.element_legend_childs.title_units);
1644
+ // if the value has not changed, skip DOM update
1645
+ //if(series.last === value) return;
1646
1705
- this.element_legend.appendChild(document.createElement('br'));
1647
+ var s, r;
1648
+ if(typeof value === 'number') {
1649
+ var v = Math.abs(value);
1650
+ s = r = this.legendFormatValue(value);
1651
1707
- this.element_legend_childs.nano.className = 'netdata-legend-series';
1708
- this.element_legend.appendChild(this.element_legend_childs.nano);
1652
+ if(typeof series.last === 'number') {
1653
+ if(v > series.last) s += '<i class="fa fa-angle-up" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1654
+ else if(v < series.last) s += '<i class="fa fa-angle-down" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1655
+ else s += '<i class="fa fa-angle-left" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1656
+ }
1657
+ else s += '<i class="fa fa-angle-right" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>';
1658
+ series.last = v;
1659
+ }
1660
+ else {
1661
+ s = r = value;
1662
+ series.last = value;
1663
+ }
1664
1710
- content.className = 'netdata-legend-series-content';
1711
- this.element_legend_childs.nano.appendChild(content);
1712
- }
1713
- else {
1714
- this.element_legend_childs = {
1715
- content: content,
1716
- resize_handler: null,
1717
- title_date: null,
1718
- title_time: null,
1719
- title_units: null,
1720
- nano: null,
1721
- nano_options: null,
1722
- series: {}
1723
- };
1665
+ if(series.value !== null) series.value.innerHTML = s;
1666
+ if(series.user !== null) series.user.innerHTML = r;
1667
}
1668
1726
- if(this.data) {
1727
- this.element_legend_childs.series.labels_key = this.data.dimension_names.toString();
1728
- if(this.debug === true)
1729
- this.log('labels from data: "' + this.element_legend_childs.series.labels_key + '"');
1730
-
1731
- for(var i = 0, len = this.data.dimension_names.length; i < len ;i++) {
1732
- genLabel(this, content, this.data.dimension_names[i], i);
1733
- }
1734
- }
1735
- else {
1736
- var tmp = new Array();
1737
- for(var dim in this.chart.dimensions) {
1738
- tmp.push(this.chart.dimensions[dim].name);
1739
- genLabel(this, content, this.chart.dimensions[dim].name, i);
1669
+ this.legendSetDate = function(ms) {
1670
+ if(typeof ms !== 'number') {
1671
+ this.legendShowUndefined();
1672
+ return;
1673
}
1741
- this.element_legend_childs.series.labels_key = tmp.toString();
1742
- if(this.debug === true)
1743
- this.log('labels from chart: "' + this.element_legend_childs.series.labels_key + '"');
1744
- }
1674
1746
- // create a hidden div to be used for hidding
1747
- // the original legend of the chart library
1748
- var el = document.createElement('div');
1749
- this.element_legend.appendChild(el);
1750
- el.style.display = 'none';
1675
+ var d = new Date(ms);
1676
1752
- this.element_legend_childs.hidden = document.createElement('div');
1753
- el.appendChild(this.element_legend_childs.hidden);
1677
+ if(this.element_legend_childs.title_date)
1678
+ this.element_legend_childs.title_date.innerHTML = d.toLocaleDateString();
1679
1755
- if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
1756
- $(this.element_legend_childs.nano).nanoScroller(this.element_legend_childs.nano_options);
1680
+ if(this.element_legend_childs.title_time)
1681
+ this.element_legend_childs.title_time.innerHTML = d.toLocaleTimeString();
1682
1758
- this.legendShowLatestValues();
1759
- }
1683
+ if(this.element_legend_childs.title_units)
1684
+ this.element_legend_childs.title_units.innerHTML = this.chart.units;
1685
+ }
1686
1761
- chartState.prototype.createChartDOM = function() {
1762
- if(this.debug === true)
1763
- this.log('creating DOM');
1764
-
1765
- this.element_chart_id = this.library_name + '-' + this.uuid + '-chart';
1766
- this.element_chart = document.createElement('div');
1767
- this.element_chart.className += ' netdata-chart' + (this.hasLegend()?'-with-legend-right':'').toString();
1768
- this.element_chart.className += ' netdata-' + this.library_name + '-chart' + (this.hasLegend()?'-with-legend-right':'').toString();
1769
- this.element_chart.id = this.element_chart_id;
1770
- $(this.element_chart).data('netdata-state-object', this);
1771
- this.element.appendChild(this.element_chart);
1772
-
1773
- this.element_legend_id = this.library_name + '-' + this.uuid + '-legend';
1774
- this.element_legend = document.createElement('div');
1775
- this.element_legend.className += ' netdata-chart-legend';
1776
- this.element_legend.className += ' netdata-' + this.library_name + '-legend';
1777
- this.element_legend.id = this.element_legend_id;
1778
- $(this.element_legend).data('netdata-state-object', this);
1779
-
1780
- if(this.hasLegend() === false)
1781
- this.element_legend.style.display = 'none';
1782
- else
1783
- this.element.appendChild(this.element_legend);
1687
+ this.legendShowUndefined = function() {
1688
+ if(this.element_legend_childs.title_date)
1689
+ this.element_legend_childs.title_date.innerHTML = ' ';
1690
1785
- this.element_legend_childs.series = null;
1786
- this.legendUpdateDOM();
1691
+ if(this.element_legend_childs.title_time)
1692
+ this.element_legend_childs.title_time.innerHTML = this.chart.name;
1693
1788
- // in case the user has an active global selection sync in place
1789
- // reset it
1790
- this.globalSelectionSyncStop();
1791
- this.dom_created = true;
1792
- }
1694
+ if(this.element_legend_childs.title_units)
1695
+ this.element_legend_childs.title_units.innerHTML = ' ';
1696
1794
- chartState.prototype.hasLegend = function() {
1795
- if(typeof this.___hasLegendCache___ !== 'undefined')
1796
- return this.___hasLegendCache___;
1697
+ if(this.data && this.element_legend_childs.series !== null) {
1698
+ var labels = this.data.dimension_names;
1699
+ var i = labels.length;
1700
+ while(i--) {
1701
+ var label = labels[i];
1702
1798
- var leg = false;
1799
- if(this.library && this.library.legend(this) === 'right-side') {
1800
- var legend = $(this.element).data('legend') || 'yes';
1801
- if(legend === 'yes') leg = true;
1703
+ if(typeof label === 'undefined') continue;
1704
+ if(typeof this.element_legend_childs.series[label] === 'undefined') continue;
1705
+ this.legendSetLabelValue(label, null);
1706
+ }
1707
+ }
1708
}
1709
1804
- this.___hasLegendCache___ = leg;
1805
- return leg;
1806
- }
1710
+ this.legendShowLatestValues = function() {
1711
+ if(this.chart === null) return;
1712
+ if(this.selected) return;
1713
1808
- chartState.prototype.legendWidth = function() {
1809
- return (this.hasLegend())?140:0;
1810
- }
1714
+ if(this.data === null || this.element_legend_childs.series === null) {
1715
+ this.legendShowUndefined();
1716
+ return;
1717
+ }
1718
1812
- chartState.prototype.legendHeight = function() {
1813
- return $(this.element).height();
1814
- }
1719
+ var show_undefined = true;
1720
+ if(Math.abs(this.data.last_entry - this.data.before) <= this.data.view_update_every)
1721
+ show_undefined = false;
1722
1816
- chartState.prototype.chartWidth = function() {
1817
- return $(this.element).width() - this.legendWidth();
1818
- }
1723
+ if(show_undefined) {
1724
+ this.legendShowUndefined();
1725
+ return;
1726
+ }
1727
1820
- chartState.prototype.chartHeight = function() {
1821
- return $(this.element).height();
1822
- }
1728
+ this.legendSetDate(this.data.before * 1000);
1729
1824
- chartState.prototype.chartPixelsPerPoint = function() {
1825
- // force an options provided detail
1826
- var px = this.pixels_per_point;
1730
+ var labels = this.data.dimension_names;
1731
+ var i = labels.length;
1732
+ while(i--) {
1733
+ var label = labels[i];
1734
1828
- if(this.library && px < this.library.pixels_per_point(this))
1829
- px = this.library.pixels_per_point(this);
1735
+ if(typeof label === 'undefined') continue;
1736
+ if(typeof this.element_legend_childs.series[label] === 'undefined') continue;
1737
1831
- if(px < NETDATA.options.current.pixels_per_point)
1832
- px = NETDATA.options.current.pixels_per_point;
1738
+ if(show_undefined)
1739
+ this.legendSetLabelValue(label, null);
1740
+ else
1741
+ this.legendSetLabelValue(label, this.data.view_latest_values[i]);
1742
+ }
1743
+ }
1744
1834
- return px;
1835
- }
1745
+ this.legendReset = function() {
1746
+ this.legendShowLatestValues();
1747
+ }
1748
1837
- chartState.prototype.needsRecreation = function() {
1838
- return (
1839
- this.dom_created === true
1840
- && this.chart_created === true
1841
- && this.library
1842
- && this.library.autoresize() === false
1843
- && this.tm.last_resized < NETDATA.options.last_resized
1844
- );
1845
- }
1749
+ // this should be called just ONCE per dimension per chart
1750
+ this._chartDimensionColor = function(label) {
1751
+ if(this.colors === null) this.chartColors();
1752
1847
- chartState.prototype.resizeChart = function() {
1848
- if(this.needsRecreation()) {
1849
- if(this.debug === true)
1850
- this.log('forcing re-generation due to window resize.');
1753
+ if(typeof this.colors_assigned[label] === 'undefined') {
1754
+ if(this.colors_available.length === 0) {
1755
+ for(var i = 0, len = NETDATA.colors.length; i < len ; i++)
1756
+ this.colors_available.push(NETDATA.colors[i]);
1757
+ }
1758
1852
- this.destroyChart();
1853
- }
1759
+ this.colors_assigned[label] = this.colors_available.shift();
1760
1855
- this.tm.last_resized = new Date().getTime();
1856
- }
1761
+ if(this.debug === true)
1762
+ this.log('label "' + label + '" got color "' + this.colors_assigned[label]);
1763
+ }
1764
+ else {
1765
+ if(this.debug === true)
1766
+ this.log('label "' + label + '" already has color "' + this.colors_assigned[label] + '"');
1767
+ }
1768
1858
- chartState.prototype.chartURL = function() {
1859
- var before;
1860
- var after;
1861
- if(NETDATA.globalPanAndZoom.isActive()) {
1862
- after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
1863
- before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
1864
- this.tm.pan_and_zoom_seq = NETDATA.globalPanAndZoom.seq;
1769
+ this.colors.push(this.colors_assigned[label]);
1770
+ return this.colors_assigned[label];
1771
}
1866
- else {
1867
- before = this.current.force_before_ms !== null ? Math.round(this.current.force_before_ms / 1000) : this.before;
1868
- after = this.current.force_after_ms !== null ? Math.round(this.current.force_after_ms / 1000) : this.after;
1869
- this.tm.pan_and_zoom_seq = 0;
1772
+
1773
+ this.chartColors = function() {
1774
+ if(this.colors !== null) return this.colors;
1775
+
1776
+ this.colors = new Array();
1777
+ this.colors_available = new Array();
1778
+ // this.colors_assigned = {};
1779
+
1780
+ var c = $(this.element).data('colors');
1781
+ if(typeof c !== 'undefined' && c !== null) {
1782
+ if(typeof c !== 'string') {
1783
+ this.log('invalid color given: ' + c + ' (give a space separated list of colors)');
1784
+ }
1785
+ else {
1786
+ c = c.split(' ');
1787
+ for(var i = 0, len = c.length; i < len ; i++)
1788
+ this.colors_available.push(c[i]);
1789
+ }
1790
+ }
1791
+
1792
+ // push all the standard colors too
1793
+ for(var i = 0, len = NETDATA.colors.length; i < len ; i++)
1794
+ this.colors_available.push(NETDATA.colors[i]);
1795
+
1796
+ return this.colors;
1797
}
1798
1872
- this.current.requested_after_ms = after * 1000;
1873
- this.current.requested_before_ms = before * 1000;
1799
+ this.legendUpdateDOM = function() {
1800
+ var needed = false;
1801
1875
- this.data_points = this.points || Math.round(this.chartWidth() / this.chartPixelsPerPoint());
1802
+ // check that the legend DOM is up to date for the downloaded dimensions
1803
+ if(typeof this.element_legend_childs.series !== 'object' || this.element_legend_childs.series === null) {
1804
+ // this.log('the legend does not have any series - requesting legend update');
1805
+ needed = true;
1806
+ }
1807
+ else if(this.data === null) {
1808
+ // this.log('the chart does not have any data - requesting legend update');
1809
+ needed = true;
1810
+ }
1811
+ else if(typeof this.element_legend_childs.series.labels_key === 'undefined') {
1812
+ needed = true;
1813
+ }
1814
+ else {
1815
+ var labels = this.data.dimension_names.toString();
1816
+ if(labels !== this.element_legend_childs.series.labels_key) {
1817
+ needed = true;
1818
1877
- // build the data URL
1878
- this.data_url = this.chart.data_url;
1879
- this.data_url += "&format=" + this.library.format();
1880
- this.data_url += "&points=" + this.data_points.toString();
1881
- this.data_url += "&group=" + this.method;
1882
- this.data_url += "&options=" + this.library.options();
1883
- this.data_url += '|jsonwrap';
1819
+ if(this.debug === true)
1820
+ this.log('NEW LABELS: "' + labels + '" NOT EQUAL OLD LABELS: "' + this.element_legend_childs.series.labels_key + '"');
1821
+ }
1822
+ }
1823
1885
- if(NETDATA.options.current.eliminate_zero_dimensions === true)
1886
- this.data_url += '|nonzero';
1824
+ if(needed === false) {
1825
+ // make sure colors available
1826
+ this.chartColors();
1827
1888
- if(after)
1889
- this.data_url += "&after=" + after.toString();
1828
+ // do we have to update the current values?
1829
+ // we do this, only when the visible chart is current
1830
+ if(Math.abs(this.data.last_entry - this.data.before) <= this.data.view_update_every) {
1831
+ if(this.debug === true)
1832
+ this.log('chart in running... updating values on legend...');
1833
1891
- if(before)
1892
- this.data_url += "&before=" + before.toString();
1834
+ //var labels = this.data.dimension_names;
1835
+ //var i = labels.length;
1836
+ //while(i--)
1837
+ // this.legendSetLabelValue(labels[i], this.data.latest_values[i]);
1838
+ }
1839
+ return;
1840
+ }
1841
+ if(this.colors === null) {
1842
+ // this is the first time we update the chart
1843
+ // let's assign colors to all dimensions
1844
+ if(this.library.track_colors() === true)
1845
+ for(var dim in this.chart.dimensions)
1846
+ this._chartDimensionColor(this.chart.dimensions[dim].name);
1847
+ }
1848
+ // we will re-generate the colors for the chart
1849
+ this.colors = null;
1850
1894
- if(this.dimensions)
1895
- this.data_url += "&dimensions=" + this.dimensions;
1851
+ if(this.debug === true)
1852
+ this.log('updating Legend DOM');
1853
1897
- if(NETDATA.options.debug.chart_data_url === true || this.debug === true)
1898
- this.log('chartURL(): ' + this.data_url + ' WxH:' + this.chartWidth() + 'x' + this.chartHeight() + ' points: ' + this.data_points + ' library: ' + this.library_name);
1899
- }
1854
+ // mark all dimensions as invalid
1855
+ this.dimensions_visibility.invalidateAll();
1856
1901
- chartState.prototype.redrawChart = function() {
1902
- if(this.data !== null)
1903
- this.updateChartWithData(this.data);
1904
- }
1857
+ var genLabel = function(state, parent, name, count) {
1858
+ var color = state._chartDimensionColor(name);
1859
1906
- chartState.prototype.updateChartWithData = function(data) {
1907
- if(this.debug === true)
1908
- this.log('got data from netdata server');
1860
+ var user_element = null;
1861
+ var user_id = self.data('show-value-of-' + name + '-at') || null;
1862
+ if(user_id !== null) {
1863
+ user_element = document.getElementById(user_id) || null;
1864
+ if(user_element === null)
1865
+ me.log('Cannot find element with id: ' + user_id);
1866
+ }
1867
1910
- this.data = data;
1911
- this.updates_counter++;
1868
+ state.element_legend_childs.series[name] = {
1869
+ name: document.createElement('span'),
1870
+ value: document.createElement('span'),
1871
+ user: user_element,
1872
+ last: null
1873
+ };
1874
1913
- var started = new Date().getTime();
1914
- this.tm.last_updated = started;
1875
+ var label = state.element_legend_childs.series[name];
1876
1916
- // if the result is JSON, find the latest update-every
1917
- if(typeof data === 'object') {
1918
- if(typeof data.view_update_every !== 'undefined')
1919
- this.data_update_every = data.view_update_every * 1000;
1877
+ // create the dimension visibility tracking for this label
1878
+ var ds = state.dimensions_visibility.dimensionAdd(name, label.name, label.value, color);
1879
1921
- if(typeof data.after !== 'undefined')
1922
- this.data_after = data.after * 1000;
1880
+ var rgb = NETDATA.colorHex2Rgb(color);
1881
+ label.name.innerHTML = '<table class="netdata-legend-name-table-'
1882
+ + state.chart.chart_type
1883
+ + '" style="background-color: '
1884
+ + 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current['color_fill_opacity_' + state.chart.chart_type] + ')'
1885
+ + '"><tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr></table>'
1886
1924
- if(typeof data.before !== 'undefined')
1925
- this.data_before = data.before * 1000;
1887
+ var text = document.createTextNode(' ' + name);
1888
+ label.name.appendChild(text);
1889
1927
- if(typeof data.first_entry !== 'undefined')
1928
- this.netdata_first = data.first_entry * 1000;
1890
+ if(count > 0)
1891
+ parent.appendChild(document.createElement('br'));
1892
1930
- if(typeof data.last_entry !== 'undefined')
1931
- this.netdata_last = data.last_entry * 1000;
1893
+ parent.appendChild(label.name);
1894
+ parent.appendChild(label.value);
1895
+ };
1896
1933
- if(typeof data.points !== 'undefined')
1934
- this.data_points = data.points;
1897
+ var content = document.createElement('div');
1898
+
1899
+ if(this.hasLegend()) {
1900
+ this.element_legend_childs = {
1901
+ content: content,
1902
+ resize_handler: document.createElement('div'),
1903
+ title_date: document.createElement('span'),
1904
+ title_time: document.createElement('span'),
1905
+ title_units: document.createElement('span'),
1906
+ nano: document.createElement('div'),
1907
+ nano_options: {
1908
+ paneClass: 'netdata-legend-series-pane',
1909
+ sliderClass: 'netdata-legend-series-slider',
1910
+ contentClass: 'netdata-legend-series-content',
1911
+ enabledClass: '__enabled',
1912
+ flashedClass: '__flashed',
1913
+ activeClass: '__active',
1914
+ tabIndex: -1,
1915
+ alwaysVisible: true,
1916
+ sliderMinHeight: 10
1917
+ },
1918
+ series: {}
1919
+ };
1920
1936
- data.state = this;
1937
- }
1921
+ this.element_legend.innerHTML = '';
1922
1939
- if(this.debug === true) {
1940
- this.log('UPDATE No ' + this.updates_counter + ' COMPLETED');
1923
+ this.element_legend_childs.resize_handler.className += " netdata-legend-resize-handler";
1924
+ this.element_legend_childs.resize_handler.innerHTML = '<i class="fa fa-chevron-up"></i><i class="fa fa-chevron-down"></i>';
1925
+ this.element.appendChild(this.element_legend_childs.resize_handler);
1926
1942
- if(this.current.force_after_ms)
1943
- this.log('STATUS: forced : ' + (this.current.force_after_ms / 1000).toString() + ' - ' + (this.current.force_before_ms / 1000).toString());
1944
- else
1945
- this.log('STATUS: forced: unset');
1927
+ // mousedown event
1928
+ this.element_legend_childs.resize_handler.onmousedown =
1929
+ function(e) {
1930
+ that.resizeHandler(e);
1931
+ };
1932
1947
- this.log('STATUS: requested: ' + (this.current.requested_after_ms / 1000).toString() + ' - ' + (this.current.requested_before_ms / 1000).toString());
1948
- this.log('STATUS: rendered : ' + (this.data_after / 1000).toString() + ' - ' + (this.data_before / 1000).toString());
1949
- this.log('STATUS: points : ' + (this.data_points).toString());
1950
- }
1933
+ // touchstart event
1934
+ this.element_legend_childs.resize_handler.addEventListener('touchstart', function(e) {
1935
+ that.resizeHandler(e);
1936
+ }, false);
1937
1952
- if(this.data_points === 0) {
1953
- this.noData();
1954
- return;
1955
- }
1938
+ this.element_legend_childs.title_date.className += " netdata-legend-title-date";
1939
+ this.element_legend.appendChild(this.element_legend_childs.title_date);
1940
1957
- // this may force the chart to be re-created
1958
- this.resizeChart();
1941
+ this.element_legend.appendChild(document.createElement('br'));
1942
1960
- if(this.updates_since_last_creation >= this.library.max_updates_to_recreate()) {
1961
- if(this.debug === true)
1962
- this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.');
1943
+ this.element_legend_childs.title_time.className += " netdata-legend-title-time";
1944
+ this.element_legend.appendChild(this.element_legend_childs.title_time);
1945
1964
- this.chart_created = false;
1965
- }
1946
+ this.element_legend.appendChild(document.createElement('br'));
1947
1967
- if(this.chart_created === true
1968
- && this.dom_created === true
1969
- && typeof this.library.update === 'function') {
1948
+ this.element_legend_childs.title_units.className += " netdata-legend-title-units";
1949
+ this.element_legend.appendChild(this.element_legend_childs.title_units);
1950
1971
- if(this.debug === true)
1972
- this.log('updating chart...');
1951
+ this.element_legend.appendChild(document.createElement('br'));
1952
1974
- // check and update the legend
1975
- this.legendUpdateDOM();
1953
+ this.element_legend_childs.nano.className = 'netdata-legend-series';
1954
+ this.element_legend.appendChild(this.element_legend_childs.nano);
1955
1977
- this.updates_since_last_creation++;
1978
- if(NETDATA.options.debug.chart_errors === true) {
1979
- this.library.update(this, data);
1956
+ content.className = 'netdata-legend-series-content';
1957
+ this.element_legend_childs.nano.appendChild(content);
1958
}
1959
else {
1982
- try {
1983
- this.library.update(this, data);
1984
- }
1985
- catch(err) {
1986
- this.error('chart failed to be updated as ' + this.library_name);
1987
- }
1960
+ this.element_legend_childs = {
1961
+ content: content,
1962
+ resize_handler: null,
1963
+ title_date: null,
1964
+ title_time: null,
1965
+ title_units: null,
1966
+ nano: null,
1967
+ nano_options: null,
1968
+ series: {}
1969
+ };
1970
}
1989
- }
1990
- else {
1991
- if(this.debug === true)
1992
- this.log('creating chart...');
1971
1994
- this.createChartDOM();
1995
- this.updates_since_last_creation = 0;
1972
+ if(this.data) {
1973
+ this.element_legend_childs.series.labels_key = this.data.dimension_names.toString();
1974
+ if(this.debug === true)
1975
+ this.log('labels from data: "' + this.element_legend_childs.series.labels_key + '"');
1976
1997
- if(NETDATA.options.debug.chart_errors === true) {
1998
- this.library.create(this, data);
1999
- this.chart_created = true;
1977
+ for(var i = 0, len = this.data.dimension_names.length; i < len ;i++) {
1978
+ genLabel(this, content, this.data.dimension_names[i], i);
1979
+ }
1980
}
1981
else {
2002
- try {
2003
- this.library.create(this, data);
2004
- this.chart_created = true;
2005
- }
2006
- catch(err) {
2007
- this.error('chart failed to be created as ' + this.library_name);
1982
+ var tmp = new Array();
1983
+ for(var dim in this.chart.dimensions) {
1984
+ tmp.push(this.chart.dimensions[dim].name);
1985
+ genLabel(this, content, this.chart.dimensions[dim].name, i);
1986
}
1987
+ this.element_legend_childs.series.labels_key = tmp.toString();
1988
+ if(this.debug === true)
1989
+ this.log('labels from chart: "' + this.element_legend_childs.series.labels_key + '"');
1990
}
2010
- }
2011
- // this.legendShowLatestValues();
2012
-
2013
- // update the performance counters
2014
- var now = new Date().getTime();
2015
-
2016
- // don't update last_autorefreshed if this chart is
2017
- // forced to be updated with global PanAndZoom
2018
- if(NETDATA.globalPanAndZoom.isActive())
2019
- this.tm.last_autorefreshed = 0;
2020
- else {
2021
- if(NETDATA.options.current.parallel_refresher === true && NETDATA.options.current.concurrent_refreshes)
2022
- this.tm.last_autorefreshed = Math.round(now / this.data_update_every) * this.data_update_every;
2023
- else
2024
- this.tm.last_autorefreshed = now;
2025
- }
1991
2027
- this.refresh_dt_ms = now - started;
2028
- NETDATA.options.auto_refresher_fast_weight += this.refresh_dt_ms;
1992
+ // create a hidden div to be used for hidding
1993
+ // the original legend of the chart library
1994
+ var el = document.createElement('div');
1995
+ if(this.element_legend !== null)
1996
+ this.element_legend.appendChild(el);
1997
+ el.style.display = 'none';
1998
2030
- if(this.refresh_dt_element)
2031
- this.refresh_dt_element.innerHTML = this.refresh_dt_ms.toString();
2032
- }
1999
+ this.element_legend_childs.hidden = document.createElement('div');
2000
+ el.appendChild(this.element_legend_childs.hidden);
2001
2034
- chartState.prototype.updateChart = function(callback) {
2035
- // due to late initialization of charts and libraries
2036
- // we need to check this too
2037
- if(this.enabled === false) {
2038
- if(this.debug === true)
2039
- this.log('I am not enabled');
2002
+ if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
2003
+ $(this.element_legend_childs.nano).nanoScroller(this.element_legend_childs.nano_options);
2004
2041
- if(typeof callback === 'function') callback();
2042
- return false;
2005
+ this.legendShowLatestValues();
2006
}
2007
2045
- if(this.chart === null) {
2046
- var self = this;
2047
- this.getChart(function() { self.updateChart(callback); });
2048
- return;
2049
- }
2008
+ this.hasLegend = function() {
2009
+ if(typeof this.___hasLegendCache___ !== 'undefined')
2010
+ return this.___hasLegendCache___;
2011
2051
- if(this.library.initialized === false) {
2052
- if(this.library.enabled === true) {
2053
- var self = this;
2054
- this.library.initialize(function() { self.updateChart(callback); });
2055
- return;
2012
+ var leg = false;
2013
+ if(this.library && this.library.legend(this) === 'right-side') {
2014
+ var legend = $(this.element).data('legend') || 'yes';
2015
+ if(legend === 'yes') leg = true;
2016
}
2057
- else {
2058
- this.error('chart library "' + this.library_name + '" is not available.');
2059
- if(typeof callback === 'function') callback();
2060
- return false;
2061
- }
2062
- }
2063
-
2064
- this.clearSelection();
2065
- this.chartURL();
2066
- this.showLoading();
2067
-
2068
- if(this.debug === true)
2069
- this.log('updating from ' + this.data_url);
2070
-
2071
- var self = this;
2072
- this.xhr = $.ajax( {
2073
- url: this.data_url,
2074
- crossDomain: NETDATA.options.crossDomainAjax,
2075
- cache: false,
2076
- async: true
2077
- })
2078
- .success(function(data) {
2079
- self.hideLoading();
2017
2081
- if(self.debug === true)
2082
- self.log('data received. updating chart.');
2083
-
2084
- self.updateChartWithData(data);
2085
- })
2086
- .fail(function() {
2087
- self.hideLoading();
2088
- self.error('data download failed for url: ' + self.data_url);
2089
- })
2090
- .always(function() {
2091
- self.hideLoading();
2092
- if(typeof callback === 'function') callback();
2093
- });
2094
- }
2095
-
2096
- chartState.prototype.destroyChart = function() {
2097
- if(this.debug === true)
2098
- this.log('destroying chart');
2099
-
2100
- if(this.element_message !== null) {
2101
- this.element_message.innerHTML = '';
2102
- this.element_message = null;
2018
+ this.___hasLegendCache___ = leg;
2019
+ return leg;
2020
}
2021
2105
- if(this.element_loading !== null) {
2106
- this.element_loading.innerHTML = '';
2107
- this.element_loading = null;
2022
+ this.legendWidth = function() {
2023
+ return (this.hasLegend())?140:0;
2024
}
2025
2110
- if(this.element_legend !== null) {
2111
- this.element_legend.innerHTML = '';
2112
- this.element_legend = null;
2026
+ this.legendHeight = function() {
2027
+ return $(this.element).height();
2028
}
2029
2115
- if(this.element_chart !== null) {
2116
- this.element_chart.innerHTML = '';
2117
- this.element_chart = null;
2030
+ this.chartWidth = function() {
2031
+ return $(this.element).width() - this.legendWidth();
2032
}
2033
2120
- this.element_legend_childs = {
2121
- hidden: null,
2122
- title_date: null,
2123
- title_time: null,
2124
- title_units: null,
2125
- nano: null,
2126
- nano_options: null,
2127
- series: null
2128
- };
2129
-
2130
- this.element.innerHTML = '';
2131
- this.refresh_dt_element = null;
2132
-
2133
- this.dom_created = false;
2134
- this.chart_created = false;
2135
- this.paused = false;
2136
- this.selected = false;
2137
- this.updates_counter = 0;
2138
- this.updates_since_last_creation = 0;
2139
- this.tm.pan_and_zoom_seq = 0;
2140
- this.tm.last_resized = 0;
2141
- this.tm.last_visible_check = 0;
2142
- this.tm.last_hidden = 0;
2143
- this.tm.last_unhidden = 0;
2144
- this.tm.last_autorefreshed = 0;
2145
-
2146
- this.data = null;
2147
- this.data_points = 0;
2148
- this.data_after = 0;
2149
- this.data_before = 0;
2150
- this.data_update_every = 0;
2151
- this.netdata_first = 0;
2152
- this.netdata_last = 0;
2153
- if(this.current !== null) {
2154
- this.current.force_update_at = 0;
2155
- this.current.force_after_ms = null;
2156
- this.current.force_before_ms = null;
2157
- this.current.requested_after_ms = null;
2158
- this.current.requested_before_ms = null;
2034
+ this.chartHeight = function() {
2035
+ return $(this.element).height();
2036
}
2160
- this.init();
2161
- }
2037
2163
- chartState.prototype.unhideChart = function() {
2164
- if(typeof this.___isHidden___ !== 'undefined' && this.enabled === true) {
2165
- if(this.debug === true)
2166
- this.log('unhiding chart');
2038
+ this.chartPixelsPerPoint = function() {
2039
+ // force an options provided detail
2040
+ var px = this.pixels_per_point;
2041
2168
- this.element_message.style.display = 'none';
2169
- if(this.element_chart !== null) this.element_chart.style.display = 'inline-block';
2170
- if(this.element_legend !== null) this.element_legend.style.display = 'inline-block';
2171
- if(this.element_loading !== null) this.element_loading.style.display = 'none';
2172
- this.___isHidden___ = undefined;
2173
- this.element_message.innerHTML = 'chart ' + this.id + ' is visible now';
2042
+ if(this.library && px < this.library.pixels_per_point(this))
2043
+ px = this.library.pixels_per_point(this);
2044
2175
- // refresh the scrolbar
2176
- if(this.element_legend_childs.nano !== null && this.element_legend_childs.nano_options !== null)
2177
- $(this.element_legend_childs.nano).nanoScroller(this.element_legend_childs.nano_options);
2045
+ if(px < NETDATA.options.current.pixels_per_point)
2046
+ px = NETDATA.options.current.pixels_per_point;
2047
2179
- this.tm.last_unhidden = new Date().getTime();
2048
+ return px;
2049
}
2181
- }
2050
2183
- chartState.prototype.hideChart = function() {
2184
- if(typeof this.___isHidden___ === 'undefined' && this.enabled === true) {
2185
- if(NETDATA.options.current.destroy_on_hide === true)
2186
- this.destroyChart();
2187
-
2188
- if(this.debug === true)
2189
- this.log('hiding chart');
2190
-
2191
- this.element_message.style.display = 'inline-block';
2192
- if(this.element_chart !== null) this.element_chart.style.display = 'none';
2193
- if(this.element_legend !== null) this.element_legend.style.display = 'none';
2194
- if(this.element_loading !== null) this.element_loading.style.display = 'none';
2195
- this.___isHidden___ = true;
2196
- this.___showsLoading___ = undefined;
2197
- this.element_message.innerHTML = 'chart ' + this.id + ' is hidden to speed up the browser';
2198
- this.tm.last_hidden = new Date().getTime();
2051
+ this.needsRecreation = function() {
2052
+ return (
2053
+ this.chart_created === true
2054
+ && this.library
2055
+ && this.library.autoresize() === false
2056
+ && this.tm.last_resized < NETDATA.options.last_resized
2057
+ );
2058
}
2200
- }
2059
2202
- chartState.prototype.hideLoading = function() {
2203
- if(typeof this.___showsLoading___ !== 'undefined' && this.enabled === true) {
2204
- if(this.debug === true)
2205
- this.log('hide loading...');
2206
-
2207
- this.element_message.style.display = 'none';
2208
- if(this.element_chart !== null) this.element_chart.style.display = 'inline-block';
2209
- if(this.element_legend !== null) this.element_legend.style.display = 'inline-block';
2210
- if(this.element_loading !== null) this.element_loading.style.display = 'none';
2211
- this.___showsLoading___ = undefined;
2212
- this.element_loading.innerHTML = 'chart ' + this.id + ' finished loading!';
2213
- this.tm.last_unhidden = new Date().getTime();
2214
- }
2215
- }
2060
+ this.chartURL = function() {
2061
+ var before;
2062
+ var after;
2063
+ if(NETDATA.globalPanAndZoom.isActive()) {
2064
+ after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000);
2065
+ before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000);
2066
+ this.tm.pan_and_zoom_seq = NETDATA.globalPanAndZoom.seq;
2067
+ }
2068
+ else {
2069
+ before = this.current.force_before_ms !== null ? Math.round(this.current.force_before_ms / 1000) : this.before;
2070
+ after = this.current.force_after_ms !== null ? Math.round(this.current.force_after_ms / 1000) : this.after;
2071
+ this.tm.pan_and_zoom_seq = 0;
2072
+ }
2073
2217
- chartState.prototype.showLoading = function() {
2218
- if(typeof this.___showsLoading___ === 'undefined' && this.chart_created === false && this.enabled === true) {
2219
- if(this.debug === true)
2220
- this.log('show loading...');
2074
+ this.requested_after = after * 1000;
2075
+ this.requested_before = before * 1000;
2076
2222
- this.element_message.style.display = 'none';
2223
- if(this.element_chart !== null) this.element_chart.style.display = 'none';
2224
- if(this.element_legend !== null) this.element_legend.style.display = 'none';
2225
- if(this.element_loading !== null) this.element_loading.style.display = 'inline-block';
2226
- this.___showsLoading___ = true;
2227
- this.___isHidden___ = undefined;
2228
- this.element_loading.innerHTML = 'chart ' + this.id + ' is loading...';
2229
- this.tm.last_hidden = new Date().getTime();
2230
- }
2231
- }
2077
+ this.data_points = this.points || Math.round(this.chartWidth() / this.chartPixelsPerPoint());
2078
2233
- chartState.prototype.isVisible = function() {
2234
- // this.log('last_visible_check: ' + this.tm.last_visible_check + ', last_page_scroll: ' + NETDATA.options.last_page_scroll);
2079
+ // build the data URL
2080
+ this.data_url = this.chart.data_url;
2081
+ this.data_url += "&format=" + this.library.format();
2082
+ this.data_url += "&points=" + this.data_points.toString();
2083
+ this.data_url += "&group=" + this.method;
2084
+ this.data_url += "&options=" + this.library.options();
2085
+ this.data_url += '|jsonwrap';
2086
2236
- // caching - we do not evaluate the charts visibility
2237
- // if the page has not been scrolled since the last check
2238
- if(this.tm.last_visible_check > NETDATA.options.last_page_scroll) {
2239
- if(this.debug === true)
2240
- this.log('isVisible: ' + this.___isVisible___);
2087
+ if(NETDATA.options.current.eliminate_zero_dimensions === true)
2088
+ this.data_url += '|nonzero';
2089
2242
- return this.___isVisible___;
2243
- }
2090
+ if(after)
2091
+ this.data_url += "&after=" + after.toString();
2092
2245
- this.tm.last_visible_check = new Date().getTime();
2093
+ if(before)
2094
+ this.data_url += "&before=" + before.toString();
2095
2247
- var wh = window.innerHeight;
2248
- var x = this.element.getBoundingClientRect();
2249
- var ret = 0;
2250
- var tolerance = 0;
2096
+ if(this.dimensions)
2097
+ this.data_url += "&dimensions=" + this.dimensions;
2098
2252
- if(x.top < 0 && -x.top > x.height) {
2253
- // the chart is entirely above
2254
- ret = -x.top - x.height;
2099
+ if(NETDATA.options.debug.chart_data_url === true || this.debug === true)
2100
+ this.log('chartURL(): ' + this.data_url + ' WxH:' + this.chartWidth() + 'x' + this.chartHeight() + ' points: ' + this.data_points + ' library: ' + this.library_name);
2101
}
2256
- else if(x.top > wh) {
2257
- // the chart is entirely below
2258
- ret = x.top - wh;
2102
+
2103
+ this.redrawChart = function() {
2104
+ if(this.data !== null)
2105
+ this.updateChartWithData(this.data);
2106
}
2107
2261
- if(ret > tolerance) {
2262
- // the chart is too far
2263
- this.___isVisible___ = false;
2264
- if(this.chart_created === true) this.hideChart();
2265
-
2108
+ this.updateChartWithData = function(data) {
2109
if(this.debug === true)
2267
- this.log('isVisible: ' + this.___isVisible___);
2110
+ this.log('got data from netdata server');
2111
2269
- return this.___isVisible___;
2270
- }
2271
- else {
2272
- // the chart is inside or very close
2273
- this.___isVisible___ = true;
2274
- this.unhideChart();
2275
-
2276
- if(this.debug === true)
2277
- this.log('isVisible: ' + this.___isVisible___);
2112
+ // this may force the chart to be re-created
2113
+ resizeChart();
2114
2279
- return this.___isVisible___;
2280
- }
2281
- }
2115
+ this.data = data;
2116
+ this.updates_counter++;
2117
2283
- chartState.prototype.isAutoRefreshed = function() {
2284
- return (this.current.autorefresh);
2285
- }
2118
+ var started = new Date().getTime();
2119
2287
- chartState.prototype.canBeAutoRefreshed = function() {
2288
- now = new Date().getTime();
2120
+ // if the result is JSON, find the latest update-every
2121
+ if(typeof data === 'object') {
2122
+ if(typeof data.view_update_every !== 'undefined')
2123
+ this.data_update_every = data.view_update_every * 1000;
2124
2290
- if(this.enabled === false) {
2291
- if(this.debug === true)
2292
- this.log('I am not enabled');
2125
+ if(typeof data.after !== 'undefined')
2126
+ this.data_after = data.after * 1000;
2127
2294
- return false;
2295
- }
2128
+ if(typeof data.before !== 'undefined')
2129
+ this.data_before = data.before * 1000;
2130
2297
- if(this.library === null || this.library.enabled === false) {
2298
- this.error('charting library "' + this.library_name + '" is not available');
2299
- if(this.debug === true)
2300
- this.log('My chart library ' + this.library_name + ' is not available');
2131
+ if(typeof data.first_entry !== 'undefined')
2132
+ this.netdata_first = data.first_entry * 1000;
2133
2302
- return false;
2303
- }
2134
+ if(typeof data.last_entry !== 'undefined')
2135
+ this.netdata_last = data.last_entry * 1000;
2136
2305
- if(this.isVisible() === false) {
2306
- if(NETDATA.options.debug.visibility === true || this.debug === true)
2307
- this.log('I am not visible');
2137
+ if(typeof data.points !== 'undefined')
2138
+ this.data_points = data.points;
2139
2309
- return false;
2310
- }
2311
-
2312
- if(this.current.force_update_at !== 0 && this.current.force_update_at < now) {
2313
- if(this.debug === true)
2314
- this.log('timed force update detected - allowing this update');
2140
+ data.state = this;
2141
+ }
2142
2316
- this.current.force_update_at = 0;
2317
- return true;
2318
- }
2143
+ if(this.debug === true) {
2144
+ this.log('UPDATE No ' + this.updates_counter + ' COMPLETED');
2145
+
2146
+ if(this.current.force_after_ms)
2147
+ this.log('STATUS: forced : ' + (this.current.force_after_ms / 1000).toString() + ' - ' + (this.current.force_before_ms / 1000).toString());
2148
+ else
2149
+ this.log('STATUS: forced: unset');
2150
2320
- if(this.isAutoRefreshed() === true) {
2321
- // allow the first update, even if the page is not visible
2322
- if(this.updates_counter && NETDATA.options.page_is_visible === false) {
2323
- if(NETDATA.options.debug.focus === true || this.debug === true)
2324
- this.log('canBeAutoRefreshed(): page does not have focus');
2151
+ this.log('STATUS: requested: ' + (this.requested_after / 1000).toString() + ' - ' + (this.requested_before / 1000).toString());
2152
+ this.log('STATUS: rendered : ' + (this.data_after / 1000).toString() + ' - ' + (this.data_before / 1000).toString());
2153
+ this.log('STATUS: points : ' + (this.data_points).toString());
2154
+ }
2155
2326
- return false;
2156
+ if(this.data_points === 0) {
2157
+ noDataToShow();
2158
+ return;
2159
}
2160
2329
- if(this.needsRecreation() === true) {
2161
+ if(this.updates_since_last_creation >= this.library.max_updates_to_recreate()) {
2162
if(this.debug === true)
2331
- this.log('canBeAutoRefreshed(): needs re-creation.');
2163
+ this.log('max updates of ' + this.updates_since_last_creation.toString() + ' reached. Forcing re-generation.');
2164
2333
- return true;
2165
+ this.chart_created = false;
2166
}
2167
2336
- // options valid only for autoRefresh()
2337
- if(NETDATA.options.auto_refresher_stop_until === 0 || NETDATA.options.auto_refresher_stop_until < now) {
2338
- if(NETDATA.globalPanAndZoom.isActive()) {
2339
- if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this)) {
2340
- if(this.debug === true)
2341
- this.log('canBeAutoRefreshed(): global panning: I need an update.');
2168
+ // check and update the legend
2169
+ this.legendUpdateDOM();
2170
2343
- return true;
2344
- }
2345
- else {
2346
- if(this.debug === true)
2347
- this.log('canBeAutoRefreshed(): global panning: I am already up to date.');
2171
+ if(this.chart_created === true
2172
+ && typeof this.library.update === 'function') {
2173
2349
- return false;
2174
+ if(this.debug === true)
2175
+ this.log('updating chart...');
2176
+
2177
+ this.updates_since_last_creation++;
2178
+ if(NETDATA.options.debug.chart_errors === true) {
2179
+ this.library.update(this, data);
2180
+ }
2181
+ else {
2182
+ try {
2183
+ this.library.update(this, data);
2184
+ }
2185
+ catch(err) {
2186
+ error('chart failed to be updated as ' + this.library_name);
2187
}
2188
}
2189
+ }
2190
+ else {
2191
+ if(this.debug === true)
2192
+ this.log('creating chart...');
2193
2353
- if(this.selected === true) {
2354
- if(this.debug === true)
2355
- this.log('canBeAutoRefreshed(): I have a selection in place.');
2356
-
2357
- return false;
2194
+ if(NETDATA.options.debug.chart_errors === true) {
2195
+ this.library.create(this, data);
2196
+ this.chart_created = true;
2197
+ this.updates_since_last_creation = 0;
2198
}
2359
-
2360
- if(this.paused === true) {
2361
- if(this.debug === true)
2362
- this.log('canBeAutoRefreshed(): I am paused.');
2363
-
2364
- return false;
2199
+ else {
2200
+ try {
2201
+ this.library.create(this, data);
2202
+ this.chart_created = true;
2203
+ this.updates_since_last_creation = 0;
2204
+ }
2205
+ catch(err) {
2206
+ error('chart failed to be created as ' + this.library_name);
2207
+ }
2208
}
2209
+ }
2210
+ hideMessage();
2211
+ NETDATA.globalSelectionSync.stop();
2212
2367
- if(now - this.tm.last_autorefreshed >= this.data_update_every) {
2368
- if(this.debug === true)
2369
- this.log('canBeAutoRefreshed(): It is time to update me.');
2213
+ // this.legendShowLatestValues();
2214
2371
- return true;
2372
- }
2215
+ // update the performance counters
2216
+ var now = new Date().getTime();
2217
+ this.tm.last_updated = now;
2218
+
2219
+ // don't update last_autorefreshed if this chart is
2220
+ // forced to be updated with global PanAndZoom
2221
+ if(NETDATA.globalPanAndZoom.isActive())
2222
+ this.tm.last_autorefreshed = 0;
2223
+ else {
2224
+ if(NETDATA.options.current.parallel_refresher === true && NETDATA.options.current.concurrent_refreshes)
2225
+ this.tm.last_autorefreshed = Math.round(now / this.data_update_every) * this.data_update_every;
2226
+ else
2227
+ this.tm.last_autorefreshed = now;
2228
}
2374
- }
2229
2376
- return false;
2377
- }
2230
+ this.refresh_dt_ms = now - started;
2231
+ NETDATA.options.auto_refresher_fast_weight += this.refresh_dt_ms;
2232
2379
- chartState.prototype.autoRefresh = function(callback) {
2380
- if(this.canBeAutoRefreshed() === true) {
2381
- this.updateChart(callback);
2382
- }
2383
- else {
2384
- if(typeof callback !== 'undefined')
2385
- callback();
2233
+ if(this.refresh_dt_element !== null)
2234
+ this.refresh_dt_element.innerHTML = this.refresh_dt_ms.toString();
2235
}
2387
- }
2236
2389
- chartState.prototype._defaultsFromDownloadedChart = function(chart) {
2390
- this.chart = chart;
2391
- this.chart_url = chart.url;
2392
- this.data_update_every = chart.update_every * 1000;
2393
- this.data_points = Math.round(this.chartWidth() / this.chartPixelsPerPoint());
2394
- this.tm.last_info_downloaded = new Date().getTime();
2395
- }
2237
+ this.updateChart = function(callback) {
2238
+ // due to late initialization of charts and libraries
2239
+ // we need to check this too
2240
+ if(this.enabled === false) {
2241
+ if(this.debug === true)
2242
+ this.log('I am not enabled');
2243
2397
- // fetch the chart description from the netdata server
2398
- chartState.prototype.getChart = function(callback) {
2399
- this.chart = NETDATA.chartRegistry.get(this.host, this.id);
2400
- if(this.chart) {
2401
- this._defaultsFromDownloadedChart(this.chart);
2402
- if(typeof callback === 'function') callback();
2403
- }
2404
- else {
2405
- this.chart_url = this.host + "/api/v1/chart?chart=" + this.id;
2244
+ if(typeof callback === 'function') callback();
2245
+ return false;
2246
+ }
2247
2407
- if(this.debug === true)
2408
- this.log('downloading ' + this.chart_url);
2248
+ if(this.chart === null) {
2249
+ this.getChart(function() { that.updateChart(callback); });
2250
+ return;
2251
+ }
2252
2410
- var self = this;
2253
+ if(this.library.initialized === false) {
2254
+ if(this.library.enabled === true) {
2255
+ this.library.initialize(function() { that.updateChart(callback); });
2256
+ return;
2257
+ }
2258
+ else {
2259
+ error('chart library "' + this.library_name + '" is not available.');
2260
+ if(typeof callback === 'function') callback();
2261
+ return false;
2262
+ }
2263
+ }
2264
+
2265
+ this.clearSelection();
2266
+ this.chartURL();
2267
2412
- $.ajax( {
2413
- url: this.chart_url,
2268
+ if(this.debug === true)
2269
+ this.log('updating from ' + this.data_url);
2270
+
2271
+ this.xhr = $.ajax( {
2272
+ url: this.data_url,
2273
crossDomain: NETDATA.options.crossDomainAjax,
2274
cache: false,
2275
async: true
2276
})
2418
- .done(function(chart) {
2419
- chart.url = self.chart_url;
2420
- chart.data_url = (self.host + chart.data_url);
2421
- self._defaultsFromDownloadedChart(chart);
2422
- NETDATA.chartRegistry.add(self.host, self.id, chart);
2277
+ .success(function(data) {
2278
+ if(that.debug === true)
2279
+ that.log('data received. updating chart.');
2280
+
2281
+ that.updateChartWithData(data);
2282
})
2283
.fail(function() {
2425
- NETDATA.error(404, self.chart_url);
2426
- self.error('chart not found on url "' + self.chart_url + '"');
2284
+ error('data download failed for url: ' + that.data_url);
2285
})
2286
.always(function() {
2287
if(typeof callback === 'function') callback();
2288
});
2289
}
2432
- }
2290
2434
- // resize the chart to its real dimensions
2435
- // as given by the caller
2436
- chartState.prototype.sizeChart = function() {
2437
- if(this.hasLegend() === true)
2438
- this.element.className += " netdata-container-with-legend";
2439
- else
2440
- this.element.className += " netdata-container";
2291
+ this.isVisible = function() {
2292
+ // this.log('last_visible_check: ' + this.tm.last_visible_check + ', last_page_scroll: ' + NETDATA.options.last_page_scroll);
2293
2442
- if(this.debug === true)
2443
- this.log('sizing element');
2294
+ // caching - we do not evaluate the charts visibility
2295
+ // if the page has not been scrolled since the last check
2296
+ if(this.tm.last_visible_check > NETDATA.options.last_page_scroll) {
2297
+ if(this.debug === true)
2298
+ this.log('isVisible: ' + this.___isVisible___);
2299
2445
- if(this.width !== 0)
2446
- $(this.element).css('width', this.width);
2300
+ return this.___isVisible___;
2301
+ }
2302
2448
- if(this.height !== 0)
2449
- $(this.element).css('height', this.height);
2303
+ this.tm.last_visible_check = new Date().getTime();
2304
2451
- if(NETDATA.chartDefaults.min_width !== null)
2452
- $(this.element).css('min-width', NETDATA.chartDefaults.min_width);
2453
- }
2305
+ var wh = window.innerHeight;
2306
+ var x = this.element.getBoundingClientRect();
2307
+ var ret = 0;
2308
+ var tolerance = 0;
2309
2455
- chartState.prototype.noData = function() {
2456
- if(this.dom_created === false)
2457
- this.createChartDOM();
2310
+ if(x.top < 0 && -x.top > x.height) {
2311
+ // the chart is entirely above
2312
+ ret = -x.top - x.height;
2313
+ }
2314
+ else if(x.top > wh) {
2315
+ // the chart is entirely below
2316
+ ret = x.top - wh;
2317
+ }
2318
2459
- this.tm.last_autorefreshed = new Date().getTime();
2460
- this.data_update_every = 30 * 1000;
2461
- }
2319
+ if(ret > tolerance) {
2320
+ // the chart is too far
2321
2463
- // show a message in the chart
2464
- chartState.prototype.message = function(type, msg) {
2465
- this.hideChart();
2466
- this.element_message.innerHTML = msg;
2322
+ hideChart();
2323
+ this.___isVisible___ = false;
2324
+
2325
+ if(this.debug === true)
2326
+ this.log('isVisible: ' + this.___isVisible___);
2327
2468
- if(this.debug === null)
2469
- this.log(msg);
2470
- }
2328
+ return this.___isVisible___;
2329
+ }
2330
+ else {
2331
+ // the chart is inside or very close
2332
2472
- // show an error on the chart and stop it forever
2473
- chartState.prototype.error = function(msg) {
2474
- this.message('error', this.id + ': ' + msg);
2475
- this.enabled = false;
2476
- }
2333
+ unhideChart();
2334
+ this.___isVisible___ = true;
2335
+
2336
+ if(this.debug === true)
2337
+ this.log('isVisible: ' + this.___isVisible___);
2338
2478
- // show a message indicating the chart is loading
2479
- chartState.prototype.info = function(msg) {
2480
- this.message('info', this.id + ': ' + msg);
2481
- }
2339
+ return this.___isVisible___;
2340
+ }
2341
+ }
2342
2483
- chartState.prototype.init = function() {
2484
- this.element.innerHTML = '';
2343
+ this.isAutoRefreshed = function() {
2344
+ return (this.current.autorefresh);
2345
+ }
2346
2486
- this.element_message = document.createElement('div');
2487
- this.element_message.className += ' netdata-message';
2488
- this.element.appendChild(this.element_message);
2347
+ this.canBeAutoRefreshed = function() {
2348
+ now = new Date().getTime();
2349
2490
- this.element_loading = document.createElement('div');
2491
- this.element_loading.className += ' netdata-chart-is-loading';
2492
- this.element.appendChild(this.element_loading);
2350
+ if(this.enabled === false) {
2351
+ if(this.debug === true)
2352
+ this.log('I am not enabled');
2353
2494
- if(this.debug === null)
2495
- this.log('created');
2354
+ return false;
2355
+ }
2356
2497
- // make sure the host does not end with /
2498
- // all netdata API requests use absolute paths
2499
- while(this.host.slice(-1) === '/')
2500
- this.host = this.host.substring(0, this.host.length - 1);
2357
+ if(this.library === null || this.library.enabled === false) {
2358
+ error('charting library "' + this.library_name + '" is not available');
2359
+ if(this.debug === true)
2360
+ this.log('My chart library ' + this.library_name + ' is not available');
2361
2502
- // check the requested library is available
2503
- // we don't initialize it here - it will be initialized when
2504
- // this chart will be first used
2505
- if(typeof NETDATA.chartLibraries[this.library_name] === 'undefined') {
2506
- NETDATA.error(402, this.library_name);
2507
- this.error('chart library "' + this.library_name + '" is not found');
2362
+ return false;
2363
+ }
2364
+
2365
+ if(this.isVisible() === false) {
2366
+ if(NETDATA.options.debug.visibility === true || this.debug === true)
2367
+ this.log('I am not visible');
2368
+
2369
+ return false;
2370
+ }
2371
+
2372
+ if(this.current.force_update_at !== 0 && this.current.force_update_at < now) {
2373
+ if(this.debug === true)
2374
+ this.log('timed force update detected - allowing this update');
2375
+
2376
+ this.current.force_update_at = 0;
2377
+ return true;
2378
+ }
2379
+
2380
+ if(this.isAutoRefreshed() === true) {
2381
+ // allow the first update, even if the page is not visible
2382
+ if(this.updates_counter && NETDATA.options.page_is_visible === false) {
2383
+ if(NETDATA.options.debug.focus === true || this.debug === true)
2384
+ this.log('canBeAutoRefreshed(): page does not have focus');
2385
+
2386
+ return false;
2387
+ }
2388
+
2389
+ if(this.needsRecreation() === true) {
2390
+ if(this.debug === true)
2391
+ this.log('canBeAutoRefreshed(): needs re-creation.');
2392
+
2393
+ return true;
2394
+ }
2395
+
2396
+ // options valid only for autoRefresh()
2397
+ if(NETDATA.options.auto_refresher_stop_until === 0 || NETDATA.options.auto_refresher_stop_until < now) {
2398
+ if(NETDATA.globalPanAndZoom.isActive()) {
2399
+ if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this)) {
2400
+ if(this.debug === true)
2401
+ this.log('canBeAutoRefreshed(): global panning: I need an update.');
2402
+
2403
+ return true;
2404
+ }
2405
+ else {
2406
+ if(this.debug === true)
2407
+ this.log('canBeAutoRefreshed(): global panning: I am already up to date.');
2408
+
2409
+ return false;
2410
+ }
2411
+ }
2412
+
2413
+ if(this.selected === true) {
2414
+ if(this.debug === true)
2415
+ this.log('canBeAutoRefreshed(): I have a selection in place.');
2416
+
2417
+ return false;
2418
+ }
2419
+
2420
+ if(this.paused === true) {
2421
+ if(this.debug === true)
2422
+ this.log('canBeAutoRefreshed(): I am paused.');
2423
+
2424
+ return false;
2425
+ }
2426
+
2427
+ if(now - this.tm.last_autorefreshed >= this.data_update_every) {
2428
+ if(this.debug === true)
2429
+ this.log('canBeAutoRefreshed(): It is time to update me.');
2430
+
2431
+ return true;
2432
+ }
2433
+ }
2434
+ }
2435
+
2436
+ return false;
2437
}
2509
- else if(NETDATA.chartLibraries[this.library_name].enabled === false) {
2510
- NETDATA.error(403, this.library_name);
2511
- this.error('chart library "' + this.library_name + '" is not enabled');
2438
+
2439
+ this.autoRefresh = function(callback) {
2440
+ if(this.canBeAutoRefreshed() === true) {
2441
+ this.updateChart(callback);
2442
+ }
2443
+ else {
2444
+ if(typeof callback !== 'undefined')
2445
+ callback();
2446
+ }
2447
}
2513
- else
2514
- this.library = NETDATA.chartLibraries[this.library_name];
2448
2516
- this.sizeChart();
2449
+ this._defaultsFromDownloadedChart = function(chart) {
2450
+ this.chart = chart;
2451
+ this.chart_url = chart.url;
2452
+ this.data_update_every = chart.update_every * 1000;
2453
+ this.data_points = Math.round(this.chartWidth() / this.chartPixelsPerPoint());
2454
+ this.tm.last_info_downloaded = new Date().getTime();
2455
+ }
2456
2518
- // if we need to report the rendering speed
2519
- // find the element that needs to be updated
2520
- if(this.refresh_dt_element_name)
2521
- this.refresh_dt_element = document.getElementById(this.refresh_dt_element_name) || null;
2457
+ // fetch the chart description from the netdata server
2458
+ this.getChart = function(callback) {
2459
+ this.chart = NETDATA.chartRegistry.get(this.host, this.id);
2460
+ if(this.chart) {
2461
+ this._defaultsFromDownloadedChart(this.chart);
2462
+ if(typeof callback === 'function') callback();
2463
+ }
2464
+ else {
2465
+ this.chart_url = this.host + "/api/v1/chart?chart=" + this.id;
2466
+
2467
+ if(this.debug === true)
2468
+ this.log('downloading ' + this.chart_url);
2469
+
2470
+ $.ajax( {
2471
+ url: this.chart_url,
2472
+ crossDomain: NETDATA.options.crossDomainAjax,
2473
+ cache: false,
2474
+ async: true
2475
+ })
2476
+ .done(function(chart) {
2477
+ chart.url = that.chart_url;
2478
+ chart.data_url = (that.host + chart.data_url);
2479
+ that._defaultsFromDownloadedChart(chart);
2480
+ NETDATA.chartRegistry.add(that.host, that.id, chart);
2481
+ })
2482
+ .fail(function() {
2483
+ NETDATA.error(404, that.chart_url);
2484
+ error('chart not found on url "' + that.chart_url + '"');
2485
+ })
2486
+ .always(function() {
2487
+ if(typeof callback === 'function') callback();
2488
+ });
2489
+ }
2490
+ }
2491
+
2492
+ // ============================================================================================================
2493
+ // INITIALIZATION
2494
2523
- // the default mode for all charts
2524
- this.setMode('auto');
2495
+ init();
2496
}
2497
2498
// get or create a chart state, given a DOM element
@@ -3283,9 +3254,10 @@
3254
y: {
3255
pixelsPerLabel: 15,
3256
valueFormatter: function (x) {
3257
+ // we format legends with the state object
3258
+ // no need to do anything here
3259
// return (Math.round(x*100) / 100).toLocaleString();
3287
- //return state.legendFormatValue(x);
3288
- //FIXME
3260
+ // return state.legendFormatValue(x);
3261
return x;
3262
}
3263
}
@@ -3702,7 +3674,7 @@
3674
NETDATA.morrisChartCreate = function(state, data) {
3675
3676
state.morris_options = {
3705
- element: state.element_chart_id,
3677
+ element: state.element_chart.id,
3678
data: data.result.data,
3679
xkey: 'time',
3680
ykeys: data.dimension_names,
web/index.html
+1
-1
@@ -253,7 +253,7 @@
253
<!-- <script> netdataServer = "http://box:19999"; </script> -->
254
255
<!-- load the dashboard manager - it will do the rest -->
256
- <script type="text/javascript" src="dashboard.js?v8"></script>
256
+ <script type="text/javascript" src="dashboard.js?v9"></script>
257
</head>
258
259
<body data-spy="scroll" data-target="#sidebar">