zoukankan      html  css  js  c++  java
  • 滑动拼图

    当前滑动组件 使用了 https://gitee.com/LongbowEnterprise/SliderCaptcha 作者的

    在原基础上面 改动为 触发式

     <div class="slidercaptcha card">
                                                                            <div class="card-body" style="margin-left: -17px;">
                                                                                <div id="captcha" >
                                                                                    <input type="hidden" id="cap_id" value="errors" />
                                                                                    <div id="captimg" style="display: none;"></div>
                                                                                    <div id="capslider" style=" height: 29px;"></div>
                                                                                </div>
                                                                            </div>
                                                                        </div>
    
    
     var $captcha = $('#captcha').sliderCaptcha({
                            repeatIcon: 'layui-icon layui-icon-refersh',
                            setSrc: function () {
                                return '/app/static/code/Pic'+ Math.round(Math.random()*4) + '.jpg';
                            },
                            remoteUrl:'/login/Captcha',
                            onSuccess: function () {  //成功事件
                               $('#cap_id').val('success'); //
                               $(this).css('pointer-events','none');
                            }
                        });
    
    
                        $('#capslider').hover(function(){
                            //$('#captimg').slideDown(100);
                            $('#captimg').show();
                        });
                        $('.slidercaptcha').mouseleave(function(){
                            $('#captimg').hide();
                        });
    
    

    使用了layui形式的

    
    
    layui.define(['layer', 'form', 'table', 'jquery'], function (exports) {
        var $ = layui.$
         
        var SliderCaptcha = function (element, options) {
            this.$element = $(element);
            this.options = $.extend({}, SliderCaptcha.DEFAULTS, options);
            this.$element.css({ 'position': 'relative', 'width': this.options.width + 'px', 'margin': '0 auto' });
            this.init();
        };
    
        SliderCaptcha.VERSION = '1.0';
        SliderCaptcha.DEFAULTS = {
             234,     // canvas宽度
            height: 155,    // canvas高度
            PI: Math.PI,
            sliderL: 42,    // 滑块边长
            sliderR: 9,     // 滑块半径
            offset: 5,      // 容错偏差
            loadingText: '正在加载中...',
            failedText: '再试一次',
            barText: '向右滑动填充拼图',
            successText:'验证成功',
            repeatIcon: 'fa fa-repeat',
            maxLoadCount: 3,
            localImages: function () {
                return 'images/Pic' + Math.round(Math.random() * 4) + '.jpg';
            },
            verify: function (arr, url) {
                var ret = false;
                //console.log(JSON.stringify(arr))
                $.ajax({
                    url: url,
                    data: arr,
                    async: false,
                    cache: false,
                    type: 'post',
                    // contentType: 'application/json',
                    dataType: 'json',
                    success: function (result) {
                        
                        ret = result.status;
                      
                    }
                });
                return ret;
            },
            remoteUrl: null
        };
    
        function Plugin(option) {
            return this.each(function () {
                var $this = $(this);
                var data = $this.data('lgb.SliderCaptcha');
                var options = typeof option === 'object' && option;
    
                if (data && !/reset/.test(option)) return;
                if (!data) $this.data('lgb.SliderCaptcha', data = new SliderCaptcha(this, options));
                if (typeof option === 'string') data[option]();
            });
        }
    
        $.fn.sliderCaptcha = Plugin;
        $.fn.sliderCaptcha.Constructor = SliderCaptcha;
    
        var _proto = SliderCaptcha.prototype;
        _proto.init = function () {
            this.initDOM();
            this.initImg();
            this.bindEvents();
        };
    
        _proto.initDOM = function () {
            var createElement = function (tagName, className) {
                var elment = document.createElement(tagName);
                elment.className = className;
                return elment;
            };
    
            var createCanvas = function (width, height) {
                var canvas = document.createElement('canvas');
                canvas.width = width;
                canvas.height = height;
                return canvas;
            };
    
            var canvas = createCanvas(this.options.width - 2, this.options.height); // 画布
            var block = canvas.cloneNode(true); // 滑块
            var sliderContainer = createElement('div', 'sliderContainer');
            var refreshIcon = createElement('i', 'refreshIcon layui-icon layui-icon-refresh');
            var sliderMask = createElement('div', 'sliderMask');
            var sliderbg = createElement('div', 'sliderbg');
            var slider = createElement('div', 'slider');
            var sliderIcon = createElement('i', 'layui-icon layui-icon-right');
            var text = createElement('span', 'sliderText');
    
            block.className = 'block';
            text.innerHTML = this.options.barText;
    
            var captimg=$('#captimg');
            var capslider=$('#capslider');
            var el = this.$element;
           
            captimg.append($(canvas));
            captimg.append($(refreshIcon));
            captimg.append($(block));
            slider.appendChild(sliderIcon);
            sliderMask.appendChild(slider);
            sliderContainer.appendChild(sliderbg);
            sliderContainer.appendChild(sliderMask);
            sliderContainer.appendChild(text);
            capslider.append($(sliderContainer));
    
            var _canvas = {
                canvas: canvas,
                block: block,
                sliderContainer: $(sliderContainer),
                refreshIcon: refreshIcon,
                slider: slider,
                sliderMask: sliderMask,
                sliderIcon: sliderIcon,
                text: $(text),
                canvasCtx: canvas.getContext('2d'),
                blockCtx: block.getContext('2d')
            };
    
            if ($.isFunction(Object.assign)) {
                Object.assign(this, _canvas);
            }
            else {
                $.extend(this, _canvas);
            }
        };
    
        _proto.initImg = function () {
            var that = this;
            var isIE = window.navigator.userAgent.indexOf('Trident') > -1;
            var L = this.options.sliderL + this.options.sliderR * 2 + 3; // 滑块实际边长
            var drawImg = function (ctx, operation) {
                var l = that.options.sliderL;
                var r = that.options.sliderR;
                var PI = that.options.PI;
                var x = that.x;
                var y = that.y;
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
                ctx.lineTo(x + l, y);
                ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
                ctx.lineTo(x + l, y + l);
                ctx.lineTo(x, y + l);
                ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
                ctx.lineTo(x, y);
                ctx.lineWidth = 2;
                ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
                ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
                ctx.stroke();
                ctx[operation]();
                ctx.globalCompositeOperation = isIE ? 'xor' : 'destination-over';
            };
    
            var getRandomNumberByRange = function (start, end) {
                return Math.round(Math.random() * (end - start) + start);
            };
            var img = new Image();
            img.crossOrigin = "Anonymous";
            var loadCount = 0;
            img.onload = function () {
                // 随机创建滑块的位置
                that.x = getRandomNumberByRange(L + 10, that.options.width - (L + 10));
                that.y = getRandomNumberByRange(10 + that.options.sliderR * 2, that.options.height - (L + 10));
                
                drawImg(that.canvasCtx, 'fill');
                drawImg(that.blockCtx, 'clip');
    
                that.canvasCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height);
                that.blockCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height);
                var y = that.y - that.options.sliderR * 2 - 1;
                var ImageData = that.blockCtx.getImageData(that.x - 3, y, L, L);
                that.block.width = L;
                that.blockCtx.putImageData(ImageData, 0, y + 1);
                that.text.text(that.text.attr('data-text'));
            };
            img.onerror = function () {
                loadCount++;
                if (window.location.protocol === 'file:') {
                    loadCount = that.options.maxLoadCount;
                    console.error("can't load pic resource file from File protocal. Please try http or https");
                }
                if (loadCount >= that.options.maxLoadCount) {
                    that.text.text('加载失败').addClass('text-danger');
                    return;
                }
                img.src = that.options.localImages();
            };
            img.setSrc = function () {
                var src = '';
                loadCount = 0;
                that.text.removeClass('text-danger');
                if ($.isFunction(that.options.setSrc)) src = that.options.setSrc();
                if (!src || src === '') src = 'https://picsum.photos/' + that.options.width + '/' + that.options.height + '/?image=' + Math.round(Math.random() * 20);
                if (isIE) { // IE浏览器无法通过img.crossOrigin跨域,使用ajax获取图片blob然后转为dataURL显示
                    var xhr = new XMLHttpRequest();
                    xhr.onloadend = function (e) {
                        var file = new FileReader(); // FileReader仅支持IE10+
                        file.readAsDataURL(e.target.response);
                        file.onloadend = function (e) {
                            img.src = e.target.result;
                        };
                    };
                    xhr.open('GET', src);
                    xhr.responseType = 'blob';
                    xhr.send();
                } else img.src = src;
            };
            img.setSrc();
            this.text.attr('data-text', this.options.barText);
            this.text.text(this.options.loadingText);
            this.img = img;
        };
    
        _proto.clean = function () {
            this.canvasCtx.clearRect(0, 0, this.options.width, this.options.height);
            this.blockCtx.clearRect(0, 0, this.options.width, this.options.height);
            this.block.width = this.options.width;
        };
    
        _proto.bindEvents = function () {
            var that = this;
            this.$element.on('selectstart', function () {
                return false;
            });
    
            $(this.refreshIcon).on('click', function () {
                that.text.text(that.options.barText);
                that.reset();
                if ($.isFunction(that.options.onRefresh)) that.options.onRefresh.call(that.$element);
            });
    
            var originX, originY, trail = [],
                isMouseDown = false;
    
            var handleDragStart = function (e) {
                if (that.text.hasClass('text-danger')) return;
                originX = e.clientX || e.touches[0].clientX;
                originY = e.clientY || e.touches[0].clientY;
                isMouseDown = true;
            };
    
            var handleDragMove = function (e) {
                if (!isMouseDown) return false;
                var eventX = e.clientX || e.touches[0].clientX;
                var eventY = e.clientY || e.touches[0].clientY;
                var moveX = eventX - originX;
                var moveY = eventY - originY;
                if (moveX < 0 || moveX + 40 > that.options.width) return false;
                that.slider.style.left = (moveX - 1) + 'px';
                var blockLeft = (that.options.width - 40 - 20) / (that.options.width - 40) * moveX;
                that.block.style.left = blockLeft + 'px';
    
                that.sliderContainer.addClass('sliderContainer_active');
                that.sliderMask.style.width = (moveX + 4) + 'px';
                trail.push(Math.round(moveY));
            };
    
            var handleDragEnd = function (e) {
                if (!isMouseDown) return false;
                isMouseDown = false;
                var eventX = e.clientX || e.changedTouches[0].clientX;
                if (eventX === originX) return false;
                that.sliderContainer.removeClass('sliderContainer_active');
                that.trail = trail;
                var data = that.verify();
                if (data.spliced && data.verified) {
                    that.sliderContainer.addClass('sliderContainer_success');
                    $('.sliderText').show();
                    $('.slider').find('.layui-icon').removeClass('layui-icon-right').addClass('layui-icon-ok');
                    $('.refreshIcon').hide();
                    that.text.text('验证成功');
                    if ($.isFunction(that.options.onSuccess)) that.options.onSuccess.call(that.$element);
                } else {
                    that.sliderContainer.addClass('sliderContainer_fail');
                    if ($.isFunction(that.options.onFail)) that.options.onFail.call(that.$element);
                    setTimeout(function () {
                        that.text.text(that.options.failedText);
                        that.reset();
                    }, 1000);
                }
            };
    
            this.slider.addEventListener('mousedown', handleDragStart);
            this.slider.addEventListener('touchstart', handleDragStart);
            document.addEventListener('mousemove', handleDragMove);
            document.addEventListener('touchmove', handleDragMove);
            document.addEventListener('mouseup', handleDragEnd);
            document.addEventListener('touchend', handleDragEnd);
    
            document.addEventListener('mousedown', function () { return false; });
            document.addEventListener('touchstart', function () { return false; });
            document.addEventListener('swipe', function () { return false; });
        };
    
        _proto.verify = function () {
            var arr = this.trail; // 拖动时y轴的移动距离
            var left = parseInt(this.block.style.left);    
            var test = {
                'y_guiji':JSON.stringify(arr),
                'y_width':left,
                'y_left':this.x
    
            }
            var verified = false;
            if (this.options.remoteUrl !== null) {
                verified = this.options.verify(test, this.options.remoteUrl);
            }
            else {
                var sum = function (x, y) { return x + y; };
                var square = function (x) { return x * x; };
                var average = arr.reduce(sum) / arr.length;
                var deviations = arr.map(function (x) { return x - average; });
                var stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length);
                verified = stddev !== 0;
            }
            return {
                spliced: Math.abs(left - this.x) < this.options.offset,
                verified: verified
            };
        };
    
        _proto.reset = function () {
            this.sliderContainer.removeClass('sliderContainer_fail sliderContainer_success');
            this.slider.style.left = 0;
            this.block.style.left = 0;
            this.sliderMask.style.width = 0;
            this.clean();
            this.text.attr('data-text', this.text.text());
            this.text.text(this.options.loadingText);
            this.img.setSrc();
        };
    
        layui.link(layui.cache.base + 'SliderCaptcha/slidercaptcha.css');
        //对外暴露的接口
        exports('SliderCaptcha', SliderCaptcha);
        
      
      
      });
      
    
    

    php后台验证

     $data=json_decode($test['y_guiji'],true);
            //计算sum
            $sum=array_sum($data);
            //平均数
            $avg=$sum*1.0/count($data);
    
            $sum2=0;
            //计算平方差
            foreach($data as $v) {
                $sum2+=pow($v-$avg,2);
            }
            //用方差和来计算平均数
            $stddev=$sum2/count($data);
            //已经滑动了
            if ($stddev != 0) {
                //容错值设为5
                $width=$test['y_left'];
                $block=$test['y_width'];
    
                $pic=$width-$block;
    
                if ($pic>=0 && $pic<=5) {
                    $_SESSION['captha_code']=true;
                    exit(returnJson(array('msg'=>'验证成功','status'=>true)));
                }
                
    
            } else {
                exit(returnJson(array('msg'=>'验证失败','status'=>false)));
            }
    
    

    css 里面

  • 相关阅读:
    转载:MyBatis获取插入记录的自增长字段值
    006---抽象类
    005---组合
    004---继承与派生
    003---属性查找和绑定方法
    002---类与对象
    001---面向对象和面向过程的区别
    017---Django的中间件解决跨域
    10---git安装
    007---归并排序
  • 原文地址:https://www.cnblogs.com/mengluo/p/13558168.html
Copyright © 2011-2022 走看看