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();
});