mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-11-10 21:36:34 +01:00
#199, added behaveLikeLine and fillOpacity options, refactored morris.line to separate line and point draw operation
This commit is contained in:
parent
0cbd83371f
commit
3c9fff0aa0
31
examples/area-as-line.html
Normal file
31
examples/area-as-line.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<head>
|
||||||
|
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
||||||
|
<script src="https://raw.github.com/DmitryBaranovskiy/raphael/300aa589f5a0ba7fce667cd62c7cdda0bd5ad904/raphael-min.js"></script>
|
||||||
|
<script src="../morris.js"></script>
|
||||||
|
<script src="lib/prettify.js"></script>
|
||||||
|
<script src="lib/example.js"></script>
|
||||||
|
<link rel="stylesheet" href="lib/example.css">
|
||||||
|
<link rel="stylesheet" href="lib/prettify.css">
|
||||||
|
<link rel="stylesheet" href="../morris.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Area charts behaving like line charts</h1>
|
||||||
|
<div id="graph"></div>
|
||||||
|
<pre id="code" class="prettyprint linenums">
|
||||||
|
// Use Morris.Area instead of Morris.Line
|
||||||
|
Morris.Area({
|
||||||
|
element: 'graph',
|
||||||
|
behaveLikeLine: true,
|
||||||
|
data: [
|
||||||
|
{x: '2011 Q1', y: 3, z: 3},
|
||||||
|
{x: '2011 Q2', y: 2, z: 1},
|
||||||
|
{x: '2011 Q3', y: 2, z: 4},
|
||||||
|
{x: '2011 Q4', y: 3, z: 3}
|
||||||
|
],
|
||||||
|
xkey: 'x',
|
||||||
|
ykeys: ['y', 'z'],
|
||||||
|
labels: ['Y', 'Z']
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
</body>
|
@ -19,7 +19,7 @@ Morris.Area({
|
|||||||
data: [
|
data: [
|
||||||
{x: '2011 Q1', y: 3, z: 3},
|
{x: '2011 Q1', y: 3, z: 3},
|
||||||
{x: '2011 Q2', y: 2, z: 0},
|
{x: '2011 Q2', y: 2, z: 0},
|
||||||
{x: '2011 Q3', y: 0, z: 2},
|
{x: '2011 Q3', y: 2, z: 5},
|
||||||
{x: '2011 Q4', y: 4, z: 4}
|
{x: '2011 Q4', y: 4, z: 4}
|
||||||
],
|
],
|
||||||
xkey: 'x',
|
xkey: 'x',
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
class Morris.Area extends Morris.Line
|
class Morris.Area extends Morris.Line
|
||||||
# Initialise
|
# Initialise
|
||||||
#
|
#
|
||||||
|
areaDefaults =
|
||||||
|
fillOpacity: 'auto'
|
||||||
|
behaveLikeLine: false
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
return new Morris.Area(options) unless (@ instanceof Morris.Area)
|
return new Morris.Area(options) unless (@ instanceof Morris.Area)
|
||||||
@cumulative = true
|
areaOptions = $.extend {}, areaDefaults, options
|
||||||
super(options)
|
|
||||||
|
@cumulative = not areaOptions.behaveLikeLine
|
||||||
|
|
||||||
|
if areaOptions.fillOpacity is 'auto'
|
||||||
|
areaOptions.fillOpacity = if areaOptions.behaveLikeLine then .8 else 1
|
||||||
|
|
||||||
|
super(areaOptions)
|
||||||
|
|
||||||
# calculate series data point coordinates
|
# calculate series data point coordinates
|
||||||
#
|
#
|
||||||
@ -14,29 +24,43 @@ class Morris.Area extends Morris.Line
|
|||||||
row._x = @transX(row.x)
|
row._x = @transX(row.x)
|
||||||
total = 0
|
total = 0
|
||||||
row._y = for y in row.y
|
row._y = for y in row.y
|
||||||
total += (y || 0)
|
if @options.behaveLikeLine
|
||||||
@transY(total)
|
@transY(y)
|
||||||
row._ymax = row._y[row._y.length - 1]
|
else
|
||||||
|
total += (y || 0)
|
||||||
|
@transY(total)
|
||||||
|
row._ymax = Math.max.apply Math, row._y
|
||||||
|
|
||||||
# draw the data series
|
# draw the data series
|
||||||
#
|
#
|
||||||
# @private
|
# @private
|
||||||
drawSeries: ->
|
drawSeries: ->
|
||||||
for i in [@options.ykeys.length-1..0]
|
@seriesPoints = []
|
||||||
path = @paths[i]
|
if @options.behaveLikeLine
|
||||||
if path isnt null
|
range = [0..@options.ykeys.length-1]
|
||||||
path = path + "L#{@transX(@xmax)},#{@bottom}L#{@transX(@xmin)},#{@bottom}Z"
|
else
|
||||||
@drawFilledPath(path, @fillForSeries(i))
|
range = [@options.ykeys.length-1..0]
|
||||||
super()
|
|
||||||
|
for i in range
|
||||||
|
@_drawFillFor i
|
||||||
|
@_drawLineFor i
|
||||||
|
@_drawPointFor i
|
||||||
|
|
||||||
|
_drawFillFor: (index) ->
|
||||||
|
path = @paths[index]
|
||||||
|
if path isnt null
|
||||||
|
path = path + "L#{@transX(@xmax)},#{@bottom}L#{@transX(@xmin)},#{@bottom}Z"
|
||||||
|
@drawFilledPath path, @fillForSeries(index)
|
||||||
|
|
||||||
fillForSeries: (i) ->
|
fillForSeries: (i) ->
|
||||||
color = Raphael.rgb2hsl @colorFor(@data[i], i, 'line')
|
color = Raphael.rgb2hsl @colorFor(@data[i], i, 'line')
|
||||||
Raphael.hsl(
|
Raphael.hsl(
|
||||||
color.h,
|
color.h,
|
||||||
Math.min(255, color.s * 0.75),
|
Math.min(255, if @options.behaveLikeLine then color.s * 0.9 else color.s * 0.75),
|
||||||
Math.min(255, color.l * 1.25))
|
Math.min(255, if @options.behaveLikeLine then color.l * 1.2 else color.l * 1.25))
|
||||||
|
|
||||||
drawFilledPath: (path, fill) ->
|
drawFilledPath: (path, fill) ->
|
||||||
@raphael.path(path)
|
@raphael.path(path)
|
||||||
.attr('fill', fill)
|
.attr('fill', fill)
|
||||||
|
.attr('fill-opacity', @options.fillOpacity)
|
||||||
.attr('stroke-width', 0)
|
.attr('stroke-width', 0)
|
||||||
|
@ -166,18 +166,24 @@ class Morris.Line extends Morris.Grid
|
|||||||
#
|
#
|
||||||
# @private
|
# @private
|
||||||
drawSeries: ->
|
drawSeries: ->
|
||||||
|
@seriesPoints = []
|
||||||
for i in [@options.ykeys.length-1..0]
|
for i in [@options.ykeys.length-1..0]
|
||||||
path = @paths[i]
|
@_drawLineFor i
|
||||||
if path isnt null
|
|
||||||
@drawLinePath(path, @colorFor(row, i, 'line')) #row isn't available here?
|
|
||||||
@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
|
@_drawPointFor i
|
||||||
if row._y[i]?
|
|
||||||
circle = @drawLinePoint(row._x, row._y[i], @options.pointSize, @colorFor(row, i, 'point'), i)
|
_drawPointFor: (index) ->
|
||||||
else
|
@seriesPoints[index] = []
|
||||||
circle = null
|
for row in @data
|
||||||
@seriesPoints[i].push(circle)
|
circle = null
|
||||||
|
if row._y[index]?
|
||||||
|
circle = @drawLinePoint(row._x, row._y[index], @options.pointSize, @colorFor(row, index, 'point'), index)
|
||||||
|
@seriesPoints[index].push(circle)
|
||||||
|
|
||||||
|
_drawLineFor: (index) ->
|
||||||
|
path = @paths[index]
|
||||||
|
if path isnt null
|
||||||
|
@drawLinePath path, @colorFor(null, index, 'line')
|
||||||
|
|
||||||
# create a path for a data series
|
# create a path for a data series
|
||||||
#
|
#
|
||||||
|
124
morris.js
124
morris.js
@ -793,42 +793,42 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Line.prototype.drawSeries = function() {
|
Line.prototype.drawSeries = function() {
|
||||||
var circle, i, path, row, _i, _j, _ref, _ref1, _results;
|
var i, _i, _j, _ref, _ref1, _results;
|
||||||
|
this.seriesPoints = [];
|
||||||
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];
|
this._drawLineFor(i);
|
||||||
if (path !== null) {
|
|
||||||
this.drawLinePath(path, this.colorFor(row, i, 'line'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.seriesPoints = (function() {
|
|
||||||
var _j, _ref1, _results;
|
|
||||||
_results = [];
|
|
||||||
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 = [];
|
_results = [];
|
||||||
for (i = _j = _ref1 = this.options.ykeys.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() {
|
_results.push(this._drawPointFor(i));
|
||||||
var _k, _len, _ref2, _results1;
|
|
||||||
_ref2 = this.data;
|
|
||||||
_results1 = [];
|
|
||||||
for (_k = 0, _len = _ref2.length; _k < _len; _k++) {
|
|
||||||
row = _ref2[_k];
|
|
||||||
if (row._y[i] != null) {
|
|
||||||
circle = this.drawLinePoint(row._x, row._y[i], this.options.pointSize, this.colorFor(row, i, 'point'), i);
|
|
||||||
} else {
|
|
||||||
circle = null;
|
|
||||||
}
|
|
||||||
_results1.push(this.seriesPoints[i].push(circle));
|
|
||||||
}
|
|
||||||
return _results1;
|
|
||||||
}).call(this));
|
|
||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Line.prototype._drawPointFor = function(index) {
|
||||||
|
var circle, row, _i, _len, _ref, _results;
|
||||||
|
this.seriesPoints[index] = [];
|
||||||
|
_ref = this.data;
|
||||||
|
_results = [];
|
||||||
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||||
|
row = _ref[_i];
|
||||||
|
circle = null;
|
||||||
|
if (row._y[index] != null) {
|
||||||
|
circle = this.drawLinePoint(row._x, row._y[index], this.options.pointSize, this.colorFor(row, index, 'point'), index);
|
||||||
|
}
|
||||||
|
_results.push(this.seriesPoints[index].push(circle));
|
||||||
|
}
|
||||||
|
return _results;
|
||||||
|
};
|
||||||
|
|
||||||
|
Line.prototype._drawLineFor = function(index) {
|
||||||
|
var path;
|
||||||
|
path = this.paths[index];
|
||||||
|
if (path !== null) {
|
||||||
|
return this.drawLinePath(path, this.colorFor(null, index, 'line'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Line.createPath = function(coords, smooth, bottom) {
|
Line.createPath = function(coords, smooth, bottom) {
|
||||||
var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;
|
var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;
|
||||||
path = "";
|
path = "";
|
||||||
@ -1079,15 +1079,26 @@
|
|||||||
Morris.AUTO_LABEL_ORDER = ["decade", "year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
|
Morris.AUTO_LABEL_ORDER = ["decade", "year", "month", "day", "hour", "30min", "15min", "10min", "5min", "minute", "30sec", "15sec", "10sec", "5sec", "second"];
|
||||||
|
|
||||||
Morris.Area = (function(_super) {
|
Morris.Area = (function(_super) {
|
||||||
|
var areaDefaults;
|
||||||
|
|
||||||
__extends(Area, _super);
|
__extends(Area, _super);
|
||||||
|
|
||||||
|
areaDefaults = {
|
||||||
|
fillOpacity: 'auto',
|
||||||
|
behaveLikeLine: false
|
||||||
|
};
|
||||||
|
|
||||||
function Area(options) {
|
function Area(options) {
|
||||||
|
var areaOptions;
|
||||||
if (!(this instanceof Morris.Area)) {
|
if (!(this instanceof Morris.Area)) {
|
||||||
return new Morris.Area(options);
|
return new Morris.Area(options);
|
||||||
}
|
}
|
||||||
this.cumulative = true;
|
areaOptions = $.extend({}, areaDefaults, options);
|
||||||
Area.__super__.constructor.call(this, options);
|
this.cumulative = !areaOptions.behaveLikeLine;
|
||||||
|
if (areaOptions.fillOpacity === 'auto') {
|
||||||
|
areaOptions.fillOpacity = areaOptions.behaveLikeLine ? .8 : 1;
|
||||||
|
}
|
||||||
|
Area.__super__.constructor.call(this, areaOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
Area.prototype.calcPoints = function() {
|
Area.prototype.calcPoints = function() {
|
||||||
@ -1104,36 +1115,63 @@
|
|||||||
_results1 = [];
|
_results1 = [];
|
||||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||||
y = _ref1[_j];
|
y = _ref1[_j];
|
||||||
total += y || 0;
|
if (this.options.behaveLikeLine) {
|
||||||
_results1.push(this.transY(total));
|
_results1.push(this.transY(y));
|
||||||
|
} else {
|
||||||
|
total += y || 0;
|
||||||
|
_results1.push(this.transY(total));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return _results1;
|
return _results1;
|
||||||
}).call(this);
|
}).call(this);
|
||||||
_results.push(row._ymax = row._y[row._y.length - 1]);
|
_results.push(row._ymax = Math.max.apply(Math, row._y));
|
||||||
}
|
}
|
||||||
return _results;
|
return _results;
|
||||||
};
|
};
|
||||||
|
|
||||||
Area.prototype.drawSeries = function() {
|
Area.prototype.drawSeries = function() {
|
||||||
var i, path, _i, _ref;
|
var i, range, _i, _j, _k, _len, _ref, _ref1, _results, _results1, _results2;
|
||||||
for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
|
this.seriesPoints = [];
|
||||||
path = this.paths[i];
|
if (this.options.behaveLikeLine) {
|
||||||
if (path !== null) {
|
range = (function() {
|
||||||
path = path + ("L" + (this.transX(this.xmax)) + "," + this.bottom + "L" + (this.transX(this.xmin)) + "," + this.bottom + "Z");
|
_results = [];
|
||||||
this.drawFilledPath(path, this.fillForSeries(i));
|
for (var _i = 0, _ref = this.options.ykeys.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }
|
||||||
}
|
return _results;
|
||||||
|
}).apply(this);
|
||||||
|
} else {
|
||||||
|
range = (function() {
|
||||||
|
_results1 = [];
|
||||||
|
for (var _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; _ref1 <= 0 ? _j++ : _j--){ _results1.push(_j); }
|
||||||
|
return _results1;
|
||||||
|
}).apply(this);
|
||||||
|
}
|
||||||
|
_results2 = [];
|
||||||
|
for (_k = 0, _len = range.length; _k < _len; _k++) {
|
||||||
|
i = range[_k];
|
||||||
|
this._drawFillFor(i);
|
||||||
|
this._drawLineFor(i);
|
||||||
|
_results2.push(this._drawPointFor(i));
|
||||||
|
}
|
||||||
|
return _results2;
|
||||||
|
};
|
||||||
|
|
||||||
|
Area.prototype._drawFillFor = function(index) {
|
||||||
|
var path;
|
||||||
|
path = this.paths[index];
|
||||||
|
if (path !== null) {
|
||||||
|
path = path + ("L" + (this.transX(this.xmax)) + "," + this.bottom + "L" + (this.transX(this.xmin)) + "," + this.bottom + "Z");
|
||||||
|
return this.drawFilledPath(path, this.fillForSeries(index));
|
||||||
}
|
}
|
||||||
return Area.__super__.drawSeries.call(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Area.prototype.fillForSeries = function(i) {
|
Area.prototype.fillForSeries = function(i) {
|
||||||
var color;
|
var color;
|
||||||
color = Raphael.rgb2hsl(this.colorFor(this.data[i], i, 'line'));
|
color = Raphael.rgb2hsl(this.colorFor(this.data[i], i, 'line'));
|
||||||
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, this.options.behaveLikeLine ? color.s * 0.9 : color.s * 0.75), Math.min(255, this.options.behaveLikeLine ? color.l * 1.2 : color.l * 1.25));
|
||||||
};
|
};
|
||||||
|
|
||||||
Area.prototype.drawFilledPath = function(path, fill) {
|
Area.prototype.drawFilledPath = function(path, fill) {
|
||||||
return this.raphael.path(path).attr('fill', fill).attr('stroke-width', 0);
|
return this.raphael.path(path).attr('fill', fill).attr('fill-opacity', this.options.fillOpacity).attr('stroke-width', 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
return Area;
|
return Area;
|
||||||
|
2
morris.min.js
vendored
2
morris.min.js
vendored
File diff suppressed because one or more lines are too long
@ -42,6 +42,19 @@ describe 'Morris.Area', ->
|
|||||||
gridTextColor: '#888'
|
gridTextColor: '#888'
|
||||||
gridTextSize: 12
|
gridTextSize: 12
|
||||||
|
|
||||||
|
it 'should not be cumulative if behaveLikeLine', ->
|
||||||
|
chart = Morris.Area $.extend {}, defaults, behaveLikeLine: true
|
||||||
|
chart.cumulative.should.equal false
|
||||||
|
|
||||||
|
it 'should have a line with transparent fill if behaveLikeLine', ->
|
||||||
|
chart = Morris.Area $.extend {}, defaults, behaveLikeLine: true
|
||||||
|
$('#graph').find("path[fill-opacity='0.8']").size().should.equal 1
|
||||||
|
|
||||||
|
it 'should not have a line with transparent fill', ->
|
||||||
|
chart = Morris.Area $.extend {}, defaults
|
||||||
|
$('#graph').find("path[fill-opacity='0.8']").size().should.equal 0
|
||||||
|
|
||||||
it 'should have a line with the fill of a modified line color', ->
|
it 'should have a line with the fill of a modified line color', ->
|
||||||
chart = Morris.Area $.extend {}, defaults
|
chart = Morris.Area $.extend {}, defaults
|
||||||
$('#graph').find("path[fill='#2577b5']").size().should.equal 1
|
$('#graph').find("path[fill='#0b62a4']").size().should.equal 0
|
||||||
|
$('#graph').find("path[fill='#7a92a3']").size().should.equal 0
|
||||||
|
Loading…
Reference in New Issue
Block a user