Merge "Fix the docker push"
[clamp.git] / src / main / resources / META-INF / resources / designer / lib / plugins / morris / morris.js
1 /* @license
2 morris.js v0.5.1
3 Copyright 2014 Olly Smith All rights reserved.
4 Licensed under the BSD-2-Clause License.
5 */
6
7
8 (function() {
9   var $, Morris, minutesSpecHelper, secondsSpecHelper,
10     __slice = [].slice,
11     __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
12     __hasProp = {}.hasOwnProperty,
13     __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
14     __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
15
16   Morris = window.Morris = {};
17
18   $ = jQuery;
19
20   Morris.EventEmitter = (function() {
21     function EventEmitter() {}
22
23     EventEmitter.prototype.on = function(name, handler) {
24       if (this.handlers == null) {
25         this.handlers = {};
26       }
27       if (this.handlers[name] == null) {
28         this.handlers[name] = [];
29       }
30       this.handlers[name].push(handler);
31       return this;
32     };
33
34     EventEmitter.prototype.fire = function() {
35       var args, handler, name, _i, _len, _ref, _results;
36       name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
37       if ((this.handlers != null) && (this.handlers[name] != null)) {
38         _ref = this.handlers[name];
39         _results = [];
40         for (_i = 0, _len = _ref.length; _i < _len; _i++) {
41           handler = _ref[_i];
42           _results.push(handler.apply(null, args));
43         }
44         return _results;
45       }
46     };
47
48     return EventEmitter;
49
50   })();
51
52   Morris.commas = function(num) {
53     var absnum, intnum, ret, strabsnum;
54     if (num != null) {
55       ret = num < 0 ? "-" : "";
56       absnum = Math.abs(num);
57       intnum = Math.floor(absnum).toFixed(0);
58       ret += intnum.replace(/(?=(?:\d{3})+$)(?!^)/g, ',');
59       strabsnum = absnum.toString();
60       if (strabsnum.length > intnum.length) {
61         ret += strabsnum.slice(intnum.length);
62       }
63       return ret;
64     } else {
65       return '-';
66     }
67   };
68
69   Morris.pad2 = function(number) {
70     return (number < 10 ? '0' : '') + number;
71   };
72
73   Morris.Grid = (function(_super) {
74     __extends(Grid, _super);
75
76     function Grid(options) {
77       this.hasToShow = __bind(this.hasToShow, this);
78       this.resizeHandler = __bind(this.resizeHandler, this);
79       var _this = this;
80       if (typeof options.element === 'string') {
81         this.el = $(document.getElementById(options.element));
82       } else {
83         this.el = $(options.element);
84       }
85       if ((this.el == null) || this.el.length === 0) {
86         throw new Error("Graph container element not found");
87       }
88       if (this.el.css('position') === 'static') {
89         this.el.css('position', 'relative');
90       }
91       this.options = $.extend({}, this.gridDefaults, this.defaults || {}, options);
92       if (typeof this.options.units === 'string') {
93         this.options.postUnits = options.units;
94       }
95       this.raphael = new Raphael(this.el[0]);
96       this.elementWidth = null;
97       this.elementHeight = null;
98       this.dirty = false;
99       this.selectFrom = null;
100       if (this.init) {
101         this.init();
102       }
103       this.setData(this.options.data);
104       this.el.bind('mousemove', function(evt) {
105         var left, offset, right, width, x;
106         offset = _this.el.offset();
107         x = evt.pageX - offset.left;
108         if (_this.selectFrom) {
109           left = _this.data[_this.hitTest(Math.min(x, _this.selectFrom))]._x;
110           right = _this.data[_this.hitTest(Math.max(x, _this.selectFrom))]._x;
111           width = right - left;
112           return _this.selectionRect.attr({
113             x: left,
114             width: width
115           });
116         } else {
117           return _this.fire('hovermove', x, evt.pageY - offset.top);
118         }
119       });
120       this.el.bind('mouseleave', function(evt) {
121         if (_this.selectFrom) {
122           _this.selectionRect.hide();
123           _this.selectFrom = null;
124         }
125         return _this.fire('hoverout');
126       });
127       this.el.bind('touchstart touchmove touchend', function(evt) {
128         var offset, touch;
129         touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
130         offset = _this.el.offset();
131         return _this.fire('hovermove', touch.pageX - offset.left, touch.pageY - offset.top);
132       });
133       this.el.bind('click', function(evt) {
134         var offset;
135         offset = _this.el.offset();
136         return _this.fire('gridclick', evt.pageX - offset.left, evt.pageY - offset.top);
137       });
138       if (this.options.rangeSelect) {
139         this.selectionRect = this.raphael.rect(0, 0, 0, this.el.innerHeight()).attr({
140           fill: this.options.rangeSelectColor,
141           stroke: false
142         }).toBack().hide();
143         this.el.bind('mousedown', function(evt) {
144           var offset;
145           offset = _this.el.offset();
146           return _this.startRange(evt.pageX - offset.left);
147         });
148         this.el.bind('mouseup', function(evt) {
149           var offset;
150           offset = _this.el.offset();
151           _this.endRange(evt.pageX - offset.left);
152           return _this.fire('hovermove', evt.pageX - offset.left, evt.pageY - offset.top);
153         });
154       }
155       if (this.options.resize) {
156         $(window).bind('resize', function(evt) {
157           if (_this.timeoutId != null) {
158             window.clearTimeout(_this.timeoutId);
159           }
160           return _this.timeoutId = window.setTimeout(_this.resizeHandler, 100);
161         });
162       }
163       this.el.css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
164       if (this.postInit) {
165         this.postInit();
166       }
167     }
168
169     Grid.prototype.gridDefaults = {
170       dateFormat: null,
171       axes: true,
172       grid: true,
173       gridLineColor: '#aaa',
174       gridStrokeWidth: 0.5,
175       gridTextColor: '#888',
176       gridTextSize: 12,
177       gridTextFamily: 'sans-serif',
178       gridTextWeight: 'normal',
179       hideHover: false,
180       yLabelFormat: null,
181       xLabelAngle: 0,
182       numLines: 5,
183       padding: 25,
184       parseTime: true,
185       postUnits: '',
186       preUnits: '',
187       ymax: 'auto',
188       ymin: 'auto 0',
189       goals: [],
190       goalStrokeWidth: 1.0,
191       goalLineColors: ['#666633', '#999966', '#cc6666', '#663333'],
192       events: [],
193       eventStrokeWidth: 1.0,
194       eventLineColors: ['#005a04', '#ccffbb', '#3a5f0b', '#005502'],
195       rangeSelect: null,
196       rangeSelectColor: '#eef',
197       resize: false
198     };
199
200     Grid.prototype.setData = function(data, redraw) {
201       var e, flatEvents, from, idx, index, maxGoal, minGoal, ret, row, step, to, total, y, ykey, ymax, ymin, yval, _i, _len, _ref, _ref1;
202       if (redraw == null) {
203         redraw = true;
204       }
205       this.options.data = data;
206       if ((data == null) || data.length === 0) {
207         this.data = [];
208         this.raphael.clear();
209         if (this.hover != null) {
210           this.hover.hide();
211         }
212         return;
213       }
214       ymax = this.cumulative ? 0 : null;
215       ymin = this.cumulative ? 0 : null;
216       if (this.options.goals.length > 0) {
217         minGoal = Math.min.apply(Math, this.options.goals);
218         maxGoal = Math.max.apply(Math, this.options.goals);
219         ymin = ymin != null ? Math.min(ymin, minGoal) : minGoal;
220         ymax = ymax != null ? Math.max(ymax, maxGoal) : maxGoal;
221       }
222       this.data = (function() {
223         var _i, _len, _results;
224         _results = [];
225         for (index = _i = 0, _len = data.length; _i < _len; index = ++_i) {
226           row = data[index];
227           ret = {
228             src: row
229           };
230           ret.label = row[this.options.xkey];
231           if (this.options.parseTime) {
232             ret.x = Morris.parseDate(ret.label);
233             if (this.options.dateFormat) {
234               ret.label = this.options.dateFormat(ret.x);
235             } else if (typeof ret.label === 'number') {
236               ret.label = new Date(ret.label).toString();
237             }
238           } else {
239             ret.x = index;
240             if (this.options.xLabelFormat) {
241               ret.label = this.options.xLabelFormat(ret);
242             }
243           }
244           total = 0;
245           ret.y = (function() {
246             var _j, _len1, _ref, _results1;
247             _ref = this.options.ykeys;
248             _results1 = [];
249             for (idx = _j = 0, _len1 = _ref.length; _j < _len1; idx = ++_j) {
250               ykey = _ref[idx];
251               yval = row[ykey];
252               if (typeof yval === 'string') {
253                 yval = parseFloat(yval);
254               }
255               if ((yval != null) && typeof yval !== 'number') {
256                 yval = null;
257               }
258               if ((yval != null) && this.hasToShow(idx)) {
259                 if (this.cumulative) {
260                   total += yval;
261                 } else {
262                   if (ymax != null) {
263                     ymax = Math.max(yval, ymax);
264                     ymin = Math.min(yval, ymin);
265                   } else {
266                     ymax = ymin = yval;
267                   }
268                 }
269               }
270               if (this.cumulative && (total != null)) {
271                 ymax = Math.max(total, ymax);
272                 ymin = Math.min(total, ymin);
273               }
274               _results1.push(yval);
275             }
276             return _results1;
277           }).call(this);
278           _results.push(ret);
279         }
280         return _results;
281       }).call(this);
282       if (this.options.parseTime) {
283         this.data = this.data.sort(function(a, b) {
284           return (a.x > b.x) - (b.x > a.x);
285         });
286       }
287       this.xmin = this.data[0].x;
288       this.xmax = this.data[this.data.length - 1].x;
289       this.events = [];
290       if (this.options.events.length > 0) {
291         if (this.options.parseTime) {
292           _ref = this.options.events;
293           for (_i = 0, _len = _ref.length; _i < _len; _i++) {
294             e = _ref[_i];
295             if (e instanceof Array) {
296               from = e[0], to = e[1];
297               this.events.push([Morris.parseDate(from), Morris.parseDate(to)]);
298             } else {
299               this.events.push(Morris.parseDate(e));
300             }
301           }
302         } else {
303           this.events = this.options.events;
304         }
305         flatEvents = $.map(this.events, function(e) {
306           return e;
307         });
308         this.xmax = Math.max(this.xmax, Math.max.apply(Math, flatEvents));
309         this.xmin = Math.min(this.xmin, Math.min.apply(Math, flatEvents));
310       }
311       if (this.xmin === this.xmax) {
312         this.xmin -= 1;
313         this.xmax += 1;
314       }
315       this.ymin = this.yboundary('min', ymin);
316       this.ymax = this.yboundary('max', ymax);
317       if (this.ymin === this.ymax) {
318         if (ymin) {
319           this.ymin -= 1;
320         }
321         this.ymax += 1;
322       }
323       if (((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'y') || this.options.grid === true) {
324         if (this.options.ymax === this.gridDefaults.ymax && this.options.ymin === this.gridDefaults.ymin) {
325           this.grid = this.autoGridLines(this.ymin, this.ymax, this.options.numLines);
326           this.ymin = Math.min(this.ymin, this.grid[0]);
327           this.ymax = Math.max(this.ymax, this.grid[this.grid.length - 1]);
328         } else {
329           step = (this.ymax - this.ymin) / (this.options.numLines - 1);
330           this.grid = (function() {
331             var _j, _ref2, _ref3, _results;
332             _results = [];
333             for (y = _j = _ref2 = this.ymin, _ref3 = this.ymax; step > 0 ? _j <= _ref3 : _j >= _ref3; y = _j += step) {
334               _results.push(y);
335             }
336             return _results;
337           }).call(this);
338         }
339       }
340       this.dirty = true;
341       if (redraw) {
342         return this.redraw();
343       }
344     };
345
346     Grid.prototype.yboundary = function(boundaryType, currentValue) {
347       var boundaryOption, suggestedValue;
348       boundaryOption = this.options["y" + boundaryType];
349       if (typeof boundaryOption === 'string') {
350         if (boundaryOption.slice(0, 4) === 'auto') {
351           if (boundaryOption.length > 5) {
352             suggestedValue = parseInt(boundaryOption.slice(5), 10);
353             if (currentValue == null) {
354               return suggestedValue;
355             }
356             return Math[boundaryType](currentValue, suggestedValue);
357           } else {
358             if (currentValue != null) {
359               return currentValue;
360             } else {
361               return 0;
362             }
363           }
364         } else {
365           return parseInt(boundaryOption, 10);
366         }
367       } else {
368         return boundaryOption;
369       }
370     };
371
372     Grid.prototype.autoGridLines = function(ymin, ymax, nlines) {
373       var gmax, gmin, grid, smag, span, step, unit, y, ymag;
374       span = ymax - ymin;
375       ymag = Math.floor(Math.log(span) / Math.log(10));
376       unit = Math.pow(10, ymag);
377       gmin = Math.floor(ymin / unit) * unit;
378       gmax = Math.ceil(ymax / unit) * unit;
379       step = (gmax - gmin) / (nlines - 1);
380       if (unit === 1 && step > 1 && Math.ceil(step) !== step) {
381         step = Math.ceil(step);
382         gmax = gmin + step * (nlines - 1);
383       }
384       if (gmin < 0 && gmax > 0) {
385         gmin = Math.floor(ymin / step) * step;
386         gmax = Math.ceil(ymax / step) * step;
387       }
388       if (step < 1) {
389         smag = Math.floor(Math.log(step) / Math.log(10));
390         grid = (function() {
391           var _i, _results;
392           _results = [];
393           for (y = _i = gmin; step > 0 ? _i <= gmax : _i >= gmax; y = _i += step) {
394             _results.push(parseFloat(y.toFixed(1 - smag)));
395           }
396           return _results;
397         })();
398       } else {
399         grid = (function() {
400           var _i, _results;
401           _results = [];
402           for (y = _i = gmin; step > 0 ? _i <= gmax : _i >= gmax; y = _i += step) {
403             _results.push(y);
404           }
405           return _results;
406         })();
407       }
408       return grid;
409     };
410
411     Grid.prototype._calc = function() {
412       var angle, bottomOffsets, gridLine, h, i, w, yLabelWidths, _ref, _ref1;
413       w = this.el.width();
414       h = this.el.height();
415       if (this.elementWidth !== w || this.elementHeight !== h || this.dirty) {
416         this.elementWidth = w;
417         this.elementHeight = h;
418         this.dirty = false;
419         this.left = this.options.padding;
420         this.right = this.elementWidth - this.options.padding;
421         this.top = this.options.padding;
422         this.bottom = this.elementHeight - this.options.padding;
423         if ((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'y') {
424           yLabelWidths = (function() {
425             var _i, _len, _ref1, _results;
426             _ref1 = this.grid;
427             _results = [];
428             for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
429               gridLine = _ref1[_i];
430               _results.push(this.measureText(this.yAxisFormat(gridLine)).width);
431             }
432             return _results;
433           }).call(this);
434           if (!this.options.horizontal) {
435             this.left += Math.max.apply(Math, yLabelWidths);
436           } else {
437             this.bottom -= Math.max.apply(Math, yLabelWidths);
438           }
439         }
440         if ((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'x') {
441           if (!this.options.horizontal) {
442             angle = -this.options.xLabelAngle;
443           } else {
444             angle = -90;
445           }
446           bottomOffsets = (function() {
447             var _i, _ref2, _results;
448             _results = [];
449             for (i = _i = 0, _ref2 = this.data.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {
450               _results.push(this.measureText(this.data[i].label, angle).height);
451             }
452             return _results;
453           }).call(this);
454           if (!this.options.horizontal) {
455             this.bottom -= Math.max.apply(Math, bottomOffsets);
456           } else {
457             this.left += Math.max.apply(Math, bottomOffsets);
458           }
459         }
460         this.width = Math.max(1, this.right - this.left);
461         this.height = Math.max(1, this.bottom - this.top);
462         if (!this.options.horizontal) {
463           this.dx = this.width / (this.xmax - this.xmin);
464           this.dy = this.height / (this.ymax - this.ymin);
465           this.yStart = this.bottom;
466           this.yEnd = this.top;
467           this.xStart = this.left;
468           this.xEnd = this.right;
469           this.xSize = this.width;
470           this.ySize = this.height;
471         } else {
472           this.dx = this.height / (this.xmax - this.xmin);
473           this.dy = this.width / (this.ymax - this.ymin);
474           this.yStart = this.left;
475           this.yEnd = this.right;
476           this.xStart = this.top;
477           this.xEnd = this.bottom;
478           this.xSize = this.height;
479           this.ySize = this.width;
480         }
481         if (this.calc) {
482           return this.calc();
483         }
484       }
485     };
486
487     Grid.prototype.transY = function(y) {
488       if (!this.options.horizontal) {
489         return this.bottom - (y - this.ymin) * this.dy;
490       } else {
491         return this.left + (y - this.ymin) * this.dy;
492       }
493     };
494
495     Grid.prototype.transX = function(x) {
496       if (this.data.length === 1) {
497         return (this.xStart + this.xEnd) / 2;
498       } else {
499         return this.xStart + (x - this.xmin) * this.dx;
500       }
501     };
502
503     Grid.prototype.redraw = function() {
504       this.raphael.clear();
505       this._calc();
506       this.drawGrid();
507       this.drawGoals();
508       this.drawEvents();
509       if (this.draw) {
510         return this.draw();
511       }
512     };
513
514     Grid.prototype.measureText = function(text, angle) {
515       var ret, tt;
516       if (angle == null) {
517         angle = 0;
518       }
519       tt = this.raphael.text(100, 100, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).rotate(angle);
520       ret = tt.getBBox();
521       tt.remove();
522       return ret;
523     };
524
525     Grid.prototype.yAxisFormat = function(label) {
526       return this.yLabelFormat(label, 0);
527     };
528
529     Grid.prototype.yLabelFormat = function(label, i) {
530       if (typeof this.options.yLabelFormat === 'function') {
531         return this.options.yLabelFormat(label, i);
532       } else {
533         return "" + this.options.preUnits + (Morris.commas(label)) + this.options.postUnits;
534       }
535     };
536
537     Grid.prototype.getYAxisLabelX = function() {
538       return this.left - this.options.padding / 2;
539     };
540
541     Grid.prototype.drawGrid = function() {
542       var basePos, lineY, pos, _i, _len, _ref, _ref1, _ref2, _results;
543       if (this.options.grid === false && ((_ref = this.options.axes) !== true && _ref !== 'both' && _ref !== 'y')) {
544         return;
545       }
546       if (!this.options.horizontal) {
547         basePos = this.getYAxisLabelX();
548       } else {
549         basePos = this.getXAxisLabelY();
550       }
551       _ref1 = this.grid;
552       _results = [];
553       for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
554         lineY = _ref1[_i];
555         pos = this.transY(lineY);
556         if ((_ref2 = this.options.axes) === true || _ref2 === 'both' || _ref2 === 'y') {
557           if (!this.options.horizontal) {
558             this.drawYAxisLabel(basePos, pos, this.yAxisFormat(lineY));
559           } else {
560             this.drawXAxisLabel(pos, basePos, this.yAxisFormat(lineY));
561           }
562         }
563         if (this.options.grid) {
564           pos = Math.floor(pos) + 0.5;
565           if (!this.options.horizontal) {
566             _results.push(this.drawGridLine("M" + this.xStart + "," + pos + "H" + this.xEnd));
567           } else {
568             _results.push(this.drawGridLine("M" + pos + "," + this.xStart + "V" + this.xEnd));
569           }
570         } else {
571           _results.push(void 0);
572         }
573       }
574       return _results;
575     };
576
577     Grid.prototype.drawGoals = function() {
578       var color, goal, i, _i, _len, _ref, _results;
579       _ref = this.options.goals;
580       _results = [];
581       for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
582         goal = _ref[i];
583         color = this.options.goalLineColors[i % this.options.goalLineColors.length];
584         _results.push(this.drawGoal(goal, color));
585       }
586       return _results;
587     };
588
589     Grid.prototype.drawEvents = function() {
590       var color, event, i, _i, _len, _ref, _results;
591       _ref = this.events;
592       _results = [];
593       for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
594         event = _ref[i];
595         color = this.options.eventLineColors[i % this.options.eventLineColors.length];
596         _results.push(this.drawEvent(event, color));
597       }
598       return _results;
599     };
600
601     Grid.prototype.drawGoal = function(goal, color) {
602       var path, y;
603       y = Math.floor(this.transY(goal)) + 0.5;
604       if (!this.options.horizontal) {
605         path = "M" + this.xStart + "," + y + "H" + this.xEnd;
606       } else {
607         path = "M" + y + "," + this.xStart + "V" + this.xEnd;
608       }
609       return this.raphael.path(path).attr('stroke', color).attr('stroke-width', this.options.goalStrokeWidth);
610     };
611
612     Grid.prototype.drawEvent = function(event, color) {
613       var from, path, to, x;
614       if (event instanceof Array) {
615         from = event[0], to = event[1];
616         from = Math.floor(this.transX(from)) + 0.5;
617         to = Math.floor(this.transX(to)) + 0.5;
618         if (!this.options.horizontal) {
619           return this.raphael.rect(from, this.yEnd, to - from, this.yStart - this.yEnd).attr({
620             fill: color,
621             stroke: false
622           }).toBack();
623         } else {
624           return this.raphael.rect(this.yStart, from, this.yEnd - this.yStart, to - from).attr({
625             fill: color,
626             stroke: false
627           }).toBack();
628         }
629       } else {
630         x = Math.floor(this.transX(event)) + 0.5;
631         if (!this.options.horizontal) {
632           path = "M" + x + "," + this.yStart + "V" + this.yEnd;
633         } else {
634           path = "M" + this.yStart + "," + x + "H" + this.yEnd;
635         }
636         return this.raphael.path(path).attr('stroke', color).attr('stroke-width', this.options.eventStrokeWidth);
637       }
638     };
639
640     Grid.prototype.drawYAxisLabel = function(xPos, yPos, text) {
641       return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end');
642     };
643
644     Grid.prototype.drawGridLine = function(path) {
645       return this.raphael.path(path).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth);
646     };
647
648     Grid.prototype.startRange = function(x) {
649       this.hover.hide();
650       this.selectFrom = x;
651       return this.selectionRect.attr({
652         x: x,
653         width: 0
654       }).show();
655     };
656
657     Grid.prototype.endRange = function(x) {
658       var end, start;
659       if (this.selectFrom) {
660         start = Math.min(this.selectFrom, x);
661         end = Math.max(this.selectFrom, x);
662         this.options.rangeSelect.call(this.el, {
663           start: this.data[this.hitTest(start)].x,
664           end: this.data[this.hitTest(end)].x
665         });
666         return this.selectFrom = null;
667       }
668     };
669
670     Grid.prototype.resizeHandler = function() {
671       this.timeoutId = null;
672       this.raphael.setSize(this.el.width(), this.el.height());
673       return this.redraw();
674     };
675
676     Grid.prototype.hasToShow = function(i) {
677       return this.options.shown === true || this.options.shown[i] === true;
678     };
679
680     return Grid;
681
682   })(Morris.EventEmitter);
683
684   Morris.parseDate = function(date) {
685     var isecs, m, msecs, n, o, offsetmins, p, q, r, ret, secs;
686     if (typeof date === 'number') {
687       return date;
688     }
689     m = date.match(/^(\d+) Q(\d)$/);
690     n = date.match(/^(\d+)-(\d+)$/);
691     o = date.match(/^(\d+)-(\d+)-(\d+)$/);
692     p = date.match(/^(\d+) W(\d+)$/);
693     q = date.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+)(Z|([+-])(\d\d):?(\d\d))?$/);
694     r = date.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+):(\d+(\.\d+)?)(Z|([+-])(\d\d):?(\d\d))?$/);
695     if (m) {
696       return new Date(parseInt(m[1], 10), parseInt(m[2], 10) * 3 - 1, 1).getTime();
697     } else if (n) {
698       return new Date(parseInt(n[1], 10), parseInt(n[2], 10) - 1, 1).getTime();
699     } else if (o) {
700       return new Date(parseInt(o[1], 10), parseInt(o[2], 10) - 1, parseInt(o[3], 10)).getTime();
701     } else if (p) {
702       ret = new Date(parseInt(p[1], 10), 0, 1);
703       if (ret.getDay() !== 4) {
704         ret.setMonth(0, 1 + ((4 - ret.getDay()) + 7) % 7);
705       }
706       return ret.getTime() + parseInt(p[2], 10) * 604800000;
707     } else if (q) {
708       if (!q[6]) {
709         return new Date(parseInt(q[1], 10), parseInt(q[2], 10) - 1, parseInt(q[3], 10), parseInt(q[4], 10), parseInt(q[5], 10)).getTime();
710       } else {
711         offsetmins = 0;
712         if (q[6] !== 'Z') {
713           offsetmins = parseInt(q[8], 10) * 60 + parseInt(q[9], 10);
714           if (q[7] === '+') {
715             offsetmins = 0 - offsetmins;
716           }
717         }
718         return Date.UTC(parseInt(q[1], 10), parseInt(q[2], 10) - 1, parseInt(q[3], 10), parseInt(q[4], 10), parseInt(q[5], 10) + offsetmins);
719       }
720     } else if (r) {
721       secs = parseFloat(r[6]);
722       isecs = Math.floor(secs);
723       msecs = Math.round((secs - isecs) * 1000);
724       if (!r[8]) {
725         return new Date(parseInt(r[1], 10), parseInt(r[2], 10) - 1, parseInt(r[3], 10), parseInt(r[4], 10), parseInt(r[5], 10), isecs, msecs).getTime();
726       } else {
727         offsetmins = 0;
728         if (r[8] !== 'Z') {
729           offsetmins = parseInt(r[10], 10) * 60 + parseInt(r[11], 10);
730           if (r[9] === '+') {
731             offsetmins = 0 - offsetmins;
732           }
733         }
734         return Date.UTC(parseInt(r[1], 10), parseInt(r[2], 10) - 1, parseInt(r[3], 10), parseInt(r[4], 10), parseInt(r[5], 10) + offsetmins, isecs, msecs);
735       }
736     } else {
737       return new Date(parseInt(date, 10), 0, 1).getTime();
738     }
739   };
740
741   Morris.Hover = (function() {
742     Hover.defaults = {
743       "class": 'morris-hover morris-default-style'
744     };
745
746     function Hover(options) {
747       if (options == null) {
748         options = {};
749       }
750       this.options = $.extend({}, Morris.Hover.defaults, options);
751       this.el = $("<div class='" + this.options["class"] + "'></div>");
752       this.el.hide();
753       this.options.parent.append(this.el);
754     }
755
756     Hover.prototype.update = function(html, x, y, centre_y) {
757       if (!html) {
758         return this.hide();
759       } else {
760         this.html(html);
761         this.show();
762         return this.moveTo(x, y, centre_y);
763       }
764     };
765
766     Hover.prototype.html = function(content) {
767       return this.el.html(content);
768     };
769
770     Hover.prototype.moveTo = function(x, y, centre_y) {
771       var hoverHeight, hoverWidth, left, parentHeight, parentWidth, top;
772       parentWidth = this.options.parent.innerWidth();
773       parentHeight = this.options.parent.innerHeight();
774       hoverWidth = this.el.outerWidth();
775       hoverHeight = this.el.outerHeight();
776       left = Math.min(Math.max(0, x - hoverWidth / 2), parentWidth - hoverWidth);
777       if (y != null) {
778         if (centre_y === true) {
779           top = y - hoverHeight / 2;
780           if (top < 0) {
781             top = 0;
782           }
783         } else {
784           top = y - hoverHeight - 10;
785           if (top < 0) {
786             top = y + 10;
787             if (top + hoverHeight > parentHeight) {
788               top = parentHeight / 2 - hoverHeight / 2;
789             }
790           }
791         }
792       } else {
793         top = parentHeight / 2 - hoverHeight / 2;
794       }
795       return this.el.css({
796         left: left + "px",
797         top: parseInt(top) + "px"
798       });
799     };
800
801     Hover.prototype.show = function() {
802       return this.el.show();
803     };
804
805     Hover.prototype.hide = function() {
806       return this.el.hide();
807     };
808
809     return Hover;
810
811   })();
812
813   Morris.Line = (function(_super) {
814     __extends(Line, _super);
815
816     function Line(options) {
817       this.hilight = __bind(this.hilight, this);
818       this.onHoverOut = __bind(this.onHoverOut, this);
819       this.onHoverMove = __bind(this.onHoverMove, this);
820       this.onGridClick = __bind(this.onGridClick, this);
821       if (!(this instanceof Morris.Line)) {
822         return new Morris.Line(options);
823       }
824       Line.__super__.constructor.call(this, options);
825     }
826
827     Line.prototype.init = function() {
828       if (this.options.hideHover !== 'always') {
829         this.hover = new Morris.Hover({
830           parent: this.el
831         });
832         this.on('hovermove', this.onHoverMove);
833         this.on('hoverout', this.onHoverOut);
834         return this.on('gridclick', this.onGridClick);
835       }
836     };
837
838     Line.prototype.defaults = {
839       lineWidth: 3,
840       pointSize: 4,
841       lineColors: ['#0b62a4', '#7A92A3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
842       pointStrokeWidths: [1],
843       pointStrokeColors: ['#ffffff'],
844       pointFillColors: [],
845       smooth: true,
846       shown: true,
847       xLabels: 'auto',
848       xLabelFormat: null,
849       xLabelMargin: 24,
850       hideHover: false,
851       trendLine: false,
852       trendLineWidth: 2,
853       trendLineColors: ['#689bc3', '#a2b3bf', '#64b764']
854     };
855
856     Line.prototype.calc = function() {
857       this.calcPoints();
858       return this.generatePaths();
859     };
860
861     Line.prototype.calcPoints = function() {
862       var row, y, _i, _len, _ref, _results;
863       _ref = this.data;
864       _results = [];
865       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
866         row = _ref[_i];
867         row._x = this.transX(row.x);
868         row._y = (function() {
869           var _j, _len1, _ref1, _results1;
870           _ref1 = row.y;
871           _results1 = [];
872           for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
873             y = _ref1[_j];
874             if (y != null) {
875               _results1.push(this.transY(y));
876             } else {
877               _results1.push(y);
878             }
879           }
880           return _results1;
881         }).call(this);
882         _results.push(row._ymax = Math.min.apply(Math, [this.bottom].concat((function() {
883           var _j, _len1, _ref1, _results1;
884           _ref1 = row._y;
885           _results1 = [];
886           for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
887             y = _ref1[_j];
888             if (y != null) {
889               _results1.push(y);
890             }
891           }
892           return _results1;
893         })())));
894       }
895       return _results;
896     };
897
898     Line.prototype.hitTest = function(x) {
899       var index, r, _i, _len, _ref;
900       if (this.data.length === 0) {
901         return null;
902       }
903       _ref = this.data.slice(1);
904       for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
905         r = _ref[index];
906         if (x < (r._x + this.data[index]._x) / 2) {
907           break;
908         }
909       }
910       return index;
911     };
912
913     Line.prototype.onGridClick = function(x, y) {
914       var index;
915       index = this.hitTest(x);
916       return this.fire('click', index, this.data[index].src, x, y);
917     };
918
919     Line.prototype.onHoverMove = function(x, y) {
920       var index;
921       index = this.hitTest(x);
922       return this.displayHoverForRow(index);
923     };
924
925     Line.prototype.onHoverOut = function() {
926       if (this.options.hideHover !== false) {
927         return this.displayHoverForRow(null);
928       }
929     };
930
931     Line.prototype.displayHoverForRow = function(index) {
932       var _ref;
933       if (index != null) {
934         (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));
935         return this.hilight(index);
936       } else {
937         this.hover.hide();
938         return this.hilight();
939       }
940     };
941
942     Line.prototype.hoverContentForRow = function(index) {
943       var content, j, row, y, _i, _len, _ref;
944       row = this.data[index];
945       content = $("<div class='morris-hover-row-label'>").text(row.label);
946       content = content.prop('outerHTML');
947       _ref = row.y;
948       for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
949         y = _ref[j];
950         if (this.options.labels[j] === false) {
951           continue;
952         }
953         content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n  " + this.options.labels[j] + ":\n  " + (this.yLabelFormat(y, j)) + "\n</div>";
954       }
955       if (typeof this.options.hoverCallback === 'function') {
956         content = this.options.hoverCallback(index, this.options, content, row.src);
957       }
958       return [content, row._x, row._ymax];
959     };
960
961     Line.prototype.generatePaths = function() {
962       var coords, i, r, smooth;
963       return this.paths = (function() {
964         var _i, _ref, _ref1, _results;
965         _results = [];
966         for (i = _i = 0, _ref = this.options.ykeys.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
967           smooth = typeof this.options.smooth === "boolean" ? this.options.smooth : (_ref1 = this.options.ykeys[i], __indexOf.call(this.options.smooth, _ref1) >= 0);
968           coords = (function() {
969             var _j, _len, _ref2, _results1;
970             _ref2 = this.data;
971             _results1 = [];
972             for (_j = 0, _len = _ref2.length; _j < _len; _j++) {
973               r = _ref2[_j];
974               if (r._y[i] !== void 0) {
975                 _results1.push({
976                   x: r._x,
977                   y: r._y[i]
978                 });
979               }
980             }
981             return _results1;
982           }).call(this);
983           if (coords.length > 1) {
984             _results.push(Morris.Line.createPath(coords, smooth, this.bottom));
985           } else {
986             _results.push(null);
987           }
988         }
989         return _results;
990       }).call(this);
991     };
992
993     Line.prototype.draw = function() {
994       var _ref;
995       if ((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'x') {
996         this.drawXAxis();
997       }
998       this.drawSeries();
999       if (this.options.hideHover === false) {
1000         return this.displayHoverForRow(this.data.length - 1);
1001       }
1002     };
1003
1004     Line.prototype.drawXAxis = function() {
1005       var drawLabel, l, labels, prevAngleMargin, prevLabelMargin, row, ypos, _i, _len, _results,
1006         _this = this;
1007       ypos = this.bottom + this.options.padding / 2;
1008       prevLabelMargin = null;
1009       prevAngleMargin = null;
1010       drawLabel = function(labelText, xpos) {
1011         var label, labelBox, margin, offset, textBox;
1012         label = _this.drawXAxisLabel(_this.transX(xpos), ypos, labelText);
1013         textBox = label.getBBox();
1014         label.transform("r" + (-_this.options.xLabelAngle));
1015         labelBox = label.getBBox();
1016         label.transform("t0," + (labelBox.height / 2) + "...");
1017         if (_this.options.xLabelAngle !== 0) {
1018           offset = -0.5 * textBox.width * Math.cos(_this.options.xLabelAngle * Math.PI / 180.0);
1019           label.transform("t" + offset + ",0...");
1020         }
1021         labelBox = label.getBBox();
1022         if (((prevLabelMargin == null) || prevLabelMargin >= labelBox.x + labelBox.width || (prevAngleMargin != null) && prevAngleMargin >= labelBox.x) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < _this.el.width()) {
1023           if (_this.options.xLabelAngle !== 0) {
1024             margin = 1.25 * _this.options.gridTextSize / Math.sin(_this.options.xLabelAngle * Math.PI / 180.0);
1025             prevAngleMargin = labelBox.x - margin;
1026           }
1027           return prevLabelMargin = labelBox.x - _this.options.xLabelMargin;
1028         } else {
1029           return label.remove();
1030         }
1031       };
1032       if (this.options.parseTime) {
1033         if (this.data.length === 1 && this.options.xLabels === 'auto') {
1034           labels = [[this.data[0].label, this.data[0].x]];
1035         } else {
1036           labels = Morris.labelSeries(this.xmin, this.xmax, this.width, this.options.xLabels, this.options.xLabelFormat);
1037         }
1038       } else {
1039         labels = (function() {
1040           var _i, _len, _ref, _results;
1041           _ref = this.data;
1042           _results = [];
1043           for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1044             row = _ref[_i];
1045             _results.push([row.label, row.x]);
1046           }
1047           return _results;
1048         }).call(this);
1049       }
1050       labels.reverse();
1051       _results = [];
1052       for (_i = 0, _len = labels.length; _i < _len; _i++) {
1053         l = labels[_i];
1054         _results.push(drawLabel(l[0], l[1]));
1055       }
1056       return _results;
1057     };
1058
1059     Line.prototype.drawSeries = function() {
1060       var i, _i, _j, _ref, _ref1, _results;
1061       this.seriesPoints = [];
1062       for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
1063         if (this.hasToShow(i)) {
1064           if (this.options.trendLine !== false && this.options.trendLine === true || this.options.trendLine[i] === true) {
1065             this._drawTrendLine(i);
1066           }
1067           this._drawLineFor(i);
1068         }
1069       }
1070       _results = [];
1071       for (i = _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {
1072         if (this.hasToShow(i)) {
1073           _results.push(this._drawPointFor(i));
1074         } else {
1075           _results.push(void 0);
1076         }
1077       }
1078       return _results;
1079     };
1080
1081     Line.prototype._drawPointFor = function(index) {
1082       var circle, row, _i, _len, _ref, _results;
1083       this.seriesPoints[index] = [];
1084       _ref = this.data;
1085       _results = [];
1086       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1087         row = _ref[_i];
1088         circle = null;
1089         if (row._y[index] != null) {
1090           circle = this.drawLinePoint(row._x, row._y[index], this.colorFor(row, index, 'point'), index);
1091         }
1092         _results.push(this.seriesPoints[index].push(circle));
1093       }
1094       return _results;
1095     };
1096
1097     Line.prototype._drawLineFor = function(index) {
1098       var path;
1099       path = this.paths[index];
1100       if (path !== null) {
1101         return this.drawLinePath(path, this.colorFor(null, index, 'line'), index);
1102       }
1103     };
1104
1105     Line.prototype._drawTrendLine = function(index) {
1106       var a, b, data, datapoints, path, sum_x, sum_xx, sum_xy, sum_y, val, x, y, _i, _len, _ref;
1107       sum_x = 0;
1108       sum_y = 0;
1109       sum_xx = 0;
1110       sum_xy = 0;
1111       datapoints = 0;
1112       _ref = this.data;
1113       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1114         val = _ref[_i];
1115         x = val.x;
1116         y = val.y[index];
1117         if (y === void 0) {
1118           continue;
1119         }
1120         datapoints += 1;
1121         sum_x += x;
1122         sum_y += y;
1123         sum_xx += x * x;
1124         sum_xy += x * y;
1125       }
1126       a = (datapoints * sum_xy - sum_x * sum_y) / (datapoints * sum_xx - sum_x * sum_x);
1127       b = (sum_y / datapoints) - ((a * sum_x) / datapoints);
1128       data = [{}, {}];
1129       data[0].x = this.transX(this.data[0].x);
1130       data[0].y = this.transY(this.data[0].x * a + b);
1131       data[1].x = this.transX(this.data[this.data.length - 1].x);
1132       data[1].y = this.transY(this.data[this.data.length - 1].x * a + b);
1133       path = Morris.Line.createPath(data, false, this.bottom);
1134       return path = this.raphael.path(path).attr('stroke', this.colorFor(null, index, 'trendLine')).attr('stroke-width', this.options.trendLineWidth);
1135     };
1136
1137     Line.createPath = function(coords, smooth, bottom) {
1138       var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;
1139       path = "";
1140       if (smooth) {
1141         grads = Morris.Line.gradients(coords);
1142       }
1143       prevCoord = {
1144         y: null
1145       };
1146       for (i = _i = 0, _len = coords.length; _i < _len; i = ++_i) {
1147         coord = coords[i];
1148         if (coord.y != null) {
1149           if (prevCoord.y != null) {
1150             if (smooth) {
1151               g = grads[i];
1152               lg = grads[i - 1];
1153               ix = (coord.x - prevCoord.x) / 4;
1154               x1 = prevCoord.x + ix;
1155               y1 = Math.min(bottom, prevCoord.y + ix * lg);
1156               x2 = coord.x - ix;
1157               y2 = Math.min(bottom, coord.y - ix * g);
1158               path += "C" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + coord.x + "," + coord.y;
1159             } else {
1160               path += "L" + coord.x + "," + coord.y;
1161             }
1162           } else {
1163             if (!smooth || (grads[i] != null)) {
1164               path += "M" + coord.x + "," + coord.y;
1165             }
1166           }
1167         }
1168         prevCoord = coord;
1169       }
1170       return path;
1171     };
1172
1173     Line.gradients = function(coords) {
1174       var coord, grad, i, nextCoord, prevCoord, _i, _len, _results;
1175       grad = function(a, b) {
1176         return (a.y - b.y) / (a.x - b.x);
1177       };
1178       _results = [];
1179       for (i = _i = 0, _len = coords.length; _i < _len; i = ++_i) {
1180         coord = coords[i];
1181         if (coord.y != null) {
1182           nextCoord = coords[i + 1] || {
1183             y: null
1184           };
1185           prevCoord = coords[i - 1] || {
1186             y: null
1187           };
1188           if ((prevCoord.y != null) && (nextCoord.y != null)) {
1189             _results.push(grad(prevCoord, nextCoord));
1190           } else if (prevCoord.y != null) {
1191             _results.push(grad(prevCoord, coord));
1192           } else if (nextCoord.y != null) {
1193             _results.push(grad(coord, nextCoord));
1194           } else {
1195             _results.push(null);
1196           }
1197         } else {
1198           _results.push(null);
1199         }
1200       }
1201       return _results;
1202     };
1203
1204     Line.prototype.hilight = function(index) {
1205       var i, _i, _j, _ref, _ref1;
1206       if (this.prevHilight !== null && this.prevHilight !== index) {
1207         for (i = _i = 0, _ref = this.seriesPoints.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
1208           if (this.seriesPoints[i][this.prevHilight]) {
1209             this.seriesPoints[i][this.prevHilight].animate(this.pointShrinkSeries(i));
1210           }
1211         }
1212       }
1213       if (index !== null && this.prevHilight !== index) {
1214         for (i = _j = 0, _ref1 = this.seriesPoints.length - 1; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
1215           if (this.seriesPoints[i][index]) {
1216             this.seriesPoints[i][index].animate(this.pointGrowSeries(i));
1217           }
1218         }
1219       }
1220       return this.prevHilight = index;
1221     };
1222
1223     Line.prototype.colorFor = function(row, sidx, type) {
1224       if (typeof this.options.lineColors === 'function') {
1225         return this.options.lineColors.call(this, row, sidx, type);
1226       } else if (type === 'point') {
1227         return this.options.pointFillColors[sidx % this.options.pointFillColors.length] || this.options.lineColors[sidx % this.options.lineColors.length];
1228       } else if (type === 'line') {
1229         return this.options.lineColors[sidx % this.options.lineColors.length];
1230       } else {
1231         return this.options.trendLineColors[sidx % this.options.trendLineColors.length];
1232       }
1233     };
1234
1235     Line.prototype.drawXAxisLabel = function(xPos, yPos, text) {
1236       return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).attr('fill', this.options.gridTextColor);
1237     };
1238
1239     Line.prototype.drawLinePath = function(path, lineColor, lineIndex) {
1240       return this.raphael.path(path).attr('stroke', lineColor).attr('stroke-width', this.lineWidthForSeries(lineIndex));
1241     };
1242
1243     Line.prototype.drawLinePoint = function(xPos, yPos, pointColor, lineIndex) {
1244       return this.raphael.circle(xPos, yPos, this.pointSizeForSeries(lineIndex)).attr('fill', pointColor).attr('stroke-width', this.pointStrokeWidthForSeries(lineIndex)).attr('stroke', this.pointStrokeColorForSeries(lineIndex));
1245     };
1246
1247     Line.prototype.pointStrokeWidthForSeries = function(index) {
1248       return this.options.pointStrokeWidths[index % this.options.pointStrokeWidths.length];
1249     };
1250
1251     Line.prototype.pointStrokeColorForSeries = function(index) {
1252       return this.options.pointStrokeColors[index % this.options.pointStrokeColors.length];
1253     };
1254
1255     Line.prototype.lineWidthForSeries = function(index) {
1256       if (this.options.lineWidth instanceof Array) {
1257         return this.options.lineWidth[index % this.options.lineWidth.length];
1258       } else {
1259         return this.options.lineWidth;
1260       }
1261     };
1262
1263     Line.prototype.pointSizeForSeries = function(index) {
1264       if (this.options.pointSize instanceof Array) {
1265         return this.options.pointSize[index % this.options.pointSize.length];
1266       } else {
1267         return this.options.pointSize;
1268       }
1269     };
1270
1271     Line.prototype.pointGrowSeries = function(index) {
1272       if (this.pointSizeForSeries(index) === 0) {
1273         return;
1274       }
1275       return Raphael.animation({
1276         r: this.pointSizeForSeries(index) + 3
1277       }, 25, 'linear');
1278     };
1279
1280     Line.prototype.pointShrinkSeries = function(index) {
1281       return Raphael.animation({
1282         r: this.pointSizeForSeries(index)
1283       }, 25, 'linear');
1284     };
1285
1286     return Line;
1287
1288   })(Morris.Grid);
1289
1290   Morris.labelSeries = function(dmin, dmax, pxwidth, specName, xLabelFormat) {
1291     var d, d0, ddensity, name, ret, s, spec, t, _i, _len, _ref;
1292     ddensity = 200 * (dmax - dmin) / pxwidth;
1293     d0 = new Date(dmin);
1294     spec = Morris.LABEL_SPECS[specName];
1295     if (spec === void 0) {
1296       _ref = Morris.AUTO_LABEL_ORDER;
1297       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1298         name = _ref[_i];
1299         s = Morris.LABEL_SPECS[name];
1300         if (ddensity >= s.span) {
1301           spec = s;
1302           break;
1303         }
1304       }
1305     }
1306     if (spec === void 0) {
1307       spec = Morris.LABEL_SPECS["second"];
1308     }
1309     if (xLabelFormat) {
1310       spec = $.extend({}, spec, {
1311         fmt: xLabelFormat
1312       });
1313     }
1314     d = spec.start(d0);
1315     ret = [];
1316     while ((t = d.getTime()) <= dmax) {
1317       if (t >= dmin) {
1318         ret.push([spec.fmt(d), t]);
1319       }
1320       spec.incr(d);
1321     }
1322     return ret;
1323   };
1324
1325   minutesSpecHelper = function(interval) {
1326     return {
1327       span: interval * 60 * 1000,
1328       start: function(d) {
1329         return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours());
1330       },
1331       fmt: function(d) {
1332         return "" + (Morris.pad2(d.getHours())) + ":" + (Morris.pad2(d.getMinutes()));
1333       },
1334       incr: function(d) {
1335         return d.setUTCMinutes(d.getUTCMinutes() + interval);
1336       }
1337     };
1338   };
1339
1340   secondsSpecHelper = function(interval) {
1341     return {
1342       span: interval * 1000,
1343       start: function(d) {
1344         return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes());
1345       },
1346       fmt: function(d) {
1347         return "" + (Morris.pad2(d.getHours())) + ":" + (Morris.pad2(d.getMinutes())) + ":" + (Morris.pad2(d.getSeconds()));
1348       },
1349       incr: function(d) {
1350         return d.setUTCSeconds(d.getUTCSeconds() + interval);
1351       }
1352     };
1353   };
1354
1355   Morris.LABEL_SPECS = {
1356     "decade": {
1357       span: 172800000000,
1358       start: function(d) {
1359         return new Date(d.getFullYear() - d.getFullYear() % 10, 0, 1);
1360       },
1361       fmt: function(d) {
1362         return "" + (d.getFullYear());
1363       },
1364       incr: function(d) {
1365         return d.setFullYear(d.getFullYear() + 10);
1366       }
1367     },
1368     "year": {
1369       span: 17280000000,
1370       start: function(d) {
1371         return new Date(d.getFullYear(), 0, 1);
1372       },
1373       fmt: function(d) {
1374         return "" + (d.getFullYear());
1375       },
1376       incr: function(d) {
1377         return d.setFullYear(d.getFullYear() + 1);
1378       }
1379     },
1380     "month": {
1381       span: 2419200000,
1382       start: function(d) {
1383         return new Date(d.getFullYear(), d.getMonth(), 1);
1384       },
1385       fmt: function(d) {
1386         return "" + (d.getFullYear()) + "-" + (Morris.pad2(d.getMonth() + 1));
1387       },
1388       incr: function(d) {
1389         return d.setMonth(d.getMonth() + 1);
1390       }
1391     },
1392     "week": {
1393       span: 604800000,
1394       start: function(d) {
1395         return new Date(d.getFullYear(), d.getMonth(), d.getDate());
1396       },
1397       fmt: function(d) {
1398         return "" + (d.getFullYear()) + "-" + (Morris.pad2(d.getMonth() + 1)) + "-" + (Morris.pad2(d.getDate()));
1399       },
1400       incr: function(d) {
1401         return d.setDate(d.getDate() + 7);
1402       }
1403     },
1404     "day": {
1405       span: 86400000,
1406       start: function(d) {
1407         return new Date(d.getFullYear(), d.getMonth(), d.getDate());
1408       },
1409       fmt: function(d) {
1410         return "" + (d.getFullYear()) + "-" + (Morris.pad2(d.getMonth() + 1)) + "-" + (Morris.pad2(d.getDate()));
1411       },
1412       incr: function(d) {
1413         return d.setDate(d.getDate() + 1);
1414       }
1415     },
1416     "hour": minutesSpecHelper(60),
1417     "30min": minutesSpecHelper(30),
1418     "15min": minutesSpecHelper(15),
1419     "10min": minutesSpecHelper(10),
1420     "5min": minutesSpecHelper(5),
1421     "minute": minutesSpecHelper(1),
1422     "30sec": secondsSpecHelper(30),
1423     "15sec": secondsSpecHelper(15),
1424     "10sec": secondsSpecHelper(10),
1425     "5sec": secondsSpecHelper(5),
1426     "second": secondsSpecHelper(1)
1427   };
1428
1429   Morris.AUTO_LABEL_ORDER = ["decade", "year", "month", "week", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
1430
1431   Morris.Area = (function(_super) {
1432     var areaDefaults;
1433
1434     __extends(Area, _super);
1435
1436     areaDefaults = {
1437       fillOpacity: 'auto',
1438       behaveLikeLine: false
1439     };
1440
1441     function Area(options) {
1442       var areaOptions;
1443       if (!(this instanceof Morris.Area)) {
1444         return new Morris.Area(options);
1445       }
1446       areaOptions = $.extend({}, areaDefaults, options);
1447       this.cumulative = !areaOptions.behaveLikeLine;
1448       if (areaOptions.fillOpacity === 'auto') {
1449         areaOptions.fillOpacity = areaOptions.behaveLikeLine ? .8 : 1;
1450       }
1451       Area.__super__.constructor.call(this, areaOptions);
1452     }
1453
1454     Area.prototype.calcPoints = function() {
1455       var row, total, y, _i, _len, _ref, _results;
1456       _ref = this.data;
1457       _results = [];
1458       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1459         row = _ref[_i];
1460         row._x = this.transX(row.x);
1461         total = 0;
1462         row._y = (function() {
1463           var _j, _len1, _ref1, _results1;
1464           _ref1 = row.y;
1465           _results1 = [];
1466           for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
1467             y = _ref1[_j];
1468             if (this.options.behaveLikeLine) {
1469               _results1.push(this.transY(y));
1470             } else {
1471               total += y || 0;
1472               _results1.push(this.transY(total));
1473             }
1474           }
1475           return _results1;
1476         }).call(this);
1477         _results.push(row._ymax = Math.max.apply(Math, row._y));
1478       }
1479       return _results;
1480     };
1481
1482     Area.prototype.drawSeries = function() {
1483       var i, range, _i, _j, _k, _len, _ref, _ref1, _results, _results1, _results2;
1484       this.seriesPoints = [];
1485       if (this.options.behaveLikeLine) {
1486         range = (function() {
1487           _results = [];
1488           for (var _i = 0, _ref = this.options.ykeys.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }
1489           return _results;
1490         }).apply(this);
1491       } else {
1492         range = (function() {
1493           _results1 = [];
1494           for (var _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; _ref1 <= 0 ? _j++ : _j--){ _results1.push(_j); }
1495           return _results1;
1496         }).apply(this);
1497       }
1498       _results2 = [];
1499       for (_k = 0, _len = range.length; _k < _len; _k++) {
1500         i = range[_k];
1501         this._drawFillFor(i);
1502         this._drawLineFor(i);
1503         _results2.push(this._drawPointFor(i));
1504       }
1505       return _results2;
1506     };
1507
1508     Area.prototype._drawFillFor = function(index) {
1509       var path;
1510       path = this.paths[index];
1511       if (path !== null) {
1512         path = path + ("L" + (this.transX(this.xmax)) + "," + this.bottom + "L" + (this.transX(this.xmin)) + "," + this.bottom + "Z");
1513         return this.drawFilledPath(path, this.fillForSeries(index));
1514       }
1515     };
1516
1517     Area.prototype.fillForSeries = function(i) {
1518       var color;
1519       color = Raphael.rgb2hsl(this.colorFor(this.data[i], i, 'line'));
1520       return Raphael.hsl(color.h, this.options.behaveLikeLine ? color.s * 0.9 : color.s * 0.75, Math.min(0.98, this.options.behaveLikeLine ? color.l * 1.2 : color.l * 1.25));
1521     };
1522
1523     Area.prototype.drawFilledPath = function(path, fill) {
1524       return this.raphael.path(path).attr('fill', fill).attr('fill-opacity', this.options.fillOpacity).attr('stroke', 'none');
1525     };
1526
1527     return Area;
1528
1529   })(Morris.Line);
1530
1531   Morris.Bar = (function(_super) {
1532     __extends(Bar, _super);
1533
1534     function Bar(options) {
1535       this.onHoverOut = __bind(this.onHoverOut, this);
1536       this.onHoverMove = __bind(this.onHoverMove, this);
1537       this.onGridClick = __bind(this.onGridClick, this);
1538       if (!(this instanceof Morris.Bar)) {
1539         return new Morris.Bar(options);
1540       }
1541       Bar.__super__.constructor.call(this, $.extend({}, options, {
1542         parseTime: false
1543       }));
1544     }
1545
1546     Bar.prototype.init = function() {
1547       this.cumulative = this.options.stacked;
1548       if (this.options.hideHover !== 'always') {
1549         this.hover = new Morris.Hover({
1550           parent: this.el
1551         });
1552         this.on('hovermove', this.onHoverMove);
1553         this.on('hoverout', this.onHoverOut);
1554         return this.on('gridclick', this.onGridClick);
1555       }
1556     };
1557
1558     Bar.prototype.defaults = {
1559       barSizeRatio: 0.75,
1560       barGap: 3,
1561       barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
1562       barOpacity: 1.0,
1563       barRadius: [0, 0, 0, 0],
1564       xLabelMargin: 50,
1565       horizontal: false,
1566       shown: true
1567     };
1568
1569     Bar.prototype.calc = function() {
1570       var _ref;
1571       this.calcBars();
1572       if (this.options.hideHover === false) {
1573         return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(this.data.length - 1));
1574       }
1575     };
1576
1577     Bar.prototype.calcBars = function() {
1578       var idx, row, y, _i, _len, _ref, _results;
1579       _ref = this.data;
1580       _results = [];
1581       for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
1582         row = _ref[idx];
1583         row._x = this.xStart + this.xSize * (idx + 0.5) / this.data.length;
1584         _results.push(row._y = (function() {
1585           var _j, _len1, _ref1, _results1;
1586           _ref1 = row.y;
1587           _results1 = [];
1588           for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
1589             y = _ref1[_j];
1590             if (y != null) {
1591               _results1.push(this.transY(y));
1592             } else {
1593               _results1.push(null);
1594             }
1595           }
1596           return _results1;
1597         }).call(this));
1598       }
1599       return _results;
1600     };
1601
1602     Bar.prototype.draw = function() {
1603       var _ref;
1604       if ((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'x') {
1605         this.drawXAxis();
1606       }
1607       return this.drawSeries();
1608     };
1609
1610     Bar.prototype.drawXAxis = function() {
1611       var angle, basePos, i, label, labelBox, margin, maxSize, offset, prevAngleMargin, prevLabelMargin, row, size, startPos, textBox, _i, _ref, _results;
1612       if (!this.options.horizontal) {
1613         basePos = this.getXAxisLabelY();
1614       } else {
1615         basePos = this.getYAxisLabelX();
1616       }
1617       prevLabelMargin = null;
1618       prevAngleMargin = null;
1619       _results = [];
1620       for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
1621         row = this.data[this.data.length - 1 - i];
1622         if (!this.options.horizontal) {
1623           label = this.drawXAxisLabel(row._x, basePos, row.label);
1624         } else {
1625           label = this.drawYAxisLabel(basePos, row._x - 0.5 * this.options.gridTextSize, row.label);
1626         }
1627         if (!this.options.horizontal) {
1628           angle = this.options.xLabelAngle;
1629         } else {
1630           angle = 0;
1631         }
1632         textBox = label.getBBox();
1633         label.transform("r" + (-angle));
1634         labelBox = label.getBBox();
1635         label.transform("t0," + (labelBox.height / 2) + "...");
1636         if (angle !== 0) {
1637           offset = -0.5 * textBox.width * Math.cos(angle * Math.PI / 180.0);
1638           label.transform("t" + offset + ",0...");
1639         }
1640         if (!this.options.horizontal) {
1641           startPos = labelBox.x;
1642           size = labelBox.width;
1643           maxSize = this.el.width();
1644         } else {
1645           startPos = labelBox.y;
1646           size = labelBox.height;
1647           maxSize = this.el.height();
1648         }
1649         if (((prevLabelMargin == null) || prevLabelMargin >= startPos + size || (prevAngleMargin != null) && prevAngleMargin >= startPos) && startPos >= 0 && (startPos + size) < maxSize) {
1650           if (angle !== 0) {
1651             margin = 1.25 * this.options.gridTextSize / Math.sin(angle * Math.PI / 180.0);
1652             prevAngleMargin = startPos - margin;
1653           }
1654           if (!this.options.horizontal) {
1655             _results.push(prevLabelMargin = startPos - this.options.xLabelMargin);
1656           } else {
1657             _results.push(prevLabelMargin = startPos);
1658           }
1659         } else {
1660           _results.push(label.remove());
1661         }
1662       }
1663       return _results;
1664     };
1665
1666     Bar.prototype.getXAxisLabelY = function() {
1667       return this.bottom + (this.options.xAxisLabelTopPadding || this.options.padding / 2);
1668     };
1669
1670     Bar.prototype.drawSeries = function() {
1671       var barWidth, bottom, groupWidth, i, idx, lastTop, left, leftPadding, numBars, row, sidx, size, spaceLeft, top, ypos, zeroPos, _i, _ref;
1672       groupWidth = this.xSize / this.options.data.length;
1673       if (this.options.stacked) {
1674         numBars = 1;
1675       } else {
1676         numBars = 0;
1677         for (i = _i = 0, _ref = this.options.ykeys.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
1678           if (this.hasToShow(i)) {
1679             numBars += 1;
1680           }
1681         }
1682       }
1683       barWidth = (groupWidth * this.options.barSizeRatio - this.options.barGap * (numBars - 1)) / numBars;
1684       if (this.options.barSize) {
1685         barWidth = Math.min(barWidth, this.options.barSize);
1686       }
1687       spaceLeft = groupWidth - barWidth * numBars - this.options.barGap * (numBars - 1);
1688       leftPadding = spaceLeft / 2;
1689       zeroPos = this.ymin <= 0 && this.ymax >= 0 ? this.transY(0) : null;
1690       return this.bars = (function() {
1691         var _j, _len, _ref1, _results;
1692         _ref1 = this.data;
1693         _results = [];
1694         for (idx = _j = 0, _len = _ref1.length; _j < _len; idx = ++_j) {
1695           row = _ref1[idx];
1696           lastTop = 0;
1697           _results.push((function() {
1698             var _k, _len1, _ref2, _results1;
1699             _ref2 = row._y;
1700             _results1 = [];
1701             for (sidx = _k = 0, _len1 = _ref2.length; _k < _len1; sidx = ++_k) {
1702               ypos = _ref2[sidx];
1703               if (!this.hasToShow(sidx)) {
1704                 continue;
1705               }
1706               if (ypos !== null) {
1707                 if (zeroPos) {
1708                   top = Math.min(ypos, zeroPos);
1709                   bottom = Math.max(ypos, zeroPos);
1710                 } else {
1711                   top = ypos;
1712                   bottom = this.bottom;
1713                 }
1714                 left = this.xStart + idx * groupWidth + leftPadding;
1715                 if (!this.options.stacked) {
1716                   left += sidx * (barWidth + this.options.barGap);
1717                 }
1718                 size = bottom - top;
1719                 if (this.options.verticalGridCondition && this.options.verticalGridCondition(row.x)) {
1720                   if (!this.options.horizontal) {
1721                     this.drawBar(this.xStart + idx * groupWidth, this.yEnd, groupWidth, this.ySize, this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
1722                   } else {
1723                     this.drawBar(this.yStart, this.xStart + idx * groupWidth, this.ySize, groupWidth, this.options.verticalGridColor, this.options.verticalGridOpacity, this.options.barRadius);
1724                   }
1725                 }
1726                 if (this.options.stacked) {
1727                   top -= lastTop;
1728                 }
1729                 if (!this.options.horizontal) {
1730                   this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
1731                   _results1.push(lastTop += size);
1732                 } else {
1733                   this.drawBar(top, left, size, barWidth, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);
1734                   _results1.push(lastTop -= size);
1735                 }
1736               } else {
1737                 _results1.push(null);
1738               }
1739             }
1740             return _results1;
1741           }).call(this));
1742         }
1743         return _results;
1744       }).call(this);
1745     };
1746
1747     Bar.prototype.colorFor = function(row, sidx, type) {
1748       var r, s;
1749       if (typeof this.options.barColors === 'function') {
1750         r = {
1751           x: row.x,
1752           y: row.y[sidx],
1753           label: row.label
1754         };
1755         s = {
1756           index: sidx,
1757           key: this.options.ykeys[sidx],
1758           label: this.options.labels[sidx]
1759         };
1760         return this.options.barColors.call(this, r, s, type);
1761       } else {
1762         return this.options.barColors[sidx % this.options.barColors.length];
1763       }
1764     };
1765
1766     Bar.prototype.hitTest = function(x, y) {
1767       var pos;
1768       if (this.data.length === 0) {
1769         return null;
1770       }
1771       if (!this.options.horizontal) {
1772         pos = x;
1773       } else {
1774         pos = y;
1775       }
1776       pos = Math.max(Math.min(pos, this.xEnd), this.xStart);
1777       return Math.min(this.data.length - 1, Math.floor((pos - this.xStart) / (this.xSize / this.data.length)));
1778     };
1779
1780     Bar.prototype.onGridClick = function(x, y) {
1781       var index;
1782       index = this.hitTest(x, y);
1783       return this.fire('click', index, this.data[index].src, x, y);
1784     };
1785
1786     Bar.prototype.onHoverMove = function(x, y) {
1787       var index, _ref;
1788       index = this.hitTest(x, y);
1789       return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));
1790     };
1791
1792     Bar.prototype.onHoverOut = function() {
1793       if (this.options.hideHover !== false) {
1794         return this.hover.hide();
1795       }
1796     };
1797
1798     Bar.prototype.hoverContentForRow = function(index) {
1799       var content, j, row, x, y, _i, _len, _ref;
1800       row = this.data[index];
1801       content = $("<div class='morris-hover-row-label'>").text(row.label);
1802       content = content.prop('outerHTML');
1803       _ref = row.y;
1804       for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
1805         y = _ref[j];
1806         if (this.options.labels[j] === false) {
1807           continue;
1808         }
1809         content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n  " + this.options.labels[j] + ":\n  " + (this.yLabelFormat(y, j)) + "\n</div>";
1810       }
1811       if (typeof this.options.hoverCallback === 'function') {
1812         content = this.options.hoverCallback(index, this.options, content, row.src);
1813       }
1814       if (!this.options.horizontal) {
1815         x = this.left + (index + 0.5) * this.width / this.data.length;
1816         return [content, x];
1817       } else {
1818         x = this.left + 0.5 * this.width;
1819         y = this.top + (index + 0.5) * this.height / this.data.length;
1820         return [content, x, y, true];
1821       }
1822     };
1823
1824     Bar.prototype.drawXAxisLabel = function(xPos, yPos, text) {
1825       var label;
1826       return label = this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).attr('fill', this.options.gridTextColor);
1827     };
1828
1829     Bar.prototype.drawBar = function(xPos, yPos, width, height, barColor, opacity, radiusArray) {
1830       var maxRadius, path;
1831       maxRadius = Math.max.apply(Math, radiusArray);
1832       if (maxRadius === 0 || maxRadius > height) {
1833         path = this.raphael.rect(xPos, yPos, width, height);
1834       } else {
1835         path = this.raphael.path(this.roundedRect(xPos, yPos, width, height, radiusArray));
1836       }
1837       return path.attr('fill', barColor).attr('fill-opacity', opacity).attr('stroke', 'none');
1838     };
1839
1840     Bar.prototype.roundedRect = function(x, y, w, h, r) {
1841       if (r == null) {
1842         r = [0, 0, 0, 0];
1843       }
1844       return ["M", x, r[0] + y, "Q", x, y, x + r[0], y, "L", x + w - r[1], y, "Q", x + w, y, x + w, y + r[1], "L", x + w, y + h - r[2], "Q", x + w, y + h, x + w - r[2], y + h, "L", x + r[3], y + h, "Q", x, y + h, x, y + h - r[3], "Z"];
1845     };
1846
1847     return Bar;
1848
1849   })(Morris.Grid);
1850
1851   Morris.Donut = (function(_super) {
1852     __extends(Donut, _super);
1853
1854     Donut.prototype.defaults = {
1855       colors: ['#0B62A4', '#3980B5', '#679DC6', '#95BBD7', '#B0CCE1', '#095791', '#095085', '#083E67', '#052C48', '#042135'],
1856       backgroundColor: '#FFFFFF',
1857       labelColor: '#000000',
1858       formatter: Morris.commas,
1859       resize: false
1860     };
1861
1862     function Donut(options) {
1863       this.resizeHandler = __bind(this.resizeHandler, this);
1864       this.select = __bind(this.select, this);
1865       this.click = __bind(this.click, this);
1866       var _this = this;
1867       if (!(this instanceof Morris.Donut)) {
1868         return new Morris.Donut(options);
1869       }
1870       this.options = $.extend({}, this.defaults, options);
1871       if (typeof options.element === 'string') {
1872         this.el = $(document.getElementById(options.element));
1873       } else {
1874         this.el = $(options.element);
1875       }
1876       if (this.el === null || this.el.length === 0) {
1877         throw new Error("Graph placeholder not found.");
1878       }
1879       if (options.data === void 0 || options.data.length === 0) {
1880         return;
1881       }
1882       this.raphael = new Raphael(this.el[0]);
1883       if (this.options.resize) {
1884         $(window).bind('resize', function(evt) {
1885           if (_this.timeoutId != null) {
1886             window.clearTimeout(_this.timeoutId);
1887           }
1888           return _this.timeoutId = window.setTimeout(_this.resizeHandler, 100);
1889         });
1890       }
1891       this.setData(options.data);
1892     }
1893
1894     Donut.prototype.redraw = function() {
1895       var C, cx, cy, i, idx, last, max_value, min, next, seg, total, value, w, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;
1896       this.raphael.clear();
1897       cx = this.el.width() / 2;
1898       cy = this.el.height() / 2;
1899       w = (Math.min(cx, cy) - 10) / 3;
1900       total = 0;
1901       _ref = this.values;
1902       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1903         value = _ref[_i];
1904         total += value;
1905       }
1906       min = 5 / (2 * w);
1907       C = 1.9999 * Math.PI - min * this.data.length;
1908       last = 0;
1909       idx = 0;
1910       this.segments = [];
1911       _ref1 = this.values;
1912       for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
1913         value = _ref1[i];
1914         next = last + min + C * (value / total);
1915         seg = new Morris.DonutSegment(cx, cy, w * 2, w, last, next, this.data[i].color || this.options.colors[idx % this.options.colors.length], this.options.backgroundColor, idx, this.raphael);
1916         seg.render();
1917         this.segments.push(seg);
1918         seg.on('hover', this.select);
1919         seg.on('click', this.click);
1920         last = next;
1921         idx += 1;
1922       }
1923       this.text1 = this.drawEmptyDonutLabel(cx, cy - 10, this.options.labelColor, 15, 800);
1924       this.text2 = this.drawEmptyDonutLabel(cx, cy + 10, this.options.labelColor, 14);
1925       max_value = Math.max.apply(Math, this.values);
1926       idx = 0;
1927       _ref2 = this.values;
1928       _results = [];
1929       for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
1930         value = _ref2[_k];
1931         if (value === max_value) {
1932           this.select(idx);
1933           break;
1934         }
1935         _results.push(idx += 1);
1936       }
1937       return _results;
1938     };
1939
1940     Donut.prototype.setData = function(data) {
1941       var row;
1942       this.data = data;
1943       this.values = (function() {
1944         var _i, _len, _ref, _results;
1945         _ref = this.data;
1946         _results = [];
1947         for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1948           row = _ref[_i];
1949           _results.push(parseFloat(row.value));
1950         }
1951         return _results;
1952       }).call(this);
1953       return this.redraw();
1954     };
1955
1956     Donut.prototype.click = function(idx) {
1957       return this.fire('click', idx, this.data[idx]);
1958     };
1959
1960     Donut.prototype.select = function(idx) {
1961       var row, s, segment, _i, _len, _ref;
1962       _ref = this.segments;
1963       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1964         s = _ref[_i];
1965         s.deselect();
1966       }
1967       segment = this.segments[idx];
1968       segment.select();
1969       row = this.data[idx];
1970       return this.setLabels(row.label, this.options.formatter(row.value, row));
1971     };
1972
1973     Donut.prototype.setLabels = function(label1, label2) {
1974       var inner, maxHeightBottom, maxHeightTop, maxWidth, text1bbox, text1scale, text2bbox, text2scale;
1975       inner = (Math.min(this.el.width() / 2, this.el.height() / 2) - 10) * 2 / 3;
1976       maxWidth = 1.8 * inner;
1977       maxHeightTop = inner / 2;
1978       maxHeightBottom = inner / 3;
1979       this.text1.attr({
1980         text: label1,
1981         transform: ''
1982       });
1983       text1bbox = this.text1.getBBox();
1984       text1scale = Math.min(maxWidth / text1bbox.width, maxHeightTop / text1bbox.height);
1985       this.text1.attr({
1986         transform: "S" + text1scale + "," + text1scale + "," + (text1bbox.x + text1bbox.width / 2) + "," + (text1bbox.y + text1bbox.height)
1987       });
1988       this.text2.attr({
1989         text: label2,
1990         transform: ''
1991       });
1992       text2bbox = this.text2.getBBox();
1993       text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height);
1994       return this.text2.attr({
1995         transform: "S" + text2scale + "," + text2scale + "," + (text2bbox.x + text2bbox.width / 2) + "," + text2bbox.y
1996       });
1997     };
1998
1999     Donut.prototype.drawEmptyDonutLabel = function(xPos, yPos, color, fontSize, fontWeight) {
2000       var text;
2001       text = this.raphael.text(xPos, yPos, '').attr('font-size', fontSize).attr('fill', color);
2002       if (fontWeight != null) {
2003         text.attr('font-weight', fontWeight);
2004       }
2005       return text;
2006     };
2007
2008     Donut.prototype.resizeHandler = function() {
2009       this.timeoutId = null;
2010       this.raphael.setSize(this.el.width(), this.el.height());
2011       return this.redraw();
2012     };
2013
2014     return Donut;
2015
2016   })(Morris.EventEmitter);
2017
2018   Morris.DonutSegment = (function(_super) {
2019     __extends(DonutSegment, _super);
2020
2021     function DonutSegment(cx, cy, inner, outer, p0, p1, color, backgroundColor, index, raphael) {
2022       this.cx = cx;
2023       this.cy = cy;
2024       this.inner = inner;
2025       this.outer = outer;
2026       this.color = color;
2027       this.backgroundColor = backgroundColor;
2028       this.index = index;
2029       this.raphael = raphael;
2030       this.deselect = __bind(this.deselect, this);
2031       this.select = __bind(this.select, this);
2032       this.sin_p0 = Math.sin(p0);
2033       this.cos_p0 = Math.cos(p0);
2034       this.sin_p1 = Math.sin(p1);
2035       this.cos_p1 = Math.cos(p1);
2036       this.is_long = (p1 - p0) > Math.PI ? 1 : 0;
2037       this.path = this.calcSegment(this.inner + 3, this.inner + this.outer - 5);
2038       this.selectedPath = this.calcSegment(this.inner + 3, this.inner + this.outer);
2039       this.hilight = this.calcArc(this.inner);
2040     }
2041
2042     DonutSegment.prototype.calcArcPoints = function(r) {
2043       return [this.cx + r * this.sin_p0, this.cy + r * this.cos_p0, this.cx + r * this.sin_p1, this.cy + r * this.cos_p1];
2044     };
2045
2046     DonutSegment.prototype.calcSegment = function(r1, r2) {
2047       var ix0, ix1, iy0, iy1, ox0, ox1, oy0, oy1, _ref, _ref1;
2048       _ref = this.calcArcPoints(r1), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
2049       _ref1 = this.calcArcPoints(r2), ox0 = _ref1[0], oy0 = _ref1[1], ox1 = _ref1[2], oy1 = _ref1[3];
2050       return ("M" + ix0 + "," + iy0) + ("A" + r1 + "," + r1 + ",0," + this.is_long + ",0," + ix1 + "," + iy1) + ("L" + ox1 + "," + oy1) + ("A" + r2 + "," + r2 + ",0," + this.is_long + ",1," + ox0 + "," + oy0) + "Z";
2051     };
2052
2053     DonutSegment.prototype.calcArc = function(r) {
2054       var ix0, ix1, iy0, iy1, _ref;
2055       _ref = this.calcArcPoints(r), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
2056       return ("M" + ix0 + "," + iy0) + ("A" + r + "," + r + ",0," + this.is_long + ",0," + ix1 + "," + iy1);
2057     };
2058
2059     DonutSegment.prototype.render = function() {
2060       var _this = this;
2061       this.arc = this.drawDonutArc(this.hilight, this.color);
2062       return this.seg = this.drawDonutSegment(this.path, this.color, this.backgroundColor, function() {
2063         return _this.fire('hover', _this.index);
2064       }, function() {
2065         return _this.fire('click', _this.index);
2066       });
2067     };
2068
2069     DonutSegment.prototype.drawDonutArc = function(path, color) {
2070       return this.raphael.path(path).attr({
2071         stroke: color,
2072         'stroke-width': 2,
2073         opacity: 0
2074       });
2075     };
2076
2077     DonutSegment.prototype.drawDonutSegment = function(path, fillColor, strokeColor, hoverFunction, clickFunction) {
2078       return this.raphael.path(path).attr({
2079         fill: fillColor,
2080         stroke: strokeColor,
2081         'stroke-width': 3
2082       }).hover(hoverFunction).click(clickFunction);
2083     };
2084
2085     DonutSegment.prototype.select = function() {
2086       if (!this.selected) {
2087         this.seg.animate({
2088           path: this.selectedPath
2089         }, 150, '<>');
2090         this.arc.animate({
2091           opacity: 1
2092         }, 150, '<>');
2093         return this.selected = true;
2094       }
2095     };
2096
2097     DonutSegment.prototype.deselect = function() {
2098       if (this.selected) {
2099         this.seg.animate({
2100           path: this.path
2101         }, 150, '<>');
2102         this.arc.animate({
2103           opacity: 0
2104         }, 150, '<>');
2105         return this.selected = false;
2106       }
2107     };
2108
2109     return DonutSegment;
2110
2111   })(Morris.EventEmitter);
2112
2113 }).call(this);