mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-09-21 10:41:32 +02:00
Better automatic y-labelling.
This commit is contained in:
parent
5e240e64fe
commit
6d6e07b2aa
@ -161,31 +161,14 @@ class Morris.Grid extends Morris.EventEmitter
|
|||||||
@ymax += 1
|
@ymax += 1
|
||||||
|
|
||||||
if @options.axes is true or @options.grid is true
|
if @options.axes is true or @options.grid is true
|
||||||
# calculate grid placement
|
if @options.ymax == @defaults.ymax and @options.ymin == @defaults.ymin
|
||||||
span = @ymax - @ymin
|
# calculate 'magic' grid placement
|
||||||
ymag = Math.floor(Math.log(span) / Math.log(10))
|
@grid = @autoGridLines(@ymin, @ymax, @options.numLines)
|
||||||
unit = Math.pow(10, ymag)
|
@ymin = Math.min(@ymin, @grid[0])
|
||||||
|
@ymax = Math.max(@ymax, @grid[@grid.length - 1])
|
||||||
# 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
|
else
|
||||||
@grid = (y for y in [gmin..gmax] by step)
|
step = (@ymax - @ymin) / (@options.numLines - 1)
|
||||||
|
@grid = (y for y in [@ymin..@ymax] by step)
|
||||||
@ymin = gmin
|
|
||||||
@ymax = gmax
|
|
||||||
|
|
||||||
@dirty = true
|
@dirty = true
|
||||||
@redraw() if redraw
|
@redraw() if redraw
|
||||||
@ -205,6 +188,33 @@ class Morris.Grid extends Morris.EventEmitter
|
|||||||
else
|
else
|
||||||
boundaryOption
|
boundaryOption
|
||||||
|
|
||||||
|
autoGridLines: (ymin, ymax, nlines) ->
|
||||||
|
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.floor(ymin / unit) * unit
|
||||||
|
gmax = Math.ceil(ymax / unit) * unit
|
||||||
|
step = (gmax - gmin) / (nlines - 1)
|
||||||
|
if unit == 1 and step > 1 and Math.ceil(step) != step
|
||||||
|
step = Math.ceil(step)
|
||||||
|
gmax = gmin + step * (nlines - 1)
|
||||||
|
|
||||||
|
# ensure zero is plotted where the range includes zero
|
||||||
|
if gmin < 0 and gmax > 0
|
||||||
|
gmin = Math.floor(ymin / step) * step
|
||||||
|
gmax = Math.ceil(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)
|
||||||
|
grid
|
||||||
|
|
||||||
_calc: ->
|
_calc: ->
|
||||||
w = @el.width()
|
w = @el.width()
|
||||||
h = @el.height()
|
h = @el.height()
|
||||||
|
74
morris.js
74
morris.js
@ -138,7 +138,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Grid.prototype.setData = function(data, redraw) {
|
Grid.prototype.setData = function(data, redraw) {
|
||||||
var e, gmax, gmin, idx, index, maxGoal, minGoal, ret, row, smag, span, step, total, unit, y, ykey, ymag, ymax, ymin, yval;
|
var e, idx, index, maxGoal, minGoal, ret, row, step, total, y, ykey, ymax, ymin, yval;
|
||||||
if (redraw == null) {
|
if (redraw == null) {
|
||||||
redraw = true;
|
redraw = true;
|
||||||
}
|
}
|
||||||
@ -248,38 +248,21 @@
|
|||||||
this.ymax += 1;
|
this.ymax += 1;
|
||||||
}
|
}
|
||||||
if (this.options.axes === true || this.options.grid === true) {
|
if (this.options.axes === true || this.options.grid === true) {
|
||||||
span = this.ymax - this.ymin;
|
if (this.options.ymax === this.defaults.ymax && this.options.ymin === this.defaults.ymin) {
|
||||||
ymag = Math.floor(Math.log(span) / Math.log(10));
|
this.grid = this.autoGridLines(this.ymin, this.ymax, this.options.numLines);
|
||||||
unit = Math.pow(10, ymag);
|
this.ymin = Math.min(this.ymin, this.grid[0]);
|
||||||
gmin = Math.round(this.ymin / unit) * unit;
|
this.ymax = Math.max(this.ymax, this.grid[this.grid.length - 1]);
|
||||||
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 {
|
} else {
|
||||||
|
step = (this.ymax - this.ymin) / (this.options.numLines - 1);
|
||||||
this.grid = (function() {
|
this.grid = (function() {
|
||||||
var _i, _results;
|
var _i, _ref, _ref1, _results;
|
||||||
_results = [];
|
_results = [];
|
||||||
for (y = _i = gmin; gmin <= gmax ? _i <= gmax : _i >= gmax; y = _i += step) {
|
for (y = _i = _ref = this.ymin, _ref1 = this.ymax; _ref <= _ref1 ? _i <= _ref1 : _i >= _ref1; y = _i += step) {
|
||||||
_results.push(y);
|
_results.push(y);
|
||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
})();
|
}).call(this);
|
||||||
}
|
}
|
||||||
this.ymin = gmin;
|
|
||||||
this.ymax = gmax;
|
|
||||||
}
|
}
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
if (redraw) {
|
if (redraw) {
|
||||||
@ -313,6 +296,45 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Grid.prototype.autoGridLines = function(ymin, ymax, nlines) {
|
||||||
|
var gmax, gmin, grid, smag, span, step, unit, y, ymag;
|
||||||
|
span = ymax - ymin;
|
||||||
|
ymag = Math.floor(Math.log(span) / Math.log(10));
|
||||||
|
unit = Math.pow(10, ymag);
|
||||||
|
gmin = Math.floor(ymin / unit) * unit;
|
||||||
|
gmax = Math.ceil(ymax / unit) * unit;
|
||||||
|
step = (gmax - gmin) / (nlines - 1);
|
||||||
|
if (unit === 1 && step > 1 && Math.ceil(step) !== step) {
|
||||||
|
step = Math.ceil(step);
|
||||||
|
gmax = gmin + step * (nlines - 1);
|
||||||
|
}
|
||||||
|
if (gmin < 0 && gmax > 0) {
|
||||||
|
gmin = Math.floor(ymin / step) * step;
|
||||||
|
gmax = Math.ceil(ymax / step) * step;
|
||||||
|
}
|
||||||
|
if (step < 1) {
|
||||||
|
smag = Math.floor(Math.log(step) / Math.log(10));
|
||||||
|
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 {
|
||||||
|
grid = (function() {
|
||||||
|
var _i, _results;
|
||||||
|
_results = [];
|
||||||
|
for (y = _i = gmin; gmin <= gmax ? _i <= gmax : _i >= gmax; y = _i += step) {
|
||||||
|
_results.push(y);
|
||||||
|
}
|
||||||
|
return _results;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
return grid;
|
||||||
|
};
|
||||||
|
|
||||||
Grid.prototype._calc = function() {
|
Grid.prototype._calc = function() {
|
||||||
var h, maxYLabelWidth, w;
|
var h, maxYLabelWidth, w;
|
||||||
w = this.el.width();
|
w = this.el.width();
|
||||||
|
2
morris.min.js
vendored
2
morris.min.js
vendored
File diff suppressed because one or more lines are too long
25
spec/lib/grid/auto_grid_lines_spec.coffee
Normal file
25
spec/lib/grid/auto_grid_lines_spec.coffee
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
describe 'Morris.Grid#autoGridLines', ->
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
@subject = Morris.Grid.prototype.autoGridLines
|
||||||
|
|
||||||
|
it 'should draw at fixed intervals', ->
|
||||||
|
@subject(0, 4, 5).should.deep.equal [0, 1, 2, 3, 4]
|
||||||
|
@subject(0, 400, 5).should.deep.equal [0, 100, 200, 300, 400]
|
||||||
|
|
||||||
|
it 'should pick intervals that show significant numbers', ->
|
||||||
|
@subject(102, 499, 5).should.deep.equal [100, 200, 300, 400, 500]
|
||||||
|
|
||||||
|
it 'should draw zero when it falls within [ymin..ymax]', ->
|
||||||
|
@subject(-100, 300, 5).should.deep.equal [-100, 0, 100, 200, 300]
|
||||||
|
@subject(-50, 350, 5).should.deep.equal [-125, 0, 125, 250, 375]
|
||||||
|
@subject(-400, 400, 5).should.deep.equal [-400, -200, 0, 200, 400]
|
||||||
|
@subject(100, 500, 5).should.deep.equal [100, 200, 300, 400, 500]
|
||||||
|
@subject(-500, -100, 5).should.deep.equal [-500, -400, -300, -200, -100]
|
||||||
|
|
||||||
|
it 'should generate decimal labels to 2 significant figures', ->
|
||||||
|
@subject(0, 1, 5).should.deep.equal [0, 0.25, 0.5, 0.75, 1]
|
||||||
|
@subject(0.1, 0.5, 5).should.deep.equal [0.1, 0.2, 0.3, 0.4, 0.5]
|
||||||
|
|
||||||
|
it 'should use integer intervals for intervals larger than 1', ->
|
||||||
|
@subject(0, 9, 5).should.deep.equal [0, 3, 6, 9, 12]
|
@ -1,42 +0,0 @@
|
|||||||
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]
|
|
@ -197,3 +197,12 @@ describe 'Morris.Grid#setData', ->
|
|||||||
line.data.length.should.equal 0
|
line.data.length.should.equal 0
|
||||||
line.setData([{x: 2, y: '12'}, {x: 1, y: '13.5'}, {x: 4, y: '14'}, {x: 3, y: '16'}])
|
line.setData([{x: 2, y: '12'}, {x: 1, y: '13.5'}, {x: 4, y: '14'}, {x: 3, y: '16'}])
|
||||||
line.data.length.should.equal 4
|
line.data.length.should.equal 4
|
||||||
|
|
||||||
|
it 'should automatically choose significant numbers for y-labels', ->
|
||||||
|
line = Morris.Line
|
||||||
|
element: 'graph',
|
||||||
|
data: [{x: 1, y: 0}, {x: 2, y: 3600}]
|
||||||
|
xkey: 'x'
|
||||||
|
ykeys: ['y']
|
||||||
|
labels: ['y']
|
||||||
|
line.grid.should == [0, 1000, 2000, 3000, 4000]
|
||||||
|
Loading…
Reference in New Issue
Block a user