zoukankan      html  css  js  c++  java
  • 基于canvas的二维码邀请函生成插件

    去年是最忙碌的一年,实在没时间写博客了,看着互联网行业中一个又一个人的倒下,奉劝大家,健康要放在首位,保重身体。
    好了,言归正传,这是17年的第一篇博文,话说这天又是产品同学跑过来问我说:hi,lenny,你看现在市面上流行各种装逼H5,随便输入点名字啥的就给我生成房产证了,这种还可以分享出去,传播率可高了,或者你再看这里,一键生成邀请函,牛逼吧,要不你也帮我做一个这个功能,我去玩点传播手段。

    我看见效果后第一反映就是,肯定canvas进行的图片拼接,现在市面上流行的效果具体是如何实现的我没有去看源码,思路很清晰,于是晚饭后没有下班,开始我的插件制作之旅了。

     首先,我们需要思考,既然是图片处理,那么就必然存在图片下载,我们知道图片的onload是异步回调,所有的资源必须在下载完成后才可以进行接下来的逻辑,前置资源下载的逻辑就很关键,我们不仅需要在onload事件回调后去处理我们后续的流程,同时需要在所有必须资源加载完成后才执行,所以我们需要构建一个资源数组大致如下:

    [{
           {
                name: 'bg',
                src: '../img/bg.jpg'
            }, {
                name: 'z',
                src: '../img/z.png'
            }]

    为了获得最终的complete事件,我们需要利用一个全局变量监听onload或者onerror次数:

                var i = 1;
                arr.forEach(function(obj, index, array) {
                    function onLoad() {
                        _self[obj.name] = img;
                        if (i < array.length) {
                            ++i;
                        } else {
                            console.log('complete');
                        };
                    }
                    var img = new Image();
                    img.onload = onLoad;
                    img.onerror = onLoad;
                    img.src = obj.src;

    好了,资源加载完成事件我们得到了,可以继续下面的逻辑,既然是基于canvas,当然需要创建并初始化我们的canvas,我根据自己的需求,这个功能在我所使用的项目中不论初始化多少次,只会存在一个,所以我做了如下的控制:

    init: function() {
                var LCanvasImg_canvas = document.querySelector('#LCanvasImg_canvas');
                if (LCanvasImg_canvas) {
                    LCanvasImg_canvas.width = this.params.cw;
                    LCanvasImg_canvas.height = this.params.ch;
                    LCanvasImg_canvas.style.display = this.params.display;
                    this.canvas = LCanvasImg_canvas;
                } else {
                    var canvas = document.createElement('canvas');
                    canvas.id = 'LCanvasImg_canvas';
                    canvas.width = this.params.cw;
                    canvas.height = this.params.ch;
                    canvas.style.display = this.params.display;
                    document.body.appendChild(canvas);
                    this.canvas = canvas;
                }
                this.clear();
            },

    canvas创建好了,接下来我们需要实现图片渲染的能力,canvas的图片渲染使用的是drawImage方法,根据官方文档,该方法有3种传参方式:

    JavaScript 语法 1
    在画布上定位图像:
    context.drawImage(img,x,y);
    JavaScript 语法 2
    在画布上定位图像,并规定图像的宽度和高度:
    context.drawImage(img,x,y,width,height);
    JavaScript 语法 3
    剪切图像,并在画布上定位被剪切的部分:
    context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

    于是,我们也充分的判断好我们调用的drawImage参数:

    addImg: function(obj, callback) {
                var _self = this;
                var canvas = _self.canvas;
                var ctx = canvas.getContext("2d");
                if (obj.hasOwnProperty('sx') && obj.hasOwnProperty('sy') && obj.hasOwnProperty('sw') && obj.hasOwnProperty('sh') && obj.hasOwnProperty('x') && obj.hasOwnProperty('y') && obj.hasOwnProperty('width') && obj.hasOwnProperty('height')) {
                    ctx.drawImage(_self[obj.name], obj.sx, obj.sy, obj.sw, obj.sh, obj.x, obj.y, obj.width, obj.height);
                } else if (obj.hasOwnProperty('x') && obj.hasOwnProperty('y') && obj.hasOwnProperty('width') && obj.hasOwnProperty('height')) {
                    ctx.drawImage(_self[obj.name], obj.x, obj.y, obj.width, obj.height);
                } else if (obj.hasOwnProperty('x') && obj.hasOwnProperty('y')) {
                    ctx.drawImage(_self[obj.name], obj.x, obj.y);
                } else {
                    ctx.drawImage(_self[obj.name], 0, 0);
                }
                _self.showImg();
            },

    接下来我们需要开发文字生成的能力,这个比较简单,如果对canvas相关api熟悉点的,这部分没有难度:

    addFont: function(obj) {
                var _self = this;
                var canvas = _self.canvas;
                var ctx = canvas.getContext("2d");
                ctx.font = obj.fontsize + "px " + obj.fontfamily; //文字的字体大小和字体系列
                var ftop = obj.ftop; //文字top
                var fleft = obj.fleft; //文字left
                ctx.textBaseline = "top"; //设置绘制文本时的文本基线。
                ctx.fillText(obj.txt, fleft, ftop);
                ctx.lineWidth = 1;
                ctx.fillStyle = "#000";
                ctx.strokeStyle = "rgba(255,255,255,0.4)";
                ctx.strokeText(obj.txt, fleft, ftop);
            },

    最后一步是二维码的生成,这个有点坑,自己开发肯定来不及了,我选用的是一个开源插件:qrcode,根据这个插件,我们可以在一个img中动态生成二维码的base64字串,而有了这个字串,我们也很方便的将内容输出到我们的canvas中,为了保证体验,这个插件的最外层div直接display:none,避免它干扰到我们的实际项目。

    <div id="qrcode" style="display: none;"></div>
    /**
         * 
         * 初始化二维码生成插件
         * 
         */
        var qrdata = '';
        var myqr = document.querySelector('#myqr');
        var qrcode = document.querySelector('#qrcode');
        var qr = new QRCode(qrcode, {
             300,
            height: 300,
            colorDark: "#000000",
            colorLight: "#ffffff",
            correctLevel: QRCode.CorrectLevel.L
        });

    由于这个img是动态变化的,我们获取base64字串的时候一定要在该img的onload事件的回调内去获取,这点非常重要:

    function buildQr () {
        var img = qrcode.querySelector('img');
        img.onload = function() {
            qrdata = img.src;
            main();
        };
        qr.makeCode(myqr.value);
        }

    ok,准备工作都完成了,接下来我们需要开始初始化我们的插件了,我预先埋下了很多可配置的参数:

    var canvasImg = null;
    
        function main() {
            //初始化
            canvasImg = new LCanvasImg({
                cw: 768,//canvas width
                ch: 1163,//canvas height
                iw: '100%',//output img width
                ih: 'auto',//output img height
                display:'none'//canvas display
            });
            //资源加载
            canvasImg.load([{
                name: 'qr',
                src: qrdata
            }, {
                name: 'bg',
                src: '../img/bg.jpg'
            }, {
                name: 'z',
                src: '../img/z.png'
            }], build);
        };

    看见上面的build变量了吗?我们将图片生成逻辑全部写在这个build方法中,在load资源complete后,会执行build;

    function build() {
            var farr = [{
                txt: document.querySelector('#mytxt1').value,
                fontsize: 26,
                fontfamily: 'fzjt',
                ftop: 140,
                fleft: 194
            }, {
                txt: '胡鑫',
                fontsize: 26,
                fontfamily: 'fzjt',
                ftop: 220,
                fleft: 394
            }, {
                txt: '邓逸昕',
                fontsize: 26,
                fontfamily: 'fzjt',
                ftop: 220,
                fleft: 294
            }, {
                txt: document.querySelector('#mytxt1').value,
                fontsize: 26,
                fontfamily: 'fzjt',
                ftop: 220,
                fleft: 194
            }];
            canvasImg.addImg({
                name: 'bg',
                x: 0,
                y: 0,
                 768,
                height: 1163
            });
            farr.forEach(function(obj) {
                canvasImg.addFont(obj);
            });
            canvasImg.addImg({
                name: 'z',
                x: 0,
                y: 0,
                 100,
                height: 100
            });
            canvasImg.addImg({
                name: 'z',
                sx: 0,
                sy: 0,
                sw: 150,
                sh: 150,
                x: 100,
                y: 100,
                 100,
                height: 100
            });
            canvasImg.addImg({
                name: 'qr',
                x: 400,
                y: 800,
                 200,
                height: 200
            });
        };
        window.onload = buildQr;

    最后一句话非常重要,为什么这里我需要用window.onload事件,如果你使用的是webfont,当webfont下载成功后,其实还有一小段时间需要将font字体载入进浏览器中,只有在window.onload事件时,webfont字体文件才能生效。
    最后奉上效果截图:

    整个demo已经上传至github上了,如果需要做类似需求的同学可以下载该插件,可以节约大家许多时间
    资源地址:https://github.com/xfhxbb/LCanvasImg

  • 相关阅读:
    hao947 : Mybatis resultMap配置插入和主键自增返回 : 好947
    VelocityTracker简单介绍
    Java中StringBuilder的清空方法比較
    jquery中的动画
    数据库索引的作用和长处缺点
    很具体GC学习笔记
    深入理解 JBoss 7/WildFly Standalone 模式启动过程
    curl命令具体解释
    【免费】iPhone上最好用的短信群发软件: 高速短信4.1
    Project interpreter not specified(eclipse+pydev)
  • 原文地址:https://www.cnblogs.com/xfhxbb/p/LCanvasImg.html
Copyright © 2011-2022 走看看