プログラミング学習

動かない!?anime.jsでsvgのテキストアニメーションの作り方【fillのサンプル】

プログラミング学習

anime jsの使い方覚書です。

前半はqiitaに寄稿しました。後半は主にsvgアニメーションの解説です。

anime jsはtimeline内loopできない!?

タイムラインの最後でループさせようと思いました。

iconが上下に移動するコードですが、こういうコードでは1回しか実装されません。

.add({
  targets: '.icon-anime',
  loop: true,
  keyframes: [
    {
      translateY: [-20, 0],
      duration: 1000,
      easing: 'linear'
    },
    {
      translateY: [0, -20],
      duration: 1000,
      easing: 'linear'
    }
  ]
})

こういう画面はcompleteの使い所のようです。これでうまくいきました。

complete: () => {
  anime({
    targets: '.icon-anime',
    loop: true,
    keyframes: [
        {
          translateY: [-20, 0],
          duration: 1000,
          easing: 'linear'
        },
        {
          translateY: [0, -20],
          duration: 1000,
          easing: 'linear'
        }
    ]
  })
}

短くかくなら、direction: ‘alternate’を使うとよいです。座標飛びしないように基本的にこの書き方がよさそうです。

anime({
    targets: '.icon-anime',
    loop: true,
    direction: 'alternate',
    duration: 3000,
    translateY: -30,
    easing: 'linear'
})

keyframesはどちらかというと、loopではなく順番に実行するものに使った方がよさそうです。

スポンサーリンク

動かない!?anime.jsでsvgのpathアニメーションの作り方【サンプル】

svgのフォントが変わる原因はエスクポートデータがおかしい

illustratorやaffinity designer、クリスタでSVGファイルを作成します。

もっていない人はこの機会に契約や入手してもよいでしょう。

AdobeはxdがあったりAdobe fontsがついていたりすることがメリットです。

クリスタとaffinity designerは安価な買い切りです。

フォントはいい感じのものを用意します。フォントワークス などの有料フォントやフリーフォントがありますが、アウトライン化のライセンスを確認します。SVGはアウトライン化しますがHtmlに変換されるため組み込みとは別のようです。

データを作る際、注意事項があります。

1、アウトライン化して書き出す必要があります(勘違いする人は少ないかもですが、ラスタライズはピクセル化ですから違いますよ)。

2、文字が表示される順番がある場合、グラフィックソフトでデータを作る際に下側にあるデータから表示されるようなので1文字ずつ分割してデータを作っておきます。アウトライン化した時点でそうなるはずですが、テキストや図形が複数ある場合はこの点を注意しましょう。

3、グラフィックソフトによりますが、レイヤーなど日本語で名前をつけているとidが日本語になる場合があります。グラフィックソフト側で英語に変えとくべきでしょう。なお、グラフィックソフトによるかもしれませんが、非表示レイヤーの情報は書き出されないようです。

4、1つのアニメーショングループに対して、1つのSVGファイルがよいです。1回テキストやパーツごとに分けて書き出してテストしたのですが、座標調整が大変になります。1つのviewBoxで管理するとよいです。もしもマスクなどを作る場合は、VsCode上で切り分ける形にします。

5、affinity designer側で特殊効果(FX)などをつけると、エクスポート時にdefsに大量のデータが生成されてうまく表示されないことがあります。たとえば、やりがちなのが文字の縁取りです。ただのベタ塗りがよいでしょう。

svgの表示

エクスポートしたのち、SVGファイルを右クリックしてVsCodeで開きます。

そうするとSVGのデータを取得できます。

svgの部分をhtmlに埋め込むと表示できます。

<svg width="100%" height="100%">
</svg>

幅と高さは100%になっていましたが、削ってCSS側で指定してあげてもいいかもしれません。

svgのviewbox

viewboxは描画領域のことです。

viewBox="x, y, width, height"

下記の例は幅1200、高さ2100です。

<svg width="100%" height="100%" viewBox="0 0 1200 2100"

anime.jsでsvgのpathが動かない!?

あとはanime.jsでアニメーションさせるだけです。

とはいえ、最初、コピペするだけでは動きませんでした。動かない場合はidやclass名を見直しましょう。グラフィックソフトの階層構造や図形なのか否かによって名前が変わるようです。

pathにclassが全部あれば動くはずです。

<path class="text-anime'">
</path>
anime({
    targets: '.text-anime',
    strokeDashoffset: [anime.setDashoffset, 0],
    easing: 'easeInOutSine',
    duration: 500,
    delay(el, i) {
      return i * 3000
    }
})

実際は面倒なのでid pathなんか指定されて紹介されていますね。

targets: '#id path',

図形にclass名の指定がなかったため手動指定しました。

また文字や図形が線だと思っていたけど実は塗りだったというオチでも動きません。線にアニメをかけているわけなので。うっかりと塗りを書き出さないようにします。

複数指定

targets: '#id path, #id2 path, .class path, #shap rect, #shap path',

アウトラインはpath、図形はrectになっていました。他useなどいろいろあるようです。

fill(塗りつぶし)

タイムラインにすると線画アニメーションしたあと、塗りつぶせます。

