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