Canvas学习-时钟绘制

Canvas学习-时钟绘制

1. 绘制时钟外边框

  • 创建画布
<div class="container">
   <canvas id="clock" height="200px" width="200px"></canvas>
</div>

备注:该容器就是绘制图形的画布。

  • 绘制圆环
var dom = document.getElementById('clock'); //获取元素
var ctx = dom.getContext('2d'); //上下文
var width = ctx.canvas.width; //上下文的宽度
var height = ctx.canvas.height; //上下文的高度
var r = width / 2;  //半径

// 绘制圆环
function drawBackground() {
    ctx.translate(r, r); //确定座标远点
    ctx.beginPath(); //开始画图
    ctx.lineWidth = 10; // 设置线条粗细
    ctx.arc(0, 0, r-5, 0, 2 * Math.PI, false); //绘制圆形
    ctx.stroke(); //绘制

}
drawBackground();

2.绘制时钟内容

    // 绘制小时数
    var hourNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
    ctx.font = '18px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    hourNumbers.forEach(function (number, i) {
        var rad = 2 * Math.PI / 12 * i;
        var x = Math.cos(rad) * (r - 30);
        var y = Math.sin(rad) * (r - 30);
        ctx.fillText(number, x, y);
    })

备注:在绘制小时数的时候,我们应该确定数字与对应弧度的关系,建立数组,填充数字。


3. 绘制小时数对应的圆点

    // 绘制小时数对应的点
    for (var i = 0; i < 60; i++) {
        var rad = 2 * Math.PI / 60 * i;
        var x = Math.cos(rad) * (r - 18);
        var y = Math.sin(rad) * (r - 18);
        ctx.beginPath();
        if (i % 5 === 0) {
            ctx.fillStyle = "#000";
            ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
        } else {
            ctx.fillStyle = "#ccc";
            ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
        }
        ctx.fill();
    }

备注:绘制圆点的时候,我们需要区分整点数与非整点数之间的区别,填充不同的背景颜色。


4.绘制是真分针秒针

// 画时针
function drawHour(hour, minute) {
    ctx.save();
    ctx.beginPath();
    var rad = 2 * Math.PI / 12 * hour;
    var mrad = 2 * Math.PI / 12 / 60 * minute;
    ctx.rotate(rad + mrad);
    ctx.lineWidth = 6;
    ctx.lineCap = 'round';
    ctx.moveTo(0, 10);
    ctx.lineTo(0, -r / 2);
    ctx.stroke();
    ctx.restore();

}

// 画分针
function drawMinute(minute, second) {
    ctx.save();
    ctx.beginPath();
    var rad = 2 * Math.PI / 60 * minute;
    var srad = 2 * Math.PI / 60 / 60 * second;
    ctx.rotate(rad + srad);
    ctx.lineWidth = 3;
    ctx.lineCap = 'round';
    ctx.moveTo(0, 10);
    ctx.lineTo(0, -r + 30);
    ctx.stroke();
    ctx.restore();
}

// 画秒针
function drawSecond(second) {
    ctx.save();
    ctx.beginPath();
    ctx.fillStyle = '#c14543';
    var rad = 2 * Math.PI / 60 * second;
    ctx.rotate(rad);
    ctx.moveTo(-2, 20);
    ctx.lineTo(2, 20);
    ctx.lineTo(1, -r + 18);
    ctx.lineTo(-1, -r + 18);
    ctx.lineTo(0, -r + 30);
    ctx.fill();
    ctx.restore();
}

备注:绘制分针的时候,我们需要考虑到分针对其的影响,所以需要计算分针数引起时针的弧度改变。在绘制分针的时候,同样需要考虑秒针对分针的影响。


4. 画中心点

// 画中心点
function drawDot() {
    ctx.beginPath();
    ctx.fillStyle = '#FFFFFF';
    ctx.arc(0, 0, 3, 2 * Math.PI, false)
    ctx.fill();
}

5. 最终绘制方法

function draw() {
    ctx.clearRect(0, 0, width, height);
    var now = new Date();
    var hour = now.getHours();
    var minute = now.getMinutes();
    var second = now.getSeconds();
    drawBackground();
    drawHour(hour, minute);
    drawMinute(minute, second);
    drawSecond(second);
    drawDot();
    ctx.restore();
}


