zoukankan      html  css  js  c++  java
  • canvas实现验证码

    在通常的登录界面我们都可以看到验证码,验证码的作用是检测是不是人在操作,防止机器等非人操作,防止数据库被轻而易举的攻破。

    验证码一般用PHP和java等后端语言编写。

    但是在前端,用canva或者SVG也可以绘制验证码。

    绘制验证码不能是简单的随机字符串,而应该在绘制界面有一些干扰项:

    如:干扰线段干扰圆点背景等等。

    这里的这个demo的canvas验证码干扰项比较简单。

    可以在图示中看到本例中的干扰项。

    canvas验证码展示效果:

    点击实现改变(重绘)验证码:

    在控制台运行函数输出返回值(验证码):

    源码

      1 <!DOCTYPE html>
      2 <html lang="en">
      3 
      4 <head>
      5     <meta charset="UTF-8">
      6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
      7     <meta http-equiv="X-UA-Compatible" content="ie=edge">
      8     <title>canvas验证码</title>
      9 </head>
     10 
     11 <body>
     12     <canvas width="200" height="60" id="check" style="border:1px solid #000;">您的浏览器不支持canvas标签!</canvas>
     13     <script>
     14         var ctx = document.getElementById("check").getContext("2d");
     15         var ctxW = document.getElementById("check").clientWidth;
     16         var ctxH = document.getElementById("check").clientHeight;
     17 
     18         /**
     19          * 产生一个随机数  可设置随机数区间
     20          * @param  {[Number]} min [随机数区间下限]
     21          * @param  {[Number]} max [随机数区间上限]
     22          * @return {[Number]}     [返回一个在此区间的随机数]
     23          */
     24         function ranNum(min, max) {
     25 
     26             return Math.random() * (max - min) + min;
     27 
     28         }
     29 
     30         /**
     31          * 返回一个随机颜色 可设置颜色区间
     32          * @param  {[Number]} min [颜色下限]
     33          * @param  {[Number]} max [颜色上限]
     34          * @return {[String]}     [随机颜色]
     35          */
     36         function ranColor(min, max) {
     37 
     38             var r = ranNum(min, max);
     39 
     40             var g = ranNum(min, max);
     41 
     42             var b = ranNum(min, max);
     43 
     44             // return "rgb(" + r + "," + g + "," + b + ")";
     45             return `rgb(${r},${g},${b})`;
     46 
     47         }
     48 
     49         /**
     50          * 随机字符串数组
     51          * @return {[Array]} [随机数组]
     52          */
     53         function ranStr() {
     54 
     55             var str = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm0123456789";
     56 
     57             return str.split("").sort(function () {
     58                 return Math.random() - 0.5
     59             });
     60 
     61         }
     62 
     63         /**
     64          * 绘制文本字符串
     65          * @param  {[String]} canvasId [canvas的id]
     66          * @param  {[Number]} canvasW  [canvas的width]
     67          * @param  {[Number]} canvasH  [canvas的height]
     68          * @param  {[Number]} num      [绘制验证码的字数]
     69          * @param  {[Number]} fsMin    [字体大小下限]
     70          * @param  {[Number]} fsMax    [字体大小上限]
     71          * @param  {[Number]} frMin    [字体旋转偏移下限]
     72          * @param  {[Number]} frMax    [字体旋转偏移上限]
     73          * @param  {[Number]} min      [颜色下限]
     74          * @param  {[Number]} max      [颜色上限]
     75          * @return {[String]} [随机字符串]
     76          */
     77         function drawText(canvasId, canvasW, canvasH, num, fsMin, fsMax, frMin, frMax, min, max) {
     78 
     79             var str = "";
     80 
     81             for (var i = 0; i < num; i++) {
     82 
     83                 var char = ranStr()[Math.floor(0, ranStr().length)];
     84 
     85                 var fs = ranNum(fsMin, fsMax);
     86 
     87                 canvasId.font = fs + "px Verdana";
     88 
     89                 canvasId.fillStyle = ranColor(min, max);
     90 
     91                 // 保存绘制的状态
     92                 canvasId.save();
     93 
     94                 // context.translate(x,y);
     95                 // x    添加到水平坐标(x)上的值
     96                 // y    添加到垂直坐标(y)上的值
     97                 // 偏移
     98                 canvasId.translate(canvasW / num * i + canvasW / 20, 0);
     99 
    100                 // 变换角度
    101                 canvasId.rotate(ranNum(frMin, frMax) * Math.PI / 180);
    102 
    103                 // context.fillText(text,x,y,maxWidth);
    104                 // text    规定在画布上输出的文本。
    105                 // x    开始绘制文本的 x 坐标位置(相对于画布)。
    106                 // y    开始绘制文本的 y 坐标位置(相对于画布)。
    107                 // maxWidth    可选。允许的最大文本宽度,以像素计。
    108                 canvasId.fillText(char, 0, (canvasH + fs) / 2.5, canvasW / num);
    109 
    110                 // 返回之前保存过的路径状态和属性
    111                 ctx.restore();
    112 
    113                 str += char;
    114 
    115             }
    116 
    117             // console.log(str);
    118             return str;
    119 
    120         }
    121 
    122         /**
    123          * 绘制背景
    124          * @param  {[String]} canvasId [canvas的id]
    125          * @param  {[Number]} canvasW  [canvas的width]
    126          * @param  {[Number]} canvasH  [canvas的height]
    127          * @param  {[Number]} min      [下限]
    128          * @param  {[Number]} max      [上限]
    129          */
    130         function drawBg(canvasId, canvasW, canvasH, min, max) {
    131 
    132             // 绘制canvas背景
    133             canvasId.fillStyle = ranColor(min, max);
    134 
    135             // 填充颜色
    136             canvasId.fillRect(0, 0, canvasW, canvasH);
    137 
    138         }
    139 
    140         /**
    141          * 绘制干扰 圆点
    142          * @param  {[String]} canvasId [canvas的id]
    143          * @param  {[Number]} canvasW  [canvas的width]
    144          * @param  {[Number]} canvasH  [canvas的height]
    145          * @param  {[Number]} num      [绘制的数量]
    146          * @param  {[Number]} r        [圆点半径]
    147          * @param  {[Number]} min      [下限]
    148          * @param  {[Number]} max      [上线]
    149          */
    150         function drawCircle(canvasId, canvasW, canvasH, num, r, min, max) {
    151 
    152             for (var i = 0; i < num; i++) {
    153 
    154                 // 开始绘制 (拿起笔)
    155                 canvasId.beginPath();
    156 
    157                 // context.arc(x,y,r,sAngle,eAngle,counterclockwise); (绘制)
    158                 // x    圆的中心的 x 坐标。
    159                 // y    圆的中心的 y 坐标。
    160                 // r    圆的半径。
    161                 // sAngle    起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。
    162                 // eAngle    结束角,以弧度计。
    163                 // counterclockwise    可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。
    164                 canvasId.arc(ranNum(0, canvasW), ranNum(0, canvasH), r, 0, 2 * Math.PI);
    165 
    166                 // 填充颜色
    167                 canvasId.fillStyle = ranColor(min, max);
    168 
    169                 // 填充
    170                 canvasId.fill();
    171 
    172                 // 闭合绘制 (放开笔)
    173                 canvasId.closePath();
    174 
    175             }
    176 
    177         }
    178 
    179         /**
    180          * 绘制干扰 线段
    181          * @param  {[String]} canvasId [canvas的id]
    182          * @param  {[Number]} canvasW  [canvas的width]
    183          * @param  {[Number]} canvasH  [canvas的height]
    184          * @param  {[Number]} num      [绘制的数量]
    185          * @param  {[Number]} min      [下限]
    186          * @param  {[Number]} max      [上线]
    187          */
    188         function drawLine(canvasId, canvasW, canvasH, num, min, max) {
    189 
    190             for (var i = 0; i < num; i++) {
    191 
    192                 // 开始绘制 (拿起笔)
    193                 canvasId.beginPath();
    194 
    195                 // 绘制开始点
    196                 canvasId.moveTo(ranNum(0, canvasW), ranNum(0, canvasH));
    197 
    198                 // 绘制结束点
    199                 canvasId.lineTo(ranNum(0, canvasW), ranNum(0, canvasH));
    200 
    201                 canvasId.strokeStyle = ranColor(min, max);
    202 
    203                 canvasId.stroke();
    204 
    205                 canvasId.closePath();
    206 
    207             }
    208 
    209         }
    210 
    211         // 绘制验证码
    212         function drawCanvas() {
    213 
    214             // 清空canvas
    215             ctx.clearRect(0, 0, 200, 60);
    216 
    217             // 绘制背景
    218             drawBg(ctx, ctxW, ctxH, 200, 255);
    219 
    220             // 绘制干扰圆点
    221             drawCircle(ctx, ctxW, ctxH, 20, 5, 200, 255);
    222 
    223             // 绘制干扰线段
    224             drawLine(ctx, ctxW, ctxH, 20, 0, 255);
    225 
    226             // 绘制验证码
    227             var str = drawText(ctx, ctxW, ctxH, 4, 10, 50, -30, 30, 0, 100);
    228 
    229             return str;
    230 
    231         }
    232 
    233         drawCanvas();
    234 
    235         document.getElementById('check').onclick = drawCanvas;
    236     </script>
    237 </body>
    238 
    239 </html>
  • 相关阅读:
    序列
    2018131
    成都七中
    NOIP2017
    洛谷P1352 CodeVS1380 没有上司的舞会
    BZOJ1087 SCOI2005 互不侵犯King
    11-4-2017 星期六 R-Day?
    11-3-2017 星期五
    11-2-2017 星期四
    USACO 2014 US Open, Silver Problem 2. Dueling GPSs
  • 原文地址:https://www.cnblogs.com/lprosper/p/9504968.html
Copyright © 2011-2022 走看看