两种用js设计时钟的方法

方式一:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf8">
    <meta name="keywords" content="clock">
    <meta name="description" content="This is a clock">
    <title>Clock</title>
</head>
<body>
<audio id="ticktock">
    <source = src="ticktock.mp3" type="audio/mp3">
</audio>
<script type="text/javascript">
    /* 年(y)可以用 1-4 个占位符 月(M)、日(d)、时(H,24时)、时(h,12时)、分(m)、秒(s)、季度(q)
    可以用 1-2 个占位符 毫秒(S)只能用 1 个占位符(是 1-3 位数字)
    AM或PM只能用 1 个占位符(是 2 位英文)
    上午或下午(T)只能用 1 个占位符(是 2 位中文)
    星期(E)可以用 1-3 个占位符 季度(q)
    只能用 1 个占位符(是 1 位数字) */
    Date.prototype.format = function(fmt) {
        var map = {
            "M+" : this.getMonth() + 1,
            //月
            "d+" : this.getDate(),
            //日
            "H+" : this.getHours(),
            //24时
            /*  上午12时只代表当天上午的12时,下午的12时代表当天下午的12时,
            0时代表第二天的开始,即前面一天12时已过0时开始计算新一天的时间,
            虽然说时间上跟前面那一天下午12时重合,但日期已经发生更改,所以不能说0时就是12时  */
            "h+" : this.getHours()%12 == 0 ? 12 : this.getHours()%12,
            //12时
            "m+" : this.getMinutes(),
            //分
            "s+" : this.getSeconds(),
            //秒
            "S" : this.getMilliseconds(),
            //毫秒
            "t" : this.getHours() < 12 ? "AM" : "PM",  "T" : this.getHours() < 12 ? "上午" : "下午",
        };
        var week = {  "0" : "日",  "1" : "一",  "2" : "二",  "3" : "三",  "4" : "四",  "5" : "五",  "6" : "六", }
        var quarter = {  "0" : "一",  "1" : "二",  "2" : "三",  "3" : "四", }
        if(/(y+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
        }
        if(/(E+)/.test(fmt)) {
            var weekPreStr;
            switch(RegExp.$1.length) {
                case 1:  weekPreStr = "";
                    break;
                case 2:  weekPreStr = "周";
                    break;
                default:  weekPreStr = "星期";
                    break;
            }
            fmt = fmt.replace(RegExp.$1, weekPreStr + week[this.getDay()]);
        }
        if(/(q)/.test(fmt)) {  fmt = fmt.replace(RegExp.$1, quarter[Math.floor(this.getMonth() / 3)]); }
        for(var key in map) {
            if(new RegExp("(" + key + ")").test(fmt)) {
                fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? map[key] : ("00" + map[key]).substr((map[key]+"").length));
            }
        }
        return fmt;
    }
