鼠标代码artwlfeedback.js——仿google搜索结果页的“发送反馈”功能

在本文中,我们主要介绍鼠标代码的内容,自我感觉有个不错的提议和大家分享下

    

缘起

    不知道大家有无用过google搜索结果页的“发送反馈”功能(还没有用过的,快去体验一下吧),个人用过后认为非常酷,特别适合反馈界面视觉问题,于是就有了本文介绍的小作品。

    给不能FQ的截张图吧:

    鼠标和代码

    

效果

    不知道大家有无注意到本页最上面有个“发送反馈”的固定链接,可以点击看看效果。上面是chrome下的效果:

    鼠标和代码

    注:须要浏览器支持HTML5

    

道理

    通过查看google搜索结果页反馈时的代码可以看到,是把页面生成了一个canvas,然后在canvas上画矩形来实现的:

    鼠标和代码

    所以在不支持canvas的浏览器下,是没有这个效果的。

    我的方案是利用html2canvas库把页面内容渲染成一个canvas,然后利用canvas的画图功能来做标记,然后把canvas转换为base64格式的图片用于发送反馈。

    

代码

    代码比较简单,就是先用调用html2canvas库把页面转换成一个canvas,然后把这个canvas添加到页面上,然后再创建一个空白的canvas用于画标记(矩形),添加一个空白的canvas的作用是如果标记有误方便清除。其他的就是canvas的画图的代码,最后当用户点击保存时合并前面创建的两个canvas,并利用canvas的toDataUrl方法把canvas转换为base64格式的png图片输出,后续的操作开发者就能够自己定义了。

    JS代码如下(canvas画图的代码有参考 Javascript实现canvas画图功能 一文):

    每日一道理