draw();
setInterval(draw, 1000);

备注:在绘制图形的时候,我们需要注意一下几点:

  • 绘制之前,我们需要清除画布,避免图形的叠加。
  • 主要保存画布之前的状态,还原状态,避免影响。
  • 利用定时器,每隔一秒钟,重新绘制图片。

6. 效果图

在这里插入图片描述


7. 代码

var dom = document.getElementById('clock'); //获取元素
var ctx = dom.getContext('2d'); //上下文
var width = ctx.canvas.width; //上下文的宽度
var height = ctx.canvas.height; //上下文的高度
var r = width / 2;  //半径

// 绘制圆环
function drawBackground() {
    ctx.save();
    ctx.translate(r, r); //确定座标远点
    ctx.beginPath(); //开始画图
    ctx.lineWidth = 10; // 设置线条粗细
    ctx.arc(0, 0, r - 5, 0, 2 * Math.PI, false); //绘制圆形
    ctx.stroke(); //绘制


    // 绘制小时数
    var hourNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
    ctx.font = '18px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    hourNumbers.forEach(function (number, i) {
        var rad = 2 * Math.PI / 12 * i;
        var x = Math.cos(rad) * (r - 30);
        var y = Math.sin(rad) * (r - 30);
        ctx.fillText(number, x, y);
    })


    // 绘制小时数对应的点
    for (var i = 0; i < 60; i++) {
        var rad = 2 * Math.PI / 60 * i;
        var x = Math.cos(rad) * (r - 18);
        var y = Math.sin(rad) * (r - 18);
        ctx.beginPath();
        if (i % 5 === 0) {
            ctx.fillStyle = "#000";
            ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
        } else {
            ctx.fillStyle = "#ccc";
            ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
        }
        ctx.fill();
    }

}




// 画时针
function drawHour(hour, minute) {
    ctx.save();
    ctx.beginPath();
    var rad = 2 * Math.PI / 12 * hour;
    var mrad = 2 * Math.PI / 12 / 60 * minute;
    ctx.rotate(rad + mrad);
    ctx.lineWidth = 6;
    ctx.lineCap = 'round';
    ctx.moveTo(0, 10);
    ctx.lineTo(0, -r / 2);
    ctx.stroke();
    ctx.restore();

}

// 画分针
function drawMinute(minute, second) {
    ctx.save();
    ctx.beginPath();
    var rad = 2 * Math.PI / 60 * minute;
    var srad = 2 * Math.PI / 60 / 60 * minute;
    ctx.rotate(rad + srad);
    ctx.lineWidth = 3;
    ctx.lineCap = 'round';
    ctx.moveTo(0, 10);
    ctx.lineTo(0, -r + 30);
    ctx.stroke();
    ctx.restore();
}

// 画秒针
function drawSecond(second) {
    ctx.save();
    ctx.beginPath();
    ctx.fillStyle = '#c14543';
    var rad = 2 * Math.PI / 60 * second;
    ctx.rotate(rad);
    ctx.moveTo(-2, 20);
    ctx.lineTo(2, 20);
    ctx.lineTo(1, -r + 18);
    ctx.lineTo(-1, -r + 18);
    ctx.lineTo(0, -r + 30);
    ctx.fill();
    ctx.restore();
}

// 画中心点
function drawDot() {
    ctx.beginPath();
    ctx.fillStyle = '#FFFFFF';
    ctx.arc(0, 0, 3, 2 * Math.PI, false)
    ctx.fill();
}

function draw() {
    ctx.clearRect(0, 0, width, height);
    var now = new Date();
    var hour = now.getHours();
    var minute = now.getMinutes();
    var second = now.getSeconds();
    drawBackground();
    drawHour(hour, minute);
    drawMinute(minute, second);
    drawSecond(second);
    drawDot();
    ctx.restore();
}


draw();
setInterval(draw, 1000);

8. 思考

如果画布放大,那么图像会怎么样呢?显然,因为其中部分数据大小是固定写死的,必然出现不协调的地方,此时我们必须考虑到,数据的比例问题。修改思路如下:在宽度、文字大小部分,我们需要采用相对大小。


