最近在学习html5,为了更好地学习和帮助其他人我决定把我写过的案例写下来~~
先说一下刮刮乐这个程序实现的注意点
- 材料:一张图片和canvas画布
- 在html页面只要放图片元素,canvas由js生成。 这是为了保证canvas生成在img上面而且保证刚打开页面的时候不会看见图片
- 生成的canvas涂层要保证大小和位置和图片的相同
CSS
*{padding:0;margin:0;}
body{
background-color: skyblue;
text-align: center;
}
#img{
margin-top: 100px;
user-select: none;
}
canvas{
user-select: none;
}
html
<img src = "img/1.jpg" alt="" id = "img">
<input type = "text" id = "txt">
js
let img = document.querySelector("#img")
let txt = document.querySelector("#txt")
// 保证图片和canvas生成顺序不会出错
if( img.readyState === "complete" ){
draw()
} else{
img.onload = draw
}
function draw() {
// 生成canvas涂层
let can = document.createElement("canvas")
// 保证涂层宽高与画布宽高一致
can.width = img.width
can.height = img.height
// 保证涂层位置与画布位置一致
can.style.position = "absolute"
can.style.left = img.offsetLeft + "px"
can.style.top = img.offsetTop + "px"
// 插入生成的canvas
img.parentNode.insertBefore( can, img )
// canvas样式
let ctx = can.getContext("2d")
ctx.fillStyle = "#bbb" // 涂层的颜色
ctx.fillRect( 0, 0, img.width, img.height ) // 填充canvas涂层
// 以上的样式可以先写在一个字符串中,然后只要用ctx.cssText就好了 但是这里为了更直观我就一步步写了
// 合成 处理合成图片的透明样式
// 拖拽的时候使canvas涂层透明
ctx.globalCompositeOperation = "destination-out"
// 画笔样式
ctx.lineWidth = 30
ctx.lineCap = "round"
// 拖拽事件
can.onmousedown = function (e) {
let x = e.pageX - can.offsetLeft
let y = e.pageY - can.offsetTop
// 在涂层点一下的时候要有一个圆点
ctx.beginPath()
ctx.arc( x, y, 15, 0, 2*Math.PI, false )
ctx.fill()
can.onmousemove = function (e) {
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() // 这里是描线,用fill会没有效果
}
document.onmouseup = function (e) {
// 这里对document绑定事件是因为抬起鼠标的时候可能是在图片之外抬起
can.onmousemove = null
this.onmouseup = null
check() // 这里增加一个功能,已涂面积超过30%的时候显示全部图片
}
}
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 ){
if( data[i] === 0 && data[i+1] === 0 && data[i+2] === 0 && data[i+3] === 0 ) {
// 这里的data表示一个像素点的rgba 由于被刮过的像素点变透明,因此此时rgba都为0
n++
}
}
// 算出当前已刮面积占比
let f = n * 100 / ( can.width * can.height )
txt.value = `刮开面积:${f.toFixed(2)}%`
// 如果超过30%则展示完整画面
if( f > 30 ){
ctx.beginPath()
ctx.fillRect( 0, 0, can.width, can.height )
txt.value = `给你看完整的图片吧~~`
}
}
}
好了,要是有什么问题或者建议的话欢迎联系我~
Wish you godspeed!