目录
- 1.Canvas简介
- 2.基本使用
- 2.1 元素
- 2.2 渲染上下文
- 3. 形状绘制
- 3.1 坐标空间
- 3.2 绘制矩形
- 4. 绘制路径(path)
- 5.绘制动画
- 5.1 控制动画
- 5.2 Demo
1.Canvas简介
<canvas>
是HTML5新增的,可以使用JS绘制图像的HTML元素。由HTML配合height和width属性,JS进行图像绘制
2.基本使用
<canvas id="tutorial" width="300" height="300"></canvas>
2.1 元素
<canvas>
只有两个可选的属性 width(默认为300px)和heigth (默认150px),而没有 src、alt 属性。
- 注意: ① 不要用css属性来设置
<canvas>
的宽高,避免其与初始比例不一致而产生的扭曲。 ②
由于<canvas>
是HTML5新增标签,部分浏览器不支持显示该元素,当浏览器不支持<canvas>
渲染时,需要显示替代内容;支持时则会忽略其中的替代内容。
<!--文本替换-->
<canvas>
你的浏览器不支持 canvas,请升级你的浏览器。
</canvas>
<!--<img>替换-->
<canvas>
<img src="./美女.jpg" alt="">
</canvas>
2.2 渲染上下文
var canvas = document.getElementById('tutorial');
//获得 2d 上下文对象
var ctx = canvas.getContext('2d');
当不支持时,填充替代内容
var canvas = document.getElementById('tutorial');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
// drawing code here
} else {
// canvas-unsupported code here
}
3. 形状绘制
3.1 坐标空间
如下图所示,canvas 元素默认被网格所覆盖。通常来说网格中的一个单元相当于 canvas 元素中的一像素。栅格的起点为左上角,坐标为 (0,0) 。所有元素的位置都相对于原点来定位。
3.2 绘制矩形
<canvas>
只支持一种原生的图形绘制:矩形。canvas
提供了三种方法绘制矩形(默认颜色为黑色):
-
fillRect(x, y, width, height)
:绘制一个填充的矩形。 -
strokeRect(x, y, width, height)
:绘制一个矩形的边框。 -
clearRect(x, y, widh, height)
:清除指定的矩形区域,然后这块区域会变的完全透明。
4. 绘制路径(path)
步骤:1. 创建路径起始点
2.调用绘制方法去绘制出路径
3.把路径封闭
4.一旦路径生成,通过描边或填充路径区域来渲染图形。
beginPath()
#新建一条路径,路径一旦创建成功,图形绘制命令被指向到路径上生成路径
moveTo(x, y)
#把画笔移动到指定的坐标(x, y)。相当于设置路径的起始点坐标。
closePath()
#闭合路径之后,图形绘制命令又重新指向到上下文中
stroke()
#通过线条来绘制图形轮廓
fill()
#通过填充路径的内容区域生成实心的图形
#填充三角形
function draw(){
var canvas = document.getElementById('tutorial');
if (!canvas.getContext) return;
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(200, 50);
ctx.lineTo(200, 200);
ctx.fill(); //填充闭合区域。如果path没有闭合,则fill()会自动闭合路径。
}
draw();
5.绘制动画
动画的基本步骤
- 清空 。canvas 再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是
clearRect()
方法。- 保存 canvas 状态 。如果在绘制的过程中会更改 canvas 的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,需要保存canvas的状态。
- 绘制动画图形这一步才是真正的绘制动画帧。
- 恢复 canvas 状态。如果你前面保存了 canvas 状态,则应该在绘制完成一帧之后恢复 canvas 状态。
5.1 控制动画
为了执行动画,我们需要一些可以定时执行重绘的方法。一般用到下面三个方法(这三个方法都属于浏览器的window对象的方法):
-
setInterval(code,millisec[,"lang"])
方法可按照指定的周期(以毫秒计)来调用函数或计算表达式,实现定时周期执行。clearInterval()
取消setInterval()设置的定时器
<script>
function fun() {
document.write("定时器"+"<br>")
}
//间隔200ms周期性调用函数fun
setInterval("fun()",200);
</script>
-
setTimeout(code, millisec)
方法用于在指定的毫秒数后调用函数或计算表达式,实现倒计时。(setTimeout()
只执行 code 一次。如果要多次调用,请使用setInterval()
或者让 code 自身再次调用setTimeout()
)clearTimeout()
取消setTimeout()设置的定时器。
<script>
function fun() {
alert("定时器")
}
//2000ms,也就是2s后执行fun1函数
setTimeout("fun()",2000);
</script>
requestAnimationFrame()
<script>
let S = 0;
function fun() {
document.write("定时器"+"<br>");
// 发起下一次fun执行请求
requestAnimationFrame(fun);
S++;
}
// 开启函数fun第一次执行
fun();
</script>
5.2 Demo
**示例1:**实现一个无穷循环的计时
<html>
<head>
<script type="text/javascript">
var c=0
var t
function timedCount()
{
document.getElementById('txt').value=c
c=c+1
t=setTimeout("timedCount()",1000)
}
function stopCount()
{
clearTimeout(t)
}
</script>
</head>
<body>
<form>
<input type="button" value="开始计时!" onClick="timedCount()">
<input type="text" id="txt">
<input type="button" value="停止计时!" onClick="stopCount()">
</form>
<p>
请点击上面的“开始计时”按钮。输入框会从 0 开始一直进行计时。点击“停止计时”可停止计时。
</p>
</body>
</html>
**示例2:**一个简单的数字时钟
<html>
<head>
<script type="text/javascript">
function startTime()
{
var today=new Date()
var h=today.getHours()
var m=today.getMinutes()
var s=today.getSeconds()
// add a zero in front of numbers<10
m=checkTime(m)
s=checkTime(s)
document.getElementById('txt').innerHTML=h+":"+m+":"+s
t=setTimeout('startTime()',500)
}
function checkTime(i)
{
if (i<10)
{i="0" + i}
return i
}
</script>
</head>
<body onload="startTime()">
<div id="txt"></div>
</body>
</html>
**示例3:**一个简单的时钟表盘
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<style>
body {
padding: 0;
margin: 0;
background-color: rgba(0, 0, 0, 0.1)
}
canvas {
display: block;
margin: 200px auto;
}
</style>
</head>
<body>
<canvas id="solar" width="300" height="300"></canvas>
<script>
init();
function init(){
let canvas = document.querySelector("#solar");
let ctx = canvas.getContext("2d");
draw(ctx);
}
function draw(ctx){
requestAnimationFrame(function step(){
drawDial(ctx); //绘制表盘
drawAllHands(ctx); //绘制时分秒针
requestAnimationFrame(step);
});
}
/*绘制时分秒针*/
function drawAllHands(ctx){
let time = new Date();
let s = time.getSeconds();
let m = time.getMinutes();
let h = time.getHours();
let pi = Math.PI;
let secondAngle = pi / 180 * 6 * s; //计算出来s针的弧度
let minuteAngle = pi / 180 * 6 * m + secondAngle / 60; //计算出来分针的弧度
let hourAngle = pi / 180 * 30 * h + minuteAngle / 12; //计算出来时针的弧度
drawHand(hourAngle, 60, 6, "red", ctx); //绘制时针
drawHand(minuteAngle, 106, 4, "green", ctx); //绘制分针
drawHand(secondAngle, 129, 2, "blue", ctx); //绘制秒针
}
/*绘制时针、或分针、或秒针
* 参数1:要绘制的针的角度
* 参数2:要绘制的针的长度
* 参数3:要绘制的针的宽度
* 参数4:要绘制的针的颜色
* 参数4:ctx
* */
function drawHand(angle, len, width, color, ctx){
ctx.save();
ctx.translate(150, 150); //把坐标轴的远点平移到原来的中心
ctx.rotate(-Math.PI / 2 + angle); //旋转坐标轴。 x轴就是针的角度
ctx.beginPath();
ctx.moveTo(-4, 0);
ctx.lineTo(len, 0); // 沿着x轴绘制针
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.lineCap = "round";
ctx.stroke();
ctx.closePath();
ctx.restore();
}
/*绘制表盘*/
function drawDial(ctx){
let pi = Math.PI;
ctx.clearRect(0, 0, 300, 300); //清除所有内容
ctx.save();
ctx.translate(150, 150); //一定坐标原点到原来的中心
ctx.beginPath();
ctx.arc(0, 0, 148, 0, 2 * pi); //绘制圆周
ctx.stroke();
ctx.closePath();
for (let i = 0; i < 60; i++){//绘制刻度。
ctx.save();
ctx.rotate(-pi / 2 + i * pi / 30); //旋转坐标轴。坐标轴x的正方形从 向上开始算起
ctx.beginPath();
ctx.moveTo(110, 0);
ctx.lineTo(140, 0);
ctx.lineWidth = i % 5 ? 2 : 4;
ctx.strokeStyle = i % 5 ? "blue" : "red";
ctx.stroke();
ctx.closePath();
ctx.restore();
}
ctx.restore();
}
</script>
</body>
</html>