基于canvas的二维码邀请函生成插件


Posted in Javascript onFebruary 14, 2017

这是17年的第一篇博文,话说这天又是产品同学跑过来问我说:hi,lenny,你看现在市面上流行各种装逼H5,随便输入点名字啥的就给我生成房产证了,这种还可以分享出去,传播率可高了,或者你再看这里,一键生成邀请函,牛逼吧,要不你也帮我做一个这个功能,我去玩点传播手段。

基于canvas的二维码邀请函生成插件

我看见效果后第一反映就是,肯定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, {
 width: 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,
  width: 768,
  height: 1163
 });
 farr.forEach(function(obj) {
  canvasImg.addFont(obj);
 });
 canvasImg.addImg({
  name: 'z',
  x: 0,
  y: 0,
  width: 100,
  height: 100
 });
 canvasImg.addImg({
  name: 'z',
  sx: 0,
  sy: 0,
  sw: 150,
  sh: 150,
  x: 100,
  y: 100,
  width: 100,
  height: 100
 });
 canvasImg.addImg({
  name: 'qr',
  x: 400,
  y: 800,
  width: 200,
  height: 200
 });
 };
 window.onload = buildQr;

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

最后奉上效果截图:

基于canvas的二维码邀请函生成插件

整个demo已经上传至github上了,如果需要做类似需求的同学可以下载该插件,可以节约大家许多时间

资源地址:https://github.com/xfhxbb/LCanvasImg

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
Ext面向对象开发实践(续)
Nov 18 Javascript
Javascript类库的顶层对象名用户体验分析
Oct 24 Javascript
jQuery中removeAttr()方法用法实例
Jan 05 Javascript
jQuery在页面加载时动态修改图片尺寸的方法
Mar 20 Javascript
jQuery提示插件alertify使用指南
Apr 21 Javascript
第一次接触神奇的Bootstrap基础排版
Jul 26 Javascript
JS使用正则表达式过滤多个词语并替换为相同长度星号的方法
Aug 03 Javascript
利用SpringMVC过滤器解决vue跨域请求的问题
Feb 10 Javascript
vuex2中使用mapGetters/mapActions报错的解决方法
Oct 20 Javascript
详解基于webpack&amp;gettext的前端多语言方案
Jan 29 Javascript
推荐几个不错的console调试技巧实现
Dec 20 Javascript
Javascript表单序列化原理及实现代码详解
Oct 30 Javascript
javascript事件的绑定基础实例讲解(34)
Feb 14 #Javascript
javascript深拷贝和浅拷贝详解
Feb 14 #Javascript
javascript事件的传播基础实例讲解(35)
Feb 14 #Javascript
微信小程序中实现一对多发消息详解及实例代码
Feb 14 #Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
Feb 14 #Javascript
js基于myFocus实现轮播图效果
Feb 14 #Javascript
javascript 单例模式详解及简单实例
Feb 14 #Javascript
You might like
杏林同学录(三)
2006/10/09 PHP
PHP上传文件参考配置大文件上传
2015/12/16 PHP
thinkPHP中_initialize方法实例分析
2016/12/05 PHP
用JS操作FRAME中的IFRAME及其内容的实现代码
2008/07/26 Javascript
利用onresize使得div可以随着屏幕大小而自适应的代码
2010/01/15 Javascript
基于jquery的Repeater实现代码
2010/07/17 Javascript
js文件缓存之版本管理详解
2013/07/05 Javascript
利用Jquery实现可多选的下拉框
2014/02/21 Javascript
JavaScript实现的一个日期格式化函数分享
2014/12/06 Javascript
深入理解JavaScript系列(26):设计模式之构造函数模式详解
2015/03/03 Javascript
JavaScript实现的一个倒计时的类
2015/03/12 Javascript
jquery实现标签上移、下移、置顶
2015/04/26 Javascript
JS实现的表格操作类详解(添加,删除,排序,上移,下移)
2015/12/22 Javascript
bootstrap布局中input输入框右侧图标点击功能
2016/05/16 Javascript
javascript经典特效分享 手风琴、轮播图、图片滑动
2016/09/14 Javascript
javascript基本数据类型及类型检测常用方法小结
2016/12/14 Javascript
thinkjs之页面跳转同步异步操作
2017/02/05 Javascript
bootstrap模态框关闭后清除模态框的数据方法
2018/08/10 Javascript
从vue源码解析Vue.set()和this.$set()
2018/08/30 Javascript
Vue CLI3搭建的项目中路径相关问题的解决
2018/09/17 Javascript
vue prop传值类型检验方式
2020/07/30 Javascript
神经网络python源码分享
2017/12/15 Python
Python函数基础实例详解【函数嵌套,命名空间,函数对象,闭包函数等】
2019/03/30 Python
详解Pycharm出现out of memory的终极解决方法
2020/03/03 Python
Python虚拟环境的创建和使用详解
2020/09/07 Python
python 实现性别识别
2020/11/21 Python
使用CSS3设计地图上的雷达定位提示效果
2016/04/05 HTML / CSS
海蓝之谜(LA MER)澳大利亚官方商城:全球高端奢华护肤品牌
2017/10/27 全球购物
新东网科技Java笔试题
2012/07/13 面试题
自我鉴定四大框架
2014/01/17 职场文书
2014年会策划方案
2014/05/11 职场文书
2014幼儿园中班工作总结
2014/11/10 职场文书
烛光里的微笑观后感
2015/06/17 职场文书
MongoDB连接数据库并创建数据等使用方法
2021/11/27 MongoDB
Python内置包对JSON文件数据进行编码和解码
2022/04/12 Python
python实现学员管理系统(面向对象版)
2022/06/05 Python