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];//把图片转base64var 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) {//获取canvasvar 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){//遍历textAllfor(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是一个非常值得学习的知识,也是很有趣的一个知识。期待与大家有更多的交流和学习!



-------------------------华丽的分割线--------------------
想了解更多,关注关注我的微信公众号:守候书阁



更多专业前端知识,请上 【猿2048】www.mk2048.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache ActiveMQ 5.9发布

Apache ActiveMQ团队刚刚发布了新的ActiveMQ 5.9版本 。 Apache ActiveMQ 5.9发布 自从先前的5.8版本以来&#xff0c;此版本是8个月的辛苦工作。 在此发行版中&#xff0c;我们将像往常一样对代理进行增强&#xff0c;并使用最新的协议&#xff08;例如AMQP和MQTT&#xff…

android 美颜录像,Android 关于美颜/滤镜 利用PBO从OpenGL录制视频

前言上次我写了一遍文章《Android 关于美颜/滤镜 从OpenGl录制视频的一种方案》&#xff0c;里面利用ImageReader来从获取Surface上获取数据&#xff0c;但是经过熊皮皮的提醒&#xff0c;我发现多PBO的确可以实现跟ImageReader一样的效果&#xff0c;并且版本要求仅为Android4…

Java对象到对象映射器

我在该项目上使用了Dozer一段时间。 但是&#xff0c;最近我遇到了一个非常有趣的错误&#xff0c;它促使我环顾四周&#xff0c;并尝试使用其他“对象到对象”映射器。 这是我找到的工具列表&#xff1a; 推土机&#xff1a;推土机是Java Bean到Java Bean的映射器&#xff…

android媒体播放框架,Android 使用超简单的多媒体播放器JiaoZiVideoPlayer

在之前的项目中用到了视频播放的功能&#xff0c;在网上看了看使用了大家用的比较多的一个开源项目JiaoZiVideo可以迅速的实现视频播放的相关功能。JiaoZiVideo的简单使用集成了JiaoZiVideo后仅需这几行代码就可以实现播放视频JZVideoPlayerStandard jzVideoPlayerStandard (J…

送福利:ROKID 语音开发板免费送,开启你的物联网之旅

都让一让&#xff0c;我说个事情&#xff1a;掘金联合 Rokid 开发者社区给大家发福利啦&#xff01; 掘金联合 Rokid 开发者社区为大家准备了一些福利&#xff0c;只要秀出你的 skill 和技术栈&#xff0c;就有可能获得 Rokid 全栈语音智能开发套件。 ? Rokid开箱试用活动 活…

如何使用JavaScript控制台改进工作流程

作为Web开发人员&#xff0c;很有必要了解如何调试代码。后台开发我们经常使用外部库来记录日志&#xff0c;并在某些情况下格式化显示日志&#xff0c;前端我们会使用断点和控制台&#xff0c;但是我们浏览器的控制台比我们想象的要强大得多。 当我们考虑控制台时&#xff0c…

select、poll、epoll之间的区别总结[整理]

原文:https://www.cnblogs.com/Anker/p/3265058.html 好文章收藏下&#xff0c;慢慢品味 select&#xff0c;poll&#xff0c;epoll都是IO多路复用的机制。I/O多路复用就通过一种机制&#xff0c;可以监视多个描述符&#xff0c;一旦某个描述符就绪&#xff08;一般是读就绪或者…

JPA(七):映射关联关系------映射双向多对一的关联关系

映射双向多对一的关联关系 修改Customer.java package com.dx.jpa.singlemanytoone;import java.util.Date; import java.util.HashSet; import java.util.Set;import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; impo…

如何优雅的绘制一棵省市区三级可选择的树?

