jQuery updates DOM element and calculations simultaneously - javascript

So I have this page where on a button click, an image is added embellishments after performing various calculations on its meta-data which is stored as data-attributes.
Since the calculations can take a few seconds, I want to show an overlay on the image. So I do:
$(selectedImageId).addClass('loading');
//perform series of calculations here...
$(selectedImageId).removeClass('loading').addClass('calculated-embellishments');
I would imagine the script to first show the loading overlay on the image, then perform the lengthy calculations, then replace the overlay with the selected embellishment class. However it seems like the DOM is updated only at the end such that I never see the loading class, it just directly jumps from the plain image to the embellishment class after a few seconds.
If I add an alert('test') just before the last line which adds the embellishment then I can see the loading overlay on the image, but not otherwise.
How can I make this work the way I want it to, as I explained above?
Any pointers are very welcome!

What probably happens is that your "lengthy calculations" make the browser "hang" for processing, not having a chance to re-paint your image to reflect the newly added loading class.
Then once the calculations are done, your last instruction replaces the loading class by calculated-embellishments class, and now the browser has time to re-paint. But the loading class is already gone.
You have at least 3 workarounds to let the browser actually display your loading class before your calculations keep it busy:
Use a setTimeout as proposed by #csum, which is a bet on how much time the browser would need before doing the re-paint that will show your image with loading class. Hence the need to "test" different timeout values, but still without any guarantee as the result will depend on each client current performance (CPU, memory, current CPU load!).
Start your calculations in a callback of the "load" event of your overlay (if it is an image). But I am not sure if "load" event is a guarantee of the image (overlay) being painted (shown on screen).
Use 2 nested requestAnimationFrame to make sure at least 1 re-paint has occured, before you start your calculations.

You probably want to execute your calculations using setTimeout.
var WAIT = 10; // experiment with small values here
$(selectedImageId).addClass('loading');
setTimeout(function () {
//perform series of calculations here...
$(selectedImageId).removeClass('loading').addClass('calculated-embellishments');
}, WAIT);
If you want to play around with the timeout length, here is a jsfiddle with a demo using a similar situation: https://jsfiddle.net/v2n19w4d/1/ I find that a timeout length close to zero was not working.
This is really an issue with getting the DOM to update before it is blocked while doing your calculations. See jQuery append in loop - DOM does not update until the end, for example.

Related

Timing issue with image load?

I have a draggable image class that displays an image as expected when it is the only object on the stage. But when I add other graphics objects the image is not visible until I mouseover where the image is located.
It seems like the stage needs an extra update when there are more graphics objects on the display list. Calling tick() or setting my update flag manually doesn’t solve the issue (presumably this happens too quickly).
I can hack around it by putting a counter in the tick function like
if(update || ticks < 10). Clearly, this is not really a solution; the tick code shouldn’t have to check the counter every tick, forever.
Does anybody know the correct way?
You can see it here: http://eduk8r.org/bridge/. You’ll have to mouseover the image the first time, though. (The image is located to the left hand side of the bridge).
The relevant code is in controller.js and DraggableImage.js.
UPDATE: I had thought that reloading the page was sufficient to display the image but that only seems to happen locally.

Freezing Gif using JS at last frame

I'm trying to play a gif animation on my website and I want it to freeze on the last frame. I'm using this code found elsewhere to make it work, but it will either jump back to the first frame or disappear completely. Any help would be greatly appreciated.
<img src="http://s12.postimg.org/wq43xqknx/logoani.gif" id="img1" style="float: left"/>
setTimeout(function () {
setInterval(function () {
$('#img1').attr('src', $('#img1').attr('src'))
}, 1)
}, 1000)
and here's the jsfiddle: http://jsfiddle.net/m6e6n/6/
At the moment JavaScript does not provide an interface to deal with the frames inside an animated GIF, you'll have to find a hacky way to do this but ...
I absolutely discourage you to use that script
Look what you're telling the CPU to execute every millisecond, that is, 1000 times per second:
Traverse the HTML document to find the element "img1"
Change its attribute "src" to ....
... traverse again the HTML document for the same node
read its attribute src
assign it to the element found in 1
Then, the browser will go to the cache and find the image
Depending on the browser, the image may be decoded and rendered. It should start at frame 1, but who knows
So you can thank god if the browser still has some time for additional tasks.
Besides, assuming you don't care about overloading your users' computers, you'll have to finetune the timing very precisely to match the GIF framerate. And bad news is, if the framerate is quick, that's gonna be impossible to achieve across different browsers, or even different computers, let alone mobile devices.
So what can you do? I'd recommend you to play the GIF, then substitute it with a still image of the last frame. Just calculate how much time does one iteration take, then issue a timeout to change the gif with the still image.

Is it okay to use if-else inside jQuery .scroll() event handler?

