mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-11-10 21:36:34 +01:00
Better support for non-continous data (see #53).
This commit is contained in:
parent
fa8f8c60e5
commit
f13e9e838f
41
examples/non-continuous.html
Normal file
41
examples/non-continuous.html
Normal file
@ -0,0 +1,41 @@
|
||||
<!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>Non-continuous data</h1>
|
||||
<p>Null or missing series values will be skipped when rendering.</p>
|
||||
<div id="graph"></div>
|
||||
<pre id="code" class="prettyprint linenums">
|
||||
/* data stolen from http://howmanyleft.co.uk/vehicle/jaguar_'e'_type */
|
||||
var day_data = [
|
||||
{"period": "2012-10-01", "licensed": 3407},
|
||||
{"period": "2012-09-30", "sorned": 629},
|
||||
{"period": "2012-09-29", "sorned": 618},
|
||||
{"period": "2012-09-20", "licensed": 3246, "sorned": 661},
|
||||
{"period": "2012-09-19", "licensed": 3257, "sorned": null},
|
||||
{"period": "2012-09-18", "licensed": 3248},
|
||||
{"period": "2012-09-17", "sorned": 660},
|
||||
{"period": "2012-09-16", "sorned": 676},
|
||||
{"period": "2012-09-15", "licensed": 3201, "sorned": 656},
|
||||
{"period": "2012-09-10", "licensed": 3215}
|
||||
];
|
||||
Morris.Line({
|
||||
element: 'graph',
|
||||
data: day_data,
|
||||
xkey: 'period',
|
||||
ykeys: ['licensed', 'sorned'],
|
||||
labels: ['Licensed', 'SORN'],
|
||||
/* custom label formatting with `xLabelFormat` */
|
||||
xLabelFormat: function(d) { return (d.getMonth()+1)+'/'+d.getDate()+'/'+d.getFullYear(); },
|
||||
/* setting `xLabels` is recommended when using xLabelFormat */
|
||||
xLabels: 'day'
|
||||
});
|
||||
</pre>
|
||||
</body>
|
@ -82,7 +82,7 @@ class Morris.Line
|
||||
for ykey in @options.ykeys
|
||||
series_data = []
|
||||
for d in @options.data
|
||||
series_data.push(d[ykey])
|
||||
series_data.push(d[ykey] or null)
|
||||
@series.push(series_data)
|
||||
|
||||
# translate x labels into nominal dates
|
||||
|
126
morris.js
126
morris.js
@ -1,3 +1,4 @@
|
||||
// Generated by CoffeeScript 1.3.1
|
||||
(function() {
|
||||
var $, Morris, minutesSpecHelper, secondsSpecHelper,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
@ -8,12 +9,21 @@
|
||||
|
||||
Morris.Line = (function() {
|
||||
|
||||
Line.name = 'Line';
|
||||
|
||||
function Line(options) {
|
||||
this.updateHilight = __bind(this.updateHilight, this);
|
||||
|
||||
this.hilight = __bind(this.hilight, this);
|
||||
|
||||
this.updateHover = __bind(this.updateHover, this);
|
||||
|
||||
this.transY = __bind(this.transY, this);
|
||||
this.transX = __bind(this.transX, this); if (!(this instanceof Morris.Line)) return new Morris.Line(options);
|
||||
|
||||
this.transX = __bind(this.transX, this);
|
||||
if (!(this instanceof Morris.Line)) {
|
||||
return new Morris.Line(options);
|
||||
}
|
||||
if (typeof options.element === 'string') {
|
||||
this.el = $(document.getElementById(options.element));
|
||||
} else {
|
||||
@ -23,7 +33,9 @@
|
||||
if (typeof this.options.units === 'string') {
|
||||
this.options.postUnits = options.units;
|
||||
}
|
||||
if (this.options.data === void 0 || this.options.data.length === 0) return;
|
||||
if (this.options.data === void 0 || this.options.data.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.el.addClass('graph-initialised');
|
||||
this.precalc();
|
||||
this.redraw();
|
||||
@ -66,7 +78,7 @@
|
||||
};
|
||||
|
||||
Line.prototype.precalc = function() {
|
||||
var d, series_data, touchHandler, ykey, ymax, ymin, _i, _j, _k, _len, _len2, _ref, _ref2, _ref3, _results,
|
||||
var d, series_data, touchHandler, ykey, ymax, ymin, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2, _results,
|
||||
_this = this;
|
||||
this.options.data.sort(function(a, b) {
|
||||
return (a[_this.options.xkey] < b[_this.options.xkey]) - (b[_this.options.xkey] < a[_this.options.xkey]);
|
||||
@ -80,10 +92,10 @@
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
ykey = _ref[_i];
|
||||
series_data = [];
|
||||
_ref2 = this.options.data;
|
||||
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
|
||||
d = _ref2[_j];
|
||||
series_data.push(d[ykey]);
|
||||
_ref1 = this.options.data;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
d = _ref1[_j];
|
||||
series_data.push(d[ykey] || null);
|
||||
}
|
||||
this.series.push(series_data);
|
||||
}
|
||||
@ -94,7 +106,7 @@
|
||||
} else {
|
||||
this.xvals = (function() {
|
||||
_results = [];
|
||||
for (var _k = _ref3 = this.columnLabels.length - 1; _ref3 <= 0 ? _k <= 0 : _k >= 0; _ref3 <= 0 ? _k++ : _k--){ _results.push(_k); }
|
||||
for (var _k = _ref2 = this.columnLabels.length - 1; _ref2 <= 0 ? _k <= 0 : _k >= 0; _ref2 <= 0 ? _k++ : _k--){ _results.push(_k); }
|
||||
return _results;
|
||||
}).apply(this);
|
||||
}
|
||||
@ -225,12 +237,12 @@
|
||||
};
|
||||
|
||||
Line.prototype.drawGrid = function() {
|
||||
var drawLabel, firstY, i, l, labelText, lastY, lineY, prevLabelMargin, v, xLabelMargin, y, yInterval, ypos, _i, _len, _ref, _ref2, _results, _results2,
|
||||
var drawLabel, firstY, i, l, labelText, lastY, lineY, prevLabelMargin, v, xLabelMargin, y, yInterval, ypos, _i, _j, _k, _len, _ref, _ref1, _results, _results1,
|
||||
_this = this;
|
||||
yInterval = (this.options.ymax - this.options.ymin) / (this.options.numLines - 1);
|
||||
firstY = Math.ceil(this.options.ymin / yInterval) * yInterval;
|
||||
lastY = Math.floor(this.options.ymax / yInterval) * yInterval;
|
||||
for (lineY = firstY; firstY <= lastY ? lineY <= lastY : lineY >= lastY; lineY += yInterval) {
|
||||
for (lineY = _i = firstY; firstY <= lastY ? _i <= lastY : _i >= lastY; lineY = _i += yInterval) {
|
||||
v = Math.floor(lineY);
|
||||
y = this.transY(v);
|
||||
this.r.text(this.left - this.options.marginLeft / 2, y, this.yLabelFormat(v)).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end');
|
||||
@ -255,25 +267,25 @@
|
||||
} else {
|
||||
_ref = Morris.labelSeries(this.xmin, this.xmax, this.width, this.options.xLabels, this.options.xLabelFormat);
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
l = _ref[_i];
|
||||
for (_j = 0, _len = _ref.length; _j < _len; _j++) {
|
||||
l = _ref[_j];
|
||||
_results.push(drawLabel(l[0], l[1]));
|
||||
}
|
||||
return _results;
|
||||
}
|
||||
} else {
|
||||
_results2 = [];
|
||||
for (i = 0, _ref2 = this.columnLabels.length; 0 <= _ref2 ? i <= _ref2 : i >= _ref2; 0 <= _ref2 ? i++ : i--) {
|
||||
_results1 = [];
|
||||
for (i = _k = 0, _ref1 = this.columnLabels.length; 0 <= _ref1 ? _k <= _ref1 : _k >= _ref1; i = 0 <= _ref1 ? ++_k : --_k) {
|
||||
labelText = this.columnLabels[this.columnLabels.length - i - 1];
|
||||
_results2.push(drawLabel(labelText, i));
|
||||
_results1.push(drawLabel(labelText, i));
|
||||
}
|
||||
return _results2;
|
||||
return _results1;
|
||||
}
|
||||
};
|
||||
|
||||
Line.prototype.drawSeries = function() {
|
||||
var c, circle, coords, i, path, _ref, _ref2, _results;
|
||||
for (i = _ref = this.seriesCoords.length - 1; _ref <= 0 ? i <= 0 : i >= 0; _ref <= 0 ? i++ : i--) {
|
||||
var c, circle, coords, i, path, _i, _j, _ref, _ref1, _results;
|
||||
for (i = _i = _ref = this.seriesCoords.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
|
||||
coords = this.seriesCoords[i];
|
||||
if (coords.length > 1) {
|
||||
path = this.createPath(coords, this.options.marginTop, this.left, this.options.marginTop + this.height, this.left + this.width);
|
||||
@ -281,43 +293,43 @@
|
||||
}
|
||||
}
|
||||
this.seriesPoints = (function() {
|
||||
var _ref2, _results;
|
||||
var _j, _ref1, _results;
|
||||
_results = [];
|
||||
for (i = 0, _ref2 = this.seriesCoords.length - 1; 0 <= _ref2 ? i <= _ref2 : i >= _ref2; 0 <= _ref2 ? i++ : i--) {
|
||||
for (i = _j = 0, _ref1 = this.seriesCoords.length - 1; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
|
||||
_results.push([]);
|
||||
}
|
||||
return _results;
|
||||
}).call(this);
|
||||
_results = [];
|
||||
for (i = _ref2 = this.seriesCoords.length - 1; _ref2 <= 0 ? i <= 0 : i >= 0; _ref2 <= 0 ? i++ : i--) {
|
||||
for (i = _j = _ref1 = this.seriesCoords.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {
|
||||
_results.push((function() {
|
||||
var _i, _len, _ref3, _results2;
|
||||
_ref3 = this.seriesCoords[i];
|
||||
_results2 = [];
|
||||
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
|
||||
c = _ref3[_i];
|
||||
var _k, _len, _ref2, _results1;
|
||||
_ref2 = this.seriesCoords[i];
|
||||
_results1 = [];
|
||||
for (_k = 0, _len = _ref2.length; _k < _len; _k++) {
|
||||
c = _ref2[_k];
|
||||
if (c === null) {
|
||||
circle = null;
|
||||
} else {
|
||||
circle = this.r.circle(c.x, c.y, this.options.pointSize).attr('fill', this.options.lineColors[i]).attr('stroke-width', 1).attr('stroke', '#ffffff');
|
||||
}
|
||||
_results2.push(this.seriesPoints[i].push(circle));
|
||||
_results1.push(this.seriesPoints[i].push(circle));
|
||||
}
|
||||
return _results2;
|
||||
return _results1;
|
||||
}).call(this));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Line.prototype.createPath = function(all_coords, top, left, bottom, right) {
|
||||
var c, coords, g, grads, i, ix, lc, lg, path, x1, x2, y1, y2, _ref;
|
||||
var c, coords, g, grads, i, ix, lc, lg, path, x1, x2, y1, y2, _i, _ref;
|
||||
path = "";
|
||||
coords = $.map(all_coords, function(c) {
|
||||
return c;
|
||||
});
|
||||
if (this.options.smooth) {
|
||||
grads = this.gradients(coords);
|
||||
for (i = 0, _ref = coords.length - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
|
||||
for (i = _i = 0, _ref = coords.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
c = coords[i];
|
||||
if (i === 0) {
|
||||
path += "M" + c.x + "," + c.y;
|
||||
@ -354,7 +366,7 @@
|
||||
};
|
||||
|
||||
Line.prototype.drawHover = function() {
|
||||
var i, yLabel, _ref, _results;
|
||||
var i, yLabel, _i, _ref, _results;
|
||||
this.hoverHeight = this.options.hoverFontSize * 1.5 * (this.series.length + 1);
|
||||
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);
|
||||
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);
|
||||
@ -363,7 +375,7 @@
|
||||
this.hoverSet.push(this.xLabel);
|
||||
this.yLabels = [];
|
||||
_results = [];
|
||||
for (i = 0, _ref = this.series.length - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
|
||||
for (i = _i = 0, _ref = this.series.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (i + 1.5) - this.hoverHeight / 2, '').attr('fill', this.options.lineColors[i]).attr('font-size', this.options.hoverFontSize);
|
||||
this.yLabels.push(yLabel);
|
||||
_results.push(this.hoverSet.push(yLabel));
|
||||
@ -372,11 +384,11 @@
|
||||
};
|
||||
|
||||
Line.prototype.updateHover = function(index) {
|
||||
var i, maxLabelWidth, xloc, yloc, _ref,
|
||||
var i, maxLabelWidth, xloc, yloc, _i, _ref,
|
||||
_this = this;
|
||||
this.hoverSet.show();
|
||||
this.xLabel.attr('text', this.columnLabels[index]);
|
||||
for (i = 0, _ref = this.series.length - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
|
||||
for (i = _i = 0, _ref = this.series.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
this.yLabels[i].attr('text', "" + this.seriesLabels[i] + ": " + (this.yLabelFormat(this.series[i][index])));
|
||||
}
|
||||
maxLabelWidth = Math.max.apply(null, $.map(this.yLabels, function(l) {
|
||||
@ -405,16 +417,16 @@
|
||||
};
|
||||
|
||||
Line.prototype.hilight = function(index) {
|
||||
var i, _ref, _ref2;
|
||||
var i, _i, _j, _ref, _ref1;
|
||||
if (this.prevHilight !== null && this.prevHilight !== index) {
|
||||
for (i = 0, _ref = this.seriesPoints.length - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
|
||||
for (i = _i = 0, _ref = this.seriesPoints.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
if (this.seriesPoints[i][this.prevHilight]) {
|
||||
this.seriesPoints[i][this.prevHilight].animate(this.pointShrink);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (index !== null && this.prevHilight !== index) {
|
||||
for (i = 0, _ref2 = this.seriesPoints.length - 1; 0 <= _ref2 ? i <= _ref2 : i >= _ref2; 0 <= _ref2 ? i++ : i--) {
|
||||
for (i = _j = 0, _ref1 = this.seriesPoints.length - 1; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
|
||||
if (this.seriesPoints[i][index]) {
|
||||
this.seriesPoints[i][index].animate(this.pointGrow);
|
||||
}
|
||||
@ -422,14 +434,16 @@
|
||||
this.updateHover(index);
|
||||
}
|
||||
this.prevHilight = index;
|
||||
if (index === null) return this.hideHover();
|
||||
if (index === null) {
|
||||
return this.hideHover();
|
||||
}
|
||||
};
|
||||
|
||||
Line.prototype.updateHilight = function(x) {
|
||||
var hoverIndex, _ref, _results;
|
||||
var hoverIndex, _i, _ref, _results;
|
||||
x -= this.el.offset().left;
|
||||
_results = [];
|
||||
for (hoverIndex = _ref = this.hoverMargins.length; _ref <= 0 ? hoverIndex <= 0 : hoverIndex >= 0; _ref <= 0 ? hoverIndex++ : hoverIndex--) {
|
||||
for (hoverIndex = _i = _ref = this.hoverMargins.length; _ref <= 0 ? _i <= 0 : _i >= 0; hoverIndex = _ref <= 0 ? ++_i : --_i) {
|
||||
if (hoverIndex === 0 || this.hoverMargins[hoverIndex - 1] > x) {
|
||||
this.hilight(hoverIndex);
|
||||
break;
|
||||
@ -442,7 +456,9 @@
|
||||
|
||||
Line.prototype.measureText = function(text, fontSize) {
|
||||
var ret, tt;
|
||||
if (fontSize == null) fontSize = 12;
|
||||
if (fontSize == null) {
|
||||
fontSize = 12;
|
||||
}
|
||||
tt = this.r.text(100, 100, text).attr('font-size', fontSize);
|
||||
ret = tt.getBBox();
|
||||
tt.remove();
|
||||
@ -459,7 +475,9 @@
|
||||
|
||||
Morris.parseDate = function(date) {
|
||||
var isecs, m, msecs, n, o, offsetmins, p, q, r, ret, secs;
|
||||
if (typeof date === 'number') return date;
|
||||
if (typeof date === 'number') {
|
||||
return date;
|
||||
}
|
||||
m = date.match(/^(\d+) Q(\d)$/);
|
||||
n = date.match(/^(\d+)-(\d+)$/);
|
||||
o = date.match(/^(\d+)-(\d+)-(\d+)$/);
|
||||
@ -474,7 +492,9 @@
|
||||
return new Date(parseInt(o[1], 10), parseInt(o[2], 10) - 1, parseInt(o[3], 10)).getTime();
|
||||
} else if (p) {
|
||||
ret = new Date(parseInt(p[1], 10), 0, 1);
|
||||
if (ret.getDay() !== 4) ret.setMonth(0, 1 + ((4 - ret.getDay()) + 7) % 7);
|
||||
if (ret.getDay() !== 4) {
|
||||
ret.setMonth(0, 1 + ((4 - ret.getDay()) + 7) % 7);
|
||||
}
|
||||
return ret.getTime() + parseInt(p[2], 10) * 604800000;
|
||||
} else if (q) {
|
||||
if (!q[6]) {
|
||||
@ -483,7 +503,9 @@
|
||||
offsetmins = 0;
|
||||
if (q[6] !== 'Z') {
|
||||
offsetmins = parseInt(q[8], 10) * 60 + parseInt(q[9], 10);
|
||||
if (q[7] === '+') offsetmins = 0 - offsetmins;
|
||||
if (q[7] === '+') {
|
||||
offsetmins = 0 - offsetmins;
|
||||
}
|
||||
}
|
||||
return Date.UTC(parseInt(q[1], 10), parseInt(q[2], 10) - 1, parseInt(q[3], 10), parseInt(q[4], 10), parseInt(q[5], 10) + offsetmins);
|
||||
}
|
||||
@ -497,7 +519,9 @@
|
||||
offsetmins = 0;
|
||||
if (r[8] !== 'Z') {
|
||||
offsetmins = parseInt(r[10], 10) * 60 + parseInt(r[11], 10);
|
||||
if (r[9] === '+') offsetmins = 0 - offsetmins;
|
||||
if (r[9] === '+') {
|
||||
offsetmins = 0 - offsetmins;
|
||||
}
|
||||
}
|
||||
return Date.UTC(parseInt(r[1], 10), parseInt(r[2], 10) - 1, parseInt(r[3], 10), parseInt(r[4], 10), parseInt(r[5], 10) + offsetmins, isecs, msecs);
|
||||
}
|
||||
@ -516,7 +540,9 @@
|
||||
intnum = Math.floor(absnum).toFixed(0);
|
||||
ret += intnum.replace(/(?=(?:\d{3})+$)(?!^)/g, ',');
|
||||
strabsnum = absnum.toString();
|
||||
if (strabsnum.length > intnum.length) ret += strabsnum.slice(intnum.length);
|
||||
if (strabsnum.length > intnum.length) {
|
||||
ret += strabsnum.slice(intnum.length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
@ -541,7 +567,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spec === void 0) spec = Morris.LABEL_SPECS["second"];
|
||||
if (spec === void 0) {
|
||||
spec = Morris.LABEL_SPECS["second"];
|
||||
}
|
||||
if (xLabelFormat) {
|
||||
spec = $.extend({}, spec, {
|
||||
fmt: xLabelFormat
|
||||
@ -550,7 +578,9 @@
|
||||
d = spec.start(d0);
|
||||
ret = [];
|
||||
while ((t = d.getTime()) <= dmax) {
|
||||
if (t >= dmin) ret.push([spec.fmt(d), t]);
|
||||
if (t >= dmin) {
|
||||
ret.push([spec.fmt(d), t]);
|
||||
}
|
||||
spec.incr(d);
|
||||
}
|
||||
return ret;
|
||||
|
3
morris.min.js
vendored
3
morris.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user