support non-numeric y-axis values and single series timelines

This commit is contained in:
Clinton Sheppard 2012-03-01 18:22:52 -06:00
parent 8446be205e
commit c7fe04e5b8
4 changed files with 50 additions and 12 deletions

View File

@ -114,4 +114,33 @@
}); });
}); });
</script> </script>
<h3>Text values</h3>
<div id="graph-yyyy-mm-dd" class="graph" style="height:175px"></div>
<script>
$(function () {
// data from https://en.wikipedia.org/wiki/United_States_presidential_election,_2012_timeline
var day_data = [
{"period": "2012-01-03", "event": "Iowa"},
{"period": "2012-01-10", "event": "New Hampshire"},
{"period": "2012-01-21", "event": "South Carolina"},
{"period": "2012-01-31", "event": "Florida"},
{"period": "2012-02-04", "event": "Maine, Nevada"},
{"period": "2012-02-07", "event": "Colorado, Minnesota, Missouri"},
{"period": "2012-02-28", "event": "Arizona, Michigan"},
{"period": "2012-02-29", "event": "Wyoming"},
{"period": "2012-03-01", "event": "Washington"},
{"period": "2012-03-06", "event": "Super Tuesday"},
];
Morris.Line({
element: 'graph-yyyy-mm-dd',
data: day_data,
xkey: 'period',
ykeys: ['event'],
labels: ['event'],
marginBottom: 100,
numLines: 1
});
});
</script>
</body> </body>

View File

@ -95,6 +95,9 @@ class Morris.Line
# remove child elements (get rid of old drawings) # remove child elements (get rid of old drawings)
@el.empty() @el.empty()
isNumber = (o) =>
! isNan (o-0)
# the raphael drawing instance # the raphael drawing instance
@r = new Raphael(@el[0]) @r = new Raphael(@el[0])
@ -103,7 +106,7 @@ class Morris.Line
width = @el.width() - left - @options.marginRight width = @el.width() - left - @options.marginRight
height = @el.height() - @options.marginTop - @options.marginBottom height = @el.height() - @options.marginTop - @options.marginBottom
dx = width / (@xmax - @xmin) dx = width / (@xmax - @xmin)
dy = height / @options.ymax dy = height / (if isNumber(@options.ymax) then @options.ymax else height)
# quick translation helpers # quick translation helpers
transX = (x) => transX = (x) =>
@ -112,13 +115,15 @@ class Morris.Line
else else
left + (x - @xmin) * dx left + (x - @xmin) * dx
transY = (y) => transY = (y) =>
return @options.marginTop + height - y * dy return @options.marginTop + height - (if isNumber(y) then y * dy else dy)
# draw y axis labels, horizontal lines # draw y axis labels, horizontal lines
lineInterval = height / (@options.numLines - 1) lineInterval = height / (if @options.numLines == 1 then 2 else (@options.numLines - 1))
for i in [0..@options.numLines-1] for i in [0..@options.numLines-1]
y = @options.marginTop + i * lineInterval y = @options.marginTop + i * lineInterval
v = Math.round((@options.numLines - 1 - i) * @options.ymax / (@options.numLines - 1)) v = Math.round((@options.numLines - 1 - i) * @options.ymax / (if @options.numLines == 1 then 1 else (@options.numLines - 1)))
if isNaN(v)
v = ""
@r.text(left - @options.marginLeft/2, y, v) @r.text(left - @options.marginLeft/2, y, v)
.attr('font-size', @options.gridTextSize) .attr('font-size', @options.gridTextSize)
.attr('fill', @options.gridTextColor) .attr('fill', @options.gridTextColor)
@ -187,7 +192,7 @@ class Morris.Line
hoverSet.show() hoverSet.show()
xLabel.attr('text', @columnLabels[index]) xLabel.attr('text', @columnLabels[index])
for i in [0..@series.length-1] for i in [0..@series.length-1]
yLabels[i].attr('text', "#{@seriesLabels[i]}: #{@commas(@series[i][index])}") yLabels[i].attr('text', "#{@seriesLabels[i]}: #{if isNumber(@series[i][index]) then @commas(@series[i][index]) else @series[i][index]}")
# recalculate hover box width # recalculate hover box width
maxLabelWidth = Math.max.apply null, $.map yLabels, (l) -> maxLabelWidth = Math.max.apply null, $.map yLabels, (l) ->
l.getBBox().width l.getBBox().width

View File

