WIP: interval improvements

This commit is contained in:
Olly Smith 2013-03-29 11:48:24 -07:00
parent 7a9f523bb0
commit 5e240e64fe
5 changed files with 113 additions and 26 deletions

View File

@ -160,11 +160,32 @@ class Morris.Grid extends Morris.EventEmitter
@ymin -= 1 if ymin
@ymax += 1
@yInterval = (@ymax - @ymin) / (@options.numLines - 1)
if @yInterval > 0 and @yInterval < 1
@precision = -Math.floor(Math.log(@yInterval) / Math.log(10))
else
@precision = 0
if @options.axes is true or @options.grid is true
# calculate grid placement
span = @ymax - @ymin
ymag = Math.floor(Math.log(span) / Math.log(10))
unit = Math.pow(10, ymag)
# calculate initial grid min and max values
gmin = Math.round(@ymin / unit) * unit
gmax = Math.round(@ymax / unit) * unit
step = (gmax - gmin) / (@options.numLines - 1)
# ensure zero is plotted where the range includes zero
if gmin < 0 and gmax > 0
gmin = Math.round(@ymin / step) * step
gmax = Math.round(@ymax / step) * step
# special case for decimal numbers
if step < 1
smag = Math.floor(Math.log(step) / Math.log(10))
@grid = for y in [gmin..gmax] by step
parseFloat(y.toFixed(1 - smag))
else
@grid = (y for y in [gmin..gmax] by step)
@ymin = gmin
@ymax = gmax
@dirty = true
@redraw() if redraw
@ -259,13 +280,10 @@ class Morris.Grid extends Morris.EventEmitter
#
drawGrid: ->
return if @options.grid is false and @options.axes is false
firstY = @ymin
lastY = @ymax
for lineY in [firstY..lastY] by @yInterval
v = parseFloat(lineY.toFixed(@precision))
y = @transY(v)
for lineY in @grid
y = @transY(lineY)
if @options.axes
@drawYAxisLabel(@left - @options.padding / 2, y, @yAxisFormat(v))
@drawYAxisLabel(@left - @options.padding / 2, y, @yAxisFormat(lineY))
if @options.grid
@drawGridLine("M#{@left},#{y}H#{@left + @width}")

View File

@ -138,7 +138,7 @@
};
Grid.prototype.setData = function(data, redraw) {
var e, idx, index, maxGoal, minGoal, ret, row, total, ykey, ymax, ymin, yval;
var e, gmax, gmin, idx, index, maxGoal, minGoal, ret, row, smag, span, step, total, unit, y, ykey, ymag, ymax, ymin, yval;
if (redraw == null) {
redraw = true;
}
@ -247,11 +247,39 @@
}
this.ymax += 1;
}
this.yInterval = (this.ymax - this.ymin) / (this.options.numLines - 1);
if (this.yInterval > 0 && this.yInterval < 1) {
this.precision = -Math.floor(Math.log(this.yInterval) / Math.log(10));
} else {
this.precision = 0;
if (this.options.axes === true || this.options.grid === true) {
span = this.ymax - this.ymin;
ymag = Math.floor(Math.log(span) / Math.log(10));
unit = Math.pow(10, ymag);
gmin = Math.round(this.ymin / unit) * unit;
gmax = Math.round(this.ymax / unit) * unit;
step = (gmax - gmin) / (this.options.numLines - 1);
if (gmin < 0 && gmax > 0) {
gmin = Math.round(this.ymin / step) * step;
gmax = Math.round(this.ymax / step) * step;
}
if (step < 1) {
smag = Math.floor(Math.log(step) / Math.log(10));
this.grid = (function() {
var _i, _results;
_results = [];
for (y = _i = gmin; gmin <= gmax ? _i <= gmax : _i >= gmax; y = _i += step) {
_results.push(parseFloat(y.toFixed(1 - smag)));
}
return _results;
})();
} else {
this.grid = (function() {
var _i, _results;
_results = [];
for (y = _i = gmin; gmin <= gmax ? _i <= gmax : _i >= gmax; y = _i += step) {
_results.push(y);
}
return _results;
})();
}
this.ymin = gmin;
this.ymax = gmax;
}
this.dirty = true;
if (redraw) {
@ -367,18 +395,17 @@
};
Grid.prototype.drawGrid = function() {
var firstY, lastY, lineY, v, y, _i, _ref, _results;
var lineY, y, _i, _len, _ref, _results;
if (this.options.grid === false && this.options.axes === false) {
return;
}
firstY = this.ymin;
lastY = this.ymax;
_ref = this.grid;
_results = [];
for (lineY = _i = firstY, _ref = this.yInterval; firstY <= lastY ? _i <= lastY : _i >= lastY; lineY = _i += _ref) {
v = parseFloat(lineY.toFixed(this.precision));
y = this.transY(v);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
lineY = _ref[_i];
y = this.transY(lineY);
if (this.options.axes) {
this.drawYAxisLabel(this.left - this.options.padding / 2, y, this.yAxisFormat(v));
this.drawYAxisLabel(this.left - this.options.padding / 2, y, this.yAxisFormat(lineY));
}
if (this.options.grid) {
_results.push(this.drawGridLine("M" + this.left + "," + y + "H" + (this.left + this.width)));

2
morris.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,42 @@
gridLines = (ymin, ymax, nlines = 5) ->
interval = ymax - ymin
omag = Math.floor(Math.log(interval) / Math.log(10))
unit = Math.pow(10, omag)
ymin1 = Math.round(ymin / unit) * unit
ymax1 = Math.round(ymax / unit) * unit
step = (ymax1 - ymin1) / (nlines - 1)
# ensure zero is plotted where the range includes zero
if ymin1 < 0 and ymax1 > 0
ymin1 = Math.round(ymin / step) * step
ymax1 = Math.round(ymax / step) * step
# small numbers
if step < 1
smag = Math.floor(Math.log(step) / Math.log(10))
(parseFloat(y.toFixed(1 - smag)) for y in [ymin1..ymax1] by step)
else
(y for y in [ymin1..ymax1] by step)
describe 'Morris.Grid#gridLines', ->
it 'should draw at fixed intervals', ->
gridLines(0, 4).should.deep.equal [0, 1, 2, 3, 4]
gridLines(0, 400).should.deep.equal [0, 100, 200, 300, 400]
it 'should pick intervals that show significant numbers', ->
gridLines(98, 502).should.deep.equal [100, 200, 300, 400, 500]
gridLines(98, 302).should.deep.equal [100, 150, 200, 250, 300]
gridLines(98, 202).should.deep.equal [100, 125, 150, 175, 200]
it 'should draw zero when it falls within [ymin..ymax]', ->
gridLines(-100, 300).should.deep.equal [-100, 0, 100, 200, 300]
gridLines(-50, 350).should.deep.equal [0, 100, 200, 300, 400]
gridLines(-500, 300).should.deep.equal [-400, -200, 0, 200, 400]
gridLines(100, 500).should.deep.equal [100, 200, 300, 400, 500]
gridLines(-500, -100).should.deep.equal [-500, -400, -300, -200, -100]
it 'should generate decimal labels to 2 signigicant figures', ->
gridLines(0, 1).should.deep.equal [0, 0.25, 0.5, 0.75, 1]
gridLines(0.1, 0.5).should.deep.equal [0.1, 0.2, 0.3, 0.4, 0.5]

View File

@ -13,7 +13,7 @@ describe 'Morris.Grid#setData', ->
describe 'ymin/ymax', ->
beforeEach ->
@defaults =
@defaults =
element: 'graph'
xkey: 'x'
ykeys: ['y', 'z']