Canvas - 时钟绘制

导语:距离上一次写canvas,已经过去两年半,如今业务需要,再次拾起,随手记录。

【思考】 时钟的绘制主要在于圆的绘制:1. 使用context.arc()方法直接绘制圆或圆弧; 2. 使用圆的方程(x = r * cosA + X, y = r * sinA + Y)进行描点绘制。指针运行速率较慢,故使用setInterval进行刷新重绘。
【优化】可以使用两个canvas,一个用来绘制表盘,另一个绘制指针,如此,只需刷新重绘指针canvas,表盘canvas保持不变。

<!DOCTYPE html>
<html>
<head>
  <title>Canvas Clock</title>
</head>
<body>
<canvas id="clock">Your borswer does not support canvas element.</canvas>
<script type="text/javascript">
/**
 * 圆的方程:x = r * cosA + X, y = r * sinA + Y
 * 浏览器为了达到抗锯齿的效果会做额外的运算,故为提高渲染效率,均使用整数进行绘制。
 */
(function() {
    let clockCvs = document.getElementById(‘clock‘)
    if (!clockCvs || !clockCvs.getContext) return
    clockCvs.width = 310
    clockCvs.height = 310
    let clockCtx = clockCvs.getContext(‘2d‘)
    // X坐标偏移
    const X = 155
    // Y坐标偏移
    const Y = 155
    // 钟的半径
    const R = 150

    start()
    setInterval(start, 1000)

    function start () {
        clockCtx.clearRect(0, 0, clockCvs.width, clockCvs.height)
        renderClockPlate()
        renderClockTime()
        renderClockHand()
    }

    // 渲染表盘
    function renderClockPlate () {
        drawCircle(X, Y, ‘#070702‘, R, 1)
        drawCircle(X, Y, ‘#4f4f52‘, R - 3, 5)
        drawCircle(X, Y, ‘#070702‘, R - 6, 3)
        drawCircle(X, Y, ‘#dddddd‘, R - 8)
        drawCircle(X, Y, ‘#121213‘, R - 10, 3)
        drawCircle(X, Y, ‘#19191a‘, R - 12, 0, ‘fill‘, true)

        drawCircle(X, Y, ‘#4e4738‘, 15, 0, ‘fill‘)
        drawCircle(X, Y, ‘#eac55a‘, 10, 0, ‘fill‘)
        drawCircle(X, Y, ‘#3e3e41‘, 8, 0, ‘fill‘)
        drawCircle(X, Y, ‘#000000‘, 3, 0, ‘fill‘)
    }

    // 渲染时间
    function renderClockTime () {
        for (let angle = -90; angle < 270; angle = angle + 6) {
            let x = Math.round((R - 18) * Math.cos(angle / 180 * Math.PI) + X)
            let y = Math.round((R - 18) * Math.sin(angle / 180 * Math.PI) + Y)
            let r = angle % 90 === 0 ? 4 : 2
            drawCircle(x, y, ‘#eac55a‘, r, 0, ‘fill‘)
            if (angle % 30 === 0) {
                x = Math.round((R - 35) * Math.cos(angle / 180 * Math.PI) + X - 4)
                y = Math.round((R - 35) * Math.sin(angle / 180 * Math.PI) + Y + 6)
                clockCtx.font = angle % 90 === 0 ? ‘bold 15px yahei‘ : ‘12px yahei‘
                clockCtx.fillText((angle + 90) / 30 || 12, x , y)
            }
        }
    }

    // 渲染表针
    function renderClockHand () {
        let date = new Date()
        let hour = date.getHours()
        let minute = date.getMinutes()
        let second = date.getSeconds()
        // 秒针
        let angle1 = (second * 6 - 90)
        let x = Math.round((R - 45) * Math.cos(angle1 / 180 * Math.PI) + X)
        let y = Math.round((R - 45) * Math.sin(angle1 / 180 * Math.PI) + Y)
        drawLine([[X, Y], [x, y]], 1)
        // 分针
        let angle2 = (minute * 6 - 90)
        x = Math.round((R - 65) * Math.cos(angle2 / 180 * Math.PI) + X)
        y = Math.round((R - 65) * Math.sin(angle2 / 180 * Math.PI) + Y)
        drawLine([[X, Y], [x, y]], 2)
        // 时针, 时针角度 = 小时角度 + 分钟角度
        let angle3 = ((hour % 12) * 30 - 90) + (angle2 / 12)
        x = Math.round((R - 90) * Math.cos(angle3 / 180 * Math.PI) + X)
        y = Math.round((R - 90) * Math.sin(angle3 / 180 * Math.PI) + Y)
        drawLine([[X, Y], [x, y]], 4)

    }

    /**
     * @param {String} color 颜色
     * @param {Number} r 圆半径
     * @param {Number} lineWidth 线条粗细
     * @param {String} type 类型,stroke/fill
     * @param {Boolean} isLinear 是否渐变
     */
    function drawCircle (x, y,color = ‘#000000‘, r = 10, lineWidth = 2, type = ‘stroke‘, isLinear = false) {
        let grd = clockCtx.createLinearGradient(0, 0, clockCvs.width, clockCvs.height)
        grd.addColorStop(0, color)
        grd.addColorStop(0.5, ‘#555555‘)
        grd.addColorStop(1, color)
        clockCtx[type + ‘Style‘] = isLinear ? grd : color
        clockCtx.lineWidth = lineWidth
        clockCtx.beginPath()
        clockCtx.arc(x, y, r, 0, Math.PI * 2, true)
        clockCtx.closePath()
        clockCtx[type]()
    }

    /**
     * @param {Array} pos 坐标点集合,如 [[0, 0], [120, 120]]
     * @param {String} color 颜色
     * @param {Number} lineWidth 线条粗细
     */
    function drawLine (pos, lineWidth = 2, color = ‘#eac55a‘) {
        clockCtx.strokeStyle = color
        clockCtx.lineWidth = lineWidth
        clockCtx.beginPath()
        clockCtx.moveTo(pos[0][0], pos[0][1])
        for (let i = 0, len = pos.length; i < len; i++) {
            clockCtx.lineTo(pos[i][0], pos[i][1])
        }
        clockCtx.stroke()
        clockCtx.closePath()
    }
})()
</script>
</body>
</html>

优化前

<!DOCTYPE html>
<html>
<head>
  <title>Canvas Clock</title>
</head>
<body>
<canvas id="clock" style="position: absolute;">Your borswer does not support canvas element.</canvas>
<canvas id="clockHand" style="position: absolute;">Your borswer does not support canvas element.</canvas>
<script type="text/javascript">
/**
 * 圆的方程:x = r * cosA + X, y = r * sinA + Y
 * 浏览器为了达到抗锯齿的效果会做额外的运算,故为提高渲染效率,均使用整数进行绘制。
 */
(function() {
    let clockCvs = document.getElementById(‘clock‘)
    let clockHandCvs = document.getElementById(‘clockHand‘)
    if (!clockCvs || !clockCvs.getContext) return
    clockCvs.width = clockHandCvs.width = 310
    clockCvs.height = clockHandCvs.height = 310
    let clockCtx = clockCvs.getContext(‘2d‘)
    let clockHandCtx = clockHandCvs.getContext(‘2d‘)
    // X坐标偏移
    const X = 155
    // Y坐标偏移
    const Y = 155
    // 钟的半径
    const R = 150

    renderClockPlate()
    renderClockTime()
    renderClockHand()
    setInterval(function () {
        clockHandCtx.clearRect(0, 0, clockHandCvs.width, clockHandCvs.height)
        renderClockHand()
    }, 1000)

    // 渲染表盘
    function renderClockPlate () {
        drawCircle(clockCtx, clockCvs, X, Y, ‘#070702‘, R, 1)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#4f4f52‘, R - 3, 5)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#070702‘, R - 6, 3)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#dddddd‘, R - 8)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#121213‘, R - 10, 3)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#19191a‘, R - 12, 0, ‘fill‘, true)

        drawCircle(clockCtx, clockCvs, X, Y, ‘#4e4738‘, 15, 0, ‘fill‘)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#eac55a‘, 10, 0, ‘fill‘)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#3e3e41‘, 8, 0, ‘fill‘)
        drawCircle(clockCtx, clockCvs, X, Y, ‘#000000‘, 3, 0, ‘fill‘)
    }

    // 渲染时间
    function renderClockTime () {
        for (let angle = -90; angle < 270; angle = angle + 6) {
            let x = Math.round((R - 18) * Math.cos(angle / 180 * Math.PI) + X)
            let y = Math.round((R - 18) * Math.sin(angle / 180 * Math.PI) + Y)
            let r = angle % 90 === 0 ? 4 : 2
            drawCircle(clockCtx, clockCvs, x, y, ‘#eac55a‘, r, 0, ‘fill‘)
            if (angle % 30 === 0) {
                x = Math.round((R - 35) * Math.cos(angle / 180 * Math.PI) + X - 4)
                y = Math.round((R - 35) * Math.sin(angle / 180 * Math.PI) + Y + 6)
                clockCtx.font = angle % 90 === 0 ? ‘bold 15px yahei‘ : ‘12px yahei‘
                clockCtx.fillText((angle + 90) / 30 || 12, x , y)
            }
        }
    }

    // 渲染表针
    function renderClockHand () {
        let date = new Date()
        let hour = date.getHours()
        let minute = date.getMinutes()
        let second = date.getSeconds()
        // 秒针
        let angle1 = (second * 6 - 90)
        let x = Math.round((R - 45) * Math.cos(angle1 / 180 * Math.PI) + X)
        let y = Math.round((R - 45) * Math.sin(angle1 / 180 * Math.PI) + Y)
        drawLine(clockHandCtx, [[X, Y], [x, y]], 1)
        // 分针
        let angle2 = (minute * 6 - 90)
        x = Math.round((R - 65) * Math.cos(angle2 / 180 * Math.PI) + X)
        y = Math.round((R - 65) * Math.sin(angle2 / 180 * Math.PI) + Y)
        drawLine(clockHandCtx, [[X, Y], [x, y]], 2)
        // 时针, 时针角度 = 小时角度 + 分钟角度
        let angle3 = ((hour % 12) * 30 - 90) + (angle2 / 12)
        x = Math.round((R - 90) * Math.cos(angle3 / 180 * Math.PI) + X)
        y = Math.round((R - 90) * Math.sin(angle3 / 180 * Math.PI) + Y)
        drawLine(clockHandCtx, [[X, Y], [x, y]], 4)
    }

    /**
     * @param {String} color 颜色
     * @param {Number} r 圆半径
     * @param {Number} lineWidth 线条粗细
     * @param {String} type 类型,stroke/fill
     * @param {Boolean} isLinear 是否渐变
     */
    function drawCircle (ctx, cvs, x, y,color = ‘#000000‘, r = 10, lineWidth = 2, type = ‘stroke‘, isLinear = false) {
        let grd = ctx.createLinearGradient(0, 0, cvs.width, cvs.height)
        grd.addColorStop(0, color)
        grd.addColorStop(0.5, ‘#555555‘)
        grd.addColorStop(1, color)
        ctx[type + ‘Style‘] = isLinear ? grd : color
        ctx.lineWidth = lineWidth
        ctx.beginPath()
        ctx.arc(x, y, r, 0, Math.PI * 2, true)
        ctx.closePath()
        ctx[type]()
    }

    /**
     * @param {Array} pos 坐标点集合,如 [[0, 0], [120, 120]]
     * @param {String} color 颜色
     * @param {Number} lineWidth 线条粗细
     */
    function drawLine (ctx, pos, lineWidth = 2, color = ‘#eac55a‘) {
        ctx.strokeStyle = color
        ctx.lineWidth = lineWidth
        ctx.beginPath()
        ctx.moveTo(pos[0][0], pos[0][1])
        for (let i = 0, len = pos.length; i < len; i++) {
            ctx.lineTo(pos[i][0], pos[i][1])
        }
        ctx.stroke()
        ctx.closePath()
    }
})()
</script>
</body>
</html>

优化后

时间: 2024-11-09 00:19:56

Canvas - 时钟绘制的相关文章

canvas时钟绘制

index.html <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>时钟</title> <style> div{ text-align: center; margin-top: 250px; } </style> </head> <body> <d

canvas基础绘制-绚丽时钟

效果图: 与canvas基础绘制-绚丽倒计时的代码差异: // var endTime = new Date();//const声明变量,不可修改,必须声明时赋值: // endTime.setTime( endTime.getTime() + 3600*1000);//当前时间向后一小时: var curShowTimeSeconds = 0; function getCurrentShowTimeSeconds() { var curTime = new Date();//获取目前时间: /

原生js之canvas时钟组件

canvas一直是前端开发中不可或缺的一种用来绘制图形的标签元素,比如压缩上传的图片.比如刮刮卡.比如制作海报.图表插件等,很多人在面试的过程中也会被问到有没有接触过canvas图形绘制. 定义 canvas元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成. canvas标签只是图形容器,您必须使用脚本来绘制图形. 浏览器支持 Internet Explorer 9.Firefox.Opera.Chrome 和 Safari 支持 那么本篇文章就通过一个时钟组件来熟悉使用一下关

HTML5在canvas中绘制复杂形状附效果截图

HTML5在canvas中绘制复杂形状附效果截图 一.绘制复杂形状或路径 在简单的矩形不能满足需求的情况下,绘图环境提供了如下方法来绘制复杂的形状或路径. beginPath() : 开始绘制一个新路径. closePath() : 通过绘制一条当前点到路径起点的线段来闭合形状. fill() , stroke() : 填充形状或绘制空心形状. moveTo() : 将当前点移动到点(x,y). lineTo() : 从当前点绘制一条直线到点(x,y). arc(x,y,r,sAngle,eAn

Android中使用SurfaceView和Canvas来绘制动画

其实每个View中都有Canvas可以用来绘制动画,只需要在这个View中重载onDraw()方法就可以,但是SurfaceView类是一个专门用来制动动画的类. Canvas(中文叫做"画布")就和HTML5中的canvas标签一样可以在一定区域内自由绘制图形.Canvas+SurfaceView制作的动画与View Animation和Property Animation这类动画比起来更加适合大量的集中播放的动画,比如游戏画面.相机的图像显示等. 因为SurfaceView通常会在

HTML5 在canvas中绘制矩形

作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/32930501 一.绘制矩形 canvas使用原点(0,0)在左上角的坐标系统,x坐标向右递增,y坐标向下递增. 使用绘图环境的矩形绘制函数来绘制矩形. fillRect(x,y,width,height) : 绘制一个实心的矩形. strokeRect(x,y,width,height) : 绘制一个空心的矩形. clearRect(x,y,width,height) : 清

[HTML5 Canvas学习]绘制矩形

1.使用strokeRect和fillRect方法绘制矩形 a.strokeRect是绘制一个不填充的矩形 b.fillRect是绘制一个填充的矩形 代码: <script> var canvas = document.getElementById('canvas'), context = canvas.getContext('2d'); context.lineJoin = 'round'; context.lineWidth = 20; context.strokeRect(10, 10,

canvas基础绘制-绚丽倒计时

效果图: html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ball</title> <script src="digit_1.js"></script> <script src="countdown.js"></

HTML5 在canvas中绘制复杂形状

作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/32942667 一.绘制复杂形状或路径 在简单的矩形不能满足需求的情况下,绘图环境提供了如下方法来绘制复杂的形状或路径. beginPath()  : 开始绘制一个新路径. closePath()  : 通过绘制一条当前点到路径起点的线段来闭合形状. fill() , stroke()  : 填充形状或绘制空心形状. moveTo()  : 将当前点移动到点(x,y). lin