lazy line painter as a pre-loader - javascript
I have an animated SVG using lazy line painter that I would like to use as a pre-loader. How can I review the page content (with a transition or a simple fade-in) after the line animation is completed?
So the concept is this: on landing LOAD SVG animation when COMPLETE transition into page content.
<!-- Include lazylinepainter -->
<script src="https://cdn.jsdelivr.net/npm/ lazy-line-painter#1.9.4/lib/lazy-line-painter-1.9.4.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/d3js/5.15.0/d3.min.js"></script>
<script type="text/javascript">
(function(){
document.onreadystatechange = () => {
if (document.readyState === 'complete') {
let el = document.querySelector('#markin2');
let myAnimation = new LazyLinePainter(el, {"ease":"easeLinear","strokeWidth":2.2,"strokeOpacity":1,"strokeColor":"#fff"});
myAnimation.paint();
}
}
})();
</script>
<svg version="1.1" id="markin2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="314.094px" height="314.765px" viewBox="0 0 314.094 314.765" enable-background="new 0 0 314.094 314.765" xml:space="preserve" data-llp-composed="true" class="lazy-line-painter">
<circle fill="none" stroke-miterlimit="10" cx="157.828" cy="157.404" r="150.813" data-llp-id="markin2-0" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
<path id="#markin2" class=".markin2" fill="none" values="#000" stroke-miterlimit="10" d="M18.482,132.273
c1.019-4.147,1.774-8.38,3.099-12.427c7.988-24.405,24.611-39.774,49.798-44.317c26.582-4.795,47.878,5.064,64.031,26.525
c2.094,2.782,2.112,4.714-0.499,7.183c-3.496,3.306-6.592,7.035-10.095,10.837c-2.364-3.506-4.425-7.039-6.94-10.211
C104.843,93.427,81.91,88.297,62.884,97.426c-18.967,9.102-29.097,30.539-24.289,51.399c4.649,20.172,22.977,34.573,43.973,34.571
c13.572-0.002,24.751-5.104,33.906-15.18c22.505-24.771,44.815-49.735,67.885-73.971c17.361-18.239,39.164-24.295,63.441-17.369
c24.221,6.91,39.282,23.516,45.102,48.006c3.184,13.398,1.887,26.967-2.008,39.987c-1.322,4.422-5.715,7.985-8.899,11.78
c-10.94,13.035-24.349,21.988-41.47,24.67c-19.018,2.979-35.86-2.006-50.829-13.86c-1.162-0.92-2.304-1.863-4.361-3.533
c0,2.48-0.004,4.178,0,5.873c0.045,22.324,0.009,44.646,0.213,66.967c0.037,3.956-0.771,7.102-3.877,9.674
c-1.653,1.37-3.243,2.961-4.409,4.748c-2.552,3.912-5.974,4.865-10.668,3.637c0-6.688,0.01-13.473-0.003-20.258
c-0.041-22.488,0.024-44.979-0.227-67.465c-0.056-4.814,1.073-8.443,4.622-11.914c6.039-5.908,11.509-12.398,17.593-19.056
c4.06,8.205,9.36,14.85,16.678,19.736c15.507,10.355,35.698,10.172,51.128-0.49c15.202-10.506,22.338-29.406,18.086-47.903
c-3.979-17.298-19.188-31.573-37.106-33.975c-15.415-2.066-29.11,2.093-39.841,13.781c-21.17,23.057-42.371,46.092-63.192,69.461
c-14.497,16.271-31.743,25.988-53.992,25.404c-30.517-0.799-56.945-24.744-60.94-55.143c-0.123-0.934-0.602-1.821-0.915-2.73
C18.482,140.272,18.482,136.272,18.482,132.273z" data-llp-id="markin2-1" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
</svg>
CSS
body, html {
background: #000;
position: absolute;
width: 100%;
height: 100%;
top:0;
left:0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
#markin2 {
width: 40vw;
height: 40vh;
position: relative;
overflow: visible;
}
.markin2 {
animation: stroke_fill 4s linear forwards, changeColor 2s, forwards;
stroke-dasharray: 1538.2169189453125px;
stroke-dashoffset: 0;
}
#keyframes stroke_fill {
0% {
fill: white;
}
50% {
fill: white;
stroke-dashoffset: 0;
}
100% {
fill: black;
stroke-dashoffset: 0;
}
}
#keyframes changeColor {
from{ fill: rgba(0,0,0,0);}
to{ fill: rgba(0,0,0,1)}
}
Here is the SVG animation example:
https://codepen.io/cpawl/pen/zYvEqYq
The Lazy Line Painter library has some custom events built in to which you can listen. Such as the complete event whenever you animation has been completed. Whenever that event is called, hide the SVG.
In the example below I've added this event listener but also wrapped your animation in a Promise. This way you can wait for it to finish and then do something. And also another Promise which listens for the load event on the document. So that this is an actual page loader and the SVG would not disappear before the page would be loaded.
In your HTML first load the SVG and then the JS you see below here. Inside the then callback function either delete your SVG, or set a class to the body which hides the class. Anyway you see fit.
body,
html {
background: #000;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
#markin2 {
width: 20vw;
height: 20vh;
position: relative;
overflow: visible;
}
.markin2 {
animation: stroke_fill 4s linear forwards, changeColor 2s, forwards;
stroke-dasharray: 1538.2169189453125px;
stroke-dashoffset: 0;
}
#keyframes stroke_fill {
0% {
fill: white;
}
50% {
fill: white;
stroke-dashoffset: 0;
}
100% {
fill: black;
stroke-dashoffset: 0;
}
}
#keyframes changeColor {
from {
fill: rgba(0, 0, 0, 0);
}
to {
fill: rgba(0, 0, 0, 1);
}
}
.hsvg {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
width: 100%;
height: 100%;
background: #000000;
z-index: 999;
transition: 2000ms ease-in-out;
transition-property: opacity, visibility;
}
body.is-loaded .hsvg {
opacity: 0;
visibility: hidden;
}
.main-content {
color: #fff;
}
<script src="https://cdn.jsdelivr.net/npm/lazy-line-painter#1.9.6/lib/lazy-line-painter-1.9.6.min.js"></script>
<!-- Include lazylinepainter -->
<div class="hsvg">
<svg version="1.1" id="markin2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="314.094px" height="314.765px" viewBox="0 0 314.094 314.765" enable-background="new 0 0 314.094 314.765" xml:space="preserve"
data-llp-composed="true" class="lazy-line-painter">
<circle fill="none" stroke-miterlimit="10" cx="157.828" cy="157.404" r="150.813" data-llp-id="markin2-0" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
<path id="#markin2" class=".markin2" fill="none" values="#000" stroke-miterlimit="10" d="M18.482,132.273
c1.019-4.147,1.774-8.38,3.099-12.427c7.988-24.405,24.611-39.774,49.798-44.317c26.582-4.795,47.878,5.064,64.031,26.525
c2.094,2.782,2.112,4.714-0.499,7.183c-3.496,3.306-6.592,7.035-10.095,10.837c-2.364-3.506-4.425-7.039-6.94-10.211
C104.843,93.427,81.91,88.297,62.884,97.426c-18.967,9.102-29.097,30.539-24.289,51.399c4.649,20.172,22.977,34.573,43.973,34.571
c13.572-0.002,24.751-5.104,33.906-15.18c22.505-24.771,44.815-49.735,67.885-73.971c17.361-18.239,39.164-24.295,63.441-17.369
c24.221,6.91,39.282,23.516,45.102,48.006c3.184,13.398,1.887,26.967-2.008,39.987c-1.322,4.422-5.715,7.985-8.899,11.78
c-10.94,13.035-24.349,21.988-41.47,24.67c-19.018,2.979-35.86-2.006-50.829-13.86c-1.162-0.92-2.304-1.863-4.361-3.533
c0,2.48-0.004,4.178,0,5.873c0.045,22.324,0.009,44.646,0.213,66.967c0.037,3.956-0.771,7.102-3.877,9.674
c-1.653,1.37-3.243,2.961-4.409,4.748c-2.552,3.912-5.974,4.865-10.668,3.637c0-6.688,0.01-13.473-0.003-20.258
c-0.041-22.488,0.024-44.979-0.227-67.465c-0.056-4.814,1.073-8.443,4.622-11.914c6.039-5.908,11.509-12.398,17.593-19.056
c4.06,8.205,9.36,14.85,16.678,19.736c15.507,10.355,35.698,10.172,51.128-0.49c15.202-10.506,22.338-29.406,18.086-47.903
c-3.979-17.298-19.188-31.573-37.106-33.975c-15.415-2.066-29.11,2.093-39.841,13.781c-21.17,23.057-42.371,46.092-63.192,69.461
c-14.497,16.271-31.743,25.988-53.992,25.404c-30.517-0.799-56.945-24.744-60.94-55.143c-0.123-0.934-0.602-1.821-0.915-2.73
C18.482,140.272,18.482,136.272,18.482,132.273z" data-llp-id="markin2-1" data-llp-duration="2920" data-llp-delay="0" fill-opacity="1" data-llp-stroke-join="" data-llp-stroke-cap=""/>
</svg>
</div>
<script>
const pageLoad = new Promise(resolve => {
window.addEventListener('load', resolve);
});
const animationLoad = new Promise(resolve => {
let el = document.querySelector('#markin2');
let myAnimation = new LazyLinePainter(el, {
"ease": "easeLinear",
"strokeWidth": 2.2,
"strokeOpacity": 1,
"strokeColor": "#fff"
});
myAnimation.paint();
myAnimation.on('complete', resolve);
});
Promise.all([pageLoad, animationLoad]).then(function() {
document.body.classList.add('is-loaded');
console.log('Load event fired and animation done');
});
</script>
<div class="main-content">
<h1>IS THIS THING ON?</h1>
</div>
Related
How to change a slider to carousel / HTML & CSS & JS
I'm trying to make an infinite logo carousel for a website. However, I haven't much experience with Javascript. At first, I researched lots of sources and understood the basic structure. Then I watched and appied this 2 part video(video Repository here). Here is the code: const slide = document.querySelector('.slide'); const root = document.querySelector(':root'); let slideIndex = 1; let isMoving = false; function processImages(item) { return `<img src="${item.url}" alt="${item.alt}">`; } function moveSlides() { slide.style.transform = `translateX(-${slideIndex * 100}%)`; const slidesArray = [...slide.querySelectorAll('img')]; root.style.setProperty('--slide-progress', `${(100 / (slidesArray.length - 3)) * (slideIndex - 1)}%`); } // move when clicked function moveHandler(direction) { isMoving = true; slide.style.transition = `transform 450ms ease-in-out`; direction !== 'right' ? (slideIndex -= 1) : (slideIndex += 1); moveSlides(); } // fetch images async function fetchImages() { await fetch('images.json') .then((response) => { if (!response.ok) { throw new Error('Network response was not okay'); } return response.json(); }) .then((data) => { // cloned first and last image data.push(data[0]); data.unshift(data[data.length - 2]); // show slider slide.innerHTML = data.map(processImages).join(''); moveSlides(); }) .catch((error) => { console.error('There has been a problem with your fetch operation:', error); }); } fetchImages() // keyboard arrow handler window.addEventListener('keyup', e => { if (isMoving) { return; } switch (e.key) { case 'ArrowLeft': moveHandler() break; case 'ArrowRight': moveHandler('right') break; default: break; } }) // click right btn document.querySelector('.slider__btn--right').addEventListener('click', () => { if (isMoving) { return; } moveHandler('right'); }) // click left btn document.querySelector('.slider__btn--left').addEventListener('click', () => { if (isMoving) { return; } moveHandler(); }) slide.addEventListener('transitionend', () => { isMoving = false; const slidesArray = [...slide.querySelectorAll('img')]; root.style.setProperty('--slide-progress--transition', `${slideIndex === slidesArray.length - 1 ? 'none' : 'all 400ms cubic-bezier(0.82, 0.02, 0.39, 1.01)'}`); if (slideIndex === 0) { slide.style.transition = 'none'; slideIndex = slidesArray.length - 2; moveSlides() } if (slideIndex === slidesArray.length - 1) { slide.style.transition = 'none'; slideIndex = 1; moveSlides() } }) *, *::after, *::before { border: 0; margin: 0; padding: 0; } :root { --slide-progress: 35%; --slide-progress--transition: all 200ms cubic-bezier(0.82, 0.02, 0.39, 1.01); } .container { display: flex; /* Changed display grid to flex*/ place-items: center; align-content: center; min-height: 100vh; padding: 2rem 0; } .slider { position: relative; display: flex; /* Changed display grid to flex*/ place-items: center; max-width: 800px; overflow: hidden; box-shadow: 20px 20px 50px hsla(210, 50%, 40%, .4), -20px -20px 50px hsla(210, 50%, 80%, .2); ; } .slide { height: 100px; max-height: 100px; display: flex; } .slide img { width: 100%; margin-top: 20px; height: 60px; flex: 6 1 25%; /* Changed flex value 1 0 100% -> 6 0 25%*/ object-fit: contain; } .slider__progress { position: absolute; width: 100%; height: 6px; background: linear-gradient(90deg, hsla(210, 50%, 90%, .2), hsla(210, 50%, 70%, .1)); bottom: 0; z-index: 4; } .slider__progress::after { content: ''; position: absolute; background: linear-gradient(90deg, hsla(210, 50%, 90%, .7), hsla(210, 50%, 70%, .6)); width: var(--slide-progress); height: 6px; left: 0; transition: var(--slide-progress--transition); } .slider__btn-container { position: absolute; width: 100%; } .slider__btn { border-radius: 50%; position: absolute; z-index: 2; padding: .2rem; top: 50%; display: grid; place-items: center; cursor: pointer; background: hsla(210, 50%, 30%, .15); color: hsla(210, 50%, 95%, .9); } .slider__btn svg { pointer-events: none; } .slider__btn--left { left: 0; transform: translate(50%, -50%); } .slider__btn--left:is(:hover, :focus) { animation: 850ms infinite moveLeft cubic-bezier(0.25, -0.50, 0.17, 1.2); } #keyframes moveLeft { 10% { left: -3px; } } .slider__btn--right { right: 0; transform: translate(-50%, -50%); } .slider__btn--right:is(:hover, :focus) { animation: 850ms infinite moveRight cubic-bezier(0.25, -0.50, 0.17, 1.2); } #keyframes moveRight { 10% { right: -3px; } } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="container"> <div class="slider"> <div class="slider__progress"></div> <div class="slider__btn-container"> <button class="slider__btn slider__btn--left" aria-label="Move to previous slide"> <svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left"> <line x1="19" y1="12" x2="5" y2="12"></line> <polyline points="12 19 5 12 12 5"></polyline> </svg> </button> <button class="slider__btn slider__btn--right" aria-label="Move to next slide"> <svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right"> <line x1="5" y1="12" x2="19" y2="12"></line> <polyline points="12 5 19 12 12 19"></polyline> </svg> </button> </div> <div class="slide"> <img src="./images/image-1.jpg" alt="alt"> <img src="./images/image-1.jpg" alt="alt"> <img src="./images/image-1.jpg" alt="alt"> <img src="./images/image-1.jpg" alt="alt"> <img src="./images/image-1.jpg" alt="alt"> </div> </div> </div> when I changed .slide img { width: 100%; margin-top: 20px; height: 60px; flex: 6 0 25%; /* Changed flex value 1 0 100% -> 6 0 25%*/ object-fit: contain; } this part at CSS code it looks like what I want to see but it's not even close to work properly. What should I do for make this change correctly. ALSO, THANKS FOR ANY HELP <3
why does event Listener need two elements?
In the code below, you'll notice i have two event listeners window.addEventListener("click", jump); window.addEventListener("click", jump()); The problem is removing either one of these makes the event listener invalid i.e. it doesnt work, they have to both be present and I'm having a hard time figuring out why. note: click to jump and view snippet in full page since i havent done the responsive part yet const ball = document.querySelector(".ball"); const obs = document.querySelector(".obstacle"); const score = document.querySelector("#s"); let temp = 0; // a temporary variable to stop event listener from running as soon as game starts function jump() { let bottom = parseInt(window.getComputedStyle(ball).getPropertyValue('bottom')); if (temp > 0 && bottom === 150) { ball.style.bottom = "400px"; setTimeout(() => { ball.style.bottom = "150px"; }, 300); } temp++; } window.addEventListener("click", jump); window.addEventListener("click", jump()); let z = 0; // intitial score to be incremented by each succesful second setInterval(() => { let ballX = parseInt(window.getComputedStyle(ball).getPropertyValue('bottom')); let obsY = parseInt(window.getComputedStyle(obs).getPropertyValue('right')); if (ballX >= 150 && ballX <= 240 && obsY >= 785 && obsY <= 970) { ball.style.animationPlayState = "paused"; obs.style.animationPlayState = "paused"; ball.style.bottom = `${ballX}px` window.removeEventListener("keydown", jump); clearInterval(); } else { s.innerHTML = z; z += 1; } }, 10); window.onload = () => { if (screen.availHeight > screen.availWidth) { alert("This game is best played in landscape, so rotate your phone if you can :)"); } } #import url('https://fonts.googleapis.com/css2?family=Comic+Neue&display=swap'); * { margin: 0; padding: 0; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } .screen { margin: 20px; width: 1000px; height: 500px; background: skyblue; outline: solid 3px; position: absolute; overflow: hidden; } .score { position: absolute; top: 5px; right: 5px; width: 200px; height: 50px; display: flex; align-items: flex-end; font-size: 150%; font-family: "Comic Neue"; font-weight: bold; } .s { display: flex; justify-content: center; align-items: center; line-height: 50px; text-shadow: 3px 3px 0px white; } #s-title { width: 40%; } #s { width: 60%; } .ball { position: absolute; left: 30px; bottom: 150px; width: 80px; height: 80px; border-radius: 50%; background: red; transition: bottom 0.3s ease-in-out; animation: spin 1s linear infinite; } #keyframes spin { to { transform: rotate(720deg); } } .obstacle { width: 100px; height: 100px; position: absolute; right: -150px; bottom: 150px; background: red; animation: attack 1.5s linear infinite; animation-play-state: running; } #keyframes attack { to { right: 1150px; } } .grass { position: absolute; bottom: 125px; width: 100%; height: 25px; background: rgb(55, 141, 52); } .ground { position: absolute; bottom: 0; width: 100%; height: 125px; background: rgb(82, 80, 69); } <!doctype html> <html lang='en'> <head> <!-- Required meta tags --> <meta charset='utf-8'> <meta name='viewport' content='width=device-width, initial-scale=1'> <title>Rollin</title> <link rel='stylesheet' href='rollin.css'> <link rel='icon' href='assets/logo.ico'> </head> <body> <div class="screen"> <div class="score"> <div id="s-title" class="s">Score:</div> <div id="s" class="s">000000</div> </div> <div class="ball"> <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="100%" height="100%" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" viewBox="0 0 1024 1024" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xodm="http://www.corel.com/coreldraw/odm/2003"> <defs> <style type="text/css"> .str0 {stroke:black;stroke-width:0.667;stroke-miterlimit:2.61313} .fil1 {fill:black} .fil2 {fill:#1A1A1A} .fil0 {fill:#AE0000} </style> </defs> <g id="Layer_x0020_1"> <metadata id="CorelCorpID_0Corel-Layer"/> <g> <path class="fil0" d="M517.231 11.182c277.954,0 503.28,225.327 503.28,503.281 0,277.954 -225.326,503.281 -503.28,503.281 -277.954,0 -503.281,-225.327 -503.281,-503.281 0,-277.954 225.327,-503.281 503.281,-503.281z"/> <path id="1" class="fil1" d="M517.231 11.182c277.954,0 503.28,225.327 503.28,503.281 0,277.954 -225.326,503.281 -503.28,503.281 -277.954,0 -503.281,-225.327 -503.281,-503.281 0,-277.954 225.327,-503.281 503.281,-503.281zm338.197 165.084c-86.55,-86.551 -206.121,-140.084 -338.197,-140.084 -132.076,0 -251.648,53.533 -338.198,140.084 -86.55,86.55 -140.083,206.121 -140.083,338.197 0,132.076 53.533,251.647 140.083,338.197 86.551,86.551 206.122,140.084 338.198,140.084 132.076,0 251.647,-53.533 338.197,-140.084 86.551,-86.55 140.083,-206.121 140.083,-338.197 0,-132.076 -53.532,-251.647 -140.083,-338.197z"/> </g> <g> <path class="fil2" d="M517.231 246.225c149.688,0 271.035,121.346 271.035,271.035 0,149.688 -121.347,271.035 -271.035,271.035 -149.689,0 -271.035,-121.347 -271.035,-271.035 0,-149.689 121.346,-271.035 271.035,-271.035zm184.58 86.454c-47.237,-47.237 -112.497,-76.454 -184.58,-76.454 -72.084,0 -137.343,29.217 -184.581,76.454 -47.237,47.238 -76.455,112.497 -76.455,184.581 0,72.083 29.218,137.343 76.455,184.58 47.238,47.237 112.497,76.455 184.581,76.455 72.083,0 137.343,-29.218 184.58,-76.455 47.237,-47.237 76.455,-112.497 76.455,-184.58 0,-72.084 -29.218,-137.343 -76.455,-184.581z"/> </g> <circle class="fil1 str0" cx="517.231" cy="517.26" r="100.656"/> <path class="fil1 str0" d="M213.398 645.876c-54.056,-27.029 -41.008,-69.901 -48.444,-92.065 -3.228,-9.623 -41.293,134.779 56.413,170.477 18.411,6.727 36.767,13.855 70.319,8.264 25.978,-4.33 61.512,-22.368 72.238,-53.613 12.934,-37.676 6.05,-56.363 -16.318,-82.46 -8.188,-9.553 -35.416,-37.28 -89.472,-20.504 -33.759,19.875 -36.584,43.161 -44.736,69.901z"/> <path class="fil1 str0" d="M561.667 188.198c52.09,-14.249 81.039,-0.564 103.952,4.079 9.948,2.016 -96.076,-103.15 -175.843,-36.384 -15.032,12.581 -30.384,24.914 -42.317,56.766 -9.24,24.663 -11.386,64.455 10.311,89.367 26.161,30.039 45.787,33.421 79.571,27.098 12.367,-2.315 49.994,-12.031 62.493,-67.234 -0.333,-39.173 -19.087,-53.263 -38.167,-73.692z"/> <path class="fil1 str0" d="M786.104 714.481c3.621,60.329 -40.031,70.465 -55.509,87.986 -6.72,7.607 137.369,-31.629 119.431,-134.093 -3.38,-19.308 -6.384,-38.769 -28.003,-65.031 -16.738,-20.332 -50.127,-42.086 -82.549,-35.753 -39.095,7.637 -51.837,22.942 -63.253,55.361 -4.179,11.868 -14.578,49.312 26.979,87.737 34.092,19.299 55.671,10.103 82.904,3.793z"/> </g> </svg> </div> <div class="obstacle"> <img src="assets/kakashi.png" alt=""> </div> <div class="grass"></div> <div class="ground"></div> </div> <script src='rollin.js' defer></script> </body> </html>
How does this not work? You can try this better here: JSFidlle const ball = document.querySelector(".ball"); const obs = document.querySelector(".obstacle"); const score = document.querySelector("#s"); let temp = 0; // a temporary variable to stop event listener from running as soon as game starts function jump() { let bottom = parseInt(window.getComputedStyle(ball).getPropertyValue('bottom')); if (temp > 0 && bottom === 150) { ball.style.bottom = "400px"; setTimeout(() => { ball.style.bottom = "150px"; }, 300); } temp++; } window.addEventListener("click", jump); let z = 0; // intitial score to be incremented by each succesful second setInterval(() => { let ballX = parseInt(window.getComputedStyle(ball).getPropertyValue('bottom')); let obsY = parseInt(window.getComputedStyle(obs).getPropertyValue('right')); if (ballX >= 150 && ballX <= 240 && obsY >= 785 && obsY <= 970) { ball.style.animationPlayState = "paused"; obs.style.animationPlayState = "paused"; ball.style.bottom = `${ballX}px` window.removeEventListener("keydown", jump); clearInterval(); } else { s.innerHTML = z; z += 1; } }, 10); window.onload = () => { if (screen.availHeight > screen.availWidth) { alert("This game is best played in landscape, so rotate your phone if you can :)"); } } #import url('https://fonts.googleapis.com/css2?family=Comic+Neue&display=swap'); * { margin: 0; padding: 0; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } .screen { margin: 20px; width: 1000px; height: 500px; background: skyblue; outline: solid 3px; position: absolute; overflow: hidden; } .score { position: absolute; top: 5px; right: 5px; width: 200px; height: 50px; display: flex; align-items: flex-end; font-size: 150%; font-family: "Comic Neue"; font-weight: bold; } .s { display: flex; justify-content: center; align-items: center; line-height: 50px; text-shadow: 3px 3px 0px white; } #s-title { width: 40%; } #s { width: 60%; } .ball { position: absolute; left: 30px; bottom: 150px; width: 80px; height: 80px; border-radius: 50%; background: red; transition: bottom 0.3s ease-in-out; animation: spin 1s linear infinite; } #keyframes spin { to { transform: rotate(720deg); } } .obstacle { width: 100px; height: 100px; position: absolute; right: -150px; bottom: 150px; background: red; animation: attack 1.5s linear infinite; animation-play-state: running; } #keyframes attack { to { right: 1150px; } } .grass { position: absolute; bottom: 125px; width: 100%; height: 25px; background: rgb(55, 141, 52); } .ground { position: absolute; bottom: 0; width: 100%; height: 125px; background: rgb(82, 80, 69); } <!doctype html> <html lang='en'> <head> <!-- Required meta tags --> <meta charset='utf-8'> <meta name='viewport' content='width=device-width, initial-scale=1'> <title>Rollin</title> <link rel='stylesheet' href='rollin.css'> <link rel='icon' href='assets/logo.ico'> </head> <body> <div class="screen"> <div class="score"> <div id="s-title" class="s">Score:</div> <div id="s" class="s">000000</div> </div> <div class="ball"> <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="100%" height="100%" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" viewBox="0 0 1024 1024" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xodm="http://www.corel.com/coreldraw/odm/2003"> <defs> <style type="text/css"> .str0 {stroke:black;stroke-width:0.667;stroke-miterlimit:2.61313} .fil1 {fill:black} .fil2 {fill:#1A1A1A} .fil0 {fill:#AE0000} </style> </defs> <g id="Layer_x0020_1"> <metadata id="CorelCorpID_0Corel-Layer"/> <g> <path class="fil0" d="M517.231 11.182c277.954,0 503.28,225.327 503.28,503.281 0,277.954 -225.326,503.281 -503.28,503.281 -277.954,0 -503.281,-225.327 -503.281,-503.281 0,-277.954 225.327,-503.281 503.281,-503.281z"/> <path id="1" class="fil1" d="M517.231 11.182c277.954,0 503.28,225.327 503.28,503.281 0,277.954 -225.326,503.281 -503.28,503.281 -277.954,0 -503.281,-225.327 -503.281,-503.281 0,-277.954 225.327,-503.281 503.281,-503.281zm338.197 165.084c-86.55,-86.551 -206.121,-140.084 -338.197,-140.084 -132.076,0 -251.648,53.533 -338.198,140.084 -86.55,86.55 -140.083,206.121 -140.083,338.197 0,132.076 53.533,251.647 140.083,338.197 86.551,86.551 206.122,140.084 338.198,140.084 132.076,0 251.647,-53.533 338.197,-140.084 86.551,-86.55 140.083,-206.121 140.083,-338.197 0,-132.076 -53.532,-251.647 -140.083,-338.197z"/> </g> <g> <path class="fil2" d="M517.231 246.225c149.688,0 271.035,121.346 271.035,271.035 0,149.688 -121.347,271.035 -271.035,271.035 -149.689,0 -271.035,-121.347 -271.035,-271.035 0,-149.689 121.346,-271.035 271.035,-271.035zm184.58 86.454c-47.237,-47.237 -112.497,-76.454 -184.58,-76.454 -72.084,0 -137.343,29.217 -184.581,76.454 -47.237,47.238 -76.455,112.497 -76.455,184.581 0,72.083 29.218,137.343 76.455,184.58 47.238,47.237 112.497,76.455 184.581,76.455 72.083,0 137.343,-29.218 184.58,-76.455 47.237,-47.237 76.455,-112.497 76.455,-184.58 0,-72.084 -29.218,-137.343 -76.455,-184.581z"/> </g> <circle class="fil1 str0" cx="517.231" cy="517.26" r="100.656"/> <path class="fil1 str0" d="M213.398 645.876c-54.056,-27.029 -41.008,-69.901 -48.444,-92.065 -3.228,-9.623 -41.293,134.779 56.413,170.477 18.411,6.727 36.767,13.855 70.319,8.264 25.978,-4.33 61.512,-22.368 72.238,-53.613 12.934,-37.676 6.05,-56.363 -16.318,-82.46 -8.188,-9.553 -35.416,-37.28 -89.472,-20.504 -33.759,19.875 -36.584,43.161 -44.736,69.901z"/> <path class="fil1 str0" d="M561.667 188.198c52.09,-14.249 81.039,-0.564 103.952,4.079 9.948,2.016 -96.076,-103.15 -175.843,-36.384 -15.032,12.581 -30.384,24.914 -42.317,56.766 -9.24,24.663 -11.386,64.455 10.311,89.367 26.161,30.039 45.787,33.421 79.571,27.098 12.367,-2.315 49.994,-12.031 62.493,-67.234 -0.333,-39.173 -19.087,-53.263 -38.167,-73.692z"/> <path class="fil1 str0" d="M786.104 714.481c3.621,60.329 -40.031,70.465 -55.509,87.986 -6.72,7.607 137.369,-31.629 119.431,-134.093 -3.38,-19.308 -6.384,-38.769 -28.003,-65.031 -16.738,-20.332 -50.127,-42.086 -82.549,-35.753 -39.095,7.637 -51.837,22.942 -63.253,55.361 -4.179,11.868 -14.578,49.312 26.979,87.737 34.092,19.299 55.671,10.103 82.904,3.793z"/> </g> </svg> </div> <div class="obstacle"> <img src="assets/kakashi.png" alt=""> </div> <div class="grass"></div> <div class="ground"></div> </div> <script src='rollin.js' defer></script> </body> </html>
You can try to put the -listener- above the -jump- function and remove: -- window.addEventListener("click", jump()); --
On click add class to hide other elements using vanilla JavaScript
At the moment when the user clicks one of the SVGs the class "clicked" is added to that particular SVG. What I would like to happen is that when an SVG is clicked on the page, the other SVG elements are hidden (opacity: 0 or something) and not clickable. My JS knowledge is a bit limited. I was thinking a class would need to be added to the SVGs when the others were inactive as I was thinking about transitioning them out when a click happens, however would appreciate any suggestions. <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Interactive SVG</title> <link rel="stylesheet" href="static/css/styles.css" /> </head> <body> <div class="container" id="container"> <svg version="1.0" class="svg svg-a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> <rect class="rect rect-a" width="100" height="100" /> </svg> <svg version="1.0" class="svg svg-b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> <rect class="rect rect-b" width="100" height="100" /> </svg> <svg version="1.0" class="svg svg-c" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> <rect class="rect rect-c" width="100" height="100" /> </svg> </div> <script src="https://cdn.jsdelivr.net/npm/animejs#3.0.1/lib/anime.min.js"></script> <script src="static/js/script.js"></script> </body> </html> body { margin: 0; padding: 0; } .container { display: flex; justify-content: center; align-items: center; flex-direction: column; height: 100vh; background: #222; position: relative; } svg { display: flex; width: 100px; height: 100px; transition: 0.7s ease-out; } .rect { cursor: pointer; fill: #eee; transform-origin: 50% 50%; transition: 0.5s; transition-timing-function: cubic-bezier(0.4, 0, 1, 1); box-shadow: 20px 20px 20px 0; position: absolute; } .rect-a { fill: cornflowerblue; z-index: 390; } .rect-b { fill: pink; box-shadow: 20px 20px 20px 0; } .rect-c { fill: azure; box-shadow: 20px 20px 20px 0; } .clicked { fill: cornflowerblue; transform: scale(1.2); transform-origin: 50% 50%; transition: 0.5s; transition-timing-function: cubic-bezier(0.4, 0, 1, 1); } .clicked svg { fill: red; transform: translateY(500px); } button { position: absolute; z-index: 1000; color: red; top: -5px; right: -5px; border-radius: 100px; z-index: 900; } // First we get all the path elements and put them in an array let paths = document.getElementsByClassName('svg'); // Now we can loop over the array and add an eventlistener to each path in the array and it listens to the 'click' event and then runs function toggleClass() for (let i = 0; i < paths.length; i++) { paths[i].addEventListener('click', toggleClass); } // In the function toggleClass we can toggle the 'clicked' class. function toggleClass() { this.classList.toggle('clicked'); } https://codepen.io/chrismorrison/pen/ZEWdJyV
Updated CodePen w/ rough implementation of what I believe you are looking for. Below are the changes I made: JS // In the function toggleClass we can toggle the 'clicked' class. function toggleClass(e) { const clickedClassName = 'clicked'; // If "disabled", don't respond to the click event. if(this.classList.contains('disabled')) { e.preventDefault(); } // The element is "enabled". Has it been clicked // already? If so, we need to restore it along with // all the other SVGs back to their original state. // If not, then hide all other SVGs and add the "clicked" // class to the element that was clicked else if(!this.classList.contains(clickedClassName)) { this.classList.add(clickedClassName); for(let p of paths) { if(this !== p) { toggleDisabled(p) } } } else { this.classList.remove(clickedClassName); for(let p of paths) { if(this !== p) { toggleDisabled(p) } } } } function toggleDisabled(p) { p.classList.contains('disabled') ? p.classList.remove('disabled') : p.classList.add('disabled') } CSS .disabled { opacity: 0; }
seconds in a circle corner (like a clock)
I'm trying to create a circle that has small pins around (like seconds in a clock) to be like 60 of them (to count a minute) here is a picture to describe what I mean https://www.123rf.com/photo_91759207_stock-vector-close-up-of-digital-timer-showing-time-that-is-running-out-only-25-seconds-left-clock-on-vector-illu.html I'm using React, javascript, css, how can I make a loop that each pin would be stack to the circle 'corner' to fit his place ? I'm having really hard time to find a way how to arrange them to look like it. my final goal is to create a component that will receive a fill as prop that will represent the number of pins that needs to be in a different color, so I need a way to be able to control the background-color of each pin. any advice would be awesome. thanks!
Do you mean something like the following? The code will create 60 "pins" for all tags with the class clock. window.onload = function() { var clocks = document.getElementsByClassName('clock'), r = 0, i, j, d, clock; for(j=0;j<clocks.length;j++) { clock = clocks[j] for(i=0;i<60;i++) { d = document.createElement('div'); d.style.transform = "rotate("+ r +"deg)"; clock.appendChild(d); r += 6; } } } .clock { position:relative; width:180px; height:180px; background:#eee; } .clock > div { position:absolute; margin-left:87px; width:6px; height:160px; bottom:10px; background: linear-gradient(to bottom, #491 16px, transparent 16px); } <div class="clock"></div>
Drawing the 'clock face' itself is easily done with SVG and stroke-dasharray. Animating the clock can be done with an SVG mask, and some javascript to change the stroke-dashoffset. An explanation of the maths for coming up with the values for the stroke-dasharray can be found in this answer. const maskCircle = document.querySelector(".mask"); const clockText = document.querySelector(".clock-text"); const r = 50; const c = 2 * r * Math.PI; let secondsLeft = 60; window.setInterval(function() { if (secondsLeft > 0) { secondsLeft--; clockText.innerText = secondsLeft; maskCircle.style.strokeDashoffset = maskCircle.style.strokeDashoffset - c / 60 * -1; } else { clearInterval(); } }, 1000); body { background: black; } .clock { margin: 0 auto; position: relative; width: 200px; height: 200px; border-radius: 50%; overflow: hidden; } .clock-face { stroke-width: 15; stroke-linecap: butt; fill: transparent; stroke-dasharray: 2.236 3; } .grey { stroke: #333; } .white { stroke: white; } .mask { stroke-dasharray: 314.15 314.15; stroke-dashoffset: 0; } .clock-text { width: 100%; margin: 0 auto; color: white; text-align: center; position: absolute; top: 50%; font-size: 6em; transform: translateY(-50%); } <div class="clock"> <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"> <defs> <mask id="mask"> <circle class="clock-face white mask" cx="50" cy="50" r="50" transform="rotate(-90.5 50 50)" /> </mask> </defs> <circle class="clock-face grey" cx="50" cy="50" r="50" /> <circle class="clock-face white" cx="50" cy="50" r="50" mask="url(#mask)" /> </svg> <div class="clock-text">60</div> </div>
JavaScript if CSS animation ended
I am making a game in HTML/JavaScript and as part of this there is a "special ability" that can only be triggered every x seconds. I have created a GUI element that displays whether the ability is yet ready for use. Because I am using CSS animations, I want to check if, on a keypress, the element has finished animating (indicating that it is ready). I want to do this in a simple if statement, rather than using addEventListener but I am not sure if this is possible. My code so far is: var keystate = {}; window.addEventListener("keydown", function(e) { keystate[e.keycode || e.which] = true; }, true); window.addEventListener("keyup", function(e) { keystate[e.keycode || e.which] = false; }, true); window.setInterval(function() { if (keystate[87]) { //w key, THIS is where I want to check if the animation has completed as well //do stuff document.getElementById("circle_flash_glow").classList.add("circle_flash_use"); } }, 16.666666666666667); #svg_circle_loader { position: absolute; right: 0; bottom: 0; background: none; border: none; margin: none; padding: none; } #circle_flash_loader { fill: none; stroke: #F00; stroke-width: 10px; stroke-dashoffset: 80; animation-fill-mode: forwards; } .circle_loader_load { animation: circle_flash_loading linear; animation-duration: 2.5s; } #keyframes circle_flash_loading { 0% { stroke-dasharray: 0, 314; } 100% { stroke-dasharray: 314, 0; } } #circle_flash_glow { fill: none; stroke: #F00; stroke-width: 0px; animation-fill-mode: forwards; opacity: 1; } .circle_flash_use { animation: circle_flash_pulse 0.6s ease-out; } #keyframes circle_flash_pulse { 0% { opacity: 1; stroke-width: 0px; } 100% { opacity: 0; stroke-width: 70px; } } <svg id="svg_circle_loader" width="200" height="200"> <defs> <filter id="f1" x="-50" y="-50" width="200" height="200"> <feGaussianBlur stdDeviation="5"></feGaussianBlur> </filter> </defs> <circle cx="100" cy="100" r="50" id="circle_flash_glow" class="" filter="url(#f1)"></circle> <circle cx="100" cy="100" r="50" id="circle_flash_loader" class="circle_loader_load"></circle> </svg>
Add a variable to set the current state, and set it with setTimeout() for checking whether it is animating or not. also add window.onload to get its state by adding window.onload=function(){ animating=true; sts.value=animating; window.setTimeout(function() { animating=false; sts.value=animating; }, 2500); }; where I am using 2500. because your css animation property has 2.5s=2500ms var animating = false; var keystate = {}; window.addEventListener("keydown", function(e) { keystate[e.keycode || e.which] = true; }, true); window.addEventListener("keyup", function(e) { keystate[e.keycode || e.which] = false; }, true); window.setInterval(function() { if (keystate[87]) { //w key, THIS is where I want to check if the animation has completed as well //do stuff if (!animating) { alert("animation finished"); document.getElementById("circle_flash_glow").classList.add("circle_flash_use"); } } }, 16.666666666666667); window.onload = function() { animating = true; sts.value = animating; window.setTimeout(function() { animating = false; sts.value = animating; }, 2500); }; #svg_circle_loader { position: absolute; right: 0; bottom: 0; background: none; border: none; margin: none; padding: none; } #circle_flash_loader { fill: none; stroke: #F00; stroke-width: 10px; stroke-dashoffset: 80; animation-fill-mode: forwards; } .circle_loader_load { animation: circle_flash_loading linear; animation-duration: 2.5s; } #keyframes circle_flash_loading { 0% { stroke-dasharray: 0, 314; } 100% { stroke-dasharray: 314, 0; } } #circle_flash_glow { fill: none; stroke: #F00; stroke-width: 0px; animation-fill-mode: forwards; opacity: 1; } .circle_flash_use { animation: circle_flash_pulse 0.6s ease-out; } #keyframes circle_flash_pulse { 0% { opacity: 1; stroke-width: 0px; } 100% { opacity: 0; stroke-width: 70px; } } <svg id="svg_circle_loader" width="200" height="200"> <defs> <filter id="f1" x="-50" y="-50" width="200" height="200"> <feGaussianBlur stdDeviation="5"></feGaussianBlur> </filter> </defs> <circle cx="100" cy="100" r="50" id="circle_flash_glow" class="" filter="url(#f1)"></circle> <circle cx="100" cy="100" r="50" id="circle_flash_loader" class="circle_loader_load"></circle> </svg> <input id="sts" value="" />