Angular JS上で、d3.jsを使用した円グラフアニメーション作成

エンジニアの土屋と申します。 今回はAngular JS上で円グラフをアニメーション表示させる事をやって見まし…

エンジニアの土屋と申します。

今回はAngular JS上で円グラフをアニメーション表示させる事をやって見ました。

グラフアニメーションですが、バーグラフなどはgoogle Chartで可能なのですがなぜか、
円グラフは対応してませんでした。。

色々調べた結果、d3.jsを使って円グラフのアニメーションを作成してみることにしました。
URL:https://d3js.org/
参考URL:http://ja.d3js.info/alignedleft/tutorials/d3/

・d3.jsとは
D3は(Data Driven Document)の略で、JSON、XML、CSV、タブ区切りテキスト、
javascriptの配列などの様々な形式のデータを可視化する時に便利なライブラリです。

ちなみにアニメーションイメージは真上からくるっと一周して円グラフが描画される感じです。

・準備
動作させる環境は、毎度おなじみAngular JSです。
導入は超簡単です。app/index.htmlに本体ファイルを読み込むよう設定してあげれば
オッケーです。

  <script src="http://d3js.org/d3.v3.min.js"></script>

・実装
コントローラー部分の実装を抜粋します。

controllers/piechart.js

    //円グラフアニメーション
    this.createPieChartAnimation = function(selections) {
  
      // サイズを設定
      // ウィンドウサイズによって可変する
      var size = {
        width : 240,
        height: 240
      };

      //要素/(要素の合計)x100
      var percent_1 = selections[0].selected_count/(selections[0].selected_count + selections[1].selected_count) * 100;
      var percent_2 = selections[1].selected_count/(selections[0].selected_count + selections[1].selected_count) * 100;

      //四捨五入する   
      percent_1 = Math.round(percent_1);
      percent_2 = Math.round(percent_2);
      // 円グラフの表示データ
      var legendData1 = selections[0].body + " " + percent_1 + "%";
      var legendData2 = selections[1].body + " " + percent_2 + "%";

      var data = [
        {legend:legendData1, value:selections[0].selected_count, color:"#e74c3c"},
        {legend:legendData2, value:selections[1].selected_count, color:"#3498db"},
      ];
  
      // d3用の変数
      var win   = d3.select(window), //リサイズイベントの設定に使用します
          svg   = d3.select("#chart"),
          pie   = d3.layout.pie().sort(null).value(function(d){ return d.value; }),
          arc   = d3.svg.arc().innerRadius(0);
      
      // アニメーション終了の判定フラグ
      var isAnimated = false;
           
      // グラフの描画
      // 描画処理に徹して、サイズに関する情報はupdate()内で調整する。
      function render(){
      
        // グループの作成
        var g = svg.selectAll(".arc")
          .data(pie(data))
          .enter()
          .append("g")
            .attr("class", "arc");
      
        // 円弧の作成
        g.append("path")
          .attr("stroke", "white")
          .attr("fill", function(d){ return d.data.color; });
      
        // データの表示
        var maxValue = d3.max(data,function(d){ return d.value; });
      
        g.append("text")
          .attr("dy", ".35em")
          .attr("font-size", function(d){ return d.value / maxValue * 16; }) //最大のサイズを16に
          .attr("fill", "white")
          .style("text-anchor", "middle")
          .text(function(d){ return d.data.legend; });
      }
            
      // グラフのサイズを更新
      function update(){
      
        // 自身のサイズを取得する
        size.width = parseInt(svg.style("width"));
        size.height = parseInt(svg.style("height")); //←取得はしていますが、使用していません...
      
        // 円グラフの外径を更新
        arc.outerRadius(size.width / 2);
      
        // 取得したサイズを元に拡大・縮小させる
        svg
          .attr("width", size.width)
          .attr("height", size.width);
      
        // それぞれのグループの位置を調整
        var g = svg.selectAll(".arc")
          .attr("transform", "translate(" + (size.width / 2) + "," + (size.width / 2) + ")");
      
        // パスのサイズを調整
        // アニメーションが終了していない場合はサイズを設定しないように
        if( isAnimated ){
          g.selectAll("path").attr("d", arc);
        }
      
        // テキストの位置を再調整
        g.selectAll("text").attr("transform", function(d){ return "translate(" + arc.centroid(d) + ")"; });
      }
            
      // グラフのアニメーション設定
      function animate(){
        var g = svg.selectAll(".arc"),
            length = data.length,
            i = 0;
      
        g.selectAll("path")
          .transition()
          .ease("cubic-out")
          .delay(500)
          .duration(1000)
          .attrTween("d", function(d){
            var interpolate = d3.interpolate(
              {startAngle: 0, endAngle: 0},
              {startAngle: d.startAngle, endAngle: d.endAngle}
            );
            return function(t){
              return arc(interpolate(t));
            };
          })
          .each("end", function(transition, callback){
            i++;
            isAnimated = i === length; //最後の要素の時だけtrue
          });
      }
            
      // 初期化
      render();
      update();
      animate();
      win.on("resize", update); // ウィンドウのリサイズイベントにハンドラを設定
  
    };

view側も非常に簡単です。表示させたいviewファイルに以下を書けばグラフが表示されます。

views/piechart.html

<svg style="width:70%;" id="chart"></svg>

・結果
以下のようにグラフを動作させることができました。
※アニメーションしない場合は画像を右クリックで別画面で表示させてください。

・終わりに
以上、簡単に説明させていただきましたがd3はその他色々なことができるみたいで機会がありましたら
他の実装も試してみたいです。

今回参考にさせていただきましたD3のチュートリアルを書いているスコット・マレイさんは自らを
「code artist」と肩書きをつけていました。ちょっとかっこいいなぁと思いました。