block by jeremycflin cedd1e29495520c41a2cc05199717fe8

Starry Sky (Long Exposure)

Full Screen

Recreating a long exposure photograph of the night sky in d3. Randomly generate circles and arcs. Arcs are animated using attrTween.

forked from tlfrd‘s block: Starry Sky (Long Exposure)

forked from anonymous‘s block: Starry Sky (Long Exposure)

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; };
  </style>
</head>

<body>
  <script>
    var width = 960,
        height = 960;
    
    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);
    
    var definitions = svg.append("defs");
    var filter = definitions.append("filter")
    	.attr("id", "glow");
    filter.append("feGaussianBlur")
      .attr("class", "blur")
      .attr("stdDeviation", 2)
      .attr("result","coloredBlur");
    var feMerge = filter.append("feMerge")
    feMerge.append("feMergeNode")
      .attr("in","coloredBlur");
    feMerge.append("feMergeNode")
      .attr("in","SourceGraphic");
    
    var gradient = definitions.append("linearGradient")
      .attr("id", "gradient")
      .attr("x1", "0%")
      .attr("y1", "0%")
      .attr("x2", "0%")
      .attr("y2", "100%")
      .attr("spreadMethod", "pad");

  	gradient.append("stop")
      .attr("offset", "0%")
      .attr("stop-color", "#black")
      .attr("stop-opacity", 1);

		gradient.append("stop")
      .attr("offset", "100%")
      .attr("stop-color", "#131862")
      .attr("stop-opacity", 1);
    
    var bg = svg.append("rect")
    	.attr("width", width)
    	.attr("height", height)
    	.style("fill", "url(#gradient)")
        
    var tau = 2 * Math.PI;
    
    var config = {
      starRadius: 2,
      rotationPoint: [width / 2, height / 2],
      angle: 45,
      arcLength: 0
    };
    
    var g = svg.append("g")
    	.attr("transform", "translate(" + config.rotationPoint + ")");    
    
    function calculateDistance(point) {
      return Math.sqrt(Math.pow(point[0], 2) + Math.pow(point[1], 2));
    }
    
    function calculateAngle(point) {
      var angle = Math.atan2(point[1], point[0]) + Math.PI / 2;
      return angle;
    }
    
    var stars;
    
    generateStars(500, false);
    
    svg.append("circle")
    	.attr("cx", config.rotationPoint[0])
    	.attr("cy", config.rotationPoint[1])
    	.attr("r", 2.5)
    	.style("fill", "white")
    	.style("filter", "url(#glow)");
    
   	function generateStars(number, glow) {
      var starData = d3.range(number).map(d => 
           i = {x: Math.random() * (width) - (width / 2), 
                y: Math.random() * (height) - (height / 2), 
                r: Math.random() * config.starRadius,
                opacity: Math.random()
               }
        );
      
      stars = g.selectAll("circle")
      	.data(starData)
      	.enter().append("circle")
      		.attr("class", "star")
      		.attr("cx", d => d.x)
      		.attr("cy", d => d.y)
      		.attr("r", d => d.r)
      		.style("opacity", d => d.opacity)
      		.style("fill", "white")
    			.style("filter", glow ? "url(#glow)" : "");
      
      
      stars.transition()
      	.duration(10000)
      	.style("opacity", 0);
      
      starData.forEach(d => {        
      	var arc = d3.arc()
          .innerRadius(calculateDistance([d.x, d.y]))
          .outerRadius(calculateDistance([d.x, d.y]))
          .startAngle(calculateAngle([d.x, d.y]) + config.arcLength);
        
        var arcLine = g.append("path")
          .datum({endAngle: calculateAngle([d.x, d.y])})
          .style("stroke", "white")
        	.style("stroke-width", d.r)
        	.style("opacity", d.opacity)
        	.style("stroke-linecap", "round")
          .attr("d", arc)
    			.style("filter", glow ? "url(#glow)" : "");

        
        
       	arcLine.transition()
          .duration(20000)
          .attrTween("d", arcTween(calculateAngle([d.x, d.y]) + 1));
      
        function arcTween(newAngle) {
          return function(a) {
            var interpolate = d3.interpolate(a.endAngle, newAngle);

            return function(t) {
              a.endAngle = interpolate(t);
              return arc(a);
            };
          };
        }
        
      });

    }
    

  </script>
</body>