Continuous animation on hover (performance) - javascript

I've created a jQuery function that scrolls a DIV by decreasing the left-margin of the element. It works, but it's incredibly slow. It eats up 100% CPU in no time :s
$(".scroll").hover(
function () {
var scroll_offset = parseInt($('#content').css('margin-left'));
sliderInt = self.setInterval(function(){
$content.css({'margin-left':scroll_offset+'px'});
scroll_offset--;
},8);
},
function () {
clearInterval(sliderInt);
}
);
Obviously I am running this function every 8ms, which is asking a lot. I'm already cacheing my selectors, so I don't know what I can do to improve performance. Am I just going about it the wrong way?

function play () {
$('#ball').animate({left: '+=20'}, 100, 'linear', play);
}
function pause () {
$('#ball').stop();
}
$("#bar").hover( play, pause );
#bar {
margin-top: 20px;
background: #444;
height: 20px;
}
#bar:hover #ball {
background: lightgreen;
}
#ball {
position: relative;
left: 0;
width: 20px;
height: 20px;
background: red;
border-radius: 50%;
}
<div id="bar">
<div id="ball"></div>
</div>
<script src="//code.jquery.com/jquery-3.1.0.js"></script>
This is really simple without the setInterval or even setTimeout.
The only important thing is to know that .animate() accepts a function callback, ideal for our purpose to create loop a function. Make sure to use the linear easing instead of the default 'swing' to make our loop constant.
To stop our animations we can use stop() to prevent animation buildups.
Simply create 2 functions and use them in your hover method.
Using CSS3
and toggling play/pause classes using jQuery:
function play() {
$('#ball').addClass("play").removeClass("pause");
}
function pause() {
$('#ball').addClass("pause"); // don't remove .play here
}
$("#bar").hover(play, pause);
#bar {
margin-top: 20px;
background: #444;
height: 20px;
}
#bar:hover #ball {
background: lightgreen;
}
#ball {
position: relative;
left: 0;
width: 20px;
height: 20px;
background: red;
border-radius: 50%;
}
.play {
animation: ball-anim 5s infinite linear;
}
.pause {
animation-play-state: paused;
}
#keyframes ball-anim {
0% { left: 0; }
50% { left: calc(100% - 20px); }
100% { left: 0; }
}
<div id="bar">
<div id="ball"></div>
</div>
<script src="//code.jquery.com/jquery-3.1.0.js"></script>

.animate() is a good way to do it. Example:
$(".scroll").hover(function(){
$("#content").animate({
marginLeft: "100px",
}, 1500 );
});​
Working DEMO
Read the documentation to get the idea how to use it.

Related

How can I zoom in on a div element on scroll using javascript?

What I'm trying to achieve here is that when I scroll on a particular div here .ball, it should scale up to 1.5.
but when I'm not scrolling on that ball div it should shrink down to it's original height and width.
Here I'm using window method to do this trick and as soon as I scroll ball scale up which isn't what I'm trying to do. What can I use instead of window method and is there any other approach to do achieve this?
const ball = document.querySelector('.ball');
window.addEventListener('scroll', ()=> {
if (scroll) {
ball.classList.add('active');
} else {
ball.classList.remove('active');
}
});
.ball {
height: 200px;
width: 200px;
border-radius: 100%;
background-color: orange;
}
.ball.active {
transform: scale(1.5);
position: fixed;
}
body {
height: 150vh;
}
<div class="ball"></div>
I would use a setTimeout function to remove the class after a short period after the scroll. Do not forget to clear the timeout otherwise it will lead to weird behaviour. (as suggested by Lakshya when I was answering to the question).
To make the ball smoothly transition, I would add a css transition as shown bellow.
const ball = document.querySelector('.ball');
const container = document.querySelector('.container')
let scrollTimeout;
container.addEventListener('scroll', ()=> {
ball.classList.add('active');
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(()=> ball.classList.remove('active'), 100);
});
.ball {
height: 200px;
width: 200px;
border-radius: 100%;
background-color: orange;
transition: transform 0.3s ease;
position: fixed;
top: 50px;
left: 50px;
}
.ball.active {
transform: scale(1.5);
}
.container{
width: 100%;
background: red;
overflow: scroll;
height: 500px;
}
.inside_container{
position: relative;
width: 100%;
height: 2000px;
}
<div class="container">
<div class="inside_container">
<div class="ball"></div>
</div>
</div>
One of the approaches could be delaying the removal of .active class on ball by 200ms such that each time you try to scroll again, the timer is cleared and a new one starts to do the same. A debounce approach in a nutshell.
const ball = document.querySelector('.ball');
let scrollTimeout;
window.addEventListener('scroll', ()=> {
ball.classList.add('active');
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(()=> ball.classList.remove('active'),200);
});
.ball {
height: 200px;
width: 200px;
border-radius: 100%;
background-color: orange;
}
.ball.active {
transform: scale(1.5);
position: fixed;
}
body {
height: 150vh;
}
<div class="ball"></div>

Material Design Ripple Animation into Transition HTML Web

Hello StackOverFlowers!
I found this really awesome animation on jsfiddle.net and would really love to use it in my project.
I'f you follow the link the author, 'internoma', states that it can be used as a page transition if a little Ajax is added.
My question is: What Ajax code do I add in order to make this work?!
I'm extremely lost, any suggestions will be greatly appreciated.
If you happen to know how to make this working using Barba.js or smoothState.js that would be awesome also since those are to plugins I'd like to dive deeper in learning.
Thanks in advance!
Link: Material Design Ripple Transition
JavaScript:
$(document).ready(function() {var ripple_wrap = $('.ripple-wrap'),
rippler = $('.ripple'),
finish = false,
monitor = function(el) {
var computed = window.getComputedStyle(el, null),
borderwidth = parseFloat(computed.getPropertyValue('border-left-width'));
if (!finish && borderwidth >= 1500) {
el.style.WebkitAnimationPlayState = "paused";
el.style.animationPlayState = "paused";
swapContent();
}
if (finish) {
el.style.WebkitAnimationPlayState = "running";
el.style.animationPlayState = "running";
return;
} else {
window.requestAnimationFrame(function() {monitor(el)});
}
};
storedcontent = $('#content-2').html();
$('#content-2').remove();
rippler.bind("webkitAnimationEnd oAnimationEnd msAnimationEnd
mozAnimationEnd animationend", function(e){
ripple_wrap.removeClass('goripple');
});
$('body').on('click', 'a', function(e) {
rippler.css('left', e.clientX + 'px');
rippler.css('top', e.clientY + 'px');
e.preventDefault();
finish = false;
ripple_wrap.addClass('goripple');
window.requestAnimationFrame(function() {monitor(rippler[0])});
});
function swapContent() {
var newcontent = $('#content-area').html();
$('#content-area').html(storedcontent);
storedcontent = newcontent;
// do some Ajax, put it in the DOM and then set this to true
setTimeout(function() {
finish = true;
},10);
}
});
CSS
.ripple-wrap {
display: none;
overflow: hidden;
position: fixed;
font-size: 0;
z-index: 1000;
top: 0; left: 0; right: 0; bottom: 0;
}
#-webkit-keyframes RIPPLER {
0% { border-width: 0; }
40% {
height: 0;
width: 0;
border-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
41% {
height: 0;
width: 0;
border-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
100% {
border-width: 1500px;
height: 2000px;
width: 2000px;
margin-top: -2500px;
margin-left:-2500px;
border-color: #009688;
}
}
#keyframes RIPPLER {
0% { border-width: 0; }
40% {
height: 0;
width: 0;
order-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
41% {
height: 0;
width: 0;
border-width: 1500px;
margin-top: -1500px;
margin-left:-1500px;
border-color: #009688;
}
100% {
border-width: 1500px;
height: 2000px;
width: 2000px;
margin-top: -2500px;
margin-left:-2500px;
border-color: #009688;
}
}
.ripple {
display: block;
height: 0;
width: 0;
border-width: 0px;
border-style: solid;
border-color: #00796b;
border-radius: 100%;
position: absolute;
top: 300px;
left: 300px;
-webkit-animation: none;
animation: none;
}
.ripple-wrap.goripple {
display: block;
}
.ripple-wrap.goripple .ripple {
-webkit-animation-name: RIPPLER;
-webkit-animation-duration: 1.5s;
-webkit-animation-fill-mode: forwards;
animation-name: RIPPLER;
animation-duration: 1.5s;
animation-fill-mode: forwards;
}
HTML
<div class="wrap" id="content-area">
<h1>Material Design Ripple Transition</h1>
<p>Just playing around to see if I can recreate the Material Design
ripple as a page transition in CSS. Click any link in
this block of text to load another set of text. The links don't go anywhere yet. They are just hooks to allow you to click somewhere</p>
<p>The style and animation is entirely CSS so it is smooth. JavaScript
is used to add classes at the right time. It also pauses to wait for the
content to be replaced, and calculates where to centre the hole. There
are two stages to the animation. When a link is clicked
the border-width grows very large.</p>
<p>That's enough reading on this slide. Click a link to
load the second slide</p>
</div>
<div id="content-2" style="display:none">
<h2>Slide Two</h2>
<p>This is the second slide. If you want you can <a href="#">go back to
the first slide</a>. The second part of the animation is increasing the
size of the element itself in order to create a hole.</p>
<p>This transition could be used for presentation slides. Using
pushState then this could be used as a transition between webpages.</p>
</div>
<div class="ripple-wrap"><div class="ripple"></div></div>

Progress bar according to countdown

I want to display a progress bar based on a countdown of 7 minutes that is displayed in a div: <div id = "quiz-time-left"> 0:06:24 </ div>
I need if the page is reloaded don´t reset the progress bar. Would it be possible with CSS and a script that the bar represents what the timer displays?
I use this css progress bar:
#quiz-time-left {
width: 0;
height: 100%;
-webkit-animation: progreso 420s linear;
animation: progreso 420s linear;
color: #eb7260;
background: #eb7260;
}
#page-mod-quiz-summary #quiz-timer {
text-align: center;
display: none;
position: absolute;
left: -50px;
top: -50px;
}
#quiz-timer {
border: 2px solid #eb7260;
text-indent: -9999px;
display:block;
font-size: 0px;
height: 35px;
}
#-webkit-keyframes progreso {
0% {
width: 100%;;
}
100% {
width: 0;
}
}
#keyframes progreso {
0% {
width: 100%;
}
100% {
width: 0;
}
}
html
<div id="quiz-timer" role="timer" aria-atomic="true" aria-relevant="text" style="display: block;">Time left: <div id="quiz-time-left">0:06:41</div></div>
Thank you. Best regards.
What you can do is using localStorage to store the current state of the timer and each second decrease this number.
So when the page has finished loading, test if localStorage is undefined, if it is then set it to 420. If localStorage != undefined then resume the animation from the time stored in localStorage.
You could implement something like this:
Make sure you save time left in localStorage
window.onbeforeunload = function(timeLeft) {
localStorage.setItem('countDown', timeLeft);
}
When loading the page check if there is an item called countDown and resume countDown with the value:
if(localStorage['countDown'] {
resumeCountdown(localStorage.getItem('countDown');
}

What's causing the paint event in this CSS animation?

I'm building an animated menu based off of Smooth as Butter: Achieving 60 FPS Animations with CSS3.
The canonical demo which I'm comparing my code against is: http://codepen.io/Onyros/pen/jAJxkW
This is my demo code:
var navLayer = document.querySelector('.nav-layer'),
open = document.querySelector('.open'),
close = document.querySelector('.close');
function toggleNav() {
navLayer.classList.add('nav-layer__animating');
if (navLayer.classList.contains('nav-layer__visible')) {
navLayer.classList.remove('nav-layer__visible');
} else {
navLayer.classList.add('nav-layer__visible');
}
}
open.addEventListener('click', toggleNav, false);
close.addEventListener('click', toggleNav, false);
navLayer.addEventListener('transitionend', function() {
navLayer.classList.remove('nav-layer__animating');
}, false);
.nav-layer {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
z-index: 2;
pointer-events: none;
}
.nav-layer__visible {
pointer-events: auto;
}
.header {
position: fixed;
top: 0;
left: 0;
background-color: beige;
height: 10vh;
width: 100vw;
z-index: 1;
}
.nav {
position: relative;
height: 100vh;
width: 90vw;
background-color: aquamarine;
z-index: 3;
transform: translateX(-91vw);
will-change: transform;
}
.nav-layer__animating .nav {
transition: all 300ms ease-in;
}
.nav-layer__visible.nav-layer__animating .nav {
transition: all 300ms ease-out;
}
.nav-layer__visible .nav {
transform: none;
}
<div class="nav-layer">
<nav class="nav">
<button class="close">Close</button>
</nav>
</div>
<header class="header"><button class="open">Menu</button></header>
<article>
<p>O hai</p>
</article>
When I run the canonical demo with paint flashing enabled in Chrome DevTools, I don't see any paint events.
When I run my demo, I see a flash of paint when I close the menu.
The event log in DevTools shows that there was a paint on #document and another on nav.nav.
The answer I'm looking for here is: find the CSS property in the canonical demo which is preventing this flash of paint. Or, maybe the difference is in how I've structured my HTML. I think the JS is equivalent, so it's unlikely to be there.
Please provide your methodology, too!

Moving the whole page to left and then right

i am looking for this kind of template . Moving the page to left and then page to right. Can anyone tell me how can i make this or is there any javascript example similar to this.
Create two <div>s, put them next to each other, make them take up the whole window, and change them as needed.
HTML:
<div class="left">left</div>
<div class="right">right</div>
CSS:
body {
margin: 0;
}
.left {
background-color: green;
bottom: 0;
left: 0;
position: fixed;
top: 0;
transition: width 1s;
width: 0;
}
.left.active {
width: 200px;
}
.right {
background-color: red;
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
transition: left 1s;
}
.right.active {
left: 200px;
}
JS (width jQuery):
$('.right').on('click', function() {
$('.left').toggleClass('active');
$('.right').toggleClass('active');
});
And here's a fiddle.
Using .toggle(effect,options,duration) method to moving the page to left to right.
// Set the effect type
var effect = 'slide';
// Set the options for the effect type chosen
var options = { direction: 'right' };
// Set the duration (default: 400 milliseconds)
var duration = 700;
$('#Id').toggle(effect, options, duration);
Taken via this link
If you want it to animate smooth on all devices you should use css transitions and transforms. Hiding and showing would be as basic as toggling a class then.
The example in jsfiddle
<style media="screen">
.wrapper {
width: 100%;
overflow: hidden;
}
.menu {
height: 100vh;
width: 100px;
background: #ABC;
color: white;
position: absolute;
left:0;
transition: transform 0.3s;
transform: translateX(-100px);
}
.content {
transition: transform 0.3s;
}
.active .menu {
transform: translateX(0);
}
.active .content {
transform: translateX(100px);
}
</style>
<button class="toggle">Toggle</button>
<div class="wrapper">
<div class="menu">
My menu
</div>
<div class="content">
My content
</div>
</div>
<script type="text/javascript">
document.querySelector('.toggle').addEventListener('click', function(event) {
event.preventDefault();
document.querySelector('.wrapper').classList.toggle("active");
});
</script>
NB! Supported from IE10. IE 9 will support without the animation and you probably should add the needed -ms-, -webkit-, -moz-, etc prefixes to support the older browsers if needed for transition and transform properties.
Also I advise not animating body or html with this method and put the content of page in the wrapper (in .content in the examples case). Moving body and html directly may lead to unpleasant surprises later.

Categories