151 lines
5.1 KiB
JavaScript
151 lines
5.1 KiB
JavaScript
/*!
|
||
* jquery-captcha v1.0 (https://github.com/honguangli/jquery-captcha)
|
||
* Copyright honguangli
|
||
* Licensed under the MIT license
|
||
*/
|
||
;
|
||
let Captcha;
|
||
(function($) {
|
||
'use strict';
|
||
const resourceUpper = ['A','B','C','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','W','X','Y','Z'];
|
||
const resourceLower = ['a','b','c','e','f','g','h','j','k','l','m','n','p','q','r','s','t','w','x','y','z'];
|
||
const resourceNumber = ['0','1','2','3','4','5','6','7','8','9'];
|
||
|
||
Captcha = function(element, options) {
|
||
const self = this;
|
||
const defaults = {
|
||
length: 5, // 校验码长度
|
||
width: 100, // canvas宽度
|
||
height: 40, // canvas高度
|
||
font: 'bold 23px Arial', // 文本字体样式
|
||
resourceType: 'aA0', // 资源类型:a-小写字母、A-大写字母、0-数字,可任意组合
|
||
resourceExtra: [], // 额外资源
|
||
clickRefresh: true, // 点击刷新
|
||
autoRefresh: true, // 调用校验接口后是否自动刷新(校验成功不会刷新)
|
||
caseSensitive: true, // 大小写是否敏感
|
||
};
|
||
|
||
self.element = element;
|
||
|
||
self.options = $.extend(true, defaults, options);
|
||
|
||
// 合并资源
|
||
let resource = [];
|
||
if (self.options.resourceType.length > 0) {
|
||
if (self.options.resourceType.indexOf('A') !== -1) {
|
||
resource = resource.concat(resourceUpper);
|
||
}
|
||
if (self.options.resourceType.indexOf('a') !== -1) {
|
||
resource = resource.concat(resourceLower);
|
||
}
|
||
if (self.options.resourceType.indexOf('0') !== -1) {
|
||
resource = resource.concat(resourceNumber);
|
||
}
|
||
}
|
||
if (self.options.resourceExtra.length > 0) {
|
||
resource = resource.concat(self.options.resourceExtra);
|
||
}
|
||
// 配置资源为空
|
||
if (resource.length === 0) {
|
||
resource = resourceUpper.concat(resourceLower).concat(resourceNumber)
|
||
}
|
||
self.resource = resource;
|
||
|
||
if (self.options.clickRefresh) {
|
||
self.element.on('click', function () {
|
||
self.refresh();
|
||
});
|
||
}
|
||
self.refresh();
|
||
};
|
||
// 刷新
|
||
Captcha.prototype.refresh = function() {
|
||
const self = this;
|
||
|
||
const canvas = self.element[0]; // 获取canvas对象
|
||
canvas.width = self.options.width;
|
||
canvas.height = self.options.height;
|
||
const context = canvas.getContext("2d"); // 获取canvas环境
|
||
context.font = self.options.font;
|
||
|
||
const codes = self.randomCode();
|
||
|
||
const spaceWidth = canvas.width - context.measureText(codes.join('')).width - 40;
|
||
const wordSpace = Math.floor(spaceWidth / codes.length);
|
||
|
||
let left = 10;
|
||
for (let i = 0; i < codes.length; i++) {
|
||
const deg = Math.random() * 30 * Math.PI / 180; // 产生0~30之间的随机弧度
|
||
const x = left; // 文本的x坐标
|
||
const y = canvas.height / 2 + Math.random()*10; // 文本的y坐标
|
||
|
||
context.translate(x, y);
|
||
context.rotate(deg);
|
||
|
||
context.fillStyle = self.randomColor();
|
||
context.fillText(codes[i], 0, 0);
|
||
|
||
context.rotate(-deg);
|
||
context.translate(-x, -y);
|
||
|
||
left += context.measureText(codes[i]).width + wordSpace + Math.floor(Math.random()*5);
|
||
}
|
||
self.code = codes;
|
||
|
||
const strokeLength = codes.length * Math.round(Math.random()+1) + 3;
|
||
for (let i = 0; i < strokeLength; i++) {
|
||
context.strokeStyle = self.randomColor(true);
|
||
context.beginPath();
|
||
// 显示线条
|
||
context.moveTo(Math.random() * self.options.width, Math.random() * self.options.height);
|
||
context.lineTo(Math.random() * self.options.width, Math.random() * self.options.height);
|
||
// 显示小点
|
||
const x = Math.random() * self.options.width;
|
||
const y = Math.random() * self.options.height;
|
||
context.moveTo(x, y);
|
||
context.lineTo(x + 1, y + 1);
|
||
context.stroke();
|
||
}
|
||
};
|
||
// 获取当前验证码
|
||
Captcha.prototype.getCode = function() {
|
||
return this.code.join('');
|
||
};
|
||
// 校验
|
||
Captcha.prototype.valid = function(code) {
|
||
const self = this;
|
||
let ans = false;
|
||
if (!self.options.caseSensitive) {
|
||
ans = code.toLowerCase() === self.getCode().toLowerCase();
|
||
} else {
|
||
ans = code === self.getCode();
|
||
}
|
||
if (!ans && self.options.autoRefresh) {
|
||
self.refresh();
|
||
}
|
||
return ans;
|
||
};
|
||
// 获取随机校验码
|
||
Captcha.prototype.randomCode = function() {
|
||
const self = this;
|
||
const codes = [];
|
||
const resourceLength = self.resource.length;
|
||
for (let i = 0; i < self.options.length; i++) {
|
||
const txt = self.resource[Math.floor(Math.random() * resourceLength)]; // 得到随机的一个资源码
|
||
codes.push(txt);
|
||
}
|
||
return codes;
|
||
};
|
||
// 获取随机的颜色值
|
||
Captcha.prototype.randomColor = function(alpha) {
|
||
const r = Math.round(Math.random() * 255);
|
||
const g = Math.round(Math.random() * 255);
|
||
const b = Math.round(Math.random() * 255);
|
||
if (!alpha) {
|
||
return 'rgb(' + r + ',' + g + ',' + b + ')';
|
||
}
|
||
const a = Math.random();
|
||
return 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')';
|
||
};
|
||
})($);
|