<html>

<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css">
    
</head>

<body>
  <div class="container">
    <div class="row">
	<div class="btn" id="a">Unroll</div>
	<div class="btn" id="b">Rollup</div>
    </div>
    
    <div class="row">
      <div id="holder">
      </div>
  </div>
  </div>
</body>

  <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> 
  <script src="https://d3js.org/d3.v4.min.js"></script>
  


</html>
.circle {
    stroke: #a3e112;
    stroke-dasharray: 2;
    stroke-width: 2;
    fill:none;
    opacity: .2;
}

.line {
    stroke: #a3e112; 
    
    
    /*stroke: rgba(160, 206, 78, 1);*/
    stroke-width: 1;
    fill:none;
    opacity: 1;
}

body {
  background-color: #000000;
  
}

#holder {
  width: 1200px;
  height: 300px;
  
  background-color: black;
}

.container { 
  
}
var numberOfPoints = 145;
var totalPoints = numberOfPoints;
var radius = 24;
var margin = {top: 0, left: 0};
var marginleft = margin.left;
var margintop = margin.top;

var fullAngle = 6 * Math.PI;

var lineLength = radius * fullAngle;
var lineDivision = lineLength / totalPoints;
var cx = 17;
var cy = 17;
var dur = 3000/numberOfPoints;

var aspiral = 10;
var bspiral = 0.5;

var circleStates = [];

for (i = 0; i < totalPoints; i++)
{
    var circleState = $.map(Array(numberOfPoints), function (d, j) {
      
      var angle = fullAngle * (numberOfPoints - j - 1) / (numberOfPoints - 1);
      
      var x = marginleft + radius + lineDivision * i - Math.sin(angle) * (angle * bspiral + aspiral);
      var y = margintop + radius + Math.cos(angle) * (angle * bspiral + aspiral);      
      
      return { x: x, y: y};
    })

    circleState.splice(numberOfPoints - i);

    var lineState = $.map(Array(numberOfPoints), function (d, j) {
      var x = marginleft + radius + lineDivision * j;
      var y = margintop + 1.8 * radius;
      return { x: x, y: y};
    })
    lineState.splice(i);

    var individualState = lineState.concat(circleState);
    circleStates.push(individualState);
}

var pathFunction = d3.line()
    .x(function (d) {return d.x;})
    .y(function (d) {return d.y;})
    
//Attend where needed  

var svgContainer = d3.select("#holder").append("svg").attr("preserveAspectRatio", "xMinYMin meet")
   .attr("viewBox", "0 0 500 50");
        
var circle = svgContainer.append("g")
    .append("path")
    .data([circleStates[0]])
    .attr("d", pathFunction)    
    .attr("class", "line");
   
var unrollSpiral = function() 
{
    for (i = 0; i < numberOfPoints; i++)
    {
        circle.data([circleStates[i]])
            .transition()
            .ease(d3.easeExp)
            .delay(dur * i / 1.7)
            .duration(dur)
            .attr('d', pathFunction)    
            .transition()
            .delay(dur * (numberOfPoints - 1))
            .duration(100)
            .ease(d3.easeLinear)
            //.attr("transform", "scale(0,0.5)")
            
        
    }
}
function reverse() 
{
  for (i = 0; i < numberOfPoints; i++)
  {
      circle.data([circleStates[numberOfPoints-1-i]])
          .transition()
          .delay(dur * i / 2)
          .duration(dur)
          .ease(d3.easeLinear)
          .attr('d', pathFunction) 
          .transition()
          .delay(dur * (numberOfPoints - 1) / 5)
          .duration(00)
          .ease(d3.easeLinear)
          
  }
}

//Manual unroll

$('#a').on("click", unrollSpiral);
$('#b').on("click", reverse);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.