滑动拼图验证码 免费 java,原生js+canvas实现滑动拼图验证码

94e2994b3ece56ede6206e46c4bc80d8.png

上图为网易云盾的滑动拼图验证码,同一张图片裁剪的位置是固定的,猜想其应该有一个专门的图片库,保存了被裁剪的背景图和可移动的滑块。我的想法是,随机生成图片,随机生成位置,再用canvas裁剪出滑块和背景图。下面介绍具体步骤。

首先随便找一张图片渲染到canvas上,这里#canvas作为画布,#block作为裁剪出来的小滑块。

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 = 'img.jpg'

7f4f520c2a48101f0340c0d7b457a2c0.png

下面考虑如何裁剪出拼图的形状,拼图形状比较复杂,首先我们画一个正方形,接着上边的代码写:

var x = 150, y = 40, w = 42, r = 10, PI = Math.PI

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)

x,y为正方形左上角的坐标,现在先随便写后边生成的时候用随机数,w为正方形的边长,r为后边画缺口的圆的半径。我们先把绘图过程用函数封装起来,方便后面同时操作背景和滑块。用clip()方法裁剪图片后生成一个正方形。

884567f2540d9493afd193f7f48cec8d.png

接下来画正方形上边和右边的圆形:

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) //

+ 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()

}

ee7fe9d9b016502ebafe8f8dac529ea9.png

两处注释的位置将圆心往内偏移了2px,实现缺口的样式。然后是左边空心的部分,由于clip是裁剪路径内的部分,因此直接像上面画圆是不行的,我们开启一条新的路径,然后画圆将这个正方形“遮盖”出一个缺口,这里会用到globalCompositeOperation 属性,'xor'顾名思义。代码接上边:

function draw(ctx) {

ctx.beginPath()

...

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()

}

67b94dbc92a1e2a8d4953185b2d17e87.png

现在一个基本的拼图形状有了,我们调整#block的大小,并将裁剪出来的滑块放入#block中:

img.onload = function() {

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

+ block_ctx.putImageData(ImageData, 0, _y)

}

b0e0608deb35399ac1edeef73d98efa8.png

现在我们需要把左边画布展示原来的图片,并且抠掉中间滑块的部分,这里画路径的过程都是一样的,唯一不同只是clip()那里改成fill()即可实现效果,我们前面已经把画路径的过程封装成函数了,稍作改动即可:

- function draw(ctx) {

+ function draw(ctx, operation) {

...

- ctx.clip()

+ ctx.fillStyle = '#fff'

+ ctx[operation]()

...

}

+ draw(canvas_ctx, 'fill')

+ draw(block_ctx, 'clip')

36a98e1711d35f5a8bab7bb1d312f2ae.png

接下来就是写样式了,略过:

39d5c829479e422a3af3f1e55dccf532.png

然后就是写拖动事件,我们可以在鼠标按下时记录鼠标位置,然后在拖动时给滑块设置left值。最后在松开鼠标时,判断滑块此时的left值和最开始裁剪滑块时的x值,如果在一定范围内就算验证通过,否则验证失败。

最后再加上随机图片和随机剪切位置,基本就ok了。另外可以判断下鼠标移动时y轴的变化,以判断是否是“人”在操作,当然web安全这块神魔乱舞的,我就不班门弄斧了,只是做个简单判断就行。

51c36a6f5cbb002583fccc045fc3c80f.png

后边代码比较杂乱,就不贴上来了,查看完整代码点这里 演示地址点这里

代码更新了,现在直接用ctx.arc画出滑块的边界,而不是像之前画正方形+三个圆去拼接,因此也能加上stroke提高辨识度了,详细见github

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值