canvas是HTML5推出的画布技术 有2D和3D 目前3D兼容性很差但相信随着VR的兴起 3D也会逐渐发力 目前只讲述关于2D 相关的API 以及 业务逻辑 常用场景 游戏等等
API部分
<style> canvas{ border:solid 2px red } </style> <canvas id="cvs" width="800" height="800"></canvas> </head> <body> <script> //获取canvas以及其上下文对象 var cvs = document.querySelector('#cvs') var ctx = cvs.getContext('2d') //开始绘制 ctx.beginPath() ctx.moveTo(200,200) ctx.lineTo(200,400) ctx.lineTo(100,400) ctx.lineWidth = 15 ctx.closePath() ctx.strokeStyle = 'red' ctx.fillStyle = 'blue' ctx.stroke() ctx.fill() //上面自己绘制了一个三角形 </script>
上面自己绘制了一个三角形 在canvas中的路径 良好的习惯每次 绘制结束 都要闭合 每次绘制开始都要重新开启路径 第一步定点 然后 绘制 路径 填充非常简单
下面放canvas绘制矩形 以及 圆弧 以及 绘制图片的API demo
ctx.fillStyle = 'red' ctx.fillRect(200,200,200,200) ctx.strokeStyle = 'blue' ctx.strokeRect(400,400,400,400)
上面绘制了两个canvas预定义的 实心矩形和 空心矩形
在绘制圆形之前首先要明白canvas 圆形绘制是根据弧度制的 也就是角度跟弧度弧度是成比例的 是什么一个关系 圆的周长 = 2πr 如果将360° 跟 周长划一个关系的话 那么必须提取一个唯一的变量那就是r 在不同大小的圆下r也是不同的
将r提取出来 周长 / 2π = r 360° / 2π = 57.29° 那么我们就可以说 无论在什么情况下 1r 的弧度就等于 = 57.29° 的角度 那么有了这个对等的关系就非常简单了 我们可以假设360°就是 2π 的弧度 实际上canvas也是这么实现的 这两个是常量 在角度 和 r 有一个对等的比例关系下 可以将其忽略 在这个前提下 那么如果我们要计算30°的弧度是多少就非常简单了 就是360 / 30 * 2π 这样我们就计算出了30 的弧度 下面讲述一下API用法
//下面是圆弧的绘制 ctx.arc(200,200,100,0,2 * Math.PI,false) ctx.fillStyle = 'red' ctx.lineWidth = 10 ctx.strokeStyle = 'blue' ctx.fill() ctx.stroke()
在canvas中所有呈现出来的元素立即被像素化 因此无法像DOM一样操作canvas中的元素 只能通过画布帧动画的概念来实现各种动画游戏效果
下面一个圆球动画的简例:
//获取canvas以及其上下文对象 var cvs = document.querySelector('#cvs') var ctx = cvs.getContext('2d') let x = 100, x1 = 100, x2 = 100 setInterval(function(){ x += 20 x1 += 40 x2 += 60 ctx.clearRect(0,0,800,800) ctx.beginPath() ctx.fillStyle = 'blue' ctx.arc(x,100,50,0,2*Math.PI,false) ctx.fill() ctx.beginPath() ctx.fillStyle = 'blue' ctx.arc(x1,200,50,0,2*Math.PI,false) ctx.fill() ctx.beginPath() ctx.fillStyle = 'blue' ctx.arc(x2,300,50,0,2*Math.PI,false) ctx.fill() },100)
在多个元素运动和canvas游戏中一般采用的是 面向对象的方式 接下来用渐进增强的方式慢慢解析
<script>
//获取canvas以及其上下文对象
var cvs = document.querySelector('#cvs')
var ctx = cvs.getContext('2d')
//运动元素构造函数
function Ball (x,y,r,speed){
this.x = x
this.y = y
this.r = r
this.speed = speed
actorsAll.push(this)
}
const actorsAll = []
//更新函数
Ball.prototype.update = function(){
this.x += this.speed
}
//渲染函数
Ball.prototype.render = function(){
ctx.beginPath()
ctx.arc(this.x,this.y,this.r,0,2 * Math.PI,false)
ctx.fillStyle = 'yellow'
ctx.fill()
}
new Ball(100,100,30,1)
new Ball(100,200,30,2)
new Ball(100,300,30,3)
new Ball(100,400,30,4)
setInterval(function(){
ctx.clearRect(0,0,800,800)
actorsAll.forEach(value => {
value.update()
value.render()
})
})
</script>
使用面向会使代码更加的规整 已读 canvas中运用面向对象是一种非常好的思路
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas{
border:solid 2px red
}
</style>
<canvas id="cvs" ></canvas>
</head>
<body>
<script>
//获取canvas以及其上下文对象
var cvs = document.querySelector('#cvs')
var ctx = cvs.getContext('2d')
cvs.width = document.documentElement.clientWidth
cvs.height = document.documentElement.clientHeight
//运动元素构造函数
function Ball(x,y){
this.x = x
this.y = y
this.color = `rgba(${parseInt(Math.random()*256)},${parseInt(Math.random()*256)},${parseInt(Math.random()*256)},0.8)`
this.r = 30
this.dx = parseInt(Math.random() * 17) - 8
this.dy = parseInt(Math.random() * 17) - 8
actorAll.push(this)
}
const actorAll = []
//渲染函数
Ball.prototype.render = function(){
ctx.beginPath()
ctx.fillStyle = this.color
ctx.arc(this.x,this.y,this.r,0,2 * Math.PI,false)
ctx.fill()
}
//更新函数
Ball.prototype.update = function(){
console.log(this.x)
console.log(this.y)
this.x += this.dx
this.y += this.dy
this.r --
if(this.r <= 0){
this.godie()
}
}
//删除函数
Ball.prototype.godie = function(){
actorAll.forEach((value,i) => {
if(this === value){
actorAll.splice(i,1)
}
})
}
cvs.addEventListener('mousemove',function(event){
new Ball(event.clientX,event.clientY)
})
setInterval(function(){
ctx.clearRect(0,0,cvs.width,cvs.height)
actorAll.forEach(value => {
value.update()
value.render()
})
},30)
</script>
</body>
</html>