开始 总结一下 开发过程中的思路想法 各位大佬们看看就好 首先你拥有的数据结构 所有省市区的信息列表 以及已经选中的信息 用的是element-ui的 el-tree const cityStorage {provinceList:[{id: 1, provinceId: "110000", name: "北京市"}],//所有省ci…

html click事件 参数,vue 实现click同时传入事件对象和自定义参数

这篇文章主要介绍了vue 实现click同时传入事件对象和自定义参数&#xff0c;具有很好的参考价值&#xff0c;希望对大家有所帮助。一起跟随小编过来看看吧仅仅传入自定义参数HTMLdddddJS代码new Vue({el:#app,methods:{tm:function(e){console.log(e);}}})仅仅传入事件对象HTML…

Android学习(七)—— Android布局

Android布局 1、LinearLayout 线性布局&#xff0c;这种布局在平时的开发中用的最多&#xff0c;内部控件只能水平或竖直进行排列&#xff0c;在搭建较复杂的界面时会有点麻烦。 常用属性 android:orientation 控制控件排列方向&#xff0c;属性值为垂直&#xff08;vertical…

不一样的ZTree,权限树.js插件

每一个有趣的创新&#xff0c;都源于苦逼的生活。在最近的工作中&#xff0c;遇到一个做权限管理筛选的需求。 简单总结需求&#xff1a; 1展示一个组织中的组织结构 2通过点击组织结构中的任意一个节点可以向上向下查询对应的组织结构 如果你不想苦逼的重复劳动&#xff0c;还…

JavaFX 2:如何加载图像

这是有关如何在JavaFX 2应用程序中加载图像的JavaFX教程。 使用ImageView可以轻松完成此操作。 ImageView是一个节点&#xff0c;用于绘制加载有Image类的图像。 因此&#xff0c;您将首先使用Image类加载图像&#xff0c;然后使用ImageView显示它。 我还将在这里演示如何从本地…

记HTML5 a 标签的一个小坑

今天写了段简单的代码&#xff0c;点击<a>标签时却抛出了这个错误&#xff1a;Uncaught TypeError: download is not a function。代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><…

C#线程 ---- 线程同步详解

线程同步 说明&#xff1a;接上一篇&#xff0c;注意分享线程同步的必要性和线程同步的方法。 测试代码下载&#xff1a;https://github.com/EkeSu/C-Thread-synchronization-C-.git 一、什么是线程同步&#xff1a; 在同一时间只允许一个线程访问资源的情况称为线程同步。 二、…

响应式方案调研及前端开发管理思考

网易首页响应式风格实现技术调研网易首页实现页面&#xff08;字体&#xff09;响应式风格的方式是在不同尺寸的视口中使用不同的容器类&#xff0c;如图 1所示。当视口大于等于1420px时&#xff0c;使用大尺寸容器类 &#xff08;index2017_1200_wrap&#xff0c;width: 1200p…

linux nexus启动_Linux一键部署Nexus 3私服仓库自动化部署脚本

此脚本是Linux一键部署Nexus 3私服仓库自动化脚本&#xff0c;有需要朋友可以参考&#xff0c;脚本内容如下&#xff1a;环境准备&#xff1a;操作系统&#xff1a;CentOS Linux release 7.8.2003软件版本&#xff1a;Docker&#xff1a;docker-ce-19.03.12[rootlocalhost ~]# …

flex.css快速入门,极速布局

什么是flex.css? css3 flex 布局相信很多人已经听说过甚至已经在开发中使用过它&#xff0c;但是我想我们都会有一个共同的经历&#xff0c;面对它的各种版本&#xff0c;各种坑&#xff0c;傻傻的分不清楚&#xff0c;flex.css就是对flex布局的一种封装&#xff0c;通过简洁…

优化Angularjs的$watch方法

Angularjs的$watch相信大家都知道&#xff0c;而且也经常使用&#xff0c;甚至&#xff0c;你还在为它的某些行为感到恼火。比如&#xff0c;一进入页面&#xff0c;它就会调用一次&#xff0c;我明明希望它在我初始化之后&#xff0c;值再次变动才调用。这种行为给我们带来许多…

JavaFX中的塔防(2)

在上一部分中&#xff0c;我们创建了一个简单的编辑器&#xff0c;让我们放置炮塔。 现在&#xff0c;我们将在敌人起源的地方添加一个生成点&#xff0c;并为其定义攻击目标。 首先&#xff0c;我将通过对象层向地图添加更多信息。 这是标准的TMX&#xff0c;因此我们可以在Ti…