Last active
August 29, 2015 14:00
-
-
Save magcks/11153513 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
/** | |
* Canvas Clock (GPLv2) | |
* | |
* @author Max (http://m9x.de) | |
* @version 1.0 | |
* | |
* Original version and design by http://www.board3.de/ | |
* JavaScript clone by Max (m9x.de) | |
*/ | |
/** | |
* A wrapper class emulating a vectorized context for a canvas. | |
* | |
* @param ctx The canvas 2d context. | |
* @param virtual_width The virtual width of the canvas (default: 100). | |
* @param virtual_height The virtual height of the canvas (default:100). | |
*/ | |
function VecCtx(ctx, virtual_width, virtual_height) { | |
this.ctx = ctx; | |
this.virtual_width = virtual_width || 100; | |
this.virtual_height = virtual_height || 100; | |
} | |
/** | |
* Computes the absolute coordinates from the relative ones. | |
* | |
* @param x The x value. | |
* @param y The y value (If the y value is a string ("x" or "y") only the x value will be computed as a x or y value (specified by the string). | |
* @return An array of the absolute coordinates (It will be no array if only one value is given). | |
*/ | |
VecCtx.prototype.rel2abs = function(x, y) { | |
var single = null; | |
if (typeof y == 'string') { | |
single = Number(y == "x"); | |
if (single == 'x') | |
y = 0; | |
else { | |
y = x; | |
x = 0; | |
} | |
} | |
var res = [ (x / this.virtual_width) * this.ctx.canvas.width, (y / this.virtual_height) * this.ctx.canvas.height, ]; | |
if (single !== null) | |
return res[single]; | |
else | |
return res; | |
}; | |
/** | |
* Executes an method to the canvas context. | |
* | |
* @param method The method name. | |
* @param ... The arguments of the method. | |
* @return Return value of the executed method. | |
*/ | |
VecCtx.prototype.exec = function(method) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
var parsed = []; | |
for (var i in args) { | |
if (args[i] instanceof VecCtx.Rel) { | |
var val = this.rel2abs(args[i].x, args[i].y); | |
if (Array.isArray(val)) { | |
parsed.push(val[0]); | |
parsed.push(val[1]); | |
} | |
else | |
parsed.push(val); | |
} | |
else | |
parsed.push(args[i]); | |
} | |
return this.ctx[method].apply(this.ctx, parsed); | |
}; | |
/** | |
* An class to signalize the exec method that this is a relative value. | |
* | |
* @param x The x coordinate. | |
* @param y The y coordinate. | |
*/ | |
VecCtx.Rel = function(x, y) { | |
this.x = x; | |
this.y = y; | |
}; | |
/** | |
* This class draws the clock to the canvas. | |
* | |
* @param canvas The canvas to which the clock should be drawn. | |
* @param refreshTime The time of a refresh cycle. | |
*/ | |
function Clock(canvas, refreshTime) { | |
this.vec = new VecCtx(canvas.getContext("2d"), 100, 100); | |
this.refreshTime = refreshTime || 10; | |
this.interval = null; | |
} | |
/** | |
* Starts the clock interval. | |
*/ | |
Clock.prototype.start = function() { | |
var self = this; | |
this.interval = setInterval(function() { | |
self.refresh(); | |
}, this.refreshTime); | |
this.refresh(); | |
}; | |
/** | |
* Stops the clock interval. | |
*/ | |
Clock.prototype.stop = function() { | |
clearInterval(this.interval); | |
this.interval = null; | |
}; | |
/** | |
* This method is called during a refresh cycle. | |
*/ | |
Clock.prototype.refresh = function() { | |
this.vec.ctx.clearRect(0, 0, this.vec.ctx.canvas.width, this.vec.ctx.canvas.height); | |
this.drawBackground(); | |
this.drawTime(new Date); | |
}; | |
/** | |
* Draw the background art to the canvas. | |
*/ | |
Clock.prototype.drawBackground = function() { | |
var vec = this.vec; | |
var ctx = vec.ctx; | |
var radius = 43; | |
var gradient_background = vec.exec("createLinearGradient", new VecCtx.Rel(0, 0), new VecCtx.Rel(0, 90)); | |
gradient_background.addColorStop(0, "#0077bb"); | |
gradient_background.addColorStop(1, "#12a1e9"); | |
var gradient_border = vec.exec("createLinearGradient", new VecCtx.Rel(0, 0), new VecCtx.Rel(0, 100)); | |
gradient_border.addColorStop(0, "#8a8a8a"); | |
gradient_border.addColorStop(1, "#d9d9d9"); | |
var gradient_border_outer = vec.exec("createLinearGradient", new VecCtx.Rel(0, 0), new VecCtx.Rel(0, 100)); | |
gradient_border_outer.addColorStop(0, "#d9d9d9"); | |
gradient_border_outer.addColorStop(1, "#8a8a8a"); | |
// outer border | |
ctx.beginPath(); | |
vec.exec("arc", new VecCtx.Rel(50, 50), new VecCtx.Rel(radius + 3, "x"), 0, 2 * Math.PI, false); | |
ctx.strokeStyle = gradient_border_outer; | |
ctx.lineWidth = vec.rel2abs(6, "x"); | |
ctx.stroke(); | |
// background | |
ctx.beginPath(); | |
vec.exec("arc", new VecCtx.Rel(50, 50), new VecCtx.Rel(radius, "x"), 0, 2 * Math.PI, false); | |
ctx.fillStyle = gradient_background; | |
ctx.fill(); | |
ctx.strokeStyle = gradient_border; | |
ctx.lineWidth = vec.rel2abs(4, "x"); | |
ctx.stroke(); | |
// reflexion | |
var start_x = 17, start_y = 28; | |
var c1_x = 21, c1_y = 38; | |
var c2_x = 13, c2_y = 35; | |
var c3_x = 25, c3_y = 35; | |
var hor1_c1_x = 35, hor1_c1_y = 5; | |
var hor1_c2_x = 100 - hor1_c1_x, hor1_c2_y = hor1_c1_y; | |
var hor2_c1_x = hor1_c2_x, hor2_c1_y = 28; | |
var hor2_c2_x = hor1_c1_x, hor2_c2_y = hor2_c1_y; | |
ctx.beginPath(); | |
vec.exec("moveTo", new VecCtx.Rel(start_x, start_y)); | |
vec.exec("bezierCurveTo", new VecCtx.Rel(hor1_c1_x, hor1_c1_y), new VecCtx.Rel(hor1_c2_x, hor1_c2_y), new VecCtx.Rel(100 - start_x, start_y)); // top | |
vec.exec("bezierCurveTo", new VecCtx.Rel(100 - c2_x, c2_y), new VecCtx.Rel(100 - c1_x, c1_y), new VecCtx.Rel(100 - c3_x, c3_y)); // right | |
vec.exec("bezierCurveTo", new VecCtx.Rel(hor2_c1_x, hor2_c1_y), new VecCtx.Rel(hor2_c2_x, hor2_c2_y), new VecCtx.Rel(c3_x, c3_y)); // bottom | |
vec.exec("bezierCurveTo", new VecCtx.Rel(c1_x, c1_y), new VecCtx.Rel(c2_x, c2_y), new VecCtx.Rel(start_x, start_y)); // left | |
ctx.fillStyle = "rgba(255, 255, 255, .2)"; | |
ctx.fill(); | |
ctx.strokeStyle = "#fff"; | |
ctx.lineWidth = vec.rel2abs(1, "x"); | |
// marker | |
var markers = 12; | |
var angle = 2 * Math.PI / markers; | |
for (var i = 0; i < markers; ++i) { | |
var current_angle = i * angle; | |
var pos1 = this.angle2xy(current_angle, 43); | |
var pos2 = this.angle2xy(current_angle, 36); | |
ctx.beginPath(); | |
vec.exec("moveTo", new VecCtx.Rel(pos1[0], pos1[1])); | |
vec.exec("lineTo", new VecCtx.Rel(pos2[0], pos2[1])); | |
ctx.stroke(); | |
} | |
}; | |
/** | |
* Draw all pointers to the canvas. | |
* | |
* @param date The current time (JavaScript Date object). | |
*/ | |
Clock.prototype.drawTime = function(date) { | |
var vec = this.vec; | |
var ctx = vec.ctx; | |
var timestamp = (date.getTime() / 1000) % (60 * 60 * 24); | |
timestamp -= date.getTimezoneOffset() * 60; | |
var hours = timestamp / (60 * 60); | |
var minutes = timestamp / 60; | |
var seconds = timestamp; | |
var a_h = this.time2angle(hours, 12); | |
var a_m = this.time2angle(minutes, 60); | |
var a_s = this.time2angle(seconds, 60); | |
// hours | |
ctx.fillStyle = "#000"; | |
this.drawPointer(a_h, -10, 34, 2); | |
// minutes | |
ctx.fillStyle = "#000"; | |
this.drawPointer(a_m, -11, 42, 1); | |
// seconds | |
ctx.fillStyle = "#900"; | |
this.drawPointer(a_s, -12, 43, 1); | |
}; | |
/** | |
* Draw a single pointer to the canvas. | |
* | |
* @param angle The angle of the pointer | |
* @param from The position from the middle of the clock circle the pointer should start (may be negative). | |
* @param to The position from the middle of the clock circle the pointer should end (may be negative but makes no sense). | |
* @param size The size of the thick side of the pointer. | |
*/ | |
Clock.prototype.drawPointer = function(angle, from, to, size) { | |
var vec = this.vec; | |
var ctx = vec.ctx; | |
var pos1 = this.angle2xy(angle, to); | |
var pos2_raw = this.angle2xy(angle, from); | |
var vec_x = pos2_raw[0] - pos1[0]; | |
var vec_y = pos2_raw[1] - pos1[1]; | |
var n = Math.sqrt(vec_x * vec_x + vec_y * vec_y); | |
var pos2 = [ pos2_raw[0] + vec_y / n * size, pos2_raw[1] + -vec_x / n * size, ]; | |
var pos3 = [ pos2_raw[0] + -vec_y / n * size, pos2_raw[1] + vec_x / n * size, ]; | |
ctx.beginPath(); | |
vec.exec("moveTo", new VecCtx.Rel(pos2[0], pos2[1])); | |
vec.exec("lineTo", new VecCtx.Rel(pos1[0], pos1[1])); | |
vec.exec("lineTo", new VecCtx.Rel(pos3[0], pos3[1])); | |
ctx.fill(); | |
}; | |
/** | |
* Converts the time to an angle. | |
* | |
* @param time The time as a double value. | |
* @param base The base of the time format (12 = hours; 60 = minutes or seconds) | |
* @return The angle value (in radians!). | |
*/ | |
Clock.prototype.time2angle = function(time, base) { | |
return (time % base) / base * 2 * Math.PI; | |
}; | |
/** | |
* Converts the angle to coordinates. | |
* | |
* @param time The time as a double value. | |
* @param base The base of the time format (12 = hours; 60 = minutes or seconds) | |
* @return An array of coordinates (index 0 = x; index 1 = y). | |
*/ | |
Clock.prototype.angle2xy = function(angle, radius) { | |
return [ 50 - (radius - 3) * -Math.sin(angle), 50 - (radius - 3) * Math.cos(angle), ]; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Newbe here.
I made a file named clock.js and uploaded it to /forums/styles/aero/theme/images/portal/clock.js
via ACP > Extensions > Portal Modules > Clock Setting I changed the name of Module Image from portal_clock.png to clock.js and where it reads: "Clock: Enter the filename of your clock. The clock needs to be located in styles/yourstyle/theme/images/portal/."
I entered clock.js. Now in Portal http://www.comcom121.org/forums/app.php/portal the digital clock doesn't show but neither does the analog clock.
I also tried putting clock.js in styles/yourstyle/theme/images/portal/clock.js but no luck
No doubt I'm not understanding something.
Kerry