りゅーそう
元高校地歴科教員。現在microCMSでエンジニアをしています。
Saitama.jsというLT会を運営中です。
発言はすべて個人の意見です。
lottie
animation
gatsby
2020/05/16
2022/01/23
最近、本業で動画制作を行う機会があり、Adobeでモーションを作成したりしていました。
そこで作成したモーションをWEBでも再生できないかと思いやってみました。
今回はlottieというライブラリを用いて行います。
サイト本体はGatsbyを使用しましたが、React環境であれば同様の方法で試せると思います。
Airbnbが開発したライブラリ。AfterEffectsで作成したモーションをAndroid,ReactNativeなどで再生できるようにしてくれます。。
WEBではlottie-webというライブラリを使用します。
lottie
lottie-web
AfterEffectsを用いて行いました。
bodymovinというライブラリを使用することで、AfterEffectsで作成したモーションをJSON形式で書き出すことができます。
詳しくは解説しませんが、以下の記事が参考になりました。
AfterEffects+Lottieを使ったアニメーションをWebサイトで表示させてみた
また、動画がなくてもlottiefileからいろんなクリエイターの方が作成したモーションをダウンロードすることもできます。
lottiefiles
動画をGatsbyで取り込むまでを解説します。
環境構築をして作成した動画をファイルに取り込みましょう。
Gatsbyのプロジェクトを作ります。starterがあるので使うと便利です。
gatsby new gatsby-starter-default https://github.com/gatsbyjs/gatsby-starter-default
ちなみに私はTypeScriptで動かしてみたいなあと思います。
興味ある方は以下のプロジェクトをgit cloneしてください。
GitHub
publicファイルに専用のファイルを作成します。
cd public
mkdir animations
animationsに動画ファイルを入れておきましょう。
lottie-webをインストールします。
yarn add lottie-web
今回使用するメソッドの紹介です。Reactの基本です。
関数コンポーネント内で副作用を処理するフックです。ユーザーの処理に応じて関数を返して処理を行うことができます。
今回はここにlottieを表示させるコードを書きます。コンポーネントの表示とともに処理を行うので今回は関数を返しません。
useEffect
refとはDOMにアクセスする関数のことです。
初期値をカッコに入れます。
const inputEl = useRef(null);
そして、
<input ref={inputEl} type="text" />
このようにDOMにアクセスして、処理を加えたりすることができます。
useRef
蛇足です。 lottie-webには型定義ファイルが(探した限り)なかったので以下のようなファイルを作成します。
//src/types/index.d.ts
declare namespace Lottie {
export interface AnimationItem {
play(): any;
stop(): any;
pause(): any;
// one param speed (1 is normal speed)
setSpeed(speed: number): any;
// one param direction (1 is normal direction)
setDirection(direction: number): any;
// If false, it will respect the original AE fps. If true, it will update as much as possible. (true by default)
setSubframe(flag: boolean): any;
// first param is a numeric value. second param is a boolean that defines time or frames for first param
goToAndPlay(value: number, isFrame: boolean): any;
// first param is a numeric value. second param is a boolean that defines time or frames for first param
goToAndStop(value: number, isFrame: boolean): any;
// first param is a single array or multiple arrays of two values each(fromFrame,toFrame), second param is a boolean for forcing the new segment right away
playSegments(
segments: number[] | number[][],
forceFlag: boolean,
): any;
// To destroy and release resources.
destroy(): any;
}
export interface AnimationConfig {
// an Object with the exported animation data.
animationData?: any;
// the relative path to the animation object. (animationData and path are mutually exclusive)
path?: string;
// true / false / number
loop?: boolean | number;
// true / false it will start playing as soon as it is ready
autoplay?: boolean;
// animation name for future reference
name?: string;
// 'svg' / 'canvas' / 'html' to set the renderer
renderer?: string;
// the dom element on which to render the animation
container?: any;
}
}
declare class LottyPlayer {
// optional parameter name to target a specific animation
play(name?: string): any;
// optional parameter name to target a specific animation
stop(name?: string): any;
// first param speed (1 is normal speed) with 1 optional parameter name to target a specific animation
setSpeed(speed: number, name?: string): any;
// first param direction (1 is normal direction.) with 1 optional parameter name to target a specific animation
setDirection(direction: number, name?: string): any;
// default 'high', set 'high','medium','low', or a number > 1 to improve player performance. In some animations as low as 2 won't show any difference.
setQuality(quality: string | number): any;
// param usually pass as location.href. Its useful when you experience mask issue in safari where your url does not have # symbol.
setLocationHref(href: string): any;
// returns an animation instance to control individually.
loadAnimation(
params: Lottie.AnimationConfig,
): Lottie.AnimationItem;
// you can register an element directly with registerAnimation. It must have the "data-animation-path" attribute pointing at the data.json url
registerAnimation(element: any, animationData?: any): any;
// looks for elements with class "lottie"
searchAnimations(
animationData: any,
standalone: boolean,
renderer?: string,
): any;
// To destroy and release resources. The DOM element will be emptied.
destroy(name?: string): any;
}
declare const Lottie: LottyPlayer;
declare module 'lottie-web' {
export = Lottie;
}
以下のissueを参考にさせていただきました。
anyだらけにしたので、あまり参考になりませんがとりあえず動きます。
GitHub
前提知識を元にコードを書いていきましょう。
コードの全体像は以下のようになります。
// src/pages/index.tsx
import React, { useEffect, useRef } from 'react';
import lottie from 'lottie-web';
function IndexPage() {
const animationContainer = useRef<HTMLDivElement>(null);
useEffect(() => {
lottie.loadAnimation({
container: animationContainer.current,
path: '/animations/data.json',
});
});
return (
<>
<h1> Welcome!!</h1>
<div ref={animationContainer} />
</>
);
}
export default IndexPage;
まずはuseRefの部分です。
const animationContainer = useRef<HTMLDivElement>(null);
このようにuseRefを宣言して初期値nullを入れます。型はこのように書きます。今回はdiv要素にアクセスするのでHTMLDivElementを使っています。
<div ref={animationContainer} />
そしてこのようにしてアクセスして、アニメーションを表示させます。
次にlottie-webの設定方法をみていきましょう。
loadAnimationというメソッドを使って、設定を書いていきます。先ほどのuseEffectの中で処理を行なっていきます。
useEffect(() => {
lottie.loadAnimation({
container: animationContainer.current,
path: '/animations/data.json',
});
});
containerにはアニメーションをレンダリングするDOM要素を設定します。
.currentプロパティは先ほどのrefの処理によって、DOMノードに設定されたプロパティです。DOMに変更があるたびに設定されます。これによって、loop再生することが可能になります。
path
先ほど入れた動画のパスを絶対パスで記述します。
他にもloop,autoplayなどが設定できます。
詳しくは以下のDocsを参照してください。
lottier-web
以上で以下のようなAnimationが表示されました
Gatsbyにlottie-webでアニメーションできた!
— りゅーそう (@ryusou_mtkh) May 16, 2020
(そんな直線的な動きCSSとかでやれとか言わない) pic.twitter.com/5sVQN1WctK
lottieを使えば、簡単に複雑なアニメーショをWEBなどに取り込むことができます。
今回はGatsby特有の話はありませんでしたが、使い方を考えればJamstack構成などにすることによってパフォーマンスを維持したままアニメーションを行うことも可能です。
ただ、 AfterEffeects全ての機能が使えるわけではなくなかなか大変でした。
ドキュメントも参照しながら動きのある楽しいサイトを制作してみてください!