block by enjalot f8c41743ca81d7828c3a

visfest experiment #3

Full Screen

hello markdown

forked from enjalot‘s block: visfest logo - technical experiment #2

forked from enjalot‘s block: visfest logo - technical experiment #3

forked from enjalot‘s block: visfest logo - technical experiment #4

forked from enjalot‘s block: visfest logo - technical experiment #5

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  <script src="sampler.js"></script>
</head>
<style>
  body {
    background-color: #192247;
  }
</style>


<body>
<svg width=960 height=500>
  <g transform="translate(-50,0)" opacity=0>
	<path id="outer" fill="none" stroke="#000000" stroke-width="0.8" stroke-miterlimit="10" d="M174.7,85c-24.5,14-57,18-45.8,45.7
		c9.5,23.4-28.2,15.1-45.8-25.7s20.5-65.8,45.8-65.8S196.7,72.5,174.7,85Z"/>
	<path id="inner" fill="none" stroke="#000000" stroke-width="0.8" stroke-miterlimit="10" d="M128.4,64.4c-1.9-0.1-5.9,6-5.9,6s-2.3-3.6-1-7.4
		c1.4-3.8,3.4-3.5,5-3.1C128.3,60.2,141.8,65.1,128.4,64.4z"/>
  </g>
  <g id="output">
  </g>
</svg>


  <script>
    var svg = d3.select("svg");
    var inner = d3.select("#inner")
    var outer = d3.select("#outer")
    var numSamples = 20;
    var numLines = 31;
    
    var scale = 3;
    var xOffset = 0;
    var yOffset = 40;
    

    
    var line = d3.svg.line()
      .x(function(d) { return d.x })
      .y(function(d) { return d.y })
      //.interpolate("linear-closed")
      .interpolate("cardinal-closed")
      .interpolate("basis-closed")
    
    var ins = Sampler.getSamples(inner.node(), numSamples);
    var outs = Sampler.getSamples(outer.node(), numSamples);
    
    var output = d3.select("#output")
    
    
    var lines = [];
    d3.range(numLines).forEach(function(index) {
      var samples = []
      var ratio = index / numLines;
      var i, x, y;
      for(i = 0; i < numSamples; i++) {
        x = ins[i].x * (1 - ratio) + outs[i].x * ratio;
        y = ins[i].y * (1 - ratio) + outs[i].y * ratio;
        samples.push({ x: x * scale + xOffset, y: y * scale + yOffset})
      }
      lines.push(samples)
    })
    
    var blended = output.selectAll("path.blend")
    .data(lines)
    blended
    .enter()
    .append("path").classed("blend", true)
    .attr({
      d: function(d) { return line(d) },
      fill: "none",
      stroke: "#ff005d",
      "stroke-width": 2,
    })
    
    var bbox = blended.node().getBoundingClientRect();
    console.log("BBOX", bbox)
    var center = {
      x: bbox.left + bbox.width/2 - 15,
      y: bbox.top + bbox.height/2 -15 
    }
    
    blended.attr({
      transform: "rotate(0, " + [center.x, center.y] + ")"
    })
    
    output.append("circle")
    .attr({
      r: 5,
      cx: center.x,
      cy: center.y,
      //fill: "white"
      fill: "none"
    })
   
    function transition() {
      blended.transition()
        .ease("cubic")
        .duration(800)
        .delay(function(d,i) { return (numLines - i) * 100 })
        .attrTween("transform", function(d) {
          return function(t) {
            var deg = d3.interpolate(0, 180)(t)
					  return "rotate(" + deg + "," + [center.x, center.y] + ")" 
          }
        })
        .each("end", function(d,i) {
          if(i !== 0) return;
          blended//.filter(function(d,j) { return i === j })
            .transition()
            .ease("sin")
            .duration(600)
            .delay(function(d,j) { return (numLines - j) * 100 + 800 })
            .attrTween("transform", function(d) {
              return function(t) {
                var deg = d3.interpolate(180, 0)(t)
                return "rotate(" + deg + "," + [center.x, center.y] + ")" 
              }
            })
            .each("end", function(d,k) {
              if(i === 0) {
                transition();
              }
            })
            
        })

    }
    transition()
    

 
    
    
  </script>
</body>









sampler.js

var Sampler = function() {}

Sampler.getSamples = function(path, num) {
  var len = path.getTotalLength()
  var p, t;
  var result = []
  for(var i = 0; i < num; i++) {
    p = path.getPointAtLength(i * len/num);
    t = Sampler.getTangent(path, i/num * 100);
    result.push({
      x: p.x,
      y: p.y,
      point: p, 
      tangent: t,
      perp: Sampler.rotate2d(t.v, 90)
    });
  }
  return result
}

Sampler.getTangent = function(path, percent) {
  // returns a normalized vector that describes the tangent
  // at the point that is found at *percent* of the path's length
  var fraction = percent/100;
  if(fraction < 0) fraction = 0;
  if(fraction > 0.99) fraction = 1;
  
  var len = path.getTotalLength();
  var point1 = path.getPointAtLength(fraction * len - 0.1);
  var point2 = path.getPointAtLength(fraction * len + 0.1);
 
  var vector = { x: point2.x - point1.x, y: point2.y - point1.y }
  var magnitude = Math.sqrt(vector.x*vector.x + vector.y*vector.y);
  vector.x /= magnitude;
  vector.y /= magnitude;

  return {p: point1, v: vector };
}

Sampler.rotate2d = function(vector, angle) {
  //rotate a vector 
  angle *= Math.PI/180; //convert to radians
  return {
    x: vector.x * Math.cos(angle) - vector.y * Math.sin(angle),
    y: vector.x * Math.sin(angle) + vector.y * Math.cos(angle)
  }
}