canvas-demo1(滑块验证码)
1. 最终效果
2.滑块验证码思路
大概思路:设置两个画布,一个为显示图像的canvas画布,一个为拼图的block画布,block画布拼图内容从图像画布中的一部分裁剪得到(使用clip()),通过绑定鼠标拖动事件,滑动滑块得到block最终的落点坐标,如果坐标落点与原剪切点坐标偏差在设置范围内,显示成功,否则显示失败。
3.绘制拼图
所需要绘制的拼图图形:
首先进行几何分析,主要由1个正方形+两块突出的部分圆+凹陷的圆
明确需要使用到的绘制方法有基本的lineTo绘制线段路径,arc绘制圆形,和globalCompositeOperation异或混合处理图形
为方便演示,单独创建画布进行每一步的操作演示:
const x = 30;//起始点x坐标
const y = 30;//起始点y坐标
const l = 42;//正方形边长
const r = 10;//圆的半径
const PI = Math.PI;
- 拼图左上角开始绘制和第一个圆形部分
ctx.moveTo(x, y);
ctx.lineTo(x + l / 2, y);//绘制边
ctx.arc(x + l / 2, y - r + 2, r, 0, 2 * PI);//绘制上圆
ctx.lineTo(x + l / 2, y);//返回到边的结束点
圆心y轴左边为(y - r + 2)中的+2是因为拼图不是完整外凸的圆形,需要一定的纵坐标偏移;
为什么需要第三步ctx.lineTo(x + l / 2, y);
是因为根据arc的定义:
arc(圆心x坐标, 圆心y坐标, 圆的半径r , 开始角度, 结束角度)
开始角度和结束角度定义如下:
因此需要从圆点对应的0度开始绘制到结束的同一个点,而下一次绘制需要回到第一条线段的结束点。
- 绘制第二个圆
ctx.lineTo(x + l, y);
ctx.lineTo(x + l, y + l / 2);
ctx.arc(x + l + r - 2, y + l / 2, r, 0, 2 * PI);
ctx.lineTo(x + l, y + l / 2);
思路同绘制第一个圆相同。
- 绘制完剩下的正方形
ctx.lineTo(x + l, y + l);
ctx.lineTo(x, y + l);
ctx.lineTo(x, y);
- 通过异或混合处理剩下的缺口
ctx.fill();//填充上述正方形
ctx.beginPath();//开始新的绘制
ctx.arc(x, y + l / 2, r, 1.5 * PI, 0.5 * PI);
ctx.globalCompositeOperation = "xor";//异或处理
ctx.fill();//
xor:使用异或操作,对源图像与目标图像进行结合处理效果如下
4.随机图片和拼图随机起始位置
随机图片由该网站获取:http://picsum.photos
通过基本的随机数字函数调用:
function getRandomNumberByRange(start, end) {
return Math.round(Math.random() * (end - start) + start);
}
function getRandomImgSrc() {
return (
"http://picsum.photos/300/150/?image=" + getRandomNumberByRange(0, 100)
);
}
拼图随机位置也是通过随机函数限定边界在画布内随机出现
draw() {
this.x = getRandomNumberByRange(ll + 10, w - (ll + 10));//10为设定的最小空隙,ll是保证滑块到最终位置和初始位置至少不会重叠
this.y = getRandomNumberByRange(10 + r * 2, h - (ll + 10));
draw(this.canvasCtx, "fill", this.x, this.y);
draw(this.blockCtx, "clip", this.x, this.y);
}