Uneven intervals with setInterval function due to other code running between intervals; - javascript

I am trying to have a div do a simple slide into a parent div in a React project using pure JS and am having problems with the smoothness of the slide. When I console log, I can see that when the code (slideIn) runs, between setInterval calls, React runs other code which take up more time than the specified intervals. Therefore, the intervals are not even, which seems to be causing the jerkiness in the slide.
I have tried requestAnimationFrame also, but the result is the same.
The challenge seems to be to make the slideIn continuous without having react run other code while running it, but how does one do that?
<div className="outer-box">
<div className="sliding-box"></div>
</div>
.outer-box {
width: 300px;
height: 200px;
position: relative;
}
.sliding-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
}
slideIn() {
const moveElemment = document.getElementById('sliding-box');
const pos = -100;
if (moveElemment) {
const id = setInterval(frame, 10);
function frame() {
if (pos == 0) {
clearInterval(id);
} else {
pos++;
moveElemment.setAttribute('style', `left: ${pos}%`);
}
}
}
}

Perphas you could take advantage of CSS transitions to achieve smoother animation that is decoupled from the JS thread, to resolve your problem? For example, you could update your CSS with a transition rule and additional selector as follows:
.sliding-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: -100px; // Initial position of sliding-box
transition: left 1s linear; //Specify the animation behaviour
}
.sliding-box.in {
left: 0px; // Position of sliding-box after animation
}
with simplified JS to trigger the transition animation as follows:
slideIn() {
const moveElemment = document.getElementById('sliding-box');
if (moveElemment) {
// When this selector is added, it triggers the animation
// transition from left:-100px to left:0px over a 1 second
// interval
moveElemment.classList.add('in');
}
}

Related

How can I make this Jquery animate() with css3 animations?

This is my jfiddle
And this is my actual code
$card.animate({
left: "1000px"
}, 500, function(){
$card.hide(500);
});
(I dont know why 'left' didnt work on jfiddle) Basically ive got a container with 5 $cards there. When user swipes the card (already implemented) the animate() is triggered and the card slides to the rightand then disappears. How can I implement such thing in CSS animations instead of using Jquery? Ive read that CSS animations run faster (and I proved it on my mobile device, the hide() runs really slow)... Any help or advice will be appreciated
First of all, create a class that you can trigger via jQuery that will have the animation.
Then, using you have two options: transition or animation. Transitions are simpler and more direct, but you can do more with animations.
Here is how I would suggest to do it: a transition for the movement, and an animation to recreate the hide() function.
#keyframes hide {
99% { display: auto; }
100%{ display: none; opacity: 0; }
}
.myelement {
transition: all .5s;
position: absolute;
left: 0;
}
.myelement.toLeft {
left: 2000px;
animation: hide .5s 1 forwards;
}
To trigger it, simply do this:
$(".myelement").addClass("toLeft");
Here is a working JSFiddle.
And like #MohitBhardwaj said, it is necessary for you to set position to absolute, relative, or static in order for positioning (i.e., the left property) to work.
It's also important to note that a transition needs an initial value. I added left: 0 to do this. Otherwise, (with a CSS transition) it would simply jump to 2000px because there is no starting point.
Also, because 2000px as a left value is very large, I suggest you change the parent element's scroll to overflow: hidden, so that the extraneous scroll bar doesn't appear.
Your left didn't work, because you need to set position to a value other than static (which is default) for it to work.
As for using CSS, you can add a class instead of animating in jQuery. This class can change the transition which you can set in css as per your requirements.
var my_div = $('.myelement');
my_div.on('click', function() {
var $this = $(this);
$this.addClass("gone");
setTimeout(function(){
$this.hide();
}, 600 );
})
#mywrapper
{
overflow: hidden;
}
.myelement {
height: 200px;
width: 200px;
background-color: red;
opacity: 1;
position: relative;
transition: all 0.5s ease;
opacity: 1;
left: 0px;
}
.myelement.gone
{
left: 500px;
opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="mywrapper">
<div class="myelement">
Click me please
</div>
</div>

How to make fixed navbar transparent based on page scroll?

I want mynavbar to be transparent when the page is scrolled to the top, however when the user scrolls I would like it to be made opaque. I tried this with javascript, but something still isn't working.
http://jsfiddle.net/6A6qy/
function myFunction() {
if ($(window).scrollTop() < 50) {
document.getElementById("masthead").style.opacity = "0.5";
}
}
#masthead {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100%;
height: 50px;
background-color: #00a087;
opacity: 1;
}
#container {
background-color: blue;
height: 1000px;
display: block;
margin-top: -50px;
}
<body onload="myFunction()">
<nav id="masthead">
<!-- Fixed navigation bar content -->
</nav>
<div id="container"></div>
</body>
How about this:
JS:
// listen for scroll
$(window).scroll( function() {
// apply css classes based on the situation
if ($(".masthead").offset().top > 100) {
$(".masthead").addClass("navbar-scrolled");
} else {
$(".masthead").removeClass("navbar-scrolled");
}
}
CSS:
.navbar-scrolled {
/* some css for navbar when scrolled */
}
JSFiddle example:
http://jsfiddle.net/8ruwnaam/
And then of course you could add some optimization to not apply the classes all the time if they are already there. But it works quite fine without such things as well.
Additional things:
The first version of this answer and your question use IDs for styling, which is not really a good idea according to a lot of people. Styling IDs goes against the DRY principles, and causes all these funny little problems when you forget to think about CSS specificity. IDs are quite alright for a lot of things when it comes to the logic in the JS or something, but try to use classes for styling.
You should create an .opaque css class and attach it based on actively scrolling or if scrollTop is < 50:
.opaque {
opacity: 0.5;
}
Then attach that class on('scroll') or at scrollTop (this is using the debounce plugin):
function myFunction() {
var $masthead = $('#masthead')
, $window = $(window);
// currently scrolling
$window.scroll($.debounce( 250, true, function(){
$masthead.addClass('opaque');
}));
// done scrolling
$window.scroll($.debounce( 250, function(){
// if at the top, add or keep opaque class
if($(this).scrollTop() < 50) {
if(!$masthead.hasClass('opaque')) {
$masthead.addClass('opaque');
}
} else {
$masthead.removeClass('opaque');
}
}));
}
You need to set it to be transparent by default (as it will be on the top) like that
#masthead {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100%;
height: 50px;
background-color: #00a087;
opacity: 0.5; /*edited the opacity to be 50% by default*/
}
then use this script to achieve your needs:
$(document).ready(function () {
$(window).scroll(function(){
var ScrollTop = parseInt($(window).scrollTop());
if (ScrollTop < 100) {
document.getElementById("masthead").style.opacity = "0.5";
} else {
document.getElementById("masthead").style.opacity = "1";
}
});
});

