Animating content loaded with Ajax - javascript

that i don't know if it's even possible. I wanna try to load content with Ajax, and animate it right away, piece by piece. I have empty body. And on server side i have document with with h1 paragraph and two images. I wanna load them with ajax with animation from different angles (left, top, right, bottom). I know how to animate but as soon as i load them they are already on the page and i want to animate them into the page. Code looks like this:
<body>
<button id="load"></button>
</body>
My jquery script
<script>
$('#load').click(function() {
callAjax();
return false;
});// end of click function
});
function callAjax() {
$.ajax({
type: "POST",
cache: false,
url: 'content.html',
success: function(data){
if(data !== ""){
$("html").prepend(data);
}
},
error: function () {
console.log('error', data);
},
complete: function () {
console.log("done"); }
}); //ajax call
} //document ready
</script>
server side data
<section class="content">
<h1>About</h1>
<p> Text</p>
<img src="ipad.png" class="rotate">
<img src="ipad1.png" class="circle">
</section>

To animate the elements you'd need more than 1 key frame. Currently you only have 1: the end-state. You'd need another one to animate from. Think of a move: to have a character walk on screen you'd have to position them off-screen first.
I'm going to assume we're doing just that: loading your content off-screen, then walking it on-screen.
Set the position for the elements (via CSS, or explicitly, but do so in the original file) off-screen. For example, use this CSS:
position: absolute;
left: -1000;
which would place the element 1000 pixels to the left of the window. That's your starting position, which is where you're going to "start" at after you have loaded the content (asynchronously).
The next part is the transition phase moving them from START to END via a series of intermediate steps computed by your code. There are many robust JS/HTML/CSS/SVG animation libraries, but I'm going to use a basic JS function: setInterval.
var thing = $('#yourThing'); // select your thing
var distInterval = 1000 / 60; // we're going to move 1000px every 60 steps
var code = function() {
thing.position().left = thing.position().left + distInterval; // move by the distance
// destination is an abs position of 100px from the left
if (thing.position().left == 100) {
window.clearInterval(); // stops the loop
}
};
var delay: 16.7; // 1/60th of a second, in ms
var intervalID = window.setInterval(code, delay); // set and start the loop
Once you are comfortable with this concept you'll soon find that this is a poor implementation choice. Some keywords to google for will be the "requestAnimationFrame()" function and the term "easings".

You could hide 'data' and then animate it in.
$(data).hide().fadeIn("slow");

Related

Change background image every minute with transition

