vendor: 11,428 bytes, lines 1-417
1/* Pretty handling of time axes. 2 3Copyright (c) 2007-2013 IOLA and Ole Laursen. 4Licensed under the MIT license. 5 6Set axis.mode to "time" to enable. See the section "Time series data" in 7API.txt for details. 8 9*/ 10 11(function($) { 12 13 var options = {}; 14 15 // round to nearby lower multiple of base 16 17 function floorInBase(n, base) { 18 return base * Math.floor(n / base); 19 } 20 21 // Returns a string with the date d formatted according to fmt. 22 // A subset of the Open Group's strftime format is supported. 23 24 function formatDate(d, fmt, monthNames, dayNames) { 25 26 if (typeof d.strftime == "function") { 27 return d.strftime(fmt); 28 } 29 30 var leftPad = function(n, pad) { 31 n = "" + n; 32 pad = "" + (pad == null ? "0" : pad); 33 return n.length == 1 ? pad + n : n; 34 }; 35 36 var r = []; 37 var escape = false; 38 var hours = d.getHours(); 39 var isAM = hours < 12; 40 41 if (monthNames == null) { 42 monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; 43 } 44 45 if (dayNames == null) { 46 dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; 47 } 48 49 var hours12; 50 51 if (hours > 12) { 52 hours12 = hours - 12; 53 } else if (hours == 0) { 54 hours12 = 12; 55 } else { 56 hours12 = hours; 57 } 58 59 for (var i = 0; i < fmt.length; ++i) { 60 61 var c = fmt.charAt(i); 62 63 if (escape) { 64 switch (c) { 65 case 'a': c = "" + dayNames[d.getDay()]; break; 66 case 'b': c = "" + monthNames[d.getMonth()]; break; 67 case 'd': c = leftPad(d.getDate()); break; 68 case 'e': c = leftPad(d.getDate(), " "); break; 69 case 'H': c = leftPad(hours); break; 70 case 'I': c = leftPad(hours12); break; 71 case 'l': c = leftPad(hours12, " "); break; 72 case 'm': c = leftPad(d.getMonth() + 1); break; 73 case 'M': c = leftPad(d.getMinutes()); break; 74 // quarters not in Open Group's strftime specification 75 case 'q': 76 c = "" + (Math.floor(d.getMonth() / 3) + 1); break; 77 case 'S': c = leftPad(d.getSeconds()); break; 78 case 'y': c = leftPad(d.getFullYear() % 100); break; 79 case 'Y': c = "" + d.getFullYear(); break; 80 case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break; 81 case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break; 82 case 'w': c = "" + d.getDay(); break; 83 } 84 r.push(c); 85 escape = false; 86 } else { 87 if (c == "%") { 88 escape = true; 89 } else { 90 r.push(c); 91 } 92 } 93 } 94 95 return r.join(""); 96 } 97 98 // To have a consistent view of time-based data independent of which time 99 // zone the client happens to be in we need a date-like object independent 100 // of time zones. This is done through a wrapper that only calls the UTC 101 // versions of the accessor methods. 102 103 function makeUtcWrapper(d) { 104 105 function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) { 106 sourceObj[sourceMethod] = function() { 107 return targetObj[targetMethod].apply(targetObj, arguments); 108 }; 109 }; 110 111 var utc = { 112 date: d 113 }; 114 115 // support strftime, if found 116 117 if (d.strftime != undefined) { 118 addProxyMethod(utc, "strftime", d, "strftime"); 119 } 120 121 addProxyMethod(utc, "getTime", d, "getTime"); 122 addProxyMethod(utc, "setTime", d, "setTime"); 123 124 var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"]; 125 126 for (var p = 0; p < props.length; p++) { 127 addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]); 128 addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]); 129 } 130 131 return utc; 132 }; 133 134 // select time zone strategy. This returns a date-like object tied to the 135 // desired timezone 136 137 function dateGenerator(ts, opts) { 138 if (opts.timezone == "browser") { 139 return new Date(ts); 140 } else if (!opts.timezone || opts.timezone == "utc") { 141 return makeUtcWrapper(new Date(ts)); 142 } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") { 143 var d = new timezoneJS.Date(); 144 // timezone-js is fickle, so be sure to set the time zone before 145 // setting the time. 146 d.setTimezone(opts.timezone); 147 d.setTime(ts); 148 return d; 149 } else { 150 return makeUtcWrapper(new Date(ts)); 151 } 152 } 153 154 // map of app. size of time units in milliseconds 155 156 var timeUnitSize = { 157 "second": 1000, 158 "minute": 60 * 1000, 159 "hour": 60 * 60 * 1000, 160 "day": 24 * 60 * 60 * 1000, 161 "month": 30 * 24 * 60 * 60 * 1000, 162 "quarter": 3 * 30 * 24 * 60 * 60 * 1000, 163 "year": 365.2425 * 24 * 60 * 60 * 1000 164 }; 165 166 // the allowed tick sizes, after 1 year we use 167 // an integer algorithm 168 169 var baseSpec = [ 170 [1, "second"], [2, "second"], [5, "second"], [10, "second"], 171 [30, "second"], 172 [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], 173 [30, "minute"], 174 [1, "hour"], [2, "hour"], [4, "hour"], 175 [8, "hour"], [12, "hour"], 176 [1, "day"], [2, "day"], [3, "day"], 177 [0.25, "month"], [0.5, "month"], [1, "month"], 178 [2, "month"] 179 ]; 180 181 // we don't know which variant(s) we'll need yet, but generating both is 182 // cheap 183 184 var specMonths = baseSpec.concat([[3, "month"], [6, "month"], 185 [1, "year"]]); 186 var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"], 187 [1, "year"]]); 188 189 function init(plot) { 190 plot.hooks.processDatapoints.push(function (plot, series, datapoints) { 191 $.each(plot.getAxes(), function(axisName, axis) { 192 193 var opts = axis.options; 194 195 if (opts.mode == "time") { 196 axis.tickGenerator = function(axis) { 197 198 var ticks = []; 199 var d = dateGenerator(axis.min, opts); 200 var minSize = 0; 201 202 // make quarter use a possibility if quarters are 203 // mentioned in either of these options 204 205 var spec = (opts.tickSize && opts.tickSize[1] === 206 "quarter") || 207 (opts.minTickSize && opts.minTickSize[1] === 208 "quarter") ? specQuarters : specMonths; 209 210 if (opts.minTickSize != null) { 211 if (typeof opts.tickSize == "number") { 212 minSize = opts.tickSize; 213 } else { 214 minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]]; 215 } 216 } 217 218 for (var i = 0; i < spec.length - 1; ++i) { 219 if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] 220 + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 221 && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) { 222 break; 223 } 224 } 225 226 var size = spec[i][0]; 227 var unit = spec[i][1]; 228 229 // special-case the possibility of several years 230 231 if (unit == "year") { 232 233 // if given a minTickSize in years, just use it, 234 // ensuring that it's an integer 235 236 if (opts.minTickSize != null && opts.minTickSize[1] == "year") { 237 size = Math.floor(opts.minTickSize[0]); 238 } else { 239 240 var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10)); 241 var norm = (axis.delta / timeUnitSize.year) / magn; 242 243 if (norm < 1.5) { 244 size = 1; 245 } else if (norm < 3) { 246 size = 2; 247 } else if (norm < 7.5) { 248 size = 5; 249 } else { 250 size = 10; 251 } 252 253 size *= magn; 254 } 255 256 // minimum size for years is 1 257 258 if (size < 1) { 259 size = 1; 260 } 261 } 262 263 axis.tickSize = opts.tickSize || [size, unit]; 264 var tickSize = axis.tickSize[0]; 265 unit = axis.tickSize[1]; 266 267 var step = tickSize * timeUnitSize[unit]; 268 269 if (unit == "second") { 270 d.setSeconds(floorInBase(d.getSeconds(), tickSize)); 271 } else if (unit == "minute") { 272 d.setMinutes(floorInBase(d.getMinutes(), tickSize)); 273 } else if (unit == "hour") { 274 d.setHours(floorInBase(d.getHours(), tickSize)); 275 } else if (unit == "month") { 276 d.setMonth(floorInBase(d.getMonth(), tickSize)); 277 } else if (unit == "quarter") { 278 d.setMonth(3 * floorInBase(d.getMonth() / 3, 279 tickSize)); 280 } else if (unit == "year") { 281 d.setFullYear(floorInBase(d.getFullYear(), tickSize)); 282 } 283 284 // reset smaller components 285 286 d.setMilliseconds(0); 287 288 if (step >= timeUnitSize.minute) { 289 d.setSeconds(0); 290 } else if (step >= timeUnitSize.hour) { 291 d.setMinutes(0); 292 } else if (step >= timeUnitSize.day) { 293 d.setHours(0); 294 } else if (step >= timeUnitSize.day * 4) { 295 d.setDate(1); 296 } else if (step >= timeUnitSize.month * 2) { 297 d.setMonth(floorInBase(d.getMonth(), 3)); 298 } else if (step >= timeUnitSize.quarter * 2) { 299 d.setMonth(floorInBase(d.getMonth(), 6)); 300 } else if (step >= timeUnitSize.year) { 301 d.setMonth(0); 302 } 303 304 var carry = 0; 305 var v = Number.NaN; 306 var prev; 307 308 do { 309 310 prev = v; 311 v = d.getTime(); 312 ticks.push(v); 313 314 if (unit == "month" || unit == "quarter") { 315 if (tickSize < 1) { 316 317 // a bit complicated - we'll divide the 318 // month/quarter up but we need to take 319 // care of fractions so we don't end up in 320 // the middle of a day 321 322 d.setDate(1); 323 var start = d.getTime(); 324 d.setMonth(d.getMonth() + 325 (unit == "quarter" ? 3 : 1)); 326 var end = d.getTime(); 327 d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize); 328 carry = d.getHours(); 329 d.setHours(0); 330 } else { 331 d.setMonth(d.getMonth() + 332 tickSize * (unit == "quarter" ? 3 : 1)); 333 } 334 } else if (unit == "year") { 335 d.setFullYear(d.getFullYear() + tickSize); 336 } else { 337 d.setTime(v + step); 338 } 339 } while (v < axis.max && v != prev); 340 341 return ticks; 342 }; 343 344 axis.tickFormatter = function (v, axis) { 345 346 var d = dateGenerator(v, axis.options); 347 348 // first check global format 349 350 if (opts.timeformat != null) { 351 return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames); 352 } 353 354 // possibly use quarters if quarters are mentioned in 355 // any of these places 356 357 var useQuarters = (axis.options.tickSize && 358 axis.options.tickSize[1] == "quarter") || 359 (axis.options.minTickSize && 360 axis.options.minTickSize[1] == "quarter"); 361 362 var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; 363 var span = axis.max - axis.min; 364 var suffix = (opts.twelveHourClock) ? " %p" : ""; 365 var hourCode = (opts.twelveHourClock) ? "%I" : "%H"; 366 var fmt; 367 368 if (t < timeUnitSize.minute) { 369 fmt = hourCode + ":%M:%S" + suffix; 370 } else if (t < timeUnitSize.day) { 371 if (span < 2 * timeUnitSize.day) { 372 fmt = hourCode + ":%M" + suffix; 373 } else { 374 fmt = "%b %d " + hourCode + ":%M" + suffix; 375 } 376 } else if (t < timeUnitSize.month) { 377 fmt = "%b %d"; 378 } else if ((useQuarters && t < timeUnitSize.quarter) || 379 (!useQuarters && t < timeUnitSize.year)) { 380 if (span < timeUnitSize.year) { 381 fmt = "%b"; 382 } else { 383 fmt = "%b %Y"; 384 } 385 } else if (useQuarters && t < timeUnitSize.year) { 386 if (span < timeUnitSize.year) { 387 fmt = "Q%q"; 388 } else { 389 fmt = "Q%q %Y"; 390 } 391 } else { 392 fmt = "%Y"; 393 } 394 395 var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames); 396 397 return rt; 398 }; 399 } 400 }); 401 }); 402 } 403 404 $.plot.plugins.push({ 405 init: init, 406 options: options, 407 name: 'time', 408 version: '1.0' 409 }); 410 411 // Time-axis support used to be in Flot core, which exposed the 412 // formatDate function on the plot object. Various plugins depend 413 // on the function, so we need to re-expose it here. 414 415 $.plot.formatDate = formatDate; 416 417})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.