von-dashboard 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2971 @@
1
+ var Rickshaw = {
2
+
3
+ namespace: function(namespace, obj) {
4
+
5
+ var parts = namespace.split('.');
6
+
7
+ var parent = Rickshaw;
8
+
9
+ for(var i = 1, length = parts.length; i < length; i++) {
10
+ var currentPart = parts[i];
11
+ parent[currentPart] = parent[currentPart] || {};
12
+ parent = parent[currentPart];
13
+ }
14
+ return parent;
15
+ },
16
+
17
+ keys: function(obj) {
18
+ var keys = [];
19
+ for (var key in obj) keys.push(key);
20
+ return keys;
21
+ },
22
+
23
+ extend: function(destination, source) {
24
+
25
+ for (var property in source) {
26
+ destination[property] = source[property];
27
+ }
28
+ return destination;
29
+ },
30
+
31
+ clone: function(obj) {
32
+ return JSON.parse(JSON.stringify(obj));
33
+ }
34
+ };
35
+
36
+ if (typeof module !== 'undefined' && module.exports) {
37
+ var d3 = require('d3');
38
+ module.exports = Rickshaw;
39
+ }
40
+
41
+ /* Adapted from https://github.com/Jakobo/PTClass */
42
+
43
+ /*
44
+ Copyright (c) 2005-2010 Sam Stephenson
45
+
46
+ Permission is hereby granted, free of charge, to any person obtaining a copy
47
+ of this software and associated documentation files (the "Software"), to deal
48
+ in the Software without restriction, including without limitation the rights
49
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
50
+ copies of the Software, and to permit persons to whom the Software is
51
+ furnished to do so, subject to the following conditions:
52
+
53
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
59
+ SOFTWARE.
60
+ */
61
+ /* Based on Alex Arnell's inheritance implementation. */
62
+ /** section: Language
63
+ * class Class
64
+ *
65
+ * Manages Prototype's class-based OOP system.
66
+ *
67
+ * Refer to Prototype's web site for a [tutorial on classes and
68
+ * inheritance](http://prototypejs.org/learn/class-inheritance).
69
+ **/
70
+ (function(globalContext) {
71
+ /* ------------------------------------ */
72
+ /* Import from object.js */
73
+ /* ------------------------------------ */
74
+ var _toString = Object.prototype.toString,
75
+ NULL_TYPE = 'Null',
76
+ UNDEFINED_TYPE = 'Undefined',
77
+ BOOLEAN_TYPE = 'Boolean',
78
+ NUMBER_TYPE = 'Number',
79
+ STRING_TYPE = 'String',
80
+ OBJECT_TYPE = 'Object',
81
+ FUNCTION_CLASS = '[object Function]';
82
+ function isFunction(object) {
83
+ return _toString.call(object) === FUNCTION_CLASS;
84
+ }
85
+ function extend(destination, source) {
86
+ for (var property in source) if (source.hasOwnProperty(property)) // modify protect primitive slaughter
87
+ destination[property] = source[property];
88
+ return destination;
89
+ }
90
+ function keys(object) {
91
+ if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
92
+ var results = [];
93
+ for (var property in object) {
94
+ if (object.hasOwnProperty(property)) {
95
+ results.push(property);
96
+ }
97
+ }
98
+ return results;
99
+ }
100
+ function Type(o) {
101
+ switch(o) {
102
+ case null: return NULL_TYPE;
103
+ case (void 0): return UNDEFINED_TYPE;
104
+ }
105
+ var type = typeof o;
106
+ switch(type) {
107
+ case 'boolean': return BOOLEAN_TYPE;
108
+ case 'number': return NUMBER_TYPE;
109
+ case 'string': return STRING_TYPE;
110
+ }
111
+ return OBJECT_TYPE;
112
+ }
113
+ function isUndefined(object) {
114
+ return typeof object === "undefined";
115
+ }
116
+ /* ------------------------------------ */
117
+ /* Import from Function.js */
118
+ /* ------------------------------------ */
119
+ var slice = Array.prototype.slice;
120
+ function argumentNames(fn) {
121
+ var names = fn.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
122
+ .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
123
+ .replace(/\s+/g, '').split(',');
124
+ return names.length == 1 && !names[0] ? [] : names;
125
+ }
126
+ function wrap(fn, wrapper) {
127
+ var __method = fn;
128
+ return function() {
129
+ var a = update([bind(__method, this)], arguments);
130
+ return wrapper.apply(this, a);
131
+ }
132
+ }
133
+ function update(array, args) {
134
+ var arrayLength = array.length, length = args.length;
135
+ while (length--) array[arrayLength + length] = args[length];
136
+ return array;
137
+ }
138
+ function merge(array, args) {
139
+ array = slice.call(array, 0);
140
+ return update(array, args);
141
+ }
142
+ function bind(fn, context) {
143
+ if (arguments.length < 2 && isUndefined(arguments[0])) return this;
144
+ var __method = fn, args = slice.call(arguments, 2);
145
+ return function() {
146
+ var a = merge(args, arguments);
147
+ return __method.apply(context, a);
148
+ }
149
+ }
150
+
151
+ /* ------------------------------------ */
152
+ /* Import from Prototype.js */
153
+ /* ------------------------------------ */
154
+ var emptyFunction = function(){};
155
+
156
+ var Class = (function() {
157
+
158
+ // Some versions of JScript fail to enumerate over properties, names of which
159
+ // correspond to non-enumerable properties in the prototype chain
160
+ var IS_DONTENUM_BUGGY = (function(){
161
+ for (var p in { toString: 1 }) {
162
+ // check actual property name, so that it works with augmented Object.prototype
163
+ if (p === 'toString') return false;
164
+ }
165
+ return true;
166
+ })();
167
+
168
+ function subclass() {};
169
+ function create() {
170
+ var parent = null, properties = [].slice.apply(arguments);
171
+ if (isFunction(properties[0]))
172
+ parent = properties.shift();
173
+
174
+ function klass() {
175
+ this.initialize.apply(this, arguments);
176
+ }
177
+
178
+ extend(klass, Class.Methods);
179
+ klass.superclass = parent;
180
+ klass.subclasses = [];
181
+
182
+ if (parent) {
183
+ subclass.prototype = parent.prototype;
184
+ klass.prototype = new subclass;
185
+ try { parent.subclasses.push(klass) } catch(e) {}
186
+ }
187
+
188
+ for (var i = 0, length = properties.length; i < length; i++)
189
+ klass.addMethods(properties[i]);
190
+
191
+ if (!klass.prototype.initialize)
192
+ klass.prototype.initialize = emptyFunction;
193
+
194
+ klass.prototype.constructor = klass;
195
+ return klass;
196
+ }
197
+
198
+ function addMethods(source) {
199
+ var ancestor = this.superclass && this.superclass.prototype,
200
+ properties = keys(source);
201
+
202
+ // IE6 doesn't enumerate `toString` and `valueOf` (among other built-in `Object.prototype`) properties,
203
+ // Force copy if they're not Object.prototype ones.
204
+ // Do not copy other Object.prototype.* for performance reasons
205
+ if (IS_DONTENUM_BUGGY) {
206
+ if (source.toString != Object.prototype.toString)
207
+ properties.push("toString");
208
+ if (source.valueOf != Object.prototype.valueOf)
209
+ properties.push("valueOf");
210
+ }
211
+
212
+ for (var i = 0, length = properties.length; i < length; i++) {
213
+ var property = properties[i], value = source[property];
214
+ if (ancestor && isFunction(value) &&
215
+ argumentNames(value)[0] == "$super") {
216
+ var method = value;
217
+ value = wrap((function(m) {
218
+ return function() { return ancestor[m].apply(this, arguments); };
219
+ })(property), method);
220
+
221
+ value.valueOf = bind(method.valueOf, method);
222
+ value.toString = bind(method.toString, method);
223
+ }
224
+ this.prototype[property] = value;
225
+ }
226
+
227
+ return this;
228
+ }
229
+
230
+ return {
231
+ create: create,
232
+ Methods: {
233
+ addMethods: addMethods
234
+ }
235
+ };
236
+ })();
237
+
238
+ if (globalContext.exports) {
239
+ globalContext.exports.Class = Class;
240
+ }
241
+ else {
242
+ globalContext.Class = Class;
243
+ }
244
+ })(Rickshaw);
245
+ Rickshaw.namespace('Rickshaw.Compat.ClassList');
246
+
247
+ Rickshaw.Compat.ClassList = function() {
248
+
249
+ /* adapted from http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
250
+
251
+ if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
252
+
253
+ (function (view) {
254
+
255
+ "use strict";
256
+
257
+ var
258
+ classListProp = "classList"
259
+ , protoProp = "prototype"
260
+ , elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
261
+ , objCtr = Object
262
+ , strTrim = String[protoProp].trim || function () {
263
+ return this.replace(/^\s+|\s+$/g, "");
264
+ }
265
+ , arrIndexOf = Array[protoProp].indexOf || function (item) {
266
+ var
267
+ i = 0
268
+ , len = this.length
269
+ ;
270
+ for (; i < len; i++) {
271
+ if (i in this && this[i] === item) {
272
+ return i;
273
+ }
274
+ }
275
+ return -1;
276
+ }
277
+ // Vendors: please allow content code to instantiate DOMExceptions
278
+ , DOMEx = function (type, message) {
279
+ this.name = type;
280
+ this.code = DOMException[type];
281
+ this.message = message;
282
+ }
283
+ , checkTokenAndGetIndex = function (classList, token) {
284
+ if (token === "") {
285
+ throw new DOMEx(
286
+ "SYNTAX_ERR"
287
+ , "An invalid or illegal string was specified"
288
+ );
289
+ }
290
+ if (/\s/.test(token)) {
291
+ throw new DOMEx(
292
+ "INVALID_CHARACTER_ERR"
293
+ , "String contains an invalid character"
294
+ );
295
+ }
296
+ return arrIndexOf.call(classList, token);
297
+ }
298
+ , ClassList = function (elem) {
299
+ var
300
+ trimmedClasses = strTrim.call(elem.className)
301
+ , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
302
+ , i = 0
303
+ , len = classes.length
304
+ ;
305
+ for (; i < len; i++) {
306
+ this.push(classes[i]);
307
+ }
308
+ this._updateClassName = function () {
309
+ elem.className = this.toString();
310
+ };
311
+ }
312
+ , classListProto = ClassList[protoProp] = []
313
+ , classListGetter = function () {
314
+ return new ClassList(this);
315
+ }
316
+ ;
317
+ // Most DOMException implementations don't allow calling DOMException's toString()
318
+ // on non-DOMExceptions. Error's toString() is sufficient here.
319
+ DOMEx[protoProp] = Error[protoProp];
320
+ classListProto.item = function (i) {
321
+ return this[i] || null;
322
+ };
323
+ classListProto.contains = function (token) {
324
+ token += "";
325
+ return checkTokenAndGetIndex(this, token) !== -1;
326
+ };
327
+ classListProto.add = function (token) {
328
+ token += "";
329
+ if (checkTokenAndGetIndex(this, token) === -1) {
330
+ this.push(token);
331
+ this._updateClassName();
332
+ }
333
+ };
334
+ classListProto.remove = function (token) {
335
+ token += "";
336
+ var index = checkTokenAndGetIndex(this, token);
337
+ if (index !== -1) {
338
+ this.splice(index, 1);
339
+ this._updateClassName();
340
+ }
341
+ };
342
+ classListProto.toggle = function (token) {
343
+ token += "";
344
+ if (checkTokenAndGetIndex(this, token) === -1) {
345
+ this.add(token);
346
+ } else {
347
+ this.remove(token);
348
+ }
349
+ };
350
+ classListProto.toString = function () {
351
+ return this.join(" ");
352
+ };
353
+
354
+ if (objCtr.defineProperty) {
355
+ var classListPropDesc = {
356
+ get: classListGetter
357
+ , enumerable: true
358
+ , configurable: true
359
+ };
360
+ try {
361
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
362
+ } catch (ex) { // IE 8 doesn't support enumerable:true
363
+ if (ex.number === -0x7FF5EC54) {
364
+ classListPropDesc.enumerable = false;
365
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
366
+ }
367
+ }
368
+ } else if (objCtr[protoProp].__defineGetter__) {
369
+ elemCtrProto.__defineGetter__(classListProp, classListGetter);
370
+ }
371
+
372
+ }(window));
373
+
374
+ }
375
+ };
376
+
377
+ if ( (typeof RICKSHAW_NO_COMPAT !== "undefined" && !RICKSHAW_NO_COMPAT) || typeof RICKSHAW_NO_COMPAT === "undefined") {
378
+ new Rickshaw.Compat.ClassList();
379
+ }
380
+ Rickshaw.namespace('Rickshaw.Graph');
381
+
382
+ Rickshaw.Graph = function(args) {
383
+
384
+ if (!args.element) throw "Rickshaw.Graph needs a reference to an element";
385
+
386
+ this.element = args.element;
387
+ this.series = args.series;
388
+
389
+ this.defaults = {
390
+ interpolation: 'cardinal',
391
+ offset: 'zero',
392
+ min: undefined,
393
+ max: undefined,
394
+ preserve: false
395
+ };
396
+
397
+ Rickshaw.keys(this.defaults).forEach( function(k) {
398
+ this[k] = args[k] || this.defaults[k];
399
+ }, this );
400
+
401
+ this.window = {};
402
+
403
+ this.updateCallbacks = [];
404
+
405
+ var self = this;
406
+
407
+ this.initialize = function(args) {
408
+
409
+ this.validateSeries(args.series);
410
+
411
+ this.series.active = function() { return self.series.filter( function(s) { return !s.disabled } ) };
412
+
413
+ this.setSize({ width: args.width, height: args.height });
414
+
415
+ this.element.classList.add('rickshaw_graph');
416
+ this.vis = d3.select(this.element)
417
+ .append("svg:svg")
418
+ .attr('width', this.width)
419
+ .attr('height', this.height);
420
+
421
+ var renderers = [
422
+ Rickshaw.Graph.Renderer.Stack,
423
+ Rickshaw.Graph.Renderer.Line,
424
+ Rickshaw.Graph.Renderer.Bar,
425
+ Rickshaw.Graph.Renderer.Area,
426
+ Rickshaw.Graph.Renderer.ScatterPlot
427
+ ];
428
+
429
+ renderers.forEach( function(r) {
430
+ if (!r) return;
431
+ self.registerRenderer(new r( { graph: self } ));
432
+ } );
433
+
434
+ this.setRenderer(args.renderer || 'stack', args);
435
+ this.discoverRange();
436
+ };
437
+
438
+ this.validateSeries = function(series) {
439
+
440
+ if (!Array.isArray(series) && !(series instanceof Rickshaw.Series)) {
441
+ var seriesSignature = Object.prototype.toString.apply(series);
442
+ throw "series is not an array: " + seriesSignature;
443
+ }
444
+
445
+ var pointsCount;
446
+
447
+ series.forEach( function(s) {
448
+
449
+ if (!(s instanceof Object)) {
450
+ throw "series element is not an object: " + s;
451
+ }
452
+ if (!(s.data)) {
453
+ throw "series has no data: " + JSON.stringify(s);
454
+ }
455
+ if (!Array.isArray(s.data)) {
456
+ throw "series data is not an array: " + JSON.stringify(s.data);
457
+ }
458
+
459
+ var x = s.data[0].x;
460
+ var y = s.data[0].y;
461
+
462
+ if (typeof x != 'number' || ( typeof y != 'number' && y !== null ) ) {
463
+ throw "x and y properties of points should be numbers instead of " +
464
+ (typeof x) + " and " + (typeof y);
465
+ }
466
+
467
+ }, this );
468
+ };
469
+
470
+ this.dataDomain = function() {
471
+
472
+ // take from the first series
473
+ var data = this.series[0].data;
474
+
475
+ return [ data[0].x, data.slice(-1).shift().x ];
476
+
477
+ };
478
+
479
+ this.discoverRange = function() {
480
+
481
+ var domain = this.renderer.domain();
482
+
483
+ this.x = d3.scale.linear().domain(domain.x).range([0, this.width]);
484
+
485
+ this.y = d3.scale.linear().domain(domain.y).range([this.height, 0]);
486
+
487
+ this.y.magnitude = d3.scale.linear()
488
+ .domain([domain.y[0] - domain.y[0], domain.y[1] - domain.y[0]])
489
+ .range([0, this.height]);
490
+ };
491
+
492
+ this.render = function() {
493
+
494
+ var stackedData = this.stackData();
495
+ this.discoverRange();
496
+
497
+ this.renderer.render();
498
+
499
+ this.updateCallbacks.forEach( function(callback) {
500
+ callback();
501
+ } );
502
+ };
503
+
504
+ this.update = this.render;
505
+
506
+ this.stackData = function() {
507
+
508
+ var data = this.series.active()
509
+ .map( function(d) { return d.data } )
510
+ .map( function(d) { return d.filter( function(d) { return this._slice(d) }, this ) }, this);
511
+
512
+ var preserve = this.preserve;
513
+ if (!preserve) {
514
+ this.series.forEach( function(series) {
515
+ if (series.scale) {
516
+ // data must be preserved when a scale is used
517
+ preserve = true;
518
+ }
519
+ } );
520
+ }
521
+
522
+ data = preserve ? Rickshaw.clone(data) : data;
523
+
524
+ this.series.forEach( function(series, index) {
525
+ if (series.scale) {
526
+ // apply scale to each series
527
+ var seriesData = data[index];
528
+ seriesData.forEach( function(d) {
529
+ d.y = series.scale(d.y);
530
+ } );
531
+ }
532
+ } );
533
+
534
+ this.stackData.hooks.data.forEach( function(entry) {
535
+ data = entry.f.apply(self, [data]);
536
+ } );
537
+
538
+ var stackedData;
539
+
540
+ if (!this.renderer.unstack) {
541
+
542
+ this._validateStackable();
543
+
544
+ var layout = d3.layout.stack();
545
+ layout.offset( self.offset );
546
+ stackedData = layout(data);
547
+ }
548
+
549
+ stackedData = stackedData || data;
550
+
551
+ this.stackData.hooks.after.forEach( function(entry) {
552
+ stackedData = entry.f.apply(self, [data]);
553
+ } );
554
+
555
+ this.series.forEach( function(series, index) {
556
+ if (series.disabled) return;
557
+ series.stack = stackedData[index];
558
+ } );
559
+
560
+ this.stackedData = stackedData;
561
+ return stackedData;
562
+ };
563
+
564
+ this._validateStackable = function() {
565
+
566
+ var series = this.series;
567
+ var pointsCount;
568
+
569
+ series.forEach( function(s) {
570
+
571
+ pointsCount = pointsCount || s.data.length;
572
+
573
+ if (pointsCount && s.data.length != pointsCount) {
574
+ throw "stacked series cannot have differing numbers of points: " +
575
+ pointsCount + " vs " + s.data.length + "; see Rickshaw.Series.fill()";
576
+ }
577
+
578
+ }, this );
579
+ };
580
+
581
+ this.stackData.hooks = { data: [], after: [] };
582
+
583
+ this._slice = function(d) {
584
+
585
+ if (this.window.xMin || this.window.xMax) {
586
+
587
+ var isInRange = true;
588
+
589
+ if (this.window.xMin && d.x < this.window.xMin) isInRange = false;
590
+ if (this.window.xMax && d.x > this.window.xMax) isInRange = false;
591
+
592
+ return isInRange;
593
+ }
594
+
595
+ return true;
596
+ };
597
+
598
+ this.onUpdate = function(callback) {
599
+ this.updateCallbacks.push(callback);
600
+ };
601
+
602
+ this.registerRenderer = function(renderer) {
603
+ this._renderers = this._renderers || {};
604
+ this._renderers[renderer.name] = renderer;
605
+ };
606
+
607
+ this.configure = function(args) {
608
+
609
+ if (args.width || args.height) {
610
+ this.setSize(args);
611
+ }
612
+
613
+ Rickshaw.keys(this.defaults).forEach( function(k) {
614
+ this[k] = k in args ? args[k]
615
+ : k in this ? this[k]
616
+ : this.defaults[k];
617
+ }, this );
618
+
619
+ this.setRenderer(args.renderer || this.renderer.name, args);
620
+ };
621
+
622
+ this.setRenderer = function(r, args) {
623
+ if (typeof r == 'function') {
624
+ this.renderer = new r( { graph: self } );
625
+ this.registerRenderer(this.renderer);
626
+ } else {
627
+ if (!this._renderers[r]) {
628
+ throw "couldn't find renderer " + r;
629
+ }
630
+ this.renderer = this._renderers[r];
631
+ }
632
+
633
+ if (typeof args == 'object') {
634
+ this.renderer.configure(args);
635
+ }
636
+ };
637
+
638
+ this.setSize = function(args) {
639
+
640
+ args = args || {};
641
+
642
+ if (typeof window !== undefined) {
643
+ var style = window.getComputedStyle(this.element, null);
644
+ var elementWidth = parseInt(style.getPropertyValue('width'), 10);
645
+ var elementHeight = parseInt(style.getPropertyValue('height'), 10);
646
+ }
647
+
648
+ this.width = args.width || elementWidth || 400;
649
+ this.height = args.height || elementHeight || 250;
650
+
651
+ this.vis && this.vis
652
+ .attr('width', this.width)
653
+ .attr('height', this.height);
654
+ };
655
+
656
+ this.initialize(args);
657
+ };
658
+ Rickshaw.namespace('Rickshaw.Fixtures.Color');
659
+
660
+ Rickshaw.Fixtures.Color = function() {
661
+
662
+ this.schemes = {};
663
+
664
+ this.schemes.spectrum14 = [
665
+ '#ecb796',
666
+ '#dc8f70',
667
+ '#b2a470',
668
+ '#92875a',
669
+ '#716c49',
670
+ '#d2ed82',
671
+ '#bbe468',
672
+ '#a1d05d',
673
+ '#e7cbe6',
674
+ '#d8aad6',
675
+ '#a888c2',
676
+ '#9dc2d3',
677
+ '#649eb9',
678
+ '#387aa3'
679
+ ].reverse();
680
+
681
+ this.schemes.spectrum2000 = [
682
+ '#57306f',
683
+ '#514c76',
684
+ '#646583',
685
+ '#738394',
686
+ '#6b9c7d',
687
+ '#84b665',
688
+ '#a7ca50',
689
+ '#bfe746',
690
+ '#e2f528',
691
+ '#fff726',
692
+ '#ecdd00',
693
+ '#d4b11d',
694
+ '#de8800',
695
+ '#de4800',
696
+ '#c91515',
697
+ '#9a0000',
698
+ '#7b0429',
699
+ '#580839',
700
+ '#31082b'
701
+ ];
702
+
703
+ this.schemes.spectrum2001 = [
704
+ '#2f243f',
705
+ '#3c2c55',
706
+ '#4a3768',
707
+ '#565270',
708
+ '#6b6b7c',
709
+ '#72957f',
710
+ '#86ad6e',
711
+ '#a1bc5e',
712
+ '#b8d954',
713
+ '#d3e04e',
714
+ '#ccad2a',
715
+ '#cc8412',
716
+ '#c1521d',
717
+ '#ad3821',
718
+ '#8a1010',
719
+ '#681717',
720
+ '#531e1e',
721
+ '#3d1818',
722
+ '#320a1b'
723
+ ];
724
+
725
+ this.schemes.classic9 = [
726
+ '#423d4f',
727
+ '#4a6860',
728
+ '#848f39',
729
+ '#a2b73c',
730
+ '#ddcb53',
731
+ '#c5a32f',
732
+ '#7d5836',
733
+ '#963b20',
734
+ '#7c2626',
735
+ '#491d37',
736
+ '#2f254a'
737
+ ].reverse();
738
+
739
+ this.schemes.httpStatus = {
740
+ 503: '#ea5029',
741
+ 502: '#d23f14',
742
+ 500: '#bf3613',
743
+ 410: '#efacea',
744
+ 409: '#e291dc',
745
+ 403: '#f457e8',
746
+ 408: '#e121d2',
747
+ 401: '#b92dae',
748
+ 405: '#f47ceb',
749
+ 404: '#a82a9f',
750
+ 400: '#b263c6',
751
+ 301: '#6fa024',
752
+ 302: '#87c32b',
753
+ 307: '#a0d84c',
754
+ 304: '#28b55c',
755
+ 200: '#1a4f74',
756
+ 206: '#27839f',
757
+ 201: '#52adc9',
758
+ 202: '#7c979f',
759
+ 203: '#a5b8bd',
760
+ 204: '#c1cdd1'
761
+ };
762
+
763
+ this.schemes.colorwheel = [
764
+ '#b5b6a9',
765
+ '#858772',
766
+ '#785f43',
767
+ '#96557e',
768
+ '#4682b4',
769
+ '#65b9ac',
770
+ '#73c03a',
771
+ '#cb513a'
772
+ ].reverse();
773
+
774
+ this.schemes.cool = [
775
+ '#5e9d2f',
776
+ '#73c03a',
777
+ '#4682b4',
778
+ '#7bc3b8',
779
+ '#a9884e',
780
+ '#c1b266',
781
+ '#a47493',
782
+ '#c09fb5'
783
+ ];
784
+
785
+ this.schemes.munin = [
786
+ '#00cc00',
787
+ '#0066b3',
788
+ '#ff8000',
789
+ '#ffcc00',
790
+ '#330099',
791
+ '#990099',
792
+ '#ccff00',
793
+ '#ff0000',
794
+ '#808080',
795
+ '#008f00',
796
+ '#00487d',
797
+ '#b35a00',
798
+ '#b38f00',
799
+ '#6b006b',
800
+ '#8fb300',
801
+ '#b30000',
802
+ '#bebebe',
803
+ '#80ff80',
804
+ '#80c9ff',
805
+ '#ffc080',
806
+ '#ffe680',
807
+ '#aa80ff',
808
+ '#ee00cc',
809
+ '#ff8080',
810
+ '#666600',
811
+ '#ffbfff',
812
+ '#00ffcc',
813
+ '#cc6699',
814
+ '#999900'
815
+ ];
816
+ };
817
+ Rickshaw.namespace('Rickshaw.Fixtures.RandomData');
818
+
819
+ Rickshaw.Fixtures.RandomData = function(timeInterval) {
820
+
821
+ var addData;
822
+ timeInterval = timeInterval || 1;
823
+
824
+ var lastRandomValue = 200;
825
+
826
+ var timeBase = Math.floor(new Date().getTime() / 1000);
827
+
828
+ this.addData = function(data) {
829
+
830
+ var randomValue = Math.random() * 100 + 15 + lastRandomValue;
831
+ var index = data[0].length;
832
+
833
+ var counter = 1;
834
+
835
+ data.forEach( function(series) {
836
+ var randomVariance = Math.random() * 20;
837
+ var v = randomValue / 25 + counter++ +
838
+ (Math.cos((index * counter * 11) / 960) + 2) * 15 +
839
+ (Math.cos(index / 7) + 2) * 7 +
840
+ (Math.cos(index / 17) + 2) * 1;
841
+
842
+ series.push( { x: (index * timeInterval) + timeBase, y: v + randomVariance } );
843
+ } );
844
+
845
+ lastRandomValue = randomValue * 0.85;
846
+ };
847
+ };
848
+
849
+ Rickshaw.namespace('Rickshaw.Fixtures.Time');
850
+
851
+ Rickshaw.Fixtures.Time = function() {
852
+
853
+ var tzOffset = new Date().getTimezoneOffset() * 60;
854
+
855
+ var self = this;
856
+
857
+ this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
858
+
859
+ this.units = [
860
+ {
861
+ name: 'decade',
862
+ seconds: 86400 * 365.25 * 10,
863
+ formatter: function(d) { return (parseInt(d.getUTCFullYear() / 10, 10) * 10) }
864
+ }, {
865
+ name: 'year',
866
+ seconds: 86400 * 365.25,
867
+ formatter: function(d) { return d.getUTCFullYear() }
868
+ }, {
869
+ name: 'month',
870
+ seconds: 86400 * 30.5,
871
+ formatter: function(d) { return self.months[d.getUTCMonth()] }
872
+ }, {
873
+ name: 'week',
874
+ seconds: 86400 * 7,
875
+ formatter: function(d) { return self.formatDate(d) }
876
+ }, {
877
+ name: 'day',
878
+ seconds: 86400,
879
+ formatter: function(d) { return d.getUTCDate() }
880
+ }, {
881
+ name: '6 hour',
882
+ seconds: 3600 * 6,
883
+ formatter: function(d) { return self.formatTime(d) }
884
+ }, {
885
+ name: 'hour',
886
+ seconds: 3600,
887
+ formatter: function(d) { return self.formatTime(d) }
888
+ }, {
889
+ name: '15 minute',
890
+ seconds: 60 * 15,
891
+ formatter: function(d) { return self.formatTime(d) }
892
+ }, {
893
+ name: 'minute',
894
+ seconds: 60,
895
+ formatter: function(d) { return d.getUTCMinutes() }
896
+ }, {
897
+ name: '15 second',
898
+ seconds: 15,
899
+ formatter: function(d) { return d.getUTCSeconds() + 's' }
900
+ }, {
901
+ name: 'second',
902
+ seconds: 1,
903
+ formatter: function(d) { return d.getUTCSeconds() + 's' }
904
+ }
905
+ ];
906
+
907
+ this.unit = function(unitName) {
908
+ return this.units.filter( function(unit) { return unitName == unit.name } ).shift();
909
+ };
910
+
911
+ this.formatDate = function(d) {
912
+ return d.toUTCString().match(/, (\w+ \w+ \w+)/)[1];
913
+ };
914
+
915
+ this.formatTime = function(d) {
916
+ return d.toUTCString().match(/(\d+:\d+):/)[1];
917
+ };
918
+
919
+ this.ceil = function(time, unit) {
920
+
921
+ var nearFuture;
922
+ var rounded;
923
+
924
+ if (unit.name == 'month') {
925
+
926
+ nearFuture = new Date((time + unit.seconds - 1) * 1000);
927
+
928
+ rounded = new Date(0);
929
+ rounded.setUTCFullYear(nearFuture.getUTCFullYear());
930
+ rounded.setUTCMonth(nearFuture.getUTCMonth());
931
+ rounded.setUTCDate(1);
932
+ rounded.setUTCHours(0);
933
+ rounded.setUTCMinutes(0);
934
+ rounded.setUTCSeconds(0);
935
+ rounded.setUTCMilliseconds(0);
936
+
937
+ return rounded.getTime() / 1000;
938
+ }
939
+
940
+ if (unit.name == 'year') {
941
+
942
+ nearFuture = new Date((time + unit.seconds - 1) * 1000);
943
+
944
+ rounded = new Date(0);
945
+ rounded.setUTCFullYear(nearFuture.getUTCFullYear());
946
+ rounded.setUTCMonth(0);
947
+ rounded.setUTCDate(1);
948
+ rounded.setUTCHours(0);
949
+ rounded.setUTCMinutes(0);
950
+ rounded.setUTCSeconds(0);
951
+ rounded.setUTCMilliseconds(0);
952
+
953
+ return rounded.getTime() / 1000;
954
+ }
955
+
956
+ return Math.ceil(time / unit.seconds) * unit.seconds;
957
+ };
958
+ };
959
+ Rickshaw.namespace('Rickshaw.Fixtures.Number');
960
+
961
+ Rickshaw.Fixtures.Number.formatKMBT = function(y) {
962
+ var abs_y = Math.abs(y);
963
+ if (abs_y >= 1000000000000) { return y / 1000000000000 + "T" }
964
+ else if (abs_y >= 1000000000) { return y / 1000000000 + "B" }
965
+ else if (abs_y >= 1000000) { return y / 1000000 + "M" }
966
+ else if (abs_y >= 1000) { return y / 1000 + "K" }
967
+ else if (abs_y < 1 && y > 0) { return y.toFixed(2) }
968
+ else if (abs_y === 0) { return '' }
969
+ else { return y }
970
+ };
971
+
972
+ Rickshaw.Fixtures.Number.formatBase1024KMGTP = function(y) {
973
+ var abs_y = Math.abs(y);
974
+ if (abs_y >= 1125899906842624) { return y / 1125899906842624 + "P" }
975
+ else if (abs_y >= 1099511627776){ return y / 1099511627776 + "T" }
976
+ else if (abs_y >= 1073741824) { return y / 1073741824 + "G" }
977
+ else if (abs_y >= 1048576) { return y / 1048576 + "M" }
978
+ else if (abs_y >= 1024) { return y / 1024 + "K" }
979
+ else if (abs_y < 1 && y > 0) { return y.toFixed(2) }
980
+ else if (abs_y === 0) { return '' }
981
+ else { return y }
982
+ };
983
+ Rickshaw.namespace("Rickshaw.Color.Palette");
984
+
985
+ Rickshaw.Color.Palette = function(args) {
986
+
987
+ var color = new Rickshaw.Fixtures.Color();
988
+
989
+ args = args || {};
990
+ this.schemes = {};
991
+
992
+ this.scheme = color.schemes[args.scheme] || args.scheme || color.schemes.colorwheel;
993
+ this.runningIndex = 0;
994
+ this.generatorIndex = 0;
995
+
996
+ if (args.interpolatedStopCount) {
997
+ var schemeCount = this.scheme.length - 1;
998
+ var i, j, scheme = [];
999
+ for (i = 0; i < schemeCount; i++) {
1000
+ scheme.push(this.scheme[i]);
1001
+ var generator = d3.interpolateHsl(this.scheme[i], this.scheme[i + 1]);
1002
+ for (j = 1; j < args.interpolatedStopCount; j++) {
1003
+ scheme.push(generator((1 / args.interpolatedStopCount) * j));
1004
+ }
1005
+ }
1006
+ scheme.push(this.scheme[this.scheme.length - 1]);
1007
+ this.scheme = scheme;
1008
+ }
1009
+ this.rotateCount = this.scheme.length;
1010
+
1011
+ this.color = function(key) {
1012
+ return this.scheme[key] || this.scheme[this.runningIndex++] || this.interpolateColor() || '#808080';
1013
+ };
1014
+
1015
+ this.interpolateColor = function() {
1016
+ if (!Array.isArray(this.scheme)) return;
1017
+ var color;
1018
+ if (this.generatorIndex == this.rotateCount * 2 - 1) {
1019
+ color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[0])(0.5);
1020
+ this.generatorIndex = 0;
1021
+ this.rotateCount *= 2;
1022
+ } else {
1023
+ color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[this.generatorIndex + 1])(0.5);
1024
+ this.generatorIndex++;
1025
+ }
1026
+ this.scheme.push(color);
1027
+ return color;
1028
+ };
1029
+
1030
+ };
1031
+ Rickshaw.namespace('Rickshaw.Graph.Ajax');
1032
+
1033
+ Rickshaw.Graph.Ajax = Rickshaw.Class.create( {
1034
+
1035
+ initialize: function(args) {
1036
+
1037
+ this.dataURL = args.dataURL;
1038
+
1039
+ this.onData = args.onData || function(d) { return d };
1040
+ this.onComplete = args.onComplete || function() {};
1041
+ this.onError = args.onError || function() {};
1042
+
1043
+ this.args = args; // pass through to Rickshaw.Graph
1044
+
1045
+ this.request();
1046
+ },
1047
+
1048
+ request: function() {
1049
+
1050
+ $.ajax( {
1051
+ url: this.dataURL,
1052
+ dataType: 'json',
1053
+ success: this.success.bind(this),
1054
+ error: this.error.bind(this)
1055
+ } );
1056
+ },
1057
+
1058
+ error: function() {
1059
+
1060
+ console.log("error loading dataURL: " + this.dataURL);
1061
+ this.onError(this);
1062
+ },
1063
+
1064
+ success: function(data, status) {
1065
+
1066
+ data = this.onData(data);
1067
+ this.args.series = this._splice({ data: data, series: this.args.series });
1068
+
1069
+ this.graph = this.graph || new Rickshaw.Graph(this.args);
1070
+ this.graph.render();
1071
+
1072
+ this.onComplete(this);
1073
+ },
1074
+
1075
+ _splice: function(args) {
1076
+
1077
+ var data = args.data;
1078
+ var series = args.series;
1079
+
1080
+ if (!args.series) return data;
1081
+
1082
+ series.forEach( function(s) {
1083
+
1084
+ var seriesKey = s.key || s.name;
1085
+ if (!seriesKey) throw "series needs a key or a name";
1086
+
1087
+ data.forEach( function(d) {
1088
+
1089
+ var dataKey = d.key || d.name;
1090
+ if (!dataKey) throw "data needs a key or a name";
1091
+
1092
+ if (seriesKey == dataKey) {
1093
+ var properties = ['color', 'name', 'data'];
1094
+ properties.forEach( function(p) {
1095
+ if (d[p]) s[p] = d[p];
1096
+ } );
1097
+ }
1098
+ } );
1099
+ } );
1100
+
1101
+ return series;
1102
+ }
1103
+ } );
1104
+
1105
+ Rickshaw.namespace('Rickshaw.Graph.Annotate');
1106
+
1107
+ Rickshaw.Graph.Annotate = function(args) {
1108
+
1109
+ var graph = this.graph = args.graph;
1110
+ this.elements = { timeline: args.element };
1111
+
1112
+ var self = this;
1113
+
1114
+ this.data = {};
1115
+
1116
+ this.elements.timeline.classList.add('rickshaw_annotation_timeline');
1117
+
1118
+ this.add = function(time, content, end_time) {
1119
+ self.data[time] = self.data[time] || {'boxes': []};
1120
+ self.data[time].boxes.push({content: content, end: end_time});
1121
+ };
1122
+
1123
+ this.update = function() {
1124
+
1125
+ Rickshaw.keys(self.data).forEach( function(time) {
1126
+
1127
+ var annotation = self.data[time];
1128
+ var left = self.graph.x(time);
1129
+
1130
+ if (left < 0 || left > self.graph.x.range()[1]) {
1131
+ if (annotation.element) {
1132
+ annotation.line.classList.add('offscreen');
1133
+ annotation.element.style.display = 'none';
1134
+ }
1135
+
1136
+ annotation.boxes.forEach( function(box) {
1137
+ if ( box.rangeElement ) box.rangeElement.classList.add('offscreen');
1138
+ });
1139
+
1140
+ return;
1141
+ }
1142
+
1143
+ if (!annotation.element) {
1144
+ var element = annotation.element = document.createElement('div');
1145
+ element.classList.add('annotation');
1146
+ this.elements.timeline.appendChild(element);
1147
+ element.addEventListener('click', function(e) {
1148
+ element.classList.toggle('active');
1149
+ annotation.line.classList.toggle('active');
1150
+ annotation.boxes.forEach( function(box) {
1151
+ if ( box.rangeElement ) box.rangeElement.classList.toggle('active');
1152
+ });
1153
+ }, false);
1154
+
1155
+ }
1156
+
1157
+ annotation.element.style.left = left + 'px';
1158
+ annotation.element.style.display = 'block';
1159
+
1160
+ annotation.boxes.forEach( function(box) {
1161
+
1162
+
1163
+ var element = box.element;
1164
+
1165
+ if (!element) {
1166
+ element = box.element = document.createElement('div');
1167
+ element.classList.add('content');
1168
+ element.innerHTML = box.content;
1169
+ annotation.element.appendChild(element);
1170
+
1171
+ annotation.line = document.createElement('div');
1172
+ annotation.line.classList.add('annotation_line');
1173
+ self.graph.element.appendChild(annotation.line);
1174
+
1175
+ if ( box.end ) {
1176
+ box.rangeElement = document.createElement('div');
1177
+ box.rangeElement.classList.add('annotation_range');
1178
+ self.graph.element.appendChild(box.rangeElement);
1179
+ }
1180
+
1181
+ }
1182
+
1183
+ if ( box.end ) {
1184
+
1185
+ var annotationRangeStart = left;
1186
+ var annotationRangeEnd = Math.min( self.graph.x(box.end), self.graph.x.range()[1] );
1187
+
1188
+ // annotation makes more sense at end
1189
+ if ( annotationRangeStart > annotationRangeEnd ) {
1190
+ annotationRangeEnd = left;
1191
+ annotationRangeStart = Math.max( self.graph.x(box.end), self.graph.x.range()[0] );
1192
+ }
1193
+
1194
+ var annotationRangeWidth = annotationRangeEnd - annotationRangeStart;
1195
+
1196
+ box.rangeElement.style.left = annotationRangeStart + 'px';
1197
+ box.rangeElement.style.width = annotationRangeWidth + 'px';
1198
+
1199
+ box.rangeElement.classList.remove('offscreen');
1200
+ }
1201
+
1202
+ annotation.line.classList.remove('offscreen');
1203
+ annotation.line.style.left = left + 'px';
1204
+ } );
1205
+ }, this );
1206
+ };
1207
+
1208
+ this.graph.onUpdate( function() { self.update() } );
1209
+ };
1210
+ Rickshaw.namespace('Rickshaw.Graph.Axis.Time');
1211
+
1212
+ Rickshaw.Graph.Axis.Time = function(args) {
1213
+
1214
+ var self = this;
1215
+
1216
+ this.graph = args.graph;
1217
+ this.elements = [];
1218
+ this.ticksTreatment = args.ticksTreatment || 'plain';
1219
+ this.fixedTimeUnit = args.timeUnit;
1220
+
1221
+ var time = new Rickshaw.Fixtures.Time();
1222
+
1223
+ this.appropriateTimeUnit = function() {
1224
+
1225
+ var unit;
1226
+ var units = time.units;
1227
+
1228
+ var domain = this.graph.x.domain();
1229
+ var rangeSeconds = domain[1] - domain[0];
1230
+
1231
+ units.forEach( function(u) {
1232
+ if (Math.floor(rangeSeconds / u.seconds) >= 2) {
1233
+ unit = unit || u;
1234
+ }
1235
+ } );
1236
+
1237
+ return (unit || time.units[time.units.length - 1]);
1238
+ };
1239
+
1240
+ this.tickOffsets = function() {
1241
+
1242
+ var domain = this.graph.x.domain();
1243
+
1244
+ var unit = this.fixedTimeUnit || this.appropriateTimeUnit();
1245
+ var count = Math.ceil((domain[1] - domain[0]) / unit.seconds);
1246
+
1247
+ var runningTick = domain[0];
1248
+
1249
+ var offsets = [];
1250
+
1251
+ for (var i = 0; i < count; i++) {
1252
+
1253
+ var tickValue = time.ceil(runningTick, unit);
1254
+ runningTick = tickValue + unit.seconds / 2;
1255
+
1256
+ offsets.push( { value: tickValue, unit: unit } );
1257
+ }
1258
+
1259
+ return offsets;
1260
+ };
1261
+
1262
+ this.render = function() {
1263
+
1264
+ this.elements.forEach( function(e) {
1265
+ e.parentNode.removeChild(e);
1266
+ } );
1267
+
1268
+ this.elements = [];
1269
+
1270
+ var offsets = this.tickOffsets();
1271
+
1272
+ offsets.forEach( function(o) {
1273
+
1274
+ if (self.graph.x(o.value) > self.graph.x.range()[1]) return;
1275
+
1276
+ var element = document.createElement('div');
1277
+ element.style.left = self.graph.x(o.value) + 'px';
1278
+ element.classList.add('x_tick');
1279
+ element.classList.add(self.ticksTreatment);
1280
+
1281
+ var title = document.createElement('div');
1282
+ title.classList.add('title');
1283
+ title.innerHTML = o.unit.formatter(new Date(o.value * 1000));
1284
+ element.appendChild(title);
1285
+
1286
+ self.graph.element.appendChild(element);
1287
+ self.elements.push(element);
1288
+
1289
+ } );
1290
+ };
1291
+
1292
+ this.graph.onUpdate( function() { self.render() } );
1293
+ };
1294
+
1295
+ Rickshaw.namespace('Rickshaw.Graph.Axis.X');
1296
+
1297
+ Rickshaw.Graph.Axis.X = function(args) {
1298
+
1299
+ var self = this;
1300
+ var berthRate = 0.10;
1301
+
1302
+ this.initialize = function(args) {
1303
+
1304
+ this.graph = args.graph;
1305
+ this.orientation = args.orientation || 'top';
1306
+
1307
+ var pixelsPerTick = args.pixelsPerTick || 75;
1308
+ this.ticks = args.ticks || Math.floor(this.graph.width / pixelsPerTick);
1309
+ this.tickSize = args.tickSize || 4;
1310
+ this.ticksTreatment = args.ticksTreatment || 'plain';
1311
+
1312
+ if (args.element) {
1313
+
1314
+ this.element = args.element;
1315
+ this._discoverSize(args.element, args);
1316
+
1317
+ this.vis = d3.select(args.element)
1318
+ .append("svg:svg")
1319
+ .attr('height', this.height)
1320
+ .attr('width', this.width)
1321
+ .attr('class', 'rickshaw_graph x_axis_d3');
1322
+
1323
+ this.element = this.vis[0][0];
1324
+ this.element.style.position = 'relative';
1325
+
1326
+ this.setSize({ width: args.width, height: args.height });
1327
+
1328
+ } else {
1329
+ this.vis = this.graph.vis;
1330
+ }
1331
+
1332
+ this.graph.onUpdate( function() { self.render() } );
1333
+ };
1334
+
1335
+ this.setSize = function(args) {
1336
+
1337
+ args = args || {};
1338
+ if (!this.element) return;
1339
+
1340
+ this._discoverSize(this.element.parentNode, args);
1341
+
1342
+ this.vis
1343
+ .attr('height', this.height)
1344
+ .attr('width', this.width * (1 + berthRate));
1345
+
1346
+ var berth = Math.floor(this.width * berthRate / 2);
1347
+ this.element.style.left = -1 * berth + 'px';
1348
+ };
1349
+
1350
+ this.render = function() {
1351
+
1352
+ if (this.graph.width !== this._renderWidth) this.setSize({ auto: true });
1353
+
1354
+ var axis = d3.svg.axis().scale(this.graph.x).orient(this.orientation);
1355
+ axis.tickFormat( args.tickFormat || function(x) { return x } );
1356
+
1357
+ var berth = Math.floor(this.width * berthRate / 2) || 0;
1358
+ var transform;
1359
+
1360
+ if (this.orientation == 'top') {
1361
+ var yOffset = this.height || this.graph.height;
1362
+ transform = 'translate(' + berth + ',' + yOffset + ')';
1363
+ } else {
1364
+ transform = 'translate(' + berth + ', 0)';
1365
+ }
1366
+
1367
+ if (this.element) {
1368
+ this.vis.selectAll('*').remove();
1369
+ }
1370
+
1371
+ this.vis
1372
+ .append("svg:g")
1373
+ .attr("class", ["x_ticks_d3", this.ticksTreatment].join(" "))
1374
+ .attr("transform", transform)
1375
+ .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));
1376
+
1377
+ var gridSize = (this.orientation == 'bottom' ? 1 : -1) * this.graph.height;
1378
+
1379
+ this.graph.vis
1380
+ .append("svg:g")
1381
+ .attr("class", "x_grid_d3")
1382
+ .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));
1383
+
1384
+ this._renderHeight = this.graph.height;
1385
+ };
1386
+
1387
+ this._discoverSize = function(element, args) {
1388
+
1389
+ if (typeof window !== 'undefined') {
1390
+
1391
+ var style = window.getComputedStyle(element, null);
1392
+ var elementHeight = parseInt(style.getPropertyValue('height'), 10);
1393
+
1394
+ if (!args.auto) {
1395
+ var elementWidth = parseInt(style.getPropertyValue('width'), 10);
1396
+ }
1397
+ }
1398
+
1399
+ this.width = (args.width || elementWidth || this.graph.width) * (1 + berthRate);
1400
+ this.height = args.height || elementHeight || 40;
1401
+ };
1402
+
1403
+ this.initialize(args);
1404
+ };
1405
+
1406
+ Rickshaw.namespace('Rickshaw.Graph.Axis.Y');
1407
+
1408
+ Rickshaw.Graph.Axis.Y = Rickshaw.Class.create( {
1409
+
1410
+ initialize: function(args) {
1411
+
1412
+ this.graph = args.graph;
1413
+ this.orientation = args.orientation || 'right';
1414
+
1415
+ var pixelsPerTick = args.pixelsPerTick || 75;
1416
+ this.ticks = args.ticks || Math.floor(this.graph.height / pixelsPerTick);
1417
+ this.tickSize = args.tickSize || 4;
1418
+ this.ticksTreatment = args.ticksTreatment || 'plain';
1419
+ this.tickFormat = args.tickFormat || function(y) { return y };
1420
+
1421
+ this.berthRate = 0.10;
1422
+
1423
+ if (args.element) {
1424
+
1425
+ this.element = args.element;
1426
+ this.vis = d3.select(args.element)
1427
+ .append("svg:svg")
1428
+ .attr('class', 'rickshaw_graph y_axis');
1429
+
1430
+ this.element = this.vis[0][0];
1431
+ this.element.style.position = 'relative';
1432
+
1433
+ this.setSize({ width: args.width, height: args.height });
1434
+
1435
+ } else {
1436
+ this.vis = this.graph.vis;
1437
+ }
1438
+
1439
+ var self = this;
1440
+ this.graph.onUpdate( function() { self.render() } );
1441
+ },
1442
+
1443
+ setSize: function(args) {
1444
+
1445
+ args = args || {};
1446
+
1447
+ if (!this.element) return;
1448
+
1449
+ if (typeof window !== 'undefined') {
1450
+
1451
+ var style = window.getComputedStyle(this.element.parentNode, null);
1452
+ var elementWidth = parseInt(style.getPropertyValue('width'), 10);
1453
+
1454
+ if (!args.auto) {
1455
+ var elementHeight = parseInt(style.getPropertyValue('height'), 10);
1456
+ }
1457
+ }
1458
+
1459
+ this.width = args.width || elementWidth || this.graph.width * this.berthRate;
1460
+ this.height = args.height || elementHeight || this.graph.height;
1461
+
1462
+ this.vis
1463
+ .attr('width', this.width)
1464
+ .attr('height', this.height * (1 + this.berthRate));
1465
+
1466
+ var berth = this.height * this.berthRate;
1467
+
1468
+ if (this.orientation == 'left') {
1469
+ this.element.style.top = -1 * berth + 'px';
1470
+ }
1471
+ },
1472
+
1473
+ render: function() {
1474
+
1475
+ if (this.graph.height !== this._renderHeight) this.setSize({ auto: true });
1476
+
1477
+ var axis = this._drawAxis(this.graph.y);
1478
+
1479
+ this._drawGrid(axis);
1480
+
1481
+ this._renderHeight = this.graph.height;
1482
+ },
1483
+
1484
+ _drawAxis: function(scale) {
1485
+ var axis = d3.svg.axis().scale(scale).orient(this.orientation);
1486
+ axis.tickFormat(this.tickFormat);
1487
+
1488
+ if (this.orientation == 'left') {
1489
+ var berth = this.height * this.berthRate;
1490
+ var transform = 'translate(' + this.width + ', ' + berth + ')';
1491
+ }
1492
+
1493
+ if (this.element) {
1494
+ this.vis.selectAll('*').remove();
1495
+ }
1496
+
1497
+ this.vis
1498
+ .append("svg:g")
1499
+ .attr("class", ["y_ticks", this.ticksTreatment].join(" "))
1500
+ .attr("transform", transform)
1501
+ .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));
1502
+
1503
+ return axis;
1504
+ },
1505
+
1506
+ _drawGrid: function(axis) {
1507
+ var gridSize = (this.orientation == 'right' ? 1 : -1) * this.graph.width;
1508
+
1509
+ this.graph.vis
1510
+ .append("svg:g")
1511
+ .attr("class", "y_grid")
1512
+ .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));
1513
+ }
1514
+ } );
1515
+ Rickshaw.namespace('Rickshaw.Graph.Axis.Y.Scaled');
1516
+
1517
+ Rickshaw.Graph.Axis.Y.Scaled = Rickshaw.Class.create( Rickshaw.Graph.Axis.Y, {
1518
+
1519
+ initialize: function($super, args) {
1520
+
1521
+ if (typeof(args.scale) === 'undefined') {
1522
+ throw new Error('Scaled requires scale');
1523
+ }
1524
+
1525
+ this.scale = args.scale;
1526
+
1527
+ if (typeof(args.grid) === 'undefined') {
1528
+ this.grid = true;
1529
+ } else {
1530
+ this.grid = args.grid;
1531
+ }
1532
+
1533
+ $super(args);
1534
+
1535
+ },
1536
+
1537
+ _drawAxis: function($super, scale) {
1538
+ // make a copy of the custom scale, adjust the range to match the graph's scale
1539
+ var adjustedScale = this.scale.copy().range(scale.range());
1540
+
1541
+ return $super(adjustedScale);
1542
+ },
1543
+
1544
+ _drawGrid: function($super, axis) {
1545
+ if (this.grid) {
1546
+ // only draw the axis if the grid option is true
1547
+ $super(axis);
1548
+ }
1549
+ }
1550
+ } );
1551
+ Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Highlight');
1552
+
1553
+ Rickshaw.Graph.Behavior.Series.Highlight = function(args) {
1554
+
1555
+ this.graph = args.graph;
1556
+ this.legend = args.legend;
1557
+
1558
+ var self = this;
1559
+
1560
+ var colorSafe = {};
1561
+ var activeLine = null;
1562
+
1563
+ this.addHighlightEvents = function (l) {
1564
+
1565
+ l.element.addEventListener( 'mouseover', function(e) {
1566
+
1567
+ if (activeLine) return;
1568
+ else activeLine = l;
1569
+
1570
+ self.legend.lines.forEach( function(line, index) {
1571
+
1572
+ if (l === line) {
1573
+
1574
+ // if we're not in a stacked renderer bring active line to the top
1575
+ if (index > 0 && self.graph.renderer.unstack) {
1576
+
1577
+ var seriesIndex = self.graph.series.length - index - 1;
1578
+ line.originalIndex = seriesIndex;
1579
+
1580
+ var series = self.graph.series.splice(seriesIndex, 1)[0];
1581
+ self.graph.series.push(series);
1582
+ }
1583
+ return;
1584
+ }
1585
+
1586
+ colorSafe[line.series.name] = colorSafe[line.series.name] || line.series.color;
1587
+ line.series.color = d3.interpolateRgb(line.series.color, d3.rgb('#d8d8d8'))(0.8).toString();
1588
+ } );
1589
+
1590
+ self.graph.update();
1591
+
1592
+ }, false );
1593
+
1594
+ l.element.addEventListener( 'mouseout', function(e) {
1595
+
1596
+ if (!activeLine) return;
1597
+ else activeLine = null;
1598
+
1599
+ self.legend.lines.forEach( function(line) {
1600
+
1601
+ // return reordered series to its original place
1602
+ if (l === line && line.hasOwnProperty('originalIndex')) {
1603
+
1604
+ var series = self.graph.series.pop();
1605
+ self.graph.series.splice(line.originalIndex, 0, series);
1606
+ delete line.originalIndex;
1607
+ }
1608
+
1609
+ if (colorSafe[line.series.name]) {
1610
+ line.series.color = colorSafe[line.series.name];
1611
+ }
1612
+ } );
1613
+
1614
+ self.graph.update();
1615
+
1616
+ }, false );
1617
+ };
1618
+
1619
+ if (this.legend) {
1620
+ this.legend.lines.forEach( function(l) {
1621
+ self.addHighlightEvents(l);
1622
+ } );
1623
+ }
1624
+
1625
+ };
1626
+ Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Order');
1627
+
1628
+ Rickshaw.Graph.Behavior.Series.Order = function(args) {
1629
+
1630
+ this.graph = args.graph;
1631
+ this.legend = args.legend;
1632
+
1633
+ var self = this;
1634
+
1635
+ if (typeof window.$ == 'undefined') {
1636
+ throw "couldn't find jQuery at window.$";
1637
+ }
1638
+
1639
+ if (typeof window.$.ui == 'undefined') {
1640
+ throw "couldn't find jQuery UI at window.$.ui";
1641
+ }
1642
+
1643
+ $(function() {
1644
+ $(self.legend.list).sortable( {
1645
+ containment: 'parent',
1646
+ tolerance: 'pointer',
1647
+ update: function( event, ui ) {
1648
+ var series = [];
1649
+ $(self.legend.list).find('li').each( function(index, item) {
1650
+ if (!item.series) return;
1651
+ series.push(item.series);
1652
+ } );
1653
+
1654
+ for (var i = self.graph.series.length - 1; i >= 0; i--) {
1655
+ self.graph.series[i] = series.shift();
1656
+ }
1657
+
1658
+ self.graph.update();
1659
+ }
1660
+ } );
1661
+ $(self.legend.list).disableSelection();
1662
+ });
1663
+
1664
+ //hack to make jquery-ui sortable behave
1665
+ this.graph.onUpdate( function() {
1666
+ var h = window.getComputedStyle(self.legend.element).height;
1667
+ self.legend.element.style.height = h;
1668
+ } );
1669
+ };
1670
+ Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Toggle');
1671
+
1672
+ Rickshaw.Graph.Behavior.Series.Toggle = function(args) {
1673
+
1674
+ this.graph = args.graph;
1675
+ this.legend = args.legend;
1676
+
1677
+ var self = this;
1678
+
1679
+ this.addAnchor = function(line) {
1680
+ var anchor = document.createElement('a');
1681
+ anchor.innerHTML = '&#10004;';
1682
+ anchor.classList.add('action');
1683
+ line.element.insertBefore(anchor, line.element.firstChild);
1684
+
1685
+ anchor.onclick = function(e) {
1686
+ if (line.series.disabled) {
1687
+ line.series.enable();
1688
+ line.element.classList.remove('disabled');
1689
+ } else {
1690
+ line.series.disable();
1691
+ line.element.classList.add('disabled');
1692
+ }
1693
+ };
1694
+
1695
+ var label = line.element.getElementsByTagName('span')[0];
1696
+ label.onclick = function(e){
1697
+
1698
+ var disableAllOtherLines = line.series.disabled;
1699
+ if ( ! disableAllOtherLines ) {
1700
+ for ( var i = 0; i < self.legend.lines.length; i++ ) {
1701
+ var l = self.legend.lines[i];
1702
+ if ( line.series === l.series ) {
1703
+ // noop
1704
+ } else if ( l.series.disabled ) {
1705
+ // noop
1706
+ } else {
1707
+ disableAllOtherLines = true;
1708
+ break;
1709
+ }
1710
+ }
1711
+ }
1712
+
1713
+ // show all or none
1714
+ if ( disableAllOtherLines ) {
1715
+
1716
+ // these must happen first or else we try ( and probably fail ) to make a no line graph
1717
+ line.series.enable();
1718
+ line.element.classList.remove('disabled');
1719
+
1720
+ self.legend.lines.forEach(function(l){
1721
+ if ( line.series === l.series ) {
1722
+ // noop
1723
+ } else {
1724
+ l.series.disable();
1725
+ l.element.classList.add('disabled');
1726
+ }
1727
+ });
1728
+
1729
+ } else {
1730
+
1731
+ self.legend.lines.forEach(function(l){
1732
+ l.series.enable();
1733
+ l.element.classList.remove('disabled');
1734
+ });
1735
+
1736
+ }
1737
+
1738
+ };
1739
+
1740
+ };
1741
+
1742
+ if (this.legend) {
1743
+
1744
+ if (typeof $ != 'undefined' && $(this.legend.list).sortable) {
1745
+
1746
+ $(this.legend.list).sortable( {
1747
+ start: function(event, ui) {
1748
+ ui.item.bind('no.onclick',
1749
+ function(event) {
1750
+ event.preventDefault();
1751
+ }
1752
+ );
1753
+ },
1754
+ stop: function(event, ui) {
1755
+ setTimeout(function(){
1756
+ ui.item.unbind('no.onclick');
1757
+ }, 250);
1758
+ }
1759
+ });
1760
+ }
1761
+
1762
+ this.legend.lines.forEach( function(l) {
1763
+ self.addAnchor(l);
1764
+ } );
1765
+ }
1766
+
1767
+ this._addBehavior = function() {
1768
+
1769
+ this.graph.series.forEach( function(s) {
1770
+
1771
+ s.disable = function() {
1772
+
1773
+ if (self.graph.series.length <= 1) {
1774
+ throw('only one series left');
1775
+ }
1776
+
1777
+ s.disabled = true;
1778
+ self.graph.update();
1779
+ };
1780
+
1781
+ s.enable = function() {
1782
+ s.disabled = false;
1783
+ self.graph.update();
1784
+ };
1785
+ } );
1786
+ };
1787
+ this._addBehavior();
1788
+
1789
+ this.updateBehaviour = function () { this._addBehavior() };
1790
+
1791
+ };
1792
+ Rickshaw.namespace('Rickshaw.Graph.HoverDetail');
1793
+
1794
+ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1795
+
1796
+ initialize: function(args) {
1797
+
1798
+ var graph = this.graph = args.graph;
1799
+
1800
+ this.xFormatter = args.xFormatter || function(x) {
1801
+ return new Date( x * 1000 ).toUTCString();
1802
+ };
1803
+
1804
+ this.yFormatter = args.yFormatter || function(y) {
1805
+ return y === null ? y : y.toFixed(2);
1806
+ };
1807
+
1808
+ var element = this.element = document.createElement('div');
1809
+ element.className = 'detail';
1810
+
1811
+ this.visible = true;
1812
+ graph.element.appendChild(element);
1813
+
1814
+ this.lastEvent = null;
1815
+ this._addListeners();
1816
+
1817
+ this.onShow = args.onShow;
1818
+ this.onHide = args.onHide;
1819
+ this.onRender = args.onRender;
1820
+
1821
+ this.formatter = args.formatter || this.formatter;
1822
+
1823
+ },
1824
+
1825
+ formatter: function(series, x, y, formattedX, formattedY, d) {
1826
+ return series.name + ':&nbsp;' + formattedY;
1827
+ },
1828
+
1829
+ update: function(e) {
1830
+
1831
+ e = e || this.lastEvent;
1832
+ if (!e) return;
1833
+ this.lastEvent = e;
1834
+
1835
+ if (!e.target.nodeName.match(/^(path|svg|rect)$/)) return;
1836
+
1837
+ var graph = this.graph;
1838
+
1839
+ var eventX = e.offsetX || e.layerX;
1840
+ var eventY = e.offsetY || e.layerY;
1841
+
1842
+ var j = 0;
1843
+ var points = [];
1844
+ var nearestPoint;
1845
+
1846
+ this.graph.series.active().forEach( function(series) {
1847
+
1848
+ var data = this.graph.stackedData[j++];
1849
+
1850
+ var domainX = graph.x.invert(eventX);
1851
+
1852
+ var domainIndexScale = d3.scale.linear()
1853
+ .domain([data[0].x, data.slice(-1)[0].x])
1854
+ .range([0, data.length - 1]);
1855
+
1856
+ var approximateIndex = Math.round(domainIndexScale(domainX));
1857
+ var dataIndex = Math.min(approximateIndex || 0, data.length - 1);
1858
+
1859
+ for (var i = approximateIndex; i < data.length - 1;) {
1860
+
1861
+ if (!data[i] || !data[i + 1]) break;
1862
+
1863
+ if (data[i].x <= domainX && data[i + 1].x > domainX) {
1864
+ dataIndex = i;
1865
+ break;
1866
+ }
1867
+
1868
+ if (data[i + 1].x <= domainX) { i++ } else { i-- }
1869
+ }
1870
+
1871
+ if (dataIndex < 0) dataIndex = 0;
1872
+ var value = data[dataIndex];
1873
+
1874
+ var distance = Math.sqrt(
1875
+ Math.pow(Math.abs(graph.x(value.x) - eventX), 2) +
1876
+ Math.pow(Math.abs(graph.y(value.y + value.y0) - eventY), 2)
1877
+ );
1878
+
1879
+ var xFormatter = series.xFormatter || this.xFormatter;
1880
+ var yFormatter = series.yFormatter || this.yFormatter;
1881
+
1882
+ var point = {
1883
+ formattedXValue: xFormatter(value.x),
1884
+ formattedYValue: yFormatter(series.scale ? series.scale.invert(value.y) : value.y),
1885
+ series: series,
1886
+ value: value,
1887
+ distance: distance,
1888
+ order: j,
1889
+ name: series.name
1890
+ };
1891
+
1892
+ if (!nearestPoint || distance < nearestPoint.distance) {
1893
+ nearestPoint = point;
1894
+ }
1895
+
1896
+ points.push(point);
1897
+
1898
+ }, this );
1899
+
1900
+
1901
+ nearestPoint.active = true;
1902
+
1903
+ var domainX = nearestPoint.value.x;
1904
+ var formattedXValue = nearestPoint.formattedXValue;
1905
+
1906
+ this.element.innerHTML = '';
1907
+ this.element.style.left = graph.x(domainX) + 'px';
1908
+
1909
+ this.visible && this.render( {
1910
+ points: points,
1911
+ detail: points, // for backwards compatibility
1912
+ mouseX: eventX,
1913
+ mouseY: eventY,
1914
+ formattedXValue: formattedXValue,
1915
+ domainX: domainX
1916
+ } );
1917
+ },
1918
+
1919
+ hide: function() {
1920
+ this.visible = false;
1921
+ this.element.classList.add('inactive');
1922
+
1923
+ if (typeof this.onHide == 'function') {
1924
+ this.onHide();
1925
+ }
1926
+ },
1927
+
1928
+ show: function() {
1929
+ this.visible = true;
1930
+ this.element.classList.remove('inactive');
1931
+
1932
+ if (typeof this.onShow == 'function') {
1933
+ this.onShow();
1934
+ }
1935
+ },
1936
+
1937
+ render: function(args) {
1938
+
1939
+ var graph = this.graph;
1940
+ var points = args.points;
1941
+ var point = points.filter( function(p) { return p.active } ).shift();
1942
+
1943
+ if (point.value.y === null) return;
1944
+
1945
+ var formattedXValue = point.formattedXValue;
1946
+ var formattedYValue = point.formattedYValue;
1947
+
1948
+ this.element.innerHTML = '';
1949
+ this.element.style.left = graph.x(point.value.x) + 'px';
1950
+
1951
+ var xLabel = document.createElement('div');
1952
+
1953
+ xLabel.className = 'x_label';
1954
+ xLabel.innerHTML = formattedXValue;
1955
+ this.element.appendChild(xLabel);
1956
+
1957
+ var item = document.createElement('div');
1958
+
1959
+ item.className = 'item';
1960
+
1961
+ // invert the scale if this series displays using a scale
1962
+ var series = point.series;
1963
+ var actualY = series.scale ? series.scale.invert(point.value.y) : point.value.y;
1964
+
1965
+ item.innerHTML = this.formatter(series, point.value.x, actualY, formattedXValue, formattedYValue, point);
1966
+ item.style.top = this.graph.y(point.value.y0 + point.value.y) + 'px';
1967
+
1968
+ this.element.appendChild(item);
1969
+
1970
+ var dot = document.createElement('div');
1971
+
1972
+ dot.className = 'dot';
1973
+ dot.style.top = item.style.top;
1974
+ dot.style.borderColor = series.color;
1975
+
1976
+ this.element.appendChild(dot);
1977
+
1978
+ if (point.active) {
1979
+ item.className = 'item active';
1980
+ dot.className = 'dot active';
1981
+ }
1982
+
1983
+ this.show();
1984
+
1985
+ if (typeof this.onRender == 'function') {
1986
+ this.onRender(args);
1987
+ }
1988
+ },
1989
+
1990
+ _addListeners: function() {
1991
+
1992
+ this.graph.element.addEventListener(
1993
+ 'mousemove',
1994
+ function(e) {
1995
+ this.visible = true;
1996
+ this.update(e);
1997
+ }.bind(this),
1998
+ false
1999
+ );
2000
+
2001
+ this.graph.onUpdate( function() { this.update() }.bind(this) );
2002
+
2003
+ this.graph.element.addEventListener(
2004
+ 'mouseout',
2005
+ function(e) {
2006
+ if (e.relatedTarget && !(e.relatedTarget.compareDocumentPosition(this.graph.element) & Node.DOCUMENT_POSITION_CONTAINS)) {
2007
+ this.hide();
2008
+ }
2009
+ }.bind(this),
2010
+ false
2011
+ );
2012
+ }
2013
+ });
2014
+
2015
+ Rickshaw.namespace('Rickshaw.Graph.JSONP');
2016
+
2017
+ Rickshaw.Graph.JSONP = Rickshaw.Class.create( Rickshaw.Graph.Ajax, {
2018
+
2019
+ request: function() {
2020
+
2021
+ $.ajax( {
2022
+ url: this.dataURL,
2023
+ dataType: 'jsonp',
2024
+ success: this.success.bind(this),
2025
+ error: this.error.bind(this)
2026
+ } );
2027
+ }
2028
+ } );
2029
+ Rickshaw.namespace('Rickshaw.Graph.Legend');
2030
+
2031
+ Rickshaw.Graph.Legend = function(args) {
2032
+
2033
+ var element = this.element = args.element;
2034
+ var graph = this.graph = args.graph;
2035
+
2036
+ var self = this;
2037
+
2038
+ element.classList.add('rickshaw_legend');
2039
+
2040
+ var list = this.list = document.createElement('ul');
2041
+ element.appendChild(list);
2042
+
2043
+ var series = graph.series
2044
+ .map( function(s) { return s } );
2045
+
2046
+ if (!args.naturalOrder) {
2047
+ series = series.reverse();
2048
+ }
2049
+
2050
+ this.lines = [];
2051
+
2052
+ this.addLine = function (series) {
2053
+ var line = document.createElement('li');
2054
+ line.className = 'line';
2055
+ if (series.disabled) {
2056
+ line.className += ' disabled';
2057
+ }
2058
+
2059
+ var swatch = document.createElement('div');
2060
+ swatch.className = 'swatch';
2061
+ swatch.style.backgroundColor = series.color;
2062
+
2063
+ line.appendChild(swatch);
2064
+
2065
+ var label = document.createElement('span');
2066
+ label.className = 'label';
2067
+ label.innerHTML = series.name;
2068
+
2069
+ line.appendChild(label);
2070
+ list.appendChild(line);
2071
+
2072
+ line.series = series;
2073
+
2074
+ if (series.noLegend) {
2075
+ line.style.display = 'none';
2076
+ }
2077
+
2078
+ var _line = { element: line, series: series };
2079
+ if (self.shelving) {
2080
+ self.shelving.addAnchor(_line);
2081
+ self.shelving.updateBehaviour();
2082
+ }
2083
+ if (self.highlighter) {
2084
+ self.highlighter.addHighlightEvents(_line);
2085
+ }
2086
+ self.lines.push(_line);
2087
+ };
2088
+
2089
+ series.forEach( function(s) {
2090
+ self.addLine(s);
2091
+ } );
2092
+
2093
+ graph.onUpdate( function() {} );
2094
+ };
2095
+ Rickshaw.namespace('Rickshaw.Graph.RangeSlider');
2096
+
2097
+ Rickshaw.Graph.RangeSlider = Rickshaw.Class.create({
2098
+
2099
+ initialize: function(args) {
2100
+
2101
+ var element = this.element = args.element;
2102
+ var graph = this.graph = args.graph;
2103
+
2104
+ this.build();
2105
+
2106
+ graph.onUpdate( function() { this.update() }.bind(this) );
2107
+ },
2108
+
2109
+ build: function() {
2110
+
2111
+ var element = this.element;
2112
+ var graph = this.graph;
2113
+
2114
+ $( function() {
2115
+ $(element).slider( {
2116
+ range: true,
2117
+ min: graph.dataDomain()[0],
2118
+ max: graph.dataDomain()[1],
2119
+ values: [
2120
+ graph.dataDomain()[0],
2121
+ graph.dataDomain()[1]
2122
+ ],
2123
+ slide: function( event, ui ) {
2124
+
2125
+ graph.window.xMin = ui.values[0];
2126
+ graph.window.xMax = ui.values[1];
2127
+ graph.update();
2128
+
2129
+ // if we're at an extreme, stick there
2130
+ if (graph.dataDomain()[0] == ui.values[0]) {
2131
+ graph.window.xMin = undefined;
2132
+ }
2133
+ if (graph.dataDomain()[1] == ui.values[1]) {
2134
+ graph.window.xMax = undefined;
2135
+ }
2136
+ }
2137
+ } );
2138
+ } );
2139
+
2140
+ element[0].style.width = graph.width + 'px';
2141
+ },
2142
+
2143
+ update: function() {
2144
+
2145
+ var element = this.element;
2146
+ var graph = this.graph;
2147
+
2148
+ var values = $(element).slider('option', 'values');
2149
+
2150
+ $(element).slider('option', 'min', graph.dataDomain()[0]);
2151
+ $(element).slider('option', 'max', graph.dataDomain()[1]);
2152
+
2153
+ if (graph.window.xMin == null) {
2154
+ values[0] = graph.dataDomain()[0];
2155
+ }
2156
+ if (graph.window.xMax == null) {
2157
+ values[1] = graph.dataDomain()[1];
2158
+ }
2159
+
2160
+ $(element).slider('option', 'values', values);
2161
+ }
2162
+ });
2163
+
2164
+ Rickshaw.namespace("Rickshaw.Graph.Renderer");
2165
+
2166
+ Rickshaw.Graph.Renderer = Rickshaw.Class.create( {
2167
+
2168
+ initialize: function(args) {
2169
+ this.graph = args.graph;
2170
+ this.tension = args.tension || this.tension;
2171
+ this.graph.unstacker = this.graph.unstacker || new Rickshaw.Graph.Unstacker( { graph: this.graph } );
2172
+ this.configure(args);
2173
+ },
2174
+
2175
+ seriesPathFactory: function() {
2176
+ //implement in subclass
2177
+ },
2178
+
2179
+ seriesStrokeFactory: function() {
2180
+ // implement in subclass
2181
+ },
2182
+
2183
+ defaults: function() {
2184
+ return {
2185
+ tension: 0.8,
2186
+ strokeWidth: 2,
2187
+ unstack: true,
2188
+ padding: { top: 0.01, right: 0, bottom: 0.01, left: 0 },
2189
+ stroke: false,
2190
+ fill: false
2191
+ };
2192
+ },
2193
+
2194
+ domain: function() {
2195
+
2196
+ var stackedData = this.graph.stackedData || this.graph.stackData();
2197
+ var firstPoint = stackedData[0][0];
2198
+
2199
+ var xMin = firstPoint.x;
2200
+ var xMax = firstPoint.x;
2201
+
2202
+ var yMin = firstPoint.y + firstPoint.y0;
2203
+ var yMax = firstPoint.y + firstPoint.y0;
2204
+
2205
+ stackedData.forEach( function(series) {
2206
+
2207
+ series.forEach( function(d) {
2208
+
2209
+ if (d.y == null) return;
2210
+
2211
+ var y = d.y + d.y0;
2212
+
2213
+ if (y < yMin) yMin = y;
2214
+ if (y > yMax) yMax = y;
2215
+ } );
2216
+
2217
+ if (series[0].x < xMin) xMin = series[0].x;
2218
+ if (series[series.length - 1].x > xMax) xMax = series[series.length - 1].x;
2219
+ } );
2220
+
2221
+ xMin -= (xMax - xMin) * this.padding.left;
2222
+ xMax += (xMax - xMin) * this.padding.right;
2223
+
2224
+ yMin = this.graph.min === 'auto' ? yMin : this.graph.min || 0;
2225
+ yMax = this.graph.max === undefined ? yMax : this.graph.max;
2226
+
2227
+ if (this.graph.min === 'auto' || yMin < 0) {
2228
+ yMin -= (yMax - yMin) * this.padding.bottom;
2229
+ }
2230
+
2231
+ if (this.graph.max === undefined) {
2232
+ yMax += (yMax - yMin) * this.padding.top;
2233
+ }
2234
+
2235
+ return { x: [xMin, xMax], y: [yMin, yMax] };
2236
+ },
2237
+
2238
+ render: function() {
2239
+
2240
+ var graph = this.graph;
2241
+
2242
+ graph.vis.selectAll('*').remove();
2243
+
2244
+ var nodes = graph.vis.selectAll("path")
2245
+ .data(this.graph.stackedData)
2246
+ .enter().append("svg:path")
2247
+ .attr("d", this.seriesPathFactory());
2248
+
2249
+ var i = 0;
2250
+ graph.series.forEach( function(series) {
2251
+ if (series.disabled) return;
2252
+ series.path = nodes[0][i++];
2253
+ this._styleSeries(series);
2254
+ }, this );
2255
+ },
2256
+
2257
+ _styleSeries: function(series) {
2258
+
2259
+ var fill = this.fill ? series.color : 'none';
2260
+ var stroke = this.stroke ? series.color : 'none';
2261
+
2262
+ series.path.setAttribute('fill', fill);
2263
+ series.path.setAttribute('stroke', stroke);
2264
+ series.path.setAttribute('stroke-width', this.strokeWidth);
2265
+ series.path.setAttribute('class', series.className);
2266
+ },
2267
+
2268
+ configure: function(args) {
2269
+
2270
+ args = args || {};
2271
+
2272
+ Rickshaw.keys(this.defaults()).forEach( function(key) {
2273
+
2274
+ if (!args.hasOwnProperty(key)) {
2275
+ this[key] = this[key] || this.graph[key] || this.defaults()[key];
2276
+ return;
2277
+ }
2278
+
2279
+ if (typeof this.defaults()[key] == 'object') {
2280
+
2281
+ Rickshaw.keys(this.defaults()[key]).forEach( function(k) {
2282
+
2283
+ this[key][k] =
2284
+ args[key][k] !== undefined ? args[key][k] :
2285
+ this[key][k] !== undefined ? this[key][k] :
2286
+ this.defaults()[key][k];
2287
+ }, this );
2288
+
2289
+ } else {
2290
+ this[key] =
2291
+ args[key] !== undefined ? args[key] :
2292
+ this[key] !== undefined ? this[key] :
2293
+ this.graph[key] !== undefined ? this.graph[key] :
2294
+ this.defaults()[key];
2295
+ }
2296
+
2297
+ }, this );
2298
+ },
2299
+
2300
+ setStrokeWidth: function(strokeWidth) {
2301
+ if (strokeWidth !== undefined) {
2302
+ this.strokeWidth = strokeWidth;
2303
+ }
2304
+ },
2305
+
2306
+ setTension: function(tension) {
2307
+ if (tension !== undefined) {
2308
+ this.tension = tension;
2309
+ }
2310
+ }
2311
+ } );
2312
+
2313
+ Rickshaw.namespace('Rickshaw.Graph.Renderer.Line');
2314
+
2315
+ Rickshaw.Graph.Renderer.Line = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2316
+
2317
+ name: 'line',
2318
+
2319
+ defaults: function($super) {
2320
+
2321
+ return Rickshaw.extend( $super(), {
2322
+ unstack: true,
2323
+ fill: false,
2324
+ stroke: true
2325
+ } );
2326
+ },
2327
+
2328
+ seriesPathFactory: function() {
2329
+
2330
+ var graph = this.graph;
2331
+
2332
+ var factory = d3.svg.line()
2333
+ .x( function(d) { return graph.x(d.x) } )
2334
+ .y( function(d) { return graph.y(d.y) } )
2335
+ .interpolate(this.graph.interpolation).tension(this.tension);
2336
+
2337
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2338
+ return factory;
2339
+ }
2340
+ } );
2341
+
2342
+ Rickshaw.namespace('Rickshaw.Graph.Renderer.Stack');
2343
+
2344
+ Rickshaw.Graph.Renderer.Stack = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2345
+
2346
+ name: 'stack',
2347
+
2348
+ defaults: function($super) {
2349
+
2350
+ return Rickshaw.extend( $super(), {
2351
+ fill: true,
2352
+ stroke: false,
2353
+ unstack: false
2354
+ } );
2355
+ },
2356
+
2357
+ seriesPathFactory: function() {
2358
+
2359
+ var graph = this.graph;
2360
+
2361
+ var factory = d3.svg.area()
2362
+ .x( function(d) { return graph.x(d.x) } )
2363
+ .y0( function(d) { return graph.y(d.y0) } )
2364
+ .y1( function(d) { return graph.y(d.y + d.y0) } )
2365
+ .interpolate(this.graph.interpolation).tension(this.tension);
2366
+
2367
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2368
+ return factory;
2369
+ }
2370
+ } );
2371
+
2372
+ Rickshaw.namespace('Rickshaw.Graph.Renderer.Bar');
2373
+
2374
+ Rickshaw.Graph.Renderer.Bar = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2375
+
2376
+ name: 'bar',
2377
+
2378
+ defaults: function($super) {
2379
+
2380
+ var defaults = Rickshaw.extend( $super(), {
2381
+ gapSize: 0.05,
2382
+ unstack: false
2383
+ } );
2384
+
2385
+ delete defaults.tension;
2386
+ return defaults;
2387
+ },
2388
+
2389
+ initialize: function($super, args) {
2390
+ args = args || {};
2391
+ this.gapSize = args.gapSize || this.gapSize;
2392
+ $super(args);
2393
+ },
2394
+
2395
+ domain: function($super) {
2396
+
2397
+ var domain = $super();
2398
+
2399
+ var frequentInterval = this._frequentInterval();
2400
+ domain.x[1] += parseInt(frequentInterval.magnitude, 10);
2401
+
2402
+ return domain;
2403
+ },
2404
+
2405
+ barWidth: function() {
2406
+
2407
+ var stackedData = this.graph.stackedData || this.graph.stackData();
2408
+ var data = stackedData.slice(-1).shift();
2409
+
2410
+ var frequentInterval = this._frequentInterval();
2411
+ var barWidth = this.graph.x(data[0].x + frequentInterval.magnitude * (1 - this.gapSize));
2412
+
2413
+ return barWidth;
2414
+ },
2415
+
2416
+ render: function() {
2417
+
2418
+ var graph = this.graph;
2419
+
2420
+ graph.vis.selectAll('*').remove();
2421
+
2422
+ var barWidth = this.barWidth();
2423
+ var barXOffset = 0;
2424
+
2425
+ var activeSeriesCount = graph.series.filter( function(s) { return !s.disabled; } ).length;
2426
+ var seriesBarWidth = this.unstack ? barWidth / activeSeriesCount : barWidth;
2427
+
2428
+ var transform = function(d) {
2429
+ // add a matrix transform for negative values
2430
+ var matrix = [ 1, 0, 0, (d.y < 0 ? -1 : 1), 0, (d.y < 0 ? graph.y.magnitude(Math.abs(d.y)) * 2 : 0) ];
2431
+ return "matrix(" + matrix.join(',') + ")";
2432
+ };
2433
+
2434
+ graph.series.forEach( function(series) {
2435
+
2436
+ if (series.disabled) return;
2437
+
2438
+ var nodes = graph.vis.selectAll("path")
2439
+ .data(series.stack.filter( function(d) { return d.y !== null } ))
2440
+ .enter().append("svg:rect")
2441
+ .attr("x", function(d) { return graph.x(d.x) + barXOffset })
2442
+ .attr("y", function(d) { return (graph.y(d.y0 + Math.abs(d.y))) * (d.y < 0 ? -1 : 1 ) })
2443
+ .attr("width", seriesBarWidth)
2444
+ .attr("height", function(d) { return graph.y.magnitude(Math.abs(d.y)) })
2445
+ .attr("transform", transform);
2446
+
2447
+ Array.prototype.forEach.call(nodes[0], function(n) {
2448
+ n.setAttribute('fill', series.color);
2449
+ } );
2450
+
2451
+ if (this.unstack) barXOffset += seriesBarWidth;
2452
+
2453
+ }, this );
2454
+ },
2455
+
2456
+ _frequentInterval: function() {
2457
+
2458
+ var stackedData = this.graph.stackedData || this.graph.stackData();
2459
+ var data = stackedData.slice(-1).shift();
2460
+
2461
+ var intervalCounts = {};
2462
+
2463
+ for (var i = 0; i < data.length - 1; i++) {
2464
+ var interval = data[i + 1].x - data[i].x;
2465
+ intervalCounts[interval] = intervalCounts[interval] || 0;
2466
+ intervalCounts[interval]++;
2467
+ }
2468
+
2469
+ var frequentInterval = { count: 0 };
2470
+
2471
+ Rickshaw.keys(intervalCounts).forEach( function(i) {
2472
+ if (frequentInterval.count < intervalCounts[i]) {
2473
+
2474
+ frequentInterval = {
2475
+ count: intervalCounts[i],
2476
+ magnitude: i
2477
+ };
2478
+ }
2479
+ } );
2480
+
2481
+ this._frequentInterval = function() { return frequentInterval };
2482
+
2483
+ return frequentInterval;
2484
+ }
2485
+ } );
2486
+
2487
+ Rickshaw.namespace('Rickshaw.Graph.Renderer.Area');
2488
+
2489
+ Rickshaw.Graph.Renderer.Area = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2490
+
2491
+ name: 'area',
2492
+
2493
+ defaults: function($super) {
2494
+
2495
+ return Rickshaw.extend( $super(), {
2496
+ unstack: false,
2497
+ fill: false,
2498
+ stroke: false
2499
+ } );
2500
+ },
2501
+
2502
+ seriesPathFactory: function() {
2503
+
2504
+ var graph = this.graph;
2505
+
2506
+ var factory = d3.svg.area()
2507
+ .x( function(d) { return graph.x(d.x) } )
2508
+ .y0( function(d) { return graph.y(d.y0) } )
2509
+ .y1( function(d) { return graph.y(d.y + d.y0) } )
2510
+ .interpolate(graph.interpolation).tension(this.tension);
2511
+
2512
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2513
+ return factory;
2514
+ },
2515
+
2516
+ seriesStrokeFactory: function() {
2517
+
2518
+ var graph = this.graph;
2519
+
2520
+ var factory = d3.svg.line()
2521
+ .x( function(d) { return graph.x(d.x) } )
2522
+ .y( function(d) { return graph.y(d.y + d.y0) } )
2523
+ .interpolate(graph.interpolation).tension(this.tension);
2524
+
2525
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2526
+ return factory;
2527
+ },
2528
+
2529
+ render: function() {
2530
+
2531
+ var graph = this.graph;
2532
+
2533
+ graph.vis.selectAll('*').remove();
2534
+
2535
+ // insert or stacked areas so strokes lay on top of areas
2536
+ var method = this.unstack ? 'append' : 'insert';
2537
+
2538
+ var nodes = graph.vis.selectAll("path")
2539
+ .data(this.graph.stackedData)
2540
+ .enter()[method]("svg:g", 'g');
2541
+
2542
+ nodes.append("svg:path")
2543
+ .attr("d", this.seriesPathFactory())
2544
+ .attr("class", 'area');
2545
+
2546
+ if (this.stroke) {
2547
+ nodes.append("svg:path")
2548
+ .attr("d", this.seriesStrokeFactory())
2549
+ .attr("class", 'line');
2550
+ }
2551
+
2552
+ var i = 0;
2553
+ graph.series.forEach( function(series) {
2554
+ if (series.disabled) return;
2555
+ series.path = nodes[0][i++];
2556
+ this._styleSeries(series);
2557
+ }, this );
2558
+ },
2559
+
2560
+ _styleSeries: function(series) {
2561
+
2562
+ if (!series.path) return;
2563
+
2564
+ d3.select(series.path).select('.area')
2565
+ .attr('fill', series.color);
2566
+
2567
+ if (this.stroke) {
2568
+ d3.select(series.path).select('.line')
2569
+ .attr('fill', 'none')
2570
+ .attr('stroke', series.stroke || d3.interpolateRgb(series.color, 'black')(0.125))
2571
+ .attr('stroke-width', this.strokeWidth);
2572
+ }
2573
+
2574
+ if (series.className) {
2575
+ series.path.setAttribute('class', series.className);
2576
+ }
2577
+ }
2578
+ } );
2579
+
2580
+ Rickshaw.namespace('Rickshaw.Graph.Renderer.ScatterPlot');
2581
+
2582
+ Rickshaw.Graph.Renderer.ScatterPlot = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2583
+
2584
+ name: 'scatterplot',
2585
+
2586
+ defaults: function($super) {
2587
+
2588
+ return Rickshaw.extend( $super(), {
2589
+ unstack: true,
2590
+ fill: true,
2591
+ stroke: false,
2592
+ padding:{ top: 0.01, right: 0.01, bottom: 0.01, left: 0.01 },
2593
+ dotSize: 4
2594
+ } );
2595
+ },
2596
+
2597
+ initialize: function($super, args) {
2598
+ $super(args);
2599
+ },
2600
+
2601
+ render: function() {
2602
+
2603
+ var graph = this.graph;
2604
+
2605
+ graph.vis.selectAll('*').remove();
2606
+
2607
+ graph.series.forEach( function(series) {
2608
+
2609
+ if (series.disabled) return;
2610
+
2611
+ var nodes = graph.vis.selectAll("path")
2612
+ .data(series.stack.filter( function(d) { return d.y !== null } ))
2613
+ .enter().append("svg:circle")
2614
+ .attr("cx", function(d) { return graph.x(d.x) })
2615
+ .attr("cy", function(d) { return graph.y(d.y) })
2616
+ .attr("r", function(d) { return ("r" in d) ? d.r : graph.renderer.dotSize});
2617
+
2618
+ Array.prototype.forEach.call(nodes[0], function(n) {
2619
+ n.setAttribute('fill', series.color);
2620
+ } );
2621
+
2622
+ }, this );
2623
+ }
2624
+ } );
2625
+ Rickshaw.namespace('Rickshaw.Graph.Smoother');
2626
+
2627
+ Rickshaw.Graph.Smoother = Rickshaw.Class.create({
2628
+
2629
+ initialize: function(args) {
2630
+
2631
+ this.graph = args.graph;
2632
+ this.element = args.element;
2633
+ this.aggregationScale = 1;
2634
+
2635
+ this.build();
2636
+
2637
+ this.graph.stackData.hooks.data.push( {
2638
+ name: 'smoother',
2639
+ orderPosition: 50,
2640
+ f: this.transformer.bind(this)
2641
+ } );
2642
+ },
2643
+
2644
+ build: function() {
2645
+
2646
+ var self = this;
2647
+
2648
+ if (this.element) {
2649
+ $( function() {
2650
+ $(self.element).slider( {
2651
+ min: 1,
2652
+ max: 100,
2653
+ slide: function( event, ui ) {
2654
+ self.setScale(ui.value);
2655
+ self.graph.update();
2656
+ }
2657
+ } );
2658
+ } );
2659
+ }
2660
+ },
2661
+
2662
+ setScale: function(scale) {
2663
+
2664
+ if (scale < 1) {
2665
+ throw "scale out of range: " + scale;
2666
+ }
2667
+
2668
+ this.aggregationScale = scale;
2669
+ this.graph.update();
2670
+ },
2671
+
2672
+ transformer: function(data) {
2673
+
2674
+ if (this.aggregationScale == 1) return data;
2675
+
2676
+ var aggregatedData = [];
2677
+
2678
+ data.forEach( function(seriesData) {
2679
+
2680
+ var aggregatedSeriesData = [];
2681
+
2682
+ while (seriesData.length) {
2683
+
2684
+ var avgX = 0, avgY = 0;
2685
+ var slice = seriesData.splice(0, this.aggregationScale);
2686
+
2687
+ slice.forEach( function(d) {
2688
+ avgX += d.x / slice.length;
2689
+ avgY += d.y / slice.length;
2690
+ } );
2691
+
2692
+ aggregatedSeriesData.push( { x: avgX, y: avgY } );
2693
+ }
2694
+
2695
+ aggregatedData.push(aggregatedSeriesData);
2696
+
2697
+ }.bind(this) );
2698
+
2699
+ return aggregatedData;
2700
+ }
2701
+ });
2702
+
2703
+ Rickshaw.namespace('Rickshaw.Graph.Unstacker');
2704
+
2705
+ Rickshaw.Graph.Unstacker = function(args) {
2706
+
2707
+ this.graph = args.graph;
2708
+ var self = this;
2709
+
2710
+ this.graph.stackData.hooks.after.push( {
2711
+ name: 'unstacker',
2712
+ f: function(data) {
2713
+
2714
+ if (!self.graph.renderer.unstack) return data;
2715
+
2716
+ data.forEach( function(seriesData) {
2717
+ seriesData.forEach( function(d) {
2718
+ d.y0 = 0;
2719
+ } );
2720
+ } );
2721
+
2722
+ return data;
2723
+ }
2724
+ } );
2725
+ };
2726
+
2727
+ Rickshaw.namespace('Rickshaw.Series');
2728
+
2729
+ Rickshaw.Series = Rickshaw.Class.create( Array, {
2730
+
2731
+ initialize: function (data, palette, options) {
2732
+
2733
+ options = options || {};
2734
+
2735
+ this.palette = new Rickshaw.Color.Palette(palette);
2736
+
2737
+ this.timeBase = typeof(options.timeBase) === 'undefined' ?
2738
+ Math.floor(new Date().getTime() / 1000) :
2739
+ options.timeBase;
2740
+
2741
+ var timeInterval = typeof(options.timeInterval) == 'undefined' ?
2742
+ 1000 :
2743
+ options.timeInterval;
2744
+
2745
+ this.setTimeInterval(timeInterval);
2746
+
2747
+ if (data && (typeof(data) == "object") && Array.isArray(data)) {
2748
+ data.forEach( function(item) { this.addItem(item) }, this );
2749
+ }
2750
+ },
2751
+
2752
+ addItem: function(item) {
2753
+
2754
+ if (typeof(item.name) === 'undefined') {
2755
+ throw('addItem() needs a name');
2756
+ }
2757
+
2758
+ item.color = (item.color || this.palette.color(item.name));
2759
+ item.data = (item.data || []);
2760
+
2761
+ // backfill, if necessary
2762
+ if ((item.data.length === 0) && this.length && (this.getIndex() > 0)) {
2763
+ this[0].data.forEach( function(plot) {
2764
+ item.data.push({ x: plot.x, y: 0 });
2765
+ } );
2766
+ } else if (item.data.length === 0) {
2767
+ item.data.push({ x: this.timeBase - (this.timeInterval || 0), y: 0 });
2768
+ }
2769
+
2770
+ this.push(item);
2771
+
2772
+ if (this.legend) {
2773
+ this.legend.addLine(this.itemByName(item.name));
2774
+ }
2775
+ },
2776
+
2777
+ addData: function(data) {
2778
+
2779
+ var index = this.getIndex();
2780
+
2781
+ Rickshaw.keys(data).forEach( function(name) {
2782
+ if (! this.itemByName(name)) {
2783
+ this.addItem({ name: name });
2784
+ }
2785
+ }, this );
2786
+
2787
+ this.forEach( function(item) {
2788
+ item.data.push({
2789
+ x: (index * this.timeInterval || 1) + this.timeBase,
2790
+ y: (data[item.name] || 0)
2791
+ });
2792
+ }, this );
2793
+ },
2794
+
2795
+ getIndex: function () {
2796
+ return (this[0] && this[0].data && this[0].data.length) ? this[0].data.length : 0;
2797
+ },
2798
+
2799
+ itemByName: function(name) {
2800
+
2801
+ for (var i = 0; i < this.length; i++) {
2802
+ if (this[i].name == name)
2803
+ return this[i];
2804
+ }
2805
+ },
2806
+
2807
+ setTimeInterval: function(iv) {
2808
+ this.timeInterval = iv / 1000;
2809
+ },
2810
+
2811
+ setTimeBase: function (t) {
2812
+ this.timeBase = t;
2813
+ },
2814
+
2815
+ dump: function() {
2816
+
2817
+ var data = {
2818
+ timeBase: this.timeBase,
2819
+ timeInterval: this.timeInterval,
2820
+ items: []
2821
+ };
2822
+
2823
+ this.forEach( function(item) {
2824
+
2825
+ var newItem = {
2826
+ color: item.color,
2827
+ name: item.name,
2828
+ data: []
2829
+ };
2830
+
2831
+ item.data.forEach( function(plot) {
2832
+ newItem.data.push({ x: plot.x, y: plot.y });
2833
+ } );
2834
+
2835
+ data.items.push(newItem);
2836
+ } );
2837
+
2838
+ return data;
2839
+ },
2840
+
2841
+ load: function(data) {
2842
+
2843
+ if (data.timeInterval) {
2844
+ this.timeInterval = data.timeInterval;
2845
+ }
2846
+
2847
+ if (data.timeBase) {
2848
+ this.timeBase = data.timeBase;
2849
+ }
2850
+
2851
+ if (data.items) {
2852
+ data.items.forEach( function(item) {
2853
+ this.push(item);
2854
+ if (this.legend) {
2855
+ this.legend.addLine(this.itemByName(item.name));
2856
+ }
2857
+
2858
+ }, this );
2859
+ }
2860
+ }
2861
+ } );
2862
+
2863
+ Rickshaw.Series.zeroFill = function(series) {
2864
+ Rickshaw.Series.fill(series, 0);
2865
+ };
2866
+
2867
+ Rickshaw.Series.fill = function(series, fill) {
2868
+
2869
+ var x;
2870
+ var i = 0;
2871
+
2872
+ var data = series.map( function(s) { return s.data } );
2873
+
2874
+ while ( i < Math.max.apply(null, data.map( function(d) { return d.length } )) ) {
2875
+
2876
+ x = Math.min.apply( null,
2877
+ data
2878
+ .filter(function(d) { return d[i] })
2879
+ .map(function(d) { return d[i].x })
2880
+ );
2881
+
2882
+ data.forEach( function(d) {
2883
+ if (!d[i] || d[i].x != x) {
2884
+ d.splice(i, 0, { x: x, y: fill });
2885
+ }
2886
+ } );
2887
+
2888
+ i++;
2889
+ }
2890
+ };
2891
+
2892
+ Rickshaw.namespace('Rickshaw.Series.FixedDuration');
2893
+
2894
+ Rickshaw.Series.FixedDuration = Rickshaw.Class.create(Rickshaw.Series, {
2895
+
2896
+ initialize: function (data, palette, options) {
2897
+
2898
+ options = options || {};
2899
+
2900
+ if (typeof(options.timeInterval) === 'undefined') {
2901
+ throw new Error('FixedDuration series requires timeInterval');
2902
+ }
2903
+
2904
+ if (typeof(options.maxDataPoints) === 'undefined') {
2905
+ throw new Error('FixedDuration series requires maxDataPoints');
2906
+ }
2907
+
2908
+ this.palette = new Rickshaw.Color.Palette(palette);
2909
+ this.timeBase = typeof(options.timeBase) === 'undefined' ? Math.floor(new Date().getTime() / 1000) : options.timeBase;
2910
+ this.setTimeInterval(options.timeInterval);
2911
+
2912
+ if (this[0] && this[0].data && this[0].data.length) {
2913
+ this.currentSize = this[0].data.length;
2914
+ this.currentIndex = this[0].data.length;
2915
+ } else {
2916
+ this.currentSize = 0;
2917
+ this.currentIndex = 0;
2918
+ }
2919
+
2920
+ this.maxDataPoints = options.maxDataPoints;
2921
+
2922
+
2923
+ if (data && (typeof(data) == "object") && Array.isArray(data)) {
2924
+ data.forEach( function (item) { this.addItem(item) }, this );
2925
+ this.currentSize += 1;
2926
+ this.currentIndex += 1;
2927
+ }
2928
+
2929
+ // reset timeBase for zero-filled values if needed
2930
+ this.timeBase -= (this.maxDataPoints - this.currentSize) * this.timeInterval;
2931
+
2932
+ // zero-fill up to maxDataPoints size if we don't have that much data yet
2933
+ if ((typeof(this.maxDataPoints) !== 'undefined') && (this.currentSize < this.maxDataPoints)) {
2934
+ for (var i = this.maxDataPoints - this.currentSize - 1; i > 0; i--) {
2935
+ this.currentSize += 1;
2936
+ this.currentIndex += 1;
2937
+ this.forEach( function (item) {
2938
+ item.data.unshift({ x: ((i-1) * this.timeInterval || 1) + this.timeBase, y: 0, i: i });
2939
+ }, this );
2940
+ }
2941
+ }
2942
+ },
2943
+
2944
+ addData: function($super, data) {
2945
+
2946
+ $super(data);
2947
+
2948
+ this.currentSize += 1;
2949
+ this.currentIndex += 1;
2950
+
2951
+ if (this.maxDataPoints !== undefined) {
2952
+ while (this.currentSize > this.maxDataPoints) {
2953
+ this.dropData();
2954
+ }
2955
+ }
2956
+ },
2957
+
2958
+ dropData: function() {
2959
+
2960
+ this.forEach(function(item) {
2961
+ item.data.splice(0, 1);
2962
+ } );
2963
+
2964
+ this.currentSize -= 1;
2965
+ },
2966
+
2967
+ getIndex: function () {
2968
+ return this.currentIndex;
2969
+ }
2970
+ } );
2971
+