Lottieを使って簡単なアニメーションを実装してみる

# はじめに
最近Lottieに触れる機会があったので学んだことを備忘も兼ねてまとめてみます。
この記事ではLottieを使用して簡単なアニメーションを実装するところまでのお話をします。

# Lottieとは
Lottieはベクターアニメーションのファイル形式でJSONベースのフォーマットでつくられます。
拡張子は`.json`、`.lottie`になります。
ファイルの中身はアニメーションにまつわるさまざまなデータがはいっています。
After EffectsやFigma 、その他のツールでアニメーションを作成したあとLottieに書き出してファイルを作成することができます。

今回はAfter Effectsで作成したLottie（拡張子は.json）を元に紹介していきます。
実装までの流れのイメージはこちらです👇
![実装手順.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064849/48329127-6543-07be-6c25-8215c45a3641.png)


## After EffectsでLottieを作る
下記の手順で作成できます。
1. [ZXPInstaller](https://aescripts.com/learn/zxp-installer/)をインストール
    （Bodymovin拡張機能をインストールするために必要なインストーラーです）
2. [Bodymovin拡張機能](https://exchange.adobe.com/apps/cc/12557/bodymovin)をインストール
3. After Effectsでアニメーションの作成
4. Bodymovinを使用してエクスポート（ここでjsonファイルができます）
5. [Lottieプレビューページ](https://app.lottiefiles.com/preview)で正しく再生されるか確認

できあがり！

ただ注意点として、**Lottieは、After Effectsのすべての機能をサポートしているわけではない**ということがあります。
アニメーション作成の際は[公式のサポートされている機能の表](https://airbnb.io/lottie/#/supported-features)や、[Lottieプレビューページ](https://app.lottiefiles.com/preview)などを確認しながら進めるとよいです。

参考：
https://zenn.dev/getgotgoto/articles/7db64306a93193

# 実装
今回はフリー素材をお借りしてjsonファイルを入手しています。
Lottieフリー素材： https://lottiefiles.com/featured

## 導入
CDNで読み込む方法とインストールする方法がありますが今回はCDNで進めていきます。
```.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js"></script>
<script src="/js/lottie.js" defer></script> // 自前で用意したJSファイル
```

## デモ01: シンプルなLottieアニメーション
```.html
<div class="lottie-obj js-lottie01"></div>
```
```.js
  lottie.loadAnimation({
    container: document.querySelector(".js-lottie01"),
    renderer: "svg",
    loop: true,
    autoplay: true,
    path: "/img/lottie/christmas.json", // lottieファイルを置いているパス
  });
```
![demo01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064849/17cab29c-afc1-fa63-9cea-0529d640144c.gif)



## デモ02: 押したら再生
```.html
<div class="lottie-obj js-lottie02"></div>
```
```.js
  const target02 = document.querySelector(".js-lottie02");
  const anime02 = lottie.loadAnimation({
    container: target02,
    renderer: "svg",
    loop: false,
    autoplay: false,
    path: "/img/lottie/christmas.json",
  });
  target02.addEventListener("click", () => {
    anime02.play();
  });
```
![demo02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064849/b1ce5fe5-c613-1e02-dbc3-9972bcc4ae03.gif)

## デモ03: スクロールすると再生
```.html
<div class="lottie-obj js-lottie03"></div>
```
```.js
  const target03 = document.querySelector(".js-lottie03");
  const anime03 = lottie.loadAnimation({
    container: target03,
    renderer: "svg",
    loop: false,
    autoplay: false,
    path: "/img/lottie/christmas.json",
  });

  window.addEventListener("load", function () {
    ScrollTrigger.create({
      trigger: target03,
      start: "center center",
      markers: true, // 検証用マーカー
      onEnter: () => {
        anime03.play();
      },
    });
  });
```
![demo03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064849/5e71ebf8-d7de-50a0-69d3-b742a8c978ea.gif)

## デモ04: スクロール量と連動する
```.html
<div class="lottie-obj js-lottie04"></div>
```
```.js
  const target04 = document.querySelector(".js-lottie04");
  const anime04 = lottie.loadAnimation({
    container: target04,
    renderer: "svg",
    loop: false,
    autoplay: false,
    path: "/img/lottie/christmas.json",
  });

  window.addEventListener("load", function () {
    ScrollTrigger.create({
      trigger: target04,
      start: "top center",
      end: "bottom center",
      markers: true, // 検証用マーカー
      scrub: true,
      onUpdate: (self) => {
        const progress = self.progress;
        anime04.goToAndStop(anime04.totalFrames * progress, true);
      },
    });
  });
```
![demo04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064849/15c69de4-1591-cd7f-78a7-156cd0b3091c.gif)

## デモ05: 押したら再生、もう一度押したら逆再生
```.html
<div class="lottie-obj js-lottie05"></div>
```
```.js
  const target05 = document.querySelector(".js-lottie05");
  const anime05 = lottie.loadAnimation({
    container: target05,
    renderer: "svg",
    loop: false,
    autoplay: false,
    path: "/img/lottie/christmas.json",
  });

  let isPlayFlag = false; // アニメーションの再生状態を管理するフラグ
  target05.addEventListener("click", () => {
    if (isPlayFlag) {
      anime05.setDirection(-1); // 逆再生
      anime05.play();
    } else {
      anime05.setDirection(1); // 正再生
      anime05.play();
    }
    isPlayFlag = !isPlayFlag;
  });
```
![demo05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064849/fb64e046-c5a3-12fc-f224-07ceb42e37eb.gif)

# 使いどころ
- ローディング
- アイコン
- ボタンエフェクト
- あしらいや装飾
- チュートリアルやフロー図
- MV

などなど・・・
Lottieは簡単にアニメーションを実装できるので
UXを高めるためにも使用検討ができる部分は多そうです

# メリット・デメリット
## メリット
- After Effectsを使用できればアニメーションを作れる
- 実装コストが低い
- JSで再生・逆再生・一時停止・停止や色、スピード、タイミングなど様々な操作ができる
- SVG形式で書き出されるので拡大縮小しても綺麗
- アニメーション実装におけるデザイナー・エンジニア間のワークフローを効率化できる

## デメリット
- After Effectsで作る場合はAdobeライセンスが必要
- アニメーション作成の上で表現の幅に制限がある
    - Lottieと互換性のある表現しかできないので非常に複雑なアニメーションや高度なエフェクトなどは表現できないことがある
- エクスポートしたファイルを直接操作してアニメーション編集することが難しいのでアニメーションを調整する場合はAfter Effectsを開かないといけない

# おわりに
少し触ってみた感想としては思っていたよりも簡単でとても便利だなと感じました。
実装コストがあまりかからずリッチな表現ができるなと感じたので今後も機会があれば是非挑戦してみたいと思います。
最後までお読みいただきありがとうございました。