mirror of
https://github.com/morrisjs/morris.js.git
synced 2024-09-21 10:41:32 +02:00
Merged custom sort, etc
This commit is contained in:
commit
2d2a2d4ebd
@ -25,6 +25,13 @@ Fork, hack, send a pull request :)
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### 0.2.6 - 17th March 2012
|
||||||
|
|
||||||
|
- The X labels can be disabled (with `drawXlabels` option, default is true)
|
||||||
|
- The Y labels can be disabled (with `drawYlabels` option, default is true)
|
||||||
|
- The automatic data sort can be disabled (with `sortData` option, default is true)
|
||||||
|
- The options.data can be sorted via custom function (with `sortDataFunction` option, default is null)
|
||||||
|
|
||||||
### 0.2.5 - 15th March 2012
|
### 0.2.5 - 15th March 2012
|
||||||
|
|
||||||
- Raw millisecond timestamp support (with `dateFormat` option)
|
- Raw millisecond timestamp support (with `dateFormat` option)
|
||||||
|
39
examples/custom-sort.html
Normal file
39
examples/custom-sort.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!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">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Custom data sort</h1>
|
||||||
|
<div id="graph"></div>
|
||||||
|
<pre id="code" class="prettyprint linenums">
|
||||||
|
var data = [
|
||||||
|
{"elapsed": "I", "value": 34},
|
||||||
|
{"elapsed": "II", "value": 24},
|
||||||
|
{"elapsed": "III", "value": 3},
|
||||||
|
{"elapsed": "IV", "value": 12},
|
||||||
|
{"elapsed": "V", "value": 13},
|
||||||
|
{"elapsed": "VI", "value": 22},
|
||||||
|
{"elapsed": "VII", "value": 5},
|
||||||
|
{"elapsed": "VIII", "value": 26},
|
||||||
|
{"elapsed": "IX", "value": 12},
|
||||||
|
{"elapsed": "X", "value": 19},
|
||||||
|
];
|
||||||
|
Morris.Line({
|
||||||
|
element: 'graph',
|
||||||
|
data: data,
|
||||||
|
xkey: 'elapsed',
|
||||||
|
ykeys: ['value'],
|
||||||
|
labels: ['value'],
|
||||||
|
parseTime: false,
|
||||||
|
sortDataFunction: function(a,b){
|
||||||
|
return a["value"] < b["value"];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
</body>
|
38
examples/no-xylabels.html
Normal file
38
examples/no-xylabels.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!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">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Disable X and Y labels</h1>
|
||||||
|
<div id="graph"></div>
|
||||||
|
<pre id="code" class="prettyprint linenums">
|
||||||
|
var timestamp_data = [
|
||||||
|
{"period": 1349046000000, "licensed": 3407, "sorned": 660},
|
||||||
|
{"period": 1313103600000, "licensed": 3351, "sorned": 629},
|
||||||
|
{"period": 1299110400000, "licensed": 3269, "sorned": 618},
|
||||||
|
{"period": 1281222000000, "licensed": 3246, "sorned": 661},
|
||||||
|
{"period": 1273446000000, "licensed": 3257, "sorned": 667},
|
||||||
|
{"period": 1268524800000, "licensed": 3248, "sorned": 627},
|
||||||
|
{"period": 1263081600000, "licensed": 3171, "sorned": 660},
|
||||||
|
{"period": 1260403200000, "licensed": 3171, "sorned": 676},
|
||||||
|
{"period": 1254870000000, "licensed": 3201, "sorned": 656},
|
||||||
|
{"period": 1253833200000, "licensed": 3215, "sorned": 622}
|
||||||
|
];
|
||||||
|
Morris.Line({
|
||||||
|
element: 'graph',
|
||||||
|
data: timestamp_data,
|
||||||
|
xkey: 'period',
|
||||||
|
ykeys: ['licensed', 'sorned'],
|
||||||
|
labels: ['Licensed', 'SORN'],
|
||||||
|
drawYlabel: false,
|
||||||
|
drawXlabel: false,
|
||||||
|
dateFormat: function (x) { return new Date(x).toDateString(); }
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
</body>
|
130
morris.coffee
130
morris.coffee
@ -63,12 +63,20 @@ class Morris.Line
|
|||||||
xlabel: 'year'
|
xlabel: 'year'
|
||||||
xlabelMargin: 50
|
xlabelMargin: 50
|
||||||
dateFormat: (x) -> new Date(x).toString()
|
dateFormat: (x) -> new Date(x).toString()
|
||||||
|
sortData: true
|
||||||
|
sortDataFunction: null
|
||||||
|
drawYlabel: true
|
||||||
|
drawXlabel: true
|
||||||
|
|
||||||
# Do any necessary pre-processing for a new dataset
|
# Do any necessary pre-processing for a new dataset
|
||||||
#
|
#
|
||||||
precalc: ->
|
precalc: ->
|
||||||
# sort data
|
# sort data
|
||||||
@options.data.sort (a, b) => (a[@options.xkey] < b[@options.xkey]) - (b[@options.xkey] < a[@options.xkey])
|
if @options.sortData
|
||||||
|
if typeof @options.sortDataFunction isnt 'function'
|
||||||
|
@options.data.sort (a,b) => (a[@options.xkey] < b[@options.xkey]) - (b[@options.xkey] < a[@options.xkey])
|
||||||
|
else
|
||||||
|
@options.data.sort @options.sortDataFunction
|
||||||
# extract labels
|
# extract labels
|
||||||
@columnLabels = $.map @options.data, (d) => d[@options.xkey]
|
@columnLabels = $.map @options.data, (d) => d[@options.xkey]
|
||||||
@seriesLabels = @options.labels
|
@seriesLabels = @options.labels
|
||||||
@ -147,74 +155,76 @@ class Morris.Line
|
|||||||
for lineY in [firstY..lastY] by yInterval
|
for lineY in [firstY..lastY] by yInterval
|
||||||
v = Math.floor(lineY)
|
v = Math.floor(lineY)
|
||||||
y = transY(v)
|
y = transY(v)
|
||||||
@r.text(left - @options.marginLeft/2, y, v + @options.units)
|
if @options.drawYlabels
|
||||||
.attr('font-size', @options.gridTextSize)
|
@r.text(left - @options.marginLeft/2, y, v + @options.units)
|
||||||
.attr('fill', @options.gridTextColor)
|
.attr('font-size', @options.gridTextSize)
|
||||||
.attr('text-anchor', 'end')
|
.attr('fill', @options.gridTextColor)
|
||||||
|
.attr('text-anchor', 'end')
|
||||||
@r.path("M" + left + "," + y + 'H' + (left + width))
|
@r.path("M" + left + "," + y + 'H' + (left + width))
|
||||||
.attr('stroke', @options.gridLineColor)
|
.attr('stroke', @options.gridLineColor)
|
||||||
.attr('stroke-width', @options.gridStrokeWidth)
|
.attr('stroke-width', @options.gridStrokeWidth)
|
||||||
|
|
||||||
## draw x axis labels
|
## draw x axis labels (if enabled)
|
||||||
prevLabelMargin = null
|
if @options.drawXlabel
|
||||||
xLabelMargin = @options.xlabelMargin # make this an option?
|
prevLabelMargin = null
|
||||||
xLabel = @options.xlabel
|
xLabelMargin = @options.xlabelMargin # make this an option?
|
||||||
nextLabel = (cur) -> # cur is a Date()
|
xLabel = @options.xlabel
|
||||||
switch xLabel
|
nextLabel = (cur) -> # cur is a Date()
|
||||||
when 'day'
|
switch xLabel
|
||||||
new Date(cur.getFullYear(), cur.getMonth(), cur.getDate() + 1, 0)
|
when 'day'
|
||||||
when 'month'
|
new Date(cur.getFullYear(), cur.getMonth(), cur.getDate() + 1, 0)
|
||||||
if cur.getMonth() == 11
|
when 'month'
|
||||||
|
if cur.getMonth() == 11
|
||||||
|
new Date(cur.getFullYear() + 1, 0, 1)
|
||||||
|
else
|
||||||
|
new Date(cur.getFullYear(), cur.getMonth() + 1, 1)
|
||||||
|
else # default: year
|
||||||
new Date(cur.getFullYear() + 1, 0, 1)
|
new Date(cur.getFullYear() + 1, 0, 1)
|
||||||
else
|
startLabel = (cur) -> # cur is a Date()
|
||||||
new Date(cur.getFullYear(), cur.getMonth() + 1, 1)
|
if xLabel == 'day' and cur.getHours() == 0
|
||||||
else # default: year
|
cur
|
||||||
new Date(cur.getFullYear() + 1, 0, 1)
|
else if xLabel == 'month' and cur.getDate() == 1
|
||||||
startLabel = (cur) -> # cur is a Date()
|
cur
|
||||||
if xLabel == 'day' and cur.getHours() == 0
|
else if xLabel == 'year' and cur.getDate() == 1 && cur.getMonth() == 0
|
||||||
cur
|
cur
|
||||||
else if xLabel == 'month' and cur.getDate() == 1
|
else
|
||||||
cur
|
nextLabel(cur)
|
||||||
else if xLabel == 'year' and cur.getDate() == 1 && cur.getMonth() == 0
|
labelText = (cur) -> # cur is still a Date()
|
||||||
cur
|
switch xLabel
|
||||||
else
|
when 'day'
|
||||||
nextLabel(cur)
|
d = cur.getDate().toString()
|
||||||
labelText = (cur) -> # cur is still a Date()
|
if d.length == 2 then d else '0' + d
|
||||||
switch xLabel
|
when 'month'
|
||||||
when 'day'
|
m = (cur.getMonth() + 1).toString()
|
||||||
d = cur.getDate().toString()
|
if m.length == 2 then m else '0' + m
|
||||||
if d.length == 2 then d else '0' + d
|
else cur.getFullYear()
|
||||||
when 'month'
|
|
||||||
m = (cur.getMonth() + 1).toString()
|
|
||||||
if m.length == 2 then m else '0' + m
|
|
||||||
else cur.getFullYear()
|
|
||||||
|
|
||||||
r = @r
|
r = @r
|
||||||
options = @options
|
options = @options
|
||||||
renderLabel = (xpos, text) ->
|
renderLabel = (xpos, text) ->
|
||||||
label = r.text(transX(xpos), options.marginTop + height + options.marginBottom / 2, text)
|
label = r.text(transX(xpos), options.marginTop + height + options.marginBottom / 2, text)
|
||||||
.attr('font-size', options.gridTextSize)
|
.attr('font-size', options.gridTextSize)
|
||||||
.attr('fill', options.gridTextColor)
|
.attr('fill', options.gridTextColor)
|
||||||
labelBox = label.getBBox()
|
labelBox = label.getBBox()
|
||||||
# ensure a minimum of `xLabelMargin` pixels between labels
|
# ensure a minimum of `xLabelMargin` pixels between labels
|
||||||
if prevLabelMargin is null or prevLabelMargin <= labelBox.x
|
if prevLabelMargin is null or prevLabelMargin <= labelBox.x
|
||||||
prevLabelMargin = labelBox.x + labelBox.width + xLabelMargin
|
prevLabelMargin = labelBox.x + labelBox.width + xLabelMargin
|
||||||
else
|
else
|
||||||
label.remove()
|
label.remove()
|
||||||
|
|
||||||
if @options.parseTime
|
if @options.parseTime
|
||||||
start = startLabel(new Date(@xmin))
|
start = startLabel(new Date(@xmin))
|
||||||
end = new Date(@xmax)
|
end = new Date(@xmax)
|
||||||
cur = start
|
cur = start
|
||||||
while cur <= end
|
while cur <= end
|
||||||
xpos = cur.getTime()
|
xpos = cur.getTime()
|
||||||
if xpos < @xmin
|
if xpos < @xmin
|
||||||
continue
|
continue
|
||||||
renderLabel(xpos, labelText cur)
|
renderLabel(xpos, labelText cur)
|
||||||
cur = nextLabel cur
|
cur = nextLabel cur
|
||||||
else
|
else
|
||||||
for i in [@xmin..@xmax]
|
for i in [@xmin..@xmax]
|
||||||
renderLabel(i, @columnLabels[@columnLabels.length-i-1])
|
renderLabel(i, @columnLabels[@columnLabels.length-i-1])
|
||||||
|
|
||||||
# draw the actual series
|
# draw the actual series
|
||||||
columns = (transX(x) for x in @xvals)
|
columns = (transX(x) for x in @xvals)
|
||||||
|
174
morris.js
174
morris.js
@ -53,15 +53,25 @@
|
|||||||
xlabelMargin: 50,
|
xlabelMargin: 50,
|
||||||
dateFormat: function(x) {
|
dateFormat: function(x) {
|
||||||
return new Date(x).toString();
|
return new Date(x).toString();
|
||||||
}
|
},
|
||||||
|
sortData: true,
|
||||||
|
sortDataFunction: null,
|
||||||
|
drawYlabel: true,
|
||||||
|
drawXlabel: true
|
||||||
};
|
};
|
||||||
|
|
||||||
Line.prototype.precalc = function() {
|
Line.prototype.precalc = function() {
|
||||||
var ykey, ymax, ymin, _i, _j, _len, _ref, _ref2, _results,
|
var ykey, ymax, ymin, _i, _j, _len, _ref, _ref2, _results,
|
||||||
_this = this;
|
_this = this;
|
||||||
this.options.data.sort(function(a, b) {
|
if (this.options.sortData) {
|
||||||
return (a[_this.options.xkey] < b[_this.options.xkey]) - (b[_this.options.xkey] < a[_this.options.xkey]);
|
if (typeof this.options.sortDataFunction !== 'function') {
|
||||||
});
|
this.options.data.sort(function(a, b) {
|
||||||
|
return (a[_this.options.xkey] < b[_this.options.xkey]) - (b[_this.options.xkey] < a[_this.options.xkey]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.options.data.sort(this.options.sortDataFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.columnLabels = $.map(this.options.data, function(d) {
|
this.columnLabels = $.map(this.options.data, function(d) {
|
||||||
return d[_this.options.xkey];
|
return d[_this.options.xkey];
|
||||||
});
|
});
|
||||||
@ -145,86 +155,90 @@
|
|||||||
for (lineY = firstY; firstY <= lastY ? lineY <= lastY : lineY >= lastY; lineY += yInterval) {
|
for (lineY = firstY; firstY <= lastY ? lineY <= lastY : lineY >= lastY; lineY += yInterval) {
|
||||||
v = Math.floor(lineY);
|
v = Math.floor(lineY);
|
||||||
y = transY(v);
|
y = transY(v);
|
||||||
this.r.text(left - this.options.marginLeft / 2, y, v + this.options.units).attr('font-size', this.options.gridTextSize).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end');
|
if (this.options.drawYlabels) {
|
||||||
|
this.r.text(left - this.options.marginLeft / 2, y, v + this.options.units).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);
|
||||||
}
|
}
|
||||||
prevLabelMargin = null;
|
if (this.options.drawXlabel) {
|
||||||
xLabelMargin = this.options.xlabelMargin;
|
prevLabelMargin = null;
|
||||||
xLabel = this.options.xlabel;
|
xLabelMargin = this.options.xlabelMargin;
|
||||||
nextLabel = function(cur) {
|
xLabel = this.options.xlabel;
|
||||||
switch (xLabel) {
|
nextLabel = function(cur) {
|
||||||
case 'day':
|
switch (xLabel) {
|
||||||
return new Date(cur.getFullYear(), cur.getMonth(), cur.getDate() + 1, 0);
|
case 'day':
|
||||||
case 'month':
|
return new Date(cur.getFullYear(), cur.getMonth(), cur.getDate() + 1, 0);
|
||||||
if (cur.getMonth() === 11) {
|
case 'month':
|
||||||
|
if (cur.getMonth() === 11) {
|
||||||
|
return new Date(cur.getFullYear() + 1, 0, 1);
|
||||||
|
} else {
|
||||||
|
return new Date(cur.getFullYear(), cur.getMonth() + 1, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return new Date(cur.getFullYear() + 1, 0, 1);
|
return new Date(cur.getFullYear() + 1, 0, 1);
|
||||||
} else {
|
}
|
||||||
return new Date(cur.getFullYear(), cur.getMonth() + 1, 1);
|
};
|
||||||
}
|
startLabel = function(cur) {
|
||||||
break;
|
if (xLabel === 'day' && cur.getHours() === 0) {
|
||||||
default:
|
return cur;
|
||||||
return new Date(cur.getFullYear() + 1, 0, 1);
|
} else if (xLabel === 'month' && cur.getDate() === 1) {
|
||||||
}
|
return cur;
|
||||||
};
|
} else if (xLabel === 'year' && cur.getDate() === 1 && cur.getMonth() === 0) {
|
||||||
startLabel = function(cur) {
|
return cur;
|
||||||
if (xLabel === 'day' && cur.getHours() === 0) {
|
} else {
|
||||||
return cur;
|
return nextLabel(cur);
|
||||||
} else if (xLabel === 'month' && cur.getDate() === 1) {
|
}
|
||||||
return cur;
|
};
|
||||||
} else if (xLabel === 'year' && cur.getDate() === 1 && cur.getMonth() === 0) {
|
labelText = function(cur) {
|
||||||
return cur;
|
var d, m;
|
||||||
|
switch (xLabel) {
|
||||||
|
case 'day':
|
||||||
|
d = cur.getDate().toString();
|
||||||
|
if (d.length === 2) {
|
||||||
|
return d;
|
||||||
|
} else {
|
||||||
|
return '0' + d;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'month':
|
||||||
|
m = (cur.getMonth() + 1).toString();
|
||||||
|
if (m.length === 2) {
|
||||||
|
return m;
|
||||||
|
} else {
|
||||||
|
return '0' + m;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return cur.getFullYear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
r = this.r;
|
||||||
|
options = this.options;
|
||||||
|
renderLabel = function(xpos, text) {
|
||||||
|
var label, labelBox;
|
||||||
|
label = r.text(transX(xpos), options.marginTop + height + options.marginBottom / 2, text).attr('font-size', options.gridTextSize).attr('fill', options.gridTextColor);
|
||||||
|
labelBox = label.getBBox();
|
||||||
|
if (prevLabelMargin === null || prevLabelMargin <= labelBox.x) {
|
||||||
|
return prevLabelMargin = labelBox.x + labelBox.width + xLabelMargin;
|
||||||
|
} else {
|
||||||
|
return label.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (this.options.parseTime) {
|
||||||
|
start = startLabel(new Date(this.xmin));
|
||||||
|
end = new Date(this.xmax);
|
||||||
|
cur = start;
|
||||||
|
while (cur <= end) {
|
||||||
|
xpos = cur.getTime();
|
||||||
|
if (xpos < this.xmin) continue;
|
||||||
|
renderLabel(xpos, labelText(cur));
|
||||||
|
cur = nextLabel(cur);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return nextLabel(cur);
|
for (i = _ref = this.xmin, _ref2 = this.xmax; _ref <= _ref2 ? i <= _ref2 : i >= _ref2; _ref <= _ref2 ? i++ : i--) {
|
||||||
}
|
renderLabel(i, this.columnLabels[this.columnLabels.length - i - 1]);
|
||||||
};
|
}
|
||||||
labelText = function(cur) {
|
|
||||||
var d, m;
|
|
||||||
switch (xLabel) {
|
|
||||||
case 'day':
|
|
||||||
d = cur.getDate().toString();
|
|
||||||
if (d.length === 2) {
|
|
||||||
return d;
|
|
||||||
} else {
|
|
||||||
return '0' + d;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
m = (cur.getMonth() + 1).toString();
|
|
||||||
if (m.length === 2) {
|
|
||||||
return m;
|
|
||||||
} else {
|
|
||||||
return '0' + m;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return cur.getFullYear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
r = this.r;
|
|
||||||
options = this.options;
|
|
||||||
renderLabel = function(xpos, text) {
|
|
||||||
var label, labelBox;
|
|
||||||
label = r.text(transX(xpos), options.marginTop + height + options.marginBottom / 2, text).attr('font-size', options.gridTextSize).attr('fill', options.gridTextColor);
|
|
||||||
labelBox = label.getBBox();
|
|
||||||
if (prevLabelMargin === null || prevLabelMargin <= labelBox.x) {
|
|
||||||
return prevLabelMargin = labelBox.x + labelBox.width + xLabelMargin;
|
|
||||||
} else {
|
|
||||||
return label.remove();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (this.options.parseTime) {
|
|
||||||
start = startLabel(new Date(this.xmin));
|
|
||||||
end = new Date(this.xmax);
|
|
||||||
cur = start;
|
|
||||||
while (cur <= end) {
|
|
||||||
xpos = cur.getTime();
|
|
||||||
if (xpos < this.xmin) continue;
|
|
||||||
renderLabel(xpos, labelText(cur));
|
|
||||||
cur = nextLabel(cur);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (i = _ref = this.xmin, _ref2 = this.xmax; _ref <= _ref2 ? i <= _ref2 : i >= _ref2; _ref <= _ref2 ? i++ : i--) {
|
|
||||||
renderLabel(i, this.columnLabels[this.columnLabels.length - i - 1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
columns = (function() {
|
columns = (function() {
|
||||||
|
2
morris.min.js
vendored
2
morris.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user