一步一步教大家用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");

 下面就是编写拖动代码了。。。后续补上

原文地址:https://www.cnblogs.com/fqh123/p/12359355.html