const timeline = anime.timeline({
    targets: '#id path, #id2 path, .class path',
    direction: 'normal',
    loop: false
})
timeline.add({
    strokeDashoffset: [anime.setDashoffset, 0],
    easing: 'easeInOutSine',
    fill: ['transparent', 'transparent'],
    duration: 2000,
    delay(el, i) {
    return i * 150
    }
})
timeline.add(
    {
    easing: 'easeInOutSine',
    fill: ['transparent', '#ffffff'],
    duration: 500
    },
    '-=200'
)
スポンサーリンク

動かない!?anime.jsでsvgのマスクアニメーションの作り方【サンプル】

マスクアニメーションを利用すると手書きアニメーションが実現できます。

上記の方法は線画を描いて塗りです。ただ、文字を普通に描いていく方法がデザイン的にはしっくりきますし、企業サイトで使われているものはそっちの方が多いです。

まず、マスクの理解が必要です。

囲った場所が消えます。

<defs>
    <mask id="maskname">
        <!-- pathを入れる -->
    </mask>
</defs>
<image :href="require('~/assets/images/anime/sample.svg')" width="100%" height="100%" mask="url(#maskname)" />

ただ、こちら実際に作ってみましたが手間暇かかります。一応、ざっくりと解説してみました。

svgのマスクアニメーションの作り方
  • Step1
    データを作成します。

    マスクのスタイルは消すので、わかりやすい色でOKです。ここは特に難しくありませんし、解説したサイトもたくさんあります。

    Adobe Illustrator、クリスタ、affinity designerなどの選択肢があります。ソフトにより若干吐き出されるデータが違う気もしますが、SVGは後から編集できるため、どれでもいいです。

    書き出す際に、マスクをかける画像と、その他全部(マスクを含む)は別々に書き出します。座標は合致するようにしておきます。

    SVGの外にあるコードは削ってOKです。Vs Codeで開いて削る手順になります。

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    ↑いらないコード
    <svg>
    いるコード
    <svg>

    そのうえでマスクをかける画像データはVs Codeのassets内にいれておきます。

  • Step2
    まず外部リンクを表示しましょう。

    マスク云々の前にまずはマスクする画像を外部リンクとして表示しましょう。作業は切り分けておこなうとよいです。

    <image :href="require('~/assets/images/anime/sample.svg')" width="100%" height="100%" mask="url(#maskname)" />

    リンク先がフォントを指定した画像です。リンク元がなぞったマスクです。逆にしないように注意してください。

    いくつかひっかりそうなところがあります。

    参考まですが、nuxt(vue)の場合、リンクの書き方が変わります。

    xlink:hrefは非推奨になっています。

    nuxtの場合、imageのリンクはrequareを使わないとうまく表示されません。:をつけてあげること。:href

    検証方法はChromeの検証から画像がリンクされているか確認すればOKです。また座標があっているかですね。凡ミスはたいてい座標系です。

  • Step3
    マスクだけ表示する

    次マスクだけ表示します。あえてマスクのコードをコメントアウトします。

    <!-- <defs>
        <mask id="maskname"> -->
        <g id="mask">
        マスクのpath
        </g>
        <!-- </mask>
    </defs> -->

    defsとmaskをコメントアウトするとマスクの形を見ることができます。cssの適応が正しくできるか検証できます。defsはなくてもいいですけど、推奨になっています。

    マスクの部分だけコピペすると、作りによって階層構造ががあわず座標ずれする場合もあります。その場合は上位階層も含めてコピペします。

    imageのmaskのurlを#にすると、マスクがかかっていない状態になります。
    urlを適用するとはじめてマスクがかかります。

    マスクのコードにはなぞった色のstyleが適応されています。

    そのコードは全部省いて白で塗りつぶします。

    マスクを省いた状態でアニメーションまでできるか検証してもよいでしょう。

  • Step4
    マスクの適用

    ここまで動いたら簡単です。マスクを適用して画像を消しましょう。

  • Step5
    アニメーション

    最後にアニメーションを適用させましょう。

    anime.jsの場合、strokeDashoffsetでよさそうです。今回、マスクがラインなので。

    strokeDashoffset: [anime.setDashoffset, 0]

templeteをまとめるとこんな感じです。コンポーネント化した方がよいでしょう。

<template>
  <div>
    <b-row class="mx-0 my-0 py-5 px-0">
      <b-col cols="12">
        <div class="animebox box-centering">
          <div style="width: 800px;">
            <svg id="svg" x="0px" y="0px" viewBox="0 0 1200 600" xmlns="http://www.w3.org/2000/svg">
              <defs>
                <mask id="maskname">
                  <g id="mask"></g>
                </mask>
              </defs>
              <image
                :href="require('~/assets/images/anime/sample.svg')"
                width="100%"
                height="100%"
                mask="url(#maskname)"
              />
            </svg>
          </div>
        </div>
      </b-col>
    </b-row>
  </div>
</template>
スポンサーリンク

anime.js側でscaleすると座標がおかしくなる!transformが効かない!

scaleすると、次のCSSが効いていませんでした。!importantを使うとアニメーションしなくなるため、anime.js側で解決する必要がありそうです。

transform: translateX(-50%) translateY(-50%);

初期値で座標を固定してあげるとよさそうです。改善しました。

anime({
  targets: '.logo-anime',
  translateX: ['-50%', '-50%'],
  translateY: ['-50%', '-50%']
})

他に解決方法があれば知りたいところです。

簡単でしたが、参考になれば幸いです。

コメント

タイトルとURLをコピーしました