JSFiddle - React, Tailwind, and code Playground

by BurpmanJunior

HTML

<div class="stage">
  <div class="content-block" id="block-1" style="margin-top: 50px;">
    <h2 class="title"><span>Block Title</span></h2>
    <p>Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Suspendisse faucibus, nunc et pellentesque egestas, lacus ante convallis tellus, vitae iaculis lacus elit id tortor. Vestibulum eu odio. Sed augue ipsum, egestas nec, vestibulum et, malesuada adipiscing, dui. Praesent egestas neque eu enim.</p>
  <p>Praesent ut ligula non mi varius sagittis. Nunc egestas, augue at pellentesque laoreet, felis eros vehicula leo, at malesuada velit leo quis pede. Vestibulum fringilla pede sit amet augue. Etiam sollicitudin, ipsum eu pulvinar rutrum, tellus ipsum laoreet sapien, quis venenatis ante odio sit amet eros. Cras risus ipsum, faucibus ut, ullamcorper id, varius ac, leo.</p>
  <p>In hac habitasse platea dictumst. Phasellus consectetuer vestibulum elit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce id purus. Proin sapien ipsum, porta a, auctor quis, euismod ut, mi. Nunc nec neque.</p>
  <p>Donec orci lectus, aliquam ut, faucibus non, euismod id, nulla. Morbi nec metus. Mauris turpis nunc, blandit et, volutpat molestie, porta ut, ligula. Curabitur suscipit suscipit tellus. Etiam sollicitudin, ipsum eu pulvinar rutrum, tellus ipsum laoreet sapien, quis venenatis ante odio sit amet eros.</p>
  <p>Morbi ac felis. Vestibulum eu odio. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Nam adipiscing. Nunc sed turpis.</p>
  </div>
  <div class="content-block" id="block-2" style="max-width: 450px;">
    <h2 class="title"><span>Block Title</span></h2>
    <p>In ut quam vitae odio lacinia tincidunt. Morbi vestibulum volutpat enim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed aliquam, nisi quis porttitor congue, elit erat euismod orci, ac placerat dolor lectus quis orci. Proin faucibus arcu quis ante.</p>
 ...

SCSS

@import url(https://fonts.googleapis.com/css?family=PT+Serif|Montserrat:700);

html,body{
  margin: 0;
  position: relative;
  min-height: 100%;
  font-family: 'PT Serif', sans-serif;
  font-weight: 400;
  font-size: 16px;
  color: #333;
  background-color: #BFE8CF;
  line-height: 1.4;
}

body{
  margin: 2em;
}

*,
*:before,
*:after{
  box-sizing: border-box;
}

p{
  margin: 0 0 1em;
  
  &:last-child{
    margin-bottom: 0;
  }
  
}

h1,h2,h3,h4,h5{
  font-family: 'Montserrat', sans-serif;
  font-weight: 700;
  margin: 0 0 0.5em;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.stage{
  position: relative;
  margin-bottom: 2em;
  
  & > * + *{
    margin-top: 2em;
  }
  
}

.content-block{
  background-color: #A77BAA;
  color: #FFF;
  padding: 1em;
  border-bottom: 0.25em solid #846187;
  position: relative;
  z-index: 2;
  margin-left: auto;
  margin-right: auto;
  
  h1,h2,h3,h4,h5{
    text-align: center;
    
    &:before{
      content: '';
      display: block;
      border-bottom: 1px solid currentColor;
      opacity: 0.25;
      position: relative;
      z-index: 0;
      top: 0.72em;
    }
    
    span{
      background-color: #A77BAA;
      padding: 0 0.5em;
      position: relative;
    }
    
  }
  
}

@media only screen and (min-width: 800px){
  
  .stage{
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    
    & > *{
      margin: 0;
    }
    
    & > * + *{
      margin-top: 0;
      margin-left: 3em;
    }
    
  }
  
  .content-block{
    max-width: 450px;
  }
  
}

@media only screen and (min-width: 1100px){
  
  .stage{
    align-items: center;
  }
  
}

JavaScript

var edgeProject = function(options){
	var defaultSVGCSS,
      defaultPolygonCSS;
      
  this.RAD2DEG_MOD = 180 / Math.PI;
    
  /**
   * Merge options
   */
  this.conf = {
    from: null,
    to: null,
    svgCSS: {},
    polygonCSS: {}
  }
  for(prop in options){
    this.conf[prop] = options[prop];
  }
  defaultSVGCSS = {
  	zIndex: 0
  }
  defaultPolygonCSS = {
    fill: '#eee',
    stroke: '#000',
    strokeWidth: 0  
  }
  for(prop in defaultSVGCSS){
    if(!this.conf.svgCSS[prop]){
    	this.conf.svgCSS[prop] = defaultSVGCSS[prop];
    }
  }
  for(prop in defaultPolygonCSS){
    if(!this.conf.polygonCSS[prop]){
    	this.conf.polygonCSS[prop] = defaultPolygonCSS[prop];
    }
  }
  /**
   * Init
   */
  if(!this.conf.from || !this.conf.to){ return false; }
  if(!this.conf.shapeId){
	  this.SHAPE_ID = ['projection', new Date().getTime(), (Math.floor(Math.random() * 1000))].join('-');
  }else{
  	this.SHAPE_ID = conf.shapeId;
  }
  this.process();
  this.bindEvt();
  
  return this;
}

edgeProject.prototype.bindEvt = function(){
	var self = this;
  window.addEventListener('resize', function(){ self.process.apply(self); });
  document.addEventListener('scroll', function(){ self.process.apply(self); });
}

edgeProject.prototype.process = function(){
  this.renderProjection(this.polygonData(this.pointCalc()));
}

edgeProject.prototype.pointCalc = function(){
  var from,
      from_rect,
      to,
      to_rect,
      xRange,
      yRange,
      direction = [];

  from_rect = this.conf.from.getBoundingClientRect();
  to_rect = this.conf.to.getBoundingClientRect();
  
  xRange = [Math.min(from_rect.left, to_rect.left), Math.max((from_rect.left + from_rect.width), (to_rect.left + to_rect.width))];
  yRange = [Math.min(from_rect.top, to_rect.top), Math.max((from_rect.top + from_rect.height), (to_rect.top + to_rect.height))];

  from = [
    [from_rect.left, from_rect.top],
    [(from_rect.left + from_rect.width), from_rect.top],
    [(from_rect.left +...