CSSDesignAwards を見ていたら、画像コンテンツを分割するエフェクトを見つけました (Web サイト: https://weareludwig.com)。とてもクールだったので、自分でも実装してみました。効果はかなり良かったです。効果を確認 https://codepen.io/geeknoble/pen/OQaOVG
分析するまず、画像の内容が小さな四角形に分割されており、各四角形がランダムに変換されていることがわかります。 Canvas のdrawImage 関数は、画像コンテンツを切り取って Canvas キャンバスに描画できるため、この効果の主な実装原則は、drawImage を使用することです。主な効果は 2 つあり、1 つは画像の内容を中断して復元するもの、もう 1 つは次の画像に切り替えるものです。DrawImage はどちらの効果にも使用できますが、移動距離が異なります。全体的なアイデアを理解したら、実装を開始できます。
初期の作品まず、画像の幅と高さ、四角形の数、切断サイズなどのいくつかの変数を初期化する必要があります。次に、各四角形の座標を計算し、二重ループを使用して四角形の座標をデータに保存します。 。各長方形にはランダムな変位があり、この変位もランダムに保存して保存する必要があります。このうち、x、yはcanvasキャンバスの座標を表し、x1、y1は画像のトリミングの座標を表します。
init: function (context, width, height, area, img) { this.context = context; this.imgWidth = img[0].width; //画像の幅と高さ this.imgHeight = img[ 0 ].height; this.index = 0; //現在の画像番号 this.width = width; //キャンバスの幅と高さ this.area = height; //小さな長方形の長さ this.countX = width / this.area; //水平方向と垂直方向の小さな長方形の数 this.countY = height / this.area; this.wx = this.imgWidth / this; .countX; //小さな四角形の画像の幅と高さ this.wy = this.imgHeight / this.state = true; //画像のステータス、true は分割されていないことを意味します。座標状態、true はランダムな値 this.duration が追加されないことを意味します= 1000; //アニメーション時間 this.duration2 = 0; this.data = []; //小さな四角形の座標情報 this.randoms = []; //四角形の座標を初期化します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; } x1 = 0; wy; x = 0; } this.checkMargin();エッジの検出
長方形に変位を加える前に、変位した座標が画像の限界を超えるかどうかを判断する必要があります。たとえば、上部の長方形が y 軸上で移動する場合、上方向にしか移動できないかどうかが判断条件となります。現在の座標とディスプレイスメント値の合計が 0 未満であるか、イメージの幅と高さよりも大きいです。更新された座標が 0 より小さい場合、乱数値は負の数値である必要があります。乱数値が画像の高さより大きい場合は、負の数値に変更する必要があります。各四角形は一方向に移動するため、ここでは偶数ビットが x 軸を移動し、奇数ビットが y 軸を移動すると書きます。
//エッジの検出 checkMargin: function () { var self = this; this.data.forEach(function (item,index) { if (index % 2 == 0) { // インデックスが a の場合、x 軸を移動します2 の倍数、それ以外の場合は y 軸を移動します if (item.x1 + self.randoms[index] < 0) // 正の数に変更します self.randoms[index] = -self.randoms[index]; .x1 + self.wx + self.randoms[index] > self.imgWidth ) // 負の数に変更 self.randoms[index] = -Math.abs(self.randoms[index]) } else { if (item.y1 + self .randoms[インデックス] < 0) self.randoms[インデックス] = -self.randoms[インデックス]; if (item.y1 + self.randoms[インデックス] + self.wy > self.imgHeight) self.randoms[インデックス] = -Math.abs(self.randoms[インデックス]) } }) }分離と回収
アニメーションコンテンツの分離と復元は、直交座標の値を更新することであり、コンテンツを破壊するには、データ内の座標にランダムな値を加算するだけであり、復元はランダムな値を減算することです。
//エッジの検出 checkMargin: function () { var self = this; this.data.forEach(function (item,index) { if (index % 2 == 0) { // インデックスが a の場合、x 軸を移動します2 の倍数、それ以外の場合は y 軸を移動します if (item.x1 + self.randoms[index] < 0) // 正の数に変更します self.randoms[index] = -self.randoms[index]; .x1 + self.wx + self.randoms[index] > self.imgWidth ) // 負の数に変更 self.randoms[index] = -Math.abs(self.randoms[index]) } else { if (item.y1 + self .randoms[インデックス] < 0) self.randoms[インデックス] = -self.randoms[インデックス]; if (item.y1 + self.randoms[インデックス] + self.wy > self.imgHeight) self.randoms[インデックス] = -Math.abs(self.randoms[インデックス]) } }) }
座標を保存した後、移動プロセスは Tween.js のイージング アルゴリズムを使用して実行できます。このアルゴリズムには、現在時刻、初期位置、終了位置の 4 つのパラメーターがあります。アニメーションの時間。詳細については、Zhang Xinxu の記事 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 = -1; ; } var self = this; this.startTime = +new Date() // 現在時刻を取得します this.state = !this.state (function anime() { var t = +new Date(); >= 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);リクエストアニメーションフレーム(アニメーション);
この時点で、分離と復元のアニメーションが実装されています。
映像切り替え次に、画像の切り替え部分の処理を開始します。これは、カルーセル画像のアニメーションと少し似ています。ここでも、画像に座標を追加するだけです。達成する高さ y 軸をオンにします。カルーセル画像とは異なり、ここでは Canvas タグが 1 つだけあり、切り替えるときは現在の画像と次の画像の座標を変更するだけで済みます。現在の画像の移動距離は y1 + pos です。次の図は y1 + pos. - imgHeight (imgHeight を減らす必要がある理由は言うまでもありません)。
//垂直スライドアニメーションverticalAnimation: function (val) { if (!this.time2) { return false; } var self = 1 : val = -1;上下にスライド if ((this.index + val) < 0 || (this.index + val) >= (this.img.length)) { // 画像のシリアル番号が終了かどうかを判断します return false }この状態? this.update(true) : this.update(false); this.startTime = +new Date(); (関数 anime() { var t = +new Date(); if (t >= self.startTime + self) .duration2) { val === 1 ? self.index++ : self.index--; // 画像の順序を調整します self.index < 0 ? self.img.length - 1 : self.index .index >= self.img.length ? self.index = 0 : self.index; } 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);リクエストアニメーションフレーム(アニメーション);
X 軸の切り替えについても同様です。これですべての機能がほぼ完成し、コードペンで完全なコードを確認できるようになりました。
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。