90年代初期のBLINKタグから、最新のCSS3トランジションやアニメーションに至るまで、Webページやアプリケーションの要素を移動する機能は、いつも魅力的な目標であり続けています。
今日では、SVGなどのテクノロジーを使えば、「見えないペン」と呼ぶエフェクトを比較的容易に実現できます。閲覧者は、まるで見えないペンで描かれたかのように、1ラインずつ表示される絵を目にします。
そのアイデアは新しいものではありません。よく知られているように、1953年の「Duck Amuck(カモにされたカモ)」にまでさかのぼると、のちにバッグス・バニーだと判明した見えざる手は、周りの世界を何度も消しては描き直すことによってかわいそうなダフィー・ダックを困らせます。この作品はシュールな名作です。
2013年に至ると、Jake Archibaldはstroke-dashoffset、stroke-dasharrayなどのCSSを操作して、「魔法のペンエフェクト」をSVGパス上に生成する方法を巧みに示しました。
Jakeのアプローチは、比較的単純なSVGの線画を実装するのには向いていますが、より複雑にしたい場合は必ずしも理想的なソリューションではありません。もっと複雑な線画アニメーションには、Vivus.jsなど役立つ専用ツールが用意されています。Vivusは軽量のJavaScriptライブラリーで、CSSをあまり操作せずにSVG要素をアニメーション化できます。
ここで、「純粋なCSSのアプローチよりもVivusの方が優れているのはなぜなのか」という大きな疑問が思い浮かんだのではないでしょうか。
私の考えでは、Vivusには特筆すべき3つの主なメリットがあります。
- 使いやすさ:Vivusでは、Vivusの「コンストラクターオブジェクト」内、コンテキスト内のアニメーションプロパティーの大部分をSVGドキュメントとあわせて制御する。これによって、より利便性が高く直観的な操作ができるようになった。少し調整するだけで、まったく異なるアニメーションエフェクトが得られる
- 自動化:すでに知られているように、エフェクトの主要部分である、SVGのstroke-dashoffsetプロパティはpath要素上でのみ使用できる。ただし、SVGの描画にcircle、rectangle、line、polyline、そのほかの一般的な「pathではない」オブジェクトが含まれている場合に問題が発生する可能性がある。
幸い、Vivusを使えばすべてのSVGオブジェクトをpath要素に自動的に変換し、アニメーション化もできる。これは大きなメリットだ。
ただし、Illustrator、InkScapeなどのベクターエディターを使って、すべてのtext要素を手動でpathに変換する必要があることに注意が必要だ - 柔軟性:Vivusには5つのプリセット・アニメーションタイプが豊富な操作オプションとともに用意されており、アニメーションの動作は高い柔軟性を持つ
それでは、Vivusの詳細について掘り下げ、メリットを実際に説明していきます。
デザイナーのみなさんへ:ここから先はコードが出てきますが、Vivusはデザイナーが使用するために設計されています。プログラマーでなくても、少し切り貼りして編集すれば、とてもすばらしい結果が得られます。
Vivusの探求
Vivusを使い始めるには、次のような記述をHTMLに記載する必要があります。
<script src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.3.2/vivus.js"></script>
上のコードを記載しておけば、次のようにインラインSVGが使用できます。
<svg id="canvas">
<path...>
<path...>
<path...>
</svg>
以下がスクリプトです。
<script>
new Vivus('canvas', {duration: 300}, callback);
</script>
上のスクリプトにはインラインSVGと、以下の3つのパラメーターがあるVivusコンストラクター関数があります。
- 相互に作用させたいDOM要素のID(スクリプトのIDは「canvas」)
- すべてのアニメーションオプションを配置するオプションオブジェクト
- アニメーションの最後に呼び出されるオプションのコールバック関数
次に進む前に、以下のことに注意してください。
- デフォルトでは、VivusはSVGドキュメントの定義と同じ順番で要素を描画する
- すべてのSVG要素はstrokeプロパティを持つ必要があり、塗りつぶしはできない
- SVGに非表示のpath要素は配置できない。配置すると、アニメーションが正しく表示されないことがある
- text要素をpath要素に変換できない。アニメーションにtextを使用する場合は、Illustrator、InkScapeなどのエディターを使って最初にtextをpathに変換する必要がある
Vivusの5つの描画オプション
Vivusが提供する5つのアニメーションタイプのすべてを説明します。利用可能なアニメーションオプションの違いをより明確にするために、非常にシンプルな4行で描ける線を使用します。
Delayed
このSVGは長さが等しい4本の線で構成されています。デフォルトのアニメーションdelayedモードは、各path間で少し遅延がありますが、すべてのpathがほぼ同時に開始されます。
One-By-One
oneByOneモードでは各pathが順番に描画されます。上の例では、4つの同じ線が連続して1本ずつ描画されます。
Async
asyncモードでは各pathは非同期で描画されます。上の例では、線の長さが違っても線描画の開始・終了をより明確に同時に確認できるように、長さの違う線を使用しています。
Scenario
このscenarioモードと次のscenario-syncモードのアニメーションタイプは、SVGのDOMで直接アニメーションプロパティを設定できます。アニメーションをもっと詳細に制御するとともに、より厳密に調整できます。
scenarioモードでは、data-startとdata-duration属性で各path要素の開始時間および継続時間を定義するだけです。この属性がない場合は、コンストラクターのデフォルト値が使用されます。
上の例では、最初に2番目の線の描画が始まり、次に3番目の線が素早く描画されたあと、1番目の線の描画が開始され、1番目の線の描画の途中でようやく最後の線の描画が始まり、2本の線の描画は同時に終了します。SVGの簡略化されたスキームを以下に示します。
<line data-start="200" data-duration="200" .../>
<line data-start="0" data-duration="100" .../>
<line data-start="100" data-duration="10" .../>
<line data-start="300" data-duration="100" .../>
アニメーションへの指示が分かるように、単純な数値計算をするだけにしています。ここでVivusの柔軟性が発揮されています。つまり、SVGのもともとの順番を守る必要はなく、開始したい要素から描画を開始し、好きな順番でほかのすべての要素の描画を続けられるということです。
Scenario-Sync
scenario-syncモードのデフォルト動作はoneByOneモードと同じです。ただし、以下のような特定のpath項目をターゲットにする属性で、アニメーションをさらに改良できます。
- data-duration – pathのアニメーション継続時間を定義する
- data-delay – 前のpathのアニメーションの終了と現在のpathの開始の間の遅延を定義する
- data-async(値は不要) – pathの描画を非同期にする。つまり、次のpathが同時に開始される。pathにdurationまたはdelay属性がない場合、オプションオブジェクトに設定されているデフォルト値が使用される
上の例では、最初の線はデフォルトの継続時間である200msで描画されます。2番目の線は100msの遅延および最初の線と同じ継続時間で開始されます。3番目の線は2番目の線の直後に開始され、300msの間継続します。3番目の線はdata-asyncプロパティがあるので、最後の線は3番目の線と同時に始まりますが、4番目の線の継続時間は200msなので3番目の線よりも先に終了します。
SVGの簡略化されたスキームを以下に示します。
<line .../>
<line data-delay="100" .../>
<line data-duration="300" data-async .../>
<line data-duration="200" .../>
完全な2つの例
Vivusが提供するさまざまなタイプのアニメーションが理解できたと思いますので、もっと実用的で現実的な方法で試しましょう。このあと、「delayed」および「scenario-sync」モードを使って、車の設計図とロケットを描画する完全なアニメーションを作成していきます。
車の設計図の描画
最初の例では、セアトレオンの設計図を作成します。
フリーベクターアートを集めたVecteezyから入手したこのファイルをIllustratorで開き、SVG型式でエクスポートしました。SVGコード全体については、この項の最後にあるCodePenの例を参照してください。
最初に、JavaScriptファイルまたは<script>タグ内で、canvas IDを使ってSVGを指す新しいVivusコンストラクターを作成します。オプションオブジェクトで、delayed(遅延)させるアニメーションのタイプとアニメーション全体のタイミング関数を定義します。
遅延させるため、組み込みのタイミングメソッドVivus.EASEを使います。その結果、アニメーションがより穏やかに開始・終了します。さらに、アニメーションが終了してから3秒後に描画をリセットし、再描画するコールバック関数を追加します。
new Vivus('canvas', {
start: 'autostart',
type: 'delayed',
animTimingFunction: Vivus.EASE
},
function(car){
setTimeout(function(){ car.reset().play(); }, 3000);
}
);
最終的な結果は次のようになります。
見てのとおり、最小限の労力ですばらしい設計図のアニメーションが得られました。
ロケットの描画
2つ目の例では、ロケットのイラストアニメーションを作成し、色を付けます。
目標はロケットを描画し、塗りつぶし、さらに枠線を削除することです。SVGコードについては、この項の最後にあるCodePenの例を参照してください。
新しいVivusコンストラクターを使用します。今回はアニメーションのタイプにscenario-syncを設定して、pathTimingFunctionにVivus.EASE_OUTを設定します。また、アニメーションの最後にCSSクラスを追加するコールバック関数を使います。以上で、ロケットが塗りつぶされ、枠線が削除されます。
new Vivus('canvas', {
start: 'autostart',
type: 'scenario-sync',
pathTimingFunction: Vivus.EASE_OUT
},
function(obj){
obj.el.classList.add('fill-1', 'fill-2', 'fill-3', 'fill-4', 'fill-5', 'fill-6', 'fill-7', 'clear-stroke');
}
);
CSSファイルまたは<style>タグ内で、最初にpathのfill-opacityを0に設定し、トランジションの継続時間を1sに設定します。次に、CSSセレクターでSVGの各要素にfillプロパティを割り当て、fill-opacityを1に設定して表示します。このトリックに関する詳細についてはこちらを参照してください。
最後に、各pathのstrokeにnoneを設定します。
path {
fill-opacity: 0;
transition: fill-opacity 1s;
}
.fill-1 g:first-of-type > path{
fill: #1c8ece;
fill-opacity: 1;
}
.fill-2 g:last-of-type > path{
fill: #ffffff;
fill-opacity: 1;
}
.fill-3 path:first-of-type{
fill: #f4a260;
fill-opacity: 1;
}
.fill-4 path:nth-of-type(2){
fill: #ea3e2f;
fill-opacity: 1;
}
.fill-5 path:nth-of-type(3){
fill: #d1d2d4;
fill-opacity: 1;
}
.fill-6 path:nth-of-type(4),
.fill-6 path:nth-of-type(5) {
fill: #000000;
fill-opacity: 1;
}
.fill-7 path:nth-of-type(6){
fill: #ffffff;
fill-opacity: 1;
}
.clear-stroke path{
stroke: none;
}
このSVGでは、data-durationとdata-delayプロパティで必要に応じてアニメーションを構築します。data-asyncプロパティは、ロケットの2つの翼を同時に描画するのに使っています。
SVGの簡略化されたスキームを次に示します。
<path data-duration="50" .../>
<path data-duration="150" data-delay="100" .../>
<path data-duration="50" .../>
<path data-duration="50" .../>
<g> <polygon data-duration="300" data-async .../>
<polygon data-duration="300" .../>
</g> <path data-delay="25" .../>
<path .../>
<g> <polygon data-async .../> <polygon .../> </g>
最終的な結果を示します。
最後に
Vivusを使用すれば、CSSプロパティを操作する代わりに描画のアイデアや実際の動作に集中できるようになります。SVGドキュメントさえ準備すれば、比較的簡単なプロセスで実際のアニメーションに変換できます。
少しの想像力とVivusのアニメーション機能があれば、複雑でおもしろいアニメーションをすぐに作成できるのです。
(原文:The Best Way to Create Fantastic ‘Invisible Pen’ Effects in SVG)
[翻訳:市川千枝/編集:Livit]