読者です 読者をやめる 読者になる 読者になる

jnobuyukiのブログ

JavaScriptとR言語を中心に研究活動に役立つwebアプリケーション技術について考えていきます。twitter ID: @j_nobuyuki

Google Chartsのtransitionアニメーション

グラフにアニメーションを適用して、分かりやすく示すと言えば、このブログでは今のところd3.jsの独壇場です。でも、もちろんそれ以外のライブラリも利用できます。今回は、Google chartsのtransitionを使ってみます。

ポイント:インスタンス生成は最初の一回のみ

アニメーションが生成されるために大事なポイントは、chart変数に一度、Google.visualizationクラスのオブジェクトを生成したら、そのインスタンス(という言い方でいいのか分からないのですが…)を作り直さないことです。データはもう一度生成しても問題なさそうです。

データの変更方法

色々なやり方で良いようです。今回の例の場合は以下の二つを考えてみました。

  • オリジナルデータから表示に必要なデータを作成して、チャートに代入する
  • すでにチャートに代入されたデータを加工する

実際にやってみたところ、二つの方法ではコードの書き方は少し違いますが、全く同じ結果が得られました。

optionにアニメーションパラメータを加える

transitionでは、何秒かけてやるか(duration)と動作(easing)をanimationというパラメータで決定します。例えばanimation:{duration:2000, easing: 'linear'}とすると2秒かけて、一定のスピードでtransitionアニメーションが実行されます。

例:棒グラフにカテゴリーごとの表示機能をつける

では、実例として、以前「Google Chartsを利用した棒グラフの作成」で紹介した棒グラフにカテゴリーごとの表示ができるようなボタンを設定してみましょう。なおこの例では、データを加工する方法を示します。

HTML:ボタンを作る

今回は「最高気温」「最低気温」「最高最低気温」という3つのラジオボタンを作ります。

<form>
    <input type = "radio" name = "sel" value = "max" onclick = "drawChart();" >最高気温<br>
    <input type = "radio" name = "sel" value = "min" onclick = "drawChart();">最低気温<br>
    <input type = "radio" name = "sel" value = "all" onclick = "drawChart();" checked >最高最低気温<br>
</form>

nameをそろえておくとあとで、どのボタンが押されているかを判定できます。また、いずれかのボタンが押されるたびにdrawChart()という関数が実行されるようになっています。

JavaScript その1:データの作成・読み込みと初期設定

前回使ったデータをそのまま使います。また、google.visualizationクラスの設定については説明を省略します。

var oridata = [
              ["date","tempmax","tempmin"],
              ["12/11",12.8,7.3],
              ["12/12",13.2,7.9],
              ["12/13",14.9,4.1],
              ["12/14",11.2,4.6],
              ["12/15",11.4,2.8],
              ["12/16",11.9,5.4],
              ["12/17",12,7],
              ["12/18",8.8,3.6],
              ["12/19",7.6,3.7],
              ["12/20",9.4,3.3],
              ["12/21",11,2.8],
              ["12/22",11.4,5.5],
              ["12/23",8.4,4.4],
              ["12/24",12.5,4.5],
              ["12/25",10.3,3.3],
              ["12/26",10,3.4],
              ["12/27",9.4,5.1],
              ["12/28",9.3,2.7],
              ["12/29",9.5,0.5],
              ["12/30",10.5,0.6],
              ["12/31",12.7,1.3],
              ["1/1",15.5,3.1],
              ["1/2",12.1,3.1],
              ["1/3",8.5,3.8],
              ["1/4",11.7,2.4],
              ["1/5",7.3,3.9],
              ["1/6",10.5,2.1],
              ["1/7",9.9,1.9],
              ["1/8",12.8,2.8],
              ["1/9",11.8,3],
              ["1/10",6.8,1.4],
              ["1/11",9,0.7]
    ];

google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
var prev = "initialstate";
var data;
var chart;

ボタンが押される直前にどのラジオボタンのチェックがついていたかを示す変数としてprevを用意します。その初期値としてinitialstateという文字列を代入しておきます。また、dataとchartを関数の外で宣言しておくことで、グローバルスコープを持たせます。

JavaScript その2:データの編集機能をdrawChart()に追加

drawChart()の主要な部分は前回と同様なので説明を省略します。

