I'm using iCanHaz.js to swap screens, but I need a function to fire once the new content has completed loading fully. I have been able to do this before by using a setTimeout of 0 to make the call asynchronous, but on pages with lots of images, this doesn't seem to be hitting soon enough.
function show_page(){
document.getElementById('container').innerHTML = ich.artworks({
variables : variables
});
window.setTimeout(function(){
var midWidth = (document.body.offsetWidth/2) - window.innerWidth / 2;
var midHeight = (document.body.offsetHeight/2) - window.innerHeight / 2;
scrollTo( midWidth, midHeight);
}, 0);
}
How can I delay this function until the height is known? Even if I do know the height, I cannot scroll to a point that is below the current height of the page, so I have to wait until the images are loaded if I do not know their height already.
You'd have to modify your template-based approach slightly, but if you create the images using new Image() you can use the onload events to determine when all the images have loaded and then set your dimensions.
There is a similar case in question:
How can I tell when changes to jquery html() have finished?
The proposed solution is to add a timeout of 1 (not 0) for the code to be executed after HTML rendering, as timed out code executes after JavaScript sole thread is done with its rendering stuff.
Hope that works for your case.
Related
I'm trying to position two images by changing their top margin based on the scroll position.
The margins have a max value as well.
Everything works just fine but I have a warning on the console, saying that this solution can cause a jittery scrolling effect in browsers with asynchronous scrolling.
My first question is, should I worry about this?
Also, this is literally my first few lines of javascript and I'm not sure if this solution is good enough, so any advice is appreciated.
It just looks so simple I feel like there is a catch.
I could do it by adding classes to the images and set the margins in CSS, but it would be a lot longer code I guess.
I'm trying to do this strictly with js and CSS grid, just to learn to solve problems with limited tools.
The images are in a div, which is in a grid cell.
window.addEventListener("scroll", function () {
myMargin = 0.011 * window.scrollY;
if (myMargin < 3.4) { //max margin is 3.4% for myImg1
myImg1.style.marginTop = animMargin + "%";
myImg2.style.marginTop = animMargin / 2.7 + "%"; //myImg2 moves on a different scale
} else {
myImg1.style.marginTop = "3.4%"; //when the max value reached the margin is fixed
myImg2.style.marginTop = "1.25%";
}
});
Scrolling handlers can be intensive and put performance strain on the page as they will fire far more times than your handler actually needs. This ends up causing choppy/lag when scrolling as the browser may need to repaint in response to your handler.
A common technique is to throttle or debouce the handler.
Throttle:
only invokes func at most once per every x milliseconds.
Debouce:
delays invoking func until after x milliseconds have elapsed since the last time the debounced function was invoked.
The warning you are getting is actually fine, but you may benefit from using a throttled callback and increase the wait time to the max that is suitable for your needs - so least times it is called in order for it to work for you.
Demo using lodash throttle
// only call the handler once every 200ms
const throttledScroll = _.throttle(() => {
console.info('throttled', window.scrollY);
}, 200);
window.addEventListener('scroll', throttledScroll);
html,
body {
height: 300vh;
}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
Is there a way to use a callback function after the screen is done resizing an element?
For example:
element.css('height', 'auto', function() {
element.css('height', element.height() - 6);
});
In words: when the element is reset to it's default height. The DOM needs to re-evaluate the height of the element. That takes a bit of time, but that time varies from client to client. So I don't want to use a setTimeOut function and slow down the script much more then needed.
So how can I execute some JavaScript just after the element's height is reset?
PS: I already tried the jQuery animate function. But still that callback function doesn't seem to wait long enough for the element to actually obtain it's original height.
Even tough the comments weren't helpful at all. I found something that actually seems to work. It waits for the height change to process and instantly process the next rule afterwords.
element.css('height', 'auto').delay(1).css('height', element.height() - 6);
Is it possible to load a background-image asynchronously?
I've seen many jQuery plugins to load normal image in an asynchronous way, but I can't find if it's possible to preload / asynchronously load a background-image.
EDIT
I clarify my problem. I've been working on this test site http://mentalfaps.com/
The background image is loaded randomly from a set of images refreshed each hour by a chron job (which takes random images on a flickr catalog).
The host is free and slow at the moment, so the background image takes some time to load.
The positioning of the first overlay (the one with the PNG transparent mentalfaps logo) and width are regulated by a function created in the jQuery(document).ready construct.
If you try to refresh the page many times, the width of the right overlay div is 0 (and so you see a "hole" in the layout)
Here is the method to set my positions:
function setPositions(){
var oH = $('#overlay-header');
var overlayHeaderOffset = oH.offset();
var overlayRightWidth = $(window).width() - (overlayHeaderOffset.left + oH.width());
if (overlayRightWidth >= 0) {
$('#overlay-right').width(overlayRightWidth);
} else {
$('#overlay-right').width(0);
}
var lW = $('#loader-wrapper');
lW.offset({
left: (overlayHeaderOffset.left + oH.width() - lW.width())
});
}
The problem is that the $(window).width() is lower then the effective window width! so the check fails and the script goes for $('#overlay-right').width(0);
any ideas?
Not sure whether I really understand your question, but background images (and all other images) are already loaded asynchronously - the browser will start separate requests for them as soon as it encounters the URL while parsing the HTML.
See this excellent answer for background on loading order: Load and execution sequence of a web page?
If you meant something else, please clarify.
The trick to loading something in the background is to load it once, so the next time when it is loaded it already is in the cache.
Put the following at the end of your html:
<script>
var img = new Image();
img.onload = function () {
document.getElementsByTagName('body')[0].style.backgroundImage = 'background.png';
};
img.src = 'background.png';
</script>
You could use a prefetch link in the head.
<link rel="prefetch" href="/images/background.jpg">
You should be able to add these links to the head via JavaScript.
I like to use CSS to fill the background with a color for page load.
After DOM ready event, I use jQuery to modify the CSS and add a background image. That way, the image isn't loaded until after page loads. Not sure about async, but this method gives the user a decent experience.
Example: http://it.highpoint.edu/
The right side navigation links have a background image. The page initializes with a background color. It is replaced with a background image after page load, via jQuery.
changes in this file jquery.ImageOverlay.js
set your height and width and enjoy this...
imageContainer.css({
width : "299px",
height : "138px",
borderColor : hrefOpts.border_color
});
As it is already mentioned, the background image is loaded asynchronously. If you need to load the background image from JQuery code you may also set the addClass() method to set a CSS class or attr("style=\"background-image:url('myimage.png')\"")
Ive found the answer myself, it was a problem due to the .offset() method that gived sometimes the wrong values.
I had the write values using the .position() :
var overlayHeaderOffset = oH.position();
I'm trying to resize an html element (flash object) but it doesn't seem to respond more than once per second?
Is this a limitation imposed by browsers (both IE7 and FF3 do this)?
Or should I be attempting to resize in a different/more efficient way?
function setHeightNow(height) {
if (document.getElementById) {
if (height > 0) {
var scaleItem = document.getElementById('application');
scaleItem.style.height = height + 'px';
}
}
}
If you are calling this function in a loop, as bobince mentioned in his/her comment, you should change it to a series of setTimeout calls (or setInterval) to give control back to the browser.
Something like this-
var i = INITIAL_VALUE;
(function() {
setHeightNow(foo);
if (i < FINAL_VALUE) {
i++;
setTimeout(arguments.callee, 0); //you can play around with the timeout.
}
})();
Also
The documents.getElementById check is kind of useless because all browsers support it.
It would be wise to somehow take the document.getElementById call outside this repeating function if possible.
It's certainly not a defined limitation; we run an animation loop that is triggered 30 times/sec. (Using a 33ms timeout.) Mostly we move backgrounds around (animations) or adjust opacity (fade in/out) but sometimes we also re-size elements.
However, all of those elements are absolutely positioned, or in a fixed container, so it doesn't trigger a re-layout by the browser. I suspect your problem is simply the cost of performing that re-layout, most of which would be down to the flash object itself.
I have two divs (say, divs with ids: div1 and div2) whose height I need to expand using Fx.Tween
And I want the animations to be simultaneous.
'#div1' 's style.height is to be changed from auto to 0.
'#div2' 's style.height is to be changed for current height to a new height calculated by a function called calculateHeight()
how do I do that?
Mootools animations aren't blocking (animations in JS very rarely are!) so simply executing the two tweens sequentially will have the desired affect (as close as a human can perceive)
function go()
{
$('div1').tween('height', 0);
$('div2').tween('height', calculateHeight());
}
function calculateHeight()
{
return 0; //or whatever
}
I think this has to do with the wait:false option.
I'm not a programmer and mootools is easy but not as much to be so good at it but I remember reading some docs where it says you can control wether the second animation works as soon as the first one ends or simultaneously.
Chain Method: wait
Injects pauses between chained events.
Syntax
myClass.wait(duration);
Arguments
1. duration - (integer) The duration (in milliseconds) to pause the chain stack; defaults to 500.
I think you should CHAIN the morphing and make it wait(0). But I'm not sure. Hope this helps.