Canvas绘制时钟及API说明
Canvas绘制时钟及API说明
此篇博客主要分享个人学习Canvas API过程中的一些心德及之前一些误区,建议过一遍菜鸟教程中的 HTML5 canvas基础知识.在 学习 HTML5 Canvas 这一篇文章就够了这篇博客中也收获颇丰,建议收藏敲一遍代码;
canvas是HTML5新增标签,只定义图形,绘制图形需要利用API及JS来实现;可以进行画线 图形等自定义路径进行绘制;
下边代码会结合个人理解绘制钟表demo作为演示,主要可以逻辑会在下面完整demo代码中备注说明;
一. 创建
由于某些较老的浏览器(尤其是 IE9 之前的 IE 浏览器)不支持元素,可以在标签中声明替代内容。支持 的浏览器会只渲染 标签,而忽略其中的替代内容。不支持 的浏览器则 会直接渲染替代内容。(或者在JS中根据画布的上下文进行判断,下面代码中两种默认声明都会判断)
// 声明canvas
<canvas id="canvas" width="800" height="600">您的浏览器不支持Canvas,请升级或更换浏览器!</canvas>
注意:
1.标签通常需要指定一个id属性方便引用, 元素默认大小是300*150,单位px;宽高需要使用width和height属性声明,而不是css样式控制,行内样式和内联样式都是不对的,会造成绘制的图形跟预想的并不一样.
二.初始化画布
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
if (!ctx) {
alert("您的浏览器不支持Canvas,请升级或更换浏览器!");
return;
}
三.绘制
其实绘制图形分为四步:
- 清除画布 clearRect()
- 保存状态 save()
- 绘制
- 恢复状态 restore()
以绘制表盘刻度为例,每次绘制前先save()保存当前canvas状态,旋转绘制结束后再restore()恢复之前保存状态,再循环进行下一次绘制.
// 刻度
for (let i = 0; i < 60; i++) {
ctx.save();
ctx.beginPath();
ctx.rotate(-PI / 2 + ((2 * PI) / 60) * i);
ctx.moveTo(290, 0);
ctx.lineTo(300, 0);
ctx.strokeStyle = "#fff";
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();
}
注意:
- canvas是基于状态进行绘制的,在每一次进行绘制的时候,canvas不是简单的将上一段代码进行绘制,而是检查在整个程序中设置的所有状态,基于这些状态完成一次绘制。这一点需要理解(可以参考学习 HTML5 Canvas 这一篇文章就够了).所以才会有save()、restore()等.同理绘制路径前的beginPath()也是这个原因
2.补充一下,beginPath()与closePath()没有联系,不是必然成对存在.beginPath是新建路径,closePath的意思不是结束路径,而是关闭路径,它会试图从(MoveTo点之后)当前路径的终点连一条路径到起点,让整个路径闭合起来(优化起点&终点因为线宽缺角问题).简单举例用线段绘制了一个L,在声明closePath后,画布会自动闭合这个绘制路径为一个三角形就是这个意思;
示例demo
以下是一个自适应父级宽高的canvas,在其上绘制钟表的demo;每一步的逻辑都已经解释清楚,注释说明才是我个人最想说明的部分,理解这个逻辑;这个demo非常容易写出来;
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
#wrap {
width: 80vw;
height: 80vh;
border: 2px solid #000;
}
#canvas {
background: #000;
}
</style>
<div id="wrap">
<canvas id="canvas">您的浏览器不支持Canvas,请升级或更换浏览器!</canvas>
</div>
// 获取包裹宽高
var wrap = document.getElementById("wrap"),
wrap_style = window.getComputedStyle(wrap),
wrap_width = wrap_style.width.split("px")[0],
wrap_height = wrap_style.height.split("px")[0];
// 创建画布
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
PI = Math.PI;
window.onload = function () {
init();
};
// 初始化
function init() {
if (!ctx) {
alert("您的浏览器不支持Canvas,请升级或更换浏览器!");
return;
}
// 将父容器的宽高赋值给canvas宽高属性
canvas.width = wrap_width;
canvas.height = wrap_height;
drawClock();
}
// 绘制表盘
function drawClock() {
// 绘制4大步骤
// 1.清除画布
ctx.clearRect(0, 0, wrap_width, wrap_height);
//2.保存状态&位移原点到画布中心
ctx.save();
ctx.translate(wrap_width / 2, wrap_height / 2);
//3.绘制部分
//表盘
ctx.beginPath();
ctx.arc(0, 0, 300, 0, Math.PI * 2);
ctx.strokeStyle = "rgba(255,255,255,1)";
ctx.stroke();
// 刻度
for (let i = 0; i < 60; i++) {
ctx.save();
ctx.beginPath();
ctx.rotate(-PI / 2 + ((2 * PI) / 60) * i);
ctx.moveTo(290, 0);
ctx.lineTo(300, 0);
ctx.strokeStyle = i % 5 === 0 ? "#fff" : "rgba(255,255,255,0.5)";
ctx.lineWidth = i % 5 === 0 ? 3 : 1;
ctx.stroke();
ctx.restore();
}
drawAllHands();
// 4.恢复上一次保存状态
ctx.restore();
// 5.执行动画
window.requestAnimationFrame(drawClock);
}
// 绘制时分秒
function drawAllHands() {
var date = new Date(),
h = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds();
// 注意区分每一刻度 时分秒代表的时间
var s_angle = ((2 * PI) / 60) * s;
var m_angle = ((2 * PI) / 60) * m + s_angle / 60;
var h_angle = ((2 * PI) / 12) * h + m_angle / 12;
drawHand(s_angle, -30, 290, "#fff");
drawHand(m_angle, -20, 250, "green", 4);
drawHand(h_angle, -10, 180, "red", 8);
}
// 绘制指针
function drawHand(angele, start, end, color, width) {
ctx.save();
ctx.beginPath();
ctx.rotate(-PI / 2 + angele);
ctx.moveTo(start, 0);
ctx.lineTo(end, 0);
ctx.strokeStyle = color || "#fff";
ctx.lineWidth = width || 1;
ctx.lineCap = "round" || "butt";
ctx.stroke();
ctx.restore();
}
最后感谢菜鸟教程这两篇教程,自己算是弄懂了canvas的基本功能;
有问题欢迎指正,分享请注明出处.
本文地址:https://blog.csdn.net/qq_38417082/article/details/110100505
上一篇: form表单使用小结
下一篇: 原型链相关知识点学习