Skip to content

Instantly share code, notes, and snippets.

@snaka
Created January 26, 2016 17:39
Show Gist options
  • Select an option

  • Save snaka/f88d0540c46d50cf3eaf to your computer and use it in GitHub Desktop.

Select an option

Save snaka/f88d0540c46d50cf3eaf to your computer and use it in GitHub Desktop.

Revisions

  1. snaka created this gist Jan 26, 2016.
    147 changes: 147 additions & 0 deletions siiba.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,147 @@
    /*
    フォームの入力内容を元にAPIに問い合わせ
    */
    $("#form").on("submit", function(e) {
    $("#btn-submit").prop("disabled", true);
    var user_id = $("#user_id").val()
    $.ajax({
    type: "GET",
    url: "http://qiita.com/api/v2/users/" + user_id + "/items?page=1&per_page=100",
    success: onSucceed
    });
    e.preventDefault();
    });

    // 日付のフォーマット
    var format = d3.time.format("%Y-%m-%d");

    /*
    APIから受け取った情報を元にカレンダー描画
    */
    function onSucceed(data) {
    var item_dates = {};
    $.each(data, function(idx, val) {
    var created_at = format(d3.time.day.floor(new Date(val['created_at'])));
    if (created_at in item_dates)
    item_dates[created_at]++;
    else
    item_dates[created_at] = 1;
    });
    drawCalendar(item_dates);
    $("#btn-submit").prop("disabled", false);
    }

    /*
    カレンダーの描画
    */
    var drawCalendar = (function() {
    // セルの1辺のサイズ
    var CELL_SIZE = 15;

    // カレンダ表示のマージン
    var MARGIN_LEFT = 25;
    var MARGIN_TOP = 15;

    var dataset = null;
    var color = null;
    var countScale = null;

    // 日付の計算
    var addDays = function(sourceDate, days) {
    result = new Date(sourceDate);
    result.setDate(sourceDate.getDate() + days);
    return result;
    };

    // 表示する日付の範囲(過去1年間)
    var rangeBegin = addDays(new Date, -365);
    var rangeEnd = new Date;
    var dateRange = d3.time.days(rangeBegin, rangeEnd);
    var monthRange = d3.time.months(rangeBegin, rangeEnd);

    // カレンダのオフセット値を算出する関数
    var createOffsetFunc = function() {
    var firstYearOffset = d3.time.weekOfYear(rangeBegin) * -1;
    var bounderyDate = d3.time.years(rangeBegin, rangeEnd)[0];
    var lastDayOfFirstYear = addDays(bounderyDate, -1);
    var lastWeekOfFirstYear = d3.time.weekOfYear(lastDayOfFirstYear);
    var lastYearOffset = d3.time.weekOfYear(lastDayOfFirstYear) + firstYearOffset;
    return function(sourceDate) {
    if (sourceDate.getFullYear() == rangeBegin.getFullYear())
    return firstYearOffset;
    return lastYearOffset;
    }
    };

    // メイン処理:カレンダー描画
    return function(dataset) {
    // 件数を3段階に分類
    var countScale = d3.scale.linear()
    .domain([1, d3.max(d3.values(dataset))])
    .rangeRound([1, 3]) // 3段階で色分け
    .clamp(true);
    // 分類ごとに色分け
    var colorScale = d3.scale.ordinal()
    .domain([1, 2, 3])
    .range(["#f7fcb9","#addd8e","#31a354"]);
    // 上記をまとめるスケール関数
    var color = function(f) {
    return colorScale(countScale(f));
    };

    // svg要素の作成
    var svg = d3.select(".weed");
    svg.selectAll("*").remove();
    svg.append("g");

    // 日毎の矩形を生成
    var offset = createOffsetFunc();
    var rect = svg.selectAll(".day")
    .data(dateRange)
    .enter()
    .append("rect")
    .attr("class", "day")
    .attr("width", CELL_SIZE - 1)
    .attr("height", CELL_SIZE - 1)
    .attr("x", function(d){ return (d3.time.weekOfYear(d) + offset(d)) * CELL_SIZE + MARGIN_LEFT; })
    .attr("y", function(d){ return d.getDay() * CELL_SIZE + MARGIN_TOP; })
    .attr("fill", "rgb(230,230,230)")
    .datum(format);

    // ツールチップ設定
    rect.append("title")
    .text(function(d){ return d; });

    // 投稿のあった日のツールチップと背景色を設定
    rect.filter(function(d){ return d in dataset; })
    .attr("fill", function(d){ return color(dataset[d]); })
    .select("title")
    .text(function(d){ return d + " (投稿:" + dataset[d] + "件)"; });

    // 曜日のラベル
    dayLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
    svg.selectAll(".dayLabel")
    .data([0, 1, 2, 3, 4, 5, 6])
    .enter()
    .append("text")
    .attr("class", "dayLabel")
    .attr("x", 0)
    .attr("y", function(d){ return d * CELL_SIZE + 11 + MARGIN_TOP; })
    .attr("font-size", 11)
    .attr("fill", "gray")
    .text(function(d){ return dayLabels[d]; });

    // 月のラベル
    monthLabels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
    svg.selectAll(".monthLabel")
    .data(monthRange)
    .enter()
    .append("text")
    .attr("class", "monthLabel")
    .attr("x", function(d){ return (d3.time.weekOfYear(d) + offset(d)) * CELL_SIZE + MARGIN_LEFT; })
    .attr("y", 11)
    .attr("font-size", 11)
    .attr("fill", "gray")
    .text(function(d){ return monthLabels[d.getMonth()]; });
    } // return function
    })(); // drawCalendar