MUCH simpler internal code.

This commit is contained in:
Olly Smith 2012-10-23 09:15:21 +01:00
parent f6b1cfe7a0
commit 1aca098694
5 changed files with 195 additions and 206 deletions

View File

@ -34,7 +34,7 @@ class Morris.Grid extends Morris.EventEmitter
@init() if @init
# load data
@setData(@options.data)
@setData @options.data
# Default options
#
@ -55,62 +55,55 @@ class Morris.Grid extends Morris.EventEmitter
# Update the data series and redraw the chart.
#
setData: (data, redraw = true) ->
# shallow copy data
@options.data = $.map data, (row) =>
ymax = null
ymin = null
@data = $.map data, (row, index) =>
ret = {}
ret.label = row[@options.xkey]
if @options.parseTime
$.extend {'__T': Morris.parseDate(row[@options.xkey])}, row
ret.x = Morris.parseDate(ret.label)
if @options.dateFormat
ret.label = @options.dateFormat ret.x
else if typeof ret.label is 'number'
ret.label = new Date(ret.label).toString()
else
$.extend {}, row
if @options.parseTime
@options.data = @options.data.sort (a, b) =>
(a['__T'] > b['__T']) - (b['__T'] > a['__T'])
ret.x = index
ret.y = for ykey in @options.ykeys
yval = row[ykey]
yval = parseFloat(yval) if typeof yval is 'string'
yval = null unless typeof yval is 'number'
unless yval is null
if ymax is null
ymax = ymin = yval
else
ymax = Math.max(yval, ymax)
ymin = Math.min(yval, ymin)
yval
ret
# extract series data
@series = []
for ykey in @options.ykeys
seriesData = []
for d in @options.data
y = d[ykey]
seriesData.push switch typeof y
when 'number' then y
when 'string' then parseFloat y
else null
@series.push seriesData
# extract labels / x values
@columnLabels = $.map @options.data, (row) => row[@options.xkey]
if @options.parseTime
@xvals = $.map @options.data, (row) -> row['__T']
if @options.dateFormat
@columnLabels = $.map @xvals, (d) => @options.dateFormat d
else
@columnLabels = $.map @columnLabels, (d) =>
# default formatter for numeric timestamp labels
if typeof d is 'number' then new Date(d).toString() else d
else
@xvals = [0...@columnLabels.length]
@data = @data.sort (a, b) -> (a.x > b.x) - (b.x > a.x)
# calculate horizontal range of the graph
@xmin = Math.min.apply null, @xvals
@xmax = Math.max.apply null, @xvals
@xmin = @data[0].x
@xmax = @data[@data.length - 1].x
if @xmin is @xmax
@xmin -= 1
@xmax += 1
# Compute the vertical range of the graph if desired
if typeof @options.ymax is 'string' and @options.ymax[0..3] is 'auto'
# use Array.concat to flatten arrays and find the max y value
ymax = Math.max.apply null, Array.prototype.concat.apply([], @series)
if @options.ymax.length > 5
@ymax = Math.max parseInt(@options.ymax[5..], 10), ymax
if typeof @options.ymax is 'string'
if @options.ymax[0..3] is 'auto'
# use Array.concat to flatten arrays and find the max y value
if @options.ymax.length > 5
@ymax = Math.max parseInt(@options.ymax[5..], 10), ymax
else
@ymax = ymax
else
@ymax = ymax
else if typeof @options.ymax is 'string'
@ymax = parseInt(@options.ymax, 10)
@ymax = parseInt(@options.ymax, 10)
else
@ymax = @options.ymax
if typeof @options.ymin is 'string' and @options.ymin[0..3] is 'auto'
ymin = Math.min.apply null, Array.prototype.concat.apply([], @series)
if @options.ymin.length > 5
@ymin = Math.min parseInt(@options.ymin[5..], 10), ymin
else
@ -120,7 +113,7 @@ class Morris.Grid extends Morris.EventEmitter
else
@ymin = @options.ymin
if @ymin is @ymax
if @ymin is not 0 then @ymin -= 1
if @ymin isnt 0 then @ymin -= 1
@ymax += 1
@yInterval = (@ymax - @ymin) / (@options.numLines - 1)
@ -158,7 +151,7 @@ class Morris.Grid extends Morris.EventEmitter
#
transY: (y) -> @bottom - (y - @ymin) * @dy
transX: (x) ->
if @xvals.length == 1
if @data.length == 1
(@left + @right) / 2
else
@left + (x - @xmin) * @dx

