基于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 onmouseout 解决办法
Jul 17 Javascript
js常用代码段收集
Oct 28 Javascript
JQuery遍历json数组的3种方法
Nov 08 Javascript
2014 年最热门的21款JavaScript框架推荐
Dec 25 Javascript
Bootstrap3学习笔记(二)之排版
May 20 Javascript
基于JavaScript实现在新的tab页打开url
Aug 04 Javascript
如何理解jQuery中的ajaxSubmit方法
Mar 13 Javascript
JS判断微信扫码的方法
Aug 07 Javascript
微信小程序中网络请求缓存的解决方法
Dec 29 Javascript
js、jquery实现列表模糊搜索功能过程解析
Mar 27 jQuery
微信小程序完美解决scroll-view高度自适应问题的方法
Aug 08 Javascript
vue-cli3.x配置全局的scss的时候报错问题及解决
Apr 30 Vue.js
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
生成sessionid和随机密码的例子
2006/10/09 PHP
LotusPhp笔记之:Logger组件的使用方法
2013/05/06 PHP
php计算title标题相似比的方法
2015/07/29 PHP
浅谈thinkphp5 instance 的简单实现
2017/07/30 PHP
PHP二维关联数组的遍历方式(实例讲解)
2017/10/18 PHP
pjblog中的UBBCode.js
2007/04/25 Javascript
js取消单选按钮选中并判断对象是否为空
2013/11/14 Javascript
Knockout visible绑定使用方法
2013/11/15 Javascript
js调试系列 控制台命令行API使用方法
2014/06/18 Javascript
JavaScript匿名函数之模仿块级作用域
2015/12/12 Javascript
jQuery EasyUi实战教程之布局篇
2016/01/26 Javascript
jquery实现图片上传前本地预览功能
2016/05/10 Javascript
JS利用cookies设置每隔24小时弹出框
2017/04/20 Javascript
AngularJS 验证码60秒倒计时功能的实现
2017/06/05 Javascript
详解vuejs之v-for列表渲染
2017/06/22 Javascript
Angular实现点击按钮后在上方显示输入内容的方法
2017/12/27 Javascript
vue模块拖拽实现示例代码
2019/03/09 Javascript
[01:04:06]DOTA2上海特级锦标赛A组资格赛#2 Secret VS EHOME第一局
2016/02/26 DOTA
[36:19]2018DOTA2亚洲邀请赛 小组赛 A组加赛 Newbee vs LGD
2018/04/03 DOTA
Python程序中使用SQLAlchemy时出现乱码的解决方案
2015/04/24 Python
Python实现新浪博客备份的方法
2016/04/27 Python
Python代码解决RenderView窗口not found问题
2016/08/28 Python
浅谈pandas中Dataframe的查询方法([], loc, iloc, at, iat, ix)
2018/04/10 Python
win10系统Anaconda和Pycharm的Tensorflow2.0之CPU和GPU版本安装教程
2019/12/03 Python
python爬虫学习笔记之Beautifulsoup模块用法详解
2020/04/09 Python
Html5之svg可缩放矢量图形_动力节点Java学院整理
2017/07/17 HTML / CSS
美赞臣新加坡官方旗舰店:Enfagrow新加坡
2019/05/15 全球购物
最畅销的视频游戏享受高达90%的折扣:CDKeys
2020/02/10 全球购物
两则小学生的自我评价分享
2013/11/14 职场文书
三八妇女节活动总结
2014/05/04 职场文书
实验心得体会
2014/09/05 职场文书
个人查摆剖析材料
2014/10/04 职场文书
2014年教师教学工作总结
2014/11/08 职场文书
解决python3安装pandas出错的问题
2021/05/20 Python
如何使用 resize 实现图片切换预览功能
2021/08/23 HTML / CSS
MySQL into_Mysql中replace与replace into用法案例详解
2021/09/14 MySQL