基于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 相关文章推荐
JavaScript中yield实用简洁实现方式
Jun 12 Javascript
Javascript正则控制文本框只能输入整数或浮点数
Sep 02 Javascript
使用 TypeScript 重新编写的 JavaScript 坦克大战游戏代码
Apr 07 Javascript
JavaScript实现设计模式中的单例模式的一些技巧总结
May 17 Javascript
Node.js+Express配置入门教程
May 19 Javascript
js实现3D图片展示效果
Mar 09 Javascript
Vue2 使用 Echarts 创建图表实例代码
May 18 Javascript
Angular2搜索和重置按钮过场动画
May 24 Javascript
JavaScript创建对象的七种方式全面总结
Aug 21 Javascript
关于Vue源码vm.$watch()内部原理详解
Apr 26 Javascript
详解element-ui设置下拉选择切换必填和非必填
Jun 17 Javascript
详解JS数组方法
Nov 20 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
php UTF-8、Unicode和BOM问题
2010/05/18 PHP
php中怎么搜索相关联数组键值及获取之
2013/10/17 PHP
浅析ThinkPHP的模板输出功能
2014/07/01 PHP
ThinkPHP后台首页index使用frameset时的注意事项分析
2014/08/22 PHP
非常重要的php正则表达式详解
2016/01/04 PHP
常用PHP数组排序函数归纳
2016/08/08 PHP
php注册和登录界面的实现案例(推荐)
2016/10/24 PHP
PHP封装的XML简单操作类完整实例
2017/11/13 PHP
jQuery中的$.ajax()方法应用
2014/05/06 Javascript
一个jquery实现的不错的多行文字图片滚动效果
2014/09/28 Javascript
jQuery获取iframe的document对象的方法
2014/10/10 Javascript
微信小程序 滚动到某个位置添加class效果实现代码
2017/04/19 Javascript
AngularJS路由Ui-router模块用法示例
2017/05/29 Javascript
JS实现加载时锁定HTML页面元素的方法
2017/06/24 Javascript
对angular 监控数据模型变化的事件方法$watch详解
2018/10/09 Javascript
Vue+axios+WebApi+NPOI导出Excel文件实例方法
2019/06/05 Javascript
Element-UI中关于table表格的那些骚操作(小结)
2019/08/15 Javascript
关于layui的动态图标不显示的解决方法
2019/09/04 Javascript
Python实现Tab自动补全和历史命令管理的方法
2015/03/12 Python
一份python入门应该看的学习资料
2018/04/11 Python
Python3的unicode编码转换成中文的问题及解决方案
2019/12/10 Python
基于Tensorflow批量数据的输入实现方式
2020/02/05 Python
Python selenium抓取虎牙短视频代码实例
2020/03/02 Python
python让函数不返回结果的方法
2020/06/22 Python
css3中检验表单的required,focus,valid和invalid样式
2014/02/21 HTML / CSS
全球最大的跑步用品商店:Road Runner Sports
2016/09/11 全球购物
小学教育毕业生自荐信
2013/11/18 职场文书
工厂总经理岗位职责
2014/02/07 职场文书
大学运动会入场词
2014/02/22 职场文书
就业推荐表自我鉴定范文
2014/03/21 职场文书
煤矿班组长竞聘书
2014/03/31 职场文书
专业技术人员年度考核评语
2014/12/31 职场文书
2015公司年度工作总结
2015/05/14 职场文书
2016年“5.12”护士节致辞
2015/07/31 职场文书
导游词之江南园林狮子林
2019/09/16 职场文书
Python可视化动图组件ipyvizzu绘制惊艳的可视化动图
2022/04/21 Python