| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 | /* Pretty handling of time axes.Copyright (c) 2007-2013 IOLA and Ole Laursen.Licensed under the MIT license.Set axis.mode to "time" to enable. See the section "Time series data" inAPI.txt for details.*/(function($) {	var options = {		xaxis: {			timezone: null,		// "browser" for local to the client or timezone for timezone-js			timeformat: null,	// format string to use			twelveHourClock: false,	// 12 or 24 time in time mode			monthNames: null	// list of names of months		}	};	// round to nearby lower multiple of base	function floorInBase(n, base) {		return base * Math.floor(n / base);	}	// Returns a string with the date d formatted according to fmt.	// A subset of the Open Group's strftime format is supported.	function formatDate(d, fmt, monthNames, dayNames) {		if (typeof d.strftime == "function") {			return d.strftime(fmt);		}		var leftPad = function(n, pad) {			n = "" + n;			pad = "" + (pad == null ? "0" : pad);			return n.length == 1 ? pad + n : n;		};		var r = [];		var escape = false;		var hours = d.getHours();		var isAM = hours < 12;		if (monthNames == null) {			monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];		}		if (dayNames == null) {			dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];		}		var hours12;		if (hours > 12) {			hours12 = hours - 12;		} else if (hours == 0) {			hours12 = 12;		} else {			hours12 = hours;		}		for (var i = 0; i < fmt.length; ++i) {			var c = fmt.charAt(i);			if (escape) {				switch (c) {					case 'a': c = "" + dayNames[d.getDay()]; break;					case 'b': c = "" + monthNames[d.getMonth()]; break;					case 'd': c = leftPad(d.getDate()); break;					case 'e': c = leftPad(d.getDate(), " "); break;					case 'h':	// For back-compat with 0.7; remove in 1.0					case 'H': c = leftPad(hours); break;					case 'I': c = leftPad(hours12); break;					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;					case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;					case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;					case 'w': c = "" + d.getDay(); break;				}				r.push(c);				escape = false;			} else {				if (c == "%") {					escape = true;				} else {					r.push(c);				}			}		}		return r.join("");	}	// To have a consistent view of time-based data independent of which time	// zone the client happens to be in we need a date-like object independent	// of time zones.  This is done through a wrapper that only calls the UTC	// versions of the accessor methods.	function makeUtcWrapper(d) {		function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) {			sourceObj[sourceMethod] = function() {				return targetObj[targetMethod].apply(targetObj, arguments);			};        }        var utc = {			date: d		};		// support strftime, if found		if (d.strftime != undefined) {			addProxyMethod(utc, "strftime", d, "strftime");		}		addProxyMethod(utc, "getTime", d, "getTime");		addProxyMethod(utc, "setTime", d, "setTime");		var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"];		for (var p = 0; p < props.length; p++) {			addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]);			addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]);		}		return utc;    }    // select time zone strategy.  This returns a date-like object tied to the	// desired timezone	function dateGenerator(ts, opts) {		if (opts.timezone == "browser") {			return new Date(ts);		} else if (!opts.timezone || opts.timezone == "utc") {			return makeUtcWrapper(new Date(ts));		} else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") {			var d = new timezoneJS.Date();			// timezone-js is fickle, so be sure to set the time zone before			// setting the time.			d.setTimezone(opts.timezone);			d.setTime(ts);			return d;		} else {			return makeUtcWrapper(new Date(ts));		}	}		// map of app. size of time units in milliseconds	var timeUnitSize = {		"second": 1000,		"minute": 60 * 1000,		"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 baseSpec = [		[1, "second"], [2, "second"], [5, "second"], [10, "second"],		[30, "second"], 		[1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],		[30, "minute"], 		[1, "hour"], [2, "hour"], [4, "hour"],		[8, "hour"], [12, "hour"],		[1, "day"], [2, "day"], [3, "day"],		[0.25, "month"], [0.5, "month"], [1, "month"],		[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.processOptions.push(function (plot, options) {			$.each(plot.getAxes(), function(axisName, axis) {				var opts = axis.options;				if (opts.mode == "time") {					axis.tickGenerator = function(axis) {						var ticks = [];						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;							} else {								minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];							}						}						for (var i = 0; i < spec.length - 1; ++i) {							if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]]											  + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2								&& spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {								break;							}						}						var size = spec[i][0];						var unit = spec[i][1];						// special-case the possibility of several years						if (unit == "year") {							// if given a minTickSize in years, just use it,							// ensuring that it's an integer							if (opts.minTickSize != null && opts.minTickSize[1] == "year") {								size = Math.floor(opts.minTickSize[0]);							} else {								var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10));								var norm = (axis.delta / timeUnitSize.year) / magn;								if (norm < 1.5) {									size = 1;								} else if (norm < 3) {									size = 2;								} else if (norm < 7.5) {									size = 5;								} else {									size = 10;								}								size *= magn;							}							// minimum size for years is 1							if (size < 1) {								size = 1;							}						}						axis.tickSize = opts.tickSize || [size, unit];						var tickSize = axis.tickSize[0];						unit = axis.tickSize[1];						var step = tickSize * timeUnitSize[unit];						if (unit == "second") {							d.setSeconds(floorInBase(d.getSeconds(), tickSize));						} else if (unit == "minute") {							d.setMinutes(floorInBase(d.getMinutes(), tickSize));						} else if (unit == "hour") {							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));						}						// reset smaller components						d.setMilliseconds(0);						if (step >= timeUnitSize.minute) {							d.setSeconds(0);						}						if (step >= timeUnitSize.hour) {							d.setMinutes(0);						}						if (step >= timeUnitSize.day) {							d.setHours(0);						}						if (step >= timeUnitSize.day * 4) {							d.setDate(1);						}						if (step >= timeUnitSize.month * 2) {							d.setMonth(floorInBase(d.getMonth(), 3));						}						if (step >= timeUnitSize.quarter * 2) {							d.setMonth(floorInBase(d.getMonth(), 6));						}						if (step >= timeUnitSize.year) {							d.setMonth(0);						}						var carry = 0;						var v = Number.NaN;						var prev;						do {							prev = v;							v = d.getTime();							ticks.push(v);							if (unit == "month" || unit == "quarter") {								if (tickSize < 1) {									// 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() +										(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 * (unit == "quarter" ? 3 : 1));								}							} else if (unit == "year") {								d.setFullYear(d.getFullYear() + tickSize);							} else {								d.setTime(v + step);							}						} while (v < axis.max && v != prev);						return ticks;					};					axis.tickFormatter = function (v, axis) {						var d = dateGenerator(v, axis.options);						// first check global format						if (opts.timeformat != null) {							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" : "";						var hourCode = (opts.twelveHourClock) ? "%I" : "%H";						var fmt;						if (t < timeUnitSize.minute) {							fmt = hourCode + ":%M:%S" + suffix;						} else if (t < timeUnitSize.day) {							if (span < 2 * timeUnitSize.day) {								fmt = hourCode + ":%M" + suffix;							} else {								fmt = "%b %d " + hourCode + ":%M" + suffix;							}						} else if (t < timeUnitSize.month) {							fmt = "%b %d";						} 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";						}						var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames);						return rt;					};				}			});		});	}	$.plot.plugins.push({		init: init,		options: options,		name: 'time',		version: '1.0'	});	// Time-axis support used to be in Flot core, which exposed the	// formatDate function on the plot object.  Various plugins depend	// on the function, so we need to re-expose it here.	$.plot.formatDate = formatDate;})(jQuery);
 |