Commit 43e3a70d authored by Mark Côté's avatar Mark Côté

Merge pull request #900 from markrcote/master

Add nonstandard %q datetime specifier for quarters.
parents 3640b939 0d47f513
...@@ -585,7 +585,7 @@ xaxis: { ...@@ -585,7 +585,7 @@ xaxis: {
``` ```
This will result in tick labels like "2000/12/24". A subset of the This will result in tick labels like "2000/12/24". A subset of the
standard strftime specifiers are supported: standard strftime specifiers are supported (plus the nonstandard %q):
```js ```js
%a: weekday name (customizable) %a: weekday name (customizable)
...@@ -596,6 +596,7 @@ standard strftime specifiers are supported: ...@@ -596,6 +596,7 @@ standard strftime specifiers are supported:
%I: hours, 12-hour time, zero-padded (01-12) %I: hours, 12-hour time, zero-padded (01-12)
%m: month, zero-padded (01-12) %m: month, zero-padded (01-12)
%M: minutes, zero-padded (00-59) %M: minutes, zero-padded (00-59)
%q: quarter (1-4)
%S: seconds, zero-padded (00-59) %S: seconds, zero-padded (00-59)
%y: year (two digits) %y: year (two digits)
%Y: year (four digits) %Y: year (four digits)
......
...@@ -13,9 +13,9 @@ the dates are displayed. If null, the dates are displayed as UTC. If ...@@ -13,9 +13,9 @@ the dates are displayed. If null, the dates are displayed as UTC. If
"browser", the dates are displayed in the time zone of the user's browser. "browser", the dates are displayed in the time zone of the user's browser.
Date/time formatting has changed and now follows a proper subset of the Date/time formatting has changed and now follows a proper subset of the
standard strftime specifiers. Additionally, if a strftime function is found in standard strftime specifiers, plus one nonstandard specifier for quarters.
the Date object's prototype, it will be used instead of the built-in Additionally, if a strftime function is found in the Date object's prototype,
formatter. it will be used instead of the built-in formatter.
Axis labels are now drawn with canvas text with some parsing to support Axis labels are now drawn with canvas text with some parsing to support
newlines. This solves various issues but also means that they no longer newlines. This solves various issues but also means that they no longer
...@@ -29,6 +29,9 @@ The base and overlay canvas are now using the CSS classes "flot-base" and ...@@ -29,6 +29,9 @@ The base and overlay canvas are now using the CSS classes "flot-base" and
### Changes ### ### Changes ###
- Addition of nonstandard %q specifier to date/time formatting. (patch
by risicle, issue 49)
- Date/time formatting follows proper subset of strftime specifiers, and - Date/time formatting follows proper subset of strftime specifiers, and
support added for Date.prototype.strftime, if found. (patch by Mark Cote, support added for Date.prototype.strftime, if found. (patch by Mark Cote,
issues 419 and 558) issues 419 and 558)
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
<p>Zoom to: <button id="whole">Whole period</button> <p>Zoom to: <button id="whole">Whole period</button>
<button id="nineties">1990-2000</button> <button id="nineties">1990-2000</button>
<button id="latenineties">1996-2000</button> <button id="latenineties">1996-2000</button>
<button id="ninetyninequarters">1999 by quarter</button>
<button id="ninetynine">1999</button> <button id="ninetynine">1999</button>
<button id="lastweekninetynine">end of 1999</button> <button id="lastweekninetynine">end of 1999</button>
<button id="lastdayninetynine">very end of 1999</button></p> <button id="lastdayninetynine">very end of 1999</button></p>
...@@ -69,6 +70,17 @@ $(function () { ...@@ -69,6 +70,17 @@ $(function () {
}); });
}); });
$("#ninetyninequarters").click(function () {
$.plot($("#placeholder"), [d], {
xaxis: {
mode: "time",
minTickSize: [1, "quarter"],
min: (new Date(1999, 0, 1)).getTime(),
max: (new Date(2000, 0, 1)).getTime()
}
});
});
$("#ninetynine").click(function () { $("#ninetynine").click(function () {
$.plot($("#placeholder"), [d], { $.plot($("#placeholder"), [d], {
xaxis: { xaxis: {
......
...@@ -71,6 +71,9 @@ API.txt for details. ...@@ -71,6 +71,9 @@ API.txt for details.
case 'l': c = leftPad(hours12, " "); break; case 'l': c = leftPad(hours12, " "); break;
case 'm': c = leftPad(d.getMonth() + 1); break; case 'm': c = leftPad(d.getMonth() + 1); break;
case 'M': c = leftPad(d.getMinutes()); break; case 'M': c = leftPad(d.getMinutes()); break;
// quarters not in Open Group's strftime specification
case 'q':
c = "" + (Math.floor(d.getMonth() / 3) + 1); break;
case 'S': c = leftPad(d.getSeconds()); break; case 'S': c = leftPad(d.getSeconds()); break;
case 'y': c = leftPad(d.getFullYear() % 100); break; case 'y': c = leftPad(d.getFullYear() % 100); break;
case 'Y': c = "" + d.getFullYear(); break; case 'Y': c = "" + d.getFullYear(); break;
...@@ -156,13 +159,14 @@ API.txt for details. ...@@ -156,13 +159,14 @@ API.txt for details.
"hour": 60 * 60 * 1000, "hour": 60 * 60 * 1000,
"day": 24 * 60 * 60 * 1000, "day": 24 * 60 * 60 * 1000,
"month": 30 * 24 * 60 * 60 * 1000, "month": 30 * 24 * 60 * 60 * 1000,
"quarter": 3 * 30 * 24 * 60 * 60 * 1000,
"year": 365.2425 * 24 * 60 * 60 * 1000 "year": 365.2425 * 24 * 60 * 60 * 1000
}; };
// the allowed tick sizes, after 1 year we use // the allowed tick sizes, after 1 year we use
// an integer algorithm // an integer algorithm
var spec = [ var baseSpec = [
[1, "second"], [2, "second"], [5, "second"], [10, "second"], [1, "second"], [2, "second"], [5, "second"], [10, "second"],
[30, "second"], [30, "second"],
[1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
...@@ -171,10 +175,17 @@ API.txt for details. ...@@ -171,10 +175,17 @@ API.txt for details.
[8, "hour"], [12, "hour"], [8, "hour"], [12, "hour"],
[1, "day"], [2, "day"], [3, "day"], [1, "day"], [2, "day"], [3, "day"],
[0.25, "month"], [0.5, "month"], [1, "month"], [0.25, "month"], [0.5, "month"], [1, "month"],
[2, "month"], [3, "month"], [6, "month"], [2, "month"]
[1, "year"]
]; ];
// we don't know which variant(s) we'll need yet, but generating both is
// cheap
var specMonths = baseSpec.concat([[3, "month"], [6, "month"],
[1, "year"]]);
var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"],
[1, "year"]]);
function init(plot) { function init(plot) {
plot.hooks.processDatapoints.push(function (plot, series, datapoints) { plot.hooks.processDatapoints.push(function (plot, series, datapoints) {
$.each(plot.getAxes(), function(axisName, axis) { $.each(plot.getAxes(), function(axisName, axis) {
...@@ -188,6 +199,14 @@ API.txt for details. ...@@ -188,6 +199,14 @@ API.txt for details.
var d = dateGenerator(axis.min, opts); var d = dateGenerator(axis.min, opts);
var minSize = 0; var minSize = 0;
// make quarter use a possibility if quarters are
// mentioned in either of these options
var spec = (opts.tickSize && opts.tickSize[1] ===
"quarter") ||
(opts.minTickSize && opts.minTickSize[1] ===
"quarter") ? specQuarters : specMonths;
if (opts.minTickSize != null) { if (opts.minTickSize != null) {
if (typeof opts.tickSize == "number") { if (typeof opts.tickSize == "number") {
minSize = opts.tickSize; minSize = opts.tickSize;
...@@ -255,6 +274,9 @@ API.txt for details. ...@@ -255,6 +274,9 @@ API.txt for details.
d.setHours(floorInBase(d.getHours(), tickSize)); d.setHours(floorInBase(d.getHours(), tickSize));
} else if (unit == "month") { } else if (unit == "month") {
d.setMonth(floorInBase(d.getMonth(), tickSize)); d.setMonth(floorInBase(d.getMonth(), tickSize));
} else if (unit == "quarter") {
d.setMonth(3 * floorInBase(d.getMonth() / 3,
tickSize));
} else if (unit == "year") { } else if (unit == "year") {
d.setFullYear(floorInBase(d.getFullYear(), tickSize)); d.setFullYear(floorInBase(d.getFullYear(), tickSize));
} }
...@@ -271,6 +293,10 @@ API.txt for details. ...@@ -271,6 +293,10 @@ API.txt for details.
d.setHours(0); d.setHours(0);
} else if (step >= timeUnitSize.day * 4) { } else if (step >= timeUnitSize.day * 4) {
d.setDate(1); d.setDate(1);
} else if (step >= timeUnitSize.month * 2) {
d.setMonth(floorInBase(d.getMonth(), 3));
} else if (step >= timeUnitSize.quarter * 2) {
d.setMonth(floorInBase(d.getMonth(), 6));
} else if (step >= timeUnitSize.year) { } else if (step >= timeUnitSize.year) {
d.setMonth(0); d.setMonth(0);
} }
...@@ -285,22 +311,25 @@ API.txt for details. ...@@ -285,22 +311,25 @@ API.txt for details.
v = d.getTime(); v = d.getTime();
ticks.push(v); ticks.push(v);
if (unit == "month") { if (unit == "month" || unit == "quarter") {
if (tickSize < 1) { if (tickSize < 1) {
// a bit complicated - we'll divide the month // a bit complicated - we'll divide the
// up but we need to take care of fractions // month/quarter up but we need to take
// so we don't end up in the middle of a day // care of fractions so we don't end up in
// the middle of a day
d.setDate(1); d.setDate(1);
var start = d.getTime(); var start = d.getTime();
d.setMonth(d.getMonth() + 1); d.setMonth(d.getMonth() +
(unit == "quarter" ? 3 : 1));
var end = d.getTime(); var end = d.getTime();
d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize); d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
carry = d.getHours(); carry = d.getHours();
d.setHours(0); d.setHours(0);
} else { } else {
d.setMonth(d.getMonth() + tickSize); d.setMonth(d.getMonth() +
tickSize * (unit == "quarter" ? 3 : 1));
} }
} else if (unit == "year") { } else if (unit == "year") {
d.setFullYear(d.getFullYear() + tickSize); d.setFullYear(d.getFullYear() + tickSize);
...@@ -322,6 +351,14 @@ API.txt for details. ...@@ -322,6 +351,14 @@ API.txt for details.
return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames); return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames);
} }
// possibly use quarters if quarters are mentioned in
// any of these places
var useQuarters = (axis.options.tickSize &&
axis.options.tickSize[1] == "quarter") ||
(axis.options.minTickSize &&
axis.options.minTickSize[1] == "quarter");
var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
var span = axis.max - axis.min; var span = axis.max - axis.min;
var suffix = (opts.twelveHourClock) ? " %p" : ""; var suffix = (opts.twelveHourClock) ? " %p" : "";
...@@ -338,12 +375,19 @@ API.txt for details. ...@@ -338,12 +375,19 @@ API.txt for details.
} }
} else if (t < timeUnitSize.month) { } else if (t < timeUnitSize.month) {
fmt = "%b %d"; fmt = "%b %d";
} else if (t < timeUnitSize.year) { } else if ((useQuarters && t < timeUnitSize.quarter) ||
(!useQuarters && t < timeUnitSize.year)) {
if (span < timeUnitSize.year) { if (span < timeUnitSize.year) {
fmt = "%b"; fmt = "%b";
} else { } else {
fmt = "%b %Y"; fmt = "%b %Y";
} }
} else if (useQuarters && t < timeUnitSize.year) {
if (span < timeUnitSize.year) {
fmt = "Q%q";
} else {
fmt = "Q%q %Y";
}
} else { } else {
fmt = "%Y"; fmt = "%Y";
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment