morrisjs-rails 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -44,9 +44,7 @@
44
44
 
45
45
  Morris.commas = function(num) {
46
46
  var absnum, intnum, ret, strabsnum;
47
- if (num === null) {
48
- return "-";
49
- } else {
47
+ if (num != null) {
50
48
  ret = num < 0 ? "-" : "";
51
49
  absnum = Math.abs(num);
52
50
  intnum = Math.floor(absnum).toFixed(0);
@@ -56,6 +54,8 @@
56
54
  ret += strabsnum.slice(intnum.length);
57
55
  }
58
56
  return ret;
57
+ } else {
58
+ return '-';
59
59
  }
60
60
  };
61
61
 
@@ -68,14 +68,18 @@
68
68
  __extends(Grid, _super);
69
69
 
70
70
  function Grid(options) {
71
+ var _this = this;
71
72
  if (typeof options.element === 'string') {
72
73
  this.el = $(document.getElementById(options.element));
73
74
  } else {
74
75
  this.el = $(options.element);
75
76
  }
76
- if (this.el === null || this.el.length === 0) {
77
+ if (!(this.el != null) || this.el.length === 0) {
77
78
  throw new Error("Graph container element not found");
78
79
  }
80
+ if (this.el.css('position') === 'static') {
81
+ this.el.css('position', 'relative');
82
+ }
79
83
  this.options = $.extend({}, this.gridDefaults, this.defaults || {}, options);
80
84
  if (this.options.data === void 0 || this.options.data.length === 0) {
81
85
  return;
@@ -83,7 +87,7 @@
83
87
  if (typeof this.options.units === 'string') {
84
88
  this.options.postUnits = options.units;
85
89
  }
86
- this.r = new Raphael(this.el[0]);
90
+ this.raphael = new Raphael(this.el[0]);
87
91
  this.elementWidth = null;
88
92
  this.elementHeight = null;
89
93
  this.dirty = false;
@@ -91,81 +95,119 @@
91
95
  this.init();
92
96
  }
93
97
  this.setData(this.options.data);
98
+ this.el.bind('mousemove', function(evt) {
99
+ var offset;
100
+ offset = _this.el.offset();
101
+ return _this.fire('hovermove', evt.pageX - offset.left, evt.pageY - offset.top);
102
+ });
103
+ this.el.bind('mouseout', function(evt) {
104
+ return _this.fire('hoverout');
105
+ });
106
+ this.el.bind('touchstart touchmove touchend', function(evt) {
107
+ var offset, touch;
108
+ touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
109
+ offset = _this.el.offset();
110
+ _this.fire('hover', touch.pageX - offset.left, touch.pageY - offset.top);
111
+ return touch;
112
+ });
113
+ if (this.postInit) {
114
+ this.postInit();
115
+ }
94
116
  }
95
117
 
96
118
  Grid.prototype.gridDefaults = {
97
119
  dateFormat: null,
120
+ axes: true,
121
+ grid: true,
98
122
  gridLineColor: '#aaa',
99
123
  gridStrokeWidth: 0.5,
100
124
  gridTextColor: '#888',
101
125
  gridTextSize: 12,
126
+ hideHover: false,
127
+ yLabelFormat: null,
102
128
  numLines: 5,
103
129
  padding: 25,
104
130
  parseTime: true,
105
131
  postUnits: '',
106
132
  preUnits: '',
107
133
  ymax: 'auto',
108
- ymin: 'auto 0'
134
+ ymin: 'auto 0',
135
+ goals: [],
136
+ goalStrokeWidth: 1.0,
137
+ goalLineColors: ['#666633', '#999966', '#cc6666', '#663333'],
138
+ events: [],
139
+ eventStrokeWidth: 1.0,
140
+ eventLineColors: ['#005a04', '#ccffbb', '#3a5f0b', '#005502']
109
141
  };
110
142
 
111
143
  Grid.prototype.setData = function(data, redraw) {
112
- var ymax, ymin,
113
- _this = this;
144
+ var e, idx, index, maxGoal, minGoal, ret, row, total, ykey, ymax, ymin, yval;
114
145
  if (redraw == null) {
115
146
  redraw = true;
116
147
  }
117
148
  ymax = this.cumulative ? 0 : null;
118
149
  ymin = this.cumulative ? 0 : null;
119
- this.data = $.map(data, function(row, index) {
120
- var idx, ret, total, ykey, yval;
121
- ret = {};
122
- ret.label = row[_this.options.xkey];
123
- if (_this.options.parseTime) {
124
- ret.x = Morris.parseDate(ret.label);
125
- if (_this.options.dateFormat) {
126
- ret.label = _this.options.dateFormat(ret.x);
127
- } else if (typeof ret.label === 'number') {
128
- ret.label = new Date(ret.label).toString();
129
- }
130
- } else {
131
- ret.x = index;
132
- }
133
- total = 0;
134
- ret.y = (function() {
135
- var _i, _len, _ref, _results;
136
- _ref = this.options.ykeys;
137
- _results = [];
138
- for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
139
- ykey = _ref[idx];
140
- yval = row[ykey];
141
- if (typeof yval === 'string') {
142
- yval = parseFloat(yval);
143
- }
144
- if (typeof yval !== 'number') {
145
- yval = null;
150
+ if (this.options.goals.length > 0) {
151
+ minGoal = Math.min.apply(null, this.options.goals);
152
+ maxGoal = Math.max.apply(null, this.options.goals);
153
+ ymin = ymin != null ? Math.min(ymin, minGoal) : minGoal;
154
+ ymax = ymax != null ? Math.max(ymax, maxGoal) : maxGoal;
155
+ }
156
+ this.data = (function() {
157
+ var _i, _len, _results;
158
+ _results = [];
159
+ for (index = _i = 0, _len = data.length; _i < _len; index = ++_i) {
160
+ row = data[index];
161
+ ret = {};
162
+ ret.label = row[this.options.xkey];
163
+ if (this.options.parseTime) {
164
+ ret.x = Morris.parseDate(ret.label);
165
+ if (this.options.dateFormat) {
166
+ ret.label = this.options.dateFormat(ret.x);
167
+ } else if (typeof ret.label === 'number') {
168
+ ret.label = new Date(ret.label).toString();
146
169
  }
147
- if (yval !== null) {
148
- if (this.cumulative) {
149
- total += yval;
150
- } else {
151
- if (ymax === null) {
152
- ymax = ymin = yval;
170
+ } else {
171
+ ret.x = index;
172
+ }
173
+ total = 0;
174
+ ret.y = (function() {
175
+ var _j, _len1, _ref, _results1;
176
+ _ref = this.options.ykeys;
177
+ _results1 = [];
178
+ for (idx = _j = 0, _len1 = _ref.length; _j < _len1; idx = ++_j) {
179
+ ykey = _ref[idx];
180
+ yval = row[ykey];
181
+ if (typeof yval === 'string') {
182
+ yval = parseFloat(yval);
183
+ }
184
+ if ((yval != null) && typeof yval !== 'number') {
185
+ yval = null;
186
+ }
187
+ if (yval != null) {
188
+ if (this.cumulative) {
189
+ total += yval;
153
190
  } else {
154
- ymax = Math.max(yval, ymax);
155
- ymin = Math.min(yval, ymin);
191
+ if (ymax != null) {
192
+ ymax = Math.max(yval, ymax);
193
+ ymin = Math.min(yval, ymin);
194
+ } else {
195
+ ymax = ymin = yval;
196
+ }
156
197
  }
157
198
  }
199
+ if (this.cumulative && (total != null)) {
200
+ ymax = Math.max(total, ymax);
201
+ ymin = Math.min(total, ymin);
202
+ }
203
+ _results1.push(yval);
158
204
  }
159
- if (this.cumulative && total !== null) {
160
- ymax = Math.max(total, ymax);
161
- ymin = Math.min(total, ymin);
162
- }
163
- _results.push(yval);
164
- }
165
- return _results;
166
- }).call(_this);
167
- return ret;
168
- });
205
+ return _results1;
206
+ }).call(this);
207
+ _results.push(ret);
208
+ }
209
+ return _results;
210
+ }).call(this);
169
211
  if (this.options.parseTime) {
170
212
  this.data = this.data.sort(function(a, b) {
171
213
  return (a.x > b.x) - (b.x > a.x);
@@ -173,42 +215,27 @@
173
215
  }
174
216
  this.xmin = this.data[0].x;
175
217
  this.xmax = this.data[this.data.length - 1].x;
218
+ this.events = [];
219
+ if (this.options.parseTime && this.options.events.length > 0) {
220
+ this.events = (function() {
221
+ var _i, _len, _ref, _results;
222
+ _ref = this.options.events;
223
+ _results = [];
224
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
225
+ e = _ref[_i];
226
+ _results.push(Morris.parseDate(e));
227
+ }
228
+ return _results;
229
+ }).call(this);
230
+ this.xmax = Math.max(this.xmax, Math.max.apply(null, this.events));
231
+ this.xmin = Math.min(this.xmin, Math.min.apply(null, this.events));
232
+ }
176
233
  if (this.xmin === this.xmax) {
177
234
  this.xmin -= 1;
178
235
  this.xmax += 1;
179
236
  }
180
- if (typeof this.options.ymax === 'string') {
181
- if (this.options.ymax.slice(0, 4) === 'auto') {
182
- if (this.options.ymax.length > 5) {
183
- this.ymax = parseInt(this.options.ymax.slice(5), 10);
184
- if (ymax !== null) {
185
- this.ymax = Math.max(ymax, this.ymax);
186
- }
187
- } else {
188
- this.ymax = ymax !== null ? ymax : 0;
189
- }
190
- } else {
191
- this.ymax = parseInt(this.options.ymax, 10);
192
- }
193
- } else {
194
- this.ymax = this.options.ymax;
195
- }
196
- if (typeof this.options.ymin === 'string') {
197
- if (this.options.ymin.slice(0, 4) === 'auto') {
198
- if (this.options.ymin.length > 5) {
199
- this.ymin = parseInt(this.options.ymin.slice(5), 10);
200
- if (ymin !== null) {
201
- this.ymin = Math.min(ymin, this.ymin);
202
- }
203
- } else {
204
- this.ymin = ymin !== null ? ymin : 0;
205
- }
206
- } else {
207
- this.ymin = parseInt(this.options.ymin, 10);
208
- }
209
- } else {
210
- this.ymin = this.options.ymin;
211
- }
237
+ this.ymin = this.yboundary('min', ymin);
238
+ this.ymax = this.yboundary('max', ymax);
212
239
  if (this.ymin === this.ymax) {
213
240
  if (ymin) {
214
241
  this.ymin -= 1;
@@ -227,6 +254,32 @@
227
254
  }
228
255
  };
229
256
 
257
+ Grid.prototype.yboundary = function(boundaryType, currentValue) {
258
+ var boundaryOption, suggestedValue;
259
+ boundaryOption = this.options["y" + boundaryType];
260
+ if (typeof boundaryOption === 'string') {
261
+ if (boundaryOption.slice(0, 4) === 'auto') {
262
+ if (boundaryOption.length > 5) {
263
+ suggestedValue = parseInt(boundaryOption.slice(5), 10);
264
+ if (currentValue == null) {
265
+ return suggestedValue;
266
+ }
267
+ return Math[boundaryType](currentValue, suggestedValue);
268
+ } else {
269
+ if (currentValue != null) {
270
+ return currentValue;
271
+ } else {
272
+ return 0;
273
+ }
274
+ }
275
+ } else {
276
+ return parseInt(boundaryOption, 10);
277
+ }
278
+ } else {
279
+ return boundaryOption;
280
+ }
281
+ };
282
+
230
283
  Grid.prototype._calc = function() {
231
284
  var h, maxYLabelWidth, w;
232
285
  w = this.el.width();
@@ -235,11 +288,15 @@
235
288
  this.elementWidth = w;
236
289
  this.elementHeight = h;
237
290
  this.dirty = false;
238
- maxYLabelWidth = Math.max(this.measureText(this.yAxisFormat(this.ymin), this.options.gridTextSize).width, this.measureText(this.yAxisFormat(this.ymax), this.options.gridTextSize).width);
239
- this.left = maxYLabelWidth + this.options.padding;
291
+ this.left = this.options.padding;
240
292
  this.right = this.elementWidth - this.options.padding;
241
293
  this.top = this.options.padding;
242
- this.bottom = this.elementHeight - this.options.padding - 1.5 * this.options.gridTextSize;
294
+ this.bottom = this.elementHeight - this.options.padding;
295
+ if (this.options.axes) {
296
+ maxYLabelWidth = Math.max(this.measureText(this.yAxisFormat(this.ymin), this.options.gridTextSize).width, this.measureText(this.yAxisFormat(this.ymax), this.options.gridTextSize).width);
297
+ this.left += maxYLabelWidth;
298
+ this.bottom -= 1.5 * this.options.gridTextSize;
299
+ }
243
300
  this.width = this.right - this.left;
244
301
  this.height = this.bottom - this.top;
245
302
  this.dx = this.width / (this.xmax - this.xmin);
@@ -263,24 +320,57 @@
263
320
  };
264
321
 
265
322
  Grid.prototype.redraw = function() {
266
- this.r.clear();
323
+ this.raphael.clear();
267
324
  this._calc();
268
325
  this.drawGrid();
326
+ this.drawGoals();
327
+ this.drawEvents();
269
328
  if (this.draw) {
270
329
  return this.draw();
271
330
  }
272
331
  };
273
332
 
333
+ Grid.prototype.drawGoals = function() {
334
+ var goal, i, _i, _len, _ref, _results;
335
+ _ref = this.options.goals;
336
+ _results = [];
337
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
338
+ goal = _ref[i];
339
+ _results.push(this.drawGoal("M" + this.left + "," + (this.transY(goal)) + "H" + (this.left + this.width)));
340
+ }
341
+ return _results;
342
+ };
343
+
344
+ Grid.prototype.drawEvents = function() {
345
+ var event, i, _i, _len, _ref, _results;
346
+ _ref = this.events;
347
+ _results = [];
348
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
349
+ event = _ref[i];
350
+ _results.push(this.drawEvent("M" + (this.transX(event)) + "," + this.bottom + "V" + this.top));
351
+ }
352
+ return _results;
353
+ };
354
+
274
355
  Grid.prototype.drawGrid = function() {
275
356
  var firstY, lastY, lineY, v, y, _i, _ref, _results;
357
+ if (this.options.grid === false && this.options.axes === false) {
358
+ return;
359
+ }
276
360
  firstY = this.ymin;
277
361
  lastY = this.ymax;
278
362
  _results = [];
279
363
  for (lineY = _i = firstY, _ref = this.yInterval; firstY <= lastY ? _i <= lastY : _i >= lastY; lineY = _i += _ref) {
280
364
  v = parseFloat(lineY.toFixed(this.precision));
281
365
  y = this.transY(v);
282
- this.r.text(this.left - this.options.padding / 2, y, this.yAxisFormat(v)).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end');
283
- _results.push(this.r.path("M" + this.left + "," + y + "H" + (this.left + this.width)).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth));
366
+ if (this.options.axes) {
367
+ this.drawYAxisLabel(this.left - this.options.padding / 2, y, this.yAxisFormat(v));
368
+ }
369
+ if (this.options.grid) {
370
+ _results.push(this.drawGridLine("M" + this.left + "," + y + "H" + (this.left + this.width)));
371
+ } else {
372
+ _results.push(void 0);
373
+ }
284
374
  }
285
375
  return _results;
286
376
  };
@@ -290,7 +380,7 @@
290
380
  if (fontSize == null) {
291
381
  fontSize = 12;
292
382
  }
293
- tt = this.r.text(100, 100, text).attr('font-size', fontSize);
383
+ tt = this.raphael.text(100, 100, text).attr('font-size', fontSize);
294
384
  ret = tt.getBBox();
295
385
  tt.remove();
296
386
  return ret;
@@ -301,7 +391,35 @@
301
391
  };
302
392
 
303
393
  Grid.prototype.yLabelFormat = function(label) {
304
- return "" + this.options.preUnits + (Morris.commas(label)) + this.options.postUnits;
394
+ if (typeof this.options.yLabelFormat === 'function') {
395
+ return this.options.yLabelFormat(label);
396
+ } else {
397
+ return "" + this.options.preUnits + (Morris.commas(label)) + this.options.postUnits;
398
+ }
399
+ };
400
+
401
+ Grid.prototype.updateHover = function(x, y) {
402
+ var hit, _ref;
403
+ hit = this.hitTest(x, y);
404
+ if (hit != null) {
405
+ return (_ref = this.hover).update.apply(_ref, hit);
406
+ }
407
+ };
408
+
409
+ Grid.prototype.drawGoal = function(path) {
410
+ return this.raphael.path(path).attr('stroke', this.options.goalLineColors[i % this.options.goalLineColors.length]).attr('stroke-width', this.options.goalStrokeWidth);
411
+ };
412
+
413
+ Grid.prototype.drawEvent = function(path) {
414
+ return this.raphael.path(path).attr('stroke', this.options.eventLineColors[i % this.options.eventLineColors.length]).attr('stroke-width', this.options.eventStrokeWidth);
415
+ };
416
+
417
+ Grid.prototype.drawYAxisLabel = function(xPos, yPos, text) {
418
+ return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end');
419
+ };
420
+
421
+ Grid.prototype.drawGridLine = function(path) {
422
+ return this.raphael.path(path).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth);
305
423
  };
306
424
 
307
425
  return Grid;
@@ -365,16 +483,78 @@
365
483
  }
