R&Dトレンドレポート

第20回マッシュアップ開発のススメその6:PC版フロントエンドの構成③]

前回に続いて今回もPCのフロントエンドの説明となります。今回はグラフ表示機能の説明です。

グラフ表示機能について

グラフの横軸は時系列となり、これは動画再生時間全体となります。グラフの縦軸は時系列に対するポストされたコメントの頻度を表します。つまり、縦軸に高いほど、多くのコメントがその時間帯にポストされたことを意味し、そこがその動画のスイートスポットである、というわけです。

またこのグラフにはそういった盛り上がり点を表現する以外に、以下の3つの機能を持たせました。

  • 動画の再生位置をグラフ上で表現すること
  • グラフのクリックから動画の再生位置をスキップさせること
  • グラフのオンマウスオーバーでその位置のスクリーンショットのサムネイルを表示する(シーン選択が容易になるように)

動画からの経過時間を横軸に反映し、グラフからは逆に、インタラクティブな操作で動画の再生位置を変える、再生位置を変える前にサムネイルで何となく雰囲気を知ることができるという、双方向のコントローラとなります。

この機能のために用いたのが、グラフライブラリの1つであるHighchartsです。こちらもデモを参照していただけるとわかりやすいと思いますが、非常に柔軟なグラフ描画と美しいデザイン、アニメーションを備えています。棒グラフ、円グラフ、パイチャートなどさまざまなグラフを簡単に使うことが可能です。

Highchartsでのグラフの生成

Highchartsのソースの読み込み
<script type="text/javascript" src="js/highcharts.src.js"></script>

グラフはChartメソッドで初期化しますが、その際にオブジェクトを引数に与えますが、そのオブジェクトによってどのようなグラフを生成するかが決定します。

Highchartsの初期化部分
var chart = new Highchars.Chart(options); //optionがオブジェクト

それでは渡されるオブジェクトの内容です。

var options = 
{
   credits: {
       enabled: false,
   },

   // 描写先やグラフのタイプを指定する
   chart: {
     renderTo: "myChart", //グラフ表示先のDIV要素のIDを指定する。
     defaultSeriesType: "spline",
     margin: [50, 150, 60, 80],
     marginRight: 20,
     marginLeft: 60,
   },

   // グラフのタイトルとデザイン
   title: {
     text: "盛り上がりグラフ",
     style: {
       margin: "10px 100px 0 0" // center it
     }
   },

   // グラフのサブタイトルとデザイン
   subtitle: {
     text: "[二][文]金曜ロードショー「アルマゲドン」(1998年米)"+
       "J・J・エイブラムスほか脚本マイケル・ベイ監督ブルース・ウィリスベン・アフ",
     style: {
       margin: "0 100px 0 0" // center it
     }
   },

   // グラフの横軸のメモリと単位
   xAxis: {
     title: {
       text: "時間"
     }
   },

   // グラフの縦軸のメモリと単位
   yAxis: {
     title: {
       text: "res数"
     }
   },

   // グラフ頂点でのツールチップ表示の方法
   tooltip: {
     formatter: function() {
     return "<strong>"+ this.series.name +"</strong>"+  // HTMLが使える
     mktime(this.x*asec) +": "+ this.y +" (回)";
     },
     // グラフ上のポインターの位置にドットのラインを引く。
     crosshairs: {
        width: 2,
        color: 'gray',
        dashStyle: 'shortdot'
     }
   },

   // 表示するデータを配列形式で保持する
   // 今回の場合は2つのデータを描画する。
   // 一つは時間単位の2chの総コメント数で、もう一つはtwitterの総コメント数。
  series: [
   {"name":"2chのres数","data":
    [119,177,307,523,387,513,487,464,284,331,156,99,96,117,
    162,354,213,189,593,385,170,362,420,392,703,567,527,390,
    485,346,353,263,310,257,175,207,271,269, 247,469,130,123,
    421,510,361,371,361,276,419,553,61,124,224,782,670,1097,736]
   },
   {"name":"twitterのres数","data":
    [101,138,196,304,262,333,299,284,205,224,127,76,79,87,128,259,
    168, 149,400,298,137,278,332,291,470,387,389,305,337,272,277,210,
    240,219,145,177,207,206,176,324,107, 86,313,353,256,259,288,214,
    301,391,54,100,182,489,425,657,558]
   }
  ],

  // クリックやマウスオーバーの処理を記述。
  plotOptions: 
  {
    series: //seriesに対するオプションを設定する
    {
      point: // 頂点についてイベントを設定する
      {
        events: 
        {
          click: function() { //clickイベントを定義。
              var seektime = (this.x * asec);  // 横軸の値を動画再生時間に変換する
              myvid.currentTime = seektime; // 動画の再生位置を変更する。
            },
          mouseOver: function() { //mouseOverイベントを定義
              showImg(this.x); // サムネイル画像を表示する。
            }
        }
      },
      marker: {
        enabled: false,
      }
    },
  }
};

