Initial area charts.

This commit is contained in:
Olly Smith 2012-10-28 18:55:37 +00:00
parent 16b88ba1de
commit f72b14f619
7 changed files with 472 additions and 278 deletions

29
examples/area.html Normal file
View File

@ -0,0 +1,29 @@
<!doctype html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://raw.github.com/DmitryBaranovskiy/raphael/300aa589f5a0ba7fce667cd62c7cdda0bd5ad904/raphael-min.js"></script>
<script src="../morris.js"></script>
<script src="lib/prettify.js"></script>
<script src="lib/example.js"></script>
<link rel="stylesheet" href="lib/example.css">
<link rel="stylesheet" href="lib/prettify.css">
</head>
<body>
<h1>Area charts</h1>
<div id="graph"></div>
<pre id="code" class="prettyprint linenums">
// Use Morris.Area instead of Morris.Line
Morris.Area({
element: 'graph',
data: [
{x: '2011 Q1', y: 3, z: 3},
{x: '2011 Q2', y: 2, z: 0},
{x: '2011 Q3', y: 0, z: 2},
{x: '2011 Q4', y: 4, z: 4}
],
xkey: 'x',
ykeys: ['y', 'z'],
labels: ['Y', 'Z']
});
</pre>
</body>

View File

@ -13,7 +13,13 @@ module.exports = function (grunt) {
} }
}, },
concat: { concat: {
'build/morris.coffee': ['lib/**/*.coffee'], 'build/morris.coffee': [
'lib/morris.coffee',
'lib/morris.grid.coffee',
'lib/morris.line.coffee',
'lib/morris.area.coffee',
'lib/morris.donut.coffee'
],
'build/spec.coffee': ['spec/support/**/*.coffee', 'spec/lib/**/*.coffee'] 'build/spec.coffee': ['spec/support/**/*.coffee', 'spec/lib/**/*.coffee']
}, },
min: { min: {

38
lib/morris.area.coffee Normal file
View File

@ -0,0 +1,38 @@
class Morris.Area extends Morris.Line
# Initialise
#
constructor: (options) ->
return new Morris.Area(options) unless (@ instanceof Morris.Area)
@cumulative = true
super(options)
# calculate series data point coordinates
#
# @private
calcPoints: ->
for row in @data
row._x = @transX(row.x)
total = 0
row._y = for y in row.y
total += (y || 0)
@transY(total)
# draw the data series
#
# @private
drawSeries: ->
for i in [@options.ykeys.length-1..0]
path = @paths[i]
if path isnt null
path = path + "L#{@transX(@xmax)},#{@bottom}L#{@transX(@xmin)},#{@bottom}Z"
@r.path(path)
.attr('fill', @fillForSeries(i))
.attr('stroke-width', 0)
super()
fillForSeries: (i) ->
color = Raphael.rgb2hsl @colorForSeries(i)
Raphael.hsl(
color.h,
Math.min(255, color.s * 0.75),
Math.min(255, color.l * 1.25))

View File

@ -55,8 +55,8 @@ class Morris.Grid extends Morris.EventEmitter
# Update the data series and redraw the chart. # Update the data series and redraw the chart.
# #
setData: (data, redraw = true) -> setData: (data, redraw = true) ->
ymax = null ymax = if @cumulative then 0 else null
ymin = null ymin = if @cumulative then 0 else null
@data = $.map data, (row, index) => @data = $.map data, (row, index) =>
ret = {} ret = {}
ret.label = row[@options.xkey] ret.label = row[@options.xkey]
@ -68,16 +68,23 @@ class Morris.Grid extends Morris.EventEmitter
ret.label = new Date(ret.label).toString() ret.label = new Date(ret.label).toString()
else else
ret.x = index ret.x = index
ret.y = for ykey in @options.ykeys total = 0
ret.y = for ykey, idx in @options.ykeys
yval = row[ykey] yval = row[ykey]
yval = parseFloat(yval) if typeof yval is 'string' yval = parseFloat(yval) if typeof yval is 'string'
yval = null unless typeof yval is 'number' yval = null unless typeof yval is 'number'
unless yval is null unless yval is null
if ymax is null if @cumulative
ymax = ymin = yval total += yval
else else
ymax = Math.max(yval, ymax) if ymax is null
ymin = Math.min(yval, ymin) ymax = ymin = yval
else
ymax = Math.max(yval, ymax)
ymin = Math.min(yval, ymin)
if @cumulative and total isnt null
ymax = Math.max(total, ymax)
ymin = Math.min(total, ymin)
yval yval
ret ret

View File

@ -59,7 +59,14 @@ class Morris.Line extends Morris.Grid
# #
# @private # @private
calc: -> calc: ->
# calculate series data point coordinates @calcPoints()
@generatePaths()
@calcHoverMargins()
# calculate series data point coordinates
#
# @private
calcPoints: ->
for row in @data for row in @data
row._x = @transX(row.x) row._x = @transX(row.x)
row._y = for y in row.y row._y = for y in row.y
@ -67,9 +74,25 @@ class Morris.Line extends Morris.Grid
null null
else else
@transY(y) @transY(y)
# calculate hover margins
# calculate hover margins
#
# @private
calcHoverMargins: ->
@hoverMargins = $.map @data.slice(1), (r, i) => (r._x + @data[i]._x) / 2 @hoverMargins = $.map @data.slice(1), (r, i) => (r._x + @data[i]._x) / 2
# generate paths for series lines
#
# @private
generatePaths: ->
@paths = for i in [0...@options.ykeys.length]
smooth = @options.smooth is true or @options.ykeys[i] in @options.smooth
coords = ({x: r._x, y: r._y[i]} for r in @data when r._y[i] isnt null)
if coords.length > 1
@createPath coords, smooth
else
null
# Draws the line chart. # Draws the line chart.
# #
draw: -> draw: ->
@ -116,11 +139,8 @@ class Morris.Line extends Morris.Grid
# @private # @private
drawSeries: -> drawSeries: ->
for i in [@options.ykeys.length-1..0] for i in [@options.ykeys.length-1..0]
coords = ({x: r._x, y: r._y[i]} for r in @data when r._y[i] isnt null) path = @paths[i]
smooth = @options.smooth is true or if path isnt null
$.inArray(@options.ykeys[i], @options.smooth) > -1
if coords.length > 1
path = @createPath coords, @bottom, smooth
@r.path(path) @r.path(path)
.attr('stroke', @colorForSeries(i)) .attr('stroke', @colorForSeries(i))
.attr('stroke-width', @options.lineWidth) .attr('stroke-width', @options.lineWidth)
@ -213,7 +233,7 @@ class Morris.Line extends Morris.Grid
@hover.attr 'width', maxLabelWidth + @options.hoverPaddingX * 2 @hover.attr 'width', maxLabelWidth + @options.hoverPaddingX * 2
@hover.attr 'x', -@options.hoverPaddingX - maxLabelWidth / 2 @hover.attr 'x', -@options.hoverPaddingX - maxLabelWidth / 2
# move to y pos # move to y pos
yloc = Math.min.apply null, row.y yloc = Math.min.apply null, row._y
if yloc > @hoverHeight + @options.hoverPaddingY * 2 + @options.hoverMargin + @top if yloc > @hoverHeight + @options.hoverPaddingY * 2 + @options.hoverMargin + @top
yloc = yloc - @hoverHeight / 2 - @options.hoverPaddingY - @options.hoverMargin yloc = yloc - @hoverHeight / 2 - @options.hoverPaddingY - @options.hoverMargin
else else

616
morris.js
View File

@ -1,9 +1,10 @@
(function() { (function() {
var $, Morris, minutesSpecHelper, secondsSpecHelper, var $, Morris, minutesSpecHelper, secondsSpecHelper,
__slice = [].slice, __slice = [].slice,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty, __hasProp = {}.hasOwnProperty,
__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; }; __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; },
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__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; };
Morris = window.Morris = {}; Morris = window.Morris = {};
@ -62,227 +63,6 @@
return (number < 10 ? '0' : '') + number; return (number < 10 ? '0' : '') + number;
}; };
Morris.Donut = (function() {
Donut.prototype.defaults = {
colors: ['#0B62A4', '#3980B5', '#679DC6', '#95BBD7', '#B0CCE1', '#095791', '#095085', '#083E67', '#052C48', '#042135'],
formatter: Morris.commas
};
function Donut(options) {
this.select = __bind(this.select, this);
if (!(this instanceof Morris.Donut)) {
return new Morris.Donut(options);
}
if (typeof options.element === 'string') {
this.el = $(document.getElementById(options.element));
} else {
this.el = $(options.element);
}
this.options = $.extend({}, this.defaults, options);
if (this.el === null || this.el.length === 0) {
throw new Error("Graph placeholder not found.");
}
if (options.data === void 0 || options.data.length === 0) {
return;
}
this.data = options.data;
this.el.addClass('graph-initialised');
this.redraw();
}
Donut.prototype.redraw = function() {
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;
this.el.empty();
this.r = new Raphael(this.el[0]);
cx = this.el.width() / 2;
cy = this.el.height() / 2;
w = (Math.min(cx, cy) - 10) / 3;
total = 0;
_ref = this.data;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
x = _ref[_i];
total += x.value;
}
min = 5 / (2 * w);
C = 1.9999 * Math.PI - min * this.data.length;
last = 0;
idx = 0;
this.segments = [];
_ref1 = this.data;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
d = _ref1[_j];
next = last + min + C * (d.value / total);
seg = new Morris.DonutSegment(cx, cy, w * 2, w, last, next, this.options.colors[idx % this.options.colors.length], d);
seg.render(this.r);
this.segments.push(seg);
seg.on('hover', this.select);
last = next;
idx += 1;
}
this.text1 = this.r.text(cx, cy - 10, '').attr({
'font-size': 15,
'font-weight': 800
});
this.text2 = this.r.text(cx, cy + 10, '').attr({
'font-size': 14
});
max_value = Math.max.apply(null, (function() {
var _k, _len2, _ref2, _results;
_ref2 = this.data;
_results = [];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
d = _ref2[_k];
_results.push(d.value);
}
return _results;
}).call(this));
idx = 0;
_ref2 = this.data;
_results = [];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
d = _ref2[_k];
if (d.value === max_value) {
this.select(idx);
break;
}
_results.push(idx += 1);
}
return _results;
};
Donut.prototype.select = function(idx) {
var s, segment, _i, _len, _ref;
_ref = this.segments;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
s = _ref[_i];
s.deselect();
}
if (typeof idx === 'number') {
segment = this.segments[idx];
} else {
segment = idx;
}
segment.select();
return this.setLabels(segment.data.label, this.options.formatter(segment.data.value));
};
Donut.prototype.setLabels = function(label1, label2) {
var inner, maxHeightBottom, maxHeightTop, maxWidth, text1bbox, text1scale, text2bbox, text2scale;
inner = (Math.min(this.el.width() / 2, this.el.height() / 2) - 10) * 2 / 3;
maxWidth = 1.8 * inner;
maxHeightTop = inner / 2;
maxHeightBottom = inner / 3;
this.text1.attr({
text: label1,
transform: ''
});
text1bbox = this.text1.getBBox();
text1scale = Math.min(maxWidth / text1bbox.width, maxHeightTop / text1bbox.height);
this.text1.attr({
transform: "S" + text1scale + "," + text1scale + "," + (text1bbox.x + text1bbox.width / 2) + "," + (text1bbox.y + text1bbox.height)
});
this.text2.attr({
text: label2,
transform: ''
});
text2bbox = this.text2.getBBox();
text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height);
return this.text2.attr({
transform: "S" + text2scale + "," + text2scale + "," + (text2bbox.x + text2bbox.width / 2) + "," + text2bbox.y
});
};
return Donut;
})();
Morris.DonutSegment = (function(_super) {
__extends(DonutSegment, _super);
function DonutSegment(cx, cy, inner, outer, p0, p1, color, data) {
this.cx = cx;
this.cy = cy;
this.inner = inner;
this.outer = outer;
this.color = color;
this.data = data;
this.deselect = __bind(this.deselect, this);
this.select = __bind(this.select, this);
this.sin_p0 = Math.sin(p0);
this.cos_p0 = Math.cos(p0);
this.sin_p1 = Math.sin(p1);
this.cos_p1 = Math.cos(p1);
this.long = (p1 - p0) > Math.PI ? 1 : 0;
this.path = this.calcSegment(this.inner + 3, this.inner + this.outer - 5);
this.selectedPath = this.calcSegment(this.inner + 3, this.inner + this.outer);
this.hilight = this.calcArc(this.inner);
}
DonutSegment.prototype.calcArcPoints = function(r) {
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];
};
DonutSegment.prototype.calcSegment = function(r1, r2) {
var ix0, ix1, iy0, iy1, ox0, ox1, oy0, oy1, _ref, _ref1;
_ref = this.calcArcPoints(r1), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
_ref1 = this.calcArcPoints(r2), ox0 = _ref1[0], oy0 = _ref1[1], ox1 = _ref1[2], oy1 = _ref1[3];
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";
};
DonutSegment.prototype.calcArc = function(r) {
var ix0, ix1, iy0, iy1, _ref;
_ref = this.calcArcPoints(r), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
return ("M" + ix0 + "," + iy0) + ("A" + r + "," + r + ",0," + this.long + ",0," + ix1 + "," + iy1);
};
DonutSegment.prototype.render = function(r) {
var _this = this;
this.arc = r.path(this.hilight).attr({
stroke: this.color,
'stroke-width': 2,
opacity: 0
});
return this.seg = r.path(this.path).attr({
fill: this.color,
stroke: 'white',
'stroke-width': 3
}).hover(function() {
return _this.fire('hover', _this);
});
};
DonutSegment.prototype.select = function() {
if (!this.selected) {
this.seg.animate({
path: this.selectedPath
}, 150, '<>');
this.arc.animate({
opacity: 1
}, 150, '<>');
return this.selected = true;
}
};
DonutSegment.prototype.deselect = function() {
if (this.selected) {
this.seg.animate({
path: this.path
}, 150, '<>');
this.arc.animate({
opacity: 0
}, 150, '<>');
return this.selected = false;
}
};
return DonutSegment;
})(Morris.EventEmitter);
Morris.Grid = (function(_super) { Morris.Grid = (function(_super) {
__extends(Grid, _super); __extends(Grid, _super);
@ -334,10 +114,10 @@
if (redraw == null) { if (redraw == null) {
redraw = true; redraw = true;
} }
ymax = null; ymax = this.cumulative ? 0 : null;
ymin = null; ymin = this.cumulative ? 0 : null;
this.data = $.map(data, function(row, index) { this.data = $.map(data, function(row, index) {
var ret, ykey, yval; var idx, ret, total, ykey, yval;
ret = {}; ret = {};
ret.label = row[_this.options.xkey]; ret.label = row[_this.options.xkey];
if (_this.options.parseTime) { if (_this.options.parseTime) {
@ -350,12 +130,13 @@
} else { } else {
ret.x = index; ret.x = index;
} }
total = 0;
ret.y = (function() { ret.y = (function() {
var _i, _len, _ref, _results; var _i, _len, _ref, _results;
_ref = this.options.ykeys; _ref = this.options.ykeys;
_results = []; _results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
ykey = _ref[_i]; ykey = _ref[idx];
yval = row[ykey]; yval = row[ykey];
if (typeof yval === 'string') { if (typeof yval === 'string') {
yval = parseFloat(yval); yval = parseFloat(yval);
@ -364,13 +145,21 @@
yval = null; yval = null;
} }
if (yval !== null) { if (yval !== null) {
if (ymax === null) { if (this.cumulative) {
ymax = ymin = yval; total += yval;
} else { } else {
ymax = Math.max(yval, ymax); if (ymax === null) {
ymin = Math.min(yval, ymin); ymax = ymin = yval;
} else {
ymax = Math.max(yval, ymax);
ymin = Math.min(yval, ymin);
}
} }
} }
if (this.cumulative && total !== null) {
ymax = Math.max(total, ymax);
ymin = Math.min(total, ymin);
}
_results.push(yval); _results.push(yval);
} }
return _results; return _results;
@ -644,32 +433,75 @@
}; };
Line.prototype.calc = function() { Line.prototype.calc = function() {
var row, y, _i, _len, _ref, this.calcPoints();
_this = this; this.generatePaths();
return this.calcHoverMargins();
};
Line.prototype.calcPoints = function() {
var row, y, _i, _len, _ref, _results;
_ref = this.data; _ref = this.data;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
row = _ref[_i]; row = _ref[_i];
row._x = this.transX(row.x); row._x = this.transX(row.x);
row._y = (function() { _results.push(row._y = (function() {
var _j, _len1, _ref1, _results; var _j, _len1, _ref1, _results1;
_ref1 = row.y; _ref1 = row.y;
_results = []; _results1 = [];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
y = _ref1[_j]; y = _ref1[_j];
if (y === null) { if (y === null) {
_results.push(null); _results1.push(null);
} else { } else {
_results.push(this.transY(y)); _results1.push(this.transY(y));
} }
} }
return _results; return _results1;
}).call(this); }).call(this));
} }
return _results;
};
Line.prototype.calcHoverMargins = function() {
var _this = this;
return this.hoverMargins = $.map(this.data.slice(1), function(r, i) { return this.hoverMargins = $.map(this.data.slice(1), function(r, i) {
return (r._x + _this.data[i]._x) / 2; return (r._x + _this.data[i]._x) / 2;
}); });
}; };
Line.prototype.generatePaths = function() {
var coords, i, r, smooth;
return this.paths = (function() {
var _i, _ref, _ref1, _results;
_results = [];
for (i = _i = 0, _ref = this.options.ykeys.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
smooth = this.options.smooth === true || (_ref1 = this.options.ykeys[i], __indexOf.call(this.options.smooth, _ref1) >= 0);
coords = (function() {
var _j, _len, _ref2, _results1;
_ref2 = this.data;
_results1 = [];
for (_j = 0, _len = _ref2.length; _j < _len; _j++) {
r = _ref2[_j];
if (r._y[i] !== null) {
_results1.push({
x: r._x,
y: r._y[i]
});
}
}
return _results1;
}).call(this);
if (coords.length > 1) {
_results.push(this.createPath(coords, smooth));
} else {
_results.push(null);
}
}
return _results;
}).call(this);
};
Line.prototype.draw = function() { Line.prototype.draw = function() {
this.drawXAxis(); this.drawXAxis();
this.drawSeries(); this.drawSeries();
@ -717,26 +549,10 @@
}; };
Line.prototype.drawSeries = function() { Line.prototype.drawSeries = function() {
var circle, coords, i, path, r, row, smooth, _i, _j, _ref, _ref1, _results; var circle, i, path, row, _i, _j, _ref, _ref1, _results;
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) { for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
coords = (function() { path = this.paths[i];
var _j, _len, _ref1, _results; if (path !== null) {
_ref1 = this.data;
_results = [];
for (_j = 0, _len = _ref1.length; _j < _len; _j++) {
r = _ref1[_j];
if (r._y[i] !== null) {
_results.push({
x: r._x,
y: r._y[i]
});
}
}
return _results;
}).call(this);
smooth = this.options.smooth === true || $.inArray(this.options.ykeys[i], this.options.smooth) > -1;
if (coords.length > 1) {
path = this.createPath(coords, this.bottom, smooth);
this.r.path(path).attr('stroke', this.colorForSeries(i)).attr('stroke-width', this.options.lineWidth); this.r.path(path).attr('stroke', this.colorForSeries(i)).attr('stroke-width', this.options.lineWidth);
} }
} }
@ -844,7 +660,7 @@
maxLabelWidth = Math.max(maxLabelWidth, this.xLabel.getBBox().width); maxLabelWidth = Math.max(maxLabelWidth, this.xLabel.getBBox().width);
this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 2); this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 2);
this.hover.attr('x', -this.options.hoverPaddingX - maxLabelWidth / 2); this.hover.attr('x', -this.options.hoverPaddingX - maxLabelWidth / 2);
yloc = Math.min.apply(null, row.y); yloc = Math.min.apply(null, row._y);
if (yloc > this.hoverHeight + this.options.hoverPaddingY * 2 + this.options.hoverMargin + this.top) { if (yloc > this.hoverHeight + this.options.hoverPaddingY * 2 + this.options.hoverMargin + this.top) {
yloc = yloc - this.hoverHeight / 2 - this.options.hoverPaddingY - this.options.hoverMargin; yloc = yloc - this.hoverHeight / 2 - this.options.hoverPaddingY - this.options.hoverMargin;
} else { } else {
@ -1032,4 +848,282 @@
Morris.AUTO_LABEL_ORDER = ["year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"]; Morris.AUTO_LABEL_ORDER = ["year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
Morris.Area = (function(_super) {
__extends(Area, _super);
function Area(options) {
if (!(this instanceof Morris.Area)) {
return new Morris.Area(options);
}
this.cumulative = true;
Area.__super__.constructor.call(this, options);
}
Area.prototype.calcPoints = function() {
var row, total, y, _i, _len, _ref, _results;
_ref = this.data;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
row = _ref[_i];
row._x = this.transX(row.x);
total = 0;
_results.push(row._y = (function() {
var _j, _len1, _ref1, _results1;
_ref1 = row.y;
_results1 = [];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
y = _ref1[_j];
total += y || 0;
_results1.push(this.transY(total));
}
return _results1;
}).call(this));
}
return _results;
};
Area.prototype.drawSeries = function() {
var i, path, _i, _ref;
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
path = this.paths[i];
if (path !== null) {
path = path + ("L" + (this.transX(this.xmax)) + "," + this.bottom + "L" + (this.transX(this.xmin)) + "," + this.bottom + "Z");
this.r.path(path).attr('fill', this.fillForSeries(i)).attr('stroke-width', 0);
}
}
return Area.__super__.drawSeries.call(this);
};
Area.prototype.fillForSeries = function(i) {
var color;
color = Raphael.rgb2hsl(this.colorForSeries(i));
return Raphael.hsl(color.h, Math.min(255, color.s * 0.75), Math.min(255, color.l * 1.25));
};
return Area;
})(Morris.Line);
Morris.Donut = (function() {
Donut.prototype.defaults = {
colors: ['#0B62A4', '#3980B5', '#679DC6', '#95BBD7', '#B0CCE1', '#095791', '#095085', '#083E67', '#052C48', '#042135'],
formatter: Morris.commas
};
function Donut(options) {
this.select = __bind(this.select, this);
if (!(this instanceof Morris.Donut)) {
return new Morris.Donut(options);
}
if (typeof options.element === 'string') {
this.el = $(document.getElementById(options.element));
} else {
this.el = $(options.element);
}
this.options = $.extend({}, this.defaults, options);
if (this.el === null || this.el.length === 0) {
throw new Error("Graph placeholder not found.");
}
if (options.data === void 0 || options.data.length === 0) {
return;
}
this.data = options.data;
this.el.addClass('graph-initialised');
this.redraw();
}
Donut.prototype.redraw = function() {
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;
this.el.empty();
this.r = new Raphael(this.el[0]);
cx = this.el.width() / 2;
cy = this.el.height() / 2;
w = (Math.min(cx, cy) - 10) / 3;
total = 0;
_ref = this.data;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
x = _ref[_i];
total += x.value;
}
min = 5 / (2 * w);
C = 1.9999 * Math.PI - min * this.data.length;
last = 0;
idx = 0;
this.segments = [];
_ref1 = this.data;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
d = _ref1[_j];
next = last + min + C * (d.value / total);
seg = new Morris.DonutSegment(cx, cy, w * 2, w, last, next, this.options.colors[idx % this.options.colors.length], d);
seg.render(this.r);
this.segments.push(seg);
seg.on('hover', this.select);
last = next;
idx += 1;
}
this.text1 = this.r.text(cx, cy - 10, '').attr({
'font-size': 15,
'font-weight': 800
});
this.text2 = this.r.text(cx, cy + 10, '').attr({
'font-size': 14
});
max_value = Math.max.apply(null, (function() {
var _k, _len2, _ref2, _results;
_ref2 = this.data;
_results = [];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
d = _ref2[_k];
_results.push(d.value);
}
return _results;
}).call(this));
idx = 0;
_ref2 = this.data;
_results = [];
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
d = _ref2[_k];
if (d.value === max_value) {
this.select(idx);
break;
}
_results.push(idx += 1);
}
return _results;
};
Donut.prototype.select = function(idx) {
var s, segment, _i, _len, _ref;
_ref = this.segments;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
s = _ref[_i];
s.deselect();
}
if (typeof idx === 'number') {
segment = this.segments[idx];
} else {
segment = idx;
}
segment.select();
return this.setLabels(segment.data.label, this.options.formatter(segment.data.value));
};
Donut.prototype.setLabels = function(label1, label2) {
var inner, maxHeightBottom, maxHeightTop, maxWidth, text1bbox, text1scale, text2bbox, text2scale;
inner = (Math.min(this.el.width() / 2, this.el.height() / 2) - 10) * 2 / 3;
maxWidth = 1.8 * inner;
maxHeightTop = inner / 2;
maxHeightBottom = inner / 3;
this.text1.attr({
text: label1,
transform: ''
});
text1bbox = this.text1.getBBox();
text1scale = Math.min(maxWidth / text1bbox.width, maxHeightTop / text1bbox.height);
this.text1.attr({
transform: "S" + text1scale + "," + text1scale + "," + (text1bbox.x + text1bbox.width / 2) + "," + (text1bbox.y + text1bbox.height)
});
this.text2.attr({
text: label2,
transform: ''
});
text2bbox = this.text2.getBBox();
text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height);
return this.text2.attr({
transform: "S" + text2scale + "," + text2scale + "," + (text2bbox.x + text2bbox.width / 2) + "," + text2bbox.y
});
};
return Donut;
})();
Morris.DonutSegment = (function(_super) {
__extends(DonutSegment, _super);
function DonutSegment(cx, cy, inner, outer, p0, p1, color, data) {
this.cx = cx;
this.cy = cy;
this.inner = inner;
this.outer = outer;
this.color = color;
this.data = data;
this.deselect = __bind(this.deselect, this);
this.select = __bind(this.select, this);
this.sin_p0 = Math.sin(p0);
this.cos_p0 = Math.cos(p0);
this.sin_p1 = Math.sin(p1);
this.cos_p1 = Math.cos(p1);
this.long = (p1 - p0) > Math.PI ? 1 : 0;
this.path = this.calcSegment(this.inner + 3, this.inner + this.outer - 5);
this.selectedPath = this.calcSegment(this.inner + 3, this.inner + this.outer);
this.hilight = this.calcArc(this.inner);
}
DonutSegment.prototype.calcArcPoints = function(r) {
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];
};
DonutSegment.prototype.calcSegment = function(r1, r2) {
var ix0, ix1, iy0, iy1, ox0, ox1, oy0, oy1, _ref, _ref1;
_ref = this.calcArcPoints(r1), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
_ref1 = this.calcArcPoints(r2), ox0 = _ref1[0], oy0 = _ref1[1], ox1 = _ref1[2], oy1 = _ref1[3];
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";
};
DonutSegment.prototype.calcArc = function(r) {
var ix0, ix1, iy0, iy1, _ref;
_ref = this.calcArcPoints(r), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];
return ("M" + ix0 + "," + iy0) + ("A" + r + "," + r + ",0," + this.long + ",0," + ix1 + "," + iy1);
};
DonutSegment.prototype.render = function(r) {
var _this = this;
this.arc = r.path(this.hilight).attr({
stroke: this.color,
'stroke-width': 2,
opacity: 0
});
return this.seg = r.path(this.path).attr({
fill: this.color,
stroke: 'white',
'stroke-width': 3
}).hover(function() {
return _this.fire('hover', _this);
});
};
DonutSegment.prototype.select = function() {
if (!this.selected) {
this.seg.animate({
path: this.selectedPath
}, 150, '<>');
this.arc.animate({
opacity: 1
}, 150, '<>');
return this.selected = true;
}
};
DonutSegment.prototype.deselect = function() {
if (this.selected) {
this.seg.animate({
path: this.path
}, 150, '<>');
this.arc.animate({
opacity: 0
}, 150, '<>');
return this.selected = false;
}
};
return DonutSegment;
})(Morris.EventEmitter);
}).call(this); }).call(this);

2
morris.min.js vendored

File diff suppressed because one or more lines are too long