366
484
  };
367
485
 
486
+ Morris.Hover = (function() {
487
+
488
+ Hover.defaults = {
489
+ "class": 'morris-hover morris-default-style'
490
+ };
491
+
492
+ function Hover(options) {
493
+ if (options == null) {
494
+ options = {};
495
+ }
496
+ this.options = $.extend({}, Morris.Hover.defaults, options);
497
+ this.el = $("<div class='" + this.options["class"] + "'></div>");
498
+ this.el.hide();
499
+ this.options.parent.append(this.el);
500
+ }
501
+
502
+ Hover.prototype.update = function(html, x, y) {
503
+ this.html(html);
504
+ this.show();
505
+ return this.moveTo(x, y);
506
+ };
507
+
508
+ Hover.prototype.html = function(content) {
509
+ return this.el.html(content);
510
+ };
511
+
512
+ Hover.prototype.moveTo = function(x, y) {
513
+ var hoverHeight, hoverWidth, left, parentHeight, parentWidth, top;
514
+ parentWidth = this.options.parent.innerWidth();
515
+ parentHeight = this.options.parent.innerHeight();
516
+ hoverWidth = this.el.outerWidth();
517
+ hoverHeight = this.el.outerHeight();
518
+ left = Math.min(Math.max(0, x - hoverWidth / 2), parentWidth - hoverWidth);
519
+ if (y != null) {
520
+ top = y - hoverHeight - 10;
521
+ if (top < 0) {
522
+ top = y + 10;
523
+ if (top + hoverHeight > parentHeight) {
524
+ top = parentHeight / 2 - hoverHeight / 2;
525
+ }
526
+ }
527
+ } else {
528
+ top = parentHeight / 2 - hoverHeight / 2;
529
+ }
530
+ return this.el.css({
531
+ left: left + "px",
532
+ top: top + "px"
533
+ });
534
+ };
535
+
536
+ Hover.prototype.show = function() {
537
+ return this.el.show();
538
+ };
539
+
540
+ Hover.prototype.hide = function() {
541
+ return this.el.hide();
542
+ };
543
+
544
+ return Hover;
545
+
546
+ })();
547
+
368
548
  Morris.Line = (function(_super) {
369
549
 
370
550
  __extends(Line, _super);
371
551
 
372
552
  function Line(options) {
373
- this.updateHilight = __bind(this.updateHilight, this);
374
-
375
553
  this.hilight = __bind(this.hilight, this);
376
554
 
377
- this.updateHover = __bind(this.updateHover, this);
555
+ this.onHoverOut = __bind(this.onHoverOut, this);
556
+
557
+ this.onHoverMove = __bind(this.onHoverMove, this);
378
558
  if (!(this instanceof Morris.Line)) {
379
559
  return new Morris.Line(options);
380
560
  }
@@ -382,32 +562,19 @@
382
562
  }
383
563
 
384
564
  Line.prototype.init = function() {
385
- var touchHandler,
386
- _this = this;
387
565
  this.pointGrow = Raphael.animation({
388
566
  r: this.options.pointSize + 3
389
567
  }, 25, 'linear');
390
568
  this.pointShrink = Raphael.animation({
391
569
  r: this.options.pointSize
392
570
  }, 25, 'linear');
393
- this.prevHilight = null;
394
- this.el.mousemove(function(evt) {
395
- return _this.updateHilight(evt.pageX);
396
- });
397
- if (this.options.hideHover) {
398
- this.el.mouseout(function(evt) {
399
- return _this.hilight(null);
571
+ if (this.options.hideHover !== 'always') {
572
+ this.hover = new Morris.Hover({
573
+ parent: this.el
400
574
  });
575
+ this.on('hovermove', this.onHoverMove);
576
+ return this.on('hoverout', this.onHoverOut);
401
577
  }
402
- touchHandler = function(evt) {
403
- var touch;
404
- touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
405
- _this.updateHilight(touch.pageX);
406
- return touch;
407
- };
408
- this.el.bind('touchstart', touchHandler);
409
- this.el.bind('touchmove', touchHandler);
410
- return this.el.bind('touchend', touchHandler);
411
578
  };
412
579
 
413
580
  Line.prototype.defaults = {
@@ -417,25 +584,17 @@
417
584
  pointWidths: [1],
418
585
  pointStrokeColors: ['#ffffff'],
419
586
  pointFillColors: [],
420
- hoverPaddingX: 10,
421
- hoverPaddingY: 5,
422
- hoverMargin: 10,
423
- hoverFillColor: '#fff',
424
- hoverBorderColor: '#ccc',
425
- hoverBorderWidth: 2,
426
- hoverOpacity: 0.95,
427
- hoverLabelColor: '#444',
428
- hoverFontSize: 12,
429
587
  smooth: true,
430
- hideHover: false,
431
588
  xLabels: 'auto',
432
- xLabelFormat: null
589
+ xLabelFormat: null,
590
+ xLabelMargin: 50,
591
+ continuousLine: true,
592
+ hideHover: false
433
593
  };
434
594
 
435
595
  Line.prototype.calc = function() {
436
596
  this.calcPoints();
437
- this.generatePaths();
438
- return this.calcHoverMargins();
597
+ return this.generatePaths();
439
598
  };
440
599
 
441
600
  Line.prototype.calcPoints = function() {
@@ -445,33 +604,89 @@
445
604
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
446
605
  row = _ref[_i];
447
606
  row._x = this.transX(row.x);
448
- _results.push(row._y = (function() {
607
+ row._y = (function() {
449
608
  var _j, _len1, _ref1, _results1;
450
609
  _ref1 = row.y;
451
610
  _results1 = [];
452
611
  for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
453
612
  y = _ref1[_j];
454
- if (y === null) {
455
- _results1.push(null);
456
- } else {
613
+ if (y != null) {
457
614
  _results1.push(this.transY(y));
615
+ } else {
616
+ _results1.push(y);
458
617
  }
459
618
  }
460
619
  return _results1;
461
- }).call(this));
620
+ }).call(this);
621
+ _results.push(row._ymax = Math.min.apply(null, [this.bottom].concat((function() {
622
+ var _j, _len1, _ref1, _results1;
623
+ _ref1 = row._y;
624
+ _results1 = [];
625
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
626
+ y = _ref1[_j];
627
+ if (y != null) {
628
+ _results1.push(y);
629
+ }
630
+ }
631
+ return _results1;
632
+ })())));
462
633
  }
463
634
  return _results;
464
635
  };
465
636
 
466
- Line.prototype.calcHoverMargins = function() {
467
- var _this = this;
468
- return this.hoverMargins = $.map(this.data.slice(1), function(r, i) {
469
- return (r._x + _this.data[i]._x) / 2;
470
- });
637
+ Line.prototype.hitTest = function(x, y) {
638
+ var index, r, _i, _len, _ref;
639
+ _ref = this.data.slice(1);
640
+ for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
641
+ r = _ref[index];
642
+ if (x < (r._x + this.data[index]._x) / 2) {
643
+ break;
644
+ }
645
+ }
646
+ return index;
647
+ };
648
+
649
+ Line.prototype.onHoverMove = function(x, y) {
650
+ var index;
651
+ index = this.hitTest(x, y);
652
+ return this.displayHoverForRow(index);
653
+ };
654
+
655
+ Line.prototype.onHoverOut = function() {
656
+ if (this.options.hideHover === 'auto') {
657
+ return this.displayHoverForRow(null);
658
+ }
659
+ };
660
+
661
+ Line.prototype.displayHoverForRow = function(index) {
662
+ var _ref;
663
+ if (index != null) {
664
+ (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));
665
+ return this.hilight(index);
666
+ } else {
667
+ this.hover.hide();
668
+ return this.hilight();
669
+ }
670
+ };
671
+
672
+ Line.prototype.hoverContentForRow = function(index) {
673
+ var content, j, row, y, _i, _len, _ref;
674
+ row = this.data[index];
675
+ if (typeof this.options.hoverCallback === 'function') {
676
+ content = this.options.hoverCallback(index, this.options);
677
+ } else {
678
+ content = "<div class='morris-hover-row-label'>" + row.label + "</div>";
679
+ _ref = row.y;
680
+ for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
681
+ y = _ref[j];
682
+ content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y)) + "\n</div>";
683
+ }
684
+ }
685
+ return [content, row._x, row._ymax];
471
686
  };
