I have a script that loops through a series of JSON objects that represent images, the loop loads an image and once it has been loaded it appends it to an element on my website/application.
The images are in the correct order in the JSON however they are appearing in different orders depending on the images that load the quickest because they are appended first. I want to make sure that whatever order the images load, they are always in the correct order (The order that the loop denotes).
The method I'm hoping to end up with allow me to access the style of the wrapping anchor before the image is loaded to show a loading icon also.
Here's the part of the script that I am talking about:
$.each(project.images, function (index, image){
var image_src = '<?= IMAGE_PATH ?>library/preview/'+ image.file_name;
var image_markup = $('<img class="new-image" />').attr('src', image_src)
.load(function(){
if (this.complete)
{
var anchor_markup = $('<a href="javascript:void(0)" class="image-anchor" data-image-index="'+ index +'" id="image-index-'+ index +'">');
$(anchor_markup).append(image_markup);
globals.markup.image_slider.append(anchor_markup);
$('.new-image').fadeIn(200).removeClass("new-image");
}
});
});
The example can also be seen at http://www.staging.codebycoady.com/work
If you want them in the correct order just append them without waiting for them to load, hide them and then in the onload callback toggle them visible.
If you want images to appear in correct order then you should listen on load event of images and once an image is loaded you mark it (in some array/object) it's loaded. And then you show all images that are marked as loaded from the beginning (i.e. when 1,2,3 are loaded and 4 is not, then you set display block on 1,2,3, even if 5 was just loaded).
Related
The purpose - an image gallery.
As opposed to creating each gallery-image inside a 'gallery' div, like below:
<div id="html_collection">
<img src="picture_1">
<img src="picture_2">
<img src="picture_3">
</div>
I'm storing them inside a javascript array object - for simplicity, like below:
var js_collection = [
{
'gallery' : 'picture_1.jpg',
},
{
'gallery' : 'picture_2.jpg',
},
{
'gallery' : 'picture_3.jpg'
}
From there I will create an empty <div id="carousel"></div> inside the HTML file and append each 'gallery' image into it dynamically through JS, by clicking 'next' and 'previous' buttons. These buttons will cycle through the js_collection array.
For example:
function showCarousel(x) {
var slide = document.createElement('img')
slide.src = js_collection[x].gallery
var output = carousel.appendChild(slide)
}
The concern - I feel like redrawing the img node and fetching the current img from the JS collection everytime we hit next or previous.. may be dirty in a way. I know the same result can be achieved by showing and hiding imgs in the first 'html_collection' option - but I prefer the flexibility of the second implementation. Can I get away with it, or is this just wrong?
EDIT: I went with Leeish's suggestion and created a div like so,
<div id='carousel'>
<img id='carousel_slide' src='nameOfFirstSlideHere.jpg'>
</div>
From there, I dynamically switched the img 'SRC' rather in redraw the 'IMG' itself each time. Cheers
My concern about your script approach is that the user may experience a noticeable delay upon every click of the next/previous button while waiting for the next image to be retrieved, at least as your script is currently written. On the other hand, if the number of images is large, there would be a significant up-front delay in the HTML version as you waited for the entire group of images to load.
I think the best solution would be one that preloaded at least enough images to make sure that when the user clicks the button, the next or previous images is (at least usually) already loaded so the only delay is the tiny one to append the content. If your images are small, you might consider using CSS sprites to load several images at once and cut down on the number of HTTP requests, though this would require a bit more coding.
The other option, which is simpler to code, but doesn't reduce the number of image requests, would be have your showCarousel method create an image object, load the src, and append to the carousel for image x + 1, but hide that image x + 1 initially and show image x. That way, assuming the user spent a few seconds looking at each image, the user should see image x essentially immediately, while x + 1 gets ready just in case the user asks for it.
Here is my scenario:
I am having a page with pagination and enhanced with infinite-scroll
The page has a list of items, where each item looks like this in smarty
<div id="link-{index}">
<div align="left"><a href={$url}></div><div alight="right"><img src="" id="{$url}"></div>
</div> <script>imager({$url});</script>
I am using a service to dynamically grab image src for a given URL and append it to the image by defining imager(x){ document.getElementById(x).src = service(x).image; }
Now this works, as in shows correct images along side URLs as long as normal pagination is used. Doesn't work for page 2 onwards with infinite scroll as it uses JQuery and that parses out the imager JS script for each item.
I am stuck with trying to create a callback function for infinite scroll that will do what imager does but after a page is loaded but I am unable to get it to work.
Any tips will be appreciated. Thank you
In the callback for when a new page is loaded, you can do something like this:
$('img:not([src])').each(function() {
$(this).attr('src', service($(this).attr('id')).image);
});
This assumes that the only images without a source are those that were just loaded by the infinite scroller. If the widget provides parameters to the callback that tells it which parts of the DOM were just paged in, you may be able to use that to narrow down further; the second argument to a jQuery selector is the context to search.
My page has a list of links that each loads new pages with ajax. These new pages contains a gallery of images and a main image.
My objective is to get the source-url from the main image to show as a thumbnail on the corresponding link on the link page.
I have no idea how to go about this. If someone could point me in the right direction and maybe give me some code to follow I'd be grateful.
You can load an external page with jQuery.get.
$.get('my_external_page.html', function(data) {
// data is the pages contents.
});
Then shove that into a div
$.get('my_external_page.html', function(data) {
// data is the pages contents.
var haystack = $('<div>').html(data);
var needle = haystack.find('.image-we-want');
var imageSrc = needle.attr('src');
});
That's a start. Of course it assumes you can use jquery, and the element you're searching for has a class or ID.
Got it working. Probably not the smartest way to do it, but it works.
I have a page full of links (). I also have an empty div at the bottom of called .
The code loads an icon to these links. The links points to a new pages containing several images. The icons are minified versions of the pages' standard images.
function iconPicHandler(){
var aTags = $('#linkpage a');
for(var i = 0; i < aTags.length; i++){
$('#invisible').load('page3.html #standardImage',function(aLink){
return function(){
$('<img src="'+ $('#standardImage').attr("href") +'" />')
.prependTo(aLink);
}
}
($(atags[i])));
}
$('#invisible').hide();
}
So the first thing I do is get all the links in the linkpage. I put the rest of the code into a for-loop, so I can do the same for all the links.
Then I load " #standardImage" from page3.html into "#invisible". #standardImage" is an empty div containing an url to a minified version of page3's standardImage. The url is held as the div's href attribute.
Then came the tricky part. I'm not sure what I did here. But as a callback function I made a function, that takes one argument, which is specified at the end($(atags[i])). This function then returns a new function! This enabled me to both have access to the atags(links) and the newly loaded $('#standardImage').
Inside the function I extract the href from $('#standardImage') and use it as a src for an image prepended to the link.
At the end, outside the for-loop, I hide $('#invisible').
As previously stated this is not a very smart way of doing this, but it gets the job done. Who knows, maybe it can help the next beginner walking by who just happen to have a similar problem.
I have a callback from an ajax call that returns a bunch of image links. I store this array in a variable (called fullPeopleList) and then on the click of a link, i show all of the images in the DOM. something like this:
function ShowAllPeople() {
var html = [];
$.each(fullPeopleList, function (i, person) {
html.push("<img title='" + person.Name + "' height='45' width='45' src='" + person.SafePicLink + "' /> ");
});
html.push(" <a id='showTop' href=''>Show Less ...");
$("#people").html(html.join(""));
}
the issue is that when i click on the list to show all of the people it takes a while to actually load all of the pictures so it shows the ugly browser empty placeholder box for each image until the images each load one by one
Is there anyway i can load these images in the background when i get the initial list so when i click on the "Show" link they are show up quickly ?
How about wrapping the area they shown in in a div then visibility: hidden initially then use the link to change it to visibilty: visible it? (preferably thropugh add/removing a class). Using hidden means the space still gets taken up as opposed to none which would not do that. You would still need to create areas of the right size though as you can't reserve space if you don't know about the image size (yet).
Why not just do the DOM manipulation you're doing now when the image links are initially obtained? Just pop them into a hidden element until the user decides to view them all, at which point ShowAllPeople() would simply make the element visible.
I believe that the "classic" method is to us abs positioning to "display" the image outside the viewport. Eg at -10000 0 location.
You can also use an img elements "onload" event. See SO Q
You should also investigate to ensure that there is no slowdown from your image server. I recommend that you store the images on Amazon S3. I do and they are both very fast and very cheap.
Finally, you should re-examine your User Experience. Eg show some animations while the images are loading. Or display the images using a gallery or carousel. The advantage is that if the user will only see one or two images at a time, it will seem faster. -- Since you can then be pre-loading the additional images in the background until the user (later) presses the Next button.
I'm working on a little image gallery, where you'd roll over a small thumbnail, the larger image would display over it. Clicking on the image would load a full size version in an overlay.
http://shopcoobie.server303.com/shop/
The issue is with the larger image, the rollovers are working fine, but the script I have updates the href which points to the full size image only seems to work the first time I click the image.
$$('.thumbs img').each(function(s) {
$(s).observe('mouseover', function(e) {
var el = e.target;
var thumb = $(el).src;
var large = $(el).alt;
$(el).up(3).down(1).href = large;
$(el).up(3).down(2).src = thumb;
console.log((el).up(3).down(1).href);
console.log(thumb);
});
});
The console outputs the proper image reference, so it seems this should work (and partially does), Im just not sure why it only works once.
Thanks
Rich
I think the lightview plugin builds up its list of images first, then you change the src dynamically, and it doesn't update. So try adding a call to Lightview.updateViews(); at the end of the mouseover handler above.
From Lightview:
Lightview.updateViews(): Force a reset of all Lightview
elements on the page. Most of the time
you won't need to do this since
Lightview will pick up on newly
inserted elements automatically. After
updating existing elements it might be
required to call this function.
So yours is a case where it doesn't automatically pick up the change.