canvas入门实战--邀请卡生成与下载
1.前言
写了很多的javascript和css3的文章,是时候写一篇canvas的了。canvas是html5提供的一个新的功能!至于作用,就是一个画布。然后画笔就是javascript。canvas的用途非常的广,特别是html5游戏以及数据可视化这两个方面。现在canvas给我的感觉就和css3一样,可以不用太厉害,但是必须要会基础的用法。但是以后对canvas的需求,肯定会越来越大。所以canvas很值得学习,而且学好canvas,就是很好的一个加分项。对于这篇文章,我也是以canvas初学者的角度写的,会有很多改善的地方。如果大家觉得我有什么可以改善的,或者建议,欢迎指点迷津!代码已上传github,需要的欢迎star(downloadImg)。
大家看这篇文章之前,要了解javascript的一些基础,也要看着了解一些canvas的api(canvas-MSN教程,canvas菜鸟教程)
2.邀请卡实例
邀请卡自动生成这个会有的,毕竟有时候,很多邀请卡都是一样的,就是被邀请的人不一样而已,也就是说,整个邀请卡,就是一个名字不一样,那么下面。就写一套代码,根据名字生成邀请卡!
2-1.运行效果
html代码
<html> <head> <meta charset="utf-8"> <title>下载图片</title> <style> .set-option { float: left; width: 400px; } .set-option .text { width: 200px; height: 40px; padding-left: 10px; border-radius: 4px; border: 1px solid #ccc; } .set-option td { padding: 10px 0; } .set-option td:first-child { text-align: right; padding-right: 10px; } .set-option p { margin: 0; line-height: 16px; } .check-box { width: 16px; height: 16px; margin: 0; vertical-align: top; } button { width: 200px; height: 50px; border: none; color: #fff; font-size: 16px; cursor: pointer; display: block; margin: 10px auto; } button:hover { opacity: .9; } .btn-all { background: #f90; } .btn-save { background: #09f; } .btn-download { background: #4CAF50; } </style> </head> <body> <div> <div class="set-option"> <table> <tr> <td>画布尺寸</td> <td><input type="text" class="text" id="size"/></td> </tr> <tr> <td>背景图片</td> <td><input type="file" id="file"/></td> </tr> <tr> <td>用户名</td> <td> <input type="text" class="text" id="user-name"/> </td> </tr> <tr> <td>用户名x坐标</td> <td> <input type="number" class="text" id="text-option-x"/></br> <p><input type="checkbox" class="check-box" value="1" id="is-center-x">居中显示</p> </td> </tr> <tr> <td>用户名y坐标</td> <td> <input type="number" class="text" id="text-option-y"/></br> <p><input type="checkbox" class="check-box" value="1" id="is-center-y">居中显示</p> </td> </tr> <tr> <td>用户名字体大小</td> <td><input type="number" class="text" id="text-size"/></td> </tr> <tr> <td>文字颜色</td> <td><input type="text" class="text" id="text-color"/></td> </tr> <tr> <td>图片类型</td> <td> <select type="text" class="text" id="img-type"> <option value="jpg">jpg</option> <option value="png">png</option> </select> </td> </tr> </table> <button id="save-image" class="btn-save">效果预览</button> <button id="download-img" class="btn-download">下载当前图片</button> <button id="download-all" class="btn-all">批量导出</button> </div> <div class="show-canvas"> <canvas width=200 height=200 id="thecanvas"></canvas> </div> </div> </body> </html>
效果如图,那么大家细想一下,关于一张邀请卡,有什么东西是需要改变的!看到上图相比不难发现!有如下需要改变的属性:图片的大小,图片,用户名,用户名的坐标(x,y,x轴是否居中,y轴是否居中),用户名字体的大小,用户名字体的颜色,以及下载图片的类型。
这样就得到了如下的参数(大家看到有些参数是有值的,可以想成默认值就行了)
var option = { img: '111.jpg', width: 500, height: 350, fontSize: "20px Microsoft YaHei", color: "black", text: '守候', imgType: 'jpg', x: 30, y: 30, xCenter: false, yCenter: false, };
2-2.步骤
1.初步效果
根据上面的参数,先初步画一个效果,代码基本都是一个写法,没什么技巧
//画图 function draw(obj) { var canvas = document.getElementById("thecanvas"); //画布大小 canvas.width = obj.width; canvas.height = obj.height; //设置图片 var img = new Image(); img.src = obj.img; var ctx = canvas.getContext("2d"); //设置字体的坐标 var _x = obj.x, _y = obj.y; //是否居中显示 if (obj.xCenter) { _x = obj.width / 2; } if (obj.yCenter) { _y = obj.height / 2; } //图片加载后 img.onload = function () { //先画图片 ctx.drawImage(img, 0, 0); //设置文字的大小 ctx.font = obj.fontSize; //设置文字的颜色 ctx.fillStyle = obj.color; //设置文字坐标 if (obj.xCenter) { ctx.textAlign = "center"; } //画文字 ctx.fillText(obj.text, _x, _y); }; } window.onload = function () { draw(option); }
2.动态改变参数
看到图已经画好了,工作其实已经完成一半了!
下面就是动态改变参数!这一步其实很简单。
首先,改变画布的尺寸
//画布尺寸 //获取按钮 var size = document.getElementById("size"); size.addEventListener("blur", function () { //根据空格,区分高宽 var _width = parseInt(size.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/)[0]), _height = parseInt(size.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/)[1]); //把参数的width和height改掉 option.width = _width || 100; option.height = _height || 100; //重新画图 draw(option); });
上面代码设置了,只要输入框失去了焦点,就会改变画布的大小,下面来运行下,看下效果(gif图差强人意,大家看懂就好)
canvas没有层级的说法,只要改canvas,都要重绘。哪怕就是一个字移动一个像素。
做好了这个,下面做选择图片的功能!
//选择图片 //获取图片控件 var file = document.getElementById("file"), imagesFile, imageData; file.addEventListener('change', function (e) { //获取图片 imagesFile = e.target.files[0]; //把图片转base64 var reader = new FileReader(); reader.readAsDataURL(imagesFile); //图片加载后 reader.onload = function (e) { //设置option的img属性,再冲洗年绘制 imageData = this.result; option.img = imageData; draw(option); } });
下面开始改文字,用户名这个有点不一样,我以空格分割。如果输入多个用户名,以第一个用户名重绘。下面代码,注释就不写了,还是和上面的逻辑一样!
//用户名 var userName = document.getElementById("user-name"); userName.addEventListener("blur", function () { var _text = userName.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/); option.text = _text[0]; draw(option); });
下面开始用户名的坐标,代码方面,也是改option的相关属性
optionXCenter.addEventListener("change", function () { if (optionXCenter.checked) { option.xCenter = true; } else { option.xCenter = false; option.x = parseInt(optionX.value); } draw(option); }); //纵坐标 var optionY = document.getElementById("text-option-y"); optionY.value = option.y; var optionYCenter = document.getElementById("is-center-y"); optionY.addEventListener("input", function () { if (optionYCenter.checked) { option.yCenter = true; } else { option.yCenter = false; option.y = parseInt(optionY.value); } draw(option); }); //是否垂直居中显示 optionYCenter.addEventListener("change", function () { if (optionYCenter.checked) { option.yCenter = true; } else { option.yCenter = false; option.y = parseInt(optionY.value); } draw(option); });
是否水平居中显示
其他的属性,字体大小和颜色,基本是一样的代码,运行的效果图我不放了!
//字体颜色 var textColor = document.getElementById("text-color"); textColor.addEventListener("blur", function () { textColor.value === "" ? option.color = "#fff" : option.color = '#' + textColor.value; draw(option); }); //字体大小 var textSize = document.getElementById("text-size"); textSize.addEventListener("input", function () { textSize.value === "" ? option.fontSize = '20px Microsoft YaHei' : option.fontSize = textSize.value + 'px Microsoft YaHei'; draw(option); });
3.按钮操作
效果预览
就是预览当前canvas的一个效果,这个就很简单了,就是新开一个窗口,然后把图片写进去而已
//预览图片 function saveImageInfo() { var mycanvas = document.getElementById("thecanvas"); //生成图片 var image = mycanvas.toDataURL("image/png"); var w = window.open('about:blank', 'image from canvas'); //把图片新进新的窗口 w.document.write("<img src='" + image + "' alt='from canvas'/>"); } var saveButton = document.getElementById("save-image"); saveButton.addEventListener('click', saveImageInfo);
下载当前图片
下载图片这个,基本也是写法的,都是些记忆的东西
//图片类型 var imgType = document.getElementById("img-type"); imgType.addEventListener("change",function () { option.imgType=this.value; }); //下载图片 function downloadImg(fileName) { //获取canvas var myCanvas = document.getElementById("thecanvas"); //设置图片类型 var image = myCanvas.toDataURL("image/" + option.imgType).replace("image/" + option.imgType, "image/octet-stream"); var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); save_link.href = image; //设置下载图片的名称 save_link.download = fileName + '.' + option.imgType; //下载图片 var event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); save_link.dispatchEvent(event); }
批量下载图片
这个复杂一点,但也不难,下面一步一步来!
1.首先批量导出,那么用户名我这里是使用空格分割,那么现在我在option里面,弄一个字段textAll,所有文字的集合。all代表是否是批量下载。fn属性代表回调函数
//批量导出 var downloadAll = document.getElementById("download-all"); downloadAll.addEventListener('click', function () { var _text = userName.value.replace(/(^\s*)|(\s*$)/g, "").split(/\s+/); option.textAll = _text; option.all = true; option.fn = downloadImg; draw(option); });
2.然后修改绘制的函数draw,判断是否是全部绘制的情况!
function draw(obj) { var canvas = document.getElementById("thecanvas"); //画布大小 canvas.width = obj.width; canvas.height = obj.height; //设置图片 var img = new Image(); img.src = obj.img; var ctx = canvas.getContext("2d"); //设置字体的坐标 var _x = obj.x, _y = obj.y; //是否居中显示 if (obj.xCenter) { _x = obj.width / 2; } if (obj.yCenter) { _y = obj.height / 2; } //图片加载后 img.onload = function () { //是否是全部打印 if(obj.all){ //遍历textAll for(var i=0;i<obj.textAll.length;i++){ //绘制图片 ctx.drawImage(img,0,0); //设置字体大小 ctx.font=obj.fontSize; //设置字体颜色 ctx.fillStyle=obj.color; //是否居中显示 if(obj.xCenter){ ctx.textAlign="center"; } //绘制文字 ctx.fillText(obj.textAll[i], _x,_y); //是否回调 if(obj.fn){ obj.fn(obj.textAll[i]); } } //最后取消全部批量下载 defult.all=false; } else{ ctx.drawImage(img,0,0); ctx.font=obj.fontSize; ctx.fillStyle=obj.color; if(obj.xCenter){ ctx.textAlign="center"; } ctx.fillText(obj.text, _x,_y); } }; }
3.小结
关于canvas入门的第一篇文章,就写到这里了。写完之后,也发现自己对canvas的也是有很多的不懂!上文的这例子,知识canvas很简单的一个入门实例。canvas如果深入学习,能做到很多让人惊讶的效果,这个得以后要加强学习,如果发现些值得记录的知识,我也会写文章。canvas是一个非常值得学习的知识,也是很有趣的一个知识。期待与大家有更多的交流和学习!
-------------------------华丽的分割线--------------------
想了解更多,关注关注我的微信公众号:守候书阁