472
687
 
473
688
  Line.prototype.generatePaths = function() {
474
- var coords, i, r, smooth;
689
+ var c, coords, i, r, smooth;
475
690
  return this.paths = (function() {
476
691
  var _i, _ref, _ref1, _results;
477
692
  _results = [];
@@ -483,7 +698,7 @@
483
698
  _results1 = [];
484
699
  for (_j = 0, _len = _ref2.length; _j < _len; _j++) {
485
700
  r = _ref2[_j];
486
- if (r._y[i] !== null) {
701
+ if (r._y[i] !== void 0) {
487
702
  _results1.push({
488
703
  x: r._x,
489
704
  y: r._y[i]
@@ -492,8 +707,21 @@
492
707
  }
493
708
  return _results1;
494
709
  }).call(this);
710
+ if (this.options.continuousLine) {
711
+ coords = (function() {
712
+ var _j, _len, _results1;
713
+ _results1 = [];
714
+ for (_j = 0, _len = coords.length; _j < _len; _j++) {
715
+ c = coords[_j];
716
+ if (c.y !== null) {
717
+ _results1.push(c);
718
+ }
719
+ }
720
+ return _results1;
721
+ })();
722
+ }
495
723
  if (coords.length > 1) {
496
- _results.push(this.createPath(coords, smooth));
724
+ _results.push(Morris.Line.createPath(coords, smooth, this.bottom));
497
725
  } else {
498
726
  _results.push(null);
499
727
  }
@@ -503,24 +731,26 @@
503
731
  };
504
732
 
505
733
  Line.prototype.draw = function() {
506
- this.drawXAxis();
734
+ if (this.options.axes) {
735
+ this.drawXAxis();
736
+ }
507
737
  this.drawSeries();
508
- this.drawHover();
509
- return this.hilight(this.options.hideHover ? null : this.data.length - 1);
738
+ if (this.options.hideHover === false) {
739
+ return this.displayHoverForRow(this.data.length - 1);
740
+ }
510
741
  };
511
742
 
512
743
  Line.prototype.drawXAxis = function() {
513
- var drawLabel, l, labels, prevLabelMargin, row, xLabelMargin, ypos, _i, _len, _results,
744
+ var drawLabel, l, labels, prevLabelMargin, row, ypos, _i, _len, _results,
514
745
  _this = this;
515
746
  ypos = this.bottom + this.options.gridTextSize * 1.25;
516
- xLabelMargin = 50;
517
747
  prevLabelMargin = null;
518
748
  drawLabel = function(labelText, xpos) {
519
749
  var label, labelBox;
520
- label = _this.r.text(_this.transX(xpos), ypos, labelText).attr('font-size', _this.options.gridTextSize).attr('fill', _this.options.gridTextColor);
750
+ label = _this.drawXAxisLabel(_this.transX(xpos), ypos, labelText);
521
751
  labelBox = label.getBBox();
522
- if ((prevLabelMargin === null || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < _this.el.width()) {
523
- return prevLabelMargin = labelBox.x - xLabelMargin;
752
+ if ((!(prevLabelMargin != null) || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < _this.el.width()) {
753
+ return prevLabelMargin = labelBox.x - _this.options.xLabelMargin;
524
754
  } else {
525
755
  return label.remove();
526
756
  }
@@ -557,7 +787,7 @@
557
787
  for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
558
788
  path = this.paths[i];
559
789
  if (path !== null) {
560
- this.r.path(path).attr('stroke', this.colorForSeries(i)).attr('stroke-width', this.options.lineWidth);
790
+ this.drawLinePath(path, this.colorFor(row, i, 'line'));
561
791
  }
562
792
  }
563
793
  this.seriesPoints = (function() {
@@ -576,10 +806,10 @@
576
806
  _results1 = [];
577
807
  for (_k = 0, _len = _ref2.length; _k < _len; _k++) {
578
808
  row = _ref2[_k];
579
- if (row._y[i] === null) {
580
- circle = null;
809
+ if (row._y[i] != null) {
810
+ circle = this.drawLinePoint(row._x, row._y[i], this.options.pointSize, this.colorFor(row, i, 'point'), i);
581
811
  } else {
582
- circle = this.r.circle(row._x, row._y[i], this.options.pointSize).attr('fill', this.pointFillColorForSeries(i) || this.colorForSeries(i)).attr('stroke-width', this.strokeWidthForSeries(i)).attr('stroke', this.strokeForSeries(i));
812
+ circle = null;
583
813
  }
584
814
  _results1.push(this.seriesPoints[i].push(circle));
585
815
  }
@@ -589,108 +819,71 @@
589
819
  return _results;
590
820
  };
591
821
 
592
- Line.prototype.createPath = function(coords, smooth) {
593
- var c, g, grads, i, ix, lc, lg, path, x1, x2, y1, y2, _i, _ref;
822
+ Line.createPath = function(coords, smooth, bottom) {
823
+ var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;
594
824
  path = "";
595
825
  if (smooth) {
596
- grads = this.gradients(coords);
597
- for (i = _i = 0, _ref = coords.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
598
- c = coords[i];
599
- if (i === 0) {
600
- path += "M" + c.x + "," + c.y;
826
+ grads = Morris.Line.gradients(coords);
827
+ }
828
+ prevCoord = {
829
+ y: null
830
+ };
831
+ for (i = _i = 0, _len = coords.length; _i < _len; i = ++_i) {
832
+ coord = coords[i];
833
+ if (coord.y != null) {
834
+ if (prevCoord.y != null) {
835
+ if (smooth) {
836
+ g = grads[i];
837
+ lg = grads[i - 1];
838
+ ix = (coord.x - prevCoord.x) / 4;
839
+ x1 = prevCoord.x + ix;
840
+ y1 = Math.min(bottom, prevCoord.y + ix * lg);
841
+ x2 = coord.x - ix;
842
+ y2 = Math.min(bottom, coord.y - ix * g);
843
+ path += "C" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + coord.x + "," + coord.y;
844
+ } else {
845
+ path += "L" + coord.x + "," + coord.y;
846
+ }
601
847
  } else {
602
- g = grads[i];
603
- lc = coords[i - 1];
604
- lg = grads[i - 1];
605
- ix = (c.x - lc.x) / 4;
606
- x1 = lc.x + ix;
607
- y1 = Math.min(this.bottom, lc.y + ix * lg);
608
- x2 = c.x - ix;
609
- y2 = Math.min(this.bottom, c.y - ix * g);
610
- path += "C" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + c.x + "," + c.y;
848
+ if (!smooth || (grads[i] != null)) {
849
+ path += "M" + coord.x + "," + coord.y;
850
+ }
611
851
  }
612
852
  }
613
- } else {
614
- path = "M" + $.map(coords, function(c) {
615
- return "" + c.x + "," + c.y;
616
- }).join("L");
853
+ prevCoord = coord;
617
854
  }
618
855
  return path;
619
856
  };
620
857
 
621
- Line.prototype.gradients = function(coords) {
622
- return $.map(coords, function(c, i) {
623
- if (i === 0) {
624
- return (coords[1].y - c.y) / (coords[1].x - c.x);
625
- } else if (i === (coords.length - 1)) {
626
- return (c.y - coords[i - 1].y) / (c.x - coords[i - 1].x);
627
- } else {
628
- return (coords[i + 1].y - coords[i - 1].y) / (coords[i + 1].x - coords[i - 1].x);
629
- }
630
- });
631
- };
632
-
633
- Line.prototype.drawHover = function() {
634
- var i, idx, yLabel, _i, _ref, _results;
635
- this.hoverHeight = this.options.hoverFontSize * 1.5 * (this.options.ykeys.length + 1);
636
- this.hover = this.r.rect(-10, -this.hoverHeight / 2 - this.options.hoverPaddingY, 20, this.hoverHeight + this.options.hoverPaddingY * 2, 10).attr('fill', this.options.hoverFillColor).attr('stroke', this.options.hoverBorderColor).attr('stroke-width', this.options.hoverBorderWidth).attr('opacity', this.options.hoverOpacity);
637
- this.xLabel = this.r.text(0, (this.options.hoverFontSize * 0.75) - this.hoverHeight / 2, '').attr('fill', this.options.hoverLabelColor).attr('font-weight', 'bold').attr('font-size', this.options.hoverFontSize);
638
- this.hoverSet = this.r.set();
639
- this.hoverSet.push(this.hover);
640
- this.hoverSet.push(this.xLabel);
641
- this.yLabels = [];
858
+ Line.gradients = function(coords) {
859
+ var coord, grad, i, nextCoord, prevCoord, _i, _len, _results;
860
+ grad = function(a, b) {
861
+ return (a.y - b.y) / (a.x - b.x);
862
+ };
642
863
  _results = [];
643
- for (i = _i = 0, _ref = this.options.ykeys.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
644
- idx = this.cumulative ? this.options.ykeys.length - i - 1 : i;
645
- yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (idx + 1.5) - this.hoverHeight / 2, '').attr('fill', this.colorForSeries(i)).attr('font-size', this.options.hoverFontSize);
646
- this.yLabels.push(yLabel);
647
- _results.push(this.hoverSet.push(yLabel));
648
- }
649
- return _results;
650
- };
651
-
652
- Line.prototype.updateHover = function(index) {
653
- var i, maxLabelWidth, row, xloc, y, yloc, _i, _len, _ref;
654
- this.hoverSet.show();
655
- row = this.data[index];
656
- this.xLabel.attr('text', row.label);
657
- _ref = row.y;
658
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
659
- y = _ref[i];
660
- this.yLabels[i].attr('text', "" + this.options.labels[i] + ": " + (this.yLabelFormat(y)));
661
- }
662
- maxLabelWidth = Math.max.apply(null, $.map(this.yLabels, function(l) {
663
- return l.getBBox().width;
664
- }));
665
- maxLabelWidth = Math.max(maxLabelWidth, this.xLabel.getBBox().width);
666
- this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 2);
667
- this.hover.attr('x', -this.options.hoverPaddingX - maxLabelWidth / 2);
668
- yloc = Math.min.apply(null, ((function() {
669
- var _j, _len1, _ref1, _results;
670
- _ref1 = row._y;
671
- _results = [];
672
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
673
- y = _ref1[_j];
674
- if (y !== null) {
675
- _results.push(y);
864
+ for (i = _i = 0, _len = coords.length; _i < _len; i = ++_i) {
865
+ coord = coords[i];
866
+ if (coord.y != null) {
867
+ nextCoord = coords[i + 1] || {
868
+ y: null
869
+ };
870
+ prevCoord = coords[i - 1] || {
871
+ y: null
872
+ };
873
+ if ((prevCoord.y != null) && (nextCoord.y != null)) {
874
+ _results.push(grad(prevCoord, nextCoord));
875
+ } else if (prevCoord.y != null) {
876
+ _results.push(grad(prevCoord, coord));
877
+ } else if (nextCoord.y != null) {
878
+ _results.push(grad(coord, nextCoord));
879
+ } else {
880
+ _results.push(null);
676
881
  }
882
+ } else {
883
+ _results.push(null);
677
884
  }
678
- return _results;
679
- })()).concat(this.bottom));
680
- if (yloc > this.hoverHeight + this.options.hoverPaddingY * 2 + this.options.hoverMargin + this.top) {
681
- yloc = yloc - this.hoverHeight / 2 - this.options.hoverPaddingY - this.options.hoverMargin;
682
- } else {
683
- yloc = yloc + this.hoverHeight / 2 + this.options.hoverPaddingY + this.options.hoverMargin;
684
885
  }
685
- yloc = Math.max(this.top + this.hoverHeight / 2 + this.options.hoverPaddingY, yloc);
686
- yloc = Math.min(this.bottom - this.hoverHeight / 2 - this.options.hoverPaddingY, yloc);
687
- xloc = Math.min(this.right - maxLabelWidth / 2 - this.options.hoverPaddingX, this.data[index]._x);
688
- xloc = Math.max(this.left + maxLabelWidth / 2 + this.options.hoverPaddingX, xloc);
689
- return this.hoverSet.attr('transform', "t" + xloc + "," + yloc);
690
- };
691
-
692
- Line.prototype.hideHover = function() {
693
- return this.hoverSet.hide();
886
+ return _results;
694
887
  };
695
888
 
696
889
  Line.prototype.hilight = function(index) {
@@ -708,27 +901,30 @@
708
901
  this.seriesPoints[i][index].animate(this.pointGrow);
709
902
  }
710
903
  }
711
- this.updateHover(index);
712
- }
713
- this.prevHilight = index;
714
- if (index === null) {
715
- return this.hideHover();
716
904
  }
905
+ return this.prevHilight = index;
717
906
  };
718
907
 
719
- Line.prototype.updateHilight = function(x) {
720
- var hoverIndex, _i, _ref;
721
- x -= this.el.offset().left;
722
- for (hoverIndex = _i = 0, _ref = this.hoverMargins.length; 0 <= _ref ? _i < _ref : _i > _ref; hoverIndex = 0 <= _ref ? ++_i : --_i) {
723
- if (this.hoverMargins[hoverIndex] > x) {
724
- break;
725
- }
908
+ Line.prototype.colorFor = function(row, sidx, type) {
909
+ if (typeof this.options.lineColors === 'function') {
910
+ return this.options.lineColors.call(this, row, sidx, type);
911
+ } else if (type === 'point') {
912
+ return this.options.pointFillColors[sidx % this.options.pointFillColors.length] || this.options.lineColors[sidx % this.options.lineColors.length];
913
+ } else {
914
+ return this.options.lineColors[sidx % this.options.lineColors.length];
726
915
  }
727
- return this.hilight(hoverIndex);
728
916
  };
729
917
 
730
- Line.prototype.colorForSeries = function(index) {
731
- return this.options.lineColors[index % this.options.lineColors.length];
918
+ Line.prototype.drawXAxisLabel = function(xPos, yPos, text) {
919
+ return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor);
920
+ };
921
+
922
+ Line.prototype.drawLinePath = function(path, lineColor) {
923
+ return this.raphael.path(path).attr('stroke', lineColor).attr('stroke-width', this.options.lineWidth);
924
+ };
925
+
926
+ Line.prototype.drawLinePoint = function(xPos, yPos, size, pointColor, lineIndex) {
927
+ return this.raphael.circle(xPos, yPos, size).attr('fill', pointColor).attr('stroke-width', this.strokeWidthForSeries(lineIndex)).attr('stroke', this.strokeForSeries(lineIndex));
732
928
  };
733
929
 
734
930
  Line.prototype.strokeWidthForSeries = function(index) {
@@ -739,10 +935,6 @@
739
935
  return this.options.pointStrokeColors[index % this.options.pointStrokeColors.length];
740
936
  };
741
937
 
742
- Line.prototype.pointFillColorForSeries = function(index) {
743
- return this.options.pointFillColors[index % this.options.pointFillColors.length];
744
- };
745
-
746
938
  return Line;
747
939
 
748
940
  })(Morris.Grid);
@@ -813,6 +1005,18 @@
813
1005
  };
814
1006
 
815
1007
  Morris.LABEL_SPECS = {
1008
+ "decade": {
1009
+ span: 172800000000,
1010
+ start: function(d) {
1011
+ return new Date(d.getFullYear() - d.getFullYear() % 10, 0, 1);
1012
+ },
1013
+ fmt: function(d) {
1014
+ return "" + (d.getFullYear());
1015
+ },
1016
+ incr: function(d) {
1017
+ return d.setFullYear(d.getFullYear() + 10);
1018
+ }
1019
+ },
816
1020
  "year": {
817
1021
  span: 17280000000,
818
1022
  start: function(d) {
@@ -862,7 +1066,7 @@
862
1066
  "second": secondsSpecHelper(1)
863
1067
  };
864
1068
 
865
- Morris.AUTO_LABEL_ORDER = ["year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
1069
+ Morris.AUTO_LABEL_ORDER = ["decade", "year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
866
1070
 
867
1071
  Morris.Area = (function(_super) {
868
1072
 
@@ -884,7 +1088,7 @@
884
1088
  row = _ref[_i];
885
1089
  row._x = this.transX(row.x);
886
1090
  total = 0;
887
- _results.push(row._y = (function() {
1091
+ row._y = (function() {
888
1092
  var _j, _len1, _ref1, _results1;
889
1093
  _ref1 = row.y;
890
1094
  _results1 = [];
@@ -894,7 +1098,8 @@
894
1098
  _results1.push(this.transY(total));
895
1099
  }
896
1100
  return _results1;
897
- }).call(this));
1101
+ }).call(this);
1102
+ _results.push(row._ymax = row._y[row._y.length - 1]);
898
1103
  }
899
1104
  return _results;
900
1105
  };
@@ -905,7 +1110,7 @@
905
1110
  path = this.paths[i];
906
1111
  if (path !== null) {
907
1112
  path = path + ("L" + (this.transX(this.xmax)) + "," + this.bottom + "L" + (this.transX(this.xmin)) + "," + this.bottom + "Z");
908
- this.r.path(path).attr('fill', this.fillForSeries(i)).attr('stroke-width', 0);
1113
+ this.drawFilledPath(path, this.fillForSeries(i));
909
1114
  }
910
1115
  }
911
1116
  return Area.__super__.drawSeries.call(this);
@@ -913,10 +1118,14 @@
913
1118
 
914
1119
  Area.prototype.fillForSeries = function(i) {
915
1120
  var color;
916
- color = Raphael.rgb2hsl(this.colorForSeries(i));
1121
+ color = Raphael.rgb2hsl(this.colorFor(this.data[i], i, 'line'));
917
1122
  return Raphael.hsl(color.h, Math.min(255, color.s * 0.75), Math.min(255, color.l * 1.25));
918
1123
  };
919
1124
 
1125
+ Area.prototype.drawFilledPath = function(path, fill) {
1126
+ return this.raphael.path(path).attr('fill', fill).attr('stroke-width', 0);
1127
+ };
1128
+
920
1129
  return Area;
921
1130
 
922
1131
  })(Morris.Line);
@@ -926,11 +1135,9 @@
926
1135
  __extends(Bar, _super);
927
1136
 
928
1137
  function Bar(options) {
929
- this.updateHilight = __bind(this.updateHilight, this);
1138
+ this.onHoverOut = __bind(this.onHoverOut, this);
930
1139
 
931
- this.hilight = __bind(this.hilight, this);
932
-
933
- this.updateHover = __bind(this.updateHover, this);
1140
+ this.onHoverMove = __bind(this.onHoverMove, this);
934
1141
  if (!(this instanceof Morris.Bar)) {
935
1142
  return new Morris.Bar(options);
936
1143
  }
@@ -940,47 +1147,29 @@
940
1147
  }
941
1148
 
942
1149
  Bar.prototype.init = function() {
943
- var touchHandler,
944
- _this = this;
945
- this.prevHilight = null;
946
- this.el.mousemove(function(evt) {
947
- return _this.updateHilight(evt.pageX);
948
- });
949
- if (this.options.hideHover) {
950
- this.el.mouseout(function(evt) {
951
- return _this.hilight(null);
1150
+ this.cumulative = this.options.stacked;
1151
+ if (this.options.hideHover !== 'always') {
1152
+ this.hover = new Morris.Hover({
1153
+ parent: this.el
952
1154
  });
1155
+ this.on('hovermove', this.onHoverMove);
1156
+ return this.on('hoverout', this.onHoverOut);
953
1157
  }
954
- touchHandler = function(evt) {
955
- var touch;
956
- touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];
957
- _this.updateHilight(touch.pageX);
958
- return touch;
959
- };
960
- this.el.bind('touchstart', touchHandler);
961
- this.el.bind('touchmove', touchHandler);
962
- return this.el.bind('touchend', touchHandler);
963
1158
  };
964
1159
 
965
1160
  Bar.prototype.defaults = {
966
1161
  barSizeRatio: 0.75,
967
1162
  barGap: 3,
968
1163
  barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
969
- hoverPaddingX: 10,
970
- hoverPaddingY: 5,
971
- hoverMargin: 10,
972
- hoverFillColor: '#fff',
973
- hoverBorderColor: '#ccc',
974
- hoverBorderWidth: 2,
975
- hoverOpacity: 0.95,
976
- hoverLabelColor: '#444',
977
- hoverFontSize: 12,
978
- hideHover: false
1164
+ xLabelMargin: 50
979
1165
  };
980
1166
 
981
1167
  Bar.prototype.calc = function() {
1168
+ var _ref;
982
1169
  this.calcBars();
983
- return this.calcHoverMargins();
1170
+ if (this.options.hideHover === false) {
1171
+ return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(this.data.length - 1));
1172
+ }
984
1173
  };
985
1174
 
986
1175
  Bar.prototype.calcBars = function() {
@@ -996,10 +1185,10 @@
996
1185
  _results1 = [];
997
1186
  for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
998
1187
  y = _ref1[_j];
999
- if (y === null) {
1000
- _results1.push(null);
1001
- } else {
1188
+ if (y != null) {
1002
1189
  _results1.push(this.transY(y));
1190
+ } else {
1191
+ _results1.push(null);
1003
1192
  }
1004
1193
  }
1005
1194
  return _results1;
@@ -1008,37 +1197,24 @@
1008
1197
  return _results;
1009
1198
  };
1010
1199
 
1011
- Bar.prototype.calcHoverMargins = function() {
1012
- var i;
1013
- return this.hoverMargins = (function() {
1014
- var _i, _ref, _results;
1015
- _results = [];
1016
- for (i = _i = 1, _ref = this.data.length; 1 <= _ref ? _i < _ref : _i > _ref; i = 1 <= _ref ? ++_i : --_i) {
1017
- _results.push(this.left + i * this.width / this.data.length);
1018
- }
1019
- return _results;
1020
- }).call(this);
1021
- };
1022
-
1023
1200
  Bar.prototype.draw = function() {
1024
- this.drawXAxis();
1025
- this.drawSeries();
1026
- this.drawHover();
1027
- return this.hilight(this.options.hideHover ? null : this.data.length - 1);
1201
+ if (this.options.axes) {
1202
+ this.drawXAxis();
1203
+ }
1204
+ return this.drawSeries();
1028
1205
  };
1029
1206
 
1030
1207
  Bar.prototype.drawXAxis = function() {
1031
- var i, label, labelBox, prevLabelMargin, row, xLabelMargin, ypos, _i, _ref, _results;
1208
+ var i, label, labelBox, prevLabelMargin, row, ypos, _i, _ref, _results;
1032
1209
  ypos = this.bottom + this.options.gridTextSize * 1.25;
1033
- xLabelMargin = 50;
1034
1210
  prevLabelMargin = null;
1035
1211
  _results = [];
1036
1212
  for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
1037
1213
  row = this.data[this.data.length - 1 - i];
1038
- label = this.r.text(row._x, ypos, row.label).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor);
1214
+ label = this.drawXAxisLabel(row._x, ypos, row.label);
1039
1215
  labelBox = label.getBBox();
1040
- if ((prevLabelMargin === null || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < this.el.width()) {
1041
- _results.push(prevLabelMargin = labelBox.x - xLabelMargin);
1216
+ if ((!(prevLabelMargin != null) || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < this.el.width()) {
1217
+ _results.push(prevLabelMargin = labelBox.x - this.options.xLabelMargin);
1042
1218
  } else {
1043
1219
  _results.push(label.remove());
1044
1220
  }
@@ -1047,9 +1223,9 @@
1047
1223
  };
1048
1224
 
1049
1225
  Bar.prototype.drawSeries = function() {
1050
- var barWidth, bottom, groupWidth, idx, left, leftPadding, numBars, row, sidx, top, ypos, zeroPos;
1226
+ var barWidth, bottom, groupWidth, idx, lastTop, left, leftPadding, numBars, row, sidx, size, top, ypos, zeroPos;
1051
1227
  groupWidth = this.width / this.options.data.length;
1052
- numBars = this.options.ykeys.length;
1228
+ numBars = this.options.stacked != null ? 1 : this.options.ykeys.length;
1053
1229
  barWidth = (groupWidth * this.options.barSizeRatio - this.options.barGap * (numBars - 1)) / numBars;
1054
1230
  leftPadding = groupWidth * (1 - this.options.barSizeRatio) / 2;
1055
1231
  zeroPos = this.ymin <= 0 && this.ymax >= 0 ? this.transY(0) : null;
@@ -1059,6 +1235,7 @@
1059
1235
  _results = [];
1060
1236
  for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
1061
1237
  row = _ref[idx];
1238
+ lastTop = 0;
1062
1239
  _results.push((function() {
1063
1240
  var _j, _len1, _ref1, _results1;
1064
1241
  _ref1 = row._y;
@@ -1073,8 +1250,16 @@
1073
1250
  top = ypos;
1074
1251
  bottom = this.bottom;
1075
1252
  }
1076
- left = this.left + idx * groupWidth + leftPadding + sidx * (barWidth + this.options.barGap);
1077
- _results1.push(this.r.rect(left, top, barWidth, bottom - top).attr('fill', this.options.barColors[sidx % this.options.barColors.length]).attr('stroke-width', 0));
1253
+ left = this.left + idx * groupWidth + leftPadding;
1254
+ if (!this.options.stacked) {
1255
+ left += sidx * (barWidth + this.options.barGap);
1256
+ }
1257
+ size = bottom - top;
1258
+ if (this.options.stacked) {
1259
+ top -= lastTop;
1260
+ }
1261
+ this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar'));
1262
+ _results1.push(lastTop += size);
1078
1263
  } else {
1079
1264
  _results1.push(null);
1080
1265
  }
@@ -1086,70 +1271,66 @@
1086
1271
  }).call(this);
1087
1272
  };
1088
1273
 
1089
- Bar.prototype.drawHover = function() {
1090
- var i, yLabel, _i, _ref, _results;
1091
- this.hoverHeight = this.options.hoverFontSize * 1.5 * (this.options.ykeys.length + 1);
1092
- this.hover = this.r.rect(-10, -this.hoverHeight / 2 - this.options.hoverPaddingY, 20, this.hoverHeight + this.options.hoverPaddingY * 2, 10).attr('fill', this.options.hoverFillColor).attr('stroke', this.options.hoverBorderColor).attr('stroke-width', this.options.hoverBorderWidth).attr('opacity', this.options.hoverOpacity);
1093
- this.xLabel = this.r.text(0, (this.options.hoverFontSize * 0.75) - this.hoverHeight / 2, '').attr('fill', this.options.hoverLabelColor).attr('font-weight', 'bold').attr('font-size', this.options.hoverFontSize);
1094
- this.hoverSet = this.r.set();
1095
- this.hoverSet.push(this.hover);
1096
- this.hoverSet.push(this.xLabel);
1097
- this.yLabels = [];
1098
- _results = [];
1099
- for (i = _i = 0, _ref = this.options.ykeys.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
1100
- yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (i + 1.5) - this.hoverHeight / 2, '').attr('font-size', this.options.hoverFontSize);
1101
- this.yLabels.push(yLabel);
1102
- _results.push(this.hoverSet.push(yLabel));
1274
+ Bar.prototype.colorFor = function(row, sidx, type) {
1275
+ var r, s;
1276
+ if (typeof this.options.barColors === 'function') {
1277
+ r = {
1278
+ x: row.x,
1279
+ y: row.y[sidx],
1280
+ label: row.label
1281
+ };
1282
+ s = {
1283
+ index: sidx,
1284
+ key: this.options.ykeys[sidx],
1285
+ label: this.options.labels[sidx]
1286
+ };
1287
+ return this.options.barColors.call(this, r, s, type);
1288
+ } else {
1289
+ return this.options.barColors[sidx % this.options.barColors.length];
1103
1290
  }
1104
- return _results;
1105
1291
  };
1106
1292
 
1107
- Bar.prototype.updateHover = function(index) {
1108
- var i, maxLabelWidth, row, xloc, y, yloc, _i, _len, _ref;
1109
- this.hoverSet.show();
1110
- row = this.data[index];
1111
- this.xLabel.attr('text', row.label);
1112
- _ref = row.y;
1113
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
1114
- y = _ref[i];
1115
- this.yLabels[i].attr('fill', this.options.barColors[i % this.options.barColors.length]);
1116
- this.yLabels[i].attr('text', "" + this.options.labels[i] + ": " + (this.yLabelFormat(y)));
1117
- }
1118
- maxLabelWidth = Math.max.apply(null, $.map(this.yLabels, function(l) {
1119
- return l.getBBox().width;
1120
- }));
1121
- maxLabelWidth = Math.max(maxLabelWidth, this.xLabel.getBBox().width);
1122
- this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 2);
1123
- this.hover.attr('x', -this.options.hoverPaddingX - maxLabelWidth / 2);
1124
- yloc = (this.bottom + this.top) / 2;
1125
- xloc = Math.min(this.right - maxLabelWidth / 2 - this.options.hoverPaddingX, this.data[index]._x);
1126
- xloc = Math.max(this.left + maxLabelWidth / 2 + this.options.hoverPaddingX, xloc);
1127
- return this.hoverSet.attr('transform', "t" + xloc + "," + yloc);
1293
+ Bar.prototype.hitTest = function(x, y) {
1294
+ x = Math.max(Math.min(x, this.right), this.left);
1295
+ return Math.min(this.data.length - 1, Math.floor((x - this.left) / (this.width / this.data.length)));
1128
1296
  };
1129
1297
 
1130
- Bar.prototype.hideHover = function() {
1131
- return this.hoverSet.hide();
1298
+ Bar.prototype.onHoverMove = function(x, y) {
1299
+ var index, _ref;
1300
+ index = this.hitTest(x, y);
1301
+ return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));
1132
1302
  };
1133
1303
 
1134
- Bar.prototype.hilight = function(index) {
1135
- if (index !== null && this.prevHilight !== index) {
1136
- this.updateHover(index);
1137
- }
1138
- this.prevHilight = index;
1139
- if (index === null) {
1140
- return this.hideHover();
1304
+ Bar.prototype.onHoverOut = function() {
1305
+ if (this.options.hideHover === 'auto') {
1306
+ return this.hover.hide();
1141
1307
  }
1142
1308
  };
1143
1309
 
1144
- Bar.prototype.updateHilight = function(x) {
1145
- var hoverIndex, _i, _ref;
1146
- x -= this.el.offset().left;
1147
- for (hoverIndex = _i = 0, _ref = this.hoverMargins.length; 0 <= _ref ? _i < _ref : _i > _ref; hoverIndex = 0 <= _ref ? ++_i : --_i) {
1148
- if (this.hoverMargins[hoverIndex] > x) {
1149
- break;
1310
+ Bar.prototype.hoverContentForRow = function(index) {
1311
+ var content, j, row, x, y, _i, _len, _ref;
1312
+ if (typeof this.options.hoverCallback === 'function') {
1313
+ content = this.options.hoverCallback(index, this.options);
1314
+ } else {
1315
+ row = this.data[index];
1316
+ content = "<div class='morris-hover-row-label'>" + row.label + "</div>";
1317
+ _ref = row.y;
1318
+ for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {
1319
+ y = _ref[j];
1320
+ content += "<div class='morris-hover-point' style='color: " + (this.colorFor(row, j, 'label')) + "'>\n " + this.options.labels[j] + ":\n " + (this.yLabelFormat(y)) + "\n</div>";
1150
1321
  }
1151
1322
  }
1152
- return this.hilight(hoverIndex);
1323
+ x = this.left + (index + 0.5) * this.width / this.data.length;
1324
+ return [content, x];
1325
+ };
1326
+
1327
+ Bar.prototype.drawXAxisLabel = function(xPos, yPos, text) {
1328
+ var label;
1329
+ return label = this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor);
1330
+ };
1331
+
1332
+ Bar.prototype.drawBar = function(xPos, yPos, width, height, barColor) {
1333
+ return this.raphael.rect(xPos, yPos, width, height).attr('fill', barColor).attr('stroke-width', 0);
1153
1334
  };
1154
1335
 
1155
1336
  return Bar;
@@ -1160,6 +1341,7 @@
1160
1341
 
1161
1342
  Donut.prototype.defaults = {
1162
1343
  colors: ['#0B62A4', '#3980B5', '#679DC6', '#95BBD7', '#B0CCE1', '#095791', '#095085', '#083E67', '#052C48', '#042135'],
1344
+ backgroundColor: '#FFFFFF',
1163
1345
  formatter: Morris.commas
1164
1346
  };
1165
1347
 
@@ -1181,14 +1363,13 @@
1181
1363
  return;
1182
1364
  }
1183
1365
  this.data = options.data;
1184
- this.el.addClass('graph-initialised');
1185
1366
  this.redraw();
1186
1367
  }
1187
1368
 
1188
1369
  Donut.prototype.redraw = function() {
1189
1370
  var C, cx, cy, d, idx, last, max_value, min, next, seg, total, w, x, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;
1190
1371
  this.el.empty();
1191
- this.r = new Raphael(this.el[0]);
1372
+ this.raphael = new Raphael(this.el[0]);
1192
1373
  cx = this.el.width() / 2;
1193
1374
  cy = this.el.height() / 2;
1194
1375
  w = (Math.min(cx, cy) - 10) / 3;
@@ -1207,20 +1388,15 @@
1207
1388
  for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
1208
1389
  d = _ref1[_j];
1209
1390
  next = last + min + C * (d.value / total);
1210
- seg = new Morris.DonutSegment(cx, cy, w * 2, w, last, next, this.options.colors[idx % this.options.colors.length], d);
1211
- seg.render(this.r);
1391
+ seg = new Morris.DonutSegment(cx, cy, w * 2, w, last, next, this.options.colors[idx % this.options.colors.length], this.options.backgroundColor, d, this.raphael);
1392
+ seg.render();
1212
1393
  this.segments.push(seg);
1213
1394
  seg.on('hover', this.select);
1214
1395
  last = next;
1215
1396
  idx += 1;
1216
1397
  }
1217
- this.text1 = this.r.text(cx, cy - 10, '').attr({
1218
- 'font-size': 15,
1219
- 'font-weight': 800
1220
- });
1221
- this.text2 = this.r.text(cx, cy + 10, '').attr({
1222
- 'font-size': 14
1223
- });
1398
+ this.text1 = this.drawEmptyDonutLabel(cx, cy - 10, 15, 800);
1399
+ this.text2 = this.drawEmptyDonutLabel(cx, cy + 10, 14);
1224
1400
  max_value = Math.max.apply(null, (function() {
1225
1401
  var _k, _len2, _ref2, _results;
1226
1402
  _ref2 = this.data;
@@ -1258,7 +1434,7 @@
1258
1434
  segment = idx;
1259
1435
  }
1260
1436
  segment.select();
1261
- return this.setLabels(segment.data.label, this.options.formatter(segment.data.value));
1437
+ return this.setLabels(segment.data.label, this.options.formatter(segment.data.value, segment.data));
1262
1438
  };
1263
1439
 
1264
1440
  Donut.prototype.setLabels = function(label1, label2) {
@@ -1287,6 +1463,15 @@
1287
1463
  });
1288
1464
  };
1289
1465
 
1466
+ Donut.prototype.drawEmptyDonutLabel = function(xPos, yPos, fontSize, fontWeight) {
1467
+ var text;
1468
+ text = this.raphael.text(xPos, yPos, '').attr('font-size', fontSize);
1469
+ if (fontWeight != null) {
1470
+ text.attr('font-weight', fontWeight);
1471
+ }
1472
+ return text;
1473
+ };
1474
+
1290
1475
  return Donut;
1291
1476
 
1292
1477
  })();
@@ -1295,13 +1480,15 @@
1295
1480
 
1296
1481
  __extends(DonutSegment, _super);
1297
1482
 
1298
- function DonutSegment(cx, cy, inner, outer, p0, p1, color, data) {
1483
+ function DonutSegment(cx, cy, inner, outer, p0, p1, color, backgroundColor, data, raphael) {
1299
1484
  this.cx = cx;
1300
1485
  this.cy = cy;
1301
1486
  this.inner = inner;
1302
1487
  this.outer = outer;
1303
1488
  this.color = color;
1489
+ this.backgroundColor = backgroundColor;
1304
1490
  this.data = data;
1491
+ this.raphael = raphael;
1305
1492
  this.deselect = __bind(this.deselect, this);
1306
1493
 
1307
1494
  this.select = __bind(this.select, this);
@@ -1310,7 +1497,7 @@
1310
1497
  this.cos_p0 = Math.cos(p0);
1311
1498
  this.sin_p1 = Math.sin(p1);
1312
1499
  this.cos_p1 = Math.cos(p1);
1313
- this.long = (p1 - p0) > Math.PI ? 1 : 0;
1500
+ this.is_long = (p1 - p0) > Math.PI ? 1 : 0;
1314
1501
  this.path = this.calcSegment(this.inner + 3, this.inner + this.outer - 5);
1315
1502
  this.selectedPath = this.calcSegment(this.inner + 3, this.inner + this.outer);
1316
1503
  this.hilight = this.calcArc(this.inner);
@@ -1324,29 +1511,37 @@
1324
1511
  var ix0, ix1, iy0, iy1, ox0, ox1, oy0, oy1, _ref, _ref1;
1325
1512
  _ref = this.calcArcPoints(r1), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
1326
1513
  _ref1 = this.calcArcPoints(r2), ox0 = _ref1[0], oy0 = _ref1[1], ox1 = _ref1[2], oy1 = _ref1[3];
1327
- return ("M" + ix0 + "," + iy0) + ("A" + r1 + "," + r1 + ",0," + this.long + ",0," + ix1 + "," + iy1) + ("L" + ox1 + "," + oy1) + ("A" + r2 + "," + r2 + ",0," + this.long + ",1," + ox0 + "," + oy0) + "Z";
1514
+ 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";
1328
1515
  };
1329
1516
 
1330
1517
  DonutSegment.prototype.calcArc = function(r) {
1331
1518
  var ix0, ix1, iy0, iy1, _ref;
1332
1519
  _ref = this.calcArcPoints(r), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
1333
- return ("M" + ix0 + "," + iy0) + ("A" + r + "," + r + ",0," + this.long + ",0," + ix1 + "," + iy1);
1520
+ return ("M" + ix0 + "," + iy0) + ("A" + r + "," + r + ",0," + this.is_long + ",0," + ix1 + "," + iy1);
1334
1521
  };
1335
1522
 
1336
- DonutSegment.prototype.render = function(r) {
1523
+ DonutSegment.prototype.render = function() {
1337
1524
  var _this = this;
1338
- this.arc = r.path(this.hilight).attr({
1339
- stroke: this.color,
1525
+ this.arc = this.drawDonutArc(this.hilight, this.color);
1526
+ return this.seg = this.drawDonutSegment(this.path, this.color, this.backgroundColor, function() {
1527
+ return _this.fire('hover', _this);
1528
+ });
1529
+ };
1530
+
1531
+ DonutSegment.prototype.drawDonutArc = function(path, color) {
1532
+ return this.raphael.path(path).attr({
1533
+ stroke: color,
1340
1534
  'stroke-width': 2,
1341
1535
  opacity: 0
1342
1536
  });
1343
- return this.seg = r.path(this.path).attr({
1344
- fill: this.color,
1345
- stroke: 'white',
1537
+ };
1538
+
1539
+ DonutSegment.prototype.drawDonutSegment = function(path, fillColor, strokeColor, hoverFunction) {
1540
+ return this.raphael.path(path).attr({
1541
+ fill: fillColor,
1542
+ stroke: strokeColor,
1346
1543
  'stroke-width': 3
1347
- }).hover(function() {
1348
- return _this.fire('hover', _this);
1349
- });
1544
+ }).hover(hoverFunction);
1350
1545
  };
1351
1546
 
1352
1547
  DonutSegment.prototype.select = function() {