I'm currently working on a private dashboard. This dashboard should have changing background images that changes every minute (should be no problem to switch it to an hour or 20 seconds if I got it working then).
In order to do so, I registered for the [Pixabay API][1] and created the following API request
https://pixabay.com/api/?key=[my_key]f&q=nature&image_type=photo&orientation=horizontal&min_width=1920&min_height=1080&page=1&per_page=100
With that request, I get an array of 100 elements, each one containing the following information:
comments: 639
downloads: 785498
favorites: 3020
id: 736885
imageHeight: 1195
imageSize: 186303
imageWidth: 1920
largeImageURL: "https://pixabay.com/get/51e3d34b4257b108f5d0846096293076123ddee2504c704c7c2879d79048c05a_1280.jpg"
likes: 3966
pageURL: "https://pixabay.com/photos/tree-sunset-amazing-beautiful-736885/"
previewHeight: 93
previewURL: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_150.jpg"
previewWidth: 150
tags: "tree, sunset, amazing"
type: "photo"
user: "Bessi"
userImageURL: "https://cdn.pixabay.com/user/2019/04/11/22-45-05-994_250x250.jpg"
user_id: 909086
views: 2042402
webformatHeight: 398
webformatURL: "https://pixabay.com/get/51e3d34b4257b10ff3d8992cc62f3f79173fd9e64e507440722d78d39248c7_640.jpg"
webformatWidth: 640
From these 100 elements, I then randomly select one, take the largeImageURL and set it as background, together with a semi-transparent dark overlay to be able to read the text on top of it better. All this is done within a setInterval, so it happens every x milliseconds.
This is the code for it:
setInterval(function(){
$.post('getBackgroundImages.php', { }, function(data) {
var imageCollection = JSON.parse(data);
var imageNumber = Math.floor(Math.random() * 100);
var imageLink = imageCollection.hits[imageNumber].largeImageURL;
$('body').css("background","linear-gradient(rgba(0,0,0,.3), rgba(0,0,0,.3)),url('"+imageLink+"')");
});
},60000);
`getBackgroundImages.php' does nothing more then printing the content of the API-request.
The question now is the following: In the implemented solution, everything works, the new photo is displayed as background and switching works. However, the background is always set to a grey background for about half a second, before the image is displayed, which looks really not good, especially when often switching images.
What I'd like to get is a switching of the background without this grey background for a short time, propably even with a transition, so the change is not so abrupt...
I found a solution to first display a blured preview of the image before display the full resolution one. However, I think that this shouldn't be needed, as basically, the image has enough time to load and the background should change AFTER the image has loaded.. I do not care, if the change happens every 62 seconds, even though I set it to 60 seconds, because the image needs to load first.
Can anybody give me a hint on how to get this working better?
Thanks in advance!
[1]: https://pixabay.com/api/docs/
Maybe the most simple would be to alternate between two containers that works like backgrounds :
HTML :
<body>
<div class='bg' id='firstBg'></div>
<div class='bg' id='secondBg'></div>
<...Your Stuff...>
</body>
CSS :
body {
background: transparent;
}
.bg {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background-position: center;
z-index: -1;
background-size: cover;
transition: 3s ease-in;
}
#secondBg {
display: none;
}
JS :
setInterval(function(){
$.post('getBackgroundImages.php', { }, function(data) {
var imageCollection = JSON.parse(data);
var imageNumber = Math.floor(Math.random() * 100);
var imageLink = imageCollection.hits[imageNumber].largeImageURL;
if ($('#firstBg').css('display') == 'none') {
$('#firstBg').css("background-image","url('"+imageLink+"')");
$('#firstBg').fadeIn();
$('#secondBg').fadeOut();
}
else {
$('#secondBg').css("background-image","url('"+imageLink+"')");
$('#secondBg').fadeIn();
$('#firstBg').fadeOut();
}
});
},60000);
I did the following solution now, thanks to the hint of #zero298.
<script>
function loadImages (images) {
// each image will be loaded by this function.
// it returns a Promise that will resolve once
// the image has finished loading
let loader = function (src) {
return new Promise(function (resolve, reject) {
let img = new Image();
img.onload = function () {
// resolve the promise with our url so it is
// returned in the result of Promise.all
resolve(src);
};
img.onerror = function (err) {
reject(err);
};
img.src = src;
});
};
// create an image loader for each url
let loaders = [];
images.forEach(function (image) {
loaders.push(loader(image));
});
// Promise.all will return a promise that will resolve once all of of our
// image loader promises resolve
return Promise.all(loaders);
}
function cycleImages (images) {
let index = 0;
setInterval(function() {
// since we need an array of the image names to preload them anyway,
// just load them via JS instead of class switching so you can cut them
// out of the CSS and save some space by not being redundant
$('body').css("background","linear-gradient(rgba(0,0,0,.3), rgba(0,0,0,.3)),url('"+images[index]+"')");
// increment, roll over to 0 if at length after increment
index = (index + 1) % images.length;
}, 28800000);
}
$(function(){
$.post('getBackgroundImages.php', { }, function(data) {
var imageCollection = JSON.parse(data);
var imageNumber = Math.floor(Math.random() * 100);
var imageLink = imageCollection.hits[imageNumber].largeImageURL;
$('body').css("background","linear-gradient(rgba(0,0,0,.3), rgba(0,0,0,.3)),url('"+imageLink+"')");
});
$.ajax('getBackgroundImages.php',{
success:function(data) {
var parsed = JSON.parse(data);
var images = parsed.hits;
var imageUrls = [];
images.forEach(function(item,index){
imageUrls.push(item.largeImageURL);
})
loadImages(imageUrls).then(cycleImages).catch(function (err) {
console.error(err);
});
}
});
});
</script>
This first puts all imageUrls into an array, then loads all images with Promise to then display then without a big delay.. I didn't really manage to get a nice transition between switching the images, as jQuerys fade-to method lets the content of the page fade out as well, rather then only the background image...
Adding more div's / changing the structure of the page is not too easy by the way, as there is a lot of floating and other css rules to make the elements appear on various positions on the page. Adding a div around all content in order to try to give that div the background-image destroyed the hole layout...
All in all, I'm confident with this solution, however, if anybody has a good idea to make the switch more smooth, feel free to tell me :)

particle-slider logo won't resize in Safari

I'm loading a front-end site from Wordpress using a HTML 5 Blank Child Theme. I have a logo effect using particle slider for when I have a screen size of >960px; for screen sizes <960px I have a flat logo image. It all works fine on both Firefox and Google Chrome but when I re-size between logos on Safari the page has to be refreshed manually (i.e. by pressing cmd+r) before the PS effect shows again. The code was sourced from an original question I posted here - Original Stack Q&A
Here's the javascript code I'm now using -
particle-slider.php
<?php /* Template Name: particle-slider */ ?>
<!-- particle-slider template -->
<div id="particle-slider">
<div class="slides">
<div class="slide" data-src="<?php echo home_url(); ?>/wp-content/uploads/2017/10/havoc_logohight.png"></div>
</div>
<canvas class="draw" style="width: 100%; height: 100%;"></canvas>
</div>
<script type="text/javascript">
var ps = new ParticleSlider({ 'width':'1400', 'height': '600' });
// patch nextFrame to track failure/success
var nextFrameCalled = false;
ps.oldNextFrame = ps.nextFrame;
ps.nextFrame = function () {
try {
ps.oldNextFrame.apply(this, arguments);
nextFrameCalled = true;
} catch (e) {
console.log(e);
nextFrameCalled = false;
}
};
var addEvent = function (object, type, callback) {
if (object.addEventListener) {
object.addEventListener(type, callback, false);
} else if (object.attachEvent) {
object.attachEvent("on" + type, callback);
} else {
object["on" + type] = callback;
}
};
var oldWidth = window.innerWidth;
addEvent(window, 'resize', function () {
var newWidth = window.innerWidth;
if (newWidth >= 960 && oldWidth < 960) {
console.log("Restarting particle slider " + newWidth);
ps.resize();
if (!nextFrameCalled)
ps.nextFrame(); // force restart animation
else {
// ensure that nextFrameCalled is not still true from previous cycle
nextFrameCalled = false;
setTimeout(function () {
if (!nextFrameCalled)
ps.nextFrame(); // force restart animation
}, 100);
}
}
oldWidth = newWidth;
});
</script>
<div id="logo"> <img src="<?php echo home_url(); ?>/wp-content/uploads/2017/10/havoc_logo.png"> </div>
<!-- particle-slider template -->
I need the same effect as is seen on this site here - where the logo switches from particle to static as the page is re-sized. The particle logo re-appears perfectly.
All other relevant code is linked to the original question as nothing has changed. I'm not seeing anything in the console to suggest why it's not working.
The resize event can fire multiple times, and within that event anything you put in a setTimeout will get called after the current code block has executed. It's hard to say for sure without picking apart ParticleSlider, but I think the mix of global variables (nextFrameCalled, oldWidth) and callbacks firing out of your expected order is the cause.
I think the intention is to debounce the forced restart - you want to call ParticleSlider.nextFrame() but if it's already been called you want to wait 100ms first.
Looking at the answer you've adapted for this question that appears to be a workaround for the canvas element not being visible on requestAnimationFrame - that might still not be available after 100ms or after the ParticleSlider.nextFrame() has been called multiple times in an attempt to get it to fire.
From your original question and selected answer I think you need to ParticleSlider.init() to reset the component, but the flashing you're seeing is due to the fact that it takes a while to run every time it's called. ParticleSlider.nextFrame() doesn't take as long (and uses requestAnimationFrame to avoid jank) but doesn't create the canvas on resize in Safari.
So, to fix:
Use ParticleSlider.init()
Debounce the resize event so you're not firing it lots of times
Fire it once a short delay after the user has stopped firing resize events.
Code will be something like:
var timeout = null;
window.addEventListener('resize', function() {
// Clear any existing debounced re-init
clearTimeout(timeout);
// Set up a re-init to fire in 1/2 a secound
timeout = setTimeout(function() {
ps.init();
}, 500);
});
You'll still see the flash and the delay as the component re-initialises, but only once.
I'd add that ParticleSlider has been deprecated by the authors and replaced with NextParticle - probably to fix these kinds of issues (in fact it has specific features to handle resizing). As it is a paid for component I'd suggest asking them for the help with this, as you should get your money's worth (or switch to an open source component where you can fix these bugs yourself).
So, I've finally figured this out by retracing my steps using the Q&A from before. Previously there seemed to be an issue with some of the sample links but one appears to work now - example.
I went into the page inspector and noticed a few differences between the code firing this example and the one in the actual answer that was causing the logo to flicker like a light bulb. This is the code I have now put into the wordpress site -
<script type="text/javascript">
//wait until the DOM is ready to be queried
(function() {//document.addEventListener('DOMContentLoaded', function() { //DOM-ready callback
var ps, timeout;
var img1 = new Image();
img1.src = '<?php echo home_url(); ?>/wp-content/uploads/2017/10/havoc_logohight.png';//havoc_logo_e6os2n.png';
var imgs = [ img1 ];
handlePS();
window.addEventListener('resize', function() {
//https://davidwalsh.name/javascript-debounce-function
if (timeout) { //check if the timer has been set
clearTimeout(timeout); //clear the timer
}
//set a timer
timeout = setTimeout(handlePS, 250);
});
function handlePS() {
if (document.body.clientWidth >= 960) {
//check if ps is assigned as an instance of the ParticleSlider
if (ps != undefined && typeof ps !== null) {
ps.init(); //refresh the particle slider since it exists
console.log('called init on ps');
} else {
if (window.location.search.indexOf('d=1') > -1) {
debugger;
}
//otherwise create a new instance of the particle slider
ps = new ParticleSlider({
width: 1400,
height: 600,
imgs: imgs
});
}
}
else {
//when the flat logo is displayed, get rid of the particle slider instance
// delete ps;
ps = null;
}
}
})();
</script>
It now works fine across all the main browsers - Chrome/Safari/Firefox. It still feels a bit clunky as it pushes the rest of the page down whilst it is re-sizing and it takes probably a few seconds more than I'd like - not sure if there's a timer option to speed the reanimation up? Otherwise, everything is working fine.

Stop element from being fixed once scrolled past value

I have a fixed .widget element that remains visible at all times. Currently however, it scrolls over the footer area. My goal is to stop the widget before it hits the footer.
CSS
.widget {
position:fixed;
height:450px;
width:300px;
}
footer {
height:450px;
width:100%;
}
My route I'm taking is currently:
jQuery
var $bodyheight = $('body').height();
var $footerheight = $('footer').height();
var $widgetheight = $('.game_widget').height();
var $pageheight = $bodyheight - $footerheight - $widgetheight;
$(window).on('scroll', function() {
console.log($(this).scrollTop())
});
My next step would be to loop through to see if scrollTop > $pageheight then update some CSS.
Is this the best way of going about this? Is there a cleaner/simpler way to achieve the same result?
I have managed to solve this quite simply. Inside the scroll function I set 2 variables, one for the position of the fixed element, the other for the position of the footer. These return the exact value from how far the top of the element is from the top of the page. For the fixed element I need to know the distance to the bottom of this element so I also include the height.
var $fixedpos = $(".game_widget").offset().top + $('.game_widget').height();
var $footerpos = $("footer").offset().top - 25; // 25 accounts for margin
Using a simple if/else the CSS is updated to display none/initial depending on whether $fixedpos > $footerpos (i.e. the fixed element is overlapping the footer).
if ($fixedpos > $footerpos) {
$('.game_widget').css('display','none');
} else {
$('.game_widget').css('display','initial');
}
This works, however there is a 'flicking' effect as the fixed element overlaps the footer. This is due to the function executing extremely rapidly. The solution to the flicker is to use this simple 'throttling' plugin that adds a short delay (of your choice) between each execution of a function - http://benalman.com/projects/jquery-throttle-debounce-plugin/
You then just need to bind the on scroll function to the throttle:
function scrolling() {
console.log($(".game_widget").offset().top + $('.game_widget').height());
console.log($("footer").offset().top - 25);
var $fixedpos = $(".game_widget").offset().top + $('.game_widget').height();
var $footerpos = $("footer").offset().top - 25;
if ($fixedpos > $footerpos) {
$('.game_widget').css('display', 'none');
} else {
$('.game_widget').css('display', 'initial');
}
};
$(window).on('scroll', $.throttle(250, scrolling)); // 250ms between executing the function
});
This 250ms delay stops the function from executing so rapidly that the flickering effect occurs.
Hope this helps others trying to solve this problem.

Auto-scroll embedded window only once when entering viewport. Can't scroll back up

I have an image embedded in a container with a background image to give the effect of scrolling within the page. Initially, I had the scrolling effect take place on page load, with this simple bit of script which worked perfectly.
$(window).on("load", function () {
$(".embedded_scroller_image").animate({ scrollTop: $('.embedded_scroller_image')[0].scrollHeight}, 2500, "easeInOutCubic");
}); // end on load
However, the element is too far down the page now and I want that animation to fire when the element enters 80% of the viewport. That part is also working fine with this code here (I'm using a scroll limiter to improve browser performance)
// limit scroll call for performance
var scrollHandling = {
allow: true,
reallow: function() {
scrollHandling.allow = true;
},
delay: 500 //(milliseconds) adjust to the highest acceptable value
};
$(window).on('scroll', function() {
var flag = true;
if(scrollHandling.allow) { // call scroll limit
var inViewport = $(window).height()*0.8; // get 80% of viewport
$('.embedded_scroller_image').each(function() { // check each embedded scroller
var distance = $(this).offset().top - inViewport; // check when it reaches offset
if ($(window).scrollTop() >= distance && flag === true ) {
$(this).animate({ scrollTop: $(this)[0].scrollHeight}, 2500, "easeInOutCubic"); //animate embedded scroller
flag = false;
}
});
} // end scroll limit
}); // end window scroll function
The problem is this: I want the autoscroll to happen once and then stop. Right now, it works on entering viewport, but if I then try to manually scroll the image, it keeps pushing back down or stutters. You can't get the element to scroll normally. I attempted to use the flag in the code to stop the animation, but couldn't get that to successfully work.
How can I have this animation fire when the element is 80% in the viewport, but then completely stop after one time?
Here is a codepen I mocked up as well http://codepen.io/jphogan/pen/PPQwZL?editors=001 If you scroll down, you will see the image element autoscroll when it enters the viewport, but if you try to then scroll that image up in its container, it won't work.
Thanks!
I have tweaked your script a bit:
// limit scroll call for performance
var scrollHandling = {
allow: true,
reallow: function() { scrollHandling.allow = true; },
delay: 500 //(milliseconds) adjust to the highest acceptable value
};
$(window).on('scroll', function() {
if(scrollHandling.allow) { // call scroll limit
var inViewport = $(window).height()*0.8; // get 80% of viewport
$('.embedded_scroller_image').each(function() { // check each embedded scroller
var distance = $(this).offset().top - inViewport; // check when it reaches offset
if ($(window).scrollTop() >= distance ) {
$(this).animate({ scrollTop: $(this)[0].scrollHeight}, 2500, "easeInOutCubic"); //animate embedded scroller
scrollHandling.allow = false;
}
});
} // end scroll limit
}); // end window scroll function
I have kicked out your flag and simply made use of scrollHandling.allow declared already.
Try if it works for you :)
Cheers!

Scroll Top = Scroll Height not working in Chrome

This is the js that I have in my js file
function refreshChat()
{
//speed up by selecting the div only once
var shoutbox = $("#shoutbox");
//get the height of the scroll (if any)
var oldScrollH = shoutbox.attr("scrollHeight") - 20;
//the ajax request
$.ajax({
url: 'shoutbox/update.php',
//disable cache
cache: false,
success: function(html) {
//update the shoutbox
shoutbox.html(html);
//get the heigth of the scroll after the update
var newScrollH = shoutbox.attr("scrollHeight") - 20;
if(newScrollH > oldScrollH)
{
//*move* the scroll down using an animation :)
shoutbox.animate({scrollTop: newScrollH}, 1);
}
}
});
}
//set the refreshChat function to run every *refreshSeconds*
setInterval(refreshChat, refreshSeconds);
});
it works fine in Firefox and IE, but with Google Chrome it constantly flicks. It will scroll to the bottom on page load, but when it calls to the function refreshChat it moves back up about halfway up the div.
I also have this in my <head>
$(document).ready(function(){
//speed up by selecting the div only once
var shoutbox = $("#shoutbox");
//get the height of the scroll (if any)
var oldScrollH = shoutbox.attr("scrollHeight");
//the ajax request
$.ajax({
url: 'shoutbox/update.php',
//disable cache
cache: false,
success: function(html) {
//update the shoutbox
shoutbox.html(html);
//get the heigth of the scroll after the update
var newScrollH = shoutbox.attr("scrollHeight");
if(newScrollH > oldScrollH)
{
//*move* the scroll down using an animation :)
shoutbox.animate({scrollTop: newScrollH}, 1);
}
}
})
});
so that it will auto load the shoutbox on page load, could this be conflicting with it? It seems logical, but I don't want users to have to wait 3 seconds for the shoutbox to initially load.
You need to convert string to int.
scrollHeight is custom attribute and i guess its dynamically added so it must string thats why you need to cast it to int.
parseInt(shoutbox.attr("scrollHeight"));
try this, hope this will solve it.

Categories