インタラクティブな操作(グラフ→動画、サムネイル)

赤字の部分と青地の部分が、動画とサムネイルに対してインタラクティブな動きを実装したモノです。その他の部分はCGIで出力するときに静的に値を埋め込んでいます。

this.xはseries->data->で参照される配列の数を表しています。asec変数は1目盛における実際の秒数になります。今回は120秒毎に頻度をカウントしていますので、asecには120が入ります。

また、seriesに複数のオブジェクトを設定できますので、複数のグラフを表現することが可能です。今回は、2chのコメント数とtwitterのコメント数を表現しています。

次はマウスオーバーでサムネイル画像を呼び出しているところです。

function showimg(x)
{
  //DIVのID、thum配下にimg要素を作成します。
  $("#thum").empty();  // thum要素以下のimgを排除します。
  
  // img要素を動的に作成する。サムネイル画像は事前に作成されているモノとする。
  var im = $("<img>").attr("src", "/jikkyou/data/"+ id + "-" + (asec * x) + ".png");
  
  $("#thum").append(im); // DIV配下に追加する。
  C
  im.css("position", "absolute"); 
  // 表示位置をグラフ上のポインター位置に合わせる。グラフの大きさ(chartwidth)を超えないように
  // サムネイルの位置を調整する。256とか20とかの直値は使わない方がいいですね^^;
  im.css("left", (( chartwidth - 256 ) * (asec * x ) / totaltime ) + 20 );
}

これでグラフ上をマウスオーバーで滑らせることでサムネイルがぱらぱらと変わっていきます。

インタラクティブな操作(動画→グラフ)

以上でグラフから別のオブジェクトへの操作が可能となりました。それでは、動画からグラフに対するアクションの部分を紹介します。

var myvid = $("#myVid")[0];

myvid.addEventListener("timeupdate", function(){
  var t = Math.floor(myvid.currentTime); //現在の再生時間を整数に

  // chartはHighchartsで作成したグラフ
  chart.xAxis[0].removePlotLine("plot-line-1"); //グラフのマーカーを削除

  chart.xAxis[0].addPlotLine({
    value: myvid.currentTime / asec, // X軸(時間軸)に対して再生位置にマーカーを引く
    color: "red",
    width: 2,
    id: "plot-line-1"
  });

  // 再生時間がupdateSecで割り切れた場合。多重取得防止。
  if ( t % updateSec == 0 && t != tTime )
  {
    tTime = t;
   getRes(); // コメントを取得する。
 }
});

実は以前紹介したコメント取得の部分に含まれていたのですが、改めて説明します。

動画再生時に都度呼び出されるtimeupdateイベントで、グラフオブジェクトのX軸に対し、addPlotLine()関数を用いて動的にプロット位置に線を引いています。currentTimeをasecで割っているのは先ほどのグラフから動画の再生位置を変更するのと逆の計算となります。削除、追加を行うことで、必ずプロット線が1本しか発生しないようにしています。

また、ユーザが強制的に再生位置を変えた場合もtimeupdateイベントがファイアーするため、その際もグラフへのフィードバックが期待できます。

こんな風になりました

それでは実際のグラフの様子を見てみましょう。

画像

動画は「アルマゲドン」です。グラフを見ると、盛り上がり部分がよくわかると思います。最後の盛り上がりはすごいですね! 2分間で1,000コメントを超えています。

以上がグラフと動画、サムネイルの説明でした。このようにインタラクティブな要素が入るとアプリとして成長する感じがしますね!

コーディングも楽しくなります。

おすすめ記事

記事・ニュース一覧