View File

@ -60,18 +60,15 @@ class Morris.Line extends Morris.Grid
# @private
calc: ->
# calculate series data point coordinates
@columns = (@transX(x) for x in @xvals)
@seriesCoords = []
for s in @series
scoords = []
$.each s, (i, y) =>
if y == null
scoords.push(null)
else
scoords.push(x: @columns[i], y: @transY(y))
@seriesCoords.push(scoords)
for row in @data
row._x = @transX(row.x)
row._y = for y in row.y
if y is null
null
else
@transY(y)
# calculate hover margins
@hoverMargins = $.map @columns.slice(1), (x, i) => (x + @columns[i]) / 2
@hoverMargins = $.map @data.slice(1), (r, i) => (r._x + @data[i]._x) / 2
# Draws the line chart.
#
@ -79,7 +76,7 @@ class Morris.Line extends Morris.Grid
@drawXAxis()
@drawSeries()
@drawHover()
@hilight(if @options.hideHover then null else @options.data.length - 1)
@hilight(if @options.hideHover then null else @data.length - 1)
# draw the x-axis labels
#
@ -102,25 +99,24 @@ class Morris.Line extends Morris.Grid
else
label.remove()
if @options.parseTime
if @columnLabels.length == 1 and @options.xLabels == 'auto'
if @data.length == 1 and @options.xLabels == 'auto'
# where there's only one value in the series, we can't make a
# sensible guess for an x labelling scheme, so just use the original
# column label
drawLabel(@columnLabels[0], @xvals[0])
drawLabel(@data[0].label, @data[0].x)
else
for l in Morris.labelSeries(@xmin, @xmax, @width, @options.xLabels, @options.xLabelFormat)
drawLabel(l[0], l[1])
else
for i in [0...@columnLabels.length]
labelText = @columnLabels[i]
drawLabel(labelText, i)
for row in @data
drawLabel(row.label, row.x)
# draw the data series
#
# @private
drawSeries: ->
for i in [@seriesCoords.length-1..0]
coords = $.map @seriesCoords[i], (c) -> c
for i in [@options.ykeys.length-1..0]
coords = ({x: r._x, y: r._y[i]} for r in @data when r._y[i] isnt null)
smooth = @options.smooth is true or
$.inArray(@options.ykeys[i], @options.smooth) > -1
if coords.length > 1
@ -128,13 +124,13 @@ class Morris.Line extends Morris.Grid
@r.path(path)
.attr('stroke', @colorForSeries(i))
.attr('stroke-width', @options.lineWidth)
@seriesPoints = ([] for i in [0..@seriesCoords.length-1])
for i in [@seriesCoords.length-1..0]
for c in @seriesCoords[i]
if c == null
@seriesPoints = ([] for i in [0...@options.ykeys.length])
for i in [@options.ykeys.length-1..0]
for row in @data
if row._y[i] == null
circle = null
else
circle = @r.circle(c.x, c.y, @options.pointSize)
circle = @r.circle(row._x, row._y[i], @options.pointSize)
.attr('fill', @pointFillColorForSeries(i) || @colorForSeries(i))
.attr('stroke-width', @strokeWidthForSeries(i))
.attr('stroke', @strokeForSeries(i))
@ -182,7 +178,7 @@ class Morris.Line extends Morris.Grid
# @private
drawHover: ->
# hover labels
@hoverHeight = @options.hoverFontSize * 1.5 * (@series.length + 1)
@hoverHeight = @options.hoverFontSize * 1.5 * (@options.ykeys.length + 1)
@hover = @r.rect(-10, -@hoverHeight / 2 - @options.hoverPaddingY, 20, @hoverHeight + @options.hoverPaddingY * 2, 10)
.attr('fill', @options.hoverFillColor)
.attr('stroke', @options.hoverBorderColor)
@ -196,7 +192,7 @@ class Morris.Line extends Morris.Grid
@hoverSet.push(@hover)
@hoverSet.push(@xLabel)
@yLabels = []
for i in [0..@series.length-1]
for i in [0...@data.length]
yLabel = @r.text(0, @options.hoverFontSize * 1.5 * (i + 1.5) - @hoverHeight / 2, '')
.attr('fill', @colorForSeries(i))
.attr('font-size', @options.hoverFontSize)
@ -206,9 +202,10 @@ class Morris.Line extends Morris.Grid
# @private
updateHover: (index) =>
@hoverSet.show()
@xLabel.attr('text', @columnLabels[index])
for i in [0..@series.length-1]
@yLabels[i].attr('text', "#{@options.labels[i]}: #{@yLabelFormat(@series[i][index])}")
row = @data[index]
@xLabel.attr('text', row.label)
for y, i in row.y
@yLabels[i].attr('text', "#{@options.labels[i]}: #{@yLabelFormat(y)}")
# recalculate hover box width
maxLabelWidth = Math.max.apply null, $.map @yLabels, (l) ->
l.getBBox().width
@ -216,15 +213,14 @@ class Morris.Line extends Morris.Grid
@hover.attr 'width', maxLabelWidth + @options.hoverPaddingX * 2
@hover.attr 'x', -@options.hoverPaddingX - maxLabelWidth / 2
# move to y pos
yloc = Math.min.apply null, $.map @series, (s) =>
@transY s[index]
yloc = Math.min.apply null, row.y
if yloc > @hoverHeight + @options.hoverPaddingY * 2 + @options.hoverMargin + @top
yloc = yloc - @hoverHeight / 2 - @options.hoverPaddingY - @options.hoverMargin
else
yloc = yloc + @hoverHeight / 2 + @options.hoverPaddingY + @options.hoverMargin
yloc = Math.max @top + @hoverHeight / 2 + @options.hoverPaddingY, yloc
yloc = Math.min @bottom - @hoverHeight / 2 - @options.hoverPaddingY, yloc
xloc = Math.min @right - maxLabelWidth / 2 - @options.hoverPaddingX, @columns[index]
xloc = Math.min @right - maxLabelWidth / 2 - @options.hoverPaddingX, @data[index]._x
xloc = Math.max @left + maxLabelWidth / 2 + @options.hoverPaddingX, xloc
@hoverSet.attr 'transform', "t#{xloc},#{yloc}"