</script>
<script type="text/javascript">
    var canvas = document.createElement("canvas");
    document.body.appendChild(canvas);
    var ctx = canvas.getContext("2d");
    var halfPI = Math.PI / 2;
    var doublePI = Math.PI * 2;
    //阴影级别
    var shadowBlur = 10;
    //阴影宽度
    var shadowWidth = 10;
    //阴影在X方向上的偏移
    var shadowOffsetX = 5;
    //阴影在Y方向上的偏移
    var shadowOffsetY = 5;
    //深色阴影
    var shadowDarkColor = "rgba(0,0,0,0.8)";
    //浅色阴影
    var shadowLightColor = "rgba(0,0,0,0.1)";
    //画布中心到边缘的内切圆半径
    var canvasRadius = 250;
    canvas.width = canvasRadius * 2;
    canvas.height = canvasRadius * 2;
    //获取画布中心的坐标
    var cx = canvasRadius;
    var cy = canvasRadius;
    //时钟外圈的贝塞尔花纹个数
    var bezierPatternCount = 10;
    //时钟外圈的贝塞尔花纹波峰处半径
    var bezierPeakRadius = canvasRadius - 10;
    //时钟外圈的贝塞尔花纹一半的角度
    var bezierHalfSpan = doublePI / bezierPatternCount / 2;
    //时钟外圈的贝塞尔花纹底部半径
    var bezierRadius = bezierPeakRadius - 20;
    //时钟外圈的贝塞尔花纹颜色
    var bezierPatternColor = "Plum";
    //时钟外圈半径
    var clockBorderRadius = bezierRadius - 10;
    //时钟外圈宽度
    var clockBorderWidth = 10;
    //时钟外圈颜色
    var clockBorderColor = "Aqua";
    //时钟外圈阴影半径
    var clockBorderShadowRadius = clockBorderRadius - shadowWidth + 1;
    //时钟整数时间刻度线宽
    var clockScaleWidth = 2;
    //时钟整数时间刻度外半径
    var clockScaleOuterRadius = clockBorderRadius - shadowWidth;
    //时钟整数时间刻度内半径
    var clockScaleInnerRadius = clockScaleOuterRadius - 20;
    //时钟刻度颜色
    var clockScaleColor = "Black";
    //时钟非整数时间处半径
    var clockScaleMiddleRadius = clockScaleOuterRadius - 10;
    //时钟数字半径
    var clockNumRadius = clockBorderShadowRadius - 40;
    //时钟数字字体
    var clockNumFont = "25px Arial";
    //时钟数字颜色
    var clockNumColor = "black";
    //数字日期距中心的垂直距离
    var digitalDateMarginCenter = 50;
    //数字日期颜色
    var digitalDateColor = "Black";
    //数字日期字体
    var digitalDateFont = "bold 18px Arial";
    //数字时间距中心的垂直距离
    var digitalTimeMarginCenter = 100;
    //数字时间颜色
    var digitalTimeColor = "white";
    //数字时间背景颜色
    var digitalTimeBgColor = "DarkSlateBlue";
    //数字时间字体
    var digitalTimeFont = "bold 25px Arial";
    //数字时间高度的一半
    var digitalTimeHeight = 40;
    //数字时间分隔线宽度
    var digitalTimeSpanLineWidth = 2;
    //时钟中心点内圆的半径
    var clockCenterInnerDotRadius = 7;
    //时钟中心点内圆的颜色
    var clockCenterInnerDotColor = "FireBrick";
    //时钟中心点外圆的半径
    var clockCenterOuterDotRadius = 10;
    //时钟中心点外圆的颜色
    var clockCenterOuterDotColor = "Maroon";
    //时针线宽
    var clockNeedleWidth = 5;
    //时针半径
    var clockHourNeedleRadius = clockBorderShadowRadius - 120;
    //时针颜色
    var clockHourNeedleColor = "DarkGreen";
    //分针半径
    var clockMinuteNeedleRadius = clockBorderShadowRadius - 80;
    //分针颜色
    var clockMinuteNeedleColor = "DarkSlateGray";
    //秒针半径
    var clockSecondNeedleRadius = clockBorderShadowRadius - 40;
    //秒针尾部半径
    var clockSecondNeedleBottomRadius = -20;
    //秒针颜色
    var clockSecondNeedleColor = "FireBrick";
    //画圆环
    function strokeCircle(cx, cy, r) { ctx.beginPath(); ctx.arc(cx, cy, r, 0, doublePI); ctx.stroke(); }
    //画圆
    function fillCircle(cx, cy, r) { ctx.beginPath(); ctx.arc(cx, cy, r, 0, doublePI); ctx.fill(); }
    //绘制线条
    function strokeLine(x1, y1, x2, y2) { ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); }
    //根据角度和半径计算圆上相应位置的坐标(最右侧为起始角度,顺时针方向为正)
    function circlePos(cx, cy, theta, radius) {
        var pos = {  x: cx + radius * Math.cos(theta),  y: cy + radius * Math.sin(theta), };
        return pos;
    }
    //在圆环上绘制刻度线
    function strokeCircleLine(cx, cy, theta, r1, r2) {
        var pos1 = circlePos(cx, cy, theta, r1);
        var pos2 = circlePos(cx, cy, theta, r2);
        strokeLine(pos1.x, pos1.y, pos2.x, pos2.y);
    }
    //设置默认阴影
    function setShadow(type) {
        ctx.lineWidth = shadowWidth;
        ctx.shadowBlur = shadowBlur;
        ctx.shadowOffsetX = shadowOffsetX;
        ctx.shadowOffsetY = shadowOffsetY;
        if(type === 1) {
            ctx.shadowColor = shadowLightColor;
        } else {
            ctx.shadowColor = shadowDarkColor;
        }
    }
    //取消阴影
    function clearShadow() {
        ctx.shadowColor = "rgba(0,0,0,0)";
        ctx.shadowBlur = 0;
        ctx.shadowOffsetX = 0;
        ctx.shadowOffsetY = 0;
    }
    //绘制时钟外圈的贝塞尔花纹
    function renderBezierPattern() {
        ctx.fillStyle = bezierPatternColor;
        ctx.beginPath();
        var theta = 0;
        //由于circlePos是顺时针方向正, 故圈也是顺时针方向
        var beginPos = circlePos(cx, cy, theta, bezierRadius);
        ctx.moveTo(beginPos.x, beginPos.y);
        while(theta < doublePI) {
            //贝塞尔曲线控制点
            var controlTheta = theta + bezierHalfSpan;
            var controlPos = circlePos(cx, cy, controlTheta, bezierPeakRadius);
            //贝塞尔曲线终止点
            var endTheta = controlTheta + bezierHalfSpan;
            var endPos = circlePos(cx, cy, endTheta, bezierRadius);
            ctx.quadraticCurveTo(controlPos.x, controlPos.y, endPos.x, endPos.y);
            theta = endTheta;
        }
        //绘制圆counterclockwise=false, 即默认是顺时针方向
        ctx.arc(cx, cy, clockBorderRadius, 0, doublePI, true);
        //注意: 两个相反方向的路径内部为填充范围
        ctx.fill();
    }
    //绘制时钟边框
    function renderClockBorder() {
        //画外框
        ctx.strokeStyle = clockBorderColor;
        ctx.lineWidth = clockBorderWidth;
        strokeCircle(cx, cy, clockBorderRadius);
        //画外框的内阴影
        ctx.strokeStyle = shadowLightColor;
        setShadow(1); strokeCircle(cx, cy, clockBorderShadowRadius);
        clearShadow();
    }
    //绘制时钟圆周上的数字和刻度部分
    function renderClockNums() {
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.font = clockNumFont; var span = doublePI / 60;
        for(var i = 1, radian = -halfPI + span; i <= 60; i++, radian += span) {  if(i % 5 == 0) {
            //绘制刻度
            ctx.strokeStyle = clockScaleColor;
            ctx.lineWidth = clockScaleWidth;
            strokeCircleLine(cx, cy, radian, clockScaleInnerRadius, clockScaleOuterRadius);
            //绘制数字
            var pos = circlePos(cx, cy, radian, clockNumRadius);  var num = i / 5;
            ctx.fillStyle = clockNumColor;  ctx.fillText(num, pos.x, pos.y);
        } else {
            ctx.strokeStyle = clockScaleColor;
            ctx.lineWidth = clockScaleWidth;
            strokeCircleLine(cx, cy, radian, clockScaleMiddleRadius, clockScaleOuterRadius);
        }
        }
    }
    //绘制数字时钟
    function renderDigital(date) {
        //绘制日期
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.font = digitalDateFont;
        ctx.fillStyle = digitalDateColor;
        var text = date.format("yyyy年MM月dd日 EEE");
        ctx.fillText(text, cx, cy + digitalDateMarginCenter);
        //绘制时间
        ctx.font = digitalTimeFont; text = date.format(" HH mm ss ");
        ctx.fillStyle = digitalTimeBgColor; var textWidth = ctx.measureText(text).width;
        var textBgX = cx - textWidth / 2;
        var textBgY = cy + digitalTimeMarginCenter - digitalTimeHeight / 2;
        ctx.fillRect(textBgX, textBgY, textWidth, digitalTimeHeight);
        ctx.fillStyle = digitalTimeColor;
        ctx.fillText(text, cx, cy + digitalTimeMarginCenter);
        //绘制事件中间的分隔线
        ctx.lineWidth = digitalTimeSpanLineWidth;
        ctx.strokeStyle = digitalTimeColor;
        var textSpan = textWidth / 6;
        var leftLineX = cx - textSpan;
        strokeLine(leftLineX, textBgY, leftLineX, textBgY + digitalTimeHeight);
        var rightLineX = cx + textSpan; strokeLine(rightLineX, textBgY, rightLineX, textBgY + digitalTimeHeight);
    }
    //绘制时钟中心最下方红点
    function renderClockCenterOuterDot() {
        ctx.fillStyle = clockCenterOuterDotColor; fillCircle(cx, cy, clockCenterOuterDotRadius);
    }
    //绘制时钟中心最上方红点
    function renderClockCenterInnerDot() {
        ctx.fillStyle = clockCenterInnerDotColor; fillCircle(cx, cy, clockCenterInnerDotRadius);
    }
    //绘制时钟指针
    function renderClockNeedle(date) {
        var hourRadian = date.getHours() % 12 / 12 * doublePI - halfPI;
        var minuteRadian = date.getMinutes() / 60 * doublePI - halfPI;
        var secondRadian = date.getSeconds() / 60 * doublePI - halfPI;
        setShadow();
        ctx.lineCap = "round";
        ctx.lineWidth = clockNeedleWidth;
        ctx.strokeStyle = clockHourNeedleColor;
        strokeCircleLine(cx, cy, hourRadian, 0, clockHourNeedleRadius);
        ctx.strokeStyle = clockMinuteNeedleColor;
        strokeCircleLine(cx, cy, minuteRadian, 0, clockMinuteNeedleRadius);
        ctx.strokeStyle = clockSecondNeedleColor;
        strokeCircleLine(cx, cy, secondRadian, clockSecondNeedleBottomRadius, clockSecondNeedleRadius);
        ctx.lineCap = "square";
        clearShadow();
    }
    function render(date) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        renderBezierPattern();
        renderClockBorder();
        renderClockNums();
        renderDigital(date);
        renderClockCenterOuterDot();
        renderClockNeedle(date);
        renderClockCenterInnerDot();
    }
    var lastTime = 0;
    var audio = document.getElementById("ticktock");
    function loop() {
        var date = new Date();
        var currentTime = date.getTime();
        if(currentTime - lastTime >= 1000) {
            lastTime = currentTime;
            //注意:这里设0非常关键,否则虽然会循环播放,但会从上一次暂停的地方开始播放,造成延迟
            audio.currentTime = 0;
            audio.play();
            render(date);
        }
        requestAnimationFrame(loop);
    }
    loop();
