[GSAP, Canvas] スクロール時の画像モザイクアニメーション
この記事の概要
最近CanvasとWebGLの勉強を始めました。拙いコードですが、お手柔らかに。
まずは完成品をどうぞ。
GSAPのScrollTriggerとCanvasを使って、スクロール時のアニメーション「画像モザイク→モザイクなし」をやってみました。codePenに載せてます。
※実案件ではもっと派手にアニメーションさせてます。
画像や数値をいじったら印象変わるかもです。
掲載許可など取らないとめんどくさそうなのでURLは載せないです。見つけてね。
GSAPのScrollTrigger
Canvasの前にこちらをご覧頂きたい。
ScrollTriggerなんぞや?
アニメーション実装に特化した神ライブラリ"GSAP"、から提供されるプラグインの1つ。
ウィンドウスクロール時のイベントを簡単に設定できます。
自力で実装する場合はIntersection Observer APIとか使ってますが毎案件ほぼ確実に実装することになるのでGSAPで簡潔に実装できて助かってます。ありがとう、GSAP。
GSAP Installation
GSAPには有料機能もありますが、ScrollTriggerは無料で使えます。
自分はWebpackで開発環境組んでるのでnpmを使います。
npmのタブからチェックボックスをぽちぽちやると自動的に読み込み用のコード作ってくれます。
Canvasに描画した画像をモザイク化
canvasを使った画像のモザイク化はこちらの記事を参考にさせて頂きました。
ポイントはCSS 「image-rendering: pixelated;」
ピクセルアート的なガビガビした画像にできます。これをcanvasに設定。
スクロール時に画像サイズを徐々に変更する
スクロール時にcanvasのサイズを変更することでモザイクが徐々に取れていくように見せかけてます。
ScrollTriggerにonEnter関数があるのでこれを使います。
あとは画像サイズを徐々に変化させる処理を走らせるだけ。
ScrollTrigger.create({
trigger,
start: 'top-=50 center',
toggleClass: { targets: '.img-box', className: 'is-animation' },
onEnter: () => {
let blockSizeNum = myPixelatedImg.blockSize
function galleryTick() {
blockSizeNum -= 0.5
myPixelatedImg.update(blockSizeNum)
myReq = requestAnimationFrame(galleryTick)
if (blockSizeNum <= 1) {
// canvasのアニメーションが終わったら画像を表示
trigger.classList.add('is-finished')
cancelAnimationFrame(myReq)
}
}
galleryTick()
},
once: true,
})
モザイクのアニメーションが終わったら画像を表示
if (blockSizeNum <= 1) {
// canvasのアニメーションが終わったら画像を表示
trigger.classList.add('is-finished')
cancelAnimationFrame(myReq)
}
canvasはcssのimage-rendering: pixelated;でガビガビの画像。
これを非表示 → 元画像にすり替え。
「canvasのcssからimage-rendering: pixelated;を削除すればいいんでは?」
と思ったが、高画質な画像ではcanvas描画の画像の解像度が微妙だったため
最終的に元画像を表示させた。
...いい方法ないですか?(小声)
CSSはここ。単純にopacityを0→1にしただけ。
.img-box.is-finished .target-img {
opacity: 1;
}
.img-box.is-finished .target-canvas {
opacity: 0;
}
最後にcancelAnimationFrameでループ処理を停止。
お疲れ様でした。
その他、ウィンドウリサイズの処理など
まさか終わりじゃないですよね?
はい、そうです。。。
// リサイズ
window.onresize = () => {
const blockSizeNum = myPixelatedImg.blockSize
myPixelatedImg.update(blockSizeNum)
}
canvasに描画した画像のレスポンシブ対応。
画像の幅が変わった時にclassに登録しておいた関数を実行。
現在の画像幅でcanvasを再描画。
実際に仕事で使う際はこれに加え、複数インスタンス生成して管理したり、
スライダーの1枚目のみに実装したりでとにかく考えること多かったのですが、今回は実装サンプルとして見せたいのでこんなもので。なんとかいけました。成長💪
感想
やっと実用的なものができた。と感じた。
「CanvasとかWebGL勉強し始めたけど、実務でどうやって活かせばいいんだ?」とお考えの方は多いことでしょう。
いきなりthreee.js使ってバリバリ3Dアニメーションは敷居高すぎるので、今後も実用性高そうなサンプルが出来上がったら投稿していきたいと思います。よしなに🙂
Discussion