'use strict';
// Analog clock with HTML5/Canvas
// (c) Shingo Minagi 2020-2021
// https://www.minagi.jp/
var appSize = 300;
var canvas, ctx;
var pi = Math.PI;
var starttime = null;
var timezone=null;
window.onload = function () {
// 描画領域の大きさから盤面の直径を求める
appSize = Math.min(window.innerWidth, window.innerHeight);
// URLパラメータを取得する
var search = decodeURI(location.search);
// 「&」をデリミタに分割したトークンの配列
var searches;
// searchesの各要素を「=」をデリミタに分割したトークンの配列
var key_value;
// URLパラメータの解析
if (search) {
search = search.replace('?', '');
searches = search.split('&');
for (var i in searches) {
key_value = searches[i].split('=');
switch (key_value[0].toLowerCase()) {
case 'size':
if (!isNaN(key_value[1])) {
appSize = parseInt(key_value[1]);
}
break;
case 'timezone':
if (!isNaN(key_value[1])) {
timezone = parseFloat(key_value[1]);
}
if(key_value[1]==null){
timezone=null;
}
break;
default:
break;
}
}
}
// DOMオブジェクトの生成
var div = document.createElement('div');
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
div.style.position = 'relative';
canvas.id = 'board';
canvas.style.position = 'absolute';
canvas.style.borderRadius = Math.floor(appSize*0.21)+'px';
canvas.width = appSize;
canvas.height = appSize;
div.appendChild(canvas);
document.body.appendChild(div);
resize();
draw();
}
// 描画領域がリサイズされた時のイベントハンドラ
window.onresize = function () {
resize();
}
// 描画領域がリサイズされた時の処理
function resize() {
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
}
// 2次元座標(x,y)のオブジェクト
var COORDINATES = function (_x, _y) {
this.x = _x;
this.y = _y;
};
// 盤面の直径、角度(時計回り)、中心から外周までの長さに対する割合から
// 盤面上の座標を計算する(盤面が真円である前提)
function getCoordinates(size, degree, percent) {
// 盤面の半径
var r = size / 2;
// 時計の角度を三角関数の角度(反時計回り)に変換する
var theta = (450 - degree) % 360;
// 角度をラジアンに変換する
var radian = theta / 180 * pi;
// 三角関数
var cos = Math.cos(radian);
var sin = Math.sin(radian);
var x, y;
x = r * (1 + cos * percent / 100);
y = r * (1 - sin * percent / 100);
return new COORDINATES(x, y);
}
// getCoordinatesで計算した座標に移動する
function moveTo(context, size, degree, precent) {
var coordinates = getCoordinates(size, degree, precent);
context.moveTo(coordinates.x, coordinates.y);
}
// getCoordinatesで計算した座標へ直線を描く
function lineTo(context, size, degree, precent) {
var coordinates = getCoordinates(size, degree, precent);
context.lineTo(coordinates.x, coordinates.y);
}
// 盤面・針の描画
function draw() {
// 全体をクリアする
ctx.clearRect(0, 0, appSize, appSize);
// 角度
var deg;
// 座標
var xy;
// 周辺を黒色に塗る
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, appSize, appSize);
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(appSize / 2, appSize / 2, appSize / 2 * 0.86, 0, 2 * pi);
ctx.closePath();
ctx.fill();
// 盤面の描画
ctx.strokeStyle = '#000000';
for (var i = 0; i < 12; i++) {
deg = i * 30;
ctx.beginPath();
xy = getCoordinates(appSize, deg, 70);
ctx.moveTo(xy.x, xy.y);
ctx.fillStyle = '#000000';
ctx.font = 'bold '+Math.floor(appSize/12)+'px sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(i == 0 ? '12' : i, xy.x, xy.y, 128);
ctx.closePath();
}
// 針の描画
// 現在時刻を取得する
if(starttime == null){
starttime = new Date().getTime();
}
var currenttime = new Date().getTime();
var elapsedtime = currenttime - starttime;
starttime = currenttime;
var now = new Date(1738213934 + elapsedtime);
if(timezone != null) {
now = new Date(Date.now()+elapsedtime+new Date().getTimezoneOffset()*60*1000+timezone*60*60*1000);
}
var h = now.getHours();
var m = now.getMinutes();
var s = now.getSeconds();
var ms = now.getMilliseconds();
// 総秒数(0時0分0秒からの秒数)
var seconds = h * 60 * 60 + m * 60 + s;
// 時計の角度(中央上が0度)
var deg_h = seconds / 86400 * 2 * 360;
var deg_m = seconds / 3600 * 360;
var deg_s = seconds % 60 * 6;
var deg_ms = ms / 1000 * 6;
// 時針
ctx.strokeStyle = '#000000';
ctx.lineWidth = appSize*0.01; // 1.0.1
ctx.beginPath();
moveTo(ctx, appSize, deg_h, 45); // 1.0.1
lineTo(ctx, appSize, deg_h , 2);
ctx.stroke();
ctx.closePath();
ctx.lineCap='round';
ctx.lineWidth = appSize*0.025; // 1.0.1
ctx.beginPath();
moveTo(ctx, appSize, deg_h, 45); // 1.0.1
lineTo(ctx, appSize, deg_h , 10); // 1.0.1
ctx.stroke();
ctx.closePath();
ctx.lineCap='butt';
// 時針と分針の軸
ctx.lineWidth = appSize*0.01;
ctx.beginPath();
ctx.arc(appSize/2,appSize/2,appSize/2*0.03,0,2*pi); // 1.0.1
ctx.stroke();
ctx.closePath();
// 分針
ctx.strokeStyle = '#000000';
ctx.lineWidth = appSize*0.01;
ctx.beginPath();
moveTo(ctx, appSize, deg_m, 66); // 1.0.1
lineTo(ctx, appSize, deg_m % 360, 4);
ctx.stroke();
ctx.closePath();
ctx.lineCap='round';
ctx.strokeStyle='#000000';
ctx.lineWidth = appSize*0.025; // 1.0.1
ctx.beginPath();
moveTo(ctx, appSize, deg_m, 66); // 1.0.1
lineTo(ctx, appSize, deg_m % 360, 10); // 1.0.1
ctx.stroke();
ctx.closePath();
ctx.lineCap='butt';
// 秒針
ctx.lineCap='round'
ctx.strokeStyle = 'rgb(238,136,52)';
ctx.lineWidth = appSize*0.01;
ctx.beginPath();
moveTo(ctx, appSize, deg_s + deg_ms, 78);
lineTo(ctx, appSize, deg_s + deg_ms, 2.5);
ctx.stroke();
ctx.closePath();
ctx.lineCap='round'
ctx.beginPath();
moveTo(ctx, appSize, (deg_s + deg_ms + 180) % 360, 2.5);
lineTo(ctx, appSize, (deg_s + deg_ms + 180) % 360, 8);
ctx.stroke();
ctx.closePath();
ctx.lineCap='butt';
// 秒針の軸
ctx.lineCap='round'
ctx.lineWidth = appSize*0.01;
ctx.beginPath();
ctx.arc(appSize/2,appSize/2,appSize/2*0.02,0,2*pi); // 1.0.1
ctx.closePath();
ctx.stroke();
ctx.lineCap='butt';
// 30ミリ秒後に自分を呼び出す
setTimeout(draw, 30);
}