Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

vigigraph / vigigraph / public / js / graph.js @ c1b9f1da

History | View | Annotate | Download (12.3 KB)

1 7c9baa43 Francois POIROTTE
var Graph = new Class({
2
    Implements: [Events, Options],
3
4
    options: {
5
        // Les valeurs par défaut sont assignées dans reset().
6
        duration: 86400,
7
        start: null,
8
        autoRefresh: 0,
9
        refreshDelay: null,
10
        left: null,
11
        top: null
12
    },
13
14
    initialize: function (options, host, graph) {
15
        this.setOptions(options);
16
        this.host = host;
17
        this.graph = graph;
18
        this.refreshTimer = null;
19
20
        new Request.JSON({
21 c1b9f1da Francois POIROTTE
            url: app_path + 'rpc/startTime',
22 7c9baa43 Francois POIROTTE
            onSuccess: function (data) {
23
                this.startTime = data.starttime;
24
            }.bind(this)
25
        }).get({'host': this.host});
26
27
        var toolbar = new Jx.Toolbar({position:'top'});
28
        var periods = [
29
            [_('Last 12 hours'),    12],
30
            [_('Last 24 hours'),    24],
31
            [_('Last 48 hours'),    48],
32
            [_('Last 7 days'),      7*24],
33
            [_('Last 14 days'),     14*24],
34
            [_('Last 3 months'),    3*30*24],
35
            [_('Last 6 months'),    6*30*24],
36
            [_('Last year'),        365*24]
37
        ];
38
39
        var timeframe = new Jx.Menu({
40
            label: _("Timeframe"),
41
            image: app_path + 'images/history.png',
42
            tooltip: _("Timeframe menu")
43
        });
44
45
        periods.each(function (period) {
46
            var menuItem = new Jx.Menu.Item({
47
                label: period[0]
48
            });
49
            menuItem.options.period = period[1] * 60 * 60;
50
            menuItem.addEvent('click', function () {
51
                this[0].options.duration = this[1].options.period;
52
                this[0].updateGraph();
53
            }.bind([this, menuItem]));
54
            timeframe.add(menuItem);
55
        }, this);
56
57
        this.indicators = new Jx.Menu({
58
            label: _("Export to CSV"),
59
            image: app_path + 'images/document-export.png',
60
            tooltip: _("Export the content of this graph to CSV"),
61
        })
62
63
        new Request.JSON({
64
            url: app_path + 'rpc/getIndicators',
65
            onSuccess: function (data) {
66
                data.items.each(function (item) {
67
                    this.indicators.add(new Jx.Menu.Item({
68
                        label: item,
69
                        onClick: this.exportCSV.bind(this),
70
                        indicator: true
71
                    }));
72
                }, this);
73
74
                this.indicators.add(new Jx.Menu.Item({
75
                    label: _('All'),
76
                    onClick: this.exportCSV.bind(this),
77
                    indicator: false
78
                }));
79
            }.bind(this)
80
        }).get({
81
            'host': this.host,
82
            'graph': this.graph
83
        });
84
85
        this.refresh_button = new Jx.Button({
86
            image: app_path + 'images/refresh.png',
87 89829224 Francois POIROTTE
            tooltip: _("Automatically refresh the graph"),
88 7c9baa43 Francois POIROTTE
            toggle: true,
89
            onDown: function() {
90
                // On s'assure qu'il n'y a pas déjà un timer lancé.
91
                if ($chk(this.refreshTimer))
92
                    return;
93
                var delay =
94
                    this.options.refreshDelay ||
95
                    window.refresh_delay;
96
                this.refreshTimer =
97
                    this.updateGraph.periodical(delay * 1000, this);
98
                this.options.autoRefresh = 1;
99
                this.updateURI();
100
            }.bind(this),
101
            onUp: function() {
102
                clearInterval(this.refreshTimer);
103
                this.options.autoRefresh = 0;
104
                this.updateURI();
105
            }.bind(this)
106
        });
107
108
        toolbar.add(
109
            this.refresh_button,
110
            timeframe,
111
            new Jx.Button({
112
                image: app_path + 'images/start.png',
113
                tooltip: _("Graph start"),
114
                onClick: function() {
115
                    this.options.start = this.startTime;
116
                    this.updateGraph();
117
                }.bind(this)
118
            }),
119
            new Jx.Button({
120
                image: app_path + 'images/previous.png',
121
                tooltip: _("Previous section"),
122
                onClick: function() {
123
                    this.options.start -= this.options.duration;
124
                    this.updateGraph();
125
                }.bind(this)
126
            }),
127
            new Jx.Button({
128
                image: app_path + 'images/next.png',
129
                tooltip: _("Next section"),
130
                onClick: function() {
131
                    this.options.start += this.options.duration;
132
                    this.updateGraph();
133
                }.bind(this)
134
            }),
135
            new Jx.Button({
136
                image: app_path + 'images/end.png',
137
                tooltip: _("Graph end"),
138
                onClick: function() {
139
                    this.options.start = null;
140
                    this.updateGraph();
141
                }.bind(this)
142
            }),
143
            new Jx.Button({
144
                image: app_path + 'images/zoom-in.png',
145
                tooltip: _("Zoom in"),
146
                onClick: function() {
147
                    if (this.options.duration > 1) {
148
                        this.options.duration /= 2;
149
                        this.updateGraph();
150
                    }
151
                }.bind(this)
152
            }),
153
            new Jx.Button({
154
                image: app_path + 'images/zoom-out.png',
155
                tooltip: _("Zoom out"),
156
                onClick: function() {
157
                    this.options.duration *= 2;
158
                    this.updateGraph();
159
                }.bind(this)
160
            }),
161
            this.indicators,
162
            new Jx.Button({
163
                image: app_path + 'images/document-print-small.png',
164
                tooltip: _("Print graph"),
165
                onClick: this.print.bind(this)
166
            })
167
        );
168
169
        var label = _("Graph for \"%(graph)s\" on \"%(host)s\"");
170
        // Le pattern donné à substitute permet de garder une syntaxe
171
        // cohérente avec Python (facilite le travail des traducteurs).
172
        label = label.substitute({
173
                'graph': this.graph,
174
                'host': this.host
175
            }, (/\\?%\(([^()]+)\)s/g));
176
177
        this.graph_window = new Jx.Dialog({
178
            label: label,
179
            modal: false,
180
            move: true,
181
            close: true,
182
            horizontal: this.options.left + ' left',
183
            vertical: this.options.top + ' top',
184
            width: 575,
185
            height: 75,
186
            toolbars: [toolbar]
187
        });
188
189
        function removeDialog() {
190
            window.graphs.erase(this);
191
            this.updateURI();
192
        }
193
194
        this.updateGraph();
195
        this.graph_window.open();
196
        window.graphs.push(this);
197
198
        this.refresh_button.setActive(parseInt(this.options.autoRefresh));
199
200
        this.graph_window.addEvent('close', removeDialog.bind(this));
201
        // sizeChange est déclenché à la fois après un redimensionnement
202
        // et après un déplacement. Ce cas est mal documenté dans JxLib.
203
        this.graph_window.addEvent('sizeChange', this.dialogMoved.bind(this));
204
205
        // Simule un déplacement de la fenêtre,
206
        // pour mettre à jour les coordonnées.
207
        this.dialogMoved();
208
    },
209
210
    dialogMoved: function () {
211
        // Repris de l'API interne de JxLib (création du Drag).
212
        this.options.left = parseInt(this.graph_window.domObj.style.left, 10);
213
        this.options.top = parseInt(this.graph_window.domObj.style.top, 10);
214
        this.updateURI();
215
    },
216
217
    updateURI: function () {
218
        var graphs = [];
219
        var uri = new URI();
220
        uri.set('fragment', '');
221
222
        window.graphs.each(function (graph) {
223
            var props = new Hash(graph.options);
224
            props.extend({host: graph.host, graph: graph.graph});
225
            this.push(props.toQueryString());
226
        }, graphs);
227
228
        uri.setData({'graphs': graphs, safety: 1}, false, 'fragment');
229
        uri.go();
230
    },
231
232 89829224 Francois POIROTTE
    getStartTime: function () {
233
        if (this.options.start == null)
234
            // @TODO: cette heure est en localtime a priori.
235
            return (new Date() / 1000).toInt() - this.options.duration;
236
        return this.options.start;
237
    },
238
239 7c9baa43 Francois POIROTTE
    exportCSV: function (menuItem) {
240
        var uri = new URI(app_path + 'vigirrd/' +
241
            encodeURIComponent(this.host) + '/export');
242
243 89829224 Francois POIROTTE
        var start = this.getStartTime();
244 7c9baa43 Francois POIROTTE
245
        uri.setData({
246
            host: this.host,
247
            graphtemplate: this.graph,
248
            start: start,
249
            end: start + this.options.duration,
250
            nocache: (new Date() / 1)
251
        })
252
253
        if (menuItem.options.indicator)
254
            uri.setData({ds: menuItem.options.label}, true);
255
256
        window.open(uri.toString());
257
    },
258
259 89829224 Francois POIROTTE
    // Cette fonction est aussi utilisée dans print.js
260
    // pour gérer l'impression globale.
261
    getPrintParams: function () {
262
        var img = this.graph_window.content.getElement('img');
263
        var img_uri = new URI(img.src);
264
        var params = img_uri.getData();
265
        return {
266
            host: params.host,
267
            start: params.start,
268
            duration: params.duration,
269
            graph: params.graphtemplate,
270
            nocache: params.nocache
271
        }
272
    },
273
274 7c9baa43 Francois POIROTTE
    print: function () {
275
        var uri = new URI(app_path + 'rpc/graphsList');
276 89829224 Francois POIROTTE
        uri.setData({graphs: [this.getPrintParams()]});
277 7c9baa43 Francois POIROTTE
        var print_window = window.open(uri.toString());
278
        print_window.print();
279
    },
280
281
    updateGraph: function () {
282
        var uri = new URI(app_path + 'vigirrd/' +
283
            encodeURIComponent(this.host) + '/graph.png');
284
285 89829224 Francois POIROTTE
        var start = this.getStartTime();
286 7c9baa43 Francois POIROTTE
287
        uri.setData({
288
            host: this.host,
289
            start: start,
290
            duration: this.options.duration,
291
            graphtemplate: this.graph,
292
            // Permet d'empêcher la mise en cache du graphe.
293
            // Nécessaire car le graphe évolue dynamiquement au fil de l'eau.
294
            nocache: (new Date() / 1)
295
        });
296
        // On génère dynamiquement une balise "img" pour charger le graphe.
297
        this.graph_window.setContent(
298
            '<img src="' + uri.toString() + '"/' + '>');
299
        var img = this.graph_window.content.getElement('img');
300
        img.addEvent('load', function () {
301
            this[0].graph_window.resize(
302
                this[1].width + 25,
303
                this[1].height + 88
304
            );
305
        }.bind([this, img]));
306
        img.addEvent('error', function () {
307
            var msg = _(
308
                'Could not load the graph for "%(graph)s" on "%(host)s".\n' +
309
                'Make sure VigiRRD is running and receives performance data.'
310
            );
311
            // Le pattern donné à substitute permet de garder une syntaxe
312
            // cohérente avec Python (facilite le travail des traducteurs).
313
            msg = msg.substitute({
314
                    'graph': this.graph,
315
                    'host': this.host
316
                }, (/\\?%\(([^()]+)\)s/g));
317
            alert(msg);
318
            this.graph_window.close();
319
        }.bind(this));
320
    }
321
});
322
323
var refresh_delay = 30;
324
var graphs = [];
325
window.addEvent('load', function () {
326
    new Request.JSON({
327
        url: app_path + 'rpc/tempoDelayRefresh',
328
        onSuccess: function (data) {
329
            window.refresh_delay = data.delay;
330
        }
331
    }).get();
332
333
    // On réouvre les graphes précédemment chargés.
334
    var graphs = [];
335
    var uri = new URI();
336
    var qs = new Hash(uri.get('fragment').parseQueryString());
337
    if (qs.has('graphs')) {
338
        graphs = (new Hash(qs.get('graphs'))).getValues();
339
    }
340
341
    graphs.each(function (graph) {
342
        var uri = new URI('?' + graph);
343
        var qs = new Hash(uri.getData());
344
        if (qs.has('host') && qs.has('graph')) {
345
            var options = new Hash();
346
            var params = [
347
                'start',
348
                'duration',
349
                'left',
350
                'top',
351
                'autoRefresh',
352
                'refreshDelay'
353
            ];
354
355
            params.each(function (param) {
356
                if (this[0].has(param))
357
                    this[1].set(param, this[0].get(param));
358
            }, [qs, options]);
359
360
            new Graph(
361
                options.getClean(),
362
                qs.get('host'),
363
                qs.get('graph')
364
            );
365
        }
366
    });
367
368
    // Nécessaire car le constructeur de Graph ajoute les graphes à l'URI.
369
    // On restaure donc l'ancienne URI ici, pour éviter les doublons.
370
    if (graphs.length)
371
        uri.go();
372
});