去年是最忙碌的一年,实在没时间写博客了,看着互联网行业中一个又一个人的倒下,奉劝大家,健康要放在首位,保重身体。
好了,言归正传,这是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; ftop = obj.ftop; 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); },