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

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

<canvas width="310" height="155" id="canvas"></canvas>
<canvas width="310" height="155" id="block"></canvas>
  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'

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

  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()方法裁剪图片后生成一个正方形。

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

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

两处注释的位置将圆心往内偏移了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()
}



现在一个基本的拼图形状有了,我们调整#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)
}

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

-  function draw(ctx) {
+ function draw(ctx, operation) {
...
- ctx.clip() + ctx.fillStyle = '#fff'
+ ctx[operation]()
...
}
+ draw(canvas_ctx, 'fill')
+ draw(block_ctx, 'clip')

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

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

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

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


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

原生js+canvas实现滑动拼图验证码的更多相关文章

  1. js实现滑动拼图验证码

    js实现滑动拼图验证码,我这个样式是仿那些大网站做了, 学习用的,只用到前端. 小的个人网站感觉还可以用,大一点的别人用机器一下就破解了. 下面看图示: 样子大概是这样的. 源码在这 百度网盘:    ...

  2. 转 原生js canvas实现苹果电脑mac OS窗口最小化效果

    http://www.17sucai.com/pins/demo-show?id=2459 http://www.17sucai.com/pins/demo-show?id=2458  很多资料 ,前 ...

  3. 原生JS+Canvas实现五子棋游戏

    一.功能模块 先看下现在做完的效果: 线上体验:https://wj704.github.io/five_game.html 主要功能模块为: 1.人机对战功能 2.悔棋功能 3.撤销悔棋功能 二.代 ...

  4. 如何从零绘制k线图 -- 原生js canvas图表绘制

    样式如下图 源码地址: https://github.com/sutianbinde/charts 编写这个需要具备canvas基础,如果没有canvas基础可以学习我前面的cnavas基础博客. 具 ...

  5. 原生js移动端滑动事件

    移动端触屏滑动的效果其实就是图片轮播,在PC的页面上很好实现,绑定click和mouseover等事件来完成.但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch事件 ...

  6. 用原生js+canvas实现五子棋

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  7. JS 原生JS 判断滚动条滑动到底部(兼容苹果safari)

    ListenerScoller () { var pageIndex = 1; var startX, startY; document.addEventListener('touchstart',f ...

  8. JS 原生JS 判断滚动条滑动到底部

    window.addEventListener("scroll", function(event) { var scrollTop = document.documentEleme ...

  9. 原生JS实现全屏切换以及导航栏滑动隐藏及显示——重构前

    思路分析: 向后滚动鼠标滚轮,页面向下全屏切换:向前滚动滚轮,页面向上全屏切换.切换过程为动画效果. 第一屏时,导航栏固定在页面顶部,切换到第二屏时,导航条向左滑动隐藏.切换回第一屏时,导航栏向右滑动 ...

随机推荐

  1. Java中子类能继承父类的私有属性吗?

    前段时间去听老师讲课的时候,老师告诉我子类是可以继承父类所有的属性和方法的.当时我是极其疑惑的,因为之前学校考试时这个考点我记得很清楚:子类只能继承父类的非私有属性和方法.老师给我的解释是这样的--先 ...

  2. 在linux系统中

    A .etc下放置配置文件 B./var下放置日志文件 C./root超级用户主目录 D./home 使用者家目录 /bin  二进制执行文件,也就是命令文件 /etc 下存放的是配置文件 /dev ...

  3. nodejs之socket.io模块——实现了websocket协议

    Nodejs实现websocket的4种方式:socket.io.WebSocket-Node.faye-websocket-node.node-websocket-server,主要使用的是sock ...

  4. 沉淀,再出发——在Ubuntu Kylin15.04中配置Hadoop单机/伪分布式系统经验分享

    在Ubuntu Kylin15.04中配置Hadoop单机/伪分布式系统经验分享 一.工作准备 首先,明确工作的重心,在Ubuntu Kylin15.04中配置Hadoop集群,这里我是用的双系统中的 ...

  5. c# try-finally有什么用

     finally 代码块中的代码是 try-catch 结构执行完后无论有无异常发生都会执行的.finally 代码块中的代码是 try-catch 结构执行完后无论有无异常发生都会执行的.final ...

  6. 【其他】3dmax撤销Ctrl+z不能用的解决办法

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/3dmax_ctrlz.html 如果你经常去网上下载各种模型参考学习的话,出现这个问题的概率会非常高.因为出现这个 ...

  7. FusionCharts重写单系列图

    /** * @Title:FusionChart.java * @Package:com.yhd.chart.model * @Description:封装FusionChart单系列图 * @aut ...

  8. (二十八)monggodb和maven零散笔记

    (1)maven导包的问题:当在pom.xml界面的Dependencies中点击add之后输入jar包查询条件后,如果确定条件没有输错,repo中也确实存在相关jar包,而并没有查处任何结果时,可以 ...

  9. WDF驱动的编译、调试、安装

    编译和调试使用WDK编译,源代码应包括wdf.h,ntddk.h以及KMDF_VERSION=1,编译使用/GS.KMDF包括以下库:1). WdfDriverEntry.lib(编译时绑定):驱动入 ...

  10. Vue01 Vue介绍、Vue使用、Vue实例的创建、数据绑定、Vue实例的生命周期、差值与表达式、指令与事件、语法糖

    1 Vue介绍 1.1 官方介绍 vue是一个简单小巧的渐进式的技术栈,它提供了Web开发中常用的高级功能:视图和数据的解耦.组件的服用.路由.状态管理.虚拟DOM 说明:简单小巧 -> 压缩后 ...