mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-11-10 21:36:34 +01:00
Initial area charts.
This commit is contained in:
parent
16b88ba1de
commit
f72b14f619
29
examples/area.html
Normal file
29
examples/area.html
Normal 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>
|
8
grunt.js
8
grunt.js
@ -13,7 +13,13 @@ module.exports = function (grunt) {
|
||||
}
|
||||
},
|
||||
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']
|
||||
},
|
||||
min: {
|
||||
|
38
lib/morris.area.coffee
Normal file
38
lib/morris.area.coffee
Normal 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))
|
@ -55,8 +55,8 @@ class Morris.Grid extends Morris.EventEmitter
|
||||
# Update the data series and redraw the chart.
|
||||
#
|
||||
setData: (data, redraw = true) ->
|
||||
ymax = null
|
||||
ymin = null
|
||||
ymax = if @cumulative then 0 else null
|
||||
ymin = if @cumulative then 0 else null
|
||||
@data = $.map data, (row, index) =>
|
||||
ret = {}
|
||||
ret.label = row[@options.xkey]
|
||||
@ -68,16 +68,23 @@ class Morris.Grid extends Morris.EventEmitter
|
||||
ret.label = new Date(ret.label).toString()
|
||||
else
|
||||
ret.x = index
|
||||
ret.y = for ykey in @options.ykeys
|
||||
total = 0
|
||||
ret.y = for ykey, idx in @options.ykeys
|
||||
yval = row[ykey]
|
||||
yval = parseFloat(yval) if typeof yval is 'string'
|
||||
yval = null unless typeof yval is 'number'
|
||||
unless yval is null
|
||||
if @cumulative
|
||||
total += yval
|
||||
else
|
||||
if ymax is null
|
||||
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
|
||||
ret
|
||||
|
||||
|
@ -59,7 +59,14 @@ class Morris.Line extends Morris.Grid
|
||||
#
|
||||
# @private
|
||||
calc: ->
|
||||
@calcPoints()
|
||||
@generatePaths()
|
||||
@calcHoverMargins()
|
||||
|
||||
# calculate series data point coordinates
|
||||
#
|
||||
# @private
|
||||
calcPoints: ->
|
||||
for row in @data
|
||||
row._x = @transX(row.x)
|
||||
row._y = for y in row.y
|
||||
@ -67,9 +74,25 @@ class Morris.Line extends Morris.Grid
|
||||
null
|
||||
else
|
||||
@transY(y)
|
||||
|
||||
# calculate hover margins
|
||||
#
|
||||
# @private
|
||||
calcHoverMargins: ->
|
||||
@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.
|
||||
#
|
||||
draw: ->
|
||||
@ -116,11 +139,8 @@ class Morris.Line extends Morris.Grid
|
||||
# @private
|
||||
drawSeries: ->
|
||||
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)
|
||||
smooth = @options.smooth is true or
|
||||
$.inArray(@options.ykeys[i], @options.smooth) > -1
|
||||
if coords.length > 1
|
||||
path = @createPath coords, @bottom, smooth
|
||||
path = @paths[i]
|
||||
if path isnt null
|
||||
@r.path(path)
|
||||
.attr('stroke', @colorForSeries(i))
|
||||
.attr('stroke-width', @options.lineWidth)
|
||||
@ -213,7 +233,7 @@ class Morris.Line extends Morris.Grid
|
||||
@hover.attr 'width', maxLabelWidth + @options.hoverPaddingX * 2
|
||||
@hover.attr 'x', -@options.hoverPaddingX - maxLabelWidth / 2
|
||||
# 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
|
||||
yloc = yloc - @hoverHeight / 2 - @options.hoverPaddingY - @options.hoverMargin
|
||||
else
|
||||
|
612
morris.js
612
morris.js
@ -1,9 +1,10 @@
|
||||
(function() {
|
||||
var $, Morris, minutesSpecHelper, secondsSpecHelper,
|
||||
__slice = [].slice,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__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 = {};
|
||||
|
||||
@ -62,227 +63,6 @@
|
||||
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) {
|
||||
|
||||
__extends(Grid, _super);
|
||||
@ -334,10 +114,10 @@
|
||||
if (redraw == null) {
|
||||
redraw = true;
|
||||
}
|
||||
ymax = null;
|
||||
ymin = null;
|
||||
ymax = this.cumulative ? 0 : null;
|
||||
ymin = this.cumulative ? 0 : null;
|
||||
this.data = $.map(data, function(row, index) {
|
||||
var ret, ykey, yval;
|
||||
var idx, ret, total, ykey, yval;
|
||||
ret = {};
|
||||
ret.label = row[_this.options.xkey];
|
||||
if (_this.options.parseTime) {
|
||||
@ -350,12 +130,13 @@
|
||||
} else {
|
||||
ret.x = index;
|
||||
}
|
||||
total = 0;
|
||||
ret.y = (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = this.options.ykeys;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
ykey = _ref[_i];
|
||||
for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
|
||||
ykey = _ref[idx];
|
||||
yval = row[ykey];
|
||||
if (typeof yval === 'string') {
|
||||
yval = parseFloat(yval);
|
||||
@ -364,6 +145,9 @@
|
||||
yval = null;
|
||||
}
|
||||
if (yval !== null) {
|
||||
if (this.cumulative) {
|
||||
total += yval;
|
||||
} else {
|
||||
if (ymax === null) {
|
||||
ymax = ymin = yval;
|
||||
} else {
|
||||
@ -371,6 +155,11 @@
|
||||
ymin = Math.min(yval, ymin);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.cumulative && total !== null) {
|
||||
ymax = Math.max(total, ymax);
|
||||
ymin = Math.min(total, ymin);
|
||||
}
|
||||
_results.push(yval);
|
||||
}
|
||||
return _results;
|
||||
@ -644,30 +433,73 @@
|
||||
};
|
||||
|
||||
Line.prototype.calc = function() {
|
||||
var row, y, _i, _len, _ref,
|
||||
_this = this;
|
||||
this.calcPoints();
|
||||
this.generatePaths();
|
||||
return this.calcHoverMargins();
|
||||
};
|
||||
|
||||
Line.prototype.calcPoints = function() {
|
||||
var row, 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);
|
||||
row._y = (function() {
|
||||
var _j, _len1, _ref1, _results;
|
||||
_results.push(row._y = (function() {
|
||||
var _j, _len1, _ref1, _results1;
|
||||
_ref1 = row.y;
|
||||
_results = [];
|
||||
_results1 = [];
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
y = _ref1[_j];
|
||||
if (y === null) {
|
||||
_results.push(null);
|
||||
_results1.push(null);
|
||||
} else {
|
||||
_results.push(this.transY(y));
|
||||
_results1.push(this.transY(y));
|
||||
}
|
||||
}
|
||||
return _results1;
|
||||
}).call(this));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Line.prototype.calcHoverMargins = function() {
|
||||
var _this = this;
|
||||
return this.hoverMargins = $.map(this.data.slice(1), function(r, i) {
|
||||
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);
|
||||
}
|
||||
return this.hoverMargins = $.map(this.data.slice(1), function(r, i) {
|
||||
return (r._x + _this.data[i]._x) / 2;
|
||||
});
|
||||
};
|
||||
|
||||
Line.prototype.draw = function() {
|
||||
@ -717,26 +549,10 @@
|
||||
};
|
||||
|
||||
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) {
|
||||
coords = (function() {
|
||||
var _j, _len, _ref1, _results;
|
||||
_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);
|
||||
path = this.paths[i];
|
||||
if (path !== null) {
|
||||
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);
|
||||
this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 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) {
|
||||
yloc = yloc - this.hoverHeight / 2 - this.options.hoverPaddingY - this.options.hoverMargin;
|
||||
} else {
|
||||
@ -1032,4 +848,282 @@
|
||||
|
||||
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);
|
||||
|
2
morris.min.js
vendored
2
morris.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user