I want to know if the use of if-else inside the jQuery .scroll() to compare positions with functions like:
offset = $(window).scrollTop()
and:
nameVar = $("#divID").offset()
These comparisons also adds css styles, inside the .scroll(), I have like four if-else statements.I am trying to find out if I will get performance issues when comparing DIVs' positions.
In my first tests the page load okay, but if I leave the page open I noticed that it is getting pretty laggy.
So:
Is it a better way to use if-else inside scroll()?
Am I using if-else wrong?
Is there another way to do it right?
The issue is that .scroll() events can be called very rapidly during a scroll operation. You either need to respond to a given event very quickly OR you need to defer handling of the scroll events (usually with a timer) until the user pauses with the scroll bar and stops moving it. Either one of those behaviors will prevent the laggy behavior.
A couple if statements take almost no time. But doing heavy duty selector queries or particularly making page changes that cause relayout and repainting can take significant CPU.
There is no right or wrong description for what exactly you can and can't do in a scroll handler and not see laggy behavior because it depends upon exactly what you're doing, what computer you're running it on, how much repaint and relayout operations you might cause by your actions, etc... The best you can do is either just decide to take the deferred route so you don't make your changes live until the user pauses the scroll or you have to test your code on all relevant platforms (particularly lower horsepower platforms) to see if your scroll handler is responsive enough.
You can see this post: More efficient way to handle $(window).scroll functions in jquery? for a couple methods of deferring the scroll processing until the user pauses including a jQuery plugin that makes this automatic.
Generally speaking finding the divs on the page will be much more computationally expensive that a couple if statements. So long as you cache lookups like so (outside of the scroll handler):
var $myDivOfAwesome = $('#awesomeDiv');
$(document).scroll(function() {
if ($myDivOfAwesome.position().top > 1337) {
// do stuff...
}
});
You should be fine.
If you still want to compare different snippets of code to determine what's faster, check out JSperf

JQuery How to make condition not to run only once.

I have a little problem with conditions and its triggering. I have 2 object in my HTML (div and img), that I am trying to constantly align by JS. By constantly I mean so that when window size changes, they realign (since one is aligned to the center - and no :), I can't center-align the second one as well, because I also need to match the size, which definitely requires JS).
I made a little function that aligns them and sets proper dimensions to it and I am triggering the function on every window.onresize event (as well as on document ready). But I found out, that it does not trigger on zoom action and besides that it would be more suitable for me not to be dependent on window.onresize.
So I thought there would be a posibility to write a condition like
if (div.width() != img.widht()) {
// do something to match it again
}
But it turned out to only run this condition on the ready event (resp. load event, since I have a picture). So my question is, if there is any way, so that the condition would be checking its state just continuosly? I know, I can probably set Interval to take care of that, but a) I guess that like 99% of all executions would be pointless and b) unless I set it to like very quick repetition, it would not even fix the div's and img's mismatch problem immediately.
Thank you very much.
You can certainly define you own custom event and execute the aligning code when it occurs, but you still need a way to fire the event at appropriate time.
That can only happen during the ordinary execution flow of the program (not an option here) or in the handler for one of the existing events: if none of those events is consistently fired when the trigger condition occurs, then you're only left with timers.
I'd be happy to be wrong on this, tho'.
Consider requestAnimationFrame as an alternative to setInterval.

how to preload more than one but not all images of a slideshow with jquery

I'd like to create a web based stop motion video player. Basically a slideshow that shows 2-4 images per second. Each image might be a maximum of 20KB. I don't want to preload all images in the slideshow as there might be thousands, however I need to preload more than just the next image in the show as this will not playback fast enough (because of the playback speed the browser needs to be loading more than one image at a time).
I've been looking at using the jQuery Cycle Plugin (http://malsup.com/jquery/cycle/) with a addSlide type function but don't know how to make it work.
Would something like this might work?
-Slideshow starts
-image is played back
-preloader will attempt to load up to the next 60 images
-playback will wait for the next image in line to completely load, but will not wait for all 59 others.
The playback / preloading order is important for this application.
You can create a function that pre-loads N images , when N images are loaded it calls itself again, How much is N ? can be 5 or 10 or you can come up with some formula to calculate N based on expected Images dimensions/Size and time duration of displaying
If all images size are almost the same , first image requested to load should finish loading first, So it wouldn't wait for all 59 others.
plus a variable 'loadedN' that holds index of last loaded image
FireBug is certainly needed to debug this App.
Playback function needs to check if the requested image index is loaded or not
I don't have the exact code in a usable way, but I can explain the framework. I have done something very similar in jQuery-- although I would say it's not so much jQuery as Javascript. Here's the basics of what I did...
Create a function that "preloads" an image. The way to do this in Javascript is simply to create an Image element, eg:
`function preloadAnImage(src) {
var i = new Image(1020, 492);
i.src = src;
}`
Create a list of images, eg. imagesToPreloadIndex = ['image1.jpg','image2.jpg'... ];
Create a function that works off this queue, eg:
function preloadNextImage() {
preloadAnImage(imagesToPreload.pop());
if (imagesToPreloadIndex.length > 0) {
setTimeout(preloadNextImage, 300);
}
}
That gives you the framework.
You'll want this synced up with the actual displaying of the images. This works fine as long as everything goes right. Then you need to decide what to do if you are getting behind in your loading... do you drop a frame or slow down your slideshow? I'm not familiar with a plugin that implements this strategy, but would be fun to implement.
I could imagine that this has to be multiprocessing. What I am thinking of is split the playback logic from the image preload logic. It works like this...
You start an initializer. Once N pictures are preloaded (you can show the dreaded "buffering" screen at this point), you call 2 functions.
Function 1 - shows an image, then starts a timer after which it is called again to show the next image. With 4 images per second, it would call itself every 250ms.
Function 2 - starts a timer. Here you can work with "expected values". You can expect that, for instance, 60 images are done processing after 15 seconds. So, after 7 seconds, you start loading the next 30 or 60 images and add those to the image array, all while the other function is still showing of the already present images.
Of course, you need a limiter on function 1, which stops playback at the Nth-1 element in order to avoid stack overflows or I/O Errors.
Don't know if this was useful, but it is how I understood the question.
Sounds problematic as you'll never be able to control how fast the client can attain the images. To use video would probably be an easier and more satisfactory result.
To make this work in js you'd have to build a buffering object which can pause and resume the playback whenever the count of preloaded images falls under/over a minimal threshold; like flash movies.

Categories

Resources