@ -85,15 +85,18 @@
}; };
Line.prototype.redraw = function() { Line.prototype.redraw = function() {
var c, circle, columns, coords, dx, dy, height, hideHover, hilight, hover, hoverHeight, hoverMargins, hoverSet, i, label, labelBox, left, lineInterval, path, pointGrow, pointShrink, prevHilight, prevLabelMargin, s, seriesCoords, seriesPoints, touchHandler, transX, transY, updateHilight, updateHover, v, width, x, xLabel, xLabelMargin, y, yLabel, yLabels, _i, _j, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, var c, circle, columns, coords, dx, dy, height, hideHover, hilight, hover, hoverHeight, hoverMargins, hoverSet, i, isNumber, label, labelBox, left, lineInterval, path, pointGrow, pointShrink, prevHilight, prevLabelMargin, s, seriesCoords, seriesPoints, touchHandler, transX, transY, updateHilight, updateHover, v, width, x, xLabel, xLabelMargin, y, yLabel, yLabels, _i, _j, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8,
_this = this; _this = this;
this.el.empty(); this.el.empty();
isNumber = function(o) {
return !isNan(o - 0);
};
this.r = new Raphael(this.el[0]); this.r = new Raphael(this.el[0]);
left = this.measureText(this.options.ymax, this.options.gridTextSize).width + this.options.marginLeft; left = this.measureText(this.options.ymax, this.options.gridTextSize).width + this.options.marginLeft;
width = this.el.width() - left - this.options.marginRight; width = this.el.width() - left - this.options.marginRight;
height = this.el.height() - this.options.marginTop - this.options.marginBottom; height = this.el.height() - this.options.marginTop - this.options.marginBottom;
dx = width / (this.xmax - this.xmin); dx = width / (this.xmax - this.xmin);
dy = height / this.options.ymax; dy = height / (isNumber(this.options.ymax) ? this.options.ymax : height);
transX = function(x) { transX = function(x) {
if (_this.xvals.length === 1) { if (_this.xvals.length === 1) {
return left + width / 2; return left + width / 2;
@ -102,12 +105,13 @@
} }
}; };
transY = function(y) { transY = function(y) {
return _this.options.marginTop + height - y * dy; return _this.options.marginTop + height - (isNumber(y) ? y * dy : dy);
}; };
lineInterval = height / (this.options.numLines - 1); lineInterval = height / (this.options.numLines === 1 ? 2 : this.options.numLines - 1);
for (i = 0, _ref = this.options.numLines - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) { for (i = 0, _ref = this.options.numLines - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
y = this.options.marginTop + i * lineInterval; y = this.options.marginTop + i * lineInterval;
v = Math.round((this.options.numLines - 1 - i) * this.options.ymax / (this.options.numLines - 1)); v = Math.round((this.options.numLines - 1 - i) * this.options.ymax / (this.options.numLines === 1 ? 1 : this.options.numLines - 1));
if (isNaN(v)) v = "";
this.r.text(left - this.options.marginLeft / 2, y, v).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end'); this.r.text(left - this.options.marginLeft / 2, y, v).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end');
this.r.path("M" + left + "," + y + 'H' + (left + width)).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth); this.r.path("M" + left + "," + y + 'H' + (left + width)).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth);
} }
@ -183,7 +187,7 @@
hoverSet.show(); hoverSet.show();
xLabel.attr('text', _this.columnLabels[index]); xLabel.attr('text', _this.columnLabels[index]);
for (i = 0, _ref9 = _this.series.length - 1; 0 <= _ref9 ? i <= _ref9 : i >= _ref9; 0 <= _ref9 ? i++ : i--) { for (i = 0, _ref9 = _this.series.length - 1; 0 <= _ref9 ? i <= _ref9 : i >= _ref9; 0 <= _ref9 ? i++ : i--) {
yLabels[i].attr('text', "" + _this.seriesLabels[i] + ": " + (_this.commas(_this.series[i][index]))); yLabels[i].attr('text', "" + _this.seriesLabels[i] + ": " + (isNumber(_this.series[i][index]) ? _this.commas(_this.series[i][index]) : _this.series[i][index]));
} }
maxLabelWidth = Math.max.apply(null, $.map(yLabels, function(l) { maxLabelWidth = Math.max.apply(null, $.map(yLabels, function(l) {
return l.getBBox().width; return l.getBBox().width;

2
morris.min.js vendored

File diff suppressed because one or more lines are too long