D3 fill transition for heatmap not working

时间:2018-02-26 17:39:26

标签: d3.js data-visualization

I'm trying to create a modified version of Mike Bostock's calendar view (https://bl.ocks.org/mbostock/4063318), which only shows a few months.

I'm almost there, but I'd like to add a short transition when the individual cells are filled. I tried to create this but it isn't transitioning. I must be missing something obvious. Any ideas? Thanks!

Here is the script (see the line ".transition().duration(1000)"):

<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

 var width = 550,
      height = 750,
      cellSize = 45;

    var formatPercent = d3.format(".1%");

    var color = d3.scaleQuantize()
      .domain([0, 100])
      .range(["#ffffff", "#e6f7ff", "#b3e6ff", "#99ddff", "#66ccff", "#4dc3ff", "#1ab2ff", "#0077b3", "#004466"]);

    var month_strings = ["January", "February", "March"]

    var svg = d3.select("body")
      .selectAll("svg")
      .data([2018])
      .enter().append("svg")
      .attr("width", width)
      .attr("height", height)
      .append("g")
      .attr("transform", "translate(" + ((width - cellSize * 5) / 2) + "," + (height - cellSize * 16 - 1) + ")");

    svg.append("text")
      .attr("transform", "translate(-10," + cellSize * 3 + ")rotate(-90)")
      .attr("font-family", "sans-serif")
      .attr("font-size", 20)
      .attr("text-anchor", "middle")
      .text(month_strings[0]);

    svg.append("text")
      .attr("transform", "translate(-10," + cellSize * 7 + ")rotate(-90)")
      .attr("font-family", "sans-serif")
      .attr("font-size", 20)
      .attr("text-anchor", "middle")
      .text(month_strings[1]);

    svg.append("text")
      .attr("transform", "translate(-10," + cellSize * 11 + ")rotate(-90)")
      .attr("font-family", "sans-serif")
      .attr("font-size", 20)
      .attr("text-anchor", "middle")
      .text(month_strings[2]);



var rect = svg.append("g")
    .attr("fill", "none")
    .attr("stroke", "#d2d4d8")
  .selectAll("rect")
  .data(function(d) { return d3.timeDays(new Date(2018, 0, 1), new Date(2018, 3, 1)); })
  .enter().append("rect")
    .attr("width", cellSize)
    .attr("height", cellSize)
    .attr("class", "hour bordered")
    .attr("rx", 4)
    .attr("ry", 4)
    //.attr("x", function(d) { return d3.timeWeek.count(d3.timeYear(d), d) * cellSize; })
    //.attr("y", function(d) { return d.getDay() * cellSize; })
    .attr("x", function(d) { return d.getDay() * cellSize;})
    .attr("y", function(d) { return d3.timeWeek.count(d3.timeYear(d), d) * cellSize;  })   
    .datum(d3.timeFormat("%Y-%m-%d"));




    var g = svg.append("g")
      .attr("fill", "none")
      .attr("stroke", "#d2d4d8")
      .selectAll("g")
      .data(function(d) {
        return d3.timeDays(new Date(2018, 0, 1), new Date(2018, 3, 1));
      })
      .enter()
      .append("g")
      .attr("transform", function(d){
        var x = d.getDay() * cellSize,
            y = d3.timeWeek.count(d3.timeYear(d), d) * cellSize;
        return "translate(" + x + "," + y + ")";
      })

    g.append("rect")
      .attr("width", cellSize)
      .attr("height", cellSize)
      .attr("class", "hour bordered")
      .attr("rx", 4)
      .attr("ry", 4)
      .datum(d3.timeFormat("%Y-%m-%d"));

    g.append("text")
      .text(function(d){
        return d.getDate();
      })
      .attr("y", cellSize - 32)
      .style("font-family", "arial")
      .style("font-size", "9pt")
      .attr("stroke", "black")

    svg.append("g")
      .attr("fill", "none")
      .attr("stroke", "#000")
      .selectAll("path")
      .data(function(d) {
        return d3.timeMonths(new Date(2018, 0, 1), new Date(2018, 3, 1));
      })
      .enter().append("path")
      .attr("d", pathMonth);

    d3.csv("static/test.csv", function(error, csv) {
      if (error) throw error;

      var data = d3.nest()
        .key(function(d) {
          return d.Date;
        })
        .rollup(function(d) {
          return (d[0].Close - d[0].Open) / d[0].Open;
        })
        .object(csv);


        d3.selectAll("rect")
          .filter(function(d) {
            return d in data;
          })
          .transition().duration(1000)
          .style("fill", function(d) {
          return color(data[d]);
        });


    });

    function pathMonth(t0) {
      var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
        d0 = t0.getDay(),
        w0 = d3.timeWeek.count(d3.timeYear(t0), t0),
        d1 = t1.getDay(),
        w1 = d3.timeWeek.count(d3.timeYear(t1), t1);
      return "M" + d0 * cellSize + "," + (w0) * cellSize + "H" + 7 * cellSize + "V" + (w1) * cellSize + "H" + (d1 + 1) * cellSize + "V" + (w1 + 1) * cellSize + "H" + 0 + "V" + (w0 + 1) * cellSize + "H" + d0 * cellSize + "Z";
    }

    var start_box = svg.append("rect")
      .attr("x", 225)
      .attr("y", 45)
      .attr("width", cellSize)
      .attr("height", cellSize)
      .attr("rx", 4)
      .attr("ry", 4)
      .attr("class", "hour bordered")
      .style("fill", "#FFD700");


</script>

Here is the csv if that helps:

Date,Weekday,Open,Close
2018-01-01,0,1,0
2018-01-02,1,1,1
2018-01-03,2,1,2
2018-01-04,3,1,3
2018-01-05,4,1,4
2018-01-06,5,1,1
2018-01-07,6,1,1
2018-01-08,0,1,7
2018-01-09,1,1,8
2018-01-10,2,1,9
2018-01-11,3,1,10
2018-01-12,4,1,11
2018-01-13,5,1,1
2018-01-14,6,1,1
2018-01-15,0,1,14
2018-01-16,1,1,15
2018-01-17,2,1,16
2018-01-18,3,1,17
2018-01-19,4,1,18
2018-01-20,5,1,1
2018-01-21,6,1,1
2018-01-22,0,1,21
2018-01-23,1,1,22
2018-01-24,2,1,23
2018-01-25,3,1,24
2018-01-26,4,1,25
2018-01-27,5,1,1
2018-01-28,6,1,1
2018-01-29,0,1,28
2018-01-30,1,1,29
2018-01-31,2,1,30
2018-02-01,3,1,31
2018-02-02,4,1,32
2018-02-03,5,1,1
2018-02-04,6,1,1
2018-02-05,0,1,35
2018-02-06,1,1,36
2018-02-07,2,1,37
2018-02-08,3,1,38
2018-02-09,4,1,39
2018-02-10,5,1,1
2018-02-11,6,1,1
2018-02-12,0,1,42
2018-02-13,1,1,43
2018-02-14,2,1,44
2018-02-15,3,1,45
2018-02-16,4,1,46
2018-02-17,5,1,1
2018-02-18,6,1,1
2018-02-19,0,1,49
2018-02-20,1,1,50
2018-02-21,2,1,51
2018-02-22,3,1,52
2018-02-23,4,1,53
2018-02-24,5,1,1
2018-02-25,6,1,1
2018-02-26,0,1,56
2018-02-27,1,1,57
2018-02-28,2,1,58
2018-03-01,3,1,59
2018-03-02,4,1,60
2018-03-03,5,1,1
2018-03-04,6,1,1
2018-03-05,0,1,63
2018-03-06,1,1,64
2018-03-07,2,1,65
2018-03-08,3,1,66
2018-03-09,4,1,67
2018-03-10,5,1,1
2018-03-11,6,1,1
2018-03-12,0,1,70
2018-03-13,1,1,71
2018-03-14,2,1,72
2018-03-15,3,1,73
2018-03-16,4,1,74
2018-03-17,5,1,1
2018-03-18,6,1,1
2018-03-19,0,1,77
2018-03-20,1,1,78
2018-03-21,2,1,79
2018-03-22,3,1,80
2018-03-23,4,1,81
2018-03-24,5,1,1
2018-03-25,6,1,1
2018-03-26,0,1,84
2018-03-27,1,1,85
2018-03-28,2,1,86
2018-03-29,3,1,87
2018-03-30,4,1,88
2018-03-31,5,1,1

1 个答案:

答案 0 :(得分:2)

你需要从填充了某些东西开始,以便它们可以转换为不同的颜色。像这样:

d3.selectAll("rect")
  .filter(function(d) {
    return d in data;
  })
  // start as white
  .style("fill", "white")
  .transition()
  .duration(1000)
  // fill to blue
  .style("fill", function(d) {
    return color(data[d]);
  });

运行代码:

<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>

  <body>

      <script src="https://d3js.org/d3.v4.min.js"></script>
<script>

 var width = 550,
      height = 750,
      cellSize = 45;

    var formatPercent = d3.format(".1%");

    var color = d3.scaleQuantize()
      .domain([0, 100])
      .range(["#ffffff", "#e6f7ff", "#b3e6ff", "#99ddff", "#66ccff", "#4dc3ff", "#1ab2ff", "#0077b3", "#004466"]);

    var month_strings = ["January", "February", "March"]

    var svg = d3.select("body")
      .selectAll("svg")
      .data([2018])
      .enter().append("svg")
      .attr("width", width)
      .attr("height", height)
      .append("g")
      .attr("transform", "translate(" + ((width - cellSize * 5) / 2) + "," + (height - cellSize * 16 - 1) + ")");

    svg.append("text")
      .attr("transform", "translate(-10," + cellSize * 3 + ")rotate(-90)")
      .attr("font-family", "sans-serif")
      .attr("font-size", 20)
      .attr("text-anchor", "middle")
      .text(month_strings[0]);

    svg.append("text")
      .attr("transform", "translate(-10," + cellSize * 7 + ")rotate(-90)")
      .attr("font-family", "sans-serif")
      .attr("font-size", 20)
      .attr("text-anchor", "middle")
      .text(month_strings[1]);

    svg.append("text")
      .attr("transform", "translate(-10," + cellSize * 11 + ")rotate(-90)")
      .attr("font-family", "sans-serif")
      .attr("font-size", 20)
      .attr("text-anchor", "middle")
      .text(month_strings[2]);



var rect = svg.append("g")
    .attr("fill", "none")
    .attr("stroke", "#d2d4d8")
  .selectAll("rect")
  .data(function(d) { return d3.timeDays(new Date(2018, 0, 1), new Date(2018, 3, 1)); })
  .enter().append("rect")
    .attr("width", cellSize)
    .attr("height", cellSize)
    .attr("class", "hour bordered")
    .attr("rx", 4)
    .attr("ry", 4)
    //.attr("x", function(d) { return d3.timeWeek.count(d3.timeYear(d), d) * cellSize; })
    //.attr("y", function(d) { return d.getDay() * cellSize; })
    .attr("x", function(d) { return d.getDay() * cellSize;})
    .attr("y", function(d) { return d3.timeWeek.count(d3.timeYear(d), d) * cellSize;  })   
    .datum(d3.timeFormat("%Y-%m-%d"));




    var g = svg.append("g")
      .attr("fill", "none")
      .attr("stroke", "#d2d4d8")
      .selectAll("g")
      .data(function(d) {
        return d3.timeDays(new Date(2018, 0, 1), new Date(2018, 3, 1));
      })
      .enter()
      .append("g")
      .attr("transform", function(d){
        var x = d.getDay() * cellSize,
            y = d3.timeWeek.count(d3.timeYear(d), d) * cellSize;
        return "translate(" + x + "," + y + ")";
      })

    g.append("rect")
      .attr("width", cellSize)
      .attr("height", cellSize)
      .attr("class", "hour bordered")
      .attr("rx", 4)
      .attr("ry", 4)
      .datum(d3.timeFormat("%Y-%m-%d"));

    g.append("text")
      .text(function(d){
        return d.getDate();
      })
      .attr("y", cellSize - 32)
      .style("font-family", "arial")
      .style("font-size", "9pt")
      .attr("stroke", "black")

    svg.append("g")
      .attr("fill", "none")
      .attr("stroke", "#000")
      .selectAll("path")
      .data(function(d) {
        return d3.timeMonths(new Date(2018, 0, 1), new Date(2018, 3, 1));
      })
      .enter().append("path")
      .attr("d", pathMonth);

    //d3.csv("test.csv", function(error, csv) {
      
      var csv = [{"Date":"2018-01-01","Weekday":"0","Open":"1","Close":"0"},{"Date":"2018-01-02","Weekday":"1","Open":"1","Close":"1"},{"Date":"2018-01-03","Weekday":"2","Open":"1","Close":"2"},{"Date":"2018-01-04","Weekday":"3","Open":"1","Close":"3"},{"Date":"2018-01-05","Weekday":"4","Open":"1","Close":"4"},{"Date":"2018-01-06","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-01-07","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-01-08","Weekday":"0","Open":"1","Close":"7"},{"Date":"2018-01-09","Weekday":"1","Open":"1","Close":"8"},{"Date":"2018-01-10","Weekday":"2","Open":"1","Close":"9"},{"Date":"2018-01-11","Weekday":"3","Open":"1","Close":"10"},{"Date":"2018-01-12","Weekday":"4","Open":"1","Close":"11"},{"Date":"2018-01-13","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-01-14","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-01-15","Weekday":"0","Open":"1","Close":"14"},{"Date":"2018-01-16","Weekday":"1","Open":"1","Close":"15"},{"Date":"2018-01-17","Weekday":"2","Open":"1","Close":"16"},{"Date":"2018-01-18","Weekday":"3","Open":"1","Close":"17"},{"Date":"2018-01-19","Weekday":"4","Open":"1","Close":"18"},{"Date":"2018-01-20","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-01-21","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-01-22","Weekday":"0","Open":"1","Close":"21"},{"Date":"2018-01-23","Weekday":"1","Open":"1","Close":"22"},{"Date":"2018-01-24","Weekday":"2","Open":"1","Close":"23"},{"Date":"2018-01-25","Weekday":"3","Open":"1","Close":"24"},{"Date":"2018-01-26","Weekday":"4","Open":"1","Close":"25"},{"Date":"2018-01-27","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-01-28","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-01-29","Weekday":"0","Open":"1","Close":"28"},{"Date":"2018-01-30","Weekday":"1","Open":"1","Close":"29"},{"Date":"2018-01-31","Weekday":"2","Open":"1","Close":"30"},{"Date":"2018-02-01","Weekday":"3","Open":"1","Close":"31"},{"Date":"2018-02-02","Weekday":"4","Open":"1","Close":"32"},{"Date":"2018-02-03","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-02-04","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-02-05","Weekday":"0","Open":"1","Close":"35"},{"Date":"2018-02-06","Weekday":"1","Open":"1","Close":"36"},{"Date":"2018-02-07","Weekday":"2","Open":"1","Close":"37"},{"Date":"2018-02-08","Weekday":"3","Open":"1","Close":"38"},{"Date":"2018-02-09","Weekday":"4","Open":"1","Close":"39"},{"Date":"2018-02-10","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-02-11","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-02-12","Weekday":"0","Open":"1","Close":"42"},{"Date":"2018-02-13","Weekday":"1","Open":"1","Close":"43"},{"Date":"2018-02-14","Weekday":"2","Open":"1","Close":"44"},{"Date":"2018-02-15","Weekday":"3","Open":"1","Close":"45"},{"Date":"2018-02-16","Weekday":"4","Open":"1","Close":"46"},{"Date":"2018-02-17","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-02-18","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-02-19","Weekday":"0","Open":"1","Close":"49"},{"Date":"2018-02-20","Weekday":"1","Open":"1","Close":"50"},{"Date":"2018-02-21","Weekday":"2","Open":"1","Close":"51"},{"Date":"2018-02-22","Weekday":"3","Open":"1","Close":"52"},{"Date":"2018-02-23","Weekday":"4","Open":"1","Close":"53"},{"Date":"2018-02-24","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-02-25","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-02-26","Weekday":"0","Open":"1","Close":"56"},{"Date":"2018-02-27","Weekday":"1","Open":"1","Close":"57"},{"Date":"2018-02-28","Weekday":"2","Open":"1","Close":"58"},{"Date":"2018-03-01","Weekday":"3","Open":"1","Close":"59"},{"Date":"2018-03-02","Weekday":"4","Open":"1","Close":"60"},{"Date":"2018-03-03","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-03-04","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-03-05","Weekday":"0","Open":"1","Close":"63"},{"Date":"2018-03-06","Weekday":"1","Open":"1","Close":"64"},{"Date":"2018-03-07","Weekday":"2","Open":"1","Close":"65"},{"Date":"2018-03-08","Weekday":"3","Open":"1","Close":"66"},{"Date":"2018-03-09","Weekday":"4","Open":"1","Close":"67"},{"Date":"2018-03-10","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-03-11","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-03-12","Weekday":"0","Open":"1","Close":"70"},{"Date":"2018-03-13","Weekday":"1","Open":"1","Close":"71"},{"Date":"2018-03-14","Weekday":"2","Open":"1","Close":"72"},{"Date":"2018-03-15","Weekday":"3","Open":"1","Close":"73"},{"Date":"2018-03-16","Weekday":"4","Open":"1","Close":"74"},{"Date":"2018-03-17","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-03-18","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-03-19","Weekday":"0","Open":"1","Close":"77"},{"Date":"2018-03-20","Weekday":"1","Open":"1","Close":"78"},{"Date":"2018-03-21","Weekday":"2","Open":"1","Close":"79"},{"Date":"2018-03-22","Weekday":"3","Open":"1","Close":"80"},{"Date":"2018-03-23","Weekday":"4","Open":"1","Close":"81"},{"Date":"2018-03-24","Weekday":"5","Open":"1","Close":"1"},{"Date":"2018-03-25","Weekday":"6","Open":"1","Close":"1"},{"Date":"2018-03-26","Weekday":"0","Open":"1","Close":"84"},{"Date":"2018-03-27","Weekday":"1","Open":"1","Close":"85"},{"Date":"2018-03-28","Weekday":"2","Open":"1","Close":"86"},{"Date":"2018-03-29","Weekday":"3","Open":"1","Close":"87"},{"Date":"2018-03-30","Weekday":"4","Open":"1","Close":"88"},{"Date":"2018-03-31","Weekday":"5","Open":"1","Close":"1"}];
      
      
      //if (error) throw error;

      var data = d3.nest()
        .key(function(d) {
          return d.Date;
        })
        .rollup(function(d) {
          return (d[0].Close - d[0].Open) / d[0].Open;
        })
        .object(csv);


        d3.selectAll("rect")
          .filter(function(d) {
            return d in data;
          })
          .style("fill", "white")
          .transition()
          .duration(1000)
          .style("fill", function(d) {
            return color(data[d]);
        });


    //});

    function pathMonth(t0) {
      var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
        d0 = t0.getDay(),
        w0 = d3.timeWeek.count(d3.timeYear(t0), t0),
        d1 = t1.getDay(),
        w1 = d3.timeWeek.count(d3.timeYear(t1), t1);
      return "M" + d0 * cellSize + "," + (w0) * cellSize + "H" + 7 * cellSize + "V" + (w1) * cellSize + "H" + (d1 + 1) * cellSize + "V" + (w1 + 1) * cellSize + "H" + 0 + "V" + (w0 + 1) * cellSize + "H" + d0 * cellSize + "Z";
    }

    var start_box = svg.append("rect")
      .attr("x", 225)
      .attr("y", 45)
      .attr("width", cellSize)
      .attr("height", cellSize)
      .attr("rx", 4)
      .attr("ry", 4)
      .attr("class", "hour bordered")
      .style("fill", "#FFD700");


</script>

  </body>

</html>