diff --git a/grunt.js b/grunt.js index f2a73b6..7a1fe55 100644 --- a/grunt.js +++ b/grunt.js @@ -15,6 +15,7 @@ module.exports = function (grunt) { concat: { 'build/morris.coffee': [ 'lib/morris.coffee', + 'lib/morris.svg.coffee', 'lib/morris.grid.coffee', 'lib/morris.hover.coffee', 'lib/morris.line.coffee', diff --git a/lib/morris.area.coffee b/lib/morris.area.coffee index a654ac3..9ebe8b9 100644 --- a/lib/morris.area.coffee +++ b/lib/morris.area.coffee @@ -26,9 +26,7 @@ class Morris.Area extends Morris.Line 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) + @drawFilledPath(path, @fillForSeries(i)) super() fillForSeries: (i) -> @@ -37,3 +35,8 @@ class Morris.Area extends Morris.Line color.h, Math.min(255, color.s * 0.75), Math.min(255, color.l * 1.25)) + + drawFilledPath: (path, fill) -> + @raphael.path(path) + .attr('fill', fill) + .attr('stroke-width', 0) diff --git a/lib/morris.bar.coffee b/lib/morris.bar.coffee index d45daec..cf59396 100644 --- a/lib/morris.bar.coffee +++ b/lib/morris.bar.coffee @@ -59,9 +59,7 @@ class Morris.Bar extends Morris.Grid prevLabelMargin = null for i in [0...@data.length] row = @data[@data.length - 1 - i] - label = @r.text(row._x, ypos, row.label) - .attr('font-size', @options.gridTextSize) - .attr('fill', @options.gridTextColor) + label = @drawXAxisLabel(row._x, ypos, row.label) labelBox = label.getBBox() # ensure a minimum of `xLabelMargin` pixels between labels, and ensure # labels don't overflow the container @@ -96,9 +94,7 @@ class Morris.Bar extends Morris.Grid size = bottom - top top -= lastTop if @options.stacked - @r.rect(left, top, barWidth, size) - .attr('fill', @colorFor(row, sidx, 'bar')) - .attr('stroke-width', 0) + @drawBar(left, top, barWidth, size, @colorFor(row, sidx, 'bar')) lastTop += size else @@ -156,3 +152,13 @@ class Morris.Bar extends Morris.Grid """ x = @left + (index + 0.5) * @width / @data.length [content, x] + + drawXAxisLabel: (xPos, yPos, text) -> + label = @raphael.text(xPos, yPos, text) + .attr('font-size', @options.gridTextSize) + .attr('fill', @options.gridTextColor) + + drawBar: (xPos, yPos, width, height, barColor) -> + @raphael.rect(xPos, yPos, width, height) + .attr('fill', barColor) + .attr('stroke-width', 0) diff --git a/lib/morris.donut.coffee b/lib/morris.donut.coffee index a409e69..19963ba 100644 --- a/lib/morris.donut.coffee +++ b/lib/morris.donut.coffee @@ -55,7 +55,7 @@ class Morris.Donut redraw: -> @el.empty() - @r = new Raphael(@el[0]) + @raphael = new Raphael(@el[0]) cx = @el.width() / 2 cy = @el.height() / 2 @@ -72,14 +72,14 @@ class Morris.Donut @segments = [] for d in @data next = last + min + C * (d.value / total) - seg = new Morris.DonutSegment(cx, cy, w*2, w, last, next, @options.colors[idx % @options.colors.length], @options.backgroundColor, d) - seg.render @r + seg = new Morris.DonutSegment(cx, cy, w*2, w, last, next, @options.colors[idx % @options.colors.length], @options.backgroundColor, d, @raphael) + seg.render() @segments.push seg seg.on 'hover', @select last = next idx += 1 - @text1 = @r.text(cx, cy - 10, '').attr('font-size': 15, 'font-weight': 800) - @text2 = @r.text(cx, cy + 10, '').attr('font-size': 14) + @text1 = @drawEmptyDonutLabel(cx, cy - 10, 15, 800) + @text2 = @drawEmptyDonutLabel(cx, cy + 10, 14) max_value = Math.max.apply(null, d.value for d in @data) idx = 0 for d in @data @@ -110,12 +110,17 @@ class Morris.Donut text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height) @text2.attr(transform: "S#{text2scale},#{text2scale},#{text2bbox.x + text2bbox.width / 2},#{text2bbox.y}") + drawEmptyDonutLabel: (xPos, yPos, fontSize, fontWeight) -> + text = @raphael.text(xPos, yPos, '').attr('font-size', fontSize) + text.attr('font-weight', fontWeight) if fontWeight? + return text + # A segment within a donut chart. # # @private class Morris.DonutSegment extends Morris.EventEmitter - constructor: (@cx, @cy, @inner, @outer, p0, p1, @color, @backgroundColor, @data) -> + constructor: (@cx, @cy, @inner, @outer, p0, p1, @color, @backgroundColor, @data, @raphael) -> @sin_p0 = Math.sin(p0) @cos_p0 = Math.cos(p0) @sin_p1 = Math.sin(p1) @@ -148,11 +153,18 @@ class Morris.DonutSegment extends Morris.EventEmitter "M#{ix0},#{iy0}" + "A#{r},#{r},0,#{@is_long},0,#{ix1},#{iy1}") - render: (r) -> - @arc = r.path(@hilight).attr(stroke: @color, 'stroke-width': 2, opacity: 0) - @seg = r.path(@path) - .attr(fill: @color, stroke: @backgroundColor, 'stroke-width': 3) - .hover(=> @fire('hover', @)) + render: -> + @arc = @drawDonutArc(@hilight, @color) + @seg = @drawDonutSegment(@path, @color, @backgroundColor, => @fire('hover', @)) + + drawDonutArc: (path, color) -> + @raphael.path(path) + .attr(stroke: color, 'stroke-width': 2, opacity: 0) + + drawDonutSegment: (path, fillColor, strokeColor, hoverFunction) -> + @raphael.path(path) + .attr(fill: fillColor, stroke: strokeColor, 'stroke-width': 3) + .hover(hoverFunction) select: => unless @selected diff --git a/lib/morris.grid.coffee b/lib/morris.grid.coffee index b7b46e4..69c33eb 100644 --- a/lib/morris.grid.coffee +++ b/lib/morris.grid.coffee @@ -26,7 +26,7 @@ class Morris.Grid extends Morris.EventEmitter @options.postUnits = options.units # the raphael drawing instance - @r = new Raphael(@el[0]) + @raphael = new Raphael(@el[0]) # some redraw stuff @elementWidth = null @@ -227,7 +227,7 @@ class Morris.Grid extends Morris.EventEmitter # If you need to re-size your charts, call this method after changing the # size of the container element. redraw: -> - @r.clear() + @raphael.clear() @_calc() @drawGrid() @drawGoals() @@ -238,16 +238,12 @@ class Morris.Grid extends Morris.EventEmitter # drawGoals: -> for goal, i in @options.goals - @r.path("M#{@left},#{@transY(goal)}H#{@left + @width}") - .attr('stroke', @options.goalLineColors[i % @options.goalLineColors.length]) - .attr('stroke-width', @options.goalStrokeWidth) + @drawGoal("M#{@left},#{@transY(goal)}H#{@left + @width}") # draw events vertical lines drawEvents: -> for event, i in @events - @r.path("M#{@transX(event)},#{@bottom}V#{@top}") - .attr('stroke', @options.eventLineColors[i % @options.eventLineColors.length]) - .attr('stroke-width', @options.eventStrokeWidth) + @drawEvent("M#{@transX(event)},#{@bottom}V#{@top}") # draw y axis labels, horizontal lines # @@ -259,19 +255,14 @@ class Morris.Grid extends Morris.EventEmitter v = parseFloat(lineY.toFixed(@precision)) y = @transY(v) if @options.axes - @r.text(@left - @options.padding / 2, y, @yAxisFormat(v)) - .attr('font-size', @options.gridTextSize) - .attr('fill', @options.gridTextColor) - .attr('text-anchor', 'end') + @drawYAxisLabel(@left - @options.padding / 2, y, @yAxisFormat(v)) if @options.grid - @r.path("M#{@left},#{y}H#{@left + @width}") - .attr('stroke', @options.gridLineColor) - .attr('stroke-width', @options.gridStrokeWidth) + @drawGridLine("M#{@left},#{y}H#{@left + @width}") # @private # measureText: (text, fontSize = 12) -> - tt = @r.text(100, 100, text).attr('font-size', fontSize) + tt = @raphael.text(100, 100, text).attr('font-size', fontSize) ret = tt.getBBox() tt.remove() ret @@ -293,6 +284,27 @@ class Morris.Grid extends Morris.EventEmitter if hit? @hover.update(hit...) + drawGoal: (path) -> + @raphael.path(path) + .attr('stroke', @options.goalLineColors[i % @options.goalLineColors.length]) + .attr('stroke-width', @options.goalStrokeWidth) + + drawEvent: (path) -> + @raphael.path(path) + .attr('stroke', @options.eventLineColors[i % @options.eventLineColors.length]) + .attr('stroke-width', @options.eventStrokeWidth) + + drawYAxisLabel: (xPos, yPos, text) -> + @raphael.text(xPos, yPos, text) + .attr('font-size', @options.gridTextSize) + .attr('fill', @options.gridTextColor) + .attr('text-anchor', 'end') + + drawGridLine: (path) -> + @raphael.path(path) + .attr('stroke', @options.gridLineColor) + .attr('stroke-width', @options.gridStrokeWidth) + # Parse a date into a javascript timestamp # # diff --git a/lib/morris.line.coffee b/lib/morris.line.coffee index 8613464..55d3f96 100644 --- a/lib/morris.line.coffee +++ b/lib/morris.line.coffee @@ -138,9 +138,7 @@ class Morris.Line extends Morris.Grid ypos = @bottom + @options.gridTextSize * 1.25 prevLabelMargin = null drawLabel = (labelText, xpos) => - label = @r.text(@transX(xpos), ypos, labelText) - .attr('font-size', @options.gridTextSize) - .attr('fill', @options.gridTextColor) + label = @drawXAxisLabel(@transX(xpos), ypos, labelText) labelBox = label.getBBox() # ensure a minimum of `xLabelMargin` pixels between labels, and ensure # labels don't overflow the container @@ -170,17 +168,12 @@ class Morris.Line extends Morris.Grid for i in [@options.ykeys.length-1..0] path = @paths[i] if path isnt null - @r.path(path) - .attr('stroke', @colorFor(row, i, 'line')) - .attr('stroke-width', @options.lineWidth) + @drawLinePath(path, @colorFor(row, i, 'line')) #row isn't available here? @seriesPoints = ([] for i in [0...@options.ykeys.length]) for i in [@options.ykeys.length-1..0] for row in @data if row._y[i]? - circle = @r.circle(row._x, row._y[i], @options.pointSize) - .attr('fill', @colorFor(row, i, 'point')) - .attr('stroke-width', @strokeWidthForSeries(i)) - .attr('stroke', @strokeForSeries(i)) + circle = @drawLinePoint(row._x, row._y[i], @options.pointSize, @colorFor(row, i, 'point'), i) else circle = null @seriesPoints[i].push(circle) @@ -245,14 +238,6 @@ class Morris.Line extends Morris.Grid @seriesPoints[i][index].animate @pointGrow @prevHilight = index - # @private - strokeWidthForSeries: (index) -> - @options.pointWidths[index % @options.pointWidths.length] - - # @private - strokeForSeries: (index) -> - @options.pointStrokeColors[index % @options.pointStrokeColors.length] - colorFor: (row, sidx, type) -> if typeof @options.lineColors is 'function' @options.lineColors.call(@, row, sidx, type) @@ -261,6 +246,29 @@ class Morris.Line extends Morris.Grid else @options.lineColors[sidx % @options.lineColors.length] + drawXAxisLabel: (xPos, yPos, text) -> + @raphael.text(xPos, yPos, text) + .attr('font-size', @options.gridTextSize) + .attr('fill', @options.gridTextColor) + + drawLinePath: (path, lineColor) -> + @raphael.path(path) + .attr('stroke', lineColor) + .attr('stroke-width', @options.lineWidth) + + drawLinePoint: (xPos, yPos, size, pointColor, lineIndex) -> + @raphael.circle(xPos, yPos, size) + .attr('fill', pointColor) + .attr('stroke-width', @strokeWidthForSeries(lineIndex)) + .attr('stroke', @strokeForSeries(lineIndex)) + + # @private + strokeWidthForSeries: (index) -> + @options.pointWidths[index % @options.pointWidths.length] + + # @private + strokeForSeries: (index) -> + @options.pointStrokeColors[index % @options.pointStrokeColors.length] # generate a series of label, timestamp pairs for x-axis labels # diff --git a/morris.js b/morris.js index 2599d44..e41b2db 100644 --- a/morris.js +++ b/morris.js @@ -87,7 +87,7 @@ if (typeof this.options.units === 'string') { this.options.postUnits = options.units; } - this.r = new Raphael(this.el[0]); + this.raphael = new Raphael(this.el[0]); this.elementWidth = null; this.elementHeight = null; this.dirty = false; @@ -324,7 +324,7 @@ }; Grid.prototype.redraw = function() { - this.r.clear(); + this.raphael.clear(); this._calc(); this.drawGrid(); this.drawGoals(); @@ -340,7 +340,7 @@ _results = []; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { goal = _ref[i]; - _results.push(this.r.path("M" + this.left + "," + (this.transY(goal)) + "H" + (this.left + this.width)).attr('stroke', this.options.goalLineColors[i % this.options.goalLineColors.length]).attr('stroke-width', this.options.goalStrokeWidth)); + _results.push(this.drawGoal("M" + this.left + "," + (this.transY(goal)) + "H" + (this.left + this.width))); } return _results; }; @@ -351,7 +351,7 @@ _results = []; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { event = _ref[i]; - _results.push(this.r.path("M" + (this.transX(event)) + "," + this.bottom + "V" + this.top).attr('stroke', this.options.eventLineColors[i % this.options.eventLineColors.length]).attr('stroke-width', this.options.eventStrokeWidth)); + _results.push(this.drawEvent("M" + (this.transX(event)) + "," + this.bottom + "V" + this.top)); } return _results; }; @@ -368,10 +368,10 @@ v = parseFloat(lineY.toFixed(this.precision)); y = this.transY(v); if (this.options.axes) { - this.r.text(this.left - this.options.padding / 2, y, this.yAxisFormat(v)).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end'); + this.drawYAxisLabel(this.left - this.options.padding / 2, y, this.yAxisFormat(v)); } if (this.options.grid) { - _results.push(this.r.path("M" + this.left + "," + y + "H" + (this.left + this.width)).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth)); + _results.push(this.drawGridLine("M" + this.left + "," + y + "H" + (this.left + this.width))); } else { _results.push(void 0); } @@ -384,7 +384,7 @@ if (fontSize == null) { fontSize = 12; } - tt = this.r.text(100, 100, text).attr('font-size', fontSize); + tt = this.raphael.text(100, 100, text).attr('font-size', fontSize); ret = tt.getBBox(); tt.remove(); return ret; @@ -410,6 +410,22 @@ } }; + Grid.prototype.drawGoal = function(path) { + return this.raphael.path(path).attr('stroke', this.options.goalLineColors[i % this.options.goalLineColors.length]).attr('stroke-width', this.options.goalStrokeWidth); + }; + + Grid.prototype.drawEvent = function(path) { + return this.raphael.path(path).attr('stroke', this.options.eventLineColors[i % this.options.eventLineColors.length]).attr('stroke-width', this.options.eventStrokeWidth); + }; + + Grid.prototype.drawYAxisLabel = function(xPos, yPos, text) { + return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end'); + }; + + Grid.prototype.drawGridLine = function(path) { + return this.raphael.path(path).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth); + }; + return Grid; })(Morris.EventEmitter); @@ -735,7 +751,7 @@ prevLabelMargin = null; drawLabel = function(labelText, xpos) { var label, labelBox; - label = _this.r.text(_this.transX(xpos), ypos, labelText).attr('font-size', _this.options.gridTextSize).attr('fill', _this.options.gridTextColor); + label = _this.drawXAxisLabel(_this.transX(xpos), ypos, labelText); labelBox = label.getBBox(); if ((!(prevLabelMargin != null) || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < _this.el.width()) { return prevLabelMargin = labelBox.x - _this.options.xLabelMargin; @@ -775,7 +791,7 @@ 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) { - this.r.path(path).attr('stroke', this.colorFor(row, i, 'line')).attr('stroke-width', this.options.lineWidth); + this.drawLinePath(path, this.colorFor(row, i, 'line')); } } this.seriesPoints = (function() { @@ -795,7 +811,7 @@ for (_k = 0, _len = _ref2.length; _k < _len; _k++) { row = _ref2[_k]; if (row._y[i] != null) { - circle = this.r.circle(row._x, row._y[i], this.options.pointSize).attr('fill', this.colorFor(row, i, 'point')).attr('stroke-width', this.strokeWidthForSeries(i)).attr('stroke', this.strokeForSeries(i)); + circle = this.drawLinePoint(row._x, row._y[i], this.options.pointSize, this.colorFor(row, i, 'point'), i); } else { circle = null; } @@ -893,14 +909,6 @@ return this.prevHilight = index; }; - Line.prototype.strokeWidthForSeries = function(index) { - return this.options.pointWidths[index % this.options.pointWidths.length]; - }; - - Line.prototype.strokeForSeries = function(index) { - return this.options.pointStrokeColors[index % this.options.pointStrokeColors.length]; - }; - Line.prototype.colorFor = function(row, sidx, type) { if (typeof this.options.lineColors === 'function') { return this.options.lineColors.call(this, row, sidx, type); @@ -911,6 +919,26 @@ } }; + Line.prototype.drawXAxisLabel = function(xPos, yPos, text) { + return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor); + }; + + Line.prototype.drawLinePath = function(path, lineColor) { + return this.raphael.path(path).attr('stroke', lineColor).attr('stroke-width', this.options.lineWidth); + }; + + Line.prototype.drawLinePoint = function(xPos, yPos, size, pointColor, lineIndex) { + return this.raphael.circle(xPos, yPos, size).attr('fill', pointColor).attr('stroke-width', this.strokeWidthForSeries(lineIndex)).attr('stroke', this.strokeForSeries(lineIndex)); + }; + + Line.prototype.strokeWidthForSeries = function(index) { + return this.options.pointWidths[index % this.options.pointWidths.length]; + }; + + Line.prototype.strokeForSeries = function(index) { + return this.options.pointStrokeColors[index % this.options.pointStrokeColors.length]; + }; + return Line; })(Morris.Grid); @@ -1086,7 +1114,7 @@ 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); + this.drawFilledPath(path, this.fillForSeries(i)); } } return Area.__super__.drawSeries.call(this); @@ -1098,6 +1126,10 @@ return Raphael.hsl(color.h, Math.min(255, color.s * 0.75), Math.min(255, color.l * 1.25)); }; + Area.prototype.drawFilledPath = function(path, fill) { + return this.raphael.path(path).attr('fill', fill).attr('stroke-width', 0); + }; + return Area; })(Morris.Line); @@ -1183,7 +1215,7 @@ _results = []; for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { row = this.data[this.data.length - 1 - i]; - label = this.r.text(row._x, ypos, row.label).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor); + label = this.drawXAxisLabel(row._x, ypos, row.label); labelBox = label.getBBox(); if ((!(prevLabelMargin != null) || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < this.el.width()) { _results.push(prevLabelMargin = labelBox.x - this.options.xLabelMargin); @@ -1230,7 +1262,7 @@ if (this.options.stacked) { top -= lastTop; } - this.r.rect(left, top, barWidth, size).attr('fill', this.colorFor(row, sidx, 'bar')).attr('stroke-width', 0); + this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar')); _results1.push(lastTop += size); } else { _results1.push(null); @@ -1296,6 +1328,15 @@ return [content, x]; }; + Bar.prototype.drawXAxisLabel = function(xPos, yPos, text) { + var label; + return label = this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor); + }; + + Bar.prototype.drawBar = function(xPos, yPos, width, height, barColor) { + return this.raphael.rect(xPos, yPos, width, height).attr('fill', barColor).attr('stroke-width', 0); + }; + return Bar; })(Morris.Grid); @@ -1332,7 +1373,7 @@ 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]); + this.raphael = new Raphael(this.el[0]); cx = this.el.width() / 2; cy = this.el.height() / 2; w = (Math.min(cx, cy) - 10) / 3; @@ -1351,20 +1392,15 @@ 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], this.options.backgroundColor, d); - seg.render(this.r); + seg = new Morris.DonutSegment(cx, cy, w * 2, w, last, next, this.options.colors[idx % this.options.colors.length], this.options.backgroundColor, d, this.raphael); + seg.render(); 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 - }); + this.text1 = this.drawEmptyDonutLabel(cx, cy - 10, 15, 800); + this.text2 = this.drawEmptyDonutLabel(cx, cy + 10, 14); max_value = Math.max.apply(null, (function() { var _k, _len2, _ref2, _results; _ref2 = this.data; @@ -1431,6 +1467,15 @@ }); }; + Donut.prototype.drawEmptyDonutLabel = function(xPos, yPos, fontSize, fontWeight) { + var text; + text = this.raphael.text(xPos, yPos, '').attr('font-size', fontSize); + if (fontWeight != null) { + text.attr('font-weight', fontWeight); + } + return text; + }; + return Donut; })(); @@ -1439,7 +1484,7 @@ __extends(DonutSegment, _super); - function DonutSegment(cx, cy, inner, outer, p0, p1, color, backgroundColor, data) { + function DonutSegment(cx, cy, inner, outer, p0, p1, color, backgroundColor, data, raphael) { this.cx = cx; this.cy = cy; this.inner = inner; @@ -1447,6 +1492,7 @@ this.color = color; this.backgroundColor = backgroundColor; this.data = data; + this.raphael = raphael; this.deselect = __bind(this.deselect, this); this.select = __bind(this.select, this); @@ -1478,20 +1524,28 @@ return ("M" + ix0 + "," + iy0) + ("A" + r + "," + r + ",0," + this.is_long + ",0," + ix1 + "," + iy1); }; - DonutSegment.prototype.render = function(r) { + DonutSegment.prototype.render = function() { var _this = this; - this.arc = r.path(this.hilight).attr({ - stroke: this.color, + this.arc = this.drawDonutArc(this.hilight, this.color); + return this.seg = this.drawDonutSegment(this.path, this.color, this.backgroundColor, function() { + return _this.fire('hover', _this); + }); + }; + + DonutSegment.prototype.drawDonutArc = function(path, color) { + return this.raphael.path(path).attr({ + stroke: color, 'stroke-width': 2, opacity: 0 }); - return this.seg = r.path(this.path).attr({ - fill: this.color, - stroke: this.backgroundColor, + }; + + DonutSegment.prototype.drawDonutSegment = function(path, fillColor, strokeColor, hoverFunction) { + return this.raphael.path(path).attr({ + fill: fillColor, + stroke: strokeColor, 'stroke-width': 3 - }).hover(function() { - return _this.fire('hover', _this); - }); + }).hover(hoverFunction); }; DonutSegment.prototype.select = function() { diff --git a/morris.min.js b/morris.min.js index 4babefc..7d48f6e 100644 --- a/morris.min.js +++ b/morris.min.js @@ -1 +1 @@ -(function(){var e,t,n,r,i=[].slice,s={}.hasOwnProperty,o=function(e,t){function r(){this.constructor=e}for(var n in t)s.call(t,n)&&(e[n]=t[n]);return r.prototype=t.prototype,e.prototype=new r,e.__super__=t.prototype,e},u=function(e,t){return function(){return e.apply(t,arguments)}},a=[].indexOf||function(e){for(var t=0,n=this.length;tn.length&&(r+=i.slice(n.length)),r):"-"},t.pad2=function(e){return(e<10?"0":"")+e},t.Grid=function(n){function r(t){var n=this;typeof t.element=="string"?this.el=e(document.getElementById(t.element)):this.el=e(t.element);if(this.el==null||this.el.length===0)throw new Error("Graph container element not found");this.el.css("position")==="static"&&this.el.css("position","relative"),this.options=e.extend({},this.gridDefaults,this.defaults||{},t);if(this.options.data===void 0||this.options.data.length===0)return;typeof this.options.units=="string"&&(this.options.postUnits=t.units),this.r=new Raphael(this.el[0]),this.elementWidth=null,this.elementHeight=null,this.dirty=!1,this.init&&this.init(),this.setData(this.options.data),this.el.bind("mousemove",function(e){var t;return t=n.el.offset(),n.fire("hovermove",e.pageX-t.left,e.pageY-t.top)}),this.el.bind("mouseout",function(e){return n.fire("hoverout")}),this.el.bind("touchstart touchmove touchend",function(e){var t,r;return r=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0],t=n.el.offset(),n.fire("hover",r.pageX-t.left,r.pageY-t.top),r}),this.postInit&&this.postInit()}return o(r,n),r.prototype.gridDefaults={dateFormat:null,axes:!0,grid:!0,gridLineColor:"#aaa",gridStrokeWidth:.5,gridTextColor:"#888",gridTextSize:12,hideHover:!1,yLabelFormat:null,numLines:5,padding:25,parseTime:!0,postUnits:"",preUnits:"",ymax:"auto",ymin:"auto 0",goals:[],goalStrokeWidth:1,goalLineColors:["#666633","#999966","#cc6666","#663333"],events:[],eventStrokeWidth:1,eventLineColors:["#005a04","#ccffbb","#3a5f0b","#005502"]},r.prototype.setData=function(e,n){var r,i,s,o,u,a,f,l,c,h,p,d;n==null&&(n=!0),h=this.cumulative?0:null,p=this.cumulative?0:null,this.options.goals.length>0&&(u=Math.min.apply(null,this.options.goals),o=Math.max.apply(null,this.options.goals),p=p!=null?Math.min(p,u):u,h=h!=null?Math.max(h,o):o),this.data=function(){var n,r,o;o=[];for(s=n=0,r=e.length;nt.x)-(t.x>e.x)})),this.xmin=this.data[0].x,this.xmax=this.data[this.data.length-1].x,this.events=[],this.options.parseTime&&this.options.events.length>0&&(this.events=function(){var e,n,i,s;i=this.options.events,s=[];for(e=0,n=i.length;e5?(this.ymax=parseInt(this.options.ymax.slice(5),10),h!=null&&(this.ymax=Math.max(h,this.ymax))):this.ymax=h!=null?h:0:this.ymax=parseInt(this.options.ymax,10):this.ymax=this.options.ymax,typeof this.options.ymin=="string"?this.options.ymin.slice(0,4)==="auto"?this.options.ymin.length>5?(this.ymin=parseInt(this.options.ymin.slice(5),10),p!=null&&(this.ymin=Math.min(p,this.ymin))):this.ymin=p!==null?p:0:this.ymin=parseInt(this.options.ymin,10):this.ymin=this.options.ymin,this.ymin===this.ymax&&(p&&(this.ymin-=1),this.ymax+=1),this.yInterval=(this.ymax-this.ymin)/(this.options.numLines-1),this.yInterval>0&&this.yInterval<1?this.precision=-Math.floor(Math.log(this.yInterval)/Math.log(10)):this.precision=0,this.dirty=!0;if(n)return this.redraw()},r.prototype._calc=function(){var e,t,n;n=this.el.width(),e=this.el.height();if(this.elementWidth!==n||this.elementHeight!==e||this.dirty){this.elementWidth=n,this.elementHeight=e,this.dirty=!1,this.left=this.options.padding,this.right=this.elementWidth-this.options.padding,this.top=this.options.padding,this.bottom=this.elementHeight-this.options.padding,this.options.axes&&(t=Math.max(this.measureText(this.yAxisFormat(this.ymin),this.options.gridTextSize).width,this.measureText(this.yAxisFormat(this.ymax),this.options.gridTextSize).width),this.left+=t,this.bottom-=1.5*this.options.gridTextSize),this.width=this.right-this.left,this.height=this.bottom-this.top,this.dx=this.width/(this.xmax-this.xmin),this.dy=this.height/(this.ymax-this.ymin);if(this.calc)return this.calc()}},r.prototype.transY=function(e){return this.bottom-(e-this.ymin)*this.dy},r.prototype.transX=function(e){return this.data.length===1?(this.left+this.right)/2:this.left+(e-this.xmin)*this.dx},r.prototype.redraw=function(){this.r.clear(),this._calc(),this.drawGrid(),this.drawGoals(),this.drawEvents();if(this.draw)return this.draw()},r.prototype.drawGoals=function(){var e,t,n,r,i,s;i=this.options.goals,s=[];for(t=n=0,r=i.length;n=t;n=s+=o)r=parseFloat(n.toFixed(this.precision)),i=this.transY(r),this.options.axes&&this.r.text(this.left-this.options.padding/2,i,this.yAxisFormat(r)).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor).attr("text-anchor","end"),this.options.grid?u.push(this.r.path("M"+this.left+","+i+"H"+(this.left+this.width)).attr("stroke",this.options.gridLineColor).attr("stroke-width",this.options.gridStrokeWidth)):u.push(void 0);return u},r.prototype.measureText=function(e,t){var n,r;return t==null&&(t=12),r=this.r.text(100,100,e).attr("font-size",t),n=r.getBBox(),r.remove(),n},r.prototype.yAxisFormat=function(e){return this.yLabelFormat(e)},r.prototype.yLabelFormat=function(e){return typeof this.options.yLabelFormat=="function"?this.options.yLabelFormat(e):""+this.options.preUnits+t.commas(e)+this.options.postUnits},r.prototype.updateHover=function(e,t){var n,r;n=this.hitTest(e,t);if(n!=null)return(r=this.hover).update.apply(r,n)},r}(t.EventEmitter),t.parseDate=function(e){var t,n,r,i,s,o,u,a,f,l,c;return typeof e=="number"?e:(n=e.match(/^(\d+) Q(\d)$/),i=e.match(/^(\d+)-(\d+)$/),s=e.match(/^(\d+)-(\d+)-(\d+)$/),u=e.match(/^(\d+) W(\d+)$/),a=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+)(Z|([+-])(\d\d):?(\d\d))?$/),f=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+):(\d+(\.\d+)?)(Z|([+-])(\d\d):?(\d\d))?$/),n?(new Date(parseInt(n[1],10),parseInt(n[2],10)*3-1,1)).getTime():i?(new Date(parseInt(i[1],10),parseInt(i[2],10)-1,1)).getTime():s?(new Date(parseInt(s[1],10),parseInt(s[2],10)-1,parseInt(s[3],10))).getTime():u?(l=new Date(parseInt(u[1],10),0,1),l.getDay()!==4&&l.setMonth(0,1+(4-l.getDay()+7)%7),l.getTime()+parseInt(u[2],10)*6048e5):a?a[6]?(o=0,a[6]!=="Z"&&(o=parseInt(a[8],10)*60+parseInt(a[9],10),a[7]==="+"&&(o=0-o)),Date.UTC(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10)+o)):(new Date(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10))).getTime():f?(c=parseFloat(f[6]),t=Math.floor(c),r=Math.round((c-t)*1e3),f[8]?(o=0,f[8]!=="Z"&&(o=parseInt(f[10],10)*60+parseInt(f[11],10),f[9]==="+"&&(o=0-o)),Date.UTC(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10)+o,t,r)):(new Date(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10),t,r)).getTime()):(new Date(parseInt(e,10),0,1)).getTime())},t.Hover=function(){function n(n){n==null&&(n={}),this.options=e.extend({},t.Hover.defaults,n),this.el=e("
"),this.el.hide(),this.options.parent.append(this.el)}return n.defaults={"class":"morris-hover morris-default-style"},n.prototype.update=function(e,t,n){return this.html(e),this.show(),this.moveTo(t,n)},n.prototype.html=function(e){return this.el.html(e)},n.prototype.moveTo=function(e,t){var n,r,i,s,o,u;return o=this.options.parent.innerWidth(),s=this.options.parent.innerHeight(),r=this.el.outerWidth(),n=this.el.outerHeight(),i=Math.min(Math.max(0,e-r/2),o-r),t!=null?(u=t-n-10,u<0&&(u=t+10,u+n>s&&(u=s/2-n/2))):u=s/2-n/2,this.el.css({left:i+"px",top:u+"px"})},n.prototype.show=function(){return this.el.show()},n.prototype.hide=function(){return this.el.hide()},n}(),t.Line=function(e){function n(e){this.hilight=u(this.hilight,this),this.onHoverOut=u(this.onHoverOut,this),this.onHoverMove=u(this.onHoverMove,this);if(!(this instanceof t.Line))return new t.Line(e);n.__super__.constructor.call(this,e)}return o(n,e),n.prototype.init=function(){this.pointGrow=Raphael.animation({r:this.options.pointSize+3},25,"linear"),this.pointShrink=Raphael.animation({r:this.options.pointSize},25,"linear");if(this.options.hideHover!=="always")return this.hover=new t.Hover({parent:this.el}),this.on("hovermove",this.onHoverMove),this.on("hoverout",this.onHoverOut)},n.prototype.defaults={lineWidth:3,pointSize:4,lineColors:["#0b62a4","#7A92A3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],pointWidths:[1],pointStrokeColors:["#ffffff"],pointFillColors:[],smooth:!0,xLabels:"auto",xLabelFormat:null,xLabelMargin:50,continuousLine:!0,hideHover:!1},n.prototype.calc=function(){return this.calcPoints(),this.generatePaths()},n.prototype.calcPoints=function(){var e,t,n,r,i,s;i=this.data,s=[];for(n=0,r=i.length;n"+r.label+"",u=r.y;for(n=s=0,o=u.length;s\n "+this.options.labels[n]+":\n "+this.yLabelFormat(i)+"\n"}return[t,r._x,r._ymax]},n.prototype.generatePaths=function(){var e,n,r,i,s;return this.paths=function(){var o,u,f,l;l=[];for(r=o=0,u=this.options.ykeys.length;0<=u?ou;r=0<=u?++o:--o)s=this.options.smooth===!0||(f=this.options.ykeys[r],a.call(this.options.smooth,f)>=0),n=function(){var e,t,n,s;n=this.data,s=[];for(e=0,t=n.length;e1?l.push(t.Line.createPath(n,s,this.bottom)):l.push(null);return l}.call(this)},n.prototype.draw=function(){this.options.axes&&this.drawXAxis(),this.drawSeries();if(this.options.hideHover===!1)return this.displayHoverForRow(this.data.length-1)},n.prototype.drawXAxis=function(){var e,n,r,i,s,o,u,a,f,l=this;o=this.bottom+this.options.gridTextSize*1.25,i=null,e=function(e,t){var n,r;return n=l.r.text(l.transX(t),o,e).attr("font-size",l.options.gridTextSize).attr("fill",l.options.gridTextColor),r=n.getBBox(),(i==null||i>=r.x+r.width)&&r.x>=0&&r.x+r.width=0;t=o<=0?++i:--i)n=this.paths[t],n!==null&&this.r.path(n).attr("stroke",this.colorFor(r,t,"line")).attr("stroke-width",this.options.lineWidth);this.seriesPoints=function(){var e,n,r;r=[];for(t=e=0,n=this.options.ykeys.length;0<=n?en;t=0<=n?++e:--e)r.push([]);return r}.call(this),a=[];for(t=s=u=this.options.ykeys.length-1;u<=0?s<=0:s>=0;t=u<=0?++s:--s)a.push(function(){var n,i,s,o;s=this.data,o=[];for(n=0,i=s.length;n=i;t=0<=i?++n:--n)this.seriesPoints[t][this.prevHilight]&&this.seriesPoints[t][this.prevHilight].animate(this.pointShrink);if(e!==null&&this.prevHilight!==e)for(t=r=0,s=this.seriesPoints.length-1;0<=s?r<=s:r>=s;t=0<=s?++r:--r)this.seriesPoints[t][e]&&this.seriesPoints[t][e].animate(this.pointGrow);return this.prevHilight=e},n.prototype.strokeWidthForSeries=function(e){return this.options.pointWidths[e%this.options.pointWidths.length]},n.prototype.strokeForSeries=function(e){return this.options.pointStrokeColors[e%this.options.pointStrokeColors.length]},n.prototype.colorFor=function(e,t,n){return typeof this.options.lineColors=="function"?this.options.lineColors.call(this,e,t,n):n==="point"?this.options.pointFillColors[t%this.options.pointFillColors.length]||this.options.lineColors[t%this.options.lineColors.length]:this.options.lineColors[t%this.options.lineColors.length]},n}(t.Grid),t.labelSeries=function(n,r,i,s,o){var u,a,f,l,c,h,p,d,v,m,g;f=200*(r-n)/i,a=new Date(n),p=t.LABEL_SPECS[s];if(p===void 0){g=t.AUTO_LABEL_ORDER;for(v=0,m=g.length;v=h.span){p=h;break}}}p===void 0&&(p=t.LABEL_SPECS.second),o&&(p=e.extend({},p,{fmt:o})),u=p.start(a),c=[];while((d=u.getTime())<=r)d>=n&&c.push([p.fmt(u),d]),p.incr(u);return c},n=function(e){return{span:e*60*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())},incr:function(t){return t.setMinutes(t.getMinutes()+e)}}},r=function(e){return{span:e*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())+":"+t.pad2(e.getSeconds())},incr:function(t){return t.setSeconds(t.getSeconds()+e)}}},t.LABEL_SPECS={decade:{span:1728e8,start:function(e){return new Date(e.getFullYear()-e.getFullYear()%10,0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+10)}},year:{span:1728e7,start:function(e){return new Date(e.getFullYear(),0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+1)}},month:{span:24192e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),1)},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)},incr:function(e){return e.setMonth(e.getMonth()+1)}},day:{span:864e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate())},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)+"-"+t.pad2(e.getDate())},incr:function(e){return e.setDate(e.getDate()+1)}},hour:n(60),"30min":n(30),"15min":n(15),"10min":n(10),"5min":n(5),minute:n(1),"30sec":r(30),"15sec":r(15),"10sec":r(10),"5sec":r(5),second:r(1)},t.AUTO_LABEL_ORDER=["decade","year","month","day","hour","30min","15min","10min","5min","minute","30sec","15sec","10sec","5sec","second"],t.Area=function(e){function n(e){if(!(this instanceof t.Area))return new t.Area(e);this.cumulative=!0,n.__super__.constructor.call(this,e)}return o(n,e),n.prototype.calcPoints=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(r=0,i=s.length;r=0;e=i<=0?++r:--r)t=this.paths[e],t!==null&&(t+="L"+this.transX(this.xmax)+","+this.bottom+"L"+this.transX(this.xmin)+","+this.bottom+"Z",this.r.path(t).attr("fill",this.fillForSeries(e)).attr("stroke-width",0));return n.__super__.drawSeries.call(this)},n.prototype.fillForSeries=function(e){var t;return t=Raphael.rgb2hsl(this.colorFor(this.data[e],e,"line")),Raphael.hsl(t.h,Math.min(255,t.s*.75),Math.min(255,t.l*1.25))},n}(t.Line),t.Bar=function(n){function r(n){this.onHoverOut=u(this.onHoverOut,this),this.onHoverMove=u(this.onHoverMove,this);if(!(this instanceof t.Bar))return new t.Bar(n);r.__super__.constructor.call(this,e.extend({},n,{parseTime:!1}))}return o(r,n),r.prototype.init=function(){this.cumulative=this.options.stacked;if(this.options.hideHover!=="always")return this.hover=new t.Hover({parent:this.el}),this.on("hovermove",this.onHoverMove),this.on("hoverout",this.onHoverOut)},r.prototype.defaults={barSizeRatio:.75,barGap:3,barColors:["#0b62a4","#7a92a3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],xLabelMargin:50},r.prototype.calc=function(){var e;this.calcBars();if(this.options.hideHover===!1)return(e=this.hover).update.apply(e,this.hoverContentForRow(this.data.length-1))},r.prototype.calcBars=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(e=r=0,i=s.length;ru;e=0<=u?++o:--o)i=this.data[this.data.length-1-e],t=this.r.text(i._x,s,i.label).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor),n=t.getBBox(),(r==null||r>=n.x+n.width)&&n.x>=0&&n.x+n.width=0?this.transY(0):null,this.bars=function(){var u,d,v,m;v=this.data,m=[];for(r=u=0,d=v.length;u"+r.label+"",a=r.y;for(n=o=0,u=a.length;o\n "+this.options.labels[n]+":\n "+this.yLabelFormat(s)+"\n"}return i=this.left+(e+.5)*this.width/this.data.length,[t,i]},r}(t.Grid),t.Donut=function(){function n(n){this.select=u(this.select,this);if(!(this instanceof t.Donut))return new t.Donut(n);typeof n.element=="string"?this.el=e(document.getElementById(n.element)):this.el=e(n.element),this.options=e.extend({},this.defaults,n);if(this.el===null||this.el.length===0)throw new Error("Graph placeholder not found.");if(n.data===void 0||n.data.length===0)return;this.data=n.data,this.redraw()}return n.prototype.defaults={colors:["#0B62A4","#3980B5","#679DC6","#95BBD7","#B0CCE1","#095791","#095085","#083E67","#052C48","#042135"],backgroundColor:"#FFFFFF",formatter:t.commas},n.prototype.redraw=function(){var e,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x;this.el.empty(),this.r=new Raphael(this.el[0]),n=this.el.width()/2,r=this.el.height()/2,h=(Math.min(n,r)-10)/3,c=0,w=this.data;for(d=0,g=w.length;dMath.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)}return o(t,e),t.prototype.calcArcPoints=function(e){return[this.cx+e*this.sin_p0,this.cy+e*this.cos_p0,this.cx+e*this.sin_p1,this.cy+e*this.cos_p1]},t.prototype.calcSegment=function(e,t){var n,r,i,s,o,u,a,f,l,c;return l=this.calcArcPoints(e),n=l[0],i=l[1],r=l[2],s=l[3],c=this.calcArcPoints(t),o=c[0],a=c[1],u=c[2],f=c[3],"M"+n+","+i+("A"+e+","+e+",0,"+this.is_long+",0,"+r+","+s)+("L"+u+","+f)+("A"+t+","+t+",0,"+this.is_long+",1,"+o+","+a)+"Z"},t.prototype.calcArc=function(e){var t,n,r,i,s;return s=this.calcArcPoints(e),t=s[0],r=s[1],n=s[2],i=s[3],"M"+t+","+r+("A"+e+","+e+",0,"+this.is_long+",0,"+n+","+i)},t.prototype.render=function(e){var t=this;return this.arc=e.path(this.hilight).attr({stroke:this.color,"stroke-width":2,opacity:0}),this.seg=e.path(this.path).attr({fill:this.color,stroke:this.backgroundColor,"stroke-width":3}).hover(function(){return t.fire("hover",t)})},t.prototype.select=function(){if(!this.selected)return this.seg.animate({path:this.selectedPath},150,"<>"),this.arc.animate({opacity:1},150,"<>"),this.selected=!0},t.prototype.deselect=function(){if(this.selected)return this.seg.animate({path:this.path},150,"<>"),this.arc.animate({opacity:0},150,"<>"),this.selected=!1},t}(t.EventEmitter)}).call(this); \ No newline at end of file +(function(){var e,t,n,r,s=[].slice,o={}.hasOwnProperty,u=function(e,t){function r(){this.constructor=e}for(var n in t)o.call(t,n)&&(e[n]=t[n]);return r.prototype=t.prototype,e.prototype=new r,e.__super__=t.prototype,e},a=function(e,t){return function(){return e.apply(t,arguments)}},f=[].indexOf||function(e){for(var t=0,n=this.length;tn.length&&(r+=i.slice(n.length)),r):"-"},t.pad2=function(e){return(e<10?"0":"")+e},t.Grid=function(n){function r(t){var n=this;typeof t.element=="string"?this.el=e(document.getElementById(t.element)):this.el=e(t.element);if(this.el==null||this.el.length===0)throw new Error("Graph container element not found");this.el.css("position")==="static"&&this.el.css("position","relative"),this.options=e.extend({},this.gridDefaults,this.defaults||{},t);if(this.options.data===void 0||this.options.data.length===0)return;typeof this.options.units=="string"&&(this.options.postUnits=t.units),this.raphael=new Raphael(this.el[0]),this.elementWidth=null,this.elementHeight=null,this.dirty=!1,this.init&&this.init(),this.setData(this.options.data),this.el.bind("mousemove",function(e){var t;return t=n.el.offset(),n.fire("hovermove",e.pageX-t.left,e.pageY-t.top)}),this.el.bind("mouseout",function(e){return n.fire("hoverout")}),this.el.bind("touchstart touchmove touchend",function(e){var t,r;return r=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0],t=n.el.offset(),n.fire("hover",r.pageX-t.left,r.pageY-t.top),r}),this.postInit&&this.postInit()}return u(r,n),r.prototype.gridDefaults={dateFormat:null,axes:!0,grid:!0,gridLineColor:"#aaa",gridStrokeWidth:.5,gridTextColor:"#888",gridTextSize:12,hideHover:!1,yLabelFormat:null,numLines:5,padding:25,parseTime:!0,postUnits:"",preUnits:"",ymax:"auto",ymin:"auto 0",goals:[],goalStrokeWidth:1,goalLineColors:["#666633","#999966","#cc6666","#663333"],events:[],eventStrokeWidth:1,eventLineColors:["#005a04","#ccffbb","#3a5f0b","#005502"]},r.prototype.setData=function(e,n){var r,i,s,o,u,a,f,l,c,h,p,d;n==null&&(n=!0),h=this.cumulative?0:null,p=this.cumulative?0:null,this.options.goals.length>0&&(u=Math.min.apply(null,this.options.goals),o=Math.max.apply(null,this.options.goals),p=p!=null?Math.min(p,u):u,h=h!=null?Math.max(h,o):o),this.data=function(){var n,r,o;o=[];for(s=n=0,r=e.length;nt.x)-(t.x>e.x)})),this.xmin=this.data[0].x,this.xmax=this.data[this.data.length-1].x,this.events=[],this.options.parseTime&&this.options.events.length>0&&(this.events=function(){var e,n,i,s;i=this.options.events,s=[];for(e=0,n=i.length;e5?(this.ymax=parseInt(this.options.ymax.slice(5),10),h!=null&&(this.ymax=Math.max(h,this.ymax))):this.ymax=h!=null?h:0:this.ymax=parseInt(this.options.ymax,10):this.ymax=this.options.ymax,typeof this.options.ymin=="string"?this.options.ymin.slice(0,4)==="auto"?this.options.ymin.length>5?(this.ymin=parseInt(this.options.ymin.slice(5),10),p!=null&&(this.ymin=Math.min(p,this.ymin))):this.ymin=p!==null?p:0:this.ymin=parseInt(this.options.ymin,10):this.ymin=this.options.ymin,this.ymin===this.ymax&&(p&&(this.ymin-=1),this.ymax+=1),this.yInterval=(this.ymax-this.ymin)/(this.options.numLines-1),this.yInterval>0&&this.yInterval<1?this.precision=-Math.floor(Math.log(this.yInterval)/Math.log(10)):this.precision=0,this.dirty=!0;if(n)return this.redraw()},r.prototype._calc=function(){var e,t,n;n=this.el.width(),e=this.el.height();if(this.elementWidth!==n||this.elementHeight!==e||this.dirty){this.elementWidth=n,this.elementHeight=e,this.dirty=!1,this.left=this.options.padding,this.right=this.elementWidth-this.options.padding,this.top=this.options.padding,this.bottom=this.elementHeight-this.options.padding,this.options.axes&&(t=Math.max(this.measureText(this.yAxisFormat(this.ymin),this.options.gridTextSize).width,this.measureText(this.yAxisFormat(this.ymax),this.options.gridTextSize).width),this.left+=t,this.bottom-=1.5*this.options.gridTextSize),this.width=this.right-this.left,this.height=this.bottom-this.top,this.dx=this.width/(this.xmax-this.xmin),this.dy=this.height/(this.ymax-this.ymin);if(this.calc)return this.calc()}},r.prototype.transY=function(e){return this.bottom-(e-this.ymin)*this.dy},r.prototype.transX=function(e){return this.data.length===1?(this.left+this.right)/2:this.left+(e-this.xmin)*this.dx},r.prototype.redraw=function(){this.raphael.clear(),this._calc(),this.drawGrid(),this.drawGoals(),this.drawEvents();if(this.draw)return this.draw()},r.prototype.drawGoals=function(){var e,t,n,r,i,s;i=this.options.goals,s=[];for(t=n=0,r=i.length;n=t;n=s+=o)r=parseFloat(n.toFixed(this.precision)),i=this.transY(r),this.options.axes&&this.drawYAxisLabel(this.left-this.options.padding/2,i,this.yAxisFormat(r)),this.options.grid?u.push(this.drawGridLine("M"+this.left+","+i+"H"+(this.left+this.width))):u.push(void 0);return u},r.prototype.measureText=function(e,t){var n,r;return t==null&&(t=12),r=this.raphael.text(100,100,e).attr("font-size",t),n=r.getBBox(),r.remove(),n},r.prototype.yAxisFormat=function(e){return this.yLabelFormat(e)},r.prototype.yLabelFormat=function(e){return typeof this.options.yLabelFormat=="function"?this.options.yLabelFormat(e):""+this.options.preUnits+t.commas(e)+this.options.postUnits},r.prototype.updateHover=function(e,t){var n,r;n=this.hitTest(e,t);if(n!=null)return(r=this.hover).update.apply(r,n)},r.prototype.drawGoal=function(e){return this.raphael.path(e).attr("stroke",this.options.goalLineColors[i%this.options.goalLineColors.length]).attr("stroke-width",this.options.goalStrokeWidth)},r.prototype.drawEvent=function(e){return this.raphael.path(e).attr("stroke",this.options.eventLineColors[i%this.options.eventLineColors.length]).attr("stroke-width",this.options.eventStrokeWidth)},r.prototype.drawYAxisLabel=function(e,t,n){return this.raphael.text(e,t,n).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor).attr("text-anchor","end")},r.prototype.drawGridLine=function(e){return this.raphael.path(e).attr("stroke",this.options.gridLineColor).attr("stroke-width",this.options.gridStrokeWidth)},r}(t.EventEmitter),t.parseDate=function(e){var t,n,r,i,s,o,u,a,f,l,c;return typeof e=="number"?e:(n=e.match(/^(\d+) Q(\d)$/),i=e.match(/^(\d+)-(\d+)$/),s=e.match(/^(\d+)-(\d+)-(\d+)$/),u=e.match(/^(\d+) W(\d+)$/),a=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+)(Z|([+-])(\d\d):?(\d\d))?$/),f=e.match(/^(\d+)-(\d+)-(\d+)[ T](\d+):(\d+):(\d+(\.\d+)?)(Z|([+-])(\d\d):?(\d\d))?$/),n?(new Date(parseInt(n[1],10),parseInt(n[2],10)*3-1,1)).getTime():i?(new Date(parseInt(i[1],10),parseInt(i[2],10)-1,1)).getTime():s?(new Date(parseInt(s[1],10),parseInt(s[2],10)-1,parseInt(s[3],10))).getTime():u?(l=new Date(parseInt(u[1],10),0,1),l.getDay()!==4&&l.setMonth(0,1+(4-l.getDay()+7)%7),l.getTime()+parseInt(u[2],10)*6048e5):a?a[6]?(o=0,a[6]!=="Z"&&(o=parseInt(a[8],10)*60+parseInt(a[9],10),a[7]==="+"&&(o=0-o)),Date.UTC(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10)+o)):(new Date(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10))).getTime():f?(c=parseFloat(f[6]),t=Math.floor(c),r=Math.round((c-t)*1e3),f[8]?(o=0,f[8]!=="Z"&&(o=parseInt(f[10],10)*60+parseInt(f[11],10),f[9]==="+"&&(o=0-o)),Date.UTC(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10)+o,t,r)):(new Date(parseInt(f[1],10),parseInt(f[2],10)-1,parseInt(f[3],10),parseInt(f[4],10),parseInt(f[5],10),t,r)).getTime()):(new Date(parseInt(e,10),0,1)).getTime())},t.Hover=function(){function n(n){n==null&&(n={}),this.options=e.extend({},t.Hover.defaults,n),this.el=e("
"),this.el.hide(),this.options.parent.append(this.el)}return n.defaults={"class":"morris-hover morris-default-style"},n.prototype.update=function(e,t,n){return this.html(e),this.show(),this.moveTo(t,n)},n.prototype.html=function(e){return this.el.html(e)},n.prototype.moveTo=function(e,t){var n,r,i,s,o,u;return o=this.options.parent.innerWidth(),s=this.options.parent.innerHeight(),r=this.el.outerWidth(),n=this.el.outerHeight(),i=Math.min(Math.max(0,e-r/2),o-r),t!=null?(u=t-n-10,u<0&&(u=t+10,u+n>s&&(u=s/2-n/2))):u=s/2-n/2,this.el.css({left:i+"px",top:u+"px"})},n.prototype.show=function(){return this.el.show()},n.prototype.hide=function(){return this.el.hide()},n}(),t.Line=function(e){function n(e){this.hilight=a(this.hilight,this),this.onHoverOut=a(this.onHoverOut,this),this.onHoverMove=a(this.onHoverMove,this);if(!(this instanceof t.Line))return new t.Line(e);n.__super__.constructor.call(this,e)}return u(n,e),n.prototype.init=function(){this.pointGrow=Raphael.animation({r:this.options.pointSize+3},25,"linear"),this.pointShrink=Raphael.animation({r:this.options.pointSize},25,"linear");if(this.options.hideHover!=="always")return this.hover=new t.Hover({parent:this.el}),this.on("hovermove",this.onHoverMove),this.on("hoverout",this.onHoverOut)},n.prototype.defaults={lineWidth:3,pointSize:4,lineColors:["#0b62a4","#7A92A3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],pointWidths:[1],pointStrokeColors:["#ffffff"],pointFillColors:[],smooth:!0,xLabels:"auto",xLabelFormat:null,xLabelMargin:50,continuousLine:!0,hideHover:!1},n.prototype.calc=function(){return this.calcPoints(),this.generatePaths()},n.prototype.calcPoints=function(){var e,t,n,r,i,s;i=this.data,s=[];for(n=0,r=i.length;n"+r.label+"",u=r.y;for(n=s=0,o=u.length;s\n "+this.options.labels[n]+":\n "+this.yLabelFormat(i)+"\n"}return[t,r._x,r._ymax]},n.prototype.generatePaths=function(){var e,n,r,i,s;return this.paths=function(){var o,u,a,l;l=[];for(r=o=0,u=this.options.ykeys.length;0<=u?ou;r=0<=u?++o:--o)s=this.options.smooth===!0||(a=this.options.ykeys[r],f.call(this.options.smooth,a)>=0),n=function(){var e,t,n,s;n=this.data,s=[];for(e=0,t=n.length;e1?l.push(t.Line.createPath(n,s,this.bottom)):l.push(null);return l}.call(this)},n.prototype.draw=function(){this.options.axes&&this.drawXAxis(),this.drawSeries();if(this.options.hideHover===!1)return this.displayHoverForRow(this.data.length-1)},n.prototype.drawXAxis=function(){var e,n,r,i,s,o,u,a,f,l=this;o=this.bottom+this.options.gridTextSize*1.25,i=null,e=function(e,t){var n,r;return n=l.drawXAxisLabel(l.transX(t),o,e),r=n.getBBox(),(i==null||i>=r.x+r.width)&&r.x>=0&&r.x+r.width=0;t=o<=0?++i:--i)n=this.paths[t],n!==null&&this.drawLinePath(n,this.colorFor(r,t,"line"));this.seriesPoints=function(){var e,n,r;r=[];for(t=e=0,n=this.options.ykeys.length;0<=n?en;t=0<=n?++e:--e)r.push([]);return r}.call(this),a=[];for(t=s=u=this.options.ykeys.length-1;u<=0?s<=0:s>=0;t=u<=0?++s:--s)a.push(function(){var n,i,s,o;s=this.data,o=[];for(n=0,i=s.length;n=i;t=0<=i?++n:--n)this.seriesPoints[t][this.prevHilight]&&this.seriesPoints[t][this.prevHilight].animate(this.pointShrink);if(e!==null&&this.prevHilight!==e)for(t=r=0,s=this.seriesPoints.length-1;0<=s?r<=s:r>=s;t=0<=s?++r:--r)this.seriesPoints[t][e]&&this.seriesPoints[t][e].animate(this.pointGrow);return this.prevHilight=e},n.prototype.colorFor=function(e,t,n){return typeof this.options.lineColors=="function"?this.options.lineColors.call(this,e,t,n):n==="point"?this.options.pointFillColors[t%this.options.pointFillColors.length]||this.options.lineColors[t%this.options.lineColors.length]:this.options.lineColors[t%this.options.lineColors.length]},n.prototype.drawXAxisLabel=function(e,t,n){return this.raphael.text(e,t,n).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor)},n.prototype.drawLinePath=function(e,t){return this.raphael.path(e).attr("stroke",t).attr("stroke-width",this.options.lineWidth)},n.prototype.drawLinePoint=function(e,t,n,r,i){return this.raphael.circle(e,t,n).attr("fill",r).attr("stroke-width",this.strokeWidthForSeries(i)).attr("stroke",this.strokeForSeries(i))},n.prototype.strokeWidthForSeries=function(e){return this.options.pointWidths[e%this.options.pointWidths.length]},n.prototype.strokeForSeries=function(e){return this.options.pointStrokeColors[e%this.options.pointStrokeColors.length]},n}(t.Grid),t.labelSeries=function(n,r,i,s,o){var u,a,f,l,c,h,p,d,v,m,g;f=200*(r-n)/i,a=new Date(n),p=t.LABEL_SPECS[s];if(p===void 0){g=t.AUTO_LABEL_ORDER;for(v=0,m=g.length;v=h.span){p=h;break}}}p===void 0&&(p=t.LABEL_SPECS.second),o&&(p=e.extend({},p,{fmt:o})),u=p.start(a),c=[];while((d=u.getTime())<=r)d>=n&&c.push([p.fmt(u),d]),p.incr(u);return c},n=function(e){return{span:e*60*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())},incr:function(t){return t.setMinutes(t.getMinutes()+e)}}},r=function(e){return{span:e*1e3,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes())},fmt:function(e){return""+t.pad2(e.getHours())+":"+t.pad2(e.getMinutes())+":"+t.pad2(e.getSeconds())},incr:function(t){return t.setSeconds(t.getSeconds()+e)}}},t.LABEL_SPECS={decade:{span:1728e8,start:function(e){return new Date(e.getFullYear()-e.getFullYear()%10,0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+10)}},year:{span:1728e7,start:function(e){return new Date(e.getFullYear(),0,1)},fmt:function(e){return""+e.getFullYear()},incr:function(e){return e.setFullYear(e.getFullYear()+1)}},month:{span:24192e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),1)},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)},incr:function(e){return e.setMonth(e.getMonth()+1)}},day:{span:864e5,start:function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate())},fmt:function(e){return""+e.getFullYear()+"-"+t.pad2(e.getMonth()+1)+"-"+t.pad2(e.getDate())},incr:function(e){return e.setDate(e.getDate()+1)}},hour:n(60),"30min":n(30),"15min":n(15),"10min":n(10),"5min":n(5),minute:n(1),"30sec":r(30),"15sec":r(15),"10sec":r(10),"5sec":r(5),second:r(1)},t.AUTO_LABEL_ORDER=["decade","year","month","day","hour","30min","15min","10min","5min","minute","30sec","15sec","10sec","5sec","second"],t.Area=function(e){function n(e){if(!(this instanceof t.Area))return new t.Area(e);this.cumulative=!0,n.__super__.constructor.call(this,e)}return u(n,e),n.prototype.calcPoints=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(r=0,i=s.length;r=0;e=i<=0?++r:--r)t=this.paths[e],t!==null&&(t+="L"+this.transX(this.xmax)+","+this.bottom+"L"+this.transX(this.xmin)+","+this.bottom+"Z",this.drawFilledPath(t,this.fillForSeries(e)));return n.__super__.drawSeries.call(this)},n.prototype.fillForSeries=function(e){var t;return t=Raphael.rgb2hsl(this.colorFor(this.data[e],e,"line")),Raphael.hsl(t.h,Math.min(255,t.s*.75),Math.min(255,t.l*1.25))},n.prototype.drawFilledPath=function(e,t){return this.raphael.path(e).attr("fill",t).attr("stroke-width",0)},n}(t.Line),t.Bar=function(n){function r(n){this.onHoverOut=a(this.onHoverOut,this),this.onHoverMove=a(this.onHoverMove,this);if(!(this instanceof t.Bar))return new t.Bar(n);r.__super__.constructor.call(this,e.extend({},n,{parseTime:!1}))}return u(r,n),r.prototype.init=function(){this.cumulative=this.options.stacked;if(this.options.hideHover!=="always")return this.hover=new t.Hover({parent:this.el}),this.on("hovermove",this.onHoverMove),this.on("hoverout",this.onHoverOut)},r.prototype.defaults={barSizeRatio:.75,barGap:3,barColors:["#0b62a4","#7a92a3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],xLabelMargin:50},r.prototype.calc=function(){var e;this.calcBars();if(this.options.hideHover===!1)return(e=this.hover).update.apply(e,this.hoverContentForRow(this.data.length-1))},r.prototype.calcBars=function(){var e,t,n,r,i,s,o;s=this.data,o=[];for(e=r=0,i=s.length;ru;e=0<=u?++o:--o)i=this.data[this.data.length-1-e],t=this.drawXAxisLabel(i._x,s,i.label),n=t.getBBox(),(r==null||r>=n.x+n.width)&&n.x>=0&&n.x+n.width=0?this.transY(0):null,this.bars=function(){var u,d,v,m;v=this.data,m=[];for(r=u=0,d=v.length;u"+r.label+"",a=r.y;for(n=o=0,u=a.length;o\n "+this.options.labels[n]+":\n "+this.yLabelFormat(s)+"\n"}return i=this.left+(e+.5)*this.width/this.data.length,[t,i]},r.prototype.drawXAxisLabel=function(e,t,n){var r;return r=this.raphael.text(e,t,n).attr("font-size",this.options.gridTextSize).attr("fill",this.options.gridTextColor)},r.prototype.drawBar=function(e,t,n,r,i){return this.raphael.rect(e,t,n,r).attr("fill",i).attr("stroke-width",0)},r}(t.Grid),t.Donut=function(){function n(n){this.select=a(this.select,this);if(!(this instanceof t.Donut))return new t.Donut(n);typeof n.element=="string"?this.el=e(document.getElementById(n.element)):this.el=e(n.element),this.options=e.extend({},this.defaults,n);if(this.el===null||this.el.length===0)throw new Error("Graph placeholder not found.");if(n.data===void 0||n.data.length===0)return;this.data=n.data,this.redraw()}return n.prototype.defaults={colors:["#0B62A4","#3980B5","#679DC6","#95BBD7","#B0CCE1","#095791","#095085","#083E67","#052C48","#042135"],backgroundColor:"#FFFFFF",formatter:t.commas},n.prototype.redraw=function(){var e,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x;this.el.empty(),this.raphael=new Raphael(this.el[0]),n=this.el.width()/2,r=this.el.height()/2,h=(Math.min(n,r)-10)/3,c=0,w=this.data;for(d=0,g=w.length;dMath.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)}return u(t,e),t.prototype.calcArcPoints=function(e){return[this.cx+e*this.sin_p0,this.cy+e*this.cos_p0,this.cx+e*this.sin_p1,this.cy+e*this.cos_p1]},t.prototype.calcSegment=function(e,t){var n,r,i,s,o,u,a,f,l,c;return l=this.calcArcPoints(e),n=l[0],i=l[1],r=l[2],s=l[3],c=this.calcArcPoints(t),o=c[0],a=c[1],u=c[2],f=c[3],"M"+n+","+i+("A"+e+","+e+",0,"+this.is_long+",0,"+r+","+s)+("L"+u+","+f)+("A"+t+","+t+",0,"+this.is_long+",1,"+o+","+a)+"Z"},t.prototype.calcArc=function(e){var t,n,r,i,s;return s=this.calcArcPoints(e),t=s[0],r=s[1],n=s[2],i=s[3],"M"+t+","+r+("A"+e+","+e+",0,"+this.is_long+",0,"+n+","+i)},t.prototype.render=function(){var e=this;return this.arc=this.drawDonutArc(this.hilight,this.color),this.seg=this.drawDonutSegment(this.path,this.color,this.backgroundColor,function(){return e.fire("hover",e)})},t.prototype.drawDonutArc=function(e,t){return this.raphael.path(e).attr({stroke:t,"stroke-width":2,opacity:0})},t.prototype.drawDonutSegment=function(e,t,n,r){return this.raphael.path(e).attr({fill:t,stroke:n,"stroke-width":3}).hover(r)},t.prototype.select=function(){if(!this.selected)return this.seg.animate({path:this.selectedPath},150,"<>"),this.arc.animate({opacity:1},150,"<>"),this.selected=!0},t.prototype.deselect=function(){if(this.selected)return this.seg.animate({path:this.path},150,"<>"),this.arc.animate({opacity:0},150,"<>"),this.selected=!1},t}(t.EventEmitter)}).call(this); \ No newline at end of file diff --git a/spec/lib/area/area_spec.coffee b/spec/lib/area/area_spec.coffee new file mode 100644 index 0000000..5d3f38a --- /dev/null +++ b/spec/lib/area/area_spec.coffee @@ -0,0 +1,47 @@ +describe 'Morris.Area', -> + + describe 'svg structure', -> + defaults = + element: 'graph' + data: [{x: '2012 Q1', y: 1}, {x: '2012 Q2', y: 1}] + lineColors: [ '#0b62a4', '#7a92a3'] + gridLineColor: '#aaa' + xkey: 'x' + ykeys: ['y'] + labels: ['Y'] + + it 'should contain a line path for each line', -> + chart = Morris.Area $.extend {}, defaults + $('#graph').find("path[stroke='#0b62a4']").size().should.equal 1 + + it 'should contain a path with stroke-width 0 for each line', -> + chart = Morris.Area $.extend {}, defaults + $('#graph').find("path[stroke='#0b62a4']").size().should.equal 1 + + it 'should contain 5 grid lines', -> + chart = Morris.Area $.extend {}, defaults + $('#graph').find("path[stroke='#aaaaaa']").size().should.equal 5 + + it 'should contain 9 text elements', -> + chart = Morris.Area $.extend {}, defaults + $('#graph').find("text").size().should.equal 9 + + describe 'svg attributes', -> + defaults = + element: 'graph' + data: [{x: '2012 Q1', y: 1}, {x: '2012 Q2', y: 1}] + xkey: 'x' + ykeys: ['y'] + labels: ['Y'] + lineColors: [ '#0b62a4', '#7a92a3'] + lineWidth: 3 + pointWidths: [5] + pointStrokeColors: ['#ffffff'] + gridLineColor: '#aaa' + gridStrokeWidth: 0.5 + gridTextColor: '#888' + gridTextSize: 12 + + it 'should have a line with the fill of a modified line color', -> + chart = Morris.Area $.extend {}, defaults + $('#graph').find("path[fill='#2577b5']").size().should.equal 1 diff --git a/spec/lib/bar/bar_spec.coffee b/spec/lib/bar/bar_spec.coffee new file mode 100644 index 0000000..cfa2936 --- /dev/null +++ b/spec/lib/bar/bar_spec.coffee @@ -0,0 +1,50 @@ +describe 'Morris.Bar', -> + + describe 'svg structure', -> + defaults = + element: 'graph' + data: [{x: 'foo', y: 2, z: 3}, {x: 'bar', y: 4, z: 6}] + xkey: 'x' + ykeys: ['y', 'z'] + labels: ['Y', 'Z'] + + it 'should contain a rect for each bar', -> + chart = Morris.Bar $.extend {}, defaults + $('#graph').find("rect").size().should.equal 4 + + it 'should contain 5 grid lines', -> + chart = Morris.Bar $.extend {}, defaults + $('#graph').find("path").size().should.equal 5 + + it 'should contain 7 text elements', -> + chart = Morris.Bar $.extend {}, defaults + $('#graph').find("text").size().should.equal 7 + + describe 'svg attributes', -> + defaults = + element: 'graph' + data: [{x: 'foo', y: 2, z: 3}, {x: 'bar', y: 4, z: 6}] + xkey: 'x' + ykeys: ['y', 'z'] + labels: ['Y', 'Z'] + barColors: [ '#0b62a4', '#7a92a3'] + gridLineColor: '#aaa' + gridStrokeWidth: 0.5 + gridTextColor: '#888' + gridTextSize: 12 + + it 'should have a bar with the first default color', -> + chart = Morris.Bar $.extend {}, defaults + $('#graph').find("rect[fill='#0b62a4']").size().should.equal 2 + + it 'should have a bar with stroke width 0', -> + chart = Morris.Bar $.extend {}, defaults + $('#graph').find("rect[stroke-width='0']").size().should.equal 4 + + it 'should have text with configured fill color', -> + chart = Morris.Bar $.extend {}, defaults + $('#graph').find("text[fill='#888888']").size().should.equal 7 + + it 'should have text with configured font size', -> + chart = Morris.Bar $.extend {}, defaults + $('#graph').find("text[font-size='12px']").size().should.equal 7 diff --git a/spec/lib/bar/colours.coffee b/spec/lib/bar/colours.coffee index a061ef6..ebe5469 100644 --- a/spec/lib/bar/colours.coffee +++ b/spec/lib/bar/colours.coffee @@ -33,4 +33,4 @@ describe 'Morris.Bar#colorFor', -> stub.should.have.been.calledWith( {x:0, y:3, label:'foo'}, {index:1, key:'z', label:'Z'}, - 'hover') \ No newline at end of file + 'hover') diff --git a/spec/lib/donut/donut_spec.coffee b/spec/lib/donut/donut_spec.coffee new file mode 100644 index 0000000..92f0c2e --- /dev/null +++ b/spec/lib/donut/donut_spec.coffee @@ -0,0 +1,61 @@ +describe 'Morris.Donut', -> + + describe 'svg structure', -> + defaults = + element: 'graph' + data: [ {label: 'Jam', value: 25 }, + {label: 'Frosted', value: 40 }, + {label: 'Custard', value: 25 }, + {label: 'Sugar', value: 10 } ] + formatter: (y) -> "#{y}%" + + it 'should contain 2 paths for each segment', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("path").size().should.equal 8 + + it 'should contain 2 text elements for the label', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("text").size().should.equal 2 + + describe 'svg attributes', -> + defaults = + defaults = + element: 'graph' + data: [ {label: 'Jam', value: 25 }, + {label: 'Frosted', value: 40 }, + {label: 'Custard', value: 25 }, + {label: 'Sugar', value: 10 } ] + formatter: (y) -> "#{y}%" + colors: [ '#0B62A4', '#3980B5', '#679DC6', '#95BBD7'] + + it 'should have a label with font size 15', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("text[font-size='15px']").size().should.equal 1 + + it 'should have a label with font size 14', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("text[font-size='14px']").size().should.equal 1 + + it 'should have a label with font-weight 800', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("text[font-weight='800']").size().should.equal 1 + + it 'should have 1 paths with fill of first color', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("path[fill='#0b62a4']").size().should.equal 1 + + it 'should have 1 paths with stroke of first color', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("path[stroke='#0b62a4']").size().should.equal 1 + + it 'should have a path with white stroke', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("path[stroke='#ffffff']").size().should.equal 4 + + it 'should have a path with stroke-width 3', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("path[stroke-width='3']").size().should.equal 4 + + it 'should have a path with stroke-width 2', -> + chart = Morris.Donut $.extend {}, defaults + $('#graph').find("path[stroke-width='2']").size().should.equal 4 diff --git a/spec/lib/line/line_spec.coffee b/spec/lib/line/line_spec.coffee index b1c4b72..f0accfe 100644 --- a/spec/lib/line/line_spec.coffee +++ b/spec/lib/line/line_spec.coffee @@ -140,3 +140,68 @@ describe 'Morris.Line', -> testData = [{x: 0, y: null}, {x: 10, y: 10}, {x: 20, y: 0}, {x: 30, y: 10}, {x: 40, y: null}] path = Morris.Line.createPath(testData, true, 20) path.should.equal 'M10,10C12.5,7.5,17.5,0,20,0C22.5,0,27.5,7.5,30,10' + + describe 'svg structure', -> + defaults = + element: 'graph' + data: [{x: '2012 Q1', y: 1}, {x: '2012 Q2', y: 1}] + lineColors: [ '#0b62a4', '#7a92a3'] + xkey: 'x' + ykeys: ['y'] + labels: ['dontcare'] + + it 'should contain a path that represents the line', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("path[stroke='#0b62a4']").size().should.equal 1 + + it 'should contain a circle for each data point', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("circle").size().should.equal 2 + + it 'should contain 5 grid lines', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("path[stroke='#aaaaaa']").size().should.equal 5 + + it 'should contain 9 text elements', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("text").size().should.equal 9 + + describe 'svg attributes', -> + defaults = + element: 'graph' + data: [{x: '2012 Q1', y: 1}, {x: '2012 Q2', y: 1}] + xkey: 'x' + ykeys: ['y', 'z'] + labels: ['Y', 'Z'] + lineColors: [ '#0b62a4', '#7a92a3'] + lineWidth: 3 + pointWidths: [5] + pointStrokeColors: ['#ffffff'] + gridLineColor: '#aaa' + gridStrokeWidth: 0.5 + gridTextColor: '#888' + gridTextSize: 12 + + it 'should have circles with configured fill color', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("circle[fill='#0b62a4']").size().should.equal 2 + + it 'should have circles with configured stroke width', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("circle[stroke-width='5']").size().should.equal 2 + + it 'should have circles with configured stroke color', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("circle[stroke='#ffffff']").size().should.equal 2 + + it 'should have line with configured line width', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("path[stroke-width='3']").size().should.equal 1 + + it 'should have text with configured font size', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("text[font-size='12px']").size().should.equal 9 + + it 'should have text with configured font size', -> + chart = Morris.Line $.extend {}, defaults + $('#graph').find("text[fill='#888888']").size().should.equal 9