When I was browsing CSSDesignAwards, I found an effect that splits the image content (website: https://weareludwig.com). You can click on it to have a look. It felt very cool, so I tried to implement it myself, and the effect was pretty good. . Check the effect https://codepen.io/geeknoble/pen/OQaOVG
analyzeFirst, we can find that the content of the picture is divided into small rectangles, and each rectangle is randomly translated. The drawImage function of Canvas can crop the image content and draw it into the Canvas canvas, so the main implementation principle of this effect is to use drawImage. There are two main effects, one is to disrupt and restore the picture content, and the other is to switch to the next picture. DrawImage can be used for both effects, but the moving distance is different. Once you have the general idea, you can start implementing it.
initial workFirst we need to initialize some variables, such as the width and height of the picture, the number of rectangles, the cutting size, etc., then calculate the coordinates of each rectangle, and use a double loop to save the rectangle coordinates in data. Each rectangle has a random displacement. This displacement also needs to be saved and stored in randoms. Among them, x and y represent the coordinates of the canvas canvas, and x1 and y1 represent the coordinates of the image cropping.
init: function (context, width, height, area, img) { this.context = context; this.img = img; this.imgWidth = img[0].width; //Picture width and height this.imgHeight = img[0 ].height; this.index = 0; //Current picture number this.width = width; //Canvas width and height this.height = height; this.area = height/12; //The length of the small rectangle this.countX = width / this.area; //The number of small rectangles in the horizontal and vertical directions this.countY = height / this.area; this.wx = this.imgWidth / this.countX; //Picture Width and height in the small rectangle this.wy = this.imgHeight / this.countY; this.state = true; //Picture status, true means not split this.dataFlag = true; //Small rectangle coordinate state, true means No random value this.duration is added = 1000; //Animation time this.duration2 = 1500; this.startTime = 0; this.data = []; //Small rectangle coordinate information this.randoms = []; //Position random value//Initialize rectangle coordinates 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); //Storage rectangular coordinates this.data.push({ x1: x1, y1: y1, x: x, y: y }); //Add random values 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(); }Detect edges
Before adding a displacement to the rectangle, we need to determine whether the displaced coordinates exceed the limit of the picture. For example, if the rectangle at the top moves on the y-axis, it can only move upward. The judgment condition is whether the current coordinate plus the displacement value is less than 0 or Larger than the width and height of the image. If the updated coordinates are less than 0, then the random value must be a negative number. You need to change the random value to a positive number. If it is greater than the height of the picture, then change it to a negative number. Since each rectangle moves in one direction, I write here that the even-numbered bits move the x-axis and the odd-numbered bits move the y-axis.
//Detect edge checkMargin: function () { var self = this; this.data.forEach(function (item, index) { if (index % 2 == 0) { // Move the x-axis when the index is a multiple of 2 , otherwise move the y-axis if (item.x1 + self.randoms[index] < 0) // Change to a positive number self.randoms[index] = -self.randoms[index]; if (item.x1 + self.wx + self.randoms[index] > self.imgWidth ) // Change to negative number 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]) } }) }separation and recovery
The separation and restoration of the animation content is to update the value of the rectangular coordinates. To disrupt the content, just add random values to the coordinates in the data, and restoration is to subtract the random values.
//Detect edge checkMargin: function () { var self = this; this.data.forEach(function (item, index) { if (index % 2 == 0) { // Move the x-axis when the index is a multiple of 2 , otherwise move the y-axis if (item.x1 + self.randoms[index] < 0) // Change to a positive number self.randoms[index] = -self.randoms[index]; if (item.x1 + self.wx + self.randoms[index] > self.imgWidth ) // Change to negative number 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]) } }) }
After storing the coordinates, you can implement the translation animation. The movement process has a smooth transition. We can use the easing algorithm of Tween.js. This algorithm has 4 parameters: the current time, the initial position, and the end position. animation time. For details, please refer to Zhang Xinxu’s article https://www.zhangxinxu.com/wordpress/2016/12/how-use-tween-js-animation-easing/. Tween.js can be used to calculate the distance to move in each frame, and then use requestAnimationFrame to update the coordinates.
blockAnimation: function () { var flag = 1; if (this.state) { // Determine whether to disrupt the image or restore the image this.update(true) } else { flag = -1; this.update(false); } var self = this; this.startTime = +new Date(); // Get the current time this.state = !this.state; (function animation() { var t = +new Date(); if (t >= self.startTime + self.duration) { // Animation end condition 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); // Calculate the distance moved in each frame 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); })(); }
At this point, the animation of separation and restoration has been implemented.
Picture switchingNext, we start processing the image switching part. This is a bit like the carousel image. The carousel image animation moves the position of each image by the width of the visual window. The same is true here. Just add the coordinates to the image height to achieve y Switching on axis. Different from the carousel picture, we only have one canvas tag here. When switching, we only need to change the coordinates of the current picture and the next picture. The moving distance of the current picture is y1 + pos, and the moving distance of the next picture is y1 + pos. - imgHeight (it goes without saying why imgHeight should be reduced).
//Vertical sliding animation verticalAnimation: function (val) { if (!this.time2) { return false; } this.checkTime(2); var self = this; val ? val = 1 : val = -1; //Judgement Slide up or down if ((this.index + val) < 0 || (this.index + val) >= (this.img.length)) { // Determine whether the picture serial number is the end 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--; //Adjust the order of pictures 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); // Update the current image coordinates self.context.drawImage(self.img[self.index], item.x1, item.y1 + pos, self.wx, self.wy, item.x, item.y, self.area, self.area); // Update the coordinates of the next image 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); })() }
The same goes for switching the x-axis. Now all functions are almost completed. The complete code can be viewed in the codepen.
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.