Merge branch 'wrap_raphael_add_classes' of https://github.com/chriserin/morris.js into chriserin-wrap_raphael_add_classes

Conflicts:
	lib/morris.donut.coffee
This commit is contained in:
Olly Smith 2013-01-24 15:48:39 -08:00
commit cd5129c489
13 changed files with 416 additions and 97 deletions

View File

@ -15,6 +15,7 @@ module.exports = function (grunt) {
concat: { concat: {
'build/morris.coffee': [ 'build/morris.coffee': [
'lib/morris.coffee', 'lib/morris.coffee',
'lib/morris.svg.coffee',
'lib/morris.grid.coffee', 'lib/morris.grid.coffee',
'lib/morris.hover.coffee', 'lib/morris.hover.coffee',
'lib/morris.line.coffee', 'lib/morris.line.coffee',

View File

@ -26,9 +26,7 @@ class Morris.Area extends Morris.Line
path = @paths[i] path = @paths[i]
if path isnt null if path isnt null
path = path + "L#{@transX(@xmax)},#{@bottom}L#{@transX(@xmin)},#{@bottom}Z" path = path + "L#{@transX(@xmax)},#{@bottom}L#{@transX(@xmin)},#{@bottom}Z"
@r.path(path) @drawFilledPath(path, @fillForSeries(i))
.attr('fill', @fillForSeries(i))
.attr('stroke-width', 0)
super() super()
fillForSeries: (i) -> fillForSeries: (i) ->
@ -37,3 +35,8 @@ class Morris.Area extends Morris.Line
color.h, color.h,
Math.min(255, color.s * 0.75), Math.min(255, color.s * 0.75),
Math.min(255, color.l * 1.25)) Math.min(255, color.l * 1.25))
drawFilledPath: (path, fill) ->
@raphael.path(path)
.attr('fill', fill)
.attr('stroke-width', 0)

View File

@ -59,9 +59,7 @@ class Morris.Bar extends Morris.Grid
prevLabelMargin = null prevLabelMargin = null
for i in [0...@data.length] for i in [0...@data.length]
row = @data[@data.length - 1 - i] row = @data[@data.length - 1 - i]
label = @r.text(row._x, ypos, row.label) label = @drawXAxisLabel(row._x, ypos, row.label)
.attr('font-size', @options.gridTextSize)
.attr('fill', @options.gridTextColor)
labelBox = label.getBBox() labelBox = label.getBBox()
# ensure a minimum of `xLabelMargin` pixels between labels, and ensure # ensure a minimum of `xLabelMargin` pixels between labels, and ensure
# labels don't overflow the container # labels don't overflow the container
@ -96,9 +94,7 @@ class Morris.Bar extends Morris.Grid
size = bottom - top size = bottom - top
top -= lastTop if @options.stacked top -= lastTop if @options.stacked
@r.rect(left, top, barWidth, size) @drawBar(left, top, barWidth, size, @colorFor(row, sidx, 'bar'))
.attr('fill', @colorFor(row, sidx, 'bar'))
.attr('stroke-width', 0)
lastTop += size lastTop += size
else else
@ -156,3 +152,13 @@ class Morris.Bar extends Morris.Grid
""" """
x = @left + (index + 0.5) * @width / @data.length x = @left + (index + 0.5) * @width / @data.length
[content, x] [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)

View File

@ -55,7 +55,7 @@ class Morris.Donut
redraw: -> redraw: ->
@el.empty() @el.empty()
@r = new Raphael(@el[0]) @raphael = new Raphael(@el[0])
cx = @el.width() / 2 cx = @el.width() / 2
cy = @el.height() / 2 cy = @el.height() / 2
@ -72,14 +72,14 @@ class Morris.Donut
@segments = [] @segments = []
for d in @data for d in @data
next = last + min + C * (d.value / total) 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 = new Morris.DonutSegment(cx, cy, w*2, w, last, next, @options.colors[idx % @options.colors.length], @options.backgroundColor, d, @raphael)
seg.render @r seg.render()
@segments.push seg @segments.push seg
seg.on 'hover', @select seg.on 'hover', @select
last = next last = next
idx += 1 idx += 1
@text1 = @r.text(cx, cy - 10, '').attr('font-size': 15, 'font-weight': 800) @text1 = @drawEmptyDonutLabel(cx, cy - 10, 15, 800)
@text2 = @r.text(cx, cy + 10, '').attr('font-size': 14) @text2 = @drawEmptyDonutLabel(cx, cy + 10, 14)
max_value = Math.max.apply(null, d.value for d in @data) max_value = Math.max.apply(null, d.value for d in @data)
idx = 0 idx = 0
for d in @data for d in @data
@ -110,12 +110,17 @@ class Morris.Donut
text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height) text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height)
@text2.attr(transform: "S#{text2scale},#{text2scale},#{text2bbox.x + text2bbox.width / 2},#{text2bbox.y}") @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. # A segment within a donut chart.
# #
# @private # @private
class Morris.DonutSegment extends Morris.EventEmitter 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) @sin_p0 = Math.sin(p0)
@cos_p0 = Math.cos(p0) @cos_p0 = Math.cos(p0)
@sin_p1 = Math.sin(p1) @sin_p1 = Math.sin(p1)
@ -148,11 +153,18 @@ class Morris.DonutSegment extends Morris.EventEmitter
"M#{ix0},#{iy0}" + "M#{ix0},#{iy0}" +
"A#{r},#{r},0,#{@is_long},0,#{ix1},#{iy1}") "A#{r},#{r},0,#{@is_long},0,#{ix1},#{iy1}")
render: (r) -> render: ->
@arc = r.path(@hilight).attr(stroke: @color, 'stroke-width': 2, opacity: 0) @arc = @drawDonutArc(@hilight, @color)
@seg = r.path(@path) @seg = @drawDonutSegment(@path, @color, @backgroundColor, => @fire('hover', @))
.attr(fill: @color, stroke: @backgroundColor, 'stroke-width': 3)
.hover(=> @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: => select: =>
unless @selected unless @selected

View File

@ -26,7 +26,7 @@ class Morris.Grid extends Morris.EventEmitter
@options.postUnits = options.units @options.postUnits = options.units
# the raphael drawing instance # the raphael drawing instance
@r = new Raphael(@el[0]) @raphael = new Raphael(@el[0])
# some redraw stuff # some redraw stuff
@elementWidth = null @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 # If you need to re-size your charts, call this method after changing the
# size of the container element. # size of the container element.
redraw: -> redraw: ->
@r.clear() @raphael.clear()
@_calc() @_calc()
@drawGrid() @drawGrid()
@drawGoals() @drawGoals()
@ -238,16 +238,12 @@ class Morris.Grid extends Morris.EventEmitter
# #
drawGoals: -> drawGoals: ->
for goal, i in @options.goals for goal, i in @options.goals
@r.path("M#{@left},#{@transY(goal)}H#{@left + @width}") @drawGoal("M#{@left},#{@transY(goal)}H#{@left + @width}")
.attr('stroke', @options.goalLineColors[i % @options.goalLineColors.length])
.attr('stroke-width', @options.goalStrokeWidth)
# draw events vertical lines # draw events vertical lines
drawEvents: -> drawEvents: ->
for event, i in @events for event, i in @events
@r.path("M#{@transX(event)},#{@bottom}V#{@top}") @drawEvent("M#{@transX(event)},#{@bottom}V#{@top}")
.attr('stroke', @options.eventLineColors[i % @options.eventLineColors.length])
.attr('stroke-width', @options.eventStrokeWidth)
# draw y axis labels, horizontal lines # draw y axis labels, horizontal lines
# #
@ -259,19 +255,14 @@ class Morris.Grid extends Morris.EventEmitter
v = parseFloat(lineY.toFixed(@precision)) v = parseFloat(lineY.toFixed(@precision))
y = @transY(v) y = @transY(v)
if @options.axes if @options.axes
@r.text(@left - @options.padding / 2, y, @yAxisFormat(v)) @drawYAxisLabel(@left - @options.padding / 2, y, @yAxisFormat(v))
.attr('font-size', @options.gridTextSize)
.attr('fill', @options.gridTextColor)
.attr('text-anchor', 'end')
if @options.grid if @options.grid
@r.path("M#{@left},#{y}H#{@left + @width}") @drawGridLine("M#{@left},#{y}H#{@left + @width}")
.attr('stroke', @options.gridLineColor)
.attr('stroke-width', @options.gridStrokeWidth)
# @private # @private
# #
measureText: (text, fontSize = 12) -> 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() ret = tt.getBBox()
tt.remove() tt.remove()
ret ret
@ -293,6 +284,27 @@ class Morris.Grid extends Morris.EventEmitter
if hit? if hit?
@hover.update(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 # Parse a date into a javascript timestamp
# #
# #

View File

@ -138,9 +138,7 @@ class Morris.Line extends Morris.Grid
ypos = @bottom + @options.gridTextSize * 1.25 ypos = @bottom + @options.gridTextSize * 1.25
prevLabelMargin = null prevLabelMargin = null
drawLabel = (labelText, xpos) => drawLabel = (labelText, xpos) =>
label = @r.text(@transX(xpos), ypos, labelText) label = @drawXAxisLabel(@transX(xpos), ypos, labelText)
.attr('font-size', @options.gridTextSize)
.attr('fill', @options.gridTextColor)
labelBox = label.getBBox() labelBox = label.getBBox()
# ensure a minimum of `xLabelMargin` pixels between labels, and ensure # ensure a minimum of `xLabelMargin` pixels between labels, and ensure
# labels don't overflow the container # labels don't overflow the container
@ -170,17 +168,12 @@ class Morris.Line extends Morris.Grid
for i in [@options.ykeys.length-1..0] for i in [@options.ykeys.length-1..0]
path = @paths[i] path = @paths[i]
if path isnt null if path isnt null
@r.path(path) @drawLinePath(path, @colorFor(row, i, 'line')) #row isn't available here?
.attr('stroke', @colorFor(row, i, 'line'))
.attr('stroke-width', @options.lineWidth)
@seriesPoints = ([] for i in [0...@options.ykeys.length]) @seriesPoints = ([] for i in [0...@options.ykeys.length])
for i in [@options.ykeys.length-1..0] for i in [@options.ykeys.length-1..0]
for row in @data for row in @data
if row._y[i]? if row._y[i]?
circle = @r.circle(row._x, row._y[i], @options.pointSize) circle = @drawLinePoint(row._x, row._y[i], @options.pointSize, @colorFor(row, i, 'point'), i)
.attr('fill', @colorFor(row, i, 'point'))
.attr('stroke-width', @strokeWidthForSeries(i))
.attr('stroke', @strokeForSeries(i))
else else
circle = null circle = null
@seriesPoints[i].push(circle) @seriesPoints[i].push(circle)
@ -245,14 +238,6 @@ class Morris.Line extends Morris.Grid
@seriesPoints[i][index].animate @pointGrow @seriesPoints[i][index].animate @pointGrow
@prevHilight = index @prevHilight = index
# @private
strokeWidthForSeries: (index) ->
@options.pointWidths[index % @options.pointWidths.length]
# @private
strokeForSeries: (index) ->
@options.pointStrokeColors[index % @options.pointStrokeColors.length]
colorFor: (row, sidx, type) -> colorFor: (row, sidx, type) ->
if typeof @options.lineColors is 'function' if typeof @options.lineColors is 'function'
@options.lineColors.call(@, row, sidx, type) @options.lineColors.call(@, row, sidx, type)
@ -261,6 +246,29 @@ class Morris.Line extends Morris.Grid
else else
@options.lineColors[sidx % @options.lineColors.length] @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 # generate a series of label, timestamp pairs for x-axis labels
# #

136
morris.js
View File

@ -87,7 +87,7 @@
if (typeof this.options.units === 'string') { if (typeof this.options.units === 'string') {
this.options.postUnits = options.units; this.options.postUnits = options.units;
} }
this.r = new Raphael(this.el[0]); this.raphael = new Raphael(this.el[0]);
this.elementWidth = null; this.elementWidth = null;
this.elementHeight = null; this.elementHeight = null;
this.dirty = false; this.dirty = false;
@ -324,7 +324,7 @@
}; };
Grid.prototype.redraw = function() { Grid.prototype.redraw = function() {
this.r.clear(); this.raphael.clear();
this._calc(); this._calc();
this.drawGrid(); this.drawGrid();
this.drawGoals(); this.drawGoals();
@ -340,7 +340,7 @@
_results = []; _results = [];
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
goal = _ref[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; return _results;
}; };
@ -351,7 +351,7 @@
_results = []; _results = [];
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
event = _ref[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; return _results;
}; };
@ -368,10 +368,10 @@
v = parseFloat(lineY.toFixed(this.precision)); v = parseFloat(lineY.toFixed(this.precision));
y = this.transY(v); y = this.transY(v);
if (this.options.axes) { 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) { 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 { } else {
_results.push(void 0); _results.push(void 0);
} }
@ -384,7 +384,7 @@
if (fontSize == null) { if (fontSize == null) {
fontSize = 12; 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(); ret = tt.getBBox();
tt.remove(); tt.remove();
return ret; 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; return Grid;
})(Morris.EventEmitter); })(Morris.EventEmitter);
@ -735,7 +751,7 @@
prevLabelMargin = null; prevLabelMargin = null;
drawLabel = function(labelText, xpos) { drawLabel = function(labelText, xpos) {
var label, labelBox; 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(); labelBox = label.getBBox();
if ((!(prevLabelMargin != null) || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < _this.el.width()) { 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; 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) { for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
path = this.paths[i]; path = this.paths[i];
if (path !== null) { 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() { this.seriesPoints = (function() {
@ -795,7 +811,7 @@
for (_k = 0, _len = _ref2.length; _k < _len; _k++) { for (_k = 0, _len = _ref2.length; _k < _len; _k++) {
row = _ref2[_k]; row = _ref2[_k];
if (row._y[i] != null) { 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 { } else {
circle = null; circle = null;
} }
@ -893,14 +909,6 @@
return this.prevHilight = index; 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) { Line.prototype.colorFor = function(row, sidx, type) {
if (typeof this.options.lineColors === 'function') { if (typeof this.options.lineColors === 'function') {
return this.options.lineColors.call(this, row, sidx, type); 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; return Line;
})(Morris.Grid); })(Morris.Grid);
@ -1086,7 +1114,7 @@
path = this.paths[i]; path = this.paths[i];
if (path !== null) { if (path !== null) {
path = path + ("L" + (this.transX(this.xmax)) + "," + this.bottom + "L" + (this.transX(this.xmin)) + "," + this.bottom + "Z"); 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); 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)); 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; return Area;
})(Morris.Line); })(Morris.Line);
@ -1183,7 +1215,7 @@
_results = []; _results = [];
for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { 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]; 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(); labelBox = label.getBBox();
if ((!(prevLabelMargin != null) || prevLabelMargin >= labelBox.x + labelBox.width) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < this.el.width()) { 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); _results.push(prevLabelMargin = labelBox.x - this.options.xLabelMargin);
@ -1230,7 +1262,7 @@
if (this.options.stacked) { if (this.options.stacked) {
top -= lastTop; 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); _results1.push(lastTop += size);
} else { } else {
_results1.push(null); _results1.push(null);
@ -1296,6 +1328,15 @@
return [content, x]; 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; return Bar;
})(Morris.Grid); })(Morris.Grid);
@ -1332,7 +1373,7 @@
Donut.prototype.redraw = function() { 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; 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.el.empty();
this.r = new Raphael(this.el[0]); this.raphael = new Raphael(this.el[0]);
cx = this.el.width() / 2; cx = this.el.width() / 2;
cy = this.el.height() / 2; cy = this.el.height() / 2;
w = (Math.min(cx, cy) - 10) / 3; w = (Math.min(cx, cy) - 10) / 3;
@ -1351,20 +1392,15 @@
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
d = _ref1[_j]; d = _ref1[_j];
next = last + min + C * (d.value / total); 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 = 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.r); seg.render();
this.segments.push(seg); this.segments.push(seg);
seg.on('hover', this.select); seg.on('hover', this.select);
last = next; last = next;
idx += 1; idx += 1;
} }
this.text1 = this.r.text(cx, cy - 10, '').attr({ this.text1 = this.drawEmptyDonutLabel(cx, cy - 10, 15, 800);
'font-size': 15, this.text2 = this.drawEmptyDonutLabel(cx, cy + 10, 14);
'font-weight': 800
});
this.text2 = this.r.text(cx, cy + 10, '').attr({
'font-size': 14
});
max_value = Math.max.apply(null, (function() { max_value = Math.max.apply(null, (function() {
var _k, _len2, _ref2, _results; var _k, _len2, _ref2, _results;
_ref2 = this.data; _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; return Donut;
})(); })();
@ -1439,7 +1484,7 @@
__extends(DonutSegment, _super); __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.cx = cx;
this.cy = cy; this.cy = cy;
this.inner = inner; this.inner = inner;
@ -1447,6 +1492,7 @@
this.color = color; this.color = color;
this.backgroundColor = backgroundColor; this.backgroundColor = backgroundColor;
this.data = data; this.data = data;
this.raphael = raphael;
this.deselect = __bind(this.deselect, this); this.deselect = __bind(this.deselect, this);
this.select = __bind(this.select, 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); 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; var _this = this;
this.arc = r.path(this.hilight).attr({ this.arc = this.drawDonutArc(this.hilight, this.color);
stroke: 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, 'stroke-width': 2,
opacity: 0 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 'stroke-width': 3
}).hover(function() { }).hover(hoverFunction);
return _this.fire('hover', _this);
});
}; };
DonutSegment.prototype.select = function() { DonutSegment.prototype.select = function() {

2
morris.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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

View File

@ -33,4 +33,4 @@ describe 'Morris.Bar#colorFor', ->
stub.should.have.been.calledWith( stub.should.have.been.calledWith(
{x:0, y:3, label:'foo'}, {x:0, y:3, label:'foo'},
{index:1, key:'z', label:'Z'}, {index:1, key:'z', label:'Z'},
'hover') 'hover')

View File

@ -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

View File

@ -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}] 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 = 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' 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