block by curran 27420ce88227892d000c3988a5b06c8c

Moon Calendar 2017

Full Screen

A 2017 moon calendar. Click to show today.

Uses the “Simple” moon plase calculation from Moon Phase Calculators. Built with blockbuilder.org. Forked from curran‘s block: Moon

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    body {
      margin: 0;position: fixed;top: 0;right: 0;bottom: 0;left: 0;
    }
    text {
      font-size: 1rem;
    }
    .axis .domain, .axis line {
      display: none;
    }
  </style>
</head>

<body>
  <svg width="960" height="380"></svg>
  <script>
    
    var svg = d3.select("svg"),
        width = svg.attr("width"),
        height = svg.attr("height"),
        margin = { left: 100, right: 15, top: 35, bottom: 35 },
        moonSize = 12,
        moonStroke = 0.5,
        axisPadding = moonSize - 2,
        startDate = new Date(2017, 0, 1),
        endDate = new Date(2017, 11, 31);
    
    var g = svg.append("g")
          .attr("transform", "translate(" + [margin.left, margin.top] + ")"),
        innerWidth = width - margin.right - margin.left,
        innerHeight = height - margin.bottom - margin.top,
        formatMonth = d3.timeFormat("%B"),
        formatDay = d3.timeFormat("%d"),
        newMoon = (new Date(1970, 0, 7, 20, 35, 0)).getTime(),
        lunarPeriod = 2551443000,
        data = d3.timeDays(startDate, endDate).map(type);
    
    function type (date){
      return {
        month: formatMonth(date),
        day: formatDay(date),
        phase: -((date.getTime() - newMoon)) / lunarPeriod * 360 + 180
      };
    }
        
    var xScale = d3.scaleLinear()
          .domain(d3.extent(data, function (d){ return d.day; }))
          .range([0, innerWidth]),
        yScale = d3.scalePoint()
          .domain(data.map(function (d){ return d.month; }))
          .range([0, innerHeight]);
    
    var circle = d3.geoCircle(),
        projection = d3.geoOrthographic()
          .scale(moonSize)
          .translate([0, 0]),
        path = d3.geoPath()
          .projection(projection);
    
    g.append("g")
      .attr("class", "y axis")
      .attr("transform", "translate(-" + axisPadding + ")")
      .call(d3.axisLeft().scale(yScale));
    
    g.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0,-" + axisPadding + ")")
      .call(d3.axisTop().scale(xScale).ticks(30));
    
    g.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + (innerHeight + axisPadding) + ")")
      .call(d3.axisBottom().scale(xScale).ticks(30));
    
    var moons = g.selectAll(".moon").data(data)
      .enter().append("g")
        .attr("class", "moon")
        .attr("transform", function (d){
          return "translate(" + [xScale(d.day), yScale(d.month)] + ")";
        });
    
    moons.append("circle")
      .attr("fill", "#2b281b")
      .attr("r", moonSize + moonStroke);
    
    moons.append("path")
      .attr("fill", "#f7f6f2")
      .attr("d", function (d){
        return path(circle.center([d.phase, 0])());
      });
    
    svg.on("click", function (){
      var d = type(new Date());
      g.append("circle")
          .attr("cx", function (){ return xScale(d.day); })
          .attr("cy", function (){ return yScale(d.month); })
          .attr("stroke", "red")
          .attr("stroke-width", "50px")
          .attr("stroke-opacity", 0)
          .attr("fill", "none")
          .attr("r", 500)
        .transition().duration(1000)
          .attr("stroke-width", "3px")
          .attr("stroke-opacity", 1)
          .attr("r", moonSize + 5); 
    });
    
  </script>
</body>