LoginSignup
1
0

More than 1 year has passed since last update.

【React】四角形がたくさん表示される背景アニメーションを実装する(Anime.js)

Last updated at Posted at 2021-09-24

概要

四角形がぶわっと表示される背景アニメーションを実装します。
アニメーションには、Anime.jsを使用します。

output(video-cutter-js.com) (2).gif

元ネタは以下の動画になります。

この動画では、バニラのHTML・CSSで実装しています。
本記事では、それをReactで実装したものになっていて、動画とは作りがかなり異なっています。

バージョン

  • react - 17.0.2
  • animejs - 3.2.1
  • @emotion/css - 11.1.3

インストール

Reactプロジェクトを作成します。
プロジェクトフォルダを作成し、そこで以下を実行します。

cmd
npx create-react-app . --template typescript --use-npm

パッケージをインストールします。

cmd
npm i animejs
npm i -D @types/animejs
npm i @emotion/css

実装

import anime from 'animejs';
import React, { useEffect, useState, VFC } from 'react';
import { css, cx } from '@emotion/css';

export const BeautifulAbstractBackground: VFC = () => {
    const [refresh, setRefresh] = useState(true)

    const blockSize = 40

    const generate = () => setRefresh(!refresh)

    const randomBlockColor = () => {
        const colors = ['#fff', '#444', '#ff9213']
        const index = Math.floor(Math.random() * colors.length)
        return colors[index]
    }

    return (
        <div className={styles.container}>
            <button className={styles.button} onClick={generate}>
                Ganerate
            </button>
            {[...Array(blockSize)].map((_, i) => (
                <Block key={i} isRefresh={refresh} blockColor={randomBlockColor()} />
            ))}
        </div>
    )
}

// ==============================================
// block

type BlockProps = {
    isRefresh: boolean
    blockColor: string
}

const Block: VFC<BlockProps> = props => {
    const { isRefresh, blockColor } = props

    useEffect(() => {
        const rangeX = [-window.innerWidth / 2, window.innerWidth / 2]
        const rangeY = [-window.innerHeight / 2, window.innerHeight / 2]

        anime({
            targets: '.block-anime',
            translateX: () => anime.random(rangeX[0], rangeX[1]),
            translateY: () => anime.random(rangeY[0], rangeY[1]),
            scale: () => anime.random(1, 5)
        })
    }, [isRefresh])

    return <div className={cx(styles.block(blockColor), 'block-anime')}></div>
}

// ==============================================
// styles

const styles = {
    container: css`
        position: relative;
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: #202020;
        overflow: hidden;
    `,
    button: css`
        position: relative;
        z-index: 1;
        margin: 10px;
        border: none;
        background-color: #ce104b;
        color: #fff;
        font-size: 1.5rem;
        padding: 0.5em 1em;
        cursor: pointer;
        box-shadow: 10px 10px 30px rgba(0, 0, 0, 0.25);
    `,
    block: (color: string) => css`
        position: absolute;
        width: 50px;
        height: 50px;
        background-color: ${color};
        box-shadow: 10px 10px 30px rgba(0, 0, 0, 0.25);
    `
}
  • Blockをコンポーネント化して、blockSizeで指定した個数(40)だけBlockを生成しています。

  • Blockの色は、randomBlockColorで3色(#fff#444#ff9213)からランダムにピックしています。

  • Blockコンポーネントの中では、animeを使用してBlockのアニメーションを設定しています。animeは、targetsでCSSセレクターによってdom要素を参照しているので、useEffectの中で定義します。

  • アニメーションは、一番最初にコンポーネントがマウントされたタイミングと、isRefreshの値が変わったタイミング([Generate]ボタンが押されたタイミング)で実行されるようにします。

useRefと、anime.jsのrestartを使用することで再度アニメーションを実行することもできます。
> refを使った実装例

しかしこの方法だと、アニメーションの設定でanime.randomで設定している値が、生成されたときから変更されないので、[Generate]を押してもBlockコンポーネントの挙動が毎回同じになります。

なので、今回はuseStateでrefresh変数を作成して、コンポーネント自体を再描画してアニメーションを再生成する処理にしています。

参照

Anime.jsのドキュメントは、すごくわかりやすいです。本当にすごい...

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0