自学内容网 自学内容网

时钟之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)!