SVG heart button animated using GSAP (greensock)
A Pen by IpsumLorem16 on CodePen.
<button data-liked="false"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="42" height="42" viewBox="0 0 42 42" fill="none"> | |
<g id="heart_lines" opacity="0"> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
<g class="line-wrapper"> | |
<rect class="heart-line" x="19" y="0" width="3.30527" height="11.3992" rx="1.65264" fill="#C80000"/> | |
</g> | |
</g> | |
<path id="heart_button" d="M20.877 6.69703C20.046 6.04303 19.13 5.50502 18.15 5.09602C16.734 4.50602 15.215 4.20098 13.68 4.19898C12.146 4.19698 10.626 4.49799 9.20802 5.08399C7.79002 5.67099 6.50103 6.53101 5.41603 7.61701C4.33103 8.70201 3.47102 9.99101 2.88502 11.409C2.29802 12.827 1.99801 14.348 2.00001 15.882C2.00201 17.417 2.30701 18.936 2.89701 20.353C3.48601 21.769 4.35002 23.055 5.43702 24.137C5.43702 24.138 5.43803 24.138 5.43803 24.139L19.811 38.515L20.871 39.576L21.932 38.515L36.307 24.136L36.31 24.133C38.488 21.943 39.709 18.979 39.705 15.89C39.701 12.801 38.473 9.83898 36.289 7.65498C34.105 5.46998 31.144 4.24101 28.055 4.23701C25.442 4.23401 22.918 5.10803 20.877 6.69703Z" stroke="#B9B9B9" stroke-width="3"/> | |
</svg> | |
</button> |
/*heart lines animation*/ | |
function heartLines() { | |
let lineWraps, tl; | |
//loop though line wrappers and rotate evenly around 360deg | |
lineWraps = document.querySelectorAll(".line-wrapper"); | |
for (i = 0; i < lineWraps.length; i++) { | |
let degrees = i * (360 / lineWraps.length); | |
gsap.set(lineWraps[i], { | |
rotation: degrees, | |
transformOrigin: "center bottom" | |
}); | |
} | |
//create timeline | |
tl = gsap | |
.timeline() | |
.set("#heart_lines", { | |
opacity: 1, | |
transformOrigin: "center bottom", | |
y: 10, | |
scale: 1.2, | |
}) | |
.to(".heart-line", { | |
transformOrigin: "bottom center", | |
duration: 1, | |
y: -25, | |
height: 3 | |
}) | |
.to("#heart_lines", { | |
opacity: 0, | |
duration: 0.3, | |
position: "-=0.3" | |
}); | |
return tl; | |
} | |
/* heart shape animation */ | |
function heartShape({on}) { | |
let tl = gsap | |
.timeline({ | |
defaults: { | |
transformOrigin: "center center" | |
} | |
}) | |
.to("#heart_button", { | |
duration: 0.2, | |
scale: 0.8 | |
}) | |
.to("#heart_button", { | |
duration: 0.2, | |
fill: on ? "red": "none", | |
stroke: on ? "red": "rgb(185, 185, 185)", | |
position: "-=0.15" | |
}) | |
.to("#heart_button", { | |
duration: 1.2, | |
scale: 1, | |
ease: on ? "elastic.out(1.1, 0.2)" : "Power1.easeOut" | |
}); | |
return tl; | |
} | |
let heartOn = gsap.timeline() | |
.add(heartShape({on:true})) | |
.add(heartLines(), "<0.4") | |
.timeScale(2) | |
.pause(); | |
let heartOff = gsap.timeline() | |
.add(heartShape({on:false})) | |
.timeScale(3) | |
.pause(); | |
const button = document.querySelector("button"); | |
function toggleHeartBtn() { | |
if (button.getAttribute("data-liked") === "false") { | |
heartOff.pause(); | |
heartOn.play(0); | |
gsap.set(".heart-line",{opacity:1}); | |
button.setAttribute("data-liked", "true"); | |
} else { | |
heartOn.pause(); | |
gsap.set(".heart-line",{opacity:0}); | |
heartOff.play(0); | |
button.setAttribute("data-liked", "false"); | |
} | |
} | |
button.addEventListener("click", () => { | |
toggleHeartBtn(); | |
}); |
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.0.2/gsap.min.js"></script> |
htlm,body { | |
padding:0; | |
margin:0; | |
height:100vh; | |
} | |
body { | |
display:flex; | |
display: flex; | |
flex-direction: row; | |
justify-content: center; | |
align-items: center; | |
} | |
button { | |
outline:none; | |
padding:2px; | |
border: 0; | |
background:none; | |
display:inline-block; | |
cursor:pointer; | |
-webkit-user-select: none; | |
-webkit-tap-highlight-color: transparent; | |
} | |
svg { | |
display:block; | |
margin:0 auto; | |
max-height:100%; | |
max-width:100%; | |
overflow:visible; | |
pointer-events:none; | |
} | |