-
-
Save JonathanDn/09c3e0f037c4c52efcf56ee0878d5e4c to your computer and use it in GitHub Desktop.
| <div class="canvas"> | |
| <div id="totalCounter" class="total-counter"></div> | |
| <div id="clap" class="clap-container"> | |
| <i class="clap-icon fa fa-hand-paper-o"></i> | |
| </div> | |
| <div id="clicker" class="click-counter"> | |
| <span class="counter"></span> | |
| </div> | |
| <div id="sonar-clap" class="clap-container-sonar"></div> | |
| <div id="particles" class="particles-container"> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| </div> | |
| <div id="particles-2" class="particles-container"> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| </div> | |
| <div id="particles-3" class="particles-container"> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| <div class="triangle"> | |
| <div class="square"></div> | |
| </div> | |
| </div> | |
| </div> |
| let accCounter = 0; | |
| let totalCount = 127; | |
| const minDeg = 1; | |
| const maxDeg = 72; | |
| const particlesClasses = [ | |
| { | |
| class: "pop-top" | |
| }, | |
| { | |
| class: "pop-top-left" | |
| }, | |
| { | |
| class: "pop-top-right" | |
| }, | |
| { | |
| class: "pop-bottom-right" | |
| }, | |
| { | |
| class: "pop-bottom-left" | |
| }, | |
| ]; | |
| document.getElementById('totalCounter').innerText = totalCount; | |
| document.getElementById('clap').onmouseover = function() { | |
| let sonarClap = document.getElementById('sonar-clap'); | |
| sonarClap.classList.add('hover-active'); | |
| setTimeout(() => { | |
| sonarClap.classList.remove('hover-active'); | |
| }, 2000); | |
| } | |
| document.getElementById('clap').onclick = function() { | |
| const clap = document.getElementById('clap'); | |
| const clickCounter = document.getElementById("clicker"); | |
| const particles = document.getElementById('particles'); | |
| const particles2 = document.getElementById('particles-2'); | |
| const particles3 = document.getElementById('particles-3'); | |
| clap.classList.add('clicked'); | |
| upClickCounter(); | |
| runAnimationCycle(clap, 'scale'); | |
| if (!particles.classList.contains('animating')) { | |
| animateParticles(particles, 700); | |
| } else if(!particles2.classList.contains('animating')){ | |
| animateParticles(particles2, 700); | |
| } else if(!particles3.classList.contains('animating')) { | |
| animateParticles(particles3, 700); | |
| } | |
| } | |
| function upClickCounter() { | |
| const clickCounter = document.getElementById("clicker"); | |
| const totalClickCounter = document.getElementById('totalCounter'); | |
| accCounter ++; | |
| clickCounter.children[0].innerText = '+' + accCounter; | |
| totalClickCounter.innerText = totalCount + accCounter; | |
| if (clickCounter.classList.contains('first-active')) { | |
| runAnimationCycle(clickCounter, 'active'); | |
| } else { | |
| runAnimationCycle(clickCounter, 'first-active'); | |
| } | |
| runAnimationCycle(totalClickCounter, 'fader'); | |
| } | |
| function runAnimationCycle(el, className, duration) { | |
| if (el && !el.classList.contains(className)) { | |
| el.classList.add(className); | |
| } else { | |
| el.classList.remove(className); | |
| void el.offsetWidth; // Trigger a reflow in between removing and adding the class name | |
| el.classList.add(className); | |
| } | |
| } | |
| function runParticleAnimationCycle(el, className, duration) { | |
| if (el && !el.classList.contains(className)) { | |
| el.classList.add(className); | |
| setTimeout(() => { | |
| el.classList.remove(className); | |
| }, duration); | |
| } | |
| } | |
| function animateParticles(particles, dur) { | |
| addRandomParticlesRotation(particles.id, minDeg, maxDeg); | |
| for(let i = 0; i < particlesClasses.length; i++) { | |
| runParticleAnimationCycle(particles.children[i], particlesClasses[i].class, dur); | |
| } | |
| // Boolean functionality only to activate particles2, particles3 when needed | |
| particles.classList.add('animating'); | |
| setTimeout(() => { | |
| particles.classList.remove('animating'); | |
| }, dur); | |
| } | |
| function getRandomInt(min, max) { | |
| return Math.floor(Math.random() * (max - min + 1)) + min; | |
| } | |
| function addRandomParticlesRotation(particlesName, minDeg, maxDeg) { | |
| const particles = document.getElementById(particlesName); | |
| const randomRotationAngle = getRandomInt(minDeg, maxDeg) + 'deg'; | |
| particles.style.transform = `rotate(${randomRotationAngle})`; | |
| } |
| $default-clap-color: #03a87c; | |
| .canvas { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| width: 300px; | |
| height: 300px; | |
| position: relative; | |
| .total-counter { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| width: 100%; | |
| position: absolute; | |
| margin-top: -45px; | |
| color: gray; | |
| font-family: sans-serif; | |
| font-size: 16px; | |
| } | |
| .total-counter.fader { | |
| animation: fade-in 1400ms forwards; | |
| } | |
| .clap-container { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| position: absolute; | |
| width: 60px; | |
| height: 60px; | |
| border: 1px solid rgba(0,0,0,.15); | |
| border-radius: 50%; | |
| z-index: 2; | |
| background: #fff; | |
| cursor: pointer; | |
| .clap-icon { | |
| font-size: 30px; | |
| color: $default-clap-color; | |
| width: 30px; | |
| height: 30px; | |
| } | |
| } | |
| .clap-container:hover { | |
| border: 1px solid $default-clap-color; | |
| } | |
| .clap-container.scale { | |
| animation: scaleAndBack 700ms forwards; | |
| } | |
| .click-counter { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| width: 35px; | |
| height: 35px; | |
| position: absolute; | |
| top: 132px; | |
| background-color: $default-clap-color; | |
| border-radius: 50%; | |
| z-index: 1; | |
| .counter { | |
| font-family: sans-serif; | |
| font-size: 14px; | |
| color: #fff; | |
| } | |
| } | |
| .click-counter.first-active { | |
| animation: first-bump-in 1s forwards; | |
| } | |
| .click-counter.active { | |
| animation: bump-in 1s forwards; | |
| } | |
| .clap-container-sonar { | |
| width: 60px; | |
| height: 60px; | |
| background: $default-clap-color; | |
| border-radius: 50%; | |
| position: absolute; | |
| opacity: 0; | |
| z-index: 0; | |
| } | |
| .hover-active { | |
| animation: sonar-wave 2s forwards; | |
| } | |
| .particles-container { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| width: 60px; | |
| height: 60px; | |
| position: absolute; | |
| /* border: 1px solid gray; */ | |
| /* z-index: 3; */ | |
| .triangle { | |
| border-left: 4px solid transparent; | |
| border-right: 4px solid transparent; | |
| border-top: 10px solid red; | |
| border-bottom: 4px solid transparent; | |
| position: absolute; | |
| .square { | |
| width: 5px; | |
| height: 5px; | |
| background: $default-clap-color; | |
| position: absolute; | |
| left: -15px; | |
| top: 0; | |
| } | |
| } | |
| .pop-top { | |
| animation: pop-top 1s forwards; | |
| } | |
| .pop-top-left { | |
| animation: pop-top-left 1s forwards; | |
| } | |
| .pop-top-right { | |
| animation: pop-top-right 1s forwards; | |
| } | |
| .pop-bottom-right { | |
| animation: pop-bottom-right 1s forwards; | |
| } | |
| .pop-bottom-left { | |
| animation: pop-bottom-left 1s forwards; | |
| } | |
| } | |
| } | |
| // * * * Animations * * * // | |
| @keyframes sonar-wave { | |
| 0% { | |
| opacity: 0.7; | |
| } | |
| 100% { | |
| transform: scale(1.4); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes fade-in { | |
| 0% { | |
| opacity: 0; | |
| } | |
| 50% { | |
| opacity: 0; | |
| } | |
| 100% { | |
| opacity: 1; | |
| } | |
| } | |
| // * * * Pop Animations * * * // | |
| @keyframes pop-top { | |
| 0% { | |
| transform: translate(0, 0) rotate(0); | |
| opacity: 0.4; | |
| } | |
| 100% { | |
| transform: translate(0, -100px) rotate(0); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes pop-top-left { | |
| 0% { | |
| transform: translate(0, 0) rotate(-55deg); | |
| opacity: 0.4; | |
| } | |
| 100% { | |
| transform: translate(-100px, -50px) rotate(-55deg); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes pop-top-right { | |
| 0% { | |
| transform: translate(0, 0) rotate(55deg); | |
| opacity: 0.4; | |
| } | |
| 100% { | |
| transform: translate(100px, -50px) rotate(55deg); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes pop-bottom-right { | |
| 0% { | |
| transform: translate(0, 0) rotate(135deg); | |
| opacity: 0.4; | |
| } | |
| 100% { | |
| transform: translate(70px, 80px) rotate(135deg); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes pop-bottom-left { | |
| 0% { | |
| transform: translate(0, 0) rotate(-135deg); | |
| opacity: 0.4; | |
| } | |
| 100% { | |
| transform: translate(-70px, 80px) rotate(-135deg); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes first-bump-in { | |
| 0% { | |
| transform: translateY(-65px); | |
| opacity: 1; | |
| } | |
| 50% { | |
| transform: translateY(-80px); | |
| opacity: 1; | |
| } | |
| 100% { | |
| transform: translateY(-100px); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes bump-in { | |
| 0% { | |
| transform: translateY(-80px) scale(0.9); | |
| opacity: 1; | |
| } | |
| 50% { | |
| transform: translateY(-80px) scale(1); | |
| opacity: 1; | |
| } | |
| 100% { | |
| transform: translateY(-100px) scale(1); | |
| opacity: 0; | |
| } | |
| } | |
| @keyframes scaleAndBack { | |
| 0% { | |
| transform: scale(1); | |
| } | |
| 50% { | |
| transform: scale(1.15); | |
| } | |
| 100% { | |
| transform: scale(1); | |
| } | |
| } |
@topshef are you working with React/Vue/Vanilla JS?
@JonathanDn
Online, vanilla JS
- local + online (sync is via Webdrive)
- yes, demo it, not on js fiddle
- later, but now just a demo to understand the code and test some changes
Thanks
I'm checking this out https://stackoverflow.com/questions/9851878/is-there-a-download-function-in-jsfiddle
..Ok that was it.. just add /show to the js fiddle URL and then just save the page :-)
(not that clean though but it works)
I'm checking this out https://stackoverflow.com/questions/9851878/is-there-a-download-function-in-jsfiddle
..Ok that was it.. just add /show to the js fiddle URL and then just save the page :-)
(not that clean though but it works)
Awesome, I actually didn't know that ! I thought of uploading it all to codesandbox.io which shows the index.html boilerplate with all the script and style tags. But I guess that helps resolved your issue as well?
- Would you suggest adding a codesandbox example would be more inviting for new devs?
@topshef By the way I would love to see what you are doing with it if you would mind sharing with me :) You can also DM me that to my twitter profile: https://twitter.com/jodoron
@JonathanDn thanks a lot, yes I'll share it back on github and DM you :-)
@JonathanDn thanks a lot, yes I'll share it back on github and DM you :-)
Awesome!
@topshef Define on its own.