diff --git a/morris.coffee b/morris.coffee index 4ac638b..ebcbfd0 100644 --- a/morris.coffee +++ b/morris.coffee @@ -1,5 +1,7 @@ # The original line graph. # +$ = jQuery + Morris = {} class Morris.Line # Initialise the graph. diff --git a/morris.js b/morris.js index aac8cff..a5c6f32 100644 --- a/morris.js +++ b/morris.js @@ -1,349 +1,349 @@ -(function($) { - (function() { - var Morris; +(function() { + var $, Morris; - Morris = {}; + $ = jQuery; - Morris.Line = (function() { + Morris = {}; - function Line(options) { - if (!(this instanceof Morris.Line)) return new Morris.Line(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.options.data === void 0 || this.options.data.length === 0) return; - this.el.addClass('graph-initialised'); - this.precalc(); - this.redraw(); + Morris.Line = (function() { + + function Line(options) { + if (!(this instanceof Morris.Line)) return new Morris.Line(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.options.data === void 0 || this.options.data.length === 0) return; + this.el.addClass('graph-initialised'); + this.precalc(); + this.redraw(); + } - Line.prototype.defaults = { - lineWidth: 3, - pointSize: 4, - lineColors: ['#0b62a4', '#7A92A3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'], - ymax: 'auto', - marginTop: 25, - marginRight: 25, - marginBottom: 30, - marginLeft: 25, - numLines: 5, - gridLineColor: '#aaa', - gridTextColor: '#888', - gridTextSize: 12, - gridStrokeWidth: 0.5, - hoverPaddingX: 10, - hoverPaddingY: 5, - hoverMargin: 10, - hoverFillColor: '#fff', - hoverBorderColor: '#ccc', - hoverBorderWidth: 2, - hoverOpacity: 0.95, - hoverLabelColor: '#444', - hoverFontSize: 12, - smooth: true - }; + Line.prototype.defaults = { + lineWidth: 3, + pointSize: 4, + lineColors: ['#0b62a4', '#7A92A3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'], + ymax: 'auto', + marginTop: 25, + marginRight: 25, + marginBottom: 30, + marginLeft: 25, + numLines: 5, + gridLineColor: '#aaa', + gridTextColor: '#888', + gridTextSize: 12, + gridStrokeWidth: 0.5, + hoverPaddingX: 10, + hoverPaddingY: 5, + hoverMargin: 10, + hoverFillColor: '#fff', + hoverBorderColor: '#ccc', + hoverBorderWidth: 2, + hoverOpacity: 0.95, + hoverLabelColor: '#444', + hoverFontSize: 12, + smooth: true + }; - Line.prototype.precalc = function() { - var ykey, ymax, _i, _len, _ref, - _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]); - }); - this.columnLabels = $.map(this.options.data, function(d) { - return d[_this.options.xkey]; - }); - this.seriesLabels = this.options.labels; - this.series = []; - _ref = this.options.ykeys; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - ykey = _ref[_i]; - this.series.push($.map(this.options.data, function(d) { - return d[ykey]; - })); + Line.prototype.precalc = function() { + var ykey, ymax, _i, _len, _ref, + _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]); + }); + this.columnLabels = $.map(this.options.data, function(d) { + return d[_this.options.xkey]; + }); + this.seriesLabels = this.options.labels; + this.series = []; + _ref = this.options.ykeys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ykey = _ref[_i]; + this.series.push($.map(this.options.data, function(d) { + return d[ykey]; + })); + } + this.xvals = $.map(this.columnLabels, function(x) { + return _this.parseYear(x); + }); + this.xmin = Math.min.apply(null, this.xvals); + this.xmax = Math.max.apply(null, this.xvals); + if (this.xmin === this.xmax) { + this.xmin -= 1; + this.xmax += 1; + } + if (typeof this.options.ymax === 'string' && this.options.ymax.slice(0, 4) === 'auto') { + ymax = Math.max.apply(null, Array.prototype.concat.apply([], this.series)); + if (this.options.ymax.length > 5) { + return this.options.ymax = Math.max(parseInt(this.options.ymax.slice(5), 10), ymax); + } else { + return this.options.ymax = ymax; } - this.xvals = $.map(this.columnLabels, function(x) { - return _this.parseYear(x); - }); - this.xmin = Math.min.apply(null, this.xvals); - this.xmax = Math.max.apply(null, this.xvals); - if (this.xmin === this.xmax) { - this.xmin -= 1; - this.xmax += 1; - } - if (typeof this.options.ymax === 'string' && this.options.ymax.slice(0, 4) === 'auto') { - ymax = Math.max.apply(null, Array.prototype.concat.apply([], this.series)); - if (this.options.ymax.length > 5) { - return this.options.ymax = Math.max(parseInt(this.options.ymax.slice(5), 10), ymax); - } else { - return this.options.ymax = ymax; - } + } + }; + + Line.prototype.redraw = function() { + var c, circle, columns, coords, dx, dy, height, hideHover, hilight, hover, hoverHeight, hoverMargins, hoverSet, i, label, labelBox, left, lineInterval, path, pointGrow, pointShrink, prevHilight, prevLabelMargin, s, seriesCoords, seriesPoints, touchHandler, transX, transY, updateHilight, updateHover, v, width, x, xLabel, xLabelMargin, y, yLabel, yLabels, _i, _j, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, + _this = this; + this.el.empty(); + this.r = new Raphael(this.el[0]); + left = this.measureText(this.options.ymax, this.options.gridTextSize).width + this.options.marginLeft; + width = this.el.width() - left - this.options.marginRight; + height = this.el.height() - this.options.marginTop - this.options.marginBottom; + dx = width / (this.xmax - this.xmin); + dy = height / this.options.ymax; + transX = function(x) { + if (_this.xvals.length === 1) { + return left + width / 2; + } else { + return left + (x - _this.xmin) * dx; } }; - - Line.prototype.redraw = function() { - var c, circle, columns, coords, dx, dy, height, hideHover, hilight, hover, hoverHeight, hoverMargins, hoverSet, i, label, labelBox, left, lineInterval, path, pointGrow, pointShrink, prevHilight, prevLabelMargin, s, seriesCoords, seriesPoints, touchHandler, transX, transY, updateHilight, updateHover, v, width, x, xLabel, xLabelMargin, y, yLabel, yLabels, _i, _j, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, - _this = this; - this.el.empty(); - this.r = new Raphael(this.el[0]); - left = this.measureText(this.options.ymax, this.options.gridTextSize).width + this.options.marginLeft; - width = this.el.width() - left - this.options.marginRight; - height = this.el.height() - this.options.marginTop - this.options.marginBottom; - dx = width / (this.xmax - this.xmin); - dy = height / this.options.ymax; - transX = function(x) { - if (_this.xvals.length === 1) { - return left + width / 2; - } else { - return left + (x - _this.xmin) * dx; - } - }; - transY = function(y) { - return _this.options.marginTop + height - y * dy; - }; - lineInterval = height / (this.options.numLines - 1); - for (i = 0, _ref = this.options.numLines - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) { - y = this.options.marginTop + i * lineInterval; - v = Math.round((this.options.numLines - 1 - i) * this.options.ymax / (this.options.numLines - 1)); - this.r.text(left - this.options.marginLeft / 2, y, v).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end'); - this.r.path("M" + left + "," + y + 'H' + (left + width)).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth); + transY = function(y) { + return _this.options.marginTop + height - y * dy; + }; + lineInterval = height / (this.options.numLines - 1); + for (i = 0, _ref = this.options.numLines - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) { + y = this.options.marginTop + i * lineInterval; + v = Math.round((this.options.numLines - 1 - i) * this.options.ymax / (this.options.numLines - 1)); + this.r.text(left - this.options.marginLeft / 2, y, v).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end'); + this.r.path("M" + left + "," + y + 'H' + (left + width)).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth); + } + prevLabelMargin = null; + xLabelMargin = 50; + for (i = _ref2 = Math.ceil(this.xmin), _ref3 = Math.floor(this.xmax); _ref2 <= _ref3 ? i <= _ref3 : i >= _ref3; _ref2 <= _ref3 ? i++ : i--) { + label = this.r.text(transX(i), this.options.marginTop + height + this.options.marginBottom / 2, i).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor); + labelBox = label.getBBox(); + if (prevLabelMargin === null || prevLabelMargin <= labelBox.x) { + prevLabelMargin = labelBox.x + labelBox.width + xLabelMargin; + } else { + label.remove(); } - prevLabelMargin = null; - xLabelMargin = 50; - for (i = _ref2 = Math.ceil(this.xmin), _ref3 = Math.floor(this.xmax); _ref2 <= _ref3 ? i <= _ref3 : i >= _ref3; _ref2 <= _ref3 ? i++ : i--) { - label = this.r.text(transX(i), this.options.marginTop + height + this.options.marginBottom / 2, i).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor); - labelBox = label.getBBox(); - if (prevLabelMargin === null || prevLabelMargin <= labelBox.x) { - prevLabelMargin = labelBox.x + labelBox.width + xLabelMargin; - } else { - label.remove(); - } - } - columns = (function() { - var _i, _len, _ref4, _results; - _ref4 = this.xvals; - _results = []; - for (_i = 0, _len = _ref4.length; _i < _len; _i++) { - x = _ref4[_i]; - _results.push(transX(x)); - } - return _results; - }).call(this); - seriesCoords = []; - _ref4 = this.series; + } + columns = (function() { + var _i, _len, _ref4, _results; + _ref4 = this.xvals; + _results = []; for (_i = 0, _len = _ref4.length; _i < _len; _i++) { - s = _ref4[_i]; - seriesCoords.push($.map(s, function(y, i) { - return { - x: columns[i], - y: transY(y) - }; - })); + x = _ref4[_i]; + _results.push(transX(x)); } - for (i = _ref5 = seriesCoords.length - 1; _ref5 <= 0 ? i <= 0 : i >= 0; _ref5 <= 0 ? i++ : i--) { - coords = seriesCoords[i]; - if (coords.length > 1) { - path = this.createPath(coords, this.options.marginTop, left, this.options.marginTop + height, left + width); - this.r.path(path).attr('stroke', this.options.lineColors[i]).attr('stroke-width', this.options.lineWidth); - } + return _results; + }).call(this); + seriesCoords = []; + _ref4 = this.series; + for (_i = 0, _len = _ref4.length; _i < _len; _i++) { + s = _ref4[_i]; + seriesCoords.push($.map(s, function(y, i) { + return { + x: columns[i], + y: transY(y) + }; + })); + } + for (i = _ref5 = seriesCoords.length - 1; _ref5 <= 0 ? i <= 0 : i >= 0; _ref5 <= 0 ? i++ : i--) { + coords = seriesCoords[i]; + if (coords.length > 1) { + path = this.createPath(coords, this.options.marginTop, left, this.options.marginTop + height, left + width); + this.r.path(path).attr('stroke', this.options.lineColors[i]).attr('stroke-width', this.options.lineWidth); } - seriesPoints = (function() { - var _ref6, _results; - _results = []; - for (i = 0, _ref6 = seriesCoords.length - 1; 0 <= _ref6 ? i <= _ref6 : i >= _ref6; 0 <= _ref6 ? i++ : i--) { - _results.push([]); - } - return _results; - })(); - for (i = _ref6 = seriesCoords.length - 1; _ref6 <= 0 ? i <= 0 : i >= 0; _ref6 <= 0 ? i++ : i--) { - _ref7 = seriesCoords[i]; - for (_j = 0, _len2 = _ref7.length; _j < _len2; _j++) { - c = _ref7[_j]; - circle = this.r.circle(c.x, c.y, this.options.pointSize).attr('fill', this.options.lineColors[i]).attr('stroke-width', 1).attr('stroke', '#ffffff'); - seriesPoints[i].push(circle); - } + } + seriesPoints = (function() { + var _ref6, _results; + _results = []; + for (i = 0, _ref6 = seriesCoords.length - 1; 0 <= _ref6 ? i <= _ref6 : i >= _ref6; 0 <= _ref6 ? i++ : i--) { + _results.push([]); } - hoverHeight = this.options.hoverFontSize * 1.5 * (this.series.length + 1); - hover = this.r.rect(-10, -hoverHeight / 2 - this.options.hoverPaddingY, 20, 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); - xLabel = this.r.text(0, (this.options.hoverFontSize * 0.75) - hoverHeight / 2, '').attr('fill', this.options.hoverLabelColor).attr('font-weight', 'bold').attr('font-size', this.options.hoverFontSize); - hoverSet = this.r.set(); - hoverSet.push(hover); - hoverSet.push(xLabel); - yLabels = []; - for (i = 0, _ref8 = this.series.length - 1; 0 <= _ref8 ? i <= _ref8 : i >= _ref8; 0 <= _ref8 ? i++ : i--) { - yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (i + 1.5) - hoverHeight / 2, '').attr('fill', this.options.lineColors[i]).attr('font-size', this.options.hoverFontSize); - yLabels.push(yLabel); - hoverSet.push(yLabel); + return _results; + })(); + for (i = _ref6 = seriesCoords.length - 1; _ref6 <= 0 ? i <= 0 : i >= 0; _ref6 <= 0 ? i++ : i--) { + _ref7 = seriesCoords[i]; + for (_j = 0, _len2 = _ref7.length; _j < _len2; _j++) { + c = _ref7[_j]; + circle = this.r.circle(c.x, c.y, this.options.pointSize).attr('fill', this.options.lineColors[i]).attr('stroke-width', 1).attr('stroke', '#ffffff'); + seriesPoints[i].push(circle); } - updateHover = function(index) { - var i, maxLabelWidth, xloc, yloc, _ref9; - hoverSet.show(); - xLabel.attr('text', _this.columnLabels[index]); - for (i = 0, _ref9 = _this.series.length - 1; 0 <= _ref9 ? i <= _ref9 : i >= _ref9; 0 <= _ref9 ? i++ : i--) { - yLabels[i].attr('text', "" + _this.seriesLabels[i] + ": " + (_this.commas(_this.series[i][index]))); - } - maxLabelWidth = Math.max.apply(null, $.map(yLabels, function(l) { - return l.getBBox().width; - })); - maxLabelWidth = Math.max(maxLabelWidth, xLabel.getBBox().width); - hover.attr('width', maxLabelWidth + _this.options.hoverPaddingX * 2); - hover.attr('x', -_this.options.hoverPaddingX - maxLabelWidth / 2); - yloc = Math.min.apply(null, $.map(_this.series, function(s) { - return transY(s[index]); - })); - if (yloc > hoverHeight + _this.options.hoverPaddingY * 2 + _this.options.hoverMargin + _this.options.marginTop) { - yloc = yloc - hoverHeight / 2 - _this.options.hoverPaddingY - _this.options.hoverMargin; - } else { - yloc = yloc + hoverHeight / 2 + _this.options.hoverPaddingY + _this.options.hoverMargin; - } - yloc = Math.max(_this.options.marginTop + hoverHeight / 2 + _this.options.hoverPaddingY, yloc); - yloc = Math.min(_this.options.marginTop + height - hoverHeight / 2 - _this.options.hoverPaddingY, yloc); - xloc = Math.min(left + width - maxLabelWidth / 2 - _this.options.hoverPaddingX, columns[index]); - xloc = Math.max(left + maxLabelWidth / 2 + _this.options.hoverPaddingX, xloc); - return hoverSet.attr('transform', "t" + xloc + "," + yloc); - }; - hideHover = function() { - return hoverSet.hide(); - }; - hoverMargins = $.map(columns.slice(1), function(x, i) { - return (x + columns[i]) / 2; - }); - prevHilight = null; - pointGrow = Raphael.animation({ - r: this.options.pointSize + 3 - }, 25, 'linear'); - pointShrink = Raphael.animation({ - r: this.options.pointSize - }, 25, 'linear'); - hilight = function(index) { - var i, _ref10, _ref9; - if (prevHilight !== null && prevHilight !== index) { - for (i = 0, _ref9 = seriesPoints.length - 1; 0 <= _ref9 ? i <= _ref9 : i >= _ref9; 0 <= _ref9 ? i++ : i--) { - seriesPoints[i][prevHilight].animate(pointShrink); - } - } - if (index !== null && prevHilight !== index) { - for (i = 0, _ref10 = seriesPoints.length - 1; 0 <= _ref10 ? i <= _ref10 : i >= _ref10; 0 <= _ref10 ? i++ : i--) { - seriesPoints[i][index].animate(pointGrow); - } - updateHover(index); - } - prevHilight = index; - if (index === null) return hideHover(); - }; - updateHilight = function(x) { - var hoverIndex, _ref9, _results; - x -= _this.el.offset().left; - _results = []; - for (hoverIndex = _ref9 = hoverMargins.length; _ref9 <= 0 ? hoverIndex <= 0 : hoverIndex >= 0; _ref9 <= 0 ? hoverIndex++ : hoverIndex--) { - if (hoverIndex === 0 || hoverMargins[hoverIndex - 1] > x) { - hilight(hoverIndex); - break; - } else { - _results.push(void 0); - } - } - return _results; - }; - this.el.mousemove(function(evt) { - return updateHilight(evt.pageX); - }); - touchHandler = function(evt) { - var touch; - touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0]; - updateHilight(touch.pageX); - return touch; - }; - this.el.bind('touchstart', touchHandler); - this.el.bind('touchmove', touchHandler); - this.el.bind('touchend', touchHandler); - return hilight(0); - }; - - Line.prototype.createPath = function(coords, top, left, bottom, right) { - var c, g, grads, i, ix, lc, lg, path, x1, x2, y1, y2, _ref; - path = ""; - 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--) { - c = coords[i]; - if (i === 0) { - path += "M" + c.x + "," + c.y; - } else { - g = grads[i]; - lc = coords[i - 1]; - lg = grads[i - 1]; - ix = (c.x - lc.x) / 4; - x1 = lc.x + ix; - y1 = Math.min(bottom, lc.y + ix * lg); - x2 = c.x - ix; - y2 = Math.min(bottom, c.y - ix * g); - path += "C" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + c.x + "," + c.y; - } - } + } + hoverHeight = this.options.hoverFontSize * 1.5 * (this.series.length + 1); + hover = this.r.rect(-10, -hoverHeight / 2 - this.options.hoverPaddingY, 20, 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); + xLabel = this.r.text(0, (this.options.hoverFontSize * 0.75) - hoverHeight / 2, '').attr('fill', this.options.hoverLabelColor).attr('font-weight', 'bold').attr('font-size', this.options.hoverFontSize); + hoverSet = this.r.set(); + hoverSet.push(hover); + hoverSet.push(xLabel); + yLabels = []; + for (i = 0, _ref8 = this.series.length - 1; 0 <= _ref8 ? i <= _ref8 : i >= _ref8; 0 <= _ref8 ? i++ : i--) { + yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (i + 1.5) - hoverHeight / 2, '').attr('fill', this.options.lineColors[i]).attr('font-size', this.options.hoverFontSize); + yLabels.push(yLabel); + hoverSet.push(yLabel); + } + updateHover = function(index) { + var i, maxLabelWidth, xloc, yloc, _ref9; + hoverSet.show(); + xLabel.attr('text', _this.columnLabels[index]); + for (i = 0, _ref9 = _this.series.length - 1; 0 <= _ref9 ? i <= _ref9 : i >= _ref9; 0 <= _ref9 ? i++ : i--) { + yLabels[i].attr('text', "" + _this.seriesLabels[i] + ": " + (_this.commas(_this.series[i][index]))); + } + maxLabelWidth = Math.max.apply(null, $.map(yLabels, function(l) { + return l.getBBox().width; + })); + maxLabelWidth = Math.max(maxLabelWidth, xLabel.getBBox().width); + hover.attr('width', maxLabelWidth + _this.options.hoverPaddingX * 2); + hover.attr('x', -_this.options.hoverPaddingX - maxLabelWidth / 2); + yloc = Math.min.apply(null, $.map(_this.series, function(s) { + return transY(s[index]); + })); + if (yloc > hoverHeight + _this.options.hoverPaddingY * 2 + _this.options.hoverMargin + _this.options.marginTop) { + yloc = yloc - hoverHeight / 2 - _this.options.hoverPaddingY - _this.options.hoverMargin; } else { - path = "M" + $.map(coords, function(c) { - return "" + c.x + "," + c.y; - }).join("L"); + yloc = yloc + hoverHeight / 2 + _this.options.hoverPaddingY + _this.options.hoverMargin; } - return path; + yloc = Math.max(_this.options.marginTop + hoverHeight / 2 + _this.options.hoverPaddingY, yloc); + yloc = Math.min(_this.options.marginTop + height - hoverHeight / 2 - _this.options.hoverPaddingY, yloc); + xloc = Math.min(left + width - maxLabelWidth / 2 - _this.options.hoverPaddingX, columns[index]); + xloc = Math.max(left + maxLabelWidth / 2 + _this.options.hoverPaddingX, xloc); + return hoverSet.attr('transform', "t" + xloc + "," + yloc); }; + hideHover = function() { + return hoverSet.hide(); + }; + hoverMargins = $.map(columns.slice(1), function(x, i) { + return (x + columns[i]) / 2; + }); + prevHilight = null; + pointGrow = Raphael.animation({ + r: this.options.pointSize + 3 + }, 25, 'linear'); + pointShrink = Raphael.animation({ + r: this.options.pointSize + }, 25, 'linear'); + hilight = function(index) { + var i, _ref10, _ref9; + if (prevHilight !== null && prevHilight !== index) { + for (i = 0, _ref9 = seriesPoints.length - 1; 0 <= _ref9 ? i <= _ref9 : i >= _ref9; 0 <= _ref9 ? i++ : i--) { + seriesPoints[i][prevHilight].animate(pointShrink); + } + } + if (index !== null && prevHilight !== index) { + for (i = 0, _ref10 = seriesPoints.length - 1; 0 <= _ref10 ? i <= _ref10 : i >= _ref10; 0 <= _ref10 ? i++ : i--) { + seriesPoints[i][index].animate(pointGrow); + } + updateHover(index); + } + prevHilight = index; + if (index === null) return hideHover(); + }; + updateHilight = function(x) { + var hoverIndex, _ref9, _results; + x -= _this.el.offset().left; + _results = []; + for (hoverIndex = _ref9 = hoverMargins.length; _ref9 <= 0 ? hoverIndex <= 0 : hoverIndex >= 0; _ref9 <= 0 ? hoverIndex++ : hoverIndex--) { + if (hoverIndex === 0 || hoverMargins[hoverIndex - 1] > x) { + hilight(hoverIndex); + break; + } else { + _results.push(void 0); + } + } + return _results; + }; + this.el.mousemove(function(evt) { + return updateHilight(evt.pageX); + }); + touchHandler = function(evt) { + var touch; + touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0]; + updateHilight(touch.pageX); + return touch; + }; + this.el.bind('touchstart', touchHandler); + this.el.bind('touchmove', touchHandler); + this.el.bind('touchend', touchHandler); + return hilight(0); + }; - Line.prototype.gradients = function(coords) { - return $.map(coords, function(c, i) { + Line.prototype.createPath = function(coords, top, left, bottom, right) { + var c, g, grads, i, ix, lc, lg, path, x1, x2, y1, y2, _ref; + path = ""; + 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--) { + c = coords[i]; if (i === 0) { - return (coords[1].y - c.y) / (coords[1].x - c.x); - } else if (i === (coords.length - 1)) { - return (c.y - coords[i - 1].y) / (c.x - coords[i - 1].x); + path += "M" + c.x + "," + c.y; } else { - return (coords[i + 1].y - coords[i - 1].y) / (coords[i + 1].x - coords[i - 1].x); + g = grads[i]; + lc = coords[i - 1]; + lg = grads[i - 1]; + ix = (c.x - lc.x) / 4; + x1 = lc.x + ix; + y1 = Math.min(bottom, lc.y + ix * lg); + x2 = c.x - ix; + y2 = Math.min(bottom, c.y - ix * g); + path += "C" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + c.x + "," + c.y; } - }); - }; - - Line.prototype.measureText = function(text, fontSize) { - var ret, tt; - if (fontSize == null) fontSize = 12; - tt = this.r.text(100, 100, text).attr('font-size', fontSize); - ret = tt.getBBox(); - tt.remove(); - return ret; - }; - - Line.prototype.parseYear = function(date) { - var day, m, month, n, o, s, timestamp, y1, y2, year; - s = date.toString(); - m = s.match(/^(\d+) Q(\d)$/); - n = s.match(/^(\d+)-(\d+)$/); - o = s.match(/^(\d+)-(\d+)-(\d+)$/); - if (m) { - return parseInt(m[1], 10) + (parseInt(m[2], 10) * 3 - 1) / 12; - } else if (n) { - return parseInt(n[1], 10) + (parseInt(n[2], 10) - 1) / 12; - } else if (o) { - year = parseInt(o[1], 10); - month = parseInt(o[2], 10); - day = parseInt(o[3], 10); - timestamp = new Date(year, month - 1, day).getTime(); - y1 = new Date(year, 0, 1).getTime(); - y2 = new Date(year + 1, 0, 1).getTime(); - return year + (timestamp - y1) / (y2 - y1); - } else { - return parseInt(date, 10); } - }; + } else { + path = "M" + $.map(coords, function(c) { + return "" + c.x + "," + c.y; + }).join("L"); + } + return path; + }; - Line.prototype.commas = function(num) { - return Math.max(0, num).toFixed(0).replace(/(?=(?:\d{3})+$)(?!^)/g, ','); - }; + Line.prototype.gradients = function(coords) { + return $.map(coords, function(c, i) { + if (i === 0) { + return (coords[1].y - c.y) / (coords[1].x - c.x); + } else if (i === (coords.length - 1)) { + return (c.y - coords[i - 1].y) / (c.x - coords[i - 1].x); + } else { + return (coords[i + 1].y - coords[i - 1].y) / (coords[i + 1].x - coords[i - 1].x); + } + }); + }; - return Line; + Line.prototype.measureText = function(text, fontSize) { + var ret, tt; + if (fontSize == null) fontSize = 12; + tt = this.r.text(100, 100, text).attr('font-size', fontSize); + ret = tt.getBBox(); + tt.remove(); + return ret; + }; - })(); + Line.prototype.parseYear = function(date) { + var day, m, month, n, o, s, timestamp, y1, y2, year; + s = date.toString(); + m = s.match(/^(\d+) Q(\d)$/); + n = s.match(/^(\d+)-(\d+)$/); + o = s.match(/^(\d+)-(\d+)-(\d+)$/); + if (m) { + return parseInt(m[1], 10) + (parseInt(m[2], 10) * 3 - 1) / 12; + } else if (n) { + return parseInt(n[1], 10) + (parseInt(n[2], 10) - 1) / 12; + } else if (o) { + year = parseInt(o[1], 10); + month = parseInt(o[2], 10); + day = parseInt(o[3], 10); + timestamp = new Date(year, month - 1, day).getTime(); + y1 = new Date(year, 0, 1).getTime(); + y2 = new Date(year + 1, 0, 1).getTime(); + return year + (timestamp - y1) / (y2 - y1); + } else { + return parseInt(date, 10); + } + }; - window.Morris = Morris; + Line.prototype.commas = function(num) { + return Math.max(0, num).toFixed(0).replace(/(?=(?:\d{3})+$)(?!^)/g, ','); + }; - }).call(this); -})(jQuery); + return Line; + + })(); + + window.Morris = Morris; + +}).call(this); diff --git a/morris.min.js b/morris.min.js index e042681..7e1b86c 100644 --- a/morris.min.js +++ b/morris.min.js @@ -1 +1 @@ -((function(){var a;a={},a.Line=function(){function b(b){if(!(this instanceof a.Line))return new a.Line(b);typeof b.element=="string"?this.el=$(document.getElementById(b.element)):this.el=$(b.element),this.options=$.extend({},this.defaults,b);if(this.options.data===void 0||this.options.data.length===0)return;this.el.addClass("graph-initialised"),this.precalc(),this.redraw()}return b.prototype.defaults={lineWidth:3,pointSize:4,lineColors:["#0b62a4","#7A92A3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],ymax:"auto",marginTop:25,marginRight:25,marginBottom:30,marginLeft:25,numLines:5,gridLineColor:"#aaa",gridTextColor:"#888",gridTextSize:12,gridStrokeWidth:.5,hoverPaddingX:10,hoverPaddingY:5,hoverMargin:10,hoverFillColor:"#fff",hoverBorderColor:"#ccc",hoverBorderWidth:2,hoverOpacity:.95,hoverLabelColor:"#444",hoverFontSize:12,smooth:!0},b.prototype.precalc=function(){var a,b,c,d,e,f=this;this.options.data.sort(function(a,b){return(a[f.options.xkey]5?this.options.ymax=Math.max(parseInt(this.options.ymax.slice(5),10),b):this.options.ymax=b},b.prototype.redraw=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z=this;this.el.empty(),this.r=new Raphael(this.el[0]),q=this.measureText(this.options.ymax,this.options.gridTextSize).width+this.options.marginLeft,G=this.el.width()-q-this.options.marginRight,g=this.el.height()-this.options.marginTop-this.options.marginBottom,e=G/(this.xmax-this.xmin),f=g/this.options.ymax,B=function(a){return Z.xvals.length===1?q+G/2:q+(a-Z.xmin)*e},C=function(a){return Z.options.marginTop+g-a*f},r=g/(this.options.numLines-1);for(n=0,R=this.options.numLines-1;0<=R?n<=R:n>=R;0<=R?n++:n--)K=this.options.marginTop+n*r,F=Math.round((this.options.numLines-1-n)*this.options.ymax/(this.options.numLines-1)),this.r.text(q-this.options.marginLeft/2,K,F).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor).attr("text-anchor","end"),this.r.path("M"+q+","+K+"H"+(q+G)).attr("stroke",this.options.gridLineColor).attr("stroke-width",this.options.gridStrokeWidth);w=null,J=50;for(n=S=Math.ceil(this.xmin),T=Math.floor(this.xmax);S<=T?n<=T:n>=T;S<=T?n++:n--)o=this.r.text(B(n),this.options.marginTop+g+this.options.marginBottom/2,n).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor),p=o.getBBox(),w===null||w<=p.x?w=p.x+p.width+J:o.remove();c=function(){var a,b,c,d;c=this.xvals,d=[];for(a=0,b=c.length;a=0;V<=0?n++:n--)d=y[n],d.length>1&&(s=this.createPath(d,this.options.marginTop,q,this.options.marginTop+g,q+G),this.r.path(s).attr("stroke",this.options.lineColors[n]).attr("stroke-width",this.options.lineWidth));z=function(){var a,b;b=[];for(n=0,a=y.length-1;0<=a?n<=a:n>=a;0<=a?n++:n--)b.push([]);return b}();for(n=W=y.length-1;W<=0?n<=0:n>=0;W<=0?n++:n--){X=y[n];for(O=0,Q=X.length;O=Y;0<=Y?n++:n--)L=this.r.text(0,this.options.hoverFontSize*1.5*(n+1.5)-k/2,"").attr("fill",this.options.lineColors[n]).attr("font-size",this.options.hoverFontSize),M.push(L),m.push(L);return E=function(a){var b,d,e,f,h;m.show(),I.attr("text",Z.columnLabels[a]);for(b=0,h=Z.series.length-1;0<=h?b<=h:b>=h;0<=h?b++:b--)M[b].attr("text",""+Z.seriesLabels[b]+": "+Z.commas(Z.series[b][a]));return d=Math.max.apply(null,$.map(M,function(a){return a.getBBox().width})),d=Math.max(d,I.getBBox().width),j.attr("width",d+Z.options.hoverPaddingX*2),j.attr("x",-Z.options.hoverPaddingX-d/2),f=Math.min.apply(null,$.map(Z.series,function(b){return C(b[a])})),f>k+Z.options.hoverPaddingY*2+Z.options.hoverMargin+Z.options.marginTop?f=f-k/2-Z.options.hoverPaddingY-Z.options.hoverMargin:f=f+k/2+Z.options.hoverPaddingY+Z.options.hoverMargin,f=Math.max(Z.options.marginTop+k/2+Z.options.hoverPaddingY,f),f=Math.min(Z.options.marginTop+g-k/2-Z.options.hoverPaddingY,f),e=Math.min(q+G-d/2-Z.options.hoverPaddingX,c[a]),e=Math.max(q+d/2+Z.options.hoverPaddingX,e),m.attr("transform","t"+e+","+f)},h=function(){return m.hide()},l=$.map(c.slice(1),function(a,b){return(a+c[b])/2}),v=null,t=Raphael.animation({r:this.options.pointSize+3},25,"linear"),u=Raphael.animation({r:this.options.pointSize},25,"linear"),i=function(a){var b,c,d;if(v!==null&&v!==a)for(b=0,d=z.length-1;0<=d?b<=d:b>=d;0<=d?b++:b--)z[b][v].animate(u);if(a!==null&&v!==a){for(b=0,c=z.length-1;0<=c?b<=c:b>=c;0<=c?b++:b--)z[b][a].animate(t);E(a)}v=a;if(a===null)return h()},D=function(a){var b,c,d;a-=Z.el.offset().left,d=[];for(b=c=l.length;c<=0?b<=0:b>=0;c<=0?b++:b--){if(b===0||l[b-1]>a){i(b);break}d.push(void 0)}return d},this.el.mousemove(function(a){return D(a.pageX)}),A=function(a){var b;return b=a.originalEvent.touches[0]||a.originalEvent.changedTouches[0],D(b.pageX),b},this.el.bind("touchstart",A),this.el.bind("touchmove",A),this.el.bind("touchend",A),i(0)},b.prototype.createPath=function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r;m="";if(this.options.smooth){h=this.gradients(a);for(i=0,r=a.length-1;0<=r?i<=r:i>=r;0<=r?i++:i--)f=a[i],i===0?m+="M"+f.x+","+f.y:(g=h[i],k=a[i-1],l=h[i-1],j=(f.x-k.x)/4,n=k.x+j,p=Math.min(d,k.y+j*l),o=f.x-j,q=Math.min(d,f.y-j*g),m+="C"+n+","+p+","+o+","+q+","+f.x+","+f.y)}else m="M"+$.map(a,function(a){return""+a.x+","+a.y}).join("L");return m},b.prototype.gradients=function(a){return $.map(a,function(b,c){return c===0?(a[1].y-b.y)/(a[1].x-b.x):c===a.length-1?(b.y-a[c-1].y)/(b.x-a[c-1].x):(a[c+1].y-a[c-1].y)/(a[c+1].x-a[c-1].x)})},b.prototype.measureText=function(a,b){var c,d;return b==null&&(b=12),d=this.r.text(100,100,a).attr("font-size",b),c=d.getBBox(),d.remove(),c},b.prototype.parseYear=function(a){var b,c,d,e,f,g,h,i,j,k;return g=a.toString(),c=g.match(/^(\d+) Q(\d)$/),e=g.match(/^(\d+)-(\d+)$/),f=g.match(/^(\d+)-(\d+)-(\d+)$/),c?parseInt(c[1],10)+(parseInt(c[2],10)*3-1)/12:e?parseInt(e[1],10)+(parseInt(e[2],10)-1)/12:f?(k=parseInt(f[1],10),d=parseInt(f[2],10),b=parseInt(f[3],10),h=(new Date(k,d-1,b)).getTime(),i=(new Date(k,0,1)).getTime(),j=(new Date(k+1,0,1)).getTime(),k+(h-i)/(j-i)):parseInt(a,10)},b.prototype.commas=function(a){return Math.max(0,a).toFixed(0).replace(/(?=(?:\d{3})+$)(?!^)/g,",")},b}(),window.Morris=a})).call(this); \ No newline at end of file +((function(){var a,b;a=jQuery,b={},b.Line=function(){function c(c){if(!(this instanceof b.Line))return new b.Line(c);typeof c.element=="string"?this.el=a(document.getElementById(c.element)):this.el=a(c.element),this.options=a.extend({},this.defaults,c);if(this.options.data===void 0||this.options.data.length===0)return;this.el.addClass("graph-initialised"),this.precalc(),this.redraw()}return c.prototype.defaults={lineWidth:3,pointSize:4,lineColors:["#0b62a4","#7A92A3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],ymax:"auto",marginTop:25,marginRight:25,marginBottom:30,marginLeft:25,numLines:5,gridLineColor:"#aaa",gridTextColor:"#888",gridTextSize:12,gridStrokeWidth:.5,hoverPaddingX:10,hoverPaddingY:5,hoverMargin:10,hoverFillColor:"#fff",hoverBorderColor:"#ccc",hoverBorderWidth:2,hoverOpacity:.95,hoverLabelColor:"#444",hoverFontSize:12,smooth:!0},c.prototype.precalc=function(){var b,c,d,e,f,g=this;this.options.data.sort(function(a,b){return(a[g.options.xkey]5?this.options.ymax=Math.max(parseInt(this.options.ymax.slice(5),10),c):this.options.ymax=c},c.prototype.redraw=function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,_=this;this.el.empty(),this.r=new Raphael(this.el[0]),r=this.measureText(this.options.ymax,this.options.gridTextSize).width+this.options.marginLeft,H=this.el.width()-r-this.options.marginRight,h=this.el.height()-this.options.marginTop-this.options.marginBottom,f=H/(this.xmax-this.xmin),g=h/this.options.ymax,C=function(a){return _.xvals.length===1?r+H/2:r+(a-_.xmin)*f},D=function(a){return _.options.marginTop+h-a*g},s=h/(this.options.numLines-1);for(o=0,S=this.options.numLines-1;0<=S?o<=S:o>=S;0<=S?o++:o--)L=this.options.marginTop+o*s,G=Math.round((this.options.numLines-1-o)*this.options.ymax/(this.options.numLines-1)),this.r.text(r-this.options.marginLeft/2,L,G).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor).attr("text-anchor","end"),this.r.path("M"+r+","+L+"H"+(r+H)).attr("stroke",this.options.gridLineColor).attr("stroke-width",this.options.gridStrokeWidth);x=null,K=50;for(o=T=Math.ceil(this.xmin),U=Math.floor(this.xmax);T<=U?o<=U:o>=U;T<=U?o++:o--)p=this.r.text(C(o),this.options.marginTop+h+this.options.marginBottom/2,o).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor),q=p.getBBox(),x===null||x<=q.x?x=q.x+q.width+K:p.remove();d=function(){var a,b,c,d;c=this.xvals,d=[];for(a=0,b=c.length;a=0;W<=0?o++:o--)e=z[o],e.length>1&&(t=this.createPath(e,this.options.marginTop,r,this.options.marginTop+h,r+H),this.r.path(t).attr("stroke",this.options.lineColors[o]).attr("stroke-width",this.options.lineWidth));A=function(){var a,b;b=[];for(o=0,a=z.length-1;0<=a?o<=a:o>=a;0<=a?o++:o--)b.push([]);return b}();for(o=X=z.length-1;X<=0?o<=0:o>=0;X<=0?o++:o--){Y=z[o];for(P=0,R=Y.length;P=Z;0<=Z?o++:o--)M=this.r.text(0,this.options.hoverFontSize*1.5*(o+1.5)-l/2,"").attr("fill",this.options.lineColors[o]).attr("font-size",this.options.hoverFontSize),N.push(M),n.push(M);return F=function(b){var c,e,f,g,i;n.show(),J.attr("text",_.columnLabels[b]);for(c=0,i=_.series.length-1;0<=i?c<=i:c>=i;0<=i?c++:c--)N[c].attr("text",""+_.seriesLabels[c]+": "+_.commas(_.series[c][b]));return e=Math.max.apply(null,a.map(N,function(a){return a.getBBox().width})),e=Math.max(e,J.getBBox().width),k.attr("width",e+_.options.hoverPaddingX*2),k.attr("x",-_.options.hoverPaddingX-e/2),g=Math.min.apply(null,a.map(_.series,function(a){return D(a[b])})),g>l+_.options.hoverPaddingY*2+_.options.hoverMargin+_.options.marginTop?g=g-l/2-_.options.hoverPaddingY-_.options.hoverMargin:g=g+l/2+_.options.hoverPaddingY+_.options.hoverMargin,g=Math.max(_.options.marginTop+l/2+_.options.hoverPaddingY,g),g=Math.min(_.options.marginTop+h-l/2-_.options.hoverPaddingY,g),f=Math.min(r+H-e/2-_.options.hoverPaddingX,d[b]),f=Math.max(r+e/2+_.options.hoverPaddingX,f),n.attr("transform","t"+f+","+g)},i=function(){return n.hide()},m=a.map(d.slice(1),function(a,b){return(a+d[b])/2}),w=null,u=Raphael.animation({r:this.options.pointSize+3},25,"linear"),v=Raphael.animation({r:this.options.pointSize},25,"linear"),j=function(a){var b,c,d;if(w!==null&&w!==a)for(b=0,d=A.length-1;0<=d?b<=d:b>=d;0<=d?b++:b--)A[b][w].animate(v);if(a!==null&&w!==a){for(b=0,c=A.length-1;0<=c?b<=c:b>=c;0<=c?b++:b--)A[b][a].animate(u);F(a)}w=a;if(a===null)return i()},E=function(a){var b,c,d;a-=_.el.offset().left,d=[];for(b=c=m.length;c<=0?b<=0:b>=0;c<=0?b++:b--){if(b===0||m[b-1]>a){j(b);break}d.push(void 0)}return d},this.el.mousemove(function(a){return E(a.pageX)}),B=function(a){var b;return b=a.originalEvent.touches[0]||a.originalEvent.changedTouches[0],E(b.pageX),b},this.el.bind("touchstart",B),this.el.bind("touchmove",B),this.el.bind("touchend",B),j(0)},c.prototype.createPath=function(b,c,d,e,f){var g,h,i,j,k,l,m,n,o,p,q,r,s;n="";if(this.options.smooth){i=this.gradients(b);for(j=0,s=b.length-1;0<=s?j<=s:j>=s;0<=s?j++:j--)g=b[j],j===0?n+="M"+g.x+","+g.y:(h=i[j],l=b[j-1],m=i[j-1],k=(g.x-l.x)/4,o=l.x+k,q=Math.min(e,l.y+k*m),p=g.x-k,r=Math.min(e,g.y-k*h),n+="C"+o+","+q+","+p+","+r+","+g.x+","+g.y)}else n="M"+a.map(b,function(a){return""+a.x+","+a.y}).join("L");return n},c.prototype.gradients=function(b){return a.map(b,function(a,c){return c===0?(b[1].y-a.y)/(b[1].x-a.x):c===b.length-1?(a.y-b[c-1].y)/(a.x-b[c-1].x):(b[c+1].y-b[c-1].y)/(b[c+1].x-b[c-1].x)})},c.prototype.measureText=function(a,b){var c,d;return b==null&&(b=12),d=this.r.text(100,100,a).attr("font-size",b),c=d.getBBox(),d.remove(),c},c.prototype.parseYear=function(a){var b,c,d,e,f,g,h,i,j,k;return g=a.toString(),c=g.match(/^(\d+) Q(\d)$/),e=g.match(/^(\d+)-(\d+)$/),f=g.match(/^(\d+)-(\d+)-(\d+)$/),c?parseInt(c[1],10)+(parseInt(c[2],10)*3-1)/12:e?parseInt(e[1],10)+(parseInt(e[2],10)-1)/12:f?(k=parseInt(f[1],10),d=parseInt(f[2],10),b=parseInt(f[3],10),h=(new Date(k,d-1,b)).getTime(),i=(new Date(k,0,1)).getTime(),j=(new Date(k+1,0,1)).getTime(),k+(h-i)/(j-i)):parseInt(a,10)},c.prototype.commas=function(a){return Math.max(0,a).toFixed(0).replace(/(?=(?:\d{3})+$)(?!^)/g,",")},c}(),window.Morris=b})).call(this); \ No newline at end of file