【H5】 canvas实现刮刮乐效果
效果图如下:
全部实现代码如下:复制粘贴即可运行!
代码内有步骤详解哦!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<img src="1.jpg" width="400" id= 'img' alt="">
<input type="text" name="" id="txt">
<!-- <canvas></canvas> -->
<script>
const oImg = document.getElementById('img');
const txt = document.getElementById( 'txt' );
//oImg.readyState 图片加载状态
if( oImg.readyState ==="complete" ){
draw(); //true表示已经加载完成 执行draw()方法
}else{
//图片加载完成执行draw方法
oImg.onload = draw;
}
function draw(){ //等图片加载完成后再添加canvas画布在上面
let can = document.createElement('canvas'); //创建一个canvas画布
can.width = oImg.width; //等于图片的宽高
can.height = oImg.height;
can.style.position = "absolute"; //canvas画布设置浮动会漂浮在图片上
can.style.left = oImg.offsetLeft + "px"; //保存与画布位置一致
can.style.top = oImg.offsetTop + "px";
//找到图片的父级:parentNode 在oImg子元素前面添加canvas标签:insertBefore
oImg.parentNode.insertBefore( can,oImg ) //在img前面去插入canvas标签
let ctx = can.getContext('2d');
ctx.fillStyle = "#bbb"; //刮刮乐的颜色
ctx.fillRect( 0,0,oImg.width,oImg.height) //填充宽度
//合成:处理合成图片的透明样式;
//拖拽的时候,canvas图层显示透明;destination-out:新图形与原图形重叠部分透明
ctx.globalCompositeOperation = "destination-out";
ctx.strokeStyle = "#eee"; //触笔的颜色 随便 因为它终究变成透明
ctx.lineWidth = 30; //拖动时开始画线的线宽
ctx.lineCap = "round" //这两步是把画笔变成圆形
//按下,移动,抬起事件
can.onmousedown = function(e){
e = e || window.event; //兼容低版本IE浏览器
//e.pageX距离文档右边缘; offsetLeft:canvas画布距离文档的右边距离
let x = e.pageX - can.offsetLeft; //得到的x是在canvas上的坐标值
let y = e.pageY - can.offsetTop;
ctx.beginPath();
// ctx.moveTo( x,y )//从哪里开始来画
ctx.arc( x,y,15,0,6.3,false ); //点第一下是画一个圆
ctx.fill();
//按下后拖拽
can.onmousemove = function( e ){ //拖动时一直执行下面
e = e || window.event; //兼容低版本IE浏览器
ctx.beginPath(); //拖动时开始画线
ctx.moveTo(x,y); //起始点
ctx.lineTo(e.pageX - can.offsetLeft,e.pageY - can.offsetTop); //移动的过程
//每次移动的时候,样式所在的坐标;
x = e.pageX - can.offsetLeft; //第二次渲染刮图片效果的起始点应该在上一次的终止点
y = e.pageY - can.offsetTop;
ctx.stroke(); //弹出图形并恢复画布
}
document.onmouseup = function(){
//抬起后将事件注销
can.onmousemove = null;
this.onmouseup = null;
check(); //完成后通过像素计算刮过的的百分比
}
}
function check(){
//获取画布的像素列表
let data = ctx.getImageData( 0,0,can.width,can.height).data;
let n = 0; //计算透明像素的个数
for( let i = 0;i<data.length;i+=4 ){ //感觉这一步比较消耗性能
//RGBA
if( data[i]== 0 && data[i+1] ==0 && data[i+2] ==0&&data[i+3] ==0 ){
n++
}
}
let f = n*100/(can.width*can.height); //算出所刮的面积的占比;
txt.value = `刮开面积:${f.toFixed(2)}%`;
//刮开面积的比例
if( f > 30 ){ //如果所刮的面积大于30% 则将canvas画布整体清除fillRect
ctx.beginPath();
ctx.fillRect( 0,0,can.width , can.height )
txt.value = "刮开面积大于30%,全部显示"
}
}
}
</script>
</body>
</html>