</script>
</body>
</html>

以上代码运行结果如下:

方式二:

<!DOCTYPE html>

<html>
<head>
    <title>时钟</title>
</head>
<body>
    <canvas width="500" height="500" margin="360px auto"  display="block"  id="clock">
    您的浏览器当前版本不支持canvas表签
    </canvas>
    <script>
        var clock = document.getElementById("clock");
        var cxt = clock.getContext('2d');

        function drawClock(){
            cxt.clearRect(0,0,500,500); //清除画布
            //获取时间
            var now = new Date();   //定义时间
            var sec = now.getSeconds();  //获取秒
            var minute = now.getMinutes();  //获取分钟
            var hour = now.getHours();   //获取小时
            //小时必须获取浮点类型,产生偏移(小时+分钟比)
            hour = hour + minute/60;
            //将24小时转换为12小时
            hour=hour>12?hour-12:hour;
            //刻度
            //时针刻度
            for(var i=0; i<12; i++){
                cxt.save();
                //设置时针的样式
                cxt.lineWidth=7;
                cxt.strokeStyle="blue";
                //设置异次元空间原点
                cxt.translate(250,250);
                //设置旋转角度
                cxt.rotate(i*30*Math.PI/180);
                cxt.beginPath();
                cxt.moveTo(0,-170); //画线, 从坐标0,-170开始
                cxt.lineTo(0,-190); //到坐标0,-190结束
                cxt.stroke();
                cxt.closePath();
                cxt.restore();
            }
            //分针刻度
            for(var i=0; i<60;i++){
                cxt.save();
                cxt.lineWidth=5;
                cxt.strokeStyle="#4950a9";
                cxt.translate(250,250);
                cxt.rotate(i*6*Math.PI/180);
                cxt.beginPath();
                cxt.moveTo(0,-180);
                cxt.lineTo(0,-190);
                cxt.stroke();
                cxt.closePath();
                cxt.restore();
            }

            //时针
            cxt.save();
            //时针样式
            cxt.lineWidth = 7;
            cxt.strokeStyle="#4da96d";
            cxt.translate(250,250);
            cxt.rotate(hour*30*Math.PI/180);
            cxt.beginPath();
            cxt.moveTo(0,-140);
            cxt.lineTo(0,10);
            cxt.stroke();
            cxt.closePath();

            cxt.restore();

            //分针
            cxt.save();
            //分针样式
            cxt.lineWidth = 5;
            cxt.strokeStyle="#000000";
            cxt.translate(250,250);
            cxt.rotate(minute*6*Math.PI/180);
            cxt.beginPath();
            cxt.moveTo(0,-160);
            cxt.lineTo(0,15);
            cxt.stroke();
            cxt.closePath();

            cxt.restore();

            //秒针
            cxt.save();
            cxt.lineWidth = 3;
            cxt.strokeStyle="#a9a9a9";
            cxt.translate(250,250);
            cxt.rotate(sec*6*Math.PI/180);
            cxt.beginPath();
            cxt.moveTo(0,-185);
            cxt.lineTo(0,20);
            cxt.stroke();
            cxt.closePath();

            //画出时针,分针,秒针交叉点
            cxt.beginPath();
            cxt.strokeStyle="#ff433f";
            cxt.arc(0,0,5,0,360,false);
            cxt.fillStyle="#cbe281";   //填充颜色
            cxt.fill();   //填充
            cxt.stroke();
            cxt.closePath();

            //秒针装饰
            cxt.beginPath();
            cxt.strokeStyle="#f00";
            cxt.arc(0,-160,5,0,360,false);
            cxt.fill();
            cxt.stroke();
            cxt.closePath();
            cxt.restore();
        }
        //使用setinterval();让时钟动起来
        drawClock();
        setInterval(drawClock,1000);
    </script>
    <audio autoplay="autoplay" loop="loop" preload="auto"
           src="https://nj01ct01.baidupcs.com/file/9a0cb84855a678eaf976dbfb91bbb7fd?bkt=p3-14009a0cb84855a678eaf976dbfb91bbb7fda550bbd300000010538d&fid=4187048366-250528-833429510540241&time=1541485015&sign=FDTAXGERLQBHSKW-DCb740ccc5511e5e8fedcff06b081203-%2FPCDb6JE9IcQmwOZU23l9EWJ4cU%3D&to=63&size=1069965&sta_dx=1069965&sta_cs=1&sta_ft=mp3&sta_ct=5&sta_mt=5&fm2=MH%2CYangquan%2CAnywhere%2C%2Cguangdong%2Cct&ctime=1526541198&mtime=1526541542&resv0=cdnback&resv1=0&vuk=4187048366&iv=0&htype=&newver=1&newfm=1&secfm=1&flow_ver=3&pkey=14009a0cb84855a678eaf976dbfb91bbb7fda550bbd300000010538d&sl=76480590&expires=8h&rt=pr&r=784764042&mlogid=7180383717541960870&vbdid=462734660&fin=%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80+-+%E5%87%A4%E6%B1%82%E5%87%B0.mp3&fn=%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80+-+%E5%87%A4%E6%B1%82%E5%87%B0.mp3&rtype=1&dp-logid=7180383717541960870&dp-callid=0.1.1&hps=1&tsl=80&csl=80&csign=1xfXWaODMyPBR0bq3Ls1VTXchHM%3D&so=0&ut=6&uter=4&serv=0&uc=3073435127&ti=5902310e0d478cb66ec39ff6665d0bf45324a4534cb63f8a&by=themis">
        你的浏览器不支持audio标签
    </audio>
    <h2>
    </h2>
</center>
<div id="Layer1" style="position: absolute; width: 100%; height: 100%; z-index: -1; center: 0; top: 0;">
    <img src="http://shp.qpic.cn/ishow/2735012715/1485500432_1644740874_17754_sProdImgNo_6.jpg/0" height="100%" width="100%"  style="left: 0; top: 0;"/>
</div>
</body>
</html>

以上代码运行结果如下:

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值