Canvas基础以及动态时钟的实现
写在前面
HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成,<canvas> 标签只是图形容器,和别的标签不同,我们不在<canvas>标签里面写内容,必须使用脚本来绘制图形。Canvas是一个行内块元素。
Canvas基础
-
画布的创建,在绘图之前我们首先是需要一张“纸”,默认情况下 <canvas> 元素没有边框和内容。
<canvas id="myCanvas" width="200" height="100"></canvas>
-
标签通常需要指定一个id属性 (脚本中经常引用), width 和 height 属性定义的画布的大小
-
在<canvas>上绘制
-
首先要获取到canvas元素
-
创建context对象 (这里我们可以利用判断是否有上下文对象来判断浏览器是否支持)
var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d");
-
-
2D上下文
- 使用2d绘图上下文提供的方法,可以绘制简单的2D图形,比如矩形、弧形和路径等。2D上下文的起始位置是<canvas>画布的左上角,原点坐标为(0,0)。所有的坐标值都是基于这个点计算的,x越大表示越靠右,y越大表示越靠下。大家在绘图时候可以在脑海中构建一个坐标系。width和height表示在这两个方向上可用的像素数目。
-
线条和填充、路径
- 路径
方法 | 描述 | 属性值 |
---|---|---|
stroke() | 绘制已定义的路径 | 无 |
beginPath() | 起始一条路径,或重置当前路径 | 无 |
closePath() | 创建从当前点回到起始点的路径 | 无 |
lineTo() | 添加一个新点,然后在画布中创建从该点到最后指定点的线条 | 坐标 |
arc() | 创建弧/曲线(用于创建圆形或部分圆) | (x,y,r,sAngle,eAngle,counterclockwise) |
moveTo() | 把路径起始位置移动到画布中的指定点,不创建线条 | 坐标 |
- 线条
方法 | 描述 | 属性值 |
---|---|---|
lineCap() | 设置或返回线条的结束端点样式 | butt:向线条的每个末端添加平直的边缘。round:向线条的每个末端添加圆形线帽。square:向线条的每个末端添加正方形线帽。 |
lineWidth() | 设置或返回当前的线条宽度 | number:当前线条的宽度,以像素计。 |
- 填充
方法 | 描述 | 属性值 |
---|---|---|
fillStyle() | 设置或返回用于填充绘画的颜色、渐变或模式 | color:指示绘图填充色的CSS颜色值;gradient:用于填充绘图的渐变对象 |
fill() | 填充当前绘图(路径) | 无 |
实例:
<body>
<canvas id="canvas" width="200" height="200"></canvas>
</body>
<script>
var convas = document.getElementById('canvas');
var ctx = convas.getContext('2d');
ctx.moveTo(100, 100);
ctx.lineTo(150, 150);
ctx.lineTo(80, 150);
ctx.lineWidth = 5;
ctx.strokeStyle = "#ccc";
ctx.stroke()
ctx.fill()
</script>
-
文本、转化和保存
- 文本
方法 描述 属性值 font 设置或返回文本内容的当前字体属性 font-style、font-variant、font-weight textAlign 设置或返回文本内容的当前对齐方式 center、left、right、start、end textBaseline 设置或返回在绘制文本时使用的当前文本基线 middle、top、buttom - 转化
方法 描述 属性值 scale() 缩放当前绘图至更大或更小 scalewidth:缩放当前绘图的宽度(1=100%);scaleheight:缩放当前绘图的高度 rotate() 旋转当前绘图 angle:角度 transalte() 重新映射画布上的 (0,0) 位置 坐标(x,y) - 保存
方法 描述 属性值 save() 保存当前环境的状态 无 restore() 返回之前保存过的路径状态和属性 无 -
绘制弧线的方法(利用arc()方法)
arc(x,y,r,sAngle,eAngle,counterclockwise)
x,y就是画这个弧线的圆心坐标;r为半径值;sAngle,eAngle就是起始角和结束角;counterclockwise是表示画的方向,false为顺时针,true为逆时针。
sAngle,eAngle的具体可见下图(记住起始位置不是在上面而是在右边)
Tip:当我们使用顺时针画和逆时针画是不同的,要注意区分,请看下面例子,只是画的方向不同,图形也不同
var convas = document.getElementById('canvas');
var ctx = convas.getContext('2d');
ctx.beginPath()
ctx.arc(100, 100, 50, 0, 1.5 * Math.PI, false) //顺时针画法
ctx.stroke()
ctx.closePath()
ctx.beginPath()
ctx.arc(200, 100, 50, 0, 1.5 * Math.PI, true)//逆时针画法
ctx.stroke()
ctx.closePath()
动态时钟案例
原理:通过canvas绘制时钟的每一个线段,在把当前时间写入到绘图函数中,每一秒钟调用一次绘图函数,就可以实现时钟动态化
源码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态时钟</title>
<style>
#clock {
border: 1px solid #ccc;
}
div {
text-align: center;
}
</style>
</head>
<body>
<div>
<canvas id="clock" width="200px" height="200px"></canvas>
</div>
<script>
var clo = document.getElementById('clock');
var ctx = clo.getContext('2d');
var width = ctx.canvas.width;
var height = ctx.canvas.height;
var r = width / 2; //半径
function drawBackground() {
ctx.save(); //为了保存清除之前时钟的环境
ctx.translate(r, r); //切换中心点,此时(0,0)就在最中心了,不再是在左上角
ctx.beginPath();
ctx.lineWidth = 8;//线条的宽度
ctx.arc(0, 0, r - 4, 0, 2 * Math.PI, false)//绘制最外圆
ctx.stroke();
//画小时数
var hourNumber = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
ctx.font = '18px Arial'; //设置文本大小
ctx.textAlign = 'center'; //文本居中
ctx.textBaseline = 'middle';
hourNumber.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 - 10);
var y = Math.sin(rad) * (r - 10);
ctx.beginPath();
if (i % 5 === 0) { //被5整除也就是小时数
ctx.fillStyle = "#000"; //要加上,否则由于canvas是基于状态的,所以会把 这里的颜色也改成#ccc
ctx.arc(x, y, 2.5, 0, 2 * Math.PI, true)
} else {
ctx.fillStyle = "#ccc"
ctx.arc(x, y, 1.5, 0, 2 * Math.PI, true)
}
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 = 5;
ctx.moveTo(0, 10); //移动原点到原点的下面一点,作为画时针的起始位置
ctx.lineTo(0, -r / 2); //原点的位置在中心所以往上画要是负数
ctx.lineCap = 'round'; //设置线条的结尾形状
ctx.stroke();
ctx.restore(); //返回画小时之前的画布的保存过的路径和属性状态
}
function drawMinute(minute) {//画分针函数
//为了区分开画布环境
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 60 * minute; //每一个小时要旋转的弧度
ctx.rotate(rad); //画布的旋转
ctx.lineWidth = 3;
ctx.moveTo(0, 10); //移动原点到原点的下面一点,作为画时针的起始位置
ctx.lineTo(0, -r + 20); //原点的位置在中心所以往上画要是负数,值越大画的越短
ctx.lineCap = 'round'; //设置线条的结尾形状
ctx.stroke();
ctx.restore();
}
function drawSecond(second) {//画秒针函数
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 60 * second; //每一个小时要旋转的弧度
ctx.rotate(rad); //画布的旋转
ctx.lineWidth = 2;
ctx.strokeStyle = "red"
ctx.moveTo(0, 10); //移动原点到原点的下面一点,作为画时针的起始位置
ctx.lineTo(0, -r + 20); //原点的位置在中心所以往上画要是负数,值越大画的越短
ctx.lineCap = 'round'; //设置线条的结尾形状
ctx.stroke();
ctx.restore();
}
function drawDot() {//画中心点
ctx.beginPath();
ctx.fillStyle = "#fff"
ctx.arc(0, 0, 3, 0, 2 * Math.PI, false)
ctx.fill()
}
function draw() {//绘图函数
ctx.clearRect(0, 0, width, height); //每秒清除一次canvas再画出时分秒
var date = new Date();
var hour = date.getHours();
var minute = date.getMinutes();
var second = date.getSeconds();
drawBackground()
drawHour(hour, minute);
drawMinute(minute);
drawSecond(second);
drawDot()
ctx.restore(); //画完之后
}
draw(); //避免第一秒无效果
setInterval(draw, 1000);//定时器函数每秒调用一次
</script>
</body>
</html>
实现结果:
时钟特效
网友评论