block by curran 598e90fe0dcab73030dbecc38fb6e725

Airport Clocks

Full Screen

Would accurate clocks tick in sync all around the world?

Made with d3-component.

forked from curran‘s block: Clock

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://unpkg.com/d3@4"></script>
  <script src="https://unpkg.com/d3-component@3"></script>
  <style>
    body {
      margin: 0px;
    }
    .labeled-clock {
      display: inline-block;
      margin:  0px 0px 11px 24px;
    }
    .clock-label {
      margin:  -3px 0px 0px 0px;
      text-align: center;
      font-size: 1.8em;
    }
  </style>
</head>
<body>
  <script>
    var clock = (function (){
      var timerLocal = d3.local();
      return d3.component("svg")
      	.create(function (selection, d){
        	var width = d.width,
              height = d.height,
              side = Math.min(width, height),
              outerCircleStrokeWidth = side * d.outerCircleThickness,
              centralCircleRadius = side * d.centralCircleSize,
              numbersRadius = side/2 * d.numbersRadius,
              numbersFontSize = side/10 * d.numbersSize  + "px",
              numbersXOffset =  side * d.numbersXOffset,
              numbersYOffset =  side * d.numbersYOffset,
              ampmFontSize = side/10 * d.ampmSize  + "px",
              second = 1000,
              minute = second * 60,
              hour = minute * 60,
              day = hour * 24,
              halfDay = hour * 12,
              // TODO add actual check for whether we're in daylight savings time.
              daylightSavingsOffset = d.daylightSavings ? 1 : 0,
              timeZoneOffset = d.timeZoneOffset + daylightSavingsOffset,
              midnight = d3.utcDay(new Date()) - timeZoneOffset * hour,
              grays = d3.interpolateLab("black", "lightgray"),
              axle = selection.append("g")
                  .attr("transform", "translate(" + [width/2, height/2] + ")"),
              outerCircle = axle.append("circle")
                  .attr("r", side / 2 - outerCircleStrokeWidth)
                  .attr("fill", d.fillColor)
                  .attr("stroke", "black")
                  .attr("stroke-width", outerCircleStrokeWidth),
              ampm = axle.append("text")
                  .attr("text-anchor", "middle")
                  .attr("alignment-baseline", "middle")
                  .attr("font-size", ampmFontSize)
                  .attr("font-family", d.ampmFontFamily)
          				.attr("fill", d.ampmColor)
          				.attr("y", side * d.ampmYOffset);
        
          // SVG dimensions.
          selection
              .attr("width", width)
              .attr("height", height);
        
        	// Numbers.
        	axle.selectAll(".number").data(d3.range(12).reverse())
          	.enter().append("text")
          		.attr("class", "number")
          		.attr("x", function (d, i){
            		return -Math.sin(i/6 * Math.PI) * numbersRadius + numbersXOffset;
          		})
          		.attr("y", function (d, i){
            		return -Math.cos(i/6 * Math.PI) * numbersRadius + numbersYOffset;
          		})
          		.attr("text-anchor", "middle")
              .attr("alignment-baseline", "middle")
          		.attr("font-size", numbersFontSize)
          		.attr("font-family", d.numbersFontFamily)
              .text(function (d){ return d + 1; });
        
        	// Ticks.
        	var tickMinorRadius = side / 2 * d.tickMinorRadius,
              tickMajorRadius = side / 2 * d.tickMajorRadius,
              tickRingRadius = side / 2 * d.tickRingRadius;
        	axle.selectAll(".tick").data(d3.range(60))
          	.enter().append("circle")
          		.attr("class", "tick")
          		.attr("cx", function (d, i){
            		return Math.sin(i/30 * Math.PI) * tickRingRadius;
          		})
          		.attr("cy", function (d, i){
            		return Math.cos(i/30 * Math.PI) * tickRingRadius;
          		})
          		.attr("r", function (d, i){
                return i % 5 ? tickMinorRadius : tickMajorRadius;
              })
          		.attr("fill", "black")
        
          function hand(handLength, handWidth, color){
            var spindle = axle.append("g");
            spindle.append("line")
                .attr("x2", side / 2 * handLength)
                .attr("stroke", color || "black")
                .attr("stroke-width", side * handWidth)
            		.attr("stroke-linecap","round");
            return spindle;
          }
       
        	var hourHand = hand(d.hourHandLength, d.hourHandWidth),
        	    minuteHand = hand(d.minuteHandLength, d.minuteHandWidth),
        	    secondHand = hand(d.secondHandLength, d.secondHandWidth),
              centralCircle = axle.append("circle")
                  .attr("r", centralCircleRadius),
        	    millisecondHand = hand(d.msHandLength, d.msHandWidth, "white");
        
          function angle(ms, timespan){
            return (ms / timespan % 1) * 360 - 90;
          }
        
        	timerLocal.set(selection.node(), d3.timer(function (){
            var ms = Date.now() - midnight;
            hourHand.attr("transform", "rotate(" + angle(ms, halfDay) + ")");
            minuteHand.attr("transform", "rotate(" + angle(ms, hour) + ")");
            secondHand.attr("transform", "rotate(" + angle(ms, minute) + ")");
            millisecondHand.attr("transform", "rotate(" + angle(ms, second) + ")");
            
            centralCircle.attr("fill", grays(angle(ms, second) / 360));
            
            ampm.text((ms / day % 1) < 0.5 ? "AM" : "PM");
          }));
        })
      	.destroy(function (selection){
        	timerLocal.get(selection.node()).stop();
        });
    }());
    
    var label = d3.component("div", "clock-label")
    	.render(function (selection, d){ selection.text(d); });
    
    var labeledClock = d3.component("div", "labeled-clock")
    	.render(function (selection, d){
        selection
          .call(clock, d)
        	.call(label, d.label);
      });
    
    var clockStyle = {
      width: 210,
      height: 210,
      outerCircleThickness: 0.01,
      centralCircleSize: 0.04,
      hourHandLength: 0.56,
      hourHandWidth: 0.0348,
      minuteHandLength: 0.65,
      minuteHandWidth: 0.015,
      secondHandLength: 0.9,
      secondHandWidth: 0.005,
      msHandLength: 0.08,
      msHandWidth: 0.005,
      numbersRadius: 0.84,
      numbersSize: 1.2144,
      numbersFontFamily: "serif",
      numbersXOffset: 0.000,
      numbersYOffset: 0.015,
      fillColor: "#fffef9",
      ampmSize: 2.3,
      ampmFontFamily: "sans-serif",
      ampmColor: "#c5c3b8",
      ampmYOffset: 0.18,
      tickRingRadius: 0.68,
      tickMinorRadius: 0.01,
      tickMajorRadius: 0.02
    }

    labeledClock(document.body, [
      { label: "San Francisco", timeZoneOffset: -8, daylightSavings: true },
      { label: "New York", timeZoneOffset: -5, daylightSavings: true },
      { label: "Sao Paulo", timeZoneOffset: -3 },
      { label: "London", timeZoneOffset: 0 },
      { label: "Dubai", timeZoneOffset: 4 },
      { label: "Mumbai", timeZoneOffset: 5.5 },
      { label: "Beijing", timeZoneOffset: 8 },
      { label: "Sydney", timeZoneOffset: 11 }
    ], clockStyle);

  </script>
</body>