canvas汉字验证码

将原本在服务器端生成的验证码图形移动到浏览器端

demo地址:http://www.free361.com/demo.php?id=5



captcha.js

function canvasApp(_msg_str,callback_fun){
    function canvasSupport(){
        return     Modernizr.canvas; //检查是否支持canvas
    }
    function checkMobile(){
        return     Modernizr.touchevents; //检查是否手机浏览器
    }
    
    if(!canvasSupport()){
        return;    
    }
    
    var msg_str = _msg_str;    //"所对角的正弦之比相等",用于验证的文字
    var msg_arr = msg_str.split("");

    var cas_box_obj = document.getElementById("cas_box");
    var canvas_offset_x = cas_box_obj.offsetLeft;    //画布偏移量50
    var canvas_offset_y = cas_box_obj.offsetTop;
    
    var font_size = 18;
    var background_color_range = 50;    //杂色概率,1/50
    var save_distance = Math.ceil(font_size*2*Math.sqrt(2))-font_size/2;    //安全距离:两个字体左下角坐标点的距离>2*根号2*fontsize
    
    var is_mobile = checkMobile();    //判断是否手机
    
    var result_code = "";    //最终结果
    var positions = [];        //位置缓存
    
    var canvas_obj = document.getElementById("cas");
    var context = canvas_obj.getContext("2d");    //2d上下文对象
    
    console.log(canvas_offset_x,canvas_offset_y);
    
    canvas_obj.addEventListener("click",checkWord,false);
    
    function checkWord(e){
        if(is_mobile){
            //手机触屏
            if (e.targetTouches.length == 1) {
             event.preventDefault();// 阻止浏览器默认事件,重要 
                var touch = e.targetTouches[0];
                
                //目标坐标
                var mx = touch.pageX-canvas_offset_x;
                var my = touch.pageY-canvas_offset_y;
            }else{
                alert("不支持多点触摸");
                return;
            }
            
        }else{
            var mx = e.x-canvas_offset_x;
            var my = e.y-canvas_offset_y;
        }
        console.log(e.x,e.y,mx,my);
        
        for(var i=0;i<msg_arr.length;i++){
            //context,"arc","150,250,120,0,"+2*Math.PI
            var x = positions[i*3];
            var y = positions[i*3+1];
            
            var arg_org = positions[i*3+2];
            var angle = positions[i*3+2]*Math.PI/180;
            
            var f_x = Math.ceil(Math.cos(angle)*font_size);
            var f_y = Math.ceil(Math.sin(angle)*font_size);
            
            var m = 0;
              var n = 0;
              
            var point = [x+m,y+n,x+f_x+m,y+f_y+n,x+f_y+f_x+m,y+f_y-f_x+n,x+f_y+m,y-f_x+n];
            
            var event1=new addEvent(context,"egg",point,mx,my,i,function(n) {
                //因为beginPath清掉了前面路径的所有绑定,所以这里重新绑定区域的路径
                  
                  result_code += n;
//                  alert(this.code);
//                  console.log(result_code);
                saveCode(result_code);
                  var arr = point;
                  
                  context.beginPath();
                  context.strokeStyle = "rgba(255,0,0,1)";
                  context.lineWidth = 2;
                  var arr=this.data;
                  
                  context.moveTo(arr[0],arr[1]);    
                context.lineTo(arr[2],arr[3]);    
                context.lineTo(arr[4],arr[5]);    
                context.lineTo(arr[6],arr[7]);    
                context.lineTo(arr[0],arr[1]);    
                  
                  context.stroke();
                   context.closePath();
                   
            });
            event1.add(mx,my);
        }
        
    }
    
    function saveCode(code){
        callback_fun(code);
    }
    
    function addEvent (cobj,type,data,mx,my,id,callback) {
        this.cobj=cobj;            //给addEvent增加属性和方法
        this.type=type;
        this.data=data;
        this.callback=callback;
        this.x = mx;
        this.y = my;
        this.id= id;
        this.redraw();
    }
    
       addEvent.prototype={        //给addEvent原型增加方法
         redraw:function  () {            //重绘
               if(this.type=="egg"){
                  this.cobj.beginPath();
                  this.cobj.strokeStyle = "rgba(255,0,0,0)";
                  this.cobj.lineWidth = 2;
                  var arr=this.data;
                  
                  context.moveTo(arr[0],arr[1]);    
                context.lineTo(arr[2],arr[3]);    
                context.lineTo(arr[4],arr[5]);    
                context.lineTo(arr[6],arr[7]);    
                context.lineTo(arr[0],arr[1]);    
                  
                  this.cobj.stroke();
                  
            }
         },
         add:function  (mx,my) {
            if(this.cobj.isPointInPath(mx,my)){
                this.callback(this.id);
            }
         }
       }
    
    function drawScreen(){
        function getRandColor(){
            //随机颜色
            var r = Math.ceil(Math.random()*255);
            var g = Math.ceil(Math.random()*255);
            var b = Math.ceil(Math.random()*255);
            
            while(r>100 && g>100 && b>100){
                //不允许有白色
//                r = Math.ceil(Math.random()*255);
//                g = Math.ceil(Math.random()*255);
//                b = Math.ceil(Math.random()*255);
//                console.log(r,g,b);
                r = 0;
                g = 0;
                b = 0;
            }
            
            //透明度要在75%以上
            var a = Math.ceil(Math.random()*40)/10;
            if(a>1 || a<0.75){
                a = 1;
            }
            
            var rgb = "rgba("+r+","+g+","+b+","+a+")";
            
            return rgb;
        }
        //边界检测
        function checkBorder(x,y){
            //边框检查
            if(x > canvas_obj.width-2*font_size){
                return true;
            }
            if(y > canvas_obj.height-2*font_size){
                return true;
            }
            if(x < 2*font_size){
                return true;
            }
            if(y < 2*font_size){
                return true;
            }
            
            //字字直接检查
            if(positions.length>0){
                for(var i=0;i<positions.length;i+=3){
//                    Debugger.log(positions[i],Math.abs(x-positions[i]),save_distance);
                    
                    if(Math.abs(x-positions[i])<save_distance && Math.abs(y-positions[i+1])<save_distance){
//                        console.log(1);
                        return true;
                    }
                    
                }
            }
            
        }
        function getRandPosition(){
            var x = Math.ceil(Math.random()*canvas_obj.width);
            var y = Math.ceil(Math.random()*canvas_obj.height);
            
            while(checkBorder(x,y)){
                x = Math.ceil(Math.random()*canvas_obj.width);
                y = Math.ceil(Math.random()*canvas_obj.height);
            }
            
            var _poi = [];
            
            _poi.push(x);
            _poi.push(y);
            
            return _poi;
        }
        function getRandAngle(){
            return Math.ceil(Math.random()*360);
        }
        function getRandStyle(){
            var font_style = ["normal","italic","oblique"];
            var i = Math.ceil(Math.random()*3);
            
            return font_style[i-1];
        }
        function getRandFace(){
            var font_face = ["微软雅黑","仿宋","宋体","楷体","黑体"];
            var i = Math.ceil(Math.random()*5);
            
            return font_face[i-1];
        }
        function createBackground(ctx){
            var image_obj = ctx.getImageData(canvas_obj.width,canvas_obj.height,canvas_obj.width,canvas_obj.height);
//            Debugger.log(image_obj);
            for (var y = 0; y < image_obj.height; y++) {
                for (var x = 0;x < image_obj.width; x++) {
                    
                    var r = Math.ceil(Math.random()* background_color_range);
                    
                    if(r == 1){
                        var index = y * image_obj.width + x;      //index 为当前要处理的像素编号
                        
                        var p = index * 4;
                        
                        image_obj.data[p] = Math.ceil(Math.random()*255);
                        image_obj.data[p+1] = Math.ceil(Math.random()*255);
                        image_obj.data[p+2] = Math.ceil(Math.random()*255);
                        image_obj.data[p+3] = Math.ceil(Math.random()*255);
                    }
                        
                }
            }
//            console.log(image_obj);
            ctx.putImageData(image_obj,0,0);
        }
        
        //背景色
        createBackground(context);

        //边框
        context.strokeStyle = "#000000";
        context.strokeRect(1,1,canvas_obj.width-2,canvas_obj.height-2);
        
        for(var i=0;i<msg_arr.length;i++){
            //随机颜色
            var rgb = getRandColor();
            
            //随机位置
            var temp = getRandPosition();
            
            var x = temp[0];
            var y = temp[1];
            
            //随机角度
            var angle = getRandAngle();
            var radian = angle*Math.PI/180;    //弧度
            
            //随机样式
            var font_style = getRandStyle();
            var font_face = getRandFace();
            
            //记录各文字位置
            positions.push(x);
            positions.push(y);
            positions.push(angle);
            
            context.fillStyle = rgb;
            context.font = font_style+" "+font_size+"px "+font_face;
            
            context.save();
            context.setTransform(1,0,0,1,0,0);
            context.translate(x,y);
            context.rotate(radian);
            context.fillText(msg_arr[i],0,0);
            context.restore();
        }
        
    }
    
    drawScreen();
}

//调用

window.addEventListener("load",eventWindowLoaded,false);

function eventWindowLoaded(){
    event_can = new canvasApp("所对角的正弦之比相等",function(code){
        console.log(code);
    });
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值