function drawChart() {
    if (prev == "initialstate") {
       data = google.visualization.arrayToDataTable(oridata);
       chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
   
    }

まずは、最初の1回でdataにデータを代入し、chart_divという名前のdivにCoulmnChartオブジェクトを設定します。オブジェクトの設定をこの1回だけにすることで、あとはdrawChartが呼び出される度にtransitionアニメーションが実行されます。

    var radioList = document.getElementsByName("sel");
    var inputvalue;
    for (var i = 0;i<radioList.length;i++) {
            if(radioList[i].checked) {
                inputvalue = radioList[i].value;
                console.log(inputvalue);
                var j = 0;

                switch (inputvalue) {
                    case "max":
                        if (prev == "min") {
                            //min to max
                            for (j = 0;j<data.getNumberOfRows();j++){
                                data.setValue(j,1,oridata[j+1][1]);
                            }
                           
                        } else {
                            //all to max
                            data.removeColumn(data.getNumberOfColumns() - 1);
                           
                        }
                        break;
                    case "min":
                        if (prev == "max") {
                            //max to min
                            for (j = 0;j<data.getNumberOfRows();j++){
                                data.setValue(j,1,oridata[j+1][2]);
                            }
                        
                        } else {
                            //all to min
                            console.log("debug");
                            data.removeColumn(data.getNumberOfColumns() -1);
                            for (j = 0;j<data.getNumberOfRows();j++){
                                data.setValue(j,1,oridata[j+1][2]);
                            }
                        
                        }
                        break;

                    case "all":
                        if (prev == "min") {
                        // min to all
                            for (j = 0;j<data.getNumberOfRows();j++){
                                data.setValue(j,1,oridata[j+1][1]);
                            }
                            data.addColumn('number','tempmin');
                            for (j = 0;j<data.getNumberOfRows();j++){
                                data.setValue(j,2,oridata[j+1][2]);
                            }
                            
                            break;
                        } else if(prev == "max") {
                            //max to all
                            data.addColumn('number','tempmin');
                            for (j = 0;j<data.getNumberOfRows();j++){
                                data.setValue(j,2,oridata[j+1][2]);
                            }
                            break;
                        } else{
                            break;
                        }
                }
         }
   }

ここではまず、radioListにどのボタンが押されているのかを判定させます。html内のselという名前のボタンの情報をリストして読み込み、それぞれのcheckedパラメータの真偽を調べます。結果が真ならばそのボタンのvalueがinpuvalueに代入されます。次の部分はinputvalueとprevによる場合分けです。data.addColumnでは列の追加、data.removeColumnでは列の削除を行っています。列を追加したら、data.setValueで値を書き込みます。setValueの引数は3つで(行番号,列番号,値)です。

    chart.draw(data, options);
    prev = inputvalue;

最後にdataと後述のoptionsを利用したグラフの描画が行われます。さらに次回のために、今回押されたボタンの情報をprevに保存しておきます。

JavaScript その3:optionsの追加

多次元のオブジェクトになっているのがポイントです(詳細は省略します)。

    var options = {
    title: 'Temperature in Tokyo',
    hAxis: {title: 'DATE'},
    animation: { duration: 2000, easing: 'linear'},
    bar: {groupWidth: "100%"},
    colors: ['red', 'blue']};

transitionアニメーションに関わるのは、animation:{duration:2000, easing:'linear'}の部分です。easingは他に'in'、'out'などの値もあります。

ここまでをまとめると以下のようになります。



まとめ:transitionアニメーションは使い方に注意

以上みてきたようにGoogleChartsでは簡単にtransitionアニメーションを設定できます。最後に注意として、アニメーション効果の使い方を考えておきます。棒グラフで棒がにょきにょきと生えてくるのは、それ自体がとても面白いです。特に最初の一回は「おっ」と思わせられるかもしれません。つまり、とてもインパクトのある効果であり、伝えたい内容とアニメーションの動作がピッタリはまると見たい人に強烈な印象を与えられます。ただし以下の2点には要注意です。

  • アニメーションにインパクトを持たせ過ぎて大事なメッセージを忘れさせないようにする
  • 何度もアニメーションを使うとあっというまに見る人は慣れるし、飽きるので、繰り返しにリズムを持たせる、何度も使わないなどの工夫をする