canvas特效之刮刮乐和粒子特效
刮刮乐:
思路:在底部的图片加载时,我们先增加一个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>
html,body{
width: 100vw;
height: 100vh;
margin: 0;
overflow: hidden;
}
img{
width: 100%;
height: 100%;
display: block;
}
</style>
</head>
<body>
<img src="img/01.jpg">
<script>
const img=document.querySelector('img');
img.onload=function (){
const oC=document.createElement('canvas');
oC.style.position = 'absolute'
oC.style.left=img.offsetLeft+'px';
oC.style.top=img.offsetTop+'px';
oC.width=img.width;
oC.height=img.height;
img.parentNode.insertBefore(oC,img);
const cxt=oC.getContext('2d');
cxt.fillStyle = '#bbb'
cxt.fillRect(0,0,oC.width,oC.height);
cxt.globalCompositeOperation="destination-out";
oC.onmousedown=function(e){
let x=e.pageX-this.offsetLeft;
let y=e.pageY-this.offsetTop;
cxt.beginPath();
cxt.fillStyle="red";
cxt.arc(x,y,50,0,360*Math.PI/180);
cxt.fill()
cxt.lineWidth=100
this.onmousemove=function(e){
cxt.beginPath()
cxt.moveTo(x,y)
cxt.lineTo(e.pageX-oC.offsetLeft,e.pageY-oC.offsetTop)
cxt.stroke()
cxt.lineCap = 'round'
x = e.pageX - oC.offsetLeft
y = e.pageY - oC.offsetTop
}
this.onmouseup = function (){
this.onmousemove = null
this.onmouseup = null
checked()
}
}
function checked(){
const data=cxt.getImageData(0,0,oC.width,oC.height).data;
let n=0;
for(let i=0;i<data.length;i++){
if ( data[i] === 0 && data[i+1] === 0 && data[i+2] === 0 && data[i+3] === 0){
n++;
}
}
let f=n*100/(oC.width*oC.height);
// document.title = '被刮开的面积'+f.toFixed(2) + '%';
if ( f>200 ){
cxt.beginPath();
cxt.fillRect(0,0,oC.width,oC.height);
document.title = '全部刮开了';
}
}
}
</script>
</body>
</html>
粒子:
思路:先采用他面向对象的方法,创建粒子工厂,然后将实例化的粒子放入数组中,然后我们写draw函数,对粒子进行操作。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body{
margin: 0;
background: #000;
overflow: hidden;
}
canvas{
box-shadow: inset 0 0 100px #007aff;
}
</style>
</head>
<body>
<canvas></canvas>
<script>
const oC=document.querySelector('canvas')
const cxt=oC.getContext('2d')
let w=oC.width=window.innerWidth;
let h=oC.height=window.innerHeight;
let sumNumber=500;
let sum=[];
let colors=["red","blue","pink","purple","green","yellow"];
window.onresize=function(){
w = oC.width = window.innerWidth
h = oC.height = window.innerHeight
}
//粒子工厂
function Factory(){
this.x=Math.round(Math.random()*w);
this.y=Math.round(Math.random()*h);
this.radius=Math.round(Math.random()*10)
this.rgba = colors[Math.round(Math.random()*5)]
this.vx = Math.round(Math.random()*3) - 1.5
this.vy = Math.round(Math.random()*3) - 1.5
}
!function(){
for(let i=0;i<sumNumber;i++){
sum.push(new Factory());
}
}()
console.log(sum);
(function loop(){
draw();
requestAnimationFrame(loop);
})()
function draw(){
cxt.clearRect(0,0,w,h)//每次执行依次函数都要清理上一次的粒子
for(let i=0;i<sumNumber;i++){
let temp = sum[i];
for(let k=0;k<sumNumber;k++){
cxt.lineWidth=0.5
let temp2=sum[k];
if(temp.rgba === temp2.rgba && findLine(temp,temp2) <100){
//当两个粒子颜色一样并且他们的距离<100,我们就把他们连接起来
cxt.strokeStyle = temp.rgba
cxt.beginPath()
cxt.moveTo(temp.x,temp.y)
cxt.lineTo(temp2.x,temp2.y)
cxt.stroke()
}
}
cxt.fillStyle = temp.rgba
cxt.strokeStyle = temp.rgba
cxt.beginPath()
cxt.arc(temp.x,temp.y,temp.radius,0,2*Math.PI)
cxt.fill()
cxt.beginPath()
cxt.arc(temp.x,temp.y,(temp.radius+5),0,2*Math.PI)
cxt.stroke()
temp.x+=temp.vx
temp.y+=temp.vy
if ( temp.x > w ) temp.x = 0
if ( temp.x < 0 ) temp.x = w
if ( temp.y > h ) temp.y = 0
if ( temp.y < 0 ) temp.y = h
}
function findLine(temp,temp2){
return Math.sqrt(Math.pow((temp2.x-temp.x),2)+Math.pow((temp2.y-temp.y),2))
}
}
</script>
</body>
</html>