Javascript d3 热图日历,如何追加月份的日期?

Javascript d3 heatmap calendar, how to append day of the month?

我有一个 d3 日历,灵感来自:

http://bl.ocks.org/KathyZ/c2d4694c953419e0509b

现在可以正常工作,但我不知道在哪里或如何添加文本来显示月份中的第几天,意思是数字(1、2、... 31 等)每一天。我必须以某种方式将文本元素附加到日期矩形,但我不知道该怎么做。

function normal_cal(dom, data, clk_fn, scp){
        var width = 900,
            height = 259,
            cellSize = 12; // cell size

        var no_months_in_a_row = Math.floor(width / (cellSize * 7 + 50));
        var shift_up = cellSize * 1;

        var day = d3.time.format("%w"), // day of the week
            day_of_month = d3.time.format("%e") // day of the month
            day_of_year = d3.time.format("%j")
            week = d3.time.format("%U"), // week number of the year
            month = d3.time.format("%m"), // month number
            year = d3.time.format("%Y"),
            percent = d3.format(".1%"),
            format = d3.time.format("%Y-%m-%d"),
            parseDate = d3.time.format("%Y-%m-%d").parse,
            year_getter = d3.time.format("%Y%"),
            day_getter=d3.time.format("%a, %e");

        var color = d3.scale.quantize()
            .domain([-.05, .05])
            .range(d3.range(11).map(function(d) { return "q" + d + "-11"; }));

        // range?
        var years = [d3.extent(data, function(d) { return year_getter(parseDate(d.Date)); })];
        var start_year = parseInt(years[0][0]);
        var end_year = parseInt(years[0][1]);

        var svg = d3.select(dom.get(0)).selectAll("svg")
            .data(d3.range(start_year, end_year + 1))
          .enter().append("svg")
            .attr("width", width)
            .attr("height", height)
            .attr("class", "RdYlGn")
          .append("g")

        var rect = svg.selectAll(".day")
            .data(function(d) { 
              return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1));
            })
          .enter().append("rect")
            .attr("class", "day")
            .attr("width", cellSize)
            .attr("height", cellSize)
            .attr("x", function(d) {
              var month_padding = 1.2 * cellSize*7 * ((month(d)-1) % (no_months_in_a_row));
              return day(d) * cellSize + month_padding; 
            })
            .attr("y", function(d) { 
              var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
              var row_level = Math.ceil(month(d) / (no_months_in_a_row));
              return (week_diff*cellSize) + row_level*cellSize*8 - cellSize/2 - shift_up;
            })
            .datum(format);



        var month_titles = svg.selectAll(".month-title")  // Jan, Feb, Mar and the whatnot
              .data(function(d) { 
                return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
            .enter().append("text")
              .text(monthTitle)
              .attr("x", function(d, i) {
                var month_padding = 1.2 * cellSize*7* ((month(d)-1) % (no_months_in_a_row));
                return month_padding;
              })
              .attr("y", function(d, i) {
                var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
                var row_level = Math.ceil(month(d) / (no_months_in_a_row));
                return (week_diff*cellSize) + row_level*cellSize*8 - cellSize - shift_up;
              })
              .attr("class", "month-title")
              .attr("d", monthTitle);

        var year_titles = svg.selectAll(".year-title")  // Jan, Feb, Mar and the whatnot
              .data(function(d) { 
                return d3.time.years(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
            .enter().append("text")
              .text(yearTitle)
              .attr("x", function(d, i) { return width/2 - 100; })
              .attr("y", function(d, i) { return cellSize*3 - shift_up; })
              .attr("class", "year-title")
              .attr("d", yearTitle);


        //  Tooltip Object
        var tooltip = d3.select("body")
          .append("div").attr("id", "tooltip")
          .style("position", "absolute")
          .style("z-index", "10")
          .style("visibility", "hidden")
          .text("a simple tooltip");



        //==================================================================================PROCESS DATA
        //==================================================================================PROCESS DATA
        //==================================================================================PROCESS DATA
          var data = d3.nest()
            .key(function(d) { return d.Date; })
            .rollup(function(d) { 
              return {"value": -5, 
                "comment": d[0].comment,
                "key": d[0].key
              }; 
             })
            .map(data);

          rect.filter(function(d) { return d in data; })
              .attr("class", function(d) { return "day " + color(data[d].value); })
              .select("title")
              .text(function(d) {
                return d + ": " +data[d].comment; 
              });

          //  Tooltip
          rect.on("mouseover", mouseover);
          rect.on("mouseout", mouseout);
          rect.on("click", function(d){
            clk_fn(d, data, scp);
          });
          function mouseover(d) {
            console.log(data[d]);
            tooltip.style("visibility", "visible");
            var purchase_text = (data[d] !== undefined) ? day_getter(parseDate(d)) + " : " + data[d].comment : day_getter(parseDate(d));

            tooltip.transition()        
                        .duration(200)      
                        .style("opacity", .9);      
            tooltip.html(purchase_text)  
                        .style("left", (d3.event.pageX)+30 + "px")     
                        .style("top", (d3.event.pageY) + "px"); 
          }
          function mouseout (d) {
            tooltip.transition()        
                    .duration(500)      
                    .style("opacity", 0); 
            var $tooltip = $("#tooltip");
            $tooltip.empty();
          }



        function dayTitle (t0) {
          return t0.toString().split(" ")[2];
        }
        function monthTitle (t0) {
          return t0.toLocaleString("en-us", { month: "long" });
        }
        function yearTitle (t0) {
          return t0.toString().split(" ")[3];
        }
         //});
    }

如何在方块上附加月中的第几天(数字)?

根据您提供的link:

http://bl.ocks.org/KathyZ/c2d4694c953419e0509b

我已经以这种方式修改了 rect 定义(只需将定义 rect (var rect = svg.selectAll(".day")...) 的块替换为以下内容来尝试):

var rectContainer = svg.selectAll(".day")
    .data(function(d) { 
      return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1));
    })
    .enter().append("g")
      .attr("transform", function(d) {

        var month_padding = 1.2 * cellSize*7 * ((month(d)-1) % (no_months_in_a_row));
        var x = day(d) * cellSize + month_padding;

        var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
        var row_level = Math.ceil(month(d) / (no_months_in_a_row));
        var y = (week_diff*cellSize) + row_level*cellSize*8 - cellSize/2 - shift_up;

        return "translate(" + x + "," + y + ")";
      });

  var rect = rectContainer.append("rect")
    .attr("class", "day")
    .attr("width", cellSize)
    .attr("height", cellSize)
    .datum(format);

  rectContainer.append("text")
    .attr("x", cellSize / 2)
    .attr("y", cellSize / 2)
    .attr("dy", ".35em")
    .text(function(d) {
      return day_of_month(d);
    })
    .style("font-size", "10px");

由于无法在 rect 中添加 text(详细信息 here),因此您必须创建一个 容器 它将包含 recttext.

由于矩形的位置现在由容器的位置处理,因此必须设置容器的坐标。这是使用 transform 属性通过翻译容器而不是设置矩形的 x 和 y 来完成的。

day_of_month() 格式化程序定义在 Kathy Zhou 代码中 link 的顶部。

我会让你管理样式(字体大小,将文本恰好放在中心,...)