D3.js

データビジュアライゼーションのためのD3.js徹底入門 Webで魅せるグラフ&チャートの作り方

データビジュアライゼーションのためのD3.js徹底入門 Webで魅せるグラフ&チャートの作り方

第10章 散布図まで。 縦軸横軸、目盛り線が難しい。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>SVG</title>

    <link href="../node_modules/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet">
    <link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="../node_modules/octicons/octicons/octicons.css" rel="stylesheet">

    <!--[if lt IE 9]>
      <script src="https://cdn.jsdelivr.net/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://cdn.jsdelivr.net/respond/1.4.2/respond.min.js"></script>
    <![endif]-->

    <style media="screen">
      .axis text {
        font-family: sans-serif;
        font-size: 11px;
      }
      .axis path, .axis line { fill: none; stroke: black; }
      .grid {
        stroke: gray;
        stroke-dasharray: 4, 2;
        shape-rendering: crispEdges;
      }
      .mark { fill: red; stroke: black; }
      .tip {
        position: absolute;
        top: 0px;
        left: 0px;
        z-index: 9999;
        visibility: hidden;
        border: 1px solid black;
        background-color: yellow;
        width: 80px;
        height: 16px;
        overflow: hidden;
        text-align: center;
        font-size: 9pt;
        font-family: Tahoma, Optima, Helverica;
        color: black;
      }
      svg { width: 380px; height: 300px; border: 1px solid; }
    </style>
  </head>
  <body>
    <script src="../node_modules/jquery/dist/jquery.min.js" charset="utf-8"></script>
    <script src="../node_modules/bootstrap/dist/js/bootstrap.min.js" charset="utf-8"></script>
    <script src="../node_modules/d3/d3.min.js" charset="utf-8"></script>

    <div class="container">
      <h1>散布図を表示</h1>
      <div class="row">
        <div class="col-sm-4">
          <svg id="myGraph1"></svg>
        </div>
        <div class="col-sm-4">
        </div>
        <div class="col-sm-4">
        </div>
      </div>
      <script src="sample10.js" charset="utf-8"></script>
    </div>
  </body>
</html>
d3.csv("sample10/mydata.csv", function(error, data) {
  var svgEle = document.getElementById("myGraph1");
  var svgWidth = parseFloat(window.getComputedStyle(svgEle, null).getPropertyValue("width"));
  var svgHeight = parseFloat(window.getComputedStyle(svgEle, null).getPropertyValue("height"));
  var offsetX = 30;
  var offsetY = 20;
  var xScale;
  var yScale;
  var xAxisWidth = svgWidth - 40;
  var yAxisHeight = svgHeight - 20;
  var svg = d3.select("#myGraph1");

  // var dataset = [
  //   [30, 40], [120, 115], [125, 90], [150, 160], [300, 190],
  //   [60, 40], [140, 145], [165, 110], [200, 170], [250, 190]
  // ];

  var dataset = [];
  data.forEach(function(d, I) {
    dataset.push([d.total / 100, d.bug * 1, d.time * 1]);
  });

  // 目盛りとグリッドを先に表示 xScale などに関数セットするためにも
  drawScale();

  var circleElements = svg.selectAll("circle")
    .data(dataset);

  circleElements.enter()
    .append("circle")
    .attr("class", "mark")
    .attr("cx", svgWidth / 2 + offsetX)
    .attr("cy", svgHeight / 2 - offsetY)
    .attr("r", 100)
    .attr("opacity", 0)
    .transition()
    .duration(2000)
    .ease("bounce")
    .attr("cx", function(d, i) {
      return xScale(d[0]) + offsetX;
    })
    .attr("cy", function(d, i) {
      return yScale(d[1]);
    })
    .attr("r", 5)
    .attr("opacity", 1.0);

  function updateData(data) {
    var result = data.map(function(d, i) {
      var x = Math.random() * svgWidth;
      var y = Math.random() * svgHeight;
      return [x, y];
    });

    return result;
  }

  function updateGraph() {
    circleElements.data(dataset)
      .transition()
      .attr("cx", function(d, i) {
        return d[0] - offsetX;
      })
      .attr("cy", function(d, i) {
        return svgHeight - d[1] - offsetY;
      });
  }

  function drawScale() {
    var maxX = d3.max(dataset, function(d, i) {
      return d[0];
    });
    var maxY = d3.max(dataset, function(d, i) {
      return d[1];
    });

    yScale = d3.scale.linear()
      .domain([0, maxY])
      .range([yAxisHeight, 0]);

    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(" + offsetX + ", " + (svgHeight - yAxisHeight - offsetY) + ")")
      .call(
        d3.svg.axis()
          .scale(yScale)
          .orient("left")
      );

    xScale = d3.scale.linear()
      .domain([0, maxX])
      .range([0, xAxisWidth]);

    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(" + offsetX + ", " + (svgHeight - offsetY) + ")")
      .call(
        d3.svg.axis()
          .scale(xScale)
          .orient("bottom")
      );

    var grid = svg.append("g");
    var rangeX = d3.range(50, maxX, 50);
    var rangeY = d3.range(20, maxY, 20);

    grid.selectAll("line.y")
      .data(rangeY)
      .enter()
      .append("line")
      .attr("class", "grid")
      .attr("x1", offsetX)
      .attr("y1", function(d, i) {
        return svgHeight - yScale(d) - offsetY;
      })
      .attr("x2", maxX + offsetX)
      .attr("y2", function(d, i) {
        return svgHeight - yScale(d) - offsetY;
      });

    grid.selectAll("line.x")
      .data(rangeX)
      .enter()
      .append("line")
      .attr("class", "grid")
      .attr("x1", function(d, i) {
        return xScale(d) + offsetX;
      })
      .attr("y1", svgHeight - offsetY)
      .attr("x2", function(d, i) {
        return xScale(d) + offsetX;
      })
      .attr("y2", svgHeight - offsetY - yAxisHeight);
  }

  // ツールチップ
  var tooltip = d3.select("body")
    .append("div")
    .attr("class", "tip");

  circleElements.on("mouseover", function(d) {
    var x = parseInt(xScale(d[0]));
    var y = parseInt(yScale(d[1]));
    var data = d3.select(this).datum();
    var t = parseInt(data[2]);
    // var dx = parseInt(data[0]);
    // var dy = parseInt(data[1]);
    tooltip.style("left", offsetX + x + "px")
      .style("top", offsetY + 30 + y + "px")
      .style("visibility", "visible")
      // .text(dx + ", " + dy);
      .text(t + "時間");
  })
  .on("mouseout", function() {
    tooltip.style("visibility", "hidden");
  });
});

// setInterval(function() {
//   dataset = updateData(dataset);
//   updateGraph();
// }, 4000);

f:id:yossk:20150613110343j:plain