I can't get my navigation to change on scroll

I know it is a repeat question, but I am trying to get my navigation bar to change styling using JavaScript/jQuery/CSS by making jQuery add and remove classes depending on the position of the scrollbar, yet with no prevail. I am a huge noob with jQuery. Could someone tell me if these is something wrong with my code. I have searched for hours and I can't find and error. Here is a working example: http://codepen.io/anon/pen/QbWOJv
And here is my code:
// on scroll,
$(window).on('scroll',function(){
// we round here to reduce a little workload
stop = Math.round($(window).scrollTop());
if (stop > 50) {
$('.nav').addClass('passed-main');
} else {
$('.nav').removeClass('passed-main');
}
.nav
{
background-color: #000000;
opacity: 0.3;
width: 100%;
height: 40px;
position: fixed;
top: 0;
z-index: 2000;
transition: all 0.3s;
}
.nav.past-main
{
background-color: #ffffff;
opacity: 1;
}
<div class="nav">
</div>
Perhaps the example is something that you want to achieve, and when you try it with your code above, it's not working.
Here's the problem with your code in the snippet:
You forgot to close the function
// on scroll,
$(window).on('scroll',function(){
// we round here to reduce a little workload
stop = Math.round($(window).scrollTop());
if (stop > 50) {
$('.nav').addClass('passed-main');
} else {
$('.nav').removeClass('passed-main');
}
}); // You forgot to close the function here
You add/remove class passed-main while in your CSS you're using class selector .nav.past-main
Your window doesn't have any scrollbar, so you need to add this to the CSS to test if it works
body {
height: 1500px;
}
You forgot to include the jQuery in the Snippet.
Here's the working updated snippet
// on scroll,
$(window).on('scroll', function () {
// we round here to reduce a little workload
stop = Math.round($(window).scrollTop());
if (stop > 50) {
$('.nav').addClass('past-main');
} else {
$('.nav').removeClass('past-main');
}
});
.nav {
background-color: #000000;
opacity: 0.3;
width: 100%;
height: 40px;
position: fixed;
top: 0;
z-index: 2000;
transition: all 0.3s;
}
.nav.past-main {
background-color: #ffffff;
opacity: 1;
}
body {
height: 1500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<div class="nav"></div>

Styles apply just to first two slides

I 'm trying to do kind of slideshow on the background using two img tags. I have a couple of random images, so I have a javascript function to get a random name. But the main problem is: when I zoom or resize window first two slides crop well and display without any problem, but after that every slide is changing if I try to resize the window or zoom in-out.
Here you can see that bug: cullycross.github.io(nevermind about big images, im gonna resize them)
Here is my code:
function randomBackground () {
var active = $('#background .active');
var next = ($('#background .active').next().length > 0) ? $('#background .active').next() : $('#background img:first');
next.attr('src', getRandomName());
var imgHeight = next.height();
var windowHeight = $(window).height();
var diff = imgHeight - windowHeight;
if(diff > 0) {
next.css('top', -diff*0.6);
}
next.css('z-index', 2);
active.fadeOut(1500, function() {
active.css('z-index', 1).show().removeClass('active');
next.css('z-index', 3).addClass('active');
})
}
window.onload = function() {
$('#background .active').attr('src', getRandomName());
$('#background').fadeIn(1500);
setInterval(randomBackground, 5000)
}
Here is css:
#background {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: -1;
overflow: hidden;
}
#background img {
position: absolute;
z-index: 1;
float: left;
bottom: 0px;
left: 0px;
top: 0px;
height: auto;
width: 100%;
}
#background img.active {
z-index: 3;
}
Here is part of html:
<div id="background">
<img id="current-image" class="active" />
<img id="next-image" />
</div>
It seem to affect only the images loaded after first run.
Try adding images directly into html, using a
<ul><li><img ...></li></ul>
structure, and get the image from there.
You should decrease the fadeout delay. The problem is caused from the browser since the delay is big it can't handle both fadeout and zoom in/out
active.fadeOut(300, function() {
active.css('z-index', 1).show().removeClass('active');
next.css('z-index', 3).addClass('active');
})
And try to use light size pictures, with the same aspect ratio
I didn't found an answer, but I found a library, that makes possible that thing, that I want. Thx to https://github.com/srobbin/jquery-backstretch