听,是谁的琴声,如此凄凉,低调的音,缓慢的节奏,仿佛正诉说着什么。音低调得略微有些抖动,听起来似乎心也有些抖动,我感觉到一种压抑的沉闷气息,是不是已凝结在这空气中……
var artwlfeedback = (function(){
    var load =function(callback){
        html2canvas(document.body, {
            onrendered: function(canvas) {
                canvas.id = "artwlfeedback_pagecanvas";
                var cv = document.createElement("canvas");
                cv.width = canvas.width;
                cv.height = canvas.height;
                cv.style.background = "#666";
                cv.id = "artwlfeedback_canvas";
                document.body.appendChild(cv);
                document.body.appendChild(canvas);
                init(callback);
            }
        });
    }

    var init = function(callback){
        var paint={
            init:function(){
                this.addDrawTool();
                this.load();
                this.bind();
            },
            addDrawTool: function(){
                var NewLine = '\n';
                var drawToolHtml = '';
                drawToolHtml+='    <div id="artwlfeedback_operate">'+NewLine;
                drawToolHtml+='        <input id="artwlfeedback_clear" type="button" value=" " title="clear"/>'+NewLine;
                drawToolHtml+='        <input id="artwlfeedback_cancel" type="button" value=" " title="cancel"/>'+NewLine;
                drawToolHtml+='        <input id="artwlfeedback_save" type="button" value=" " title="save as image" />'+NewLine;
                drawToolHtml+='    </div>'+NewLine;
                var drawToolNode = document.createElement("div");
                drawToolNode.id = "artwlfeedback_draw_tool";
                drawToolNode.className = "artwlfeedback";
                drawToolNode.innerHTML = drawToolHtml;
                document.body.appendChild(drawToolNode);
            },
            load:function(){
                this.x=[];//记载鼠标挪动是的X坐标
                this.y=[];//记载鼠标挪动是的Y坐标
                this.clickDrag=[];
                this.Rectangles = [];
                this.lock=false;//鼠标挪动前,判断鼠标是不是按下
                this.storageColor="#000000";
                this.$=function(id){return typeof id=="string"?document.getElementById(id):id;};
                this.canvas=this.$("artwlfeedback_canvas");
                this.pageCanvas = this.$("artwlfeedback_pagecanvas");
                this.cxt=this.canvas.getContext('2d');
                this.cxt.lineJoin = "round";//context.lineJoin - 指定两条线段的连接方式
                this.cxt.lineWidth = 2;//线条的宽度
                this.iptClear=this.$("artwlfeedback_clear");
                this.cancel= this.$("artwlfeedback_cancel");
                this.saveAs = this.$("artwlfeedback_save");
                this.w=this.pageCanvas.width;//取画布的宽
                this.h=this.pageCanvas.height;//取画布的高
                this.touch =("createTouch" in document);//判定是不是为手持设备
                this.StartEvent = this.touch ? "touchstart" : "mousedown";//支持触摸式使用相应的事件替换
                this.MoveEvent = this.touch ? "touchmove" : "mousemove";
                this.EndEvent = this.touch ? "touchend" : "mouseup";
                this.drawTool = this.$("artwlfeedback_draw_tool");
                this.callback = callback;
            },
            bind:function(){
                var t=this;
                /*清除画布*/
                this.iptClear.οnclick=function(){
                    t.clear();
                    t.Rectangles.length = [];
                };
                this.cancel.onclick = function(){
                    t.removeNode(t.pageCanvas);
                    t.removeNode(t.canvas);
                    t.removeNode(t.drawTool);
                };
                /*保存*/
                this.saveAs.onclick = function(){
                    //创建新canvas用于合并pageCanvas和canvas
                    var saveCanvas = document.createElement('canvas');
                    saveCanvas.width = t.w;
                    saveCanvas.height = t.h;

                    var saveCxt = saveCanvas.getContext('2d');
                    saveCxt.fillStyle = "#666";
                    saveCxt.fillRect(0, 0, t.w, t.h);
                    saveCxt.globalAlpha=1;
                    saveCxt.drawImage(t.canvas, 0, 0);
                    saveCxt.globalAlpha=0.5;
                    saveCxt.drawImage(t.pageCanvas, 0, 0);

                    t.removeNode(t.pageCanvas);
                    t.removeNode(t.canvas);
                    t.removeNode(t.drawTool);

                    //输出图片
                    var imgData = saveCanvas.toDataURL("image/png");
                    if(t.callback){
                        callback(imgData);
                    } else {
                        var w=window.open('about:blank','image from canvas');
                        w.document.write("<img src='"+imgData+"' alt='from canvas'/>");
                    }
                };
                /*鼠标按下事件,记载鼠标位置,并绘制,解锁lock,打开mousemove事件*/
                this.canvas['on'+t.StartEvent]=function(e){
                    var touch=t.touch ? e.touches[0] : e;
                    var scrollTop = window.pageYOffset|| document.documentElement.scrollTop || document.body.scrollTop;
                    t.movePoint(touch.clientX - touch.target.offsetLeft,touch.clientY - touch.target.offsetTop + scrollTop);//记载鼠标位置
                    t.lock=true;
                    t.drawTool.style.display = "none";
                };
                /*鼠标挪动事件*/
                this.canvas['on'+t.MoveEvent]=function(e){
                    var touch=t.touch ? e.touches[0] : e;
                    if(t.lock)//t.lock为true则执行
                    {
                        var _x=touch.clientX - touch.target.offsetLeft;//鼠标在画布上的x坐标,以画布左上角为出发点
                        var scrollTop = window.pageYOffset|| document.documentElement.scrollTop || document.body.scrollTop;
                        var _y=touch.clientY - touch.target.offsetTop + scrollTop;//鼠标在画布上的y坐标,以画布左上角为出发点
                        t.movePoint(_x,_y,true);//记载鼠标位置
                        t.drawRectangle();
                    }
                };
                this.canvas['on'+t.EndEvent]=function(e)
                {
                    /*重置数据*/
                    t.lock=false;
                    t.Rectangles.push([t.x[0], t.y[0], t.x[t.x.length -1] - t.x[0], t.y[t.y.length -1] - t.y[0]]);
                    t.x=[];
                    t.y=[];
                    t.clickDrag=[];
                    t.drawTool.style.display = "block";
                };
            },
            movePoint:function(x,y,dragging){
                /*将鼠标坐标添加到各自对应的数组里*/
                this.x.push(x);
                this.y.push(y);
                this.clickDrag.push(y);
            },
            drawRectangle: function(){
                var width = this.x[this.x.length-1] - this.x[0],
                    height = this.y[this.y.length-1] - this.y[0];
                this.clear();
                var i = this.Rectangles.length;
                if(i){
                    for (i=i-1; i >= 0; i--) {
                        var rectangle = this.Rectangles[i],
                            r_x = rectangle[0],
                            r_y = rectangle[1],
                            r_width = rectangle[2],
                            r_height = rectangle[3];
                        this.cxt.strokeRect(r_x, r_y, r_width, r_height); // 只勾画出矩形的外框
                        this.cxt.fillStyle = "#FFFFFF";
                        this.cxt.fillRect(r_x, r_y, r_width, r_height); // 画出矩形并使用颜色填充矩形区域
                    };
                }
                this.cxt.strokeRect(this.x[0], this.y[0], width, height); // 只勾画出矩形的外框
                this.cxt.fillStyle = "#FFFFFF";
                this.cxt.fillRect(this.x[0], this.y[0], width, height); // 画出矩形并使用颜色填充矩形区域
            },
            clear:function(){
                this.cxt.clearRect(0, 0, this.w, this.h);//清除画布,左上角为出发点
            },
            removeNode: function(node){
                node.parentNode.removeChild(node);
            }
        };
        paint.init();
    }

    return {
        load: load
    }
})();

调用

     关于如何调用可参考这里:http://afeedback.duapp.com/

    

范围

     由于html2canvas有跨域制约,所以如果页面用了不同域下的图片(如本文)就不能畸形显示。

     另外,由于html2canvas是根据HTML代码从新渲染成canvas,而有些css没法识别,会形成页面跟canvas上的不完全分歧。

    

改良空间和后续筹划

     目前在不支持canvas的浏览器下没有任何效果,这个可改良为传统方式。

     html2canvas的库比较大,后续会改良为当用户点击反馈链接时进行异步加载。

     当然,大家在体验的过程中如果有什么看法和提议非常欢迎提出,一同完善。

文章结束给大家分享下程序员的一些笑话语录: 真正的程序员喜欢兼卖爆米花,他们利用CPU散发出的热量做爆米花,可以根据米花爆裂的速度听出正在运行什么程序。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值