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
......@@ -582,10 +582,10 @@ xaxis: {
mode: "time"
timeformat: "%Y/%m/%d"
}
```
```
This will result in tick labels like "2000/12/24". A subset of the
standard strftime specifiers are supported:
This will result in tick labels like "2000/12/24". A subset of the
standard strftime specifiers are supported (plus the nonstandard %q):
```js
%a: weekday name (customizable)
......@@ -596,6 +596,7 @@ standard strftime specifiers are supported:
%I: hours, 12-hour time, zero-padded (01-12)
%m: month, zero-padded (01-12)
%M: minutes, zero-padded (00-59)
%q: quarter (1-4)
%S: seconds, zero-padded (00-59)
%y: year (two digits)
%Y: year (four digits)
......
......@@ -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.
Date/time formatting has changed and now follows a proper subset of the
standard strftime specifiers. Additionally, if a strftime function is found in
the Date object's prototype, it will be used instead of the built-in
formatter.
standard strftime specifiers, plus one nonstandard specifier for quarters.
Additionally, if a strftime function is found in the Date object's prototype,
it will be used instead of the built-in formatter.
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
......@@ -29,6 +29,9 @@ The base and overlay canvas are now using the CSS classes "flot-base" and
### 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
support added for Date.prototype.strftime, if found. (patch by Mark Cote,
issues 419 and 558)
......
......@@ -23,6 +23,7 @@
<p>Zoom to: <button id="whole">Whole period</button>
<button id="nineties">1990-2000</button>
<button id="latenineties">1996-2000</button>
<button id="ninetyninequarters">1999 by quarter</button>
<button id="ninetynine">1999</button>
<button id="lastweekninetynine">end of 1999</button>
<button id="lastdayninetynine">very end of 1999</button></p>
......@@ -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 () {
$.plot($("#placeholder"), [d], {
xaxis: {
......
......@@ -71,6 +71,9 @@ API.txt for details.
case 'l': c = leftPad(hours12, " "); break;
case 'm': c = leftPad(d.getMonth() + 1); 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 'y': c = leftPad(d.getFullYear() % 100); break;
case 'Y': c = "" + d.getFullYear(); break;
......@@ -156,13 +159,14 @@ API.txt for details.
"hour": 60 * 60 * 1000,
"day": 24 * 60 * 60 * 1000,
"month": 30 * 24 * 60 * 60 * 1000,
"quarter": 3 * 30 * 24 * 60 * 60 * 1000,
"year": 365.2425 * 24 * 60 * 60 * 1000
};
// the allowed tick sizes, after 1 year we use
// an integer algorithm
var spec = [
var baseSpec = [
[1, "second"], [2, "second"], [5, "second"], [10, "second"],
[30, "second"],
[1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
......@@ -171,10 +175,17 @@ API.txt for details.
[8, "hour"], [12, "hour"],
[1, "day"], [2, "day"], [3, "day"],
[0.25, "month"], [0.5, "month"], [1, "month"],
[2, "month"], [3, "month"], [6, "month"],
[1, "year"]
[2, "month"]
];
// 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) {
plot.hooks.processDatapoints.push(function (plot, series, datapoints) {
$.each(plot.getAxes(), function(axisName, axis) {
......@@ -188,6 +199,14 @@ API.txt for details.
var d = dateGenerator(axis.min, opts);
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 (typeof opts.tickSize == "number") {
minSize = opts.tickSize;
......@@ -255,6 +274,9 @@ API.txt for details.
d.setHours(floorInBase(d.getHours(), tickSize));
} else if (unit == "month") {
d.setMonth(floorInBase(d.getMonth(), tickSize));
} else if (unit == "quarter") {
d.setMonth(3 * floorInBase(d.getMonth() / 3,
tickSize));
} else if (unit == "year") {
d.setFullYear(floorInBase(d.getFullYear(), tickSize));
}
......@@ -271,6 +293,10 @@ API.txt for details.
d.setHours(0);
} else if (step >= timeUnitSize.day * 4) {
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) {
d.setMonth(0);
}
......@@ -285,22 +311,25 @@ API.txt for details.
v = d.getTime();
ticks.push(v);
if (unit == "month") {
if (unit == "month" || unit == "quarter") {
if (tickSize < 1) {
// a bit complicated - we'll divide the month
// up but we need to take care of fractions
// so we don't end up in the middle of a day
// a bit complicated - we'll divide the
// month/quarter up but we need to take
// care of fractions so we don't end up in
// the middle of a day
d.setDate(1);
var start = d.getTime();
d.setMonth(d.getMonth() + 1);
d.setMonth(d.getMonth() +
(unit == "quarter" ? 3 : 1));
var end = d.getTime();
d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
carry = d.getHours();
d.setHours(0);
} else {
d.setMonth(d.getMonth() + tickSize);
d.setMonth(d.getMonth() +
tickSize * (unit == "quarter" ? 3 : 1));
}
} else if (unit == "year") {
d.setFullYear(d.getFullYear() + tickSize);
......@@ -322,6 +351,14 @@ API.txt for details.
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 span = axis.max - axis.min;
var suffix = (opts.twelveHourClock) ? " %p" : "";
......@@ -338,12 +375,19 @@ API.txt for details.
}
} else if (t < timeUnitSize.month) {
fmt = "%b %d";
} else if (t < timeUnitSize.year) {
} else if ((useQuarters && t < timeUnitSize.quarter) ||
(!useQuarters && t < timeUnitSize.year)) {
if (span < timeUnitSize.year) {
fmt = "%b";
} else {
fmt = "%b %Y";
}
} else if (useQuarters && t < timeUnitSize.year) {
if (span < timeUnitSize.year) {
fmt = "Q%q";
} else {
fmt = "Q%q %Y";
}
} else {
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