252
morris.js
View File

@ -62,6 +62,16 @@
return (number < 10 ? '0' : '') + number;
};
Morris.Data = (function() {
function Data() {}
Data.prototype.initialize = function(options) {};
return Data;
})();
Morris.Donut = (function() {
Donut.prototype.defaults = {
@ -329,94 +339,79 @@
};
Grid.prototype.setData = function(data, redraw) {
var d, seriesData, y, ykey, ymax, ymin, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2, _results,
var ymax, ymin,
_this = this;
if (redraw == null) {
redraw = true;
}
this.options.data = $.map(data, function(row) {
ymax = null;
ymin = null;
this.data = $.map(data, function(row, index) {
var ret, ykey, yval;
ret = {};
ret.label = row[_this.options.xkey];
if (_this.options.parseTime) {
return $.extend({
'__T': Morris.parseDate(row[_this.options.xkey])
}, row);
ret.x = Morris.parseDate(ret.label);
if (_this.options.dateFormat) {
ret.label = _this.options.dateFormat(ret.x);
} else if (typeof ret.label === 'number') {
ret.label = new Date(ret.label).toString();
}
} else {
return $.extend({}, row);
ret.x = index;
}
});
if (this.options.parseTime) {
this.options.data = this.options.data.sort(function(a, b) {
return (a['__T'] > b['__T']) - (b['__T'] > a['__T']);
});
}
this.series = [];
_ref = this.options.ykeys;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
ykey = _ref[_i];
seriesData = [];
_ref1 = this.options.data;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
d = _ref1[_j];
y = d[ykey];
seriesData.push((function() {
switch (typeof y) {
case 'number':
return y;
case 'string':
return parseFloat(y);
default:
return null;
}
})());
}
this.series.push(seriesData);
}
this.columnLabels = $.map(this.options.data, function(row) {
return row[_this.options.xkey];
});
if (this.options.parseTime) {
this.xvals = $.map(this.options.data, function(row) {
return row['__T'];
});
if (this.options.dateFormat) {
this.columnLabels = $.map(this.xvals, function(d) {
return _this.options.dateFormat(d);
});
} else {
this.columnLabels = $.map(this.columnLabels, function(d) {
if (typeof d === 'number') {
return new Date(d).toString();
} else {
return d;
}
});
}
} else {
this.xvals = (function() {
ret.y = (function() {
var _i, _len, _ref, _results;
_ref = this.options.ykeys;
_results = [];
for (var _k = 0, _ref2 = this.columnLabels.length; 0 <= _ref2 ? _k < _ref2 : _k > _ref2; 0 <= _ref2 ? _k++ : _k--){ _results.push(_k); }
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
ykey = _ref[_i];
yval = row[ykey];
if (typeof yval === 'string') {
yval = parseFloat(yval);
}
if (typeof yval !== 'number') {
yval = null;
}
if (yval !== null) {
if (ymax === null) {
ymax = ymin = yval;
} else {
ymax = Math.max(yval, ymax);
ymin = Math.min(yval, ymin);
}
}
_results.push(yval);
}
return _results;
}).apply(this);
}).call(_this);
return ret;
});
if (this.options.parseTime) {
this.data = this.data.sort(function(a, b) {
return (a.x > b.x) - (b.x > a.x);
});
}
this.xmin = Math.min.apply(null, this.xvals);
this.xmax = Math.max.apply(null, this.xvals);
this.xmin = this.data[0].x;
this.xmax = this.data[this.data.length - 1].x;
if (this.xmin === this.xmax) {
this.xmin -= 1;
this.xmax += 1;
}
if (typeof this.options.ymax === 'string' && this.options.ymax.slice(0, 4) === 'auto') {
ymax = Math.max.apply(null, Array.prototype.concat.apply([], this.series));
if (this.options.ymax.length > 5) {
this.ymax = Math.max(parseInt(this.options.ymax.slice(5), 10), ymax);
if (typeof this.options.ymax === 'string') {
if (this.options.ymax.slice(0, 4) === 'auto') {
if (this.options.ymax.length > 5) {
this.ymax = Math.max(parseInt(this.options.ymax.slice(5), 10), ymax);
} else {
this.ymax = ymax;
}
} else {
this.ymax = ymax;
this.ymax = parseInt(this.options.ymax, 10);
}
} else if (typeof this.options.ymax === 'string') {
this.ymax = parseInt(this.options.ymax, 10);
} else {
this.ymax = this.options.ymax;
}
if (typeof this.options.ymin === 'string' && this.options.ymin.slice(0, 4) === 'auto') {
ymin = Math.min.apply(null, Array.prototype.concat.apply([], this.series));
if (this.options.ymin.length > 5) {
this.ymin = Math.min(parseInt(this.options.ymin.slice(5), 10), ymin);
} else {
@ -428,7 +423,7 @@
this.ymin = this.options.ymin;
}
if (this.ymin === this.ymax) {
if (this.ymin === !0) {
if (this.ymin !== 0) {
this.ymin -= 1;
}
this.ymax += 1;
@ -473,7 +468,7 @@
};
Grid.prototype.transX = function(x) {
if (this.xvals.length === 1) {
if (this.data.length === 1) {
return (this.left + this.right) / 2;
} else {
return this.left + (x - this.xmin) * this.dx;
@ -651,37 +646,29 @@
};
Line.prototype.calc = function() {
var s, scoords, x, _i, _len, _ref,
var row, y, _i, _len, _ref,
_this = this;
this.columns = (function() {
var _i, _len, _ref, _results;
_ref = this.xvals;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
x = _ref[_i];
_results.push(this.transX(x));
}
return _results;
}).call(this);
this.seriesCoords = [];
_ref = this.series;
_ref = this.data;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
s = _ref[_i];
scoords = [];
$.each(s, function(i, y) {
if (y === null) {
return scoords.push(null);
} else {
return scoords.push({
x: _this.columns[i],
y: _this.transY(y)
});
row = _ref[_i];
row._x = this.transX(row.x);
row._y = (function() {
var _j, _len1, _ref1, _results;
_ref1 = row.y;
_results = [];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
y = _ref1[_j];
if (y === null) {
_results.push(null);
} else {
_results.push(this.transY(y));
}
}
});
this.seriesCoords.push(scoords);
return _results;
}).call(this);
}
return this.hoverMargins = $.map(this.columns.slice(1), function(x, i) {
return (x + _this.columns[i]) / 2;
return this.hoverMargins = $.map(this.data.slice(1), function(r, i) {
return (r._x + _this.data[i]._x) / 2;
});
};
@ -689,11 +676,11 @@
this.drawXAxis();
this.drawSeries();
this.drawHover();
return this.hilight(this.options.hideHover ? null : this.options.data.length - 1);
return this.hilight(this.options.hideHover ? null : this.data.length - 1);
};
Line.prototype.drawXAxis = function() {
var drawLabel, i, l, labelText, prevLabelMargin, xLabelMargin, ypos, _i, _j, _len, _ref, _ref1, _results, _results1,
var drawLabel, l, prevLabelMargin, row, xLabelMargin, ypos, _i, _j, _len, _len1, _ref, _ref1, _results, _results1,
_this = this;
ypos = this.bottom + this.options.gridTextSize * 1.25;
xLabelMargin = 50;
@ -709,8 +696,8 @@
}
};
if (this.options.parseTime) {
if (this.columnLabels.length === 1 && this.options.xLabels === 'auto') {
return drawLabel(this.columnLabels[0], this.xvals[0]);
if (this.data.length === 1 && this.options.xLabels === 'auto') {
return drawLabel(this.data[0].label, this.data[0].x);
} else {
_ref = Morris.labelSeries(this.xmin, this.xmax, this.width, this.options.xLabels, this.options.xLabelFormat);
_results = [];
@ -721,21 +708,34 @@
return _results;
}
} else {
_ref1 = this.data;
_results1 = [];
for (i = _j = 0, _ref1 = this.columnLabels.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
labelText = this.columnLabels[i];
_results1.push(drawLabel(labelText, i));
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
row = _ref1[_j];
_results1.push(drawLabel(row.label, row.x));
}
return _results1;
}
};
Line.prototype.drawSeries = function() {
var c, circle, coords, i, path, smooth, _i, _j, _ref, _ref1, _results;
for (i = _i = _ref = this.seriesCoords.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
coords = $.map(this.seriesCoords[i], function(c) {
return c;
});
var circle, coords, i, path, r, row, smooth, _i, _j, _ref, _ref1, _results;
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
coords = (function() {
var _j, _len, _ref1, _results;
_ref1 = this.data;
_results = [];
for (_j = 0, _len = _ref1.length; _j < _len; _j++) {
r = _ref1[_j];
if (r._y[i] !== null) {
_results.push({
x: r._x,
y: r._y[i]
});
}
}
return _results;
}).call(this);
smooth = this.options.smooth === true || $.inArray(this.options.ykeys[i], this.options.smooth) > -1;
if (coords.length > 1) {
path = this.createPath(coords, this.bottom, smooth);
@ -745,23 +745,23 @@
this.seriesPoints = (function() {
var _j, _ref1, _results;
_results = [];
for (i = _j = 0, _ref1 = this.seriesCoords.length - 1; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
for (i = _j = 0, _ref1 = this.options.ykeys.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
_results.push([]);
}
return _results;
}).call(this);
_results = [];
for (i = _j = _ref1 = this.seriesCoords.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {
for (i = _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {
_results.push((function() {
var _k, _len, _ref2, _results1;
_ref2 = this.seriesCoords[i];
_ref2 = this.data;
_results1 = [];
for (_k = 0, _len = _ref2.length; _k < _len; _k++) {
c = _ref2[_k];
if (c === null) {
row = _ref2[_k];
if (row._y[i] === null) {
circle = null;
} else {
circle = this.r.circle(c.x, c.y, this.options.pointSize).attr('fill', this.pointFillColorForSeries(i) || this.colorForSeries(i)).attr('stroke-width', this.strokeWidthForSeries(i)).attr('stroke', this.strokeForSeries(i));
circle = this.r.circle(row._x, row._y[i], this.options.pointSize).attr('fill', this.pointFillColorForSeries(i) || this.colorForSeries(i)).attr('stroke-width', this.strokeWidthForSeries(i)).attr('stroke', this.strokeForSeries(i));
}
_results1.push(this.seriesPoints[i].push(circle));
}
@ -814,7 +814,7 @@
Line.prototype.drawHover = function() {
var i, yLabel, _i, _ref, _results;
this.hoverHeight = this.options.hoverFontSize * 1.5 * (this.series.length + 1);
this.hoverHeight = this.options.hoverFontSize * 1.5 * (this.options.ykeys.length + 1);
this.hover = this.r.rect(-10, -this.hoverHeight / 2 - this.options.hoverPaddingY, 20, this.hoverHeight + this.options.hoverPaddingY * 2, 10).attr('fill', this.options.hoverFillColor).attr('stroke', this.options.hoverBorderColor).attr('stroke-width', this.options.hoverBorderWidth).attr('opacity', this.options.hoverOpacity);
this.xLabel = this.r.text(0, (this.options.hoverFontSize * 0.75) - this.hoverHeight / 2, '').attr('fill', this.options.hoverLabelColor).attr('font-weight', 'bold').attr('font-size', this.options.hoverFontSize);
this.hoverSet = this.r.set();
@ -822,7 +822,7 @@
this.hoverSet.push(this.xLabel);
this.yLabels = [];
_results = [];
for (i = _i = 0, _ref = this.series.length - 1; 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) {
yLabel = this.r.text(0, this.options.hoverFontSize * 1.5 * (i + 1.5) - this.hoverHeight / 2, '').attr('fill', this.colorForSeries(i)).attr('font-size', this.options.hoverFontSize);
this.yLabels.push(yLabel);
_results.push(this.hoverSet.push(yLabel));
@ -831,12 +831,14 @@
};
Line.prototype.updateHover = function(index) {
var i, maxLabelWidth, xloc, yloc, _i, _ref,
_this = this;
var i, maxLabelWidth, row, xloc, y, yloc, _i, _len, _ref;
this.hoverSet.show();
this.xLabel.attr('text', this.columnLabels[index]);
for (i = _i = 0, _ref = this.series.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
this.yLabels[i].attr('text', "" + this.options.labels[i] + ": " + (this.yLabelFormat(this.series[i][index])));
row = this.data[index];
this.xLabel.attr('text', row.label);
_ref = row.y;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
y = _ref[i];
this.yLabels[i].attr('text', "" + this.options.labels[i] + ": " + (this.yLabelFormat(y)));
}
maxLabelWidth = Math.max.apply(null, $.map(this.yLabels, function(l) {
return l.getBBox().width;
@ -844,9 +846,7 @@
maxLabelWidth = Math.max(maxLabelWidth, this.xLabel.getBBox().width);
this.hover.attr('width', maxLabelWidth + this.options.hoverPaddingX * 2);
this.hover.attr('x', -this.options.hoverPaddingX - maxLabelWidth / 2);
yloc = Math.min.apply(null, $.map(this.series, function(s) {
return _this.transY(s[index]);
}));
yloc = Math.min.apply(null, row.y);
if (yloc > this.hoverHeight + this.options.hoverPaddingY * 2 + this.options.hoverMargin + this.top) {
yloc = yloc - this.hoverHeight / 2 - this.options.hoverPaddingY - this.options.hoverMargin;
} else {
@ -854,7 +854,7 @@
}
yloc = Math.max(this.top + this.hoverHeight / 2 + this.options.hoverPaddingY, yloc);
yloc = Math.min(this.bottom - this.hoverHeight / 2 - this.options.hoverPaddingY, yloc);
xloc = Math.min(this.right - maxLabelWidth / 2 - this.options.hoverPaddingX, this.columns[index]);
xloc = Math.min(this.right - maxLabelWidth / 2 - this.options.hoverPaddingX, this.data[index]._x);
xloc = Math.max(this.left + maxLabelWidth / 2 + this.options.hoverPaddingX, xloc);
return this.hoverSet.attr('transform', "t" + xloc + "," + yloc);
};

2
morris.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -60,7 +60,7 @@ describe 'Morris.Line', ->
xkey: 'x'
ykeys: ['y']
labels: ['dontcare']
chart.columnLabels.should == ['2012 Q1', '2012 Q2']
chart.data.map((x) -> x.label).should == ['2012 Q1', '2012 Q2']
it 'should use a default format for timestamp x-values', ->
d1 = new Date(2012, 0, 1)
@ -71,7 +71,7 @@ describe 'Morris.Line', ->
xkey: 'x'
ykeys: ['y']
labels: ['dontcare']
chart.columnLabels.should == [d2.toString(), d1.toString()]
chart.data.map((x) -> x.label).should == [d2.toString(), d1.toString()]
it 'should use user-defined formatters', ->
d = new Date(2012, 0, 1)
@ -84,4 +84,4 @@ describe 'Morris.Line', ->
dateFormat: (d) ->
x = new Date(d)
"#{x.getYear()}/#{x.getMonth()+1}/#{x.getDay()}"
chart.columnLabels.should == ['2012/1/1', '2012/1/2']
chart.data.map((x) -> x.label).should == ['2012/1/1', '2012/1/2']