[GSAP, Canvas] スクロール時の画像モザイクアニメーション
この記事の概要
最近CanvasとWebGLの勉強を始めました。拙いコードですが、お手柔らかに。
まずは完成品をどうぞ。
GSAPのScrollTriggerとCanvasを使って、スクロール時のアニメーション「画像モザイク→モザイクなし」をやってみました。codePenに載せてます。
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