用H5中的Canvas等技术制作海报
myzbx 2025-01-11 15:35 34 浏览
在去年的时候也实现过合成海报的功能,不过当时时间仓促,实现的比较简单。
就一个旋转功能,图片也不能拖动放大,也不能裁剪。
这次有时间就实现一个功能稍微多点的海报。
一、概要
总共有三屏,第一屏是选择图片,第二屏是合成图片,第三屏是显示结果图,可保存分享朋友圈。
页面内容不是很多,分析起来也比较简单。
1)每一屏的左右边距相同,上边距各不相同。
2)屏幕内的元素,大部分是居中,有些特殊边距的可用绝对定位,例如第一屏中父亲图与标语图,两张图有重叠部分。
3)第2和3屏中的按钮布局可以用Flex中的两端对齐。
4)4种按钮,可将背景制作成Sprite 图,方便重用。1种弹出框,1种Loading。
5)有3种动画,放大、脉冲以及旋转360°。
6)这次实现的难点是拖动、裁剪和旋转,需要经过逻辑计算高宽、坐标等。
二、涉及的知识点
1)Sprite图
移动端的Sprite图在前面一篇《一张H5游戏页引起的思考》曾重点介绍过。
在移动端的话,位置就是用百分比来计算。从上面的总览图中可以看到多种按钮背景,有几个就是字不一样,可以重复使用。
2)PrimusUI
PrimusUI是前面一段时间整理的一个微型UI库,为了提升开发效率,提取公用模块而制作的。
有多个模块可以使用,此次就用了三个模块normalize、layout与loading。
具体内容可以参考前面一段时间写的一篇介绍文《小身材大用途,用PrimusUI驾驭你的页面》。
3)High DPI Canvas
引入High DPI Canvas,是为了解决在高清屏的设备中,绘制在 canvas 中的图形(包括文字)都会出现模糊的问题。
在demo代码中有一张hidpi.html页面,就是在比较引入此插件后表现的区别,下图是在iphone6中展现的样子。
可以看到原生的比较模糊,而引入了插件后就变的清晰了。原理就是让Canvas中的1个像素等于屏幕中的1个物理像素,关于屏幕的概念可以参考《移动开发屏幕适配分析》
下面是一段插件中的代码,就是计算devicePixelRatio(设备像素比)与webkitBackingStorePixelRatio(Canvas缓冲区的像素比),做个除法。
然后将Canvas的width和height根据这个比来放大,而CSS中的width和height再缩小回原来的,以此达到1像素的对应。
backingStore = context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1; ratio = (window.devicePixelRatio || 1) / backingStore; if (ratio > 1) { this.style.height = this.height + 'px'; this.style.width = this.width + 'px'; this.width *= ratio; this.height *= ratio; }
4)touch.js
touch.js是个开源的手势库,第二屏中的拖动和捏(双指放大缩小)就是通过这个库实现的。
touch.on(touchPad, 'drag', function(ev) { //拖动逻辑 }); touch.on(touchPad, 'pinch', function(ev) { //捏的逻辑 });
5)FileReader
使用FileReader对象,web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可以使用File对象或者Blob对象来指定所要处理的文件或数据。
在执行上传插件的“change”中,就是通过此对象获取图片的data:URL。
var file = $(this)[0].files[0]; var reader = new FileReader; reader.readAsDataURL(file); // 将文件以Data URL形式进行读入页面 reader.onload = function { var base64 = this.result; };
三、实现
1)音频控制
为了营造父亲节气氛,特地选了首接地气的歌曲配合页面。
播放器就使用了HTML5标签“audio”。
<audio id="audio" src="music.mp3" type="audio/mpeg"></audio>
这里注意下,IOS是禁止自动播放音频的,解决办法就是不要自动播放,或者就是第一次点击页面触发播放。
剩下的就是音频标签绑定播放和停止,在触发的时候添加旋转或脉冲动画。
$audio.on("play", function { isAudioLoaded = true; $music.addClass('music-rotate').removeClass('music-pulse'); }).on("pause", function { $music.removeClass('music-rotate').addClass('music-pulse'); });
2)上传图片
上传就是绑定file标签的“change”事件,除了前面说到的用FileReader获取图片的data:URL外,还将原图做了一次压缩。
压缩其实就是将图片放到Canvas中,然后用Canvas输出“jpeg图片”,并且质量是“0.7”,可以将一张800多KB的png图片压缩到50多KB。
还发现一个现象,如果用Canvas输出“png”的data:URL,会比原图还要大。
在“reader.onload”事件中除了压缩图片,还会保存此图的真实际宽度和高度,下面的旋转会用到尺寸,还保存了一条旋转信息的缓存。
var img = new Image; img.onload = function { var src = poster.filterImage(img, this.width, this.height); //将图片进行压缩,减少页面大小 $frameImg.data('width', this.width); //实际宽度 $frameImg.data('height', this.height); //实际高度 var realImg = new Image; realImg.onload = function { $frameImg.attr('src', realImg.src); //第三次载入Base64数据 }; realImg.src = src; rotates[0] = { src: src, width: this.width, height: this.height, image: realImg }; //用于旋转的缓存 }; img.src = base64;
3)拖拽、放大、缩小
此功能是需要与上面的touch.js手势库结合。
拖拽使用了CSS3的“translate3d”属性,而放大缩小使用了CSS3的“scale”属性。
function formatTransform(offx, offy, scale) { var translate = 'translate3d(' + (offx + 'px,') + (offy + 'px,') + '0)'; scale = 'scale(' + scale + ')'; //var rotate = 'rotate('+deg+'deg)'; return translate + ' ' + scale; }
原先旋转也想用CSS3的“rotate”属性实现,不过后面实现后,裁剪图片变得非常棘手,不能下手,最后是否决了这个实现方式。
4)旋转
为了解决裁剪的问题,每次旋转都会生成一张新的图片,并将这个图片信息缓存起来。
由于是新的图片,所以就可以直接按照原先的方式来裁剪了,也不用考虑旋转角度的问题。
旋转的逻辑放在“filterImage”中,当时在编写旋转的时候,碰到旋转后的图形变形的问题,后面用图片的实际宽高就解决了变形。
之所以变形是因为宽高用了CSS计算后的值,下图中的两个尺寸就是计算后的值。
旋转的代码就两行,rotate中“deg”就是旋转角度,这里是90。
ctx.rotate(deg * Math.PI / 180); ctx.drawImage(image, 0, -canvas.width);
下图介绍了操作过程:
为了提升性能,每个方向的图片信息都会被缓存起来。
rotates[direction] = {src:src, width:this.width, height:this.height, image:realImg};//缓存
5)裁剪
比较复杂的一部分,计算图片相对于画框的left和top边距。
而right和bottom与以往的定义不同,这里是高度与宽度分别和top与left相加后的值。
再根据不同逻辑,分别计算画框与图片的X、Y、width和height的值。
最后计算实际图片的宽度与CSS计算后的图片宽度比,将这个值与图片的X、Y、width和height相乘,得出最终值。
这里注意下,在iphone5S中,如果图片的实际高度 < 计算后的高度,就会出现不显示。具体的逻辑在“intersect”方法中。
下图是某一种情况下的各个坐标值:
intersect: function($frame, $img) { var imgX = 0,imgY = 0,imgW = 0,imgH = 0; var frmX = 0,frmY = 0; var imgOffset, frmOffset, left, right, top, bottom; imgOffset = $img.offset; //图片的偏移对象 frmOffset = $frame.offset; //画框的偏移对象 left = imgOffset.left - frmOffset.left - 3; //图片到边框左边的距离 去除3px的边框 right = left + imgOffset.width; //画框模型是border-box,所以图片宽度需要减去边框的宽度 就是574 top = imgOffset.top - frmOffset.top - 3; //图片到边框上边的距离 bottom = top + imgOffset.height; //图片在画框内 if (!(right <= 0 || left >= frmOffset.width || bottom <= 0 || top >= frmOffset.height)) { if (left < 0) { imgX = -left; frmX = 0; imgW = (right < frmOffset.width) ? right : frmOffset.width; } else { imgX = 0; frmX = left; imgW = (right < frmOffset.width ? right : frmOffset.width) - left; } if (top < 0) { imgY = -top; frmY = 0; imgH = (bottom < frmOffset.height) ? bottom : frmOffset.height; } else { imgY = 0; frmY = top; imgH = ((bottom < frmOffset.height) ? bottom : frmOffset.height) - top; } } var ratio = $img.data('width') / $img.width; //图片真实宽度 与 图片CSS宽度 //图片的实际高度不能低于计算后的高度 否则iphone 5S中就不显示 var imageHeight = imgH * ratio; if (+$img.data('height') < imageHeight) { imageHeight = $img.data('height'); } return { frame: {x: frmX,y: frmY,w: (imgW + 6),h: (imgH + 6)}, //此处画框是574,而画布是580 image: {x: imgX * ratio,y: imgY * ratio,w: imgW * ratio,h: imageHeight} }; }
6)合成
合成其实就是将两张Canvas合并到一起。下面代码中的“drawImage”是自定义的一个方法,最终还是会调用Canvas的“drawImage”。
poster.drawImage(ctx, rotates[direction].image, poster.intersect($frame, $frameImg)); poster.drawImage(ctx, $word, poster.intersect($frame, $word));
Canvas的“drawImage”方法有多种参数组合。第三组有9个参数, 一开始还不是理解这几个参数的含义,后面去查了一下。
sx、sy对应的是图片的x、y坐标,而dx、dy对应的是画布的x、y坐标。
demo下载:
- 上一篇:前端【Canvas】基础教程示例集锦
- 下一篇:Canvas学习笔记 | 文本操作
相关推荐
- 别让水 “跑” 出卫生间!下沉设计打造滴水不漏的家
-
你是否遭遇过卫生间的水“偷偷溜”进客厅,导致木地板鼓起、墙角发霉的糟心事?又是否为卫生间门口反复渗漏,不得不一次次返工维修而头疼不已?在家庭装修中,卫生间防水堪称“兵家必争之地”,而卫生间门口下...
- 歼-10CE vs 阵风:谁才是空中霸主?全面性能对比解析
-
歼10CE与法国阵风战斗机性能深度对比分析一、总体定位与设计哲学歼10CE:单发中型多用途战斗机,侧重于空优(制空权争夺)和对地对海打击,具有较高的性价比和较强的多任务能力。法国阵风战斗机:双发中型多...
- 知名移植工作室肯定Switch2的图形性能,却被CPU拖了后腿
-
虽然Switch2发售多日,但没入手的玩家对其性能还是有顾虑。近日,知名移植工作室Virtuos的技术总监在接受采访时讨论了Switch2的性能,并给出了他们工作室的评价。简单来说,Switch2在D...
- 虹科实测 | CAN XL vs CAN FD传输性能深度对比:速率翻倍,抖动锐减!
-
导读在汽车电子与工业通信领域,CAN协议持续进化,推动着数据传输效率的提升。本次实测基于虹科PCAN-USBXL与虹科PCAN-USBProFD硬件,在同等严苛条件下对比CANXL与CANF...
- 1J117合金材料优异的耐腐蚀性、机械性能
-
1J117合金材料概述定义:1J117是一种不锈软磁精密合金,属于铁铬基合金,其圆棒产品具有特定的形状和尺寸,可满足各种工业应用中的特定需求。标准:技术条件标准为GB/T14986,品种规格标准...
- 据高管所称,Switch2能轻松移植XSS平台60帧游戏
-
任天堂,作为主机游戏界的御三家之一,一直注重游戏性而不注重更新升级硬件设备是其最大的特点。各位任豚们,忍受着任天堂早已落后硬件设备,真想感叹一句,天下苦任久矣!但Switch2的出现或许正在渐渐的改变...
- FJK-110LED-HXJSN磁传感器有哪应用
-
作为一名从事电子技术相关工作的自媒体人,我经常会遇到各种传感器的应用问题。其中,FJK-110LED-HXJSN磁传感器是一款在工业自动化、智能设备等领域比较常见的磁场检测元件。今天我想和大家聊一聊这...
- 浅谈欧标方管200x200x5-12mm质S275JRH的优势与劣势
-
欧标方管200x200x5-12mm材质S275JRH是一种常见的结构用钢材,广泛应用于建筑、机械制造、桥梁、钢结构等领域。本文将对这种方管的优势与劣势进行浅谈,以帮助读者更好地了解其特性和适用场景。...
- 宽带拨号错误 651 全解析:故障定位与修复方案
-
在使用PPPoE拨号连接互联网时,错误651提示「调制解调器或其他连接设备报告错误」,通常表明从用户终端到运营商机房的链路中存在异常。以下从硬件、系统、网络三层维度展开排查:一、故障成因分类图...
- 模型微调:从理论到实践的深度解析
-
在人工智能领域,模型微调已成为提升模型性能、使其适应特定任务的关键技术。本文将全面系统地介绍模型微调的各个方面,帮助读者深入理解这一重要技术。一、什么是模型微调模型微调是指在已经训练好的预训练模型基础...
- 汉语拼音 z、c、s图文讲解(拼音字母表zcs教学视频)
-
以下是汉语拼音z、c、s的图文讲解,结合发音要领、书写规范及教学技巧:一、发音方法与口诀1.z的发音发音要领:舌尖轻抵上齿背,形成阻碍后稍放松,气流从窄缝中挤出,声带不振动(轻短音)。口诀:“写字写...
- 吴姗儒惹怒刘宇宁粉丝!吴宗宪护航「是综艺梗」叮咛女儿对话曝光
-
记者孟育民/台北报道Sandy吴姗儒在《小姐不熙娣》因为节目效果,将男星刘宇宁的头像踩在地上,引起粉丝怒火,节目发声明道歉后仍未平息,她也亲自发文郑重道歉:「我对刘宇宁本人完全没有任何恶意,却在综艺表...
- 苹果错误地发布了macOS Tahoe公开测试版 现已将其撤下
-
一些Beta测试人员下载了他们以为是macOSSequoia15.6RC的版本,但却错误地下载了macOSTahoe26公开测试版,后来苹果修复了该问题。苹果预计将于7月25...
- make的多种用法!(make 的用法总结)
-
一、make的用法美make[meik]①V.制造;制定,拟定;使变得,使处于;造成,引起;整理(床铺);做,作出;强迫;挑选,任命…②n.(机器、设备等的)品牌,型号;结构,构造;通电,接电⑤[...
- 北顿尖刀哗变?俄第20近卫集团军损失惨重,拒绝执行指挥官命令?
-
【军武次位面】作者:太白近日,外国社交媒体“电报”上传出了一些消息,称俄罗斯在北顿涅兹克战场上的“尖刀”部队之一,俄第20近卫集团军因为损失惨重,已经出现了部分部队拒绝执行指挥官命令,甚至哗变的情况。...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)
- JS Loop For (32)