PluginProbe
CoolClock / 2.9.8
CoolClock v2.9.8
4.3.9 4.3.8 trunk 0.1 2.0 2.9.8 3.0 3.1 3.2 3.3 4.0 4.1 4.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7
coolclock / js / coolclock.js

coolclock.js in CoolClock 2.9.8, at js/coolclock.js

388 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * CoolClock 3.0.0-pre
3 * Global Tick branch with https://github.com/henrahmagix/CoolClock/commit/00d48a01b1aeadbeb0b7d167aca892de78659b76 applied
4 *
5 Copyright (c) 2010-2013, Simon Baird.
6 All rights reserved.
7 *
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 - Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 - Neither the name Simon Baird nor the names of other contributors may be
16 used to endorse or promote products derived from this software without
17 specific prior written permission.
18 *
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL SIMON BAIRD BE LIABLE FOR ANY DIRECT,
23 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Display an analog clock using canvas.
31 * http://randomibis.com/coolclock/
32 *
33 */
34
35 // Constructor for CoolClock objects
36 window.CoolClock = function(options) {
37 return this.init(options);
38 }
39
40 // Config contains some defaults, and clock skins
41 CoolClock.config = {
42 tickDelay: 1000,
43 longTickDelay: 15000,
44 defaultRadius: 85,
45 renderRadius: 100,
46 defaultSkin: "chunkySwiss",
47 defaultFont: "15px sans-serif",
48
49 skins: {
50 // There are more skins in moreskins.js
51 // Try making your own skin by copy/pasting one of these and tweaking it
52 swissRail: {
53 outerBorder: { lineWidth: 2, radius:95, color: "black", alpha: 1 },
54 smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 },
55 largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 },
56 hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
57 minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
58 secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
59 secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
60 },
61 chunkySwiss: {
62 outerBorder: { lineWidth: 4, radius:97, color: "black", alpha: 1 },
63 smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
64 largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
65 hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
66 minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
67 secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
68 secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
69 },
70 chunkySwissOnBlack: {
71 outerBorder: { lineWidth: 4, radius:97, color: "white", alpha: 1 },
72 smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
73 largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
74 hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
75 minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
76 secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
77 secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
78 }
79
80 },
81
82 // Test for IE so we can nurse excanvas in a couple of places
83 isIE: !!document.all,
84
85 // Will store (a reference to) each clock here, indexed by the id of the canvas element
86 clockTracker: {},
87
88 // For giving a unique id to coolclock canvases with no id
89 noIdCount: 0
90 }
91
92 // Main tick handler. Refresh all the clocks then setup the next tick
93 CoolClock.tick = function() {
94
95 for (var clockId in CoolClock.config.clockTracker) {
96 var clock = CoolClock.config.clockTracker[clockId];
97 if (clock.stillHere() && clock.active) {
98 clock.refreshDisplay()
99 }
100 }
101 this.tickTimeout = setTimeout(CoolClock.tick, CoolClock.config.tickDelay);
102 };
103
104 // Define the CoolClock object's methods
105 CoolClock.prototype = {
106
107 // Initialise using the parameters parsed from the colon delimited class
108 init: function(options) {
109 // Parse and store the options
110 this.canvasId = options.canvasId;
111 this.skinId = options.skinId || CoolClock.config.defaultSkin;
112 this.font = options.font || CoolClock.config.defaultFont;
113 this.displayRadius = options.displayRadius || CoolClock.config.defaultRadius;
114 this.renderRadius = options.renderRadius || CoolClock.config.renderRadius;
115 this.showSecondHand = typeof options.showSecondHand == "boolean" ? options.showSecondHand : true;
116 this.gmtOffset = (options.gmtOffset != null && options.gmtOffset != '') ? parseFloat(options.gmtOffset) : null;
117 this.showDigital = typeof options.showDigital == "boolean" ? options.showDigital : false;
118 this.showDigital24 = typeof options.showDigital24 == "boolean" ? options.showDigital24 : false;
119 this.showDate = typeof options.showDate == "boolean" ? options.showDate : false;
120 this.logClock = typeof options.logClock == "boolean" ? options.logClock : false;
121 this.logClockRev = typeof options.logClock == "boolean" ? options.logClockRev : false;
122
123 this.tickDelay = CoolClock.config[ this.showSecondHand ? "tickDelay" : "longTickDelay" ];
124
125 // Get the canvas element
126 this.canvas = document.getElementById(this.canvasId);
127
128 // Make the canvas the requested size. It's always square.
129 this.canvas.setAttribute("width",this.displayRadius*2);
130 this.canvas.setAttribute("height",this.displayRadius*2);
131 this.canvas.style.width = this.displayRadius*2 + "px";
132 this.canvas.style.height = this.displayRadius*2 + "px";
133
134 // Determine by what factor to relate skin values to canvas positions.
135 // renderRadius is the max skin positional value before leaving the
136 // canvas. displayRadius is half the width and height of the canvas in
137 // pixels. If they are equal, there is a 1:1 relation of skin position
138 // values to canvas pixels. Setting both to 200 allows 100px of space
139 // around clock skins to add your own things: this is due to current
140 // skins maxing out at a positional value of 100.
141 this.scale = this.displayRadius / this.renderRadius;
142
143 // Initialise canvas context
144 this.ctx = this.canvas.getContext("2d");
145 this.ctx.scale(this.scale,this.scale);
146
147 // Keep track of this object
148 CoolClock.config.clockTracker[this.canvasId] = this;
149
150 // Start the clock going
151 this.start();
152
153 return this;
154 },
155
156 // Draw a circle at point x,y with params as defined in skin
157 fullCircleAt: function(x,y,skin) {
158 this.ctx.save();
159 this.ctx.globalAlpha = skin.alpha;
160 this.ctx.lineWidth = skin.lineWidth;
161
162 if (CoolClock.config.isIE) {
163 // excanvas doesn't scale line width so we will do it here
164 this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
165 }
166
167 this.ctx.beginPath();
168 this.ctx.arc(x, y, skin.radius, 0, 2*Math.PI, false);
169
170 if (CoolClock.config.isIE) {
171 // excanvas doesn't close the circle so let's fill in the tiny gap
172 this.ctx.arc(x, y, skin.radius, -0.1, 0.1, false);
173 }
174
175 if (skin.fillColor) {
176 this.ctx.fillStyle = skin.fillColor
177 this.ctx.fill();
178 }
179 if (skin.color) {
180 this.ctx.strokeStyle = skin.color;
181 this.ctx.stroke();
182 }
183 this.ctx.restore();
184 },
185
186 // Draw some text centered vertically and horizontally
187 drawTextAt: function(theText,x,y,skin) {
188 if (!skin) skin = this.getSkin();
189 this.ctx.save();
190 this.ctx.font = skin.font || this.font;
191 var tSize = this.ctx.measureText(theText);
192 // TextMetrics rarely returns a height property: use baseline instead.
193 if (!tSize.height) {
194 tSize.height = 0;
195 this.ctx.textBaseline = 'middle';
196 }
197 this.ctx.fillText(theText, x - tSize.width/2, y - tSize.height/2);
198 this.ctx.restore();
199 },
200
201 lpad2: function(num) {
202 return (num < 10 ? '0' : '') + num;
203 },
204
205 tickAngle: function(second) {
206 // Log algorithm by David Bradshaw
207 var tweak = 3; // If it's lower the one second mark looks wrong (?)
208 if (this.logClock) {
209 return second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak));
210 }
211 else if (this.logClockRev) {
212 // Flip the seconds then flip the angle (trickiness)
213 second = (60 - second) % 60;
214 return 1.0 - (second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak)));
215 }
216 else {
217 return second/60.0;
218 }
219 },
220
221 timeText: function(hour,min,sec,showAmPm,showSecs) {
222 return '' +
223 (showAmPm ? ((hour%12)==0 ? 12 : (hour%12)) : hour) + ':' +
224 this.lpad2(min) +
225 (showSecs ? ':' + this.lpad2(sec) : '') +
226 (showAmPm ? (hour < 12 ? ' am' : ' pm') : '')
227 ;
228 },
229
230 // Draw a radial line by rotating then drawing a straight line
231 // Ha ha, I think I've accidentally used Taus, (see http://tauday.com/)
232 radialLineAtAngle: function(angleFraction,skin) {
233 this.ctx.save();
234 this.ctx.translate(this.renderRadius,this.renderRadius);
235 this.ctx.rotate(Math.PI * (2.0 * angleFraction - 0.5));
236 this.ctx.globalAlpha = skin.alpha;
237 this.ctx.strokeStyle = skin.color;
238 this.ctx.lineWidth = skin.lineWidth;
239
240 if (CoolClock.config.isIE)
241 // excanvas doesn't scale line width so we will do it here
242 this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
243
244 if (skin.radius) {
245 this.fullCircleAt(skin.startAt,0,skin)
246 }
247 else {
248 this.ctx.beginPath();
249 this.ctx.moveTo(skin.startAt,0)
250 this.ctx.lineTo(skin.endAt,0);
251 this.ctx.stroke();
252 }
253 this.ctx.restore();
254 },
255
256 render: function(hour,min,sec,date) {
257 // Get the skin
258 var skin = this.getSkin();
259
260 // Clear
261 this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);
262
263 // Draw the outer edge of the clock
264 if (skin.outerBorder)
265 this.fullCircleAt(this.renderRadius,this.renderRadius,skin.outerBorder);
266
267 // Draw the tick marks. Every 5th one is a big one
268 for (var i=0;i<60;i++) {
269 (i%5) && skin.smallIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.smallIndicator);
270 !(i%5) && skin.largeIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.largeIndicator);
271 }
272
273 // Write the time and or date
274 if (this.showDigital || this.showDigital24 || this.showDate) {
275 var text;
276 if (this.showDigital) text = this.timeText(hour,min,sec,true,false);
277 else if (this.showDigital24) text = this.timeText(hour,min,sec,false,true);
278 else text = date;
279 this.drawTextAt(
280 text,
281 this.renderRadius,
282 this.renderRadius+this.renderRadius/2
283 );
284 }
285
286 var hourA = (hour%12)*5 + min/12.0,
287 minA = min + sec/60.0,
288 secA = sec;
289
290 // Draw the hands
291 if (skin.hourHand)
292 this.radialLineAtAngle(this.tickAngle(hourA),skin.hourHand);
293
294 if (skin.minuteHand)
295 this.radialLineAtAngle(this.tickAngle(minA),skin.minuteHand);
296
297 if (this.showSecondHand && skin.secondHand)
298 this.radialLineAtAngle(this.tickAngle(secA),skin.secondHand);
299
300 // Hands decoration - not in IE
301 if (!CoolClock.config.isIE) {
302 if (skin.hourDecoration)
303 this.radialLineAtAngle(this.tickAngle(hourA), skin.hourDecoration);
304
305 if (skin.minDecoration)
306 this.radialLineAtAngle(this.tickAngle(minA), skin.minDecoration);
307
308 if (this.showSecondHand && skin.secondDecoration)
309 this.radialLineAtAngle(this.tickAngle(secA),skin.secondDecoration);
310 }
311
312 if (this.extraRender) {
313 this.extraRender(hour,min,sec);
314 }
315 },
316
317 // Check the time and display the clock
318 refreshDisplay: function() {
319 var now = new Date();
320 if (this.gmtOffset != null) {
321 // Use GMT + gmtOffset
322 var offsetNow = new Date(now.valueOf() + (this.gmtOffset * 1000 * 60 * 60));
323 this.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds(),offsetNow.toLocaleDateString());
324 }
325 else {
326 // Use local time
327 this.render(now.getHours(),now.getMinutes(),now.getSeconds(),now.toLocaleDateString());
328 }
329 },
330
331
332 // Check the canvas element hasn't been removed
333 stillHere: function() {
334 return document.getElementById(this.canvasId) != null;
335 },
336
337 // Stop this clock
338 stop: function() {
339 this.active = false;
340 },
341
342 // Start this clock
343 start: function() {
344 this.active = true;
345 },
346
347 getSkin: function() {
348 var skin = CoolClock.config.skins[this.skinId];
349 if (!skin) skin = CoolClock.config.skins[CoolClock.config.defaultSkin];
350 return skin;
351 }
352 };
353
354 // Find all canvas elements that have the CoolClock class and turns them into clocks
355 CoolClock.findAndCreateClocks = function() {
356 // (Let's not use a jQuery selector here so it's easier to use frameworks other than jQuery)
357 var canvases = document.getElementsByTagName("canvas");
358 for (var i=0;i<canvases.length;i++) {
359 // Pull out the fields from the class. Example "CoolClock:chunkySwissOnBlack:1000"
360 var fields = canvases[i].className.split(" ")[0].split(":");
361 if (fields[0] == "CoolClock") {
362 if (!canvases[i].id) {
363 // If there's no id on this canvas element then give it one
364 canvases[i].id = '_coolclock_auto_id_' + CoolClock.config.noIdCount++;
365 }
366 // Create a clock object for this element
367 new CoolClock({
368 canvasId: canvases[i].id,
369 skinId: fields[1],
370 displayRadius: fields[2],
371 showSecondHand: fields[3]!='noSeconds',
372 gmtOffset: fields[4],
373 showDigital: fields[5]=='showDigital',
374 showDigital24: fields[5]=='showDigital24',
375 showDate: fields[5]=='showDate',
376 logClock: fields[6]=='logClock',
377 logClockRev: fields[6]=='logClockRev'
378 });
379 }
380 }
381 // Start ticking
382 CoolClock.tick();
383 };
384
385 // If you don't have jQuery then you need a body onload like this: <body onload="CoolClock.findAndCreateClocks()">
386 // If you do have jQuery and it's loaded already then we can do it right now
387 if (window.jQuery) jQuery(document).ready(CoolClock.findAndCreateClocks);
388