block by curran 28047fcfeb11cc0c66d10e7f30e1fe22

Clock

Full Screen

A clock, constructed using nested components with d3-component.

Since we’re not confined to physical limitations, why not have a “millisecond hand”?!

This is an optimized and refactored version of the first-pass implementation: Poorly Performing 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>
</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,
              midnight = d3.timeDay(new Date()).getTime(),
              second = 1000,
              minute = second * 60,
              hour = minute * 60,
              day = hour * 12;
        
        	// Update SVG dimensions.
          selection
              .attr("width", width)
              .attr("height", height);
          
        	// Outer circle.
        	selection.append("circle")
            	.attr("cx", width / 2)
              .attr("cy", height / 2)
              .attr("r", side / 2 - outerCircleStrokeWidth)
              .attr("fill", "none")
              .attr("stroke", "black")
              .attr("stroke-width", outerCircleStrokeWidth);
        
          // Central circle.
        	selection.append("circle")
            	.attr("cx", width / 2)
              .attr("cy", height / 2)
              .attr("r", centralCircleRadius);
        	
          function hand(handLength, handWidth, color){
            var spindle = selection.append("g")
                .attr("transform", "translate(" + width/2 + "," + height/2 + ")")
              .append("g");
            spindle.append("line")
                .attr("x2", side / 2 * handLength)
                .attr("stroke", color || "black")
                .attr("stroke-width", side * handWidth);
            return spindle;
          }
        
        	var hourHand = hand(d.hourHandLength, d.hourHandWidth),
        	    minuteHand = hand(d.minuteHandLength, d.minuteHandWidth),
        	    secondHand = hand(d.secondHandLength, d.secondHandWidth),
        	    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, day) + ")");
            minuteHand.attr("transform", "rotate(" + angle(ms, hour) + ")");
            secondHand.attr("transform", "rotate(" + angle(ms, minute) + ")");
            millisecondHand.attr("transform", "rotate(" + angle(ms, second) + ")");
          }));
        })
      	.destroy(function (selection){
        	timerLocal.get(selection.node()).stop();
        });
    }());

    d3.select("body")
      .call(clock, {
        width: 960,
        height: 500,
        outerCircleThickness: 0.01,
        centralCircleSize: 0.04,
        hourHandLength: 0.7,
        hourHandWidth: 0.03,
        minuteHandLength: 0.85,
        minuteHandWidth: 0.015,
        secondHandLength: 0.9,
        secondHandWidth: 0.005,
        msHandLength: 0.08,
        msHandWidth: 0.004
      });

  </script>
</body>