Help us understand the problem. What is going on with this article?

d3 v4でGithubのcontributionヒートマップっぽいの作ってみた

More than 1 year has passed since last update.

12月-26-2017 午後4-49-30.gif

D3を業務で使うので勉強がてらGithubのContributionヒートマップっぽいの作ってみた。
ソースコードは雑だが、見た目それっぽいのはできた。

D3は一年以上前に、v3→v4にメジャーアップデートしたのだけど、結構、v4のドキュメントがなくて辛かった。

D3

  // ダミーデータ作成
  var days = 365
  var data = [];
  for (var i = 0; i < days; i++) {
    data.push(Math.floor(Math.random() * 30));
  }
  var svg = d3.select("svg"),
    margin = {
      top: 40,
      right: 30,
      bottom: 20,
      left: 30
    },
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  // データのindexから第何週目かを取得
  var getWeekIndex = function(index) {
    return Math.floor(index / 7);
  }
  // データのindexから曜日index(0-6)を取得
  var getDayIndex = function(index) {
    return index % 7;
  }
  console.log(data);
  var opacity = d3.scaleLinear()
    .domain([0, 30])
    .range([0, 1]);

  var padding = 1;
  var rectSize = height / 7;

  // tooltipsのdiv作成
  var div = d3.select("body")
    .append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);

  // 各日付のrectを生成
  var rect = g.selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("width", rectSize)
    .attr("height", rectSize)
    .attr("x", function(d, i) {
      return getWeekIndex(i) * rectSize;
    })
    .attr("y", function(d, i) {
      return getDayIndex(i) * rectSize;
    })
    .style("fill", "green")
    .style("opacity", function(d) {
      return opacity(d)
    })
    .on("mouseover", function(d) {
      div.transition()
        .duration(500)
        .style("opacity", 0);
      div.transition()
        .duration(200)
        .style("opacity", .7);
      div.html("<b>" + d + " contributions</b><br><span> on Jan 1, 2018</span>")
        .style("left", d3.event.pageX - 50 + "px")
        .style("top", d3.event.pageY - 50 + "px");
    })


  // 軸を生成
  var monthsLabel = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  var weekDayLabel = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];

  var xScale = d3.scaleLinear()
    .domain([0, 11])
    .range([0, rectSize * 52]);

  var yScale = d3.scaleLinear()
    .domain([0, 14])
    .range([-height, 0]);

  var xAxis = d3.axisBottom(xScale)
    .ticks(monthsLabel.length)
    .tickFormat(function(d) {
      return monthsLabel[d];
    })

  var yAxis = d3.axisLeft(yScale)
    .ticks(weekDayLabel.length * 2)
    .tickFormat(function(d, i) {
      if (i % 2 == 0) {
        return '';
      } else {
        return weekDayLabel[(i - 1) / 2];
      }
    })

  g.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0, " + height + ")")
    .call(xAxis);

  g.append("g")
    .attr("class", "axis axis--y")
    .attr("transform", "translate(0, " + height + ")")
    .call(yAxis);

HTML CSS

<style>
  form {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    position: absolute;
    left: 10px;
    top: 10px;
  }

  label {
    display: block;
  }

  .axis path,
  .axis line {
    display: none;
  }

  div.tooltip {
    position: absolute;
    text-align: center;
    color: #FFFFFF;
    padding: 5px;
    background: #000000;
    border-radius: 3px;
    font-size: 10px;
  }

  div.tooltip span {
    color: #DDDDDD;
  }
</style>

<svg width="1400" height="170"></svg>

ダミーデータは大きさ365の配列で、0~30の値がランダムに入っている。(今回はdateデータは入れてない。)

[4, 7, 23, 10, 5, 27, 1, 24, 8, 2, ... , 6, 16, 12, 28, 28, 10]
mitch0807
猫と銭湯が好きな文系出身若手エンジニアです。 大学ではコンピューターサイエンス学んでないので、お手柔らかにお願いします。
https://miyach.in
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away