Posted at

[R2D3.js] D3.jsをつかってフルSVGでSTARWARSのオープニングっぽく六甲おろしを流してみる

More than 3 years have passed since last update.


R2D3.js

R2D3.js といっても D3.js と R2-D2 をかけただけで、ライブラリでもなんでもないですあしからず。

さて、 D3.js の勉強がてらに STARWARS のオープニングロール風にSVGで六甲おろしを表示させてみました。

いやー D3.js すごいしおもしろいですね。歌詞合わせて150行くらいで書けちゃいます。それもメソッドチェーン毎に改行入れてるのに。

デモとサンプルはこちら → bl.ocks.org

D3.js の勉強がてらに作成したんで、ポイントを復習してみたいと思います。


1. 大量の星

今回は100個の星を散りばめました。

100個とは言っても100個分の配列を用意してランダムに配置していますので、手間は全然かかっていません。

D3.js には等差配列を作成させるメソッドがありましたので、一気に配列を作ってランダムに配置するだけです。

var a = d3.range(0, 100, 1);

a.forEach(function(d) {
svg.selectAll("star")
.data(function() {
return [{id: d}];
})
.enter()
.append("svg:circle")
...
});

な感じ。簡単ですね。


2. 星の瞬き

細かい演出としては適当に星を瞬かせてみました。

定期的に適当な星を選んで transition で星の大きさを変えるだけです。

動きは exp を選んでじわっと大きさが変わる感じにしてみました。

d3.select(id)

.transition()
.duration(500)
.ease("exp")
.attr("r", function() {
return Math.random() * 1.5;
});

速くても遅くてもイマイチなので、 duration の値は難しいところです。


3. 流れ星

もっと細かい演出として流れ星を加えてみました。

こちらも定期的に適当な星を選んで transition で画面の端まで動かすだけです。

動きは circle を使用し、最初はゆっくりでだんだん加速がついてくるような感じにしてみました。

d3.select(id)

.transition()
.duration(1000 * Math.random() * 3)
.ease("circle")
.each("end", function() {
d3.select(id).attr("cx",function() {
return Math.random() * w;
});
});

移動した後はまたランダムな場所に星を配置しています。だんだん減っていったら寂しいですからね。


4. ヒアドキュメント

歌詞部分は容易に差し替え出来るように、「Javascriptでヒアドキュメント」を参考にヒアドキュメントの形で埋め込んでみました。

ただ、そのままだとうまく動かなかったので、いったん改行区切りで配列にして必要な部分だけを取り出しています。

D3.jsは配列のデータを期待しますから、こっちのほうがバグにも引っかからないし使い勝手も良さそうです。

var heredoc = (function () {

/*
六甲颪(おろし)に 颯爽(さっそう)と
蒼天(そうてん)翔(か)ける日輪(にちりん)の
...
*/

}).toString().replace("\r\n", "\n").split("\n");


5. 歌詞の表示

歌詞の表示については1行単位でグループ要素を作り、その中に svg:text を作成しました。

グループと言っても子要素はテキストだけなので、グループ化が必要かと言われるとどうだろう?とは思います。

まあ癖みたいなものですね。もしかしたら歌詞の左右にトラのマークとか入れたくなるかもしれませんし。

位置については、グループ要素の左端を表示域の中心にして、テキストの text-anchormiddle を指定して画面中央寄せにしています。

var line = svg.selectAll("line")

.data(data)
.enter()
.append("g");

var text = line.append("svg:text");

せっかくグループ化してますので、変数も分けて後から別々のエフェクトをかけれるようにしてあります。


6. 文字のロールアップ

ここが今回の一番のポイントですね。

今回はいったん全ての歌詞をSVG表示エリア下の外側に配置します。その後、一行目から時差をつけて順に浮上させています。

浮上させる際には一緒に文字サイズも小さくなるようにして、スターウォーズのオープニングっぽく奥行きを表現してます。

本来でしたら行の両端を揃えて台形になるようにしたいところです...

ロールアップは、グループ要素とテキスト要素別々に transition を指定してます。

duration が一緒なので、それほどおもしろくはありませんが。

グループ要素では、テキストごと上昇移動させ最後にグループを削除。

line.transition()

.delay(i * 500)
.duration(10000)
.attr("transform", function() {
return "translate(" + (w / 2) + ", 50)";
})
.each('end', function() {
d3.select(this).remove();
});

テキスト要素では文字サイズを縮小。

text.transition()

.delay(i * 500)
.duration(10000)
.style("font-size", "20px");

見ての通り、個々のグループを delay(i * 500) で500msec間隔で浮上開始させ、同じく500msec間隔で文字の縮小を始めてます。


7. bl.ocks.org

今回D3.jsの情報を集めてるときに知ったんですけど、 bl.ocks.org は便利ですね。bl.ocks.org の情報は こちら からどうぞ。

要はGistの情報を綺麗に表示してくれるページで、HTMLやJS, CSSがあればそれも一緒に動きますよってサービスですね。

htmlとjs, cssを組み合わせて動作確認やシェア出来るサービスは結構ありますが、この bl.ocks.org は見た目も良いしJSも自動的に開始されるしなかなかいいサービスです。

要望があるとすると、FacebookやG+で共有するときに thumbnail.png を共有時の画像としてくれるともっと活用の巾が広がるだろうなとか思いますね。まあ、仕組みは簡単そうなんで自分で作れってことですけど。

そういえば、Gistへの画像登録がなかなかクセモノでした。WebUIからアップロードできそうなのですが、Chromeではうまくアップロードできませんでした。

でも、そういう場合はGitでローカルにクローンを作成して thumbnail.pngcommit してプッシュすれば問題なくアップすることが出来ますね。


8. まとめ

今回はD3.jsを利用してネタサンプルを作り、 bl.ocks.org で共有するということをやってみました。

動きの調整に少し時間を取られましたが、D3.jsの出来もいいし bl.ocks.org での公開も Gist に登録するだけだしで本当に簡単です。いい時代ですね。

ネタで使いたい場合は、ヒアドキュメントの部分だけを変更して自分のGistに登録するだけです。自由にどうぞ!