在去年的时候也实现过合成海报的功能,不过当时时间仓促,实现的比较简单。
就一个旋转功能,图片也不能拖动放大,也不能裁剪。
这次有时间就实现一个功能稍微多点的海报。

第一屏
第二屏
第三屏
总共有三屏,第一屏是选择图片,第二屏是合成图片,第三屏是显示结果图,可保存分享朋友圈。
页面内容不是很多,分析起来也比较简单。
1)每一屏的左右边距相同,上边距各不相同。
2)屏幕内的元素,大部分是居中,有些特殊边距的可用绝对定位,例如第一屏中父亲图与标语图,两张图有重叠部分。
3)第2和3屏中的按钮布局可以用Flex中的两端对齐。
4)4种按钮,可将背景制作成Sprite 图,方便重用。1种弹出框,1种Loading。
5)有3种动画,放大、脉冲以及旋转360°。
6)这次实现的难点是拖动、裁剪和旋转,需要经过逻辑计算高宽、坐标等。
1)Sprite图
在移动端的话,位置就是用百分比来计算。从上面的总览图中可以看到多种按钮背景,有几个就是字不一样,可以重复使用。
2)PrimusUI
有多个模块可以使用,此次就用了三个模块normalize、layout与loading。
3)High DPI Canvas
在demo代码中有一张hidpi.html页面,就是在比较引入此插件后表现的区别,下图是在iphone6中展现的样子。
下面是一段插件中的代码,就是计算devicePixelRatio(设备像素比)与webkitBackingStorePixelRatio(Canvas缓冲区的像素比),做个除法。
然后将Canvas的width和height根据这个比来放大,而CSS中的width和height再缩小回原来的,以此达到1像素的对应。
4)touch.js
5)FileReader
在执行上传插件的“change”中,就是通过此对象获取图片的data:URL。
1)音频控制
为了营造父亲节气氛,特地选了首接地气的歌曲配合页面。
播放器就使用了HTML5标签“audio”。
这里注意下,IOS是禁止自动播放音频的,解决办法就是不要自动播放,或者就是第一次点击页面触发播放。
剩下的就是音频标签绑定播放和停止,在触发的时候添加旋转或脉冲动画。
2)上传图片
上传就是绑定file标签的“change”事件,除了前面说到的用FileReader获取图片的data:URL外,还将原图做了一次压缩。
压缩其实就是将图片放到Canvas中,然后用Canvas输出“jpeg图片”,并且质量是“0.7”,可以将一张800多KB的png图片压缩到50多KB。
还发现一个现象,如果用Canvas输出“png”的data:URL,会比原图还要大。
在“reader.onload”事件中除了压缩图片,还会保存此图的真实际宽度和高度,下面的旋转会用到尺寸,还保存了一条旋转信息的缓存。
3)拖拽、放大、缩小
此功能是需要与上面的touch.js手势库结合。
拖拽使用了CSS3的“translate3d”属性,而放大缩小使用了CSS3的“scale”属性。
原先旋转也想用CSS3的“rotate”属性实现,不过后面实现后,裁剪图片变得非常棘手,不能下手,最后是否决了这个实现方式。
4)旋转
为了解决裁剪的问题,每次旋转都会生成一张新的图片,并将这个图片信息缓存起来。
由于是新的图片,所以就可以直接按照原先的方式来裁剪了,也不用考虑旋转角度的问题。
旋转的逻辑放在“filterImage”中,当时在编写旋转的时候,碰到旋转后的图形变形的问题,后面用图片的实际宽高就解决了变形。
之所以变形是因为宽高用了CSS计算后的值,下图中的两个尺寸就是计算后的值。
下图介绍了操作过程:
为了提升性能,每个方向的图片信息都会被缓存起来。
5)裁剪
比较复杂的一部分,计算图片相对于画框的left和top边距。
而right和bottom与以往的定义不同,这里是高度与宽度分别和top与left相加后的值。
再根据不同逻辑,分别计算画框与图片的X、Y、width和height的值。
最后计算实际图片的宽度与CSS计算后的图片宽度比,将这个值与图片的X、Y、width和height相乘,得出最终值。
这里注意下,在iphone5S中,如果图片的实际高度 < 计算后的高度,就会出现不显示。具体的逻辑在“intersect”方法中。
下图是某一种情况下的各个坐标值:
6)合成
合成其实就是将两张Canvas合并到一起。下面代码中的“drawImage”是自定义的一个方法,最终还是会调用Canvas的“drawImage”。
sx、sy对应的是图片的x、y坐标,而dx、dy对应的是画布的x、y坐标。
demo下载:
<a href="https://github.com/pwstrick/father" target="_blank">https://github.com/pwstrick/father</a>
参考资料:
<a href="https://github.com/jondavidjohn/hidpi-canvas-polyfill" target="_blank">hidpi canvas</a>
<a href="http://touch.code.baidu.com/" target="_blank">touch.js</a>
<a href="http://jiaolonghuang.github.io/2015/11/16/bug-canvas/" target="_blank">一次关于canvas hidpi的2个bug解决过程</a>
<a href="http://www.html5rocks.com/en/tutorials/canvas/hidpi/?redirect_from_locale=zh" target="_blank">High DPI Canvas</a>
<a href="http://www.jianshu.com/p/2cd5143cf9aa" target="_blank">High DPI Canvas中文版</a>
<a href="http://www.straysh.info/article/9" target="_blank">结合HTML5的纯js图片上传</a>
<a href="http://stackoverflow.com/questions/6974684/how-to-send-formdata-objects-with-ajax-requests-in-jquery" target="_blank">how-to-send-formdata-objects-with-ajax-requests-in-jquery</a>
<a href="http://stackoverflow.com/questions/16968945/convert-base64-png-data-to-javascript-file-objects" target="_blank">convert-base64-png-data-to-javascript-file-objects</a>
<a href="http://ca.lagou.com/posters/index?from=singlemessage&isappinstalled=0" target="_blank">那些年,我们曾一起走过</a>
<a href="https://happycoder.net/hidpi-canvas-polyfill/" target="_blank">canvas 在高清屏下绘制图片变模糊的解决方法</a>
本文转自 咖啡机(K.F.J) 博客园博客,原文链接:http://www.cnblogs.com/strick/p/5593166.html,如需转载请自行联系原作者