9. 代码优化

优化思路:首先确定比例,var rem = width/ 200; //比例(因为初始样式的数据是按照200为基准的) ,然后在对应的数字大小部分乘上该比例即可。修改后的代码如下:

var dom = document.getElementById('clock'); //获取元素
var ctx = dom.getContext('2d'); //上下文
var width = ctx.canvas.width; //上下文的宽度
var height = ctx.canvas.height; //上下文的高度
var r = width / 2;  //半径
var rem = width/ 200; //比例(因为初始样式的数据是按照200为基准的)

// 绘制圆环
function drawBackground() {
    ctx.save();
    ctx.translate(r, r); //确定座标远点
    ctx.beginPath(); //开始画图
    ctx.lineWidth = 10 * rem; // 设置线条粗细
    ctx.arc(0, 0, r - ctx.lineWidth/2, 0, 2 * Math.PI, false); //绘制圆形
    ctx.stroke(); //绘制


    // 绘制小时数
    var hourNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
    ctx.font = 18* rem + 'px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    hourNumbers.forEach(function (number, i) {
        var rad = 2 * Math.PI / 12 * i;
        var x = Math.cos(rad) * (r - 30* rem);
        var y = Math.sin(rad) * (r - 30* rem);
        ctx.fillText(number, x, y);
    })


    // 绘制小时数对应的点
    for (var i = 0; i < 60; i++) {
        var rad = 2 * Math.PI / 60 * i;
        var x = Math.cos(rad) * (r - 18* rem);
        var y = Math.sin(rad) * (r - 18* rem);
        ctx.beginPath();
        if (i % 5 === 0) {
            ctx.fillStyle = "#000";
            ctx.arc(x, y, 2* rem, 0, 2 * Math.PI, false);
        } else {
            ctx.fillStyle = "#ccc";
            ctx.arc(x, y, 2* rem, 0, 2 * Math.PI, false);
        }
        ctx.fill();
    }

}




// 画时针
function drawHour(hour, minute) {
    ctx.save();
    ctx.beginPath();
    var rad = 2 * Math.PI / 12 * hour;
    var mrad = 2 * Math.PI / 12 / 60 * minute;
    ctx.rotate(rad + mrad);
    ctx.lineWidth = 6* rem;
    ctx.lineCap = 'round';
    ctx.moveTo(0, 10* rem);
    ctx.lineTo(0, -r / 2);
    ctx.stroke();
    ctx.restore();

}

// 画分针
function drawMinute(minute, second) {
    ctx.save();
    ctx.beginPath();
    var rad = 2 * Math.PI / 60 * minute;
    var srad = 2 * Math.PI / 60 / 60 * second;
    ctx.rotate(rad + srad);
    ctx.lineWidth = 3* rem;
    ctx.lineCap = 'round';
    ctx.moveTo(0, 10* rem);
    ctx.lineTo(0, -r + 30* rem);
    ctx.stroke();
    ctx.restore();
}

// 画秒针
function drawSecond(second) {
    ctx.save();
    ctx.beginPath();
    ctx.fillStyle = '#c14543';
    var rad = 2 * Math.PI / 60 * second;
    ctx.rotate(rad);
    ctx.moveTo(-2* rem, 20* rem);
    ctx.lineTo(2* rem, 20* rem);
    ctx.lineTo(1, -r + 18* rem);
    ctx.lineTo(-1, -r + 18* rem);
    ctx.fill();
    ctx.restore();
}

// 画中心点
function drawDot() {
    ctx.beginPath();
    ctx.fillStyle = '#FFFFFF';
    ctx.arc(0, 0, 3* rem, 2 * Math.PI, false)
    ctx.fill();
}

function draw() {
    ctx.clearRect(0, 0, width, height);
    var now = new Date();
    var hour = now.getHours();
    var minute = now.getMinutes();
    var second = now.getSeconds();
    drawBackground();
    drawHour(hour, minute);
    drawMinute(minute, second);
    drawSecond(second);
    drawDot();
    ctx.restore();
}


draw();
setInterval(draw, 1000);

10. 代码下载

链接:canvas学习代码下载

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章