以前在逛cssdesignawards时发现了1个把照片內容切分的实际效果(网站地址:https://weareludwig.com),大伙儿能够点进去看看,觉得挺酷炫的,因而自身试着完成了1下,实际效果还非常好。实际效果查询https://codepen.io/geeknoble/pen/OQaOVG
剖析
最先大家能够发现照片的內容被分为了1个个小矩形框,并对每一个矩形框开展了任意平移。Canvas的drawImage涵数能够对照片內容开展剪裁并绘图到Canvas画布中,因此该实际效果关键完成基本原理便是应用drawImage。关键实际效果有两个,1个是照片內容的打乱和还原,1个是和下张照片的切换,这两个实际效果都可以以应用drawImage,只是挪动的间距不1样。整体思路有了那末便可以去下手完成1下。
原始工作中
最先大家要原始化1些自变量,例如照片的宽高,矩形框的个数,裁切的规格等,随后再测算每一个矩形框的座标,应用1个2重循环系统将矩形框座标储存在data中。每一个矩形框有个任意位移,这个位移也必须储存起来,存在randoms中。在其中x,y表明canvas画布的座标,x1,y1表明照片剪裁的座标。
init: function (context, width, height, area, img) { this.context = context; this.img = img; this.imgWidth = img[0].width; //照片宽高 this.imgHeight = img[0].height; this.index = 0; //当今照片编号 this.width = width; //画布宽高 this.height = height; this.area = height/12; //小矩形框长度 this.countX = width / this.area; //水平静竖直方位小矩形框个数 this.countY = height / this.area; this.wx = this.imgWidth / this.countX; //照片在小矩形框中的宽高 this.wy = this.imgHeight / this.countY; this.state = true; //照片情况,true表明未拆分 this.dataFlag = true; //小矩形框座标情况,true表明未再加任意值 this.duration = 1000; //动漫時间 this.duration2 = 1500; this.startTime = 0; this.data = []; //小矩形框座标信息内容 this.randoms = []; //部位任意值 //原始化矩形框座标 var x1 = 0, y1 = 0, x = 0, y = 0; for (var i = 0; i < this.countY; i++) { for (var j = 0; j < this.countX; j++) { context.drawImage(this.img[this.index], x1, y1, this.wx, this.wy, x, y, this.area, this.area); //存储矩形框座标 this.data.push({ x1: x1, y1: y1, x: x, y: y }); //加上任意值 this.randoms.push(random(-this.area, this.area)); x1 += this.wx; x += this.area; } x1 = 0; y1 += this.wy; x = 0; y += this.area; } this.checkMargin(); }
检验边沿
在给矩形框加上位移以前大家必须分辨1下位移后的座标是不是超出照片界线,例如在顶部的矩形框假如是y轴挪动,那末只可以向上移,分辨的标准为当今座标再加位移值是不是小于0或超过照片的宽高。假如升级后的座标小于0,那末这个任意值1定是负数,必须把任意值改成正数,假如超过照片高宽比,那末改为负数便可。因为每一个矩形框的挪动全是在1个方位上挪动,因此我这里写成偶多位挪动x轴,单数位挪动y轴。
//检验边沿 checkMargin: function () { var self = this; this.data.forEach(function (item, index) { if (index % 2 == 0) { // 下标为2的倍数时挪动x轴,不然挪动y轴 if ( item.x1 + self.randoms[index] < 0) // 改成正数 self.randoms[index] = -self.randoms[index]; if (item.x1 + self.wx + self.randoms[index] > self.imgWidth ) // 改成负数 self.randoms[index] = -Math.abs(self.randoms[index]) } else { if (item.y1 + self.randoms[index] < 0) self.randoms[index] = -self.randoms[index]; if (item.y1 + self.randoms[index] + self.wy > self.imgHeight) self.randoms[index] = -Math.abs(self.randoms[index]) } }) }
分离出来和还原
动漫的內容的分离出来和还原便是升级矩形框座标的值,打乱內容要是将data里的座标再加任意值,而还原便是减去任意值,
//检验边沿 checkMargin: function () { var self = this; this.data.forEach(function (item, index) { if (index % 2 == 0) { // 下标为2的倍数时挪动x轴,不然挪动y轴 if ( item.x1 + self.randoms[index] < 0) // 改成正数 self.randoms[index] = -self.randoms[index]; if (item.x1 + self.wx + self.randoms[index] > self.imgWidth ) // 改成负数 self.randoms[index] = -Math.abs(self.randoms[index]) } else { if (item.y1 + self.randoms[index] < 0) self.randoms[index] = -self.randoms[index]; if (item.y1 + self.randoms[index] + self.wy > self.imgHeight) self.randoms[index] = -Math.abs(self.randoms[index]) } }) }
在存储好座标后便可以去完成平挪动画了,挪动的全过程有1个光滑的过渡,大家可使用Tween.js的缓动优化算法,该优化算法有4个主要参数各自是当今時间,原始部位,完毕部位,动漫時间。详尽內容能够参照张鑫旭的这篇文章内容https://www.zhangxinxu.com/wordpress/2016/12/how-use-tween-js-animation-easing/ 。根据Tween.js能够算出每帧要挪动的间距,随后再应用requestAnimationFrame去升级座标。
blockAnimation: function () { var flag = 1; if (this.state) { // 分辨是打乱照片還是复原照片 this.update(true) } else { flag = ⑴; this.update(false); } var self = this; this.startTime = +new Date(); // 获得当今時间 this.state = !this.state; (function animation() { var t = +new Date(); if (t >= self.startTime + self.duration) { // 动漫完毕标准 return false; } self.data.forEach(function (item, index) { if (index % 2 == 0) { var pos = Math.tween.Expo.easeInOut(t - self.startTime, 0, self.randoms[index] * flag, self.duration); // 测算出每帧挪动的间距 self.context.drawImage(self.img[self.index], item.x1 + pos, item.y1, self.wx, self.wy, item.x, item.y, self.area, self.area); } else { var pos = Math.tween.Expo.easeInOut(t - self.startTime, 0, self.randoms[index] * flag, self.duration); self.context.drawImage(self.img[self.index], item.x1, item.y1 + pos, self.wx, self.wy, item.x, item.y, self.area, self.area); } }); requestAnimationFrame(animation); })(); }
到这里就早已完成了分离出来和还原的动漫了
照片切换
接下来刚开始解决照片切换的一部分,这里跟轮播图有点像,轮播图动漫是将每一个照片部位挪动可视性对话框宽度的间距,这里也是1样,要是将座标再加照片高宽比便可以完成y轴上的切换。和轮播图不1样的是,大家这里仅有1个canvas标识,在切换时只必须更改当今图和下1张图的座标,当今图挪动间距为y1 + pos,下张图挪动间距为y1 + pos - imgHeight(为何要减imgHeight就无需说了吧)。
//竖直拖动动漫 verticalAnimation: function (val) { if (!this.time2) { return false; } this.checkTime(2); var self = this; val ? val = 1 : val = ⑴; //分辨上滑還是下滑 if ((this.index + val) < 0 || (this.index + val) >= (this.img.length)) { //分辨照片编号是不是究竟 return false; } this.state ? this.update(true) : this.update(false); this.startTime = +new Date(); (function animation() { var t = +new Date(); if (t >= self.startTime + self.duration2) { val === 1 ? self.index++ : self.index--; //调剂照片次序 self.index < 0 ? self.index = self.img.length - 1 : self.index; self.index >= self.img.length ? self.index = 0 : self.index; return false; } self.data.forEach(function (item) { var pos = Math.tween.Cubic.easeInOut(t - self.startTime, 0, (self.imgHeight) * val, self.duration2); // 升级当今照片座标 self.context.drawImage(self.img[self.index], item.x1, item.y1 + pos, self.wx, self.wy, item.x, item.y, self.area, self.area); // 升级下张照片座标 self.context.drawImage(self.img[self.index + val], item.x1, item.y1 + pos - self.imgHeight * val, self.wx, self.wy, item.x, item.y, self.area, self.area); }); requestAnimationFrame(animation); })() }
x轴的切换也是同理,如今全部作用都类似进行了,详细编码能够在codepen里查询。
以上便是本文的所有內容,期待对大伙儿的学习培训有一定的协助,也期待大伙儿多多适用脚本制作之家。