JSFiddle - React, Tailwind, and code Playground

by Alexandru Gatea

HTML

<div id="svgContainer">
  <svg id="svg1">
    <path class="path1" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
    <path class="path2" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
    <path class="path3" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
    <path class="path4" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
    <path class="path1" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
    <path class="path2" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
    <path class="path3" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
    <path class="path4" d="M0 0" stroke="black" stroke-width="4px" fill="none" />
  </svg>
</div>
<div class="section"></div>
<div class="section">
  <div class="container">
    <div class="connect-these">
      <div id="res"></div>
      <div id="act"></div>
      <div id="mkt"></div>
      <div id="prod"></div>
    </div>

  </div>
</div>
<div class="section">
  <div class="container">
    <div class="to-this">
      <div id="output"></div>
    </div>
  </div>
</div>
<div class="section"></div>

SCSS

body {
  position: relative;
}
.section {
  height: 200vh;
}

.section:nth-child(even) {
  background: rgba(0,0,0,0.2);
}
.container {
  display: flex;
  height: 50vh;
  flex-direction: column;
  position: relative;
  position: sticky;
  top: 0;
  
  .connect-these {
    display: flex;
    width: 420px;
    flex-wrap: wrap;
    position: absolute;
    top: 0;
}
  .connect-these div {
    width: 100px;
    height: 100px;
    border: 4px solid black;
    margin: 20px;
    background: white;
    border-radius: 10px;
    position: relative;
    
    &::after {
      content: "";
      width: 20px;
      height: 20px;
      background: #fff;
      border-radius: 32px;
      border: 4px solid #000;
      position: absolute;
      top: 100%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    &:nth-child(3) {
      margin-left: 100px;
    }
  }

  .to-this {
    display: flex;
    align-items: flex-end;
    justify-content: flex-end;
    margin-top: 0;
    margin-right: 100px;
    position: absolute;
    bottom:0;
    right:0;
      
    #output {
      width: 100px;
      height: 100px;
      border: 4px solid black;
      margin: 20px;
      background: white;
      border-radius: 10px;
      position: absolute;
      
      &::after {
        content: "";
        width: 20px;
        height: 20px;
        background: #fff;
        border-radius: 32px;
        border: 4px solid #000;
        position: absolute;
        top: 0%;
        left: 50%;
        transform: translate(-50%, -50%);
      }
    }
  }
}

#svgContainer {
	z-index: -10;
	position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  svg {
    width: 100%;
    height: 100%;
  }
}

JavaScript

function drawPath(path, goDown, bezieDown, bezierUp, startX, startY, endX, endY) {
      path.attr("d", "M" + startX + " " + startY +
        " L" + startX + " " + goDown +
        " C" + startX + " " + (goDown + bezieDown) + " " + endX + " " + (endY - bezierUp) + " " + endX + " " + endY);
    }


    function connectElements(path, offset, off, startElem, endElem) {
      var svgContainer = $("#svgContainer");
      var svgTop = svgContainer.offset().top;
      var svgLeft = svgContainer.offset().left;
      var startCoord = startElem.offset();
      var endCoord = endElem.offset();
      var startX = startCoord.left + 0.5 * startElem.outerWidth() - svgLeft;
      var startY = startCoord.top + startElem.outerHeight() - svgTop;
      var endX = endCoord.left + 0.5 * endElem.outerWidth() - svgLeft;
      var endY = endCoord.top + (endElem.outerHeight() / 2) - svgTop;
      var goDown = startY + offset;
      var bezieDown = (endCoord.top - startCoord.top) / 3;
      var bezierUp = off;
      drawPath(path, goDown, bezieDown, bezierUp, startX, startY, endX, endY);
      //$("#svg1").attr("height", "100%").attr("width", "100%");
    }

    function connectAll() {
      connectElements($(".path1"), 200, 200, $("#res"), $("#output"));
      connectElements($(".path2"), 200, 200, $("#act"), $("#output"));
      connectElements($(".path3"), 200, 200, $("#mkt"), $("#output"));
      connectElements($(".path4"), 200, 200, $("#prod"), $("#output"));

    }

    $(document).ready(function() {
      //$("#svg1").attr("height", "0").attr("width", "0");
      connectAll();
    });

    $(window).resize(function() {
      //$("#svg1").attr("height", "0").attr("width", "0");
      connectAll();
    });

    $(window).scroll(function() {
      //$("#svg1").attr("height", "0").attr("width", "0");
      connectAll();
    });