一步一步教大家用canvas做 图片滑动解锁
几天有需求做滑动解锁,想来点新鲜的,于是想挑战一下,cavas做图片滑动解锁;
原文链接:https://www.jb51.net/article/137129.htm
我们想实现这样的效果:
首先随便找一张图片渲染到canvas上,这里#canvas作为画布,#block作为裁剪出来的小滑块。
<canvas width="310" height="155" id="canvas" style="border:1px solid red;"></canvas> <canvas width="310" height="155" id="block" style="border:1px solid green;"></canvas>
script:
// 将两张图片渲染在cavas上 var canvas = document.getElementById('canvas'); var block = document.getElementById('block'); var canvas_ctx = canvas.getContext('2d'); var block_ctx = block.getContext('2d'); var img = document.createElement('img'); img.onload = function() { canvas_ctx.drawImage(img, 0, 0, 310, 155); block_ctx.drawImage(img, 0, 0, 310, 155); }; img.src = './touxiang.png';
再教大家裁剪小真方形:
script:
// 将两张图片渲染在cavas上 var canvas = document.getElementById('canvas'); var block = document.getElementById('block'); var canvas_ctx = canvas.getContext('2d'); var block_ctx = block.getContext('2d'); var img = document.createElement('img'); img.onload = function() { canvas_ctx.drawImage(img, 0, 0, 310, 155); block_ctx.drawImage(img, 0, 0, 310, 155); }; img.src = './touxiang.png'; // 先利用clip()方法裁剪出个方块儿,让大家认识裁剪 var x = 150, y = 40, w = 42, r = 10, PI = Math.PI;//x坐标、y坐标、正方形的宽、圆的半径、圆周率(3.14...) function draw(ctx) { ctx.beginPath();//拿笔 ctx.moveTo(x, y);//把笔尖点到画布上这个点 ctx.lineTo(x + w, y); ctx.lineTo(x + w, y + w); ctx.lineTo(x, y + w); ctx.clip();//剪刀裁剪 } draw(canvas_ctx); draw(block_ctx);
上面大家学会了画正方形,裁剪正方形,下面裁剪出我们想要的形状,把原来的draw方法改写一下:
// 将两张图片渲染在cavas上 var canvas = document.getElementById('canvas'); var block = document.getElementById('block'); var canvas_ctx = canvas.getContext('2d'); var block_ctx = block.getContext('2d'); var img = document.createElement('img'); img.onload = function() { canvas_ctx.drawImage(img, 0, 0, 310, 155); block_ctx.drawImage(img, 0, 0, 310, 155); }; img.src = './touxiang.png'; // 先利用clip()方法裁剪出个方块儿,让大家认识裁剪 var x = 150, y = 40, w = 42, r = 10, PI = Math.PI;//x坐标、y坐标、正方形的宽、圆的半径、圆周率(3.14...) function draw(ctx) { ctx.beginPath();//拿笔 ctx.moveTo(x,y);//把笔尖点到这个点 ctx.lineTo(x+w/2,y);//笔尖画到 正方形上边线中间 ctx.arc(x+w/2,y-r+2, r,0,2*PI); //在坐标点(x+w/2,y-r+2)画一个r为半径的圆,角度开始为0,结束角度为2π,顺时针画个圆 ctx.lineTo(x+w/2,y);//笔尖移动到 正方形上边线中间 ctx.lineTo(x+w,y);//笔尖画到 正方形的上边线的右侧 ctx.lineTo(x+w,y+w/2);//笔尖再画到正方形的右边线中间点 ctx.arc(x+w+r-2,y+w/2,r,0,2*PI) //在合适的位置画个圆 ctx.lineTo(x+w,y+w/2);//笔尖画到正方形的 右边线中间点 ctx.lineTo(x+w,y+w);//笔尖画到正方形右边线的底部 ctx.lineTo(x,y+w);//再画到正方形的下边线的左侧 ctx.lineTo(x,y);//再画到正方形的起始点 形成闭环 ctx.clip();//用剪刀裁剪 } draw(canvas_ctx); draw(block_ctx);
由于clip是裁剪路径内的部分,因此直接像上面画圆是不行的,我们开启一条新的路径,然后画圆将这个正方形“遮盖”出一个缺口,这里会用到 globalCompositeOperation 属性,'xor'顾名思义。代码接上边:
// 将两张图片渲染在cavas上 var canvas = document.getElementById('canvas'); var block = document.getElementById('block'); var canvas_ctx = canvas.getContext('2d'); var block_ctx = block.getContext('2d'); var img = document.createElement('img'); img.onload = function() { canvas_ctx.drawImage(img, 0, 0, 310, 155); block_ctx.drawImage(img, 0, 0, 310, 155); }; img.src = './touxiang.png'; // 先利用clip()方法裁剪出个方块儿,让大家认识裁剪 var x = 150, y = 40, w = 42, r = 10, PI = Math.PI;//x坐标、y坐标、正方形的宽、圆的半径、圆周率(3.14...) function draw(ctx) { ctx.beginPath();//拿笔 ctx.moveTo(x,y);//把笔尖点到这个点 ctx.lineTo(x+w/2,y);//笔尖画到 正方形上边线中间 ctx.arc(x+w/2,y-r+2, r,0,2*PI); //在坐标点(x+w/2,y-r+2)画一个r为半径的圆,角度开始为0,结束角度为2π,顺时针画个圆 ctx.lineTo(x+w/2,y);//笔尖移动到 正方形上边线中间 ctx.lineTo(x+w,y);//笔尖画到 正方形的上边线的右侧 ctx.lineTo(x+w,y+w/2);//笔尖再画到正方形的右边线中间点 ctx.arc(x+w+r-2,y+w/2,r,0,2*PI) //在合适的位置画个圆 ctx.lineTo(x+w,y+w/2);//笔尖画到正方形的 右边线中间点 ctx.lineTo(x+w,y+w);//笔尖画到正方形右边线的底部 ctx.lineTo(x,y+w);//再画到正方形的下边线的左侧 ctx.lineTo(x,y);//再画到正方形的起始点 形成闭环 ctx.clip();//用剪刀裁剪 ctx.beginPath();//重新开始画 ctx.arc(x,y+w/2, r,1.5*PI,0.5*PI) // 只需要画正方形内的半圆就行,方便背景图片的裁剪 ctx.globalCompositeOperation = "xor";//将原图遮盖出一个缺口 ctx.fill();//填充颜色 前面没加fillStyle就是白色 } draw(canvas_ctx); draw(block_ctx);
现在一个基本的拼图形状有了,我们调整#block的大小,并将裁剪出来的滑块放入#block中:
// 将两张图片渲染在cavas上 var canvas = document.getElementById('canvas'); var block = document.getElementById('block'); var canvas_ctx = canvas.getContext('2d'); var block_ctx = block.getContext('2d'); var img = document.createElement('img'); img.onload = function() { canvas_ctx.drawImage(img, 0, 0, 310, 155); block_ctx.drawImage(img, 0, 0, 310, 155); var blockWidth = w + r * 2;//滑块实际宽度 var _y = y - r * 2 + 2 // 滑块实际的y坐标 var ImageData = block_ctx.getImageData(x, _y, blockWidth, blockWidth);//拿到滑块的像素数据 block.width = blockWidth;//将滑块dom元素的宽度设置成滑块的掉 block_ctx.putImageData(ImageData, 0, _y) }; img.crossOrigin = 'Anonymous';//防止图片报跨域的错 img.src = 'http://kexiepingtaieposter.hoohui.cn//registFile/fa5df7c9-445d-4b58-97c4-ad8b86a92241/Z0134_20200224232124.png?time='+ new Date();//加事件戳 防止图片报跨域的错 // 先利用clip()方法裁剪出个方块儿,让大家认识裁剪 var x = 150, y = 40, w = 42, r = 10, PI = Math.PI;//x坐标、y坐标、正方形的宽、圆的半径、圆周率(3.14...) function draw(ctx) { ctx.beginPath();//拿笔 ctx.moveTo(x,y);//把笔尖点到这个点 ctx.lineTo(x+w/2,y);//笔尖画到 正方形上边线中间 ctx.arc(x+w/2,y-r+2, r,0,2*PI); //在坐标点(x+w/2,y-r+2)画一个r为半径的圆,角度开始为0,结束角度为2π,顺时针画个圆 ctx.lineTo(x+w/2,y);//笔尖移动到 正方形上边线中间 ctx.lineTo(x+w,y);//笔尖画到 正方形的上边线的右侧 ctx.lineTo(x+w,y+w/2);//笔尖再画到正方形的右边线中间点 ctx.arc(x+w+r-2,y+w/2,r,0,2*PI) //在合适的位置画个圆 ctx.lineTo(x+w,y+w/2);//笔尖画到正方形的 右边线中间点 ctx.lineTo(x+w,y+w);//笔尖画到正方形右边线的底部 ctx.lineTo(x,y+w);//再画到正方形的下边线的左侧 ctx.lineTo(x,y);//再画到正方形的起始点 形成闭环 ctx.clip();//用剪刀裁剪 ctx.beginPath();//重新开始画 ctx.arc(x,y+w/2, r,1.5*PI,0.5*PI) // 只需要画正方形内的半圆就行,方便背景图片的裁剪 ctx.globalCompositeOperation = "xor";//将原图遮盖出一个缺口 ctx.fill();//填充颜色 前面没加fillStyle就是白色 } draw(canvas_ctx); draw(block_ctx);
现在我们需要把左边画布展示原来的图片,并且抠掉中间滑块的部分,这里画路径的过程都是一样的,唯一不同只是clip()那里改成fill()即可实现效果,我们前面已经把画路径的过程封装成函数了,稍作改动即可:
// 将两张图片渲染在cavas上 var canvas = document.getElementById('canvas'); var block = document.getElementById('block'); var canvas_ctx = canvas.getContext('2d'); var block_ctx = block.getContext('2d'); var img = document.createElement('img'); img.onload = function() { canvas_ctx.drawImage(img, 0, 0, 310, 155); block_ctx.drawImage(img, 0, 0, 310, 155); var blockWidth = w + r * 2;//滑块实际宽度 var _y = y - r * 2 + 2 // 滑块实际的y坐标 var ImageData = block_ctx.getImageData(x, _y, blockWidth, blockWidth);//拿到滑块的像素数据 block.width = blockWidth;//将滑块dom元素的宽度设置成滑块的掉 block_ctx.putImageData(ImageData, 0, _y) }; img.crossOrigin = 'Anonymous';//防止图片报跨域的错 img.src = 'http://kexiepingtaieposter.hoohui.cn//registFile/fa5df7c9-445d-4b58-97c4-ad8b86a92241/Z0134_20200224232124.png?time='+ new Date();//加事件戳 防止图片报跨域的错 // 先利用clip()方法裁剪出个方块儿,让大家认识裁剪 var x = 150, y = 40, w = 42, r = 10, PI = Math.PI;//x坐标、y坐标、正方形的宽、圆的半径、圆周率(3.14...) function draw(ctx, operation) { ctx.beginPath();//拿笔 ctx.moveTo(x,y);//把笔尖点到这个点 ctx.lineTo(x+w/2,y);//笔尖画到 正方形上边线中间 ctx.arc(x+w/2,y-r+2, r,0,2*PI); //在坐标点(x+w/2,y-r+2)画一个r为半径的圆,角度开始为0,结束角度为2π,顺时针画个圆 ctx.lineTo(x+w/2,y);//笔尖移动到 正方形上边线中间 ctx.lineTo(x+w,y);//笔尖画到 正方形的上边线的右侧 ctx.lineTo(x+w,y+w/2);//笔尖再画到正方形的右边线中间点 ctx.arc(x+w+r-2,y+w/2,r,0,2*PI) //在合适的位置画个圆 ctx.lineTo(x+w,y+w/2);//笔尖画到正方形的 右边线中间点 ctx.lineTo(x+w,y+w);//笔尖画到正方形右边线的底部 ctx.lineTo(x,y+w);//再画到正方形的下边线的左侧 ctx.lineTo(x,y);//再画到正方形的起始点 形成闭环 // ctx.clip();//用剪刀裁剪 注释掉 ctx.fillStyle = '#fff'; ctx[operation](); ctx.beginPath();//重新开始画 ctx.arc(x,y+w/2, r,1.5*PI,0.5*PI) // 只需要画正方形内的半圆就行,方便背景图片的裁剪 ctx.globalCompositeOperation = "xor";//将原图遮盖出一个缺口 ctx.fill();//填充颜色 前面没加fillStyle就是白色 } draw(canvas_ctx,"fill"); draw(block_ctx,"clip");
下面就是编写拖动代码了。。。后续补上
。