PageSourceSearch

https://nts-yambol.org/coolclock.js

js nts-yambol.org collected 2026-10-03 02:57:22 UTC 11,114 bytes, 318 lines download raw bytes

1/**
2 * CoolClock 2.1.4
3 * Copyright 2010, Simon Baird
4 * Released under the BSD License.
5 *
6 * Display an analog clock using canvas.
7 * http://randomibis.com/coolclock/
8 *
9 */
10
11// Constructor for CoolClock objects
12window.CoolClock = function(options) {
13	return this.init(options);
14}
15
16// Config contains some defaults, and clock skins
17CoolClock.config = {
18	tickDelay: 1000,
19	longTickDelay: 15000,
20	defaultRadius: 85,
21	renderRadius: 100,
22	defaultSkin: "chunkySwiss",
23	// Should be in skin probably...
24	// (TODO: allow skinning of digital display)
25	showSecs: true,
26	showAmPm: true,
27
28	skins:	{
29		// There are more skins in moreskins.js
30		// Try making your own skin by copy/pasting one of these and tweaking it
31		swissRail: {
32			outerBorder: { lineWidth: 2, radius:95, color: "black", alpha: 1 },
33			smallIndicator: { lineWidth: 2, startAt: 88, endAt: 92, color: "black", alpha: 1 },
34			largeIndicator: { lineWidth: 4, startAt: 79, endAt: 92, color: "black", alpha: 1 },
35			hourHand: { lineWidth: 8, startAt: -15, endAt: 50, color: "black", alpha: 1 },
36			minuteHand: { lineWidth: 7, startAt: -15, endAt: 75, color: "black", alpha: 1 },
37			secondHand: { lineWidth: 1, startAt: -20, endAt: 85, color: "red", alpha: 1 },
38			secondDecoration: { lineWidth: 1, startAt: 70, radius: 4, fillColor: "red", color: "red", alpha: 1 }
39		},
40		chunkySwiss: {
41			outerBorder: { lineWidth: 4, radius:97, color: "black", alpha: 1 },
42			smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "black", alpha: 1 },
43			largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "black", alpha: 1 },
44			hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "black", alpha: 1 },
45			minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "black", alpha: 1 },
46			secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
47			secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
48		},
49		chunkySwissOnBlack: {
50			outerBorder: { lineWidth: 4, radius:97, color: "white", alpha: 1 },
51			smallIndicator: { lineWidth: 4, startAt: 89, endAt: 93, color: "white", alpha: 1 },
52			largeIndicator: { lineWidth: 8, startAt: 80, endAt: 93, color: "white", alpha: 1 },
53			hourHand: { lineWidth: 12, startAt: -15, endAt: 60, color: "white", alpha: 1 },
54			minuteHand: { lineWidth: 10, startAt: -15, endAt: 85, color: "white", alpha: 1 },
55			secondHand: { lineWidth: 4, startAt: -20, endAt: 85, color: "red", alpha: 1 },
56			secondDecoration: { lineWidth: 2, startAt: 70, radius: 8, fillColor: "red", color: "red", alpha: 1 }
57		}
58
59	},
60
61	// Test for IE so we can nurse excanvas in a couple of places
62	isIE: !!document.all,
63
64	// Will store (a reference to) each clock here, indexed by the id of the canvas element
65	clockTracker: {},
66
67	// For giving a unique id to coolclock canvases with no id
68	noIdCount: 0
69};
70
71// Define the CoolClock object's methods
72CoolClock.prototype = {
73
74	// Initialise using the parameters parsed from the colon delimited class
75	init: function(options) {
76		// Parse and store the options
77		this.canvasId       = options.canvasId;
78		this.skinId         = options.skinId || CoolClock.config.defaultSkin;
79		this.displayRadius  = options.displayRadius || CoolClock.config.defaultRadius;
80		this.showSecondHand = typeof options.showSecondHand == "boolean" ? options.showSecondHand : true;
81		this.gmtOffset      = (options.gmtOffset != null && options.gmtOffset != '') ? parseFloat(options.gmtOffset) : null;
82		this.showDigital    = typeof options.showDigital == "boolean" ? options.showDigital : false;
83		this.logClock       = typeof options.logClock == "boolean" ? options.logClock : false;
84		this.logClockRev    = typeof options.logClock == "boolean" ? options.logClockRev : false;
85
86		this.tickDelay      = CoolClock.config[ this.showSecondHand ? "tickDelay" : "longTickDelay" ];
87
88		// Get the canvas element
89		this.canvas = document.getElementById(this.canvasId);
90
91		// Make the canvas the requested size. It's always square.
92		this.canvas.setAttribute("width",this.displayRadius*2);
93		this.canvas.setAttribute("height",this.displayRadius*2);
94		this.canvas.style.width = this.displayRadius*2 + "px";
95		this.canvas.style.height = this.displayRadius*2 + "px";
96
97		// Explain me please...?
98		this.renderRadius = CoolClock.config.renderRadius;
99		this.scale = this.displayRadius / this.renderRadius;
100
101		// Initialise canvas context
102		this.ctx = this.canvas.getContext("2d");
103		this.ctx.scale(this.scale,this.scale);
104
105		// Keep track of this object
106		CoolClock.config.clockTracker[this.canvasId] = this;
107
108		// Start the clock going
109		this.tick();
110
111		return this;
112	},
113
114	// Draw a circle at point x,y with params as defined in skin
115	fullCircleAt: function(x,y,skin) {
116		this.ctx.save();
117		this.ctx.globalAlpha = skin.alpha;
118		this.ctx.lineWidth = skin.lineWidth;
119
120		if (!CoolClock.config.isIE) {
121			this.ctx.beginPath();
122		}
123
124		if (CoolClock.config.isIE) {
125			// excanvas doesn't scale line width so we will do it here
126			this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
127		}
128
129		this.ctx.arc(x, y, skin.radius, 0, 2*Math.PI, false);
130
131		if (CoolClock.config.isIE) {
132			// excanvas doesn't close the circle so let's fill in the tiny gap
133			this.ctx.arc(x, y, skin.radius, -0.1, 0.1, false);
134		}
135
136		if (skin.fillColor) {
137			this.ctx.fillStyle = skin.fillColor
138			this.ctx.fill();
139		}
140		else {
141			// XXX why not stroke and fill
142			this.ctx.strokeStyle = skin.color;
143			this.ctx.stroke();
144		}
145		this.ctx.restore();
146	},
147
148	// Draw some text centered vertically and horizontally
149	drawTextAt: function(theText,x,y) {
150		this.ctx.save();
151		this.ctx.font = '15px sans-serif';
152		var tSize = this.ctx.measureText(theText);
153		if (!tSize.height) tSize.height = 15; // no height in firefox.. :(
154		this.ctx.fillText(theText,x - tSize.width/2,y - tSize.height/2);
155		this.ctx.restore();
156	},
157
158	lpad2: function(num) {
159		return (num < 10 ? '0' : '') + num;
160	},
161
162	tickAngle: function(second) {
163		// Log algorithm by David Bradshaw
164		var tweak = 3; // If it's lower the one second mark looks wrong (?)
165		if (this.logClock) {
166			return second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak));
167		}
168		else if (this.logClockRev) {
169			// Flip the seconds then flip the angle (trickiness)
170			second = (60 - second) % 60;
171			return 1.0 - (second == 0 ? 0 : (Math.log(second*tweak) / Math.log(60*tweak)));
172		}
173		else {
174			return second/60.0;
175		}
176	},
177
178	timeText: function(hour,min,sec) {
179		var c = CoolClock.config;
180		return '' +
181			(c.showAmPm ? ((hour%12)==0 ? 12 : (hour%12)) : hour) + ':' +
182			this.lpad2(min) +
183			(c.showSecs ? ':' + this.lpad2(sec) : '') +
184			(c.showAmPm ? (hour < 12 ? ' am' : ' pm') : '')
185		;
186	},
187
188	// Draw a radial line by rotating then drawing a straight line
189	// Ha ha, I think I've accidentally used Taus, (see http://tauday.com/)
190	radialLineAtAngle: function(angleFraction,skin) {
191		this.ctx.save();
192		this.ctx.translate(this.renderRadius,this.renderRadius);
193		this.ctx.rotate(Math.PI * (2.0 * angleFraction - 0.5));
194		this.ctx.globalAlpha = skin.alpha;
195		this.ctx.strokeStyle = skin.color;
196		this.ctx.lineWidth = skin.lineWidth;
197
198		if (CoolClock.config.isIE)
199			// excanvas doesn't scale line width so we will do it here
200			this.ctx.lineWidth = this.ctx.lineWidth * this.scale;
201
202		if (skin.radius) {
203			this.fullCircleAt(skin.startAt,0,skin)
204		}
205		else {
206			this.ctx.beginPath();
207			this.ctx.moveTo(skin.startAt,0)
208			this.ctx.lineTo(skin.endAt,0);
209			this.ctx.stroke();
210		}
211		this.ctx.restore();
212	},
213
214	render: function(hour,min,sec) {
215		// Get the skin
216		var skin = CoolClock.config.skins[this.skinId];
217		if (!skin) skin = CoolClock.config.skins[CoolClock.config.defaultSkin];
218
219		// Clear
220		this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);
221
222		// Draw the outer edge of the clock
223		if (skin.outerBorder)
224			this.fullCircleAt(this.renderRadius,this.renderRadius,skin.outerBorder);
225
226		// Draw the tick marks. Every 5th one is a big one
227		for (var i=0;i<60;i++) {
228			(i%5)  && skin.smallIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.smallIndicator);
229			!(i%5) && skin.largeIndicator && this.radialLineAtAngle(this.tickAngle(i),skin.largeIndicator);
230		}
231
232		// Write the time
233		if (this.showDigital) {
234			this.drawTextAt(
235				this.timeText(hour,min,sec),
236				this.renderRadius,
237				this.renderRadius+this.renderRadius/2
238			);
239		}
240
241		// Draw the hands
242		if (skin.hourHand)
243			this.radialLineAtAngle(this.tickAngle(((hour%12)*5 + min/12.0)),skin.hourHand);
244
245		if (skin.minuteHand)
246			this.radialLineAtAngle(this.tickAngle((min + sec/60.0)),skin.minuteHand);
247
248		if (this.showSecondHand && skin.secondHand)
249			this.radialLineAtAngle(this.tickAngle(sec),skin.secondHand);
250
251		// Second hand decoration doesn't render right in IE so lets turn it off
252		if (!CoolClock.config.isIE && this.showSecondHand && skin.secondDecoration)
253			this.radialLineAtAngle(this.tickAngle(sec),skin.secondDecoration);
254	},
255
256	// Check the time and display the clock
257	refreshDisplay: function() {
258		var now = new Date();
259		if (this.gmtOffset != null) {
260			// Use GMT + gmtOffset
261			var offsetNow = new Date(now.valueOf() + (this.gmtOffset * 1000 * 60 * 60));
262			this.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds());
263		}
264		else {
265			// Use local time
266			this.render(now.getHours(),now.getMinutes(),now.getSeconds());
267		}
268	},
269
270	// Set timeout to trigger a tick in the future
271	nextTick: function() {
272		setTimeout("CoolClock.config.clockTracker['"+this.canvasId+"'].tick()",this.tickDelay);
273	},
274
275	// Check the canvas element hasn't been removed
276	stillHere: function() {
277		return document.getElementById(this.canvasId) != null;
278	},
279
280	// Main tick handler. Refresh the clock then setup the next tick
281	tick: function() {
282		if (this.stillHere()) {
283			this.refreshDisplay()
284			this.nextTick();
285		}
286	}
287};
288
289// Find all canvas elements that have the CoolClock class and turns them into clocks
290CoolClock.findAndCreateClocks = function() {
291	// (Let's not use a jQuery selector here so it's easier to use frameworks other than jQuery)
292	var canvases = document.getElementsByTagName("canvas");
293	for (var i=0;i<canvases.length;i++) {
294		// Pull out the fields from the class. Example "CoolClock:chunkySwissOnBlack:1000"
295		var fields = canvases[i].className.split(" ")[0].split(":");
296		if (fields[0] == "CoolClock") {
297			if (!canvases[i].id) {
298				// If there's no id on this canvas element then give it one
299				canvases[i].id = '_coolclock_auto_id_' + CoolClock.config.noIdCount++;
300			}
301			// Create a clock object for this element
302			new CoolClock({
303				canvasId:       canvases[i].id,
304				skinId:         fields[1],
305				displayRadius:  fields[2],
306				showSecondHand: fields[3]!='noSeconds',
307				gmtOffset:      fields[4],
308				showDigital:    fields[5]=='showDigital',
309				logClock:       fields[6]=='logClock',
310				logClockRev:    fields[6]=='logClockRev'
311			});
312		}
313	}
314};
315
316// If you don't have jQuery then you need a body onload like this: <body onload="CoolClock.findAndCreateClocks()">
317// If you do have jQuery and it's loaded already then we can do it right now
318if (window.jQuery) jQuery(document).ready(CoolClock.findAndCreateClocks);

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.