SELECTED ENTRIES
CATEGORIES
ARCHIVES
SPONSORED LINK
MOBILE
qrcode
LINKS
PROFILE
OTHERS

05
--
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
--
>>
<<
--

Agata's Blog

Python+pandasとD3.jsを使ってデータ解析とデータビジュアライゼーションに挑戦する某エンジニアのBlog
【D3.js】 折れ線グラフの作成
0
    JUGEMテーマ:JavaScript

    D3.js によるデータ可視化について紹介しているこのブログですが、そういえばまだ折れ線グラフの作例を紹介していませんでした。せっかくなので、これまで取り上げたいろいろなメソッドを織り交ぜながら、日経平均株価のデータを例に折れ線グラフを作成してみましょう。

    まずは日経平均株価のデータをもとに、CSVファイルを準備します。今回は次のようなCSVファイルを読み込んだうえで、終値の変化を折れ線グラフで表示するプログラムを作成します。

    ■nikkei.csv
    日付,始値,高値,安値,終値
    2016/2/1,17699.60,17905.37,17666.48,17865.23
    2016/2/2,17716.52,17864.70,17684.66,17750.68
    ・・・・
    2016/2/25,15983.47,16218.29,15953.93,16140.34

    サンプルページ


     
    // X,Y軸を表示できるようにグラフの周囲にマージンを確保する
    var margin = {top: 40, right: 80, bottom: 80, left: 80};
    var width = 800 - margin.left - margin.right;
    var height = 500 - margin.top - margin.bottom;
     
    // CSVファイルの読み込み
    d3.csv("./js/nikkei.csv", function(error, dataSet){
    
      // SVGの表示領域を生成
      var svg = d3.select("#MyGraph")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + ", " + margin.top + ")");
        
      // 読み込んだCSVデータから時間軸の両端を抽出
      var n = dataSet.length;
      time_start = new Date(dataSet[0]["日付"]);
      time_end = new Date(dataSet[n-1]["日付"]);
      
      // 時間軸のスケール関数を生成
      var time_scale = d3.time.scale()
        .domain([time_start, time_end])
        .range([0, width]);
      
      // 縦軸のスケール関数を生成
      var y_scale = d3.scale.linear()
        .domain([14000,18000])
        .range([height, 0]);
    
      var line = d3.svg.line()
        .x(function(d,i){
          var tmp = new Date(d["日付"]);
          return time_scale(tmp);
        })
        .y(function(d,i){
          return y_scale(d["終値"]);      
        });
        
      // 折れ線グラフを生成
      svg.append("path")
        .attr("class", "line")
        .attr("d", line(dataSet));
      
      // X軸を描画
      svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.svg
          .axis()
          .scale(time_scale)
          .orient("bottom")
          .tickFormat(function(d,i){
            var fmtFunc = d3.time.format("%b-%d");
            return fmtFunc(d);
          })
        )
        .selectAll("text")
        .attr("transform", "rotate(45)")
        .attr("dy", 10)
        .attr("dx", 10)
        .style("text-anchor", "start");
      
      // Y軸を描画
      svg.append("g")
        .attr("class", "axis")
        .call(d3.svg.axis()
          .scale(y_scale)
          .orient("left")
        );
    });
    
    


     
    このエントリーをはてなブックマークに追加
    | D3.js | 00:14 | comments(0) | - | - |
    D3.js を使った時計・その2
    0
      JUGEMテーマ:JavaScript

      以前このブログで、D3.js のパイチャートとアニメーション機能を使った時計の作例を紹介しました。今回は、前回の記事で取り上げた SVG のドロップシャドウを使って、背景から時刻が浮かび上がってくるデジタル時計を作ってみます。

      ドロップシャドウでは、feGaussianBlur の stdDeviation をゼロとして、なおかつ feOffset で 2 つの SVG 要素をずらす量もゼロとすると、影のない SVG 要素だけが表示されます。circle 要素や rect 要素ではその通りうまくいくのですが、この時計を作っているなかで、なぜか text 要素だけはどうしてもうっすら輪郭が残ってしまうことが分かりました。そこで今回のプログラムでは苦肉の策として、白い rect 要素を定期的に上から覆いかぶせて、うっすら残るテキスト要素の輪郭を画面表示から隠しています (42〜48行目と84〜87行目) 。

      サンプルページ


      ■ JavaScript プログラム
      var width = 500;
      var height = 300;
       
      svg = d3.select("#MyGraph")
        .attr("width", width)
        .attr("height", height);
      
      // #drop-shadow という ID のフィルタを定義
      var filter = svg.append("defs")
        .append("filter")
        .attr("id", "drop-shadow")
        .attr("height", "130%");
      
      // 元となるSVG要素をぼかして影を作る
      var feGaussianBlur = filter.append("feGaussianBlur")
          .attr("in", "SourceAlpha")
          .attr("stdDeviation", 3)
          .attr("result", "blur");
      
      // 作った影の表示位置を少しずらす
      var feOffset = filter.append("feOffset")
          .attr("in", "blur")
          .attr("dx", 5)
          .attr("dy", 5)
          .attr("result", "offsetBlur");
          
      // 2つの入力画像 (元のSVG要素と影) を重ねて表示       
      filter.append("feBlend")
        .attr("in", "SourceGraphic")
        .attr("in2", "blurOut")
        .attr("mode", "normal");
       
      var item = svg.append("text")
        .text("Text")
        .attr("x", width/2)
        .attr("y", height/2)
        .attr("text-anchor", "middle")
        .attr("font-size", "100px")
        .style("fill", "white")
        .style("filter", "url(#drop-shadow)");
      
      var mask = svg.append("rect")
        .attr("x", 0)
        .attr("y", 0)
        .attr("height", height)
        .attr("width", width)
        .style("fill", "white")
        .style("fill-opacity", 1);
        
      // 影の位置とぼかしの強さを変化させて、SVG要素が画面から浮かび上がるようにアニメーション
      var dest_min = 0, dest_max = 5, dest = dest_min;
      var std_min = 0, std_max = 3, std = std_min;
      var opa_min = 1, opa_max = 0, opa = opa_min;
      
      // 現在時刻を取得して変数 now に保存
      var now = new Date();
      
      var updateTime = function(){
        now = new Date();
      };
      
      var floater = function() {
        if (dest == dest_min) {
          dest = dest_max;
          std = std_max;
          opa = opa_max;
          updateTime();
        }
        else {
          dest = dest_min;
          std = std_min;
          opa = opa_min;
        }
        item.transition()
          .duration(1000)
          .text(now.toLocaleTimeString());
        feOffset.transition()
          .duration(1000)
          .attr("dx", dest)
          .attr("dy", dest)
        feGaussianBlur.transition()
          .duration(1000)
          .attr("stdDeviation", std)
        mask.transition()
          .duration(1000)
          .style("fill-opacity", opa)
          .each("end", floater);
      };
      
      floater();
      

       
      このエントリーをはてなブックマークに追加
      | D3.js | 00:52 | comments(0) | - | - |
      【D3.js】SVGにドロップシャドウをかけて立体的にする
      0
        JUGEMテーマ:JavaScript

        SVG では filter 要素を使って、画像をぼかしたり色を変えたりすることができます。この filter 要素をうまく使うと、画像の背後に影をつけて、あたかも背景から浮かび上がったような視覚的効果を出すことができます。今回は D3.js を使って、この「ドロップシャドウ」(drop-shadow) と呼ばれる効果を試してみました。

        とはいえ、ただ単純に SVG 要素にドロップシャドウ効果を加えるだけでは D3.js を使う意味がないので、filter 要素のパラメータを変化させて SVG 要素が背景から徐々に浮かび上がるようなアニメーションにしてみました。
        var width = 800;
        var height = 500;
        
        svg = d3.select("#MyGraph")
          .attr("width", width)
          .attr("height", height);
        
        // #drop-shadow という ID のフィルタを定義
        var filter = svg.append("defs")
          .append("filter")
          .attr("id", "drop-shadow")
          .attr("height", "130%");
        
        // 元となるSVG要素をぼかして影を作る
        var feGaussianBlur = filter.append("feGaussianBlur")
            .attr("in", "SourceAlpha")
            .attr("stdDeviation", 3)
            .attr("result", "blur");
        
        // 作った影の表示位置を少しずらす
        var feOffset = filter.append("feOffset")
            .attr("in", "blur")
            .attr("dx", 5)
            .attr("dy", 5)
            .attr("result", "offsetBlur");
        
        // 2つの入力画像 (元のSVG要素と影) を重ねて表示    
        filter.append("feBlend")
          .attr("in", "SourceGraphic")
          .attr("in2", "blurOut")
          .attr("mode", "normal");
         
        var item = svg.append("rect")
          .attr("x", 100)
          .attr("y", 100)
          .attr("width", width/4)
          .attr("height", height/4)
          .style("fill", "white")
          .style("filter", "url(#drop-shadow)");
        
        var item2 = svg.append("circle")
          .attr("cx", 500)
          .attr("cy", 300)
          .attr("r", 50)
          .style("fill", "white")
          .style("filter", "url(#drop-shadow)");
        
        // 影の位置とぼかしの強さを変化させて、SVG要素が画面から浮かび上がるようにアニメーション
        var dest_min = 0, dest_max = 5, dest = dest_min;
        var std_min = 0, std_max = 5, std = std_min;
        
        var floater = function() {
          if (dest == dest_min) {
            dest = dest_max;
            std = std_max;
          }
          else {
            dest = dest_min;
            std = std_min;
          }
          feOffset.transition()
            .duration(3000)
            .attr("dx", dest)
            .attr("dy", dest);
          feGaussianBlur.transition()
            .duration(3000)
            .attr("stdDeviation", std)
            .each("end", floater);
        };
        
        floater();
        

        サンプルページ

        このエントリーをはてなブックマークに追加
        | D3.js | 08:17 | comments(0) | - | - |
        【D3.js】ボロノイ図の作成
        0
          JUGEMテーマ:JavaScript

          ユークリッド平面上に複数の点が配置されているとき、どの点に最も近いかによってその平面を分割した図のことを「ボロノイ図 (Voronoi diagram)」と言います。 平面上に配置した点のことを「母点」と呼び、母点を 1 個含む分割された各領域のことを「ボロノイ領域」と呼びます。そして、隣接するボロノイ領域の境界のことを「ボロノイ境界」と言います。

          D3.jsには、ボロノイ図を作成するための d3.geom.voronoi() というメソッドが用意されています。今回は、このメソッドを使ったボロノイ図の作成方法を紹介します。
          var width = 960;
          var height = 540;
          var margin = 5;
          
          // D3.jsが用意する標準20色
          var color = d3.scale.category20c();
          
          // ボロノイ図の母点 100 個をランダムに生成
          var point = [];
          
          for(var k=0; k<100; k++){
            var x = margin+(width-2*margin)*Math.random();
            var y = margin+(height-2*margin)*Math.random();
            point.push([x,y]);
          }
          
          // ボロノイ図を作成
          draw_voronoi();
          
          // ボロノイ図を作成するための関数 draw_voronoi() を定義
          function draw_voronoi(){
            svg = d3.select("#MyGraph")
              .attr("width", width)
              .attr("height", height);
          
            var voronoiData = d3.geom.voronoi();
          
            // ボロノイ境界を計算しSVG要素として描画
            var voronoiPath = svg.selectAll("path")
              .data(voronoiData(point))
              .enter()
              .append("path")
              .attr("class", "voronoi")
              .attr("d", function(d,i){
                return "M" + d.join("L")+"Z";
              })
              .style("stroke", "white")
              .style("stroke-width", 2)
              .style("fill-opacity", 0.8)
              .style("fill", function(d,i){
                  return color(i%20);
              });
            
            // 母点をSVG要素のcircleとして追加
            var pointElement = svg.selectAll("circle")
              .data(point)
              .enter()
              .append("circle")
              .attr("cx", function(d,i){
                return d[0];
              })
              .attr("cy", function(d,i){
                return d[1];
              })
              .attr("r", 2)
              .attr("fill", "black");
          };
          
          サンプルページ



           
          このエントリーをはてなブックマークに追加
          | D3.js | 21:48 | comments(0) | - | - |
          【D3.js】 zoom メソッドの基本
          0
            JUGEMテーマ:JavaScript

            D3.jsには、ブラウザ上でのユーザ操作 (クリックやドラッグ) に応じてSVG要素を変化させるための behaviour メソッドが用意されています。2 種類ある behaviour メソッドのうち、前回は drag() メソッドを紹介しました。今回は、drag() メソッド以上にあまり紹介されることのないもう一つのメソッド、zoom() メソッドの基本的な使い方を紹介します。

            zoom() メソッドを使うと、マウスのダブルクリックやホイール操作を使って、ページ上のSVG 要素をユーザがアダプティブ拡大・縮小できる、インタラクティブなウェブページを作成することができます。そんな zoom() メソッドを使って、こんなサンプルページを作ってみました。
            var width = 800;
            var height = 500;
            
            // 57行目以下でSVG要素の円を20個追加するための配列
            var numData = d3.range(1,20);
            
            // zoomビヘイビアの設定
            var zoom = d3.behavior.zoom()
              .scaleExtent([0.1, 10])
              .on("zoom", function(){
                container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
              });
            
            // SVG を zoom ビヘイビアに渡す
            var svg = d3.select("#MyGraph")
              .attr("width", width)
              .attr("height", height)
              .append("g")
              .attr("transform", "translate(0,0)")
              .call(zoom);
            
            var container = svg.append("g");
            
            // pointer-events = all でマウスイベントをSVGの描画範囲全体で拾うよう設定
            var rect = svg.append("rect")
              .attr("width", width)
              .attr("height", height)
              .style("fill", "none")
              .style("pointer-events", "all");
            
            //====================================
            // 34行目以下は zoom ビヘイビアのテスト用のSVG要素
            //====================================
            container.append("g")
              .attr("class", "x axis")
              .selectAll("line")
              .data(d3.range(0, width, 10))
              .enter()
              .append("line")
              .attr("x1", function(d) { return d; })
              .attr("y1", 0)
              .attr("x2", function(d) { return d; })
              .attr("y2", height);
            
            container.append("g")
              .attr("class", "y axis")
              .selectAll("line")
              .data(d3.range(0, height, 10))
              .enter()
              .append("line")
              .attr("x1", 0)
              .attr("y1", function(d) { return d; })
              .attr("x2", width)
              .attr("y2", function(d) { return d; });
            
            // SVG要素の円を20個追加して、60秒間アニメーション
            container.append("g")
              .selectAll("circle")
              .data(numData)
              .enter()
              .append("circle")
              .attr({
                "cx" : function(d){return Math.random() * width},
                "cy" : function(d){return Math.random() * height},
                "r" : 10,
                "fill-opacity" : 0.8,
                "fill" : "orange"
              })
              .transition()
              .duration(60000)
              .ease("linear")
              .attr({
                "cx" : function(d){return Math.random() * width},
                "cy" : function(d){return Math.random() * height},
              });
            

            サンプルページ



            前回の drag() メソッドと同じように、8〜12行目で zoom() ビヘイビアを設定しています。9行目では拡大率の最大・最小を設定しています。その後、20行目でSVGをこの zoom() ビヘイビアに渡しています。25〜29行目では、SVG 画像の範囲全体に "pointer-event : all" を設定することで、この範囲内でのマウスイベントを拾ってSVG画像の拡大・縮小ができるようにしています。

            34行目以下は、zoom() メソッドのテスト用に、グリッドとゆっくり動く20個のオレンジ色の円を描画してみました。

            興味深いことに、zoom() メソッドを使うとSVGの拡大・縮小だけではなくて、なぜかドラッグもできるようになるようです。behaviour メソッドのサンプルプログラムで、ときどき zoom() メソッドと drag() メソッドの両方を使ったプログラムを見かけますが、プログラム作成上は zoom() メソッドだけでも十分なのかもしれません。
             
            このエントリーをはてなブックマークに追加
            | D3.js | 22:45 | comments(0) | - | - |
            【D3.js】 behaviour メソッドの基本
            0
              JUGEMテーマ:JavaScript

              D3.jsには、ブラウザ上でのユーザ操作 (クリックやドラッグ) に応じてSVG要素を変化させるための behaviour メソッドが用意されています。あまり紹介されることのない behaviour メソッドですが、うまく使いこなすとインタラクティブなウェブページの操作性を向上させることができます。今回は、そんな behaviour メソッドの基本的な使い方を紹介します。

              behaviour メソッドには、大きく drag() メソッドと zoom() メソッドの2種類が用意されています。その名のとおり、描画したSVG要素に対して、ドラッグやズームをするためのメソッドです。今回は drag メソッドを使って、SVG の circle 要素を画面上でドラッグできるようにしてみましょう。
              var svg = d3.select("#MyGraph");
              
              // SVG に circle 要素を追加
              var circle = svg.append("circle")
                .attr({
                  "cx" : 10,
                  "cy" : 10,
                  "r" : 10,
                  "fill-opacity" : 0.8,
                  "fill" : "orange"
                });
              
              // ドラッグビヘイビアを準備
              var drag = d3.behavior.drag()
                .on("drag", function(d){
                  d3.select(this)
                    .attr({
                      "cx" : d3.event.x,
                      "cy" : d3.event.y
                    })
                });
              
              // circle 要素をドラッグビヘイビアに渡す
              circle.call(drag);
              
              サンプルページ

              24行目に出てくる call() メソッドは、メソッドチェーンの上流のSVG要素 (今回の例では circle) を受け取り、関数 (今回の例では drag) に引き渡すメソッドです。これによって当該のSVG要素と drag ビヘイビアがバインドされて、画面上でドラッグできるようになります。
              このエントリーをはてなブックマークに追加
              | D3.js | 18:29 | comments(0) | - | - |
              D3.jsによるアニメーションの動き一覧
              0
                JUGEMテーマ:JavaScript

                前回、D3.jsで時計を作った際に ease("elastic") というメソッドを何の説明もなく使っていました。「これは何だろう?」と思われたかたもいたかもしれませんね。

                実はD3.jsにようアニメーションの動き方を指定するのが ease() メソッドなのです。ease() メソッドの引数として指定できる「動きの種類」と、その動作は以下の通りです。
                 
                ease() メソッドで指定できる動きの種類
                引数 動き方
                linear 一定の速度で変化する動き
                quad やや加速度的な動き
                cubic 加速度的な動き
                sin やや加速度的な動き (quadに近い)
                exp 指数関数的な動き
                circle 加速度的な動き (cubicに近い)
                elastic 弾力的な動き (ターゲットを一時的にオーバーする)
                back 後半に急速に変化する動き
                bounce 弾力的な動き (ターゲットをオーバーしない)

                前回の時計では elastic を指定することで、あの「ぷるん」とした動きを実現していました。

                さて、ease() メソッドの動き方は上の表のように纏めてみたものの、言葉ではなかなか伝わりにくいものがあります。そこで、実際にそれぞれの動きを目で見て確認できるように、こんなプログラムを作ってみました。
                // イージングタイプ一覧
                var method = [
                  "linear", "quad", "cubic", "sin", 
                  "exp", "circle", "elastic", "back", "bounce"];
                
                var svg = d3.select("#MyGraph")
                  .append("g")
                  .attr("transform", "translate(" + 110 + "," + 110 + ")");
                
                // 変化前の円を描画
                svg.append("circle")
                  .attr("class",'target')
                  .attr("r", 10)
                  .attr("fill", "orange");
                
                // 変化後の円のサイズを灰色で描画
                svg.append("circle")
                  .attr("class",'base')
                  .attr("r", 80)
                  .attr("fill-opacity", 0)
                  .attr("stroke", "#f3f3f3")
                  .attr("stroke-width", 2);
                
                var k = 0;
                
                // 適用するイージングタイプを画面上に表示
                svg.append("text")
                  .attr("class",'base_text')
                  .attr("transform", "translate(0, 100)")
                  .attr("text-anchor", "middle")
                  .text(method[k]);
                  
                // 円をクリックすると、イージングタイプに従い円のサイズが変化
                svg.on("click", function(){
                  svg.selectAll(".target")
                    .transition()
                    .duration(1000)
                    .ease(method[k])
                    .attr("r", 80) // 変化後のサイズ
                    .transition()
                    .delay(1500)
                    .duration(250)
                    .ease(method[0])
                    .attr("r", 10) // 元のサイズに戻す
                    .each("end", function(){ // 次に適用するイージングタイプを表示
                      k = (k + 1) % 9;
                      svg.selectAll(".base_text")
                        .transition()
                        .text(method[k]);
                    });
                });
                
                
                サンプルページ



                中心のオレンジの丸をクリックすると、下部に示した動き方で丸が大きくなります。クリックするたびに、上の表に示した「動きの種類」を順番に確認することができるようになっています。
                このエントリーをはてなブックマークに追加
                | D3.js | 21:37 | comments(0) | - | - |
                D3.jsを使った時計
                0
                  JUGEMテーマ:JavaScript

                  今回は、これまで学んできたことの集大成として、D3.jsを使って時計を作ってみましょう。普通の時計を作っても面白くないので、時間・分・秒の3つをパイチャートで表したうえで、それぞれのパイチャートの中心に時間・分・秒の数値を表示することにしました。また、1秒 (=1000ミリ秒) ごとに表示を更新することで、時計をリアルタイムで動かしています。
                  // 現在時刻を保存するための変数
                  var fields = [
                    {name: "Hours", value: 0, size: 12},
                    {name: "Minutes", value: 0, size: 60},
                    {name: "Seconds", value: 0, size: 60}
                  ];
                  
                  var svg = d3.select("#MyGraph")
                    .append("g")
                    .attr("transform", "translate(" + 110 + "," + 110 + ")");
                  
                  // 背景のアークを定義
                  var basearc = d3.svg.arc()
                    .innerRadius(70)
                    .outerRadius(100)
                    .startAngle(0)
                    .endAngle(function(d) {
                      return 2.0*Math.PI; 
                    });
                  
                  // 時計用のアークを定義
                  var arc = d3.svg.arc()
                    .innerRadius(70)
                    .outerRadius(100)
                    .startAngle(0)
                    .endAngle(function(d){
                      return (d.value / d.size) * (2.0 * Math.PI); 
                    });  
                  
                  // 背景のアークをSVG要素として追加
                  svg.selectAll(".base")
                    .data(fields)
                    .enter()
                    .append("path")
                    .attr("transform", function(d, i) {return "translate(" + (220*i) + ",0)"; })
                    .attr("class",'base')
                    .attr("d",basearc);
                  
                  // 各アークの下部に Hours/Minutes/Secondes を表示
                  svg.selectAll(".base_text")
                    .data(fields)
                    .enter()
                    .append("text")
                    .attr("transform", function(d, i) {return "translate(" + (220*i) + ",130)"; })
                    .attr("text-anchor", "middle")
                    .attr("class",'base_text')
                    .text(function(d){
                      return d.name;
                    });
                   
                  // 1000ミリ秒毎に以下の処理を実施 
                  setInterval(function(){
                    // 現在時刻を変数に保存
                    var now = new Date();
                    fields[0].previous = fields[0].value; fields[0].value = changeto12(now.getHours());
                    fields[1].previous = fields[1].value; fields[1].value = now.getMinutes();
                    fields[2].previous = fields[2].value; fields[2].value = now.getSeconds();
                    
                    // 各アークの中心部に現在時刻を表示
                    svg.selectAll(".clock_text")
                      .data(fields)
                      .enter()
                      .append("text")
                      .attr("transform", function(d, i) {return "translate(" + (220*i) + ",20)"; })
                      .attr("text-anchor", "middle")
                      .attr("class",'clock_text')
                      .text(function(d){
                        return d.value;
                      });
                    
                    // 各アーク中心部の現在時刻を更新
                    svg.selectAll(".clock_text")
                      .data(fields)
                      .transition()
                      .text(function(d){
                        return d.value;
                      });
                    
                    // 現在時刻に従って各アークを描画
                    svg.selectAll(".overlay")
                      .data(fields)
                      .enter()
                      .append("path")
                      .attr("transform", function(d, i) {return "translate(" + (220*i) + ",0)"; })
                      .attr("class",'overlay')
                      .transition()
                      .duration(1000)
                      .attrTween("d", arcTween);
                      
                    // 各アークの長さを現在時刻で更新  
                    svg.selectAll(".overlay")
                      .data(fields)
                      .transition()
                      .duration(1000)
                      .ease("elastic")
                      .attrTween("d", arcTween);
                      
                  }, 1000);
                  
                  // 24時間表記を12時間表記に変更
                  function changeto12(num){
                    if(num>12){
                      num = num - 12;
                    }
                    return num;
                  }
                  
                  // アーク変化の途中を補間
                  function arcTween(b,i) {
                    if(b.value == 0) {b.value = b.size}
                    var i = d3.interpolate({value: b.previous}, b);
                    return function(t){
                      return arc(i(t));
                    };
                  }
                  

                  サンプルページ

                  20160203

                  ここでは3つのアークそれぞれについて、クラス名が "base" と "overlay" という2種類のアークを重ねて描画しています。"base" はドーナツ状の固定された灰色のアークで、その上にクラス名 "overlay" のオレンジ色のアークを、1秒毎に長さを更新しながら描画しています。また、各アークの中心に現在時刻の時間・分・秒を表示するため、"clock_text" というクラス名を設定したテキストのSVG要素を追加して、これも1秒毎に更新するようにしています。1秒毎の更新処理は、52行目以降の setInterval によるタイマー処理で実現しています。

                  アークの色や現在時刻の数字のフォントサイズ等は、CSSでSVG要素のクラス名を指定することで自由に変更できます。今回の例では以下のように指定しています。
                   
                    text.clock_text{
                      font-size: 60px;
                    }
                    text.base_text{
                      font-size: 24px;
                    }
                    path.overlay {
                      fill: orange;
                    }
                    path.base{
                      fill: #f3f3f3;
                    }
                  

                  このエントリーをはてなブックマークに追加
                  | D3.js | 07:13 | comments(0) | - | - |
                  クリックした位置から広がる波紋
                  0
                    JUGEMテーマ:JavaScript

                    これまで見てきたように、D3.jsにはSVG要素を操作するメソッドを中心に、DOMを操作するいろいろなメソッドが用意されています。これらのメソッドは、データを可視化する以外の用途にも使うことができます。そこで今回は、画面上でクリックした場所から同心円が次々と広がるというプログラムを作成して、マウスの位置座標を取得する方法などについて見てゆくことにしましょう。

                    D3.jsでは、d3.mouse() というメソッドを使ってマウスの位置座標を取得することができます。また、クリックなどのイベントをトリガに処理を開始する on() というメソッドがあります。トリガの指定には、click、mouseover、mousemove、mouseout などが用意されています。この2つのメソッドを使って、クリックした場所から波紋が広がるプログラムを書いてみました。
                    var svg = d3.select("#MyGraph");
                    
                    // マウスの位置座標を表示
                    var positionLabel = svg.append("text")
                      .attr("x", 10)
                      .attr("y", 20);
                    
                    // マウスの位置座標を取得
                    svg.on("mousemove", function(){
                      positionLabel.text(d3.mouse(this));
                    });
                    
                    // クリックした場所から広がる同心円をアニメーション表示
                    svg.on("click", function(){
                      for (var i = 1; i < 6; i++){
                        var position = d3.mouse(this);
                        var circle = svg.append("circle")
                          .attr("cx", position[0])
                          .attr("cy", position[1])
                          .attr("r", 0)
                          .style("stroke", "blue")
                          .style("stroke-width", 5/(i))
                          .style("fill-opacity", 0)
                          .transition()
                          .delay(Math.pow(i, 2.5)*20)
                          .duration(2000)
                          .ease("quad")
                          .attr("r", 400)
                          .style("stroke-opacity", 0)
                          .each("end", function(){
                            d3.select(this).remove();
                          })
                      }
                    })
                    
                    サンプルページ

                    9〜11行目では、マウスの動きをトリガとしてマウスの位置座標を取得しています。取得した位置座標は、4〜6行目で指定した場所にテキストとして表示しています。また14行目以降では、こんどはクリックをトリガとして、先に取得したマウスの位置座標から5つの同心円が広がるアニメーションを描画しています。最後に、アニメーションが終わったら、30行目以降でSVG要素を削除するようにしています。
                    このエントリーをはてなブックマークに追加
                    | D3.js | 20:42 | comments(0) | - | - |
                    D3.jsによるパックレイアウトの作成
                    0
                      JUGEMテーマ:JavaScript

                      今回はD3.jsのレイアウト機能の一つであるパックレイアウト (pack layout) の使い方について見てゆきます。パックレイアウトは、データの数値を円のサイズによって表示します。データは階層構造 (ツリー構造) を持っていても良く、その場合には階層構造に従って描画される円も階層的に示されます。今回は簡単のために、階層数1のデータを使ってパックレイアウトの基本的な作成方法を説明します。

                      ここでは例として、日本の都道府県ごとの人口をパックレイアウトで作図してみましょう。まず、政府統計の総合窓口などから都道府県ごとの人口データを入手したうえで、カンマ区切りにCSV形式で保存します。2015年10月時点での人口データでは、以下のようなデータファイルになります。

                      prefecture,value
                      東京都,13490558 
                      神奈川県,9118006 
                      大阪府,8845413 
                      愛知県,7460529 
                      埼玉県,7254531 
                      ・・・
                      島根県,691931 
                      鳥取県,570188 

                      あとで便利なように、CSVファイルの1行目にはインデックス (prefecture, value) をつけています。インデックスは日本語でも大丈夫ですが、JavaScriptでは半角英数字のほうが扱いやすいのでこのようにしました。

                      D3.jsのパックレイアウトでは、d3.layout.pack() メソッドを使います。サンプルプログラムは下記のとおりです。
                      var dataSet = [];
                      
                      d3.csv("./js/population2.csv", function(error, dataSet){
                        var data = { //csvデータを一つのchidrenとしてデータセットを作成
                          children:dataSet
                        };
                        
                        // 標準20色を準備
                        var color = d3.scale.category20c();
                        
                        // パックレイアウトの表示サイズ
                        var bubble = d3.layout.pack()
                          .size([800,800])
                          .padding(2); // 円どうしの余白を指定
                        
                        // x,yと、半径rを算出
                        var nodes = bubble.nodes(data);
                        
                        // パックレイアウトを描画
                        var pack = d3.select("#MyGraph")
                          .selectAll(".node")
                          .data(nodes)
                          .enter()
                          .append("g")
                          .attr("class","node")
                          .attr("transform", function(d){
                            return "translate("+ d.y + "," + d.x + ")";
                          }); // gをそれぞれのx,yに移動
                      
                        pack.append("circle")
                          .attr("r", 0)
                          .attr("fill",function(d,i){
                            return d.depth==0 ? "white" : color(i); // rootノードは表示しない
                          })
                          .attr("stroke", "white")
                          .attr("stroke-width",2)
                          .transition()
                          .duration(1000)
                          .delay(function(d,i){
                            return i*10;
                          })
                          .attr("r", function(d){
                            return d.r;
                          });
                          
                        // 各円に都道府県名を表示
                        pack.append("text")
                          .attr("text-anchor","middle")
                          .text(function(d){
                            return d.prefecture;
                          });
                      });
                      
                      サンプルページ

                      それでは順番に見てゆきましょう。3行目は、前回出てきたCSVファイルを読み込む d3.csv() メソッドですね。ここで先ほど準備したCSVファイルを読み込んで、dataSet という配列に保存しています。

                      次の4行目から6行目では、dataSetという配列を、階層数1のデータ型に成形しています。12行目が今回のポイント、d3.layout.pack() メソッドです。ここでは全体サイズが 800×800px、隣接する円の間の余白が2pxとなるように指定しています。続く17行目の node() メソッドは、具体的には入力データの数値や階層構造をもとに、描画する円の中心位置と半径とを自動的に計算するメソッドです。このことは、18行目あたりに console.log() などで変数をコンソール上に表示してみるとよく分かります。

                      いよいよ20行目以降で、作成した多数の円を描画してゆきます。ただ、単純に描画しても面白くないので、アニメーションを使って円が次々と現れるようにしてみました (30行目以降) 。最後に47行目以降で、それぞれの円の中心に都道府県名を表示しています。




                       
                      このエントリーをはてなブックマークに追加
                      | D3.js | 00:52 | comments(0) | - | - |