简体   繁体   中英

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

I have a d3 calendar inspired by:

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

which works as it is now, but I can't figure out where or how to add text to display the day of the month, meaning, the number (1, 2, ... 31, etc) on each of the days. I have to somehow append a text element to the day rectangles and I don't know how to do that.

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];
        }
         //});
    }

How can I append the day of the month (number) on the squares?

Based on the link you provided:

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

I have modified the rect definition this way (just replace the block defining rect ( var rect = svg.selectAll(".day")...) with the following to try it out):

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");

As you can't add text inside a rect (details here ), you'll have to create a container which will contain both the rect and the text .

As the location of the rect is now handled by the location of the container, the coordinates of the container have to be set. This is done using the transform attribute by translating the container instead of setting x and y of the rect.

The day_of_month() formatter is defined at the top of link in Kathy Zhou's code.

I'll let you manage the style (font size, putting the text exactly in the center, ...)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM