前言:抽空学习了网易一年一度的娱乐行业图传h5的技术实现。有些点比较难理解,所以做个笔记。如果正好对你有帮助,首先我们可以看一下这个h5。视觉上,它从一幅画逐渐变小,然后出现另一幅画。特殊之处在于当前的画是下一幅画中的那幅。一张小图,一部分。所以称他为画中画。思路过程:第一眼看到这个效果的时候,我的想法是一开始把所有的画都放大n倍,然后当小图的尺寸刚好是屏幕的宽高的时候,就是我们的初始放大,然后把倍数慢慢缩小到1。但是这样面临各种问题,1.无法准确计算倍数。2.图片缩小时,很难计算出图片应该在什么位置。3.画面很模糊。后来想如果用小图的大图覆盖一下就可以达到这个效果了。这个方法感觉很奇怪,扯淡。然后...笨蛋,太年轻太简单我开始找它的源码然后我们找到了它控制台的源码,如下://Mainmethodwindow.WeixinJSBridge&&e.play()//处理下的音乐微信浏览器播放initCanvas//初始化画布preload//加载图片init//初始化场景showend//整个动画结束的回调函数touchEvent//触摸事件,控制动画执行draw//关键方法,让himdrawdrawImgOversize//关键方法,让他画一部分,这个后面会解释drawImgMinisize//关键方法,让他画整体,这个会解释drawImage//关键方法,canvas的native方法先放撇开整个过程中gif动画的实现不说。然后主要是画画。看到drawImage这个方法,666。所以理解了这个方法之后,我们需要换一种思路。用这个实现效果的方法不是放大缩小,而是对图片的canvas进行处理,选中图片的一部分,然后放在canvas上。这个圈出来了,考试还得考,呸。..也就是说,做这件事需要ui父母的帮助。你需要知道每张图片的大小,图片中小图片的位置和大小。然后,他们已经让我们准备好了。说了一大堆废话,我们正式开始实施分析。我们可以看到这张图片并没有自适应屏幕,而是已经设置了一个预定的尺寸,750x1206,所以我们的设计稿是iPhone6的两倍。除了封面为750x1206外,所有原始图像均为1875x3015。所以距离下方的长按按钮底部还有一点距离。目前网易还没有适应iphonex的情况。他边画边画,怎么边画边缩?这个时候就要看源码里的这些东西了this.radiothis.scale=.985,this.scaleSlow=.995一开始我什至以为这些参数可有可无...首先,在方法触发的时候touchstart,有这个requestAnimationFrame就是传说中的每秒执行60次的machoapi。在requestAnimationFrame中不断执行draw会继续绘制,然后我们用一个变量radio一直递减,然后影响drawImage的参数,说不定可以实现!(这里的关系后面会讲到)那为什么scale是0.985呢?0.211可以吗?985多少钱?我加倍为211...有这样一个计算公式,我们需要radio从1开始递减,然后乘以一个小数this.radio=this.radio*this.scale//如果这个计算每秒执行60次,那么this.radio会变小this.radio=this.radio*this.scale^60所以这个scale是一个缩小频率,频率是每秒60次,所以如果是0.985,大概是3、4秒。this.radio将变为0.0。尽量满足areaW/imgw),这是最小缩放值,不管多小,图像都要缩小。this.scaleSlow=.995会慢一些,因为我们注意到当图片快收缩的时候,会慢一些,因为图片边上的文字已经露了出来,让用户看得很清楚。所以limitMax和limitMin就是用来做这个的,什么时候应该减速收缩。当然,这里的数值是用网易的计算器算出来的,粗略算了一下,雪薇有点腥。那么源码中有这些方法吗(省略判断...)?i.radio=i.scaleSlow*i.radio:i.radio=i.scale*i.radio,if(省略判断){//ifthis.radio<=areaW/imgW那么就该换图了。this.index++,this.radio=1}然后,我们需要为每个场景绘制两张图片。为什么我们需要两张图片?只要再画一张完整的图覆盖这个区域,就可以了。嗯?清晰和模糊的图像难以理解。你自己想想吧。请参阅此处的说明https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/drawImage。智商又夺回了制高点//比如分析前两张图,我们先画两张图,剩下的再说。.走两步,没问题,skr[{link:"http://static.ws.126.net/f2e/ent/ent_painting2016/images/1.jpg?1520",//①imgW:"750",imgH:"1206"},{链接:"http://static.ws.126.net/f2e/ent/ent_painting2016/images/2.jpg?1520",//②imgW:"1875",imgH:"3015",areaW:"375",areaH:"603",areaL:"1379",areaT:"103",limitMax:.3,limitMin:.2}]然后画两张图,再次关注这个方法drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight)//drawImage(①,...)//drawImage(②,...)绘制封面图,封面图,长按后,是From全面屏到小屏,他总是很清晰,就叫他清晰图吧。它应该完全显示在屏幕上。sx、sy、sWidth、sHeight很简单。drawImage(①,0,0,1875,3015,dx,dy,dWidth,dHeight)他画在屏幕上的位置和大小应该是多少。一开始当然是整个设置区。即最小的drawImage(①,0,0,1875,3015,0,0,750,1260)有多小?这是设计稿说了算。我们可以看到②中的四个属性,areaW,areaH,areaL,areaT,描述的是小画在画中的大小和位置,所以最小的是这样drawImage(①,0,0,1875,3015,areaL,areaT,areaW,areaH)但是在缩小的过程中,最后四个参数发生了什么变化,我们需要计算的是最后四个参数drawImage(①,0,0,1875,3015,距离左边的距离屏幕的边,到屏幕顶部的距离,当前图像的宽度,当前图像的高度)同理,另一个图像呢。绘制下一幅图,长按后由模糊变清晰,故称模糊图。他应该选择区域的一部分显示在屏幕上。那个区域是什么?明明是缩小版的,怎么就模糊了?选择这么小的区域并将其填充到整个设置的屏幕区域,而不会模糊地狱。模糊也无所谓,直接拿上面那个清晰的,把它完全盖住,就完美了。那么,一开始怎么画呢?只需取一部分并完全填满设定的屏幕区域。drawImage(②,开始选择图片的位置x,开始选择图片的位置y,图片选择的宽度,图片选择的高度,0,0,750,1260)最后好了,如何绘制?对于整张图片来说,完全填满设置的屏幕区域就够了drawImage(②,0,0,1875,3015,0,0,750,1260)所以我们需要计算的是前四个参数drawImage(②,thedistancetotheleftsideofthescreenSidedistance,distancetothetopofthescreen,当前图片宽度,当前图片高度,0,0,720,1260)所以,现在有问题了,不知道是不是同学们明白我的意思了,因为即使没有,我也得继续讲下去。剩下的计算题涉及到几何数学、物理、生物、定律、离散、线性规划、高斯模糊……首先我们来计算一下,drawImgOversize就是drawImage(②,离屏幕左边的距离,离屏幕顶部的距离thescreen,currentimagewidth,currentimageheight,0,0,720,1260)我们记离屏幕左边的距离为Sx,图中是哪个?数字。对于某一时刻,HG(③)=areaW/this.radio的宽度我们可以得到一个公式://①=areaL,AB=imgW,LK=areaW,②=①-?>①/(AB-LK)=②/(HG-LK)>①/(AB-LK)=②/(HG-LK)===》①/(AB-LK)=(①-?)/(HG-LK)最后距离屏幕左侧的距离:areaL-areaL/(imgW-areaW)*(areaW/this.radio-areaW)//类似距离屏幕顶部的距离:areaT-areaT/(imgH-areaH)*(areaH/this.radio-areaH)//当前图片宽度:areaW/this.radio//当前图片高度:areaH/this.radio那么同理:对于drawImgMinisize,在某个时刻HG=750*this.radiothis._drawImgOverSize(this.containerImage,imgNext.imgW,imgNext.imgH,imgNext.areaW,imgNext.areaH,imgNext.areaL,imgNext.areaT,this.radio,)的最终完整计算值这个。,ih,aw,ah,al,at,r){this.ctx.drawImage(i,al-(aw/r-aw)*(al/(iw-aw)),在-(ah/r-ah)*(at/(ih-ah)),aw/r,ah/r,0,0,750,1206,);}_drawImgMinSize(i,ciw,cih,iw,ih,aw,ah,al,at,r){this.ctx.drawImage(i,0,0,ciw,cih,750*(1-r)*(al/(iw-aw)),//和下面的是相同的值//((ah/r-ah)*(at/(ih-ah))*r*1206)/ah,//网易认为公式太复杂1206*(1-r)*(at/(ih-ah)),750*r,1206*r,);}ok,就这些了....github地址在线预览demogithub
