之前就知道有canvas画布,但是一直都没有用的机会,so...一直也没学习过,今天就开始菜鸟的canvas学习~
<canvas></canvas>是个双标签 ,标签中间可以放替换内容--如果浏览器不兼容画布的话,就会显示中间的替代内容(i9之前的版本的不支持的!)
<canvas>有width height id 属性 (默认不设置宽高的时候显示300px宽和150px高)
canvas画布其实就是纯js画的,canvas元素有很多方法
getContext() 的方法,用来获得渲染上下文和它的绘画功能。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas创建</title>
<style>
canvas{
border: 1px solid rgb(19, 18, 18);
}
</style>
</head>
<body>
<canvas id="demo1" width="400px" height="400px"></canvas>
<script type="text/javascript">
//获取元素dom
let demo1=document.querySelector('#demo1')
//指定画布是2d形式
let ctx= demo1.getContext('2d')
</script>
</body>
</html>
简单的画布就出现了~
接下来用canvas先做一个表格背景,对canvas知识运用~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas的使用</title>
<style>
html,
body,
.container{
height: 100%;
width: 100%;
}
.container{
display: flex;
justify-content: center;
align-items: center;
}
canvas{
border: 1px solid rgb(19, 18, 18);
}
</style>
</head>
<body>
<div class="container">
<canvas id="demo2" width="400px" height="400px"></canvas>
</div>
<script type="text/javascript">
//获取元素dom
let demo2=document.querySelector('#demo2')
//指定画布是2d形式
let ctx= demo2.getContext('2d')
//创建网格线
//ctx指定画布,stepX是线与线x间距 stepY是线与线y间距 color是线的颜色 lineWidth是线的宽度
function drawGrid(ctx,stepX, stepY, color, lineWidth){
// // 设置绘制颜色
ctx.strokeStyle = color;
// 创建垂直格网线路径
for(let i = stepX; i < demo2.width; i += stepX){
// 设置绘制线段的宽度
ctx.lineWidth = lineWidth;
//开启路径
ctx.beginPath()
//笔触的位置-moveTo经常是画一些不连续的线
ctx.moveTo(i, 0);
//绘制一条从当前位置到指定x以及y位置的直线。
ctx.lineTo(i,demo2.height);
ctx.stroke()
}
// 创建水平格网线路径
for(let j = stepY; j < demo2.height; j += stepY){
// 设置绘制线段的宽度
ctx.lineWidth = lineWidth;
//开启路径
ctx.beginPath()
ctx.moveTo(0, j);
ctx.lineTo(demo2.width, j);
ctx.stroke()
}
}
//调用封装好的表格工具
drawGrid(ctx,20, 20, '#ccc', 0.5);
</script>
</body>
</html>
效果图
当然我封装的是一个表格的工具函数,在写组件的时候,可以传入需要网格的画布 ,水平和垂直的间隔 ,颜色,线条的宽 度,这些可以根据需要自己定制o~
这里有个小注意点,width和height是写在canvas标签上的,不要写到style上,不然网格会非常的模糊!
小示例 用画布画一个钟表
在开始画之前我们必须了解一下canvas的坐标空间,哪里是原点,x轴,y轴
小红点是坐标(0,0)也就是原点,水平向右是x轴,垂直向下是y轴
效果图
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas画钟</title>
<style>
html,
body,
.container{
height: 100%;
width: 100%;
}
.container{
display: flex;
justify-content: center;
align-items: center;
}
canvas{
border: 1px solid rgb(19, 18, 18);
}
</style>
<script></script>
</head>
<body>
<div class="container">
<canvas id="demo3" width="600px" height="600px"></canvas>
</div>
<script type="text/javascript">
//获取元素dom
let demo2=document.querySelector('#demo3')
//指定画布是2d形式
let ctx= demo3.getContext('2d')
ctx.save();
// ---------------------------------------------------------------------------------网格背景
//创建网格线
function drawGrid(ctx,stepX, stepY, color, lineWidth){
ctx.save()
// // 设置绘制颜色
ctx.strokeStyle = color;
// 创建垂直格网线路径
for(let i = stepX; i < demo2.width; i += stepX){
// 设置绘制线段的宽度
ctx.lineWidth = lineWidth;
//开启路径
ctx.beginPath()
//笔触的位置-moveTo经常是画一些不连续的线
ctx.moveTo(i, 0);
//绘制一条从当前位置到指定x以及y位置的直线。
ctx.lineTo(i,demo2.height);
ctx.stroke()
}
// 创建水平格网线路径
for(let j = stepY; j < demo2.height; j += stepY){
// 设置绘制线段的宽度
ctx.lineWidth = lineWidth;
//开启路径
ctx.beginPath()
ctx.moveTo(0, j);
ctx.lineTo(demo2.width, j);
ctx.stroke()
}
ctx.restore()
}
// ----------------------------------------------------表盘大圆
function bigclock() {
ctx.save()
ctx.beginPath()
// 画圆线使用arc(中心点X,中心点Y,半径,起始角度,结束角度)
ctx.arc(0, 0, 200, 0, 2 * Math.PI)
ctx.stroke() //画轮廓
ctx.closePath()
ctx.restore()
}
// -------------------------------------------------------画表心
function clockcenter(){
ctx.save()
ctx.beginPath()
// 画圆线使用arc(中心点X,中心点Y,半径,起始角度,结束角度) Math.PI=3.14=180度
ctx.arc(0, 0, 5, 0, 2 * Math.PI)
ctx.fill()
ctx.closePath()
ctx.restore()
}
// -------------------------------------------------画时针
function drawHour(hour,minutes){
ctx.save()
ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 * (minutes / 60) )
ctx.beginPath()
ctx.moveTo(-1,0);
ctx.lineTo(-10,-80);
ctx.lineTo(0,-85);
ctx.lineTo(10,-80);
ctx.lineTo(1,0);
// 设置线宽
ctx.lineWidth = 1
ctx.fillStyle="pink"
ctx.fill() //画轮廓
ctx.closePath()
ctx.restore()
}
// --------------------------------------------------画分针
function drawMinu(minutes,seconds){
ctx.save()
ctx.rotate(2 * Math.PI / 60 * minutes + 2 * Math.PI / 60 * (seconds / 60) )
ctx.beginPath()
ctx.moveTo(-1,0);
ctx.lineTo(-6,-140);
ctx.lineTo(0,-145);
ctx.lineTo(8,-140);
ctx.lineTo(1,0);
// 设置线宽
ctx.lineWidth = 1
ctx.fillStyle="red"
ctx.fill() //画轮廓
ctx.closePath()
ctx.restore()
}
//---------------------------------------------------画秒针
function drawSecond(seconds) {
ctx.save()
ctx.rotate(2 * Math.PI / 60 * seconds)
ctx.beginPath()
ctx.moveTo(-1,0);
ctx.lineTo(-4,-170);
ctx.lineTo(0,-175);
ctx.lineTo(5,-170);
ctx.lineTo(1,0);
// 设置线宽
ctx.lineWidth = 1
ctx.fillStyle="blue"
ctx.fill() //画轮廓
ctx.closePath()
ctx.restore()
}
// -------------------------------------------------画小时的刻度
function hourkedu(){
ctx.save()
ctx.lineWidth = 5
for (let i = 0; i < 60; i++) {
ctx.rotate(2 * Math.PI / 12)
ctx.beginPath()
ctx.moveTo(193, 0)
ctx.lineTo(200, 0)
ctx.stroke()
ctx.closePath()
}
ctx.restore()
}
// -------------------------------------------------画分针的刻度
function minukedu() {
ctx.save()
ctx.lineWidth = 2
for (let i = 0; i < 60; i++) {
ctx.rotate(2 * Math.PI / 60)
ctx.beginPath()
ctx.moveTo(195, 0)
ctx.lineTo(200, 0)
ctx.stroke()
ctx.closePath()
}
ctx.restore()
}
// 让表动起来
setInterval(()=>{
// -------------------------------------------------------获取当前时间
let time = new Date()
let hour = time.getHours() % 12//对当前时间取余 比如现在时间16点 对应的就是4点
let minutes = time.getMinutes()
let seconds = time.getSeconds()
// 清除画布
ctx.save()
ctx.clearRect(0, 0, 600, 600)
drawGrid(ctx,20, 20, '#ccc', 0.5);
//找到画布的中心点
ctx.translate(300,300)
// 大表盘
bigclock()
// 画表心
clockcenter()
hourkedu()
minukedu()
drawHour(hour,minutes)
drawMinu(minutes,seconds)
drawSecond(seconds)
ctx.restore()
},1000)
</script>
</body>
</html>
注意:比较难理解的地方是ctx.save()和ctx.restore()
save()是保存当前状态,比如我们获取了画布dom,设置了2d模式,需要保存一下状态
resrore()则是回退到上一个状态
canvas画画就是用坐标画出一个图,然后很多图一层一层压在一起,,每次画一个图的时候都需要先保存当前状态,然后画完之后回退到画之前
在让表动起来的时候用的是setInterval,需要先保存当前状态,清除画布,画完之后,需要回退到上一个状态!!!!!这个非常重要