时钟之Canvas+JS版
写在前面
上一篇介绍使用CSS+JS方式实现,但元素太过单一。此篇将以HTML5的canvas标签结合JS来实现。
HTML代码
<canvas id="clock" width="300" height="300"></canvas>
JS代码
var canvas = null;
var ctx = null;
var interval = null; //计时器
var clockRadius = null; //钟表半径
var hoursCalibrationWidth = 4; //时针刻度宽度
var minutesCalibrationWidth = 1; //分针刻度宽度
var hoursLineWidth = 6; //时针宽度
var minutesLineWidth = 4; //分针宽度
var secondsLineWidth = 2; //秒针宽度
window.addEventListener("visibilitychange", function (event) {
if (document.hidden) {
window.clearInterval(interval);
interval = null;
} else {
startDraw();
}
})
window.addEventListener("load", function () {
canvas = document.getElementById('clock');
if (!canvas.getContext) {
return;
}
//去除透明度
ctx = canvas.getContext('2d', { alpha: true });
//移动中心
ctx.translate(canvas.width / 2, canvas.height / 2);
//设置钟表半径
clockRadius = Math.min(canvas.width, canvas.height) / 2 * 0.95;
//调整路径结束点样式
ctx.lineCap = "round";
//开始绘制
startDraw();
});
function startDraw() {
drawClock();
interval = setInterval(drawClock, 1000);
}
function drawClock() {
// 清除上一次样式
ctx.clearRect(-clockRadius, -clockRadius, 2 * clockRadius, 2 * clockRadius);
ctx.fillStyle = "rgba(0,0,0,0.1)";
ctx.arc(0, 0, clockRadius, 0, 2 * Math.PI);
ctx.fill();
drawCalibration();
drawHourText();
drawDateTime();
drawEdge(clockRadius);
drawCenterCicle();
}
function drawEdge(radius) {
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
const grad = ctx.createRadialGradient(0, 0, radius * 0.95, 0, 0, radius * 1.05);
grad.addColorStop(0, '#eee');
grad.addColorStop(0.1, '#fff');
grad.addColorStop(0.3, '#eee');
grad.addColorStop(0.5, '#666');
grad.addColorStop(0.7, '#eee');
grad.addColorStop(0.9, '#fff');
grad.addColorStop(1, '#fff');
ctx.strokeStyle = grad;
ctx.lineWidth = radius * 0.1;
ctx.stroke();
}
//画时钟圆心
function drawCenterCicle() {
ctx.beginPath();
ctx.arc(0, 0, clockRadius * 0.03, 0, 2 * Math.PI);
ctx.lineWidth = 1;
ctx.strokeStyle = "gray";
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, clockRadius * 0.03, 0, 2 * Math.PI);
ctx.fillStyle = "#eee";
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc(0, 0, clockRadius * 0.02, 0, 2 * Math.PI);
ctx.fill();
}
//画时间
function drawDateTime() {
ctx.strokeStyle = "black";
const date = new Date();
drawDateAndLunar(date);
drawTime(ctx, clockRadius, date);
}
// 画时间时分秒表针
function drawTime(ctx, radius, now) {
let hour = now.getHours();
let minute = now.getMinutes();
let second = now.getSeconds();
// 时
hour = hour % 12;
hour = (hour * Math.PI / 6) + (minute * Math.PI / (6 * 60)) + (second * Math.PI / (360 * 60));
drawHand(ctx, hour, radius * 0.5, radius * 0.05);
// 分
minute = (minute * Math.PI / 30) + (second * Math.PI / (30 * 60));
drawHand(ctx, minute, radius * 0.65, radius * 0.02);
// 秒
second = (second * Math.PI / 30);
drawHand(ctx, second, radius * 0.88, radius * 0.005, 'red');
}
// 画表针
function drawHand(ctx, pos, length, width, color = 'black') {
ctx.beginPath();
ctx.lineWidth = width;
ctx.lineCap = "round";
ctx.moveTo(0, 0);
ctx.rotate(pos);
ctx.lineTo(0, -length);
ctx.strokeStyle = color;
ctx.stroke();
ctx.rotate(-pos);
}
//画时间
function drawHourText() {
ctx.font = "20px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
for (var i = 1; i <= 12; i++) {
ctx.fillStyle = i % 6 == 0 ? "blue" : "#eee";
var theta = (i - 3) * (Math.PI * 2) / 12;
var x = clockRadius * 0.75 * Math.cos(theta);
var y = clockRadius * 0.75 * Math.sin(theta);
ctx.fillText(i, x, y);
}
}
//画刻度线
function drawCalibration() {
for (var i = 0; i < 60; i++) {
ctx.beginPath();
var theta = i * (Math.PI * 2) / 60;
var x = clockRadius * Math.cos(theta);
var y = clockRadius * Math.sin(theta);
ctx.moveTo(x, y);
if (i % 5 == 0) {
ctx.strokeStyle = i % (12 + 3) == 0 ? "red" : "black";
ctx.lineWidth = hoursCalibrationWidth;
ctx.lineTo(0.91 * x, 0.91 * y);
} else {
ctx.strokeStyle = "#eee";
ctx.lineWidth = minutesCalibrationWidth;
ctx.lineTo(0.92 * x, 0.92 * y);
}
ctx.stroke();
}
}
// 画日期及农历
function drawDateAndLunar(date) {
// 绘制周
ctx.beginPath();
ctx.rect(clockRadius * 0.4, -clockRadius * 0.05, clockRadius * 0.1, clockRadius * 0.1)
ctx.lineWidth = 0.2;
ctx.strokeStyle = '#fff';
ctx.stroke();
ctx.beginPath();
ctx.font = clockRadius * 0.08 + 'px ms';
ctx.fillStyle = "#fff";
ctx.textAlign = "center";
ctx.fillText(weekZh(date.getDay()), clockRadius * 0.45, -clockRadius * 0.0001);
// 绘制公历日期
const datestr = date.getFullYear()
+ '-'
+ (date.getMonth() + 1).toString().padStart(2, '0')
+ '-'
+ date.getDate().toString().padStart(2, '0');
ctx.beginPath();
ctx.font = clockRadius * 0.08 + 'px ms';
ctx.fillStyle = "#ffe";
ctx.textAlign = "center";
ctx.fillText(datestr, 0, clockRadius * 0.4);
// 绘制农历日期
const dateLunarstr = transDayToLunarZh(date);
ctx.beginPath();
ctx.font = clockRadius * 0.08 + 'px ms';
ctx.fillStyle = "#eee";
ctx.textAlign = "center";
ctx.fillText(dateLunarstr, 0, clockRadius * 0.5);
}
// 周转中文
function weekZh(weeknum) {
const weeks = ['一', '二', '三', '四', '五', '六', '日'];
return weeks[weeknum - 1];
}
// 农历日期处理
function transDayToLunarZh(date) {
let map = new Map([
['1', '初一'],
['2', '初二'],
['3', '初三'],
['4', '初四'],
['5', '初五'],
['6', '初六'],
['7', '初七'],
['8', '初八'],
['9', '初九'],
['10', '初十'],
['11', '十一'],
['12', '十二'],
['13', '十三'],
['14', '十四'],
['15', '十五'],
['16', '十六'],
['17', '十七'],
['18', '十八'],
['19', '十九'],
['20', '廿'],
['21', '廿一'],
['22', '廿二'],
['23', '廿三'],
['24', '廿四'],
['25', '廿五'],
['26', '廿六'],
['27', '廿七'],
['28', '廿八'],
['29', '廿九'],
['30', '卅'],
]);
const dateLunarstr = date.toLocaleString('zh-Hans-u-ca-chinese')// 转成农历
.match(/(.*?)\s/)[1]// 提取日期部分
.match(/年(\S*)/)[1];// 提取年之后的日期
// 提取月份 及 日转换为中文
let lunarMonth = dateLunarstr.match(/(.*?)月/)[0];
let lunarDay = dateLunarstr.match(/月(\d+)/)[1];
return lunarMonth + map.get(lunarDay.toString());
}
实现效果
原文地址:https://blog.csdn.net/gengzhy/article/details/143789129
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!