How to animate through stacked images Javascript

I have a series of images that are "stacked" inside of div. I want to transition (crossfade) between these images (not using jQuery), with CSS transitions. What I do not know how to do is endlessly transition between the images. The images are added dynamically through a JSON feed, and they will continue to be added so the number of images in the divs is not set.
I was thinking an approach using the z-index to bring images on top of each other (and then animate the opacity and other properties) but if I want to animate through 4 photos, I am not sure how to keep track of z-index and the opacity settings, to know which is showing. Here is what I came up with so far, but I would be interested in how people cycle through a potentially unknown number of images and keep track of what is "shown". Basically, I have a simple CSS Transition set on the images right now and am animating by adding and removing classes and I want to be able to create a cycle that goes through the images, changing the z-index and some property, and then later send it to the back of the group.
HTML
//Example div (on my page there are many of these)
<div class="imageHolder">
<div class="imageContent">
<img class="homeImages" src="media/test.png">
<img class="homeImages" src="media/test1.png">
<img class="homeImages" src="media/test2.png">
</div>
</div>
CSS
div.imageHolder {
float: left;
position: relative;
width: 32.9%;
padding-bottom: 18.6%;
margin-right: .1em;
}
div.imageContent {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}
div img {
width: 100%;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1
}
div img.newImage {
z-index: 2;
opacity: 0;
}
div img.live {
z-index: 3;
opacity: 1;
transition: opacity 1s ease-in;
}
Javascript
function select() {
var x = Math.floor(Math.random() * divs.length);
if(divs[x].children.length > 1) {
var live = document.querySelector('div img.live');
var old = document.querySelector('div img.newImage');
live.className = 'newImage';
old.className += ' live';
}
}
You need js, at least to keep track of which is the current image and add a class that triggers the css transition.
If I understand correctly, you've almost got it. Try this
function select() {
var x = Math.floor(Math.random() * divs.length),
current = document.querySelector('.imageContent img.live'),
newOne = document.querySelectorAll('.imageContent img')[x];
current.className = ''; // clear the .live class
newOne.className = 'live';
// this triggers the css transition
setTimeout(select, 1000); // after the css transition ends, do this again
}
And change the css to
div img {
width: 100%;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
/* moved .newImage styles here as a default */
z-index: 2;
opacity: 0;
}

Categories