Situation: I have a tiny http server that can only handle 4 connections at any given time. When opening a web page, my web browser sends a get request for every image resource asynchronously (tries to open more than 4 connections at the same time). This causes some bad behaviour.
Initial solution: I wrote a JS function that loads the images sequentially and stores them in a dictionary
var loadedImages = {};
like so:
var img = new Image();
img.src = <img_location>;
loadedImages[<img_name>] = img;
After all the images are loaded i try to place them in various places in the DOM. The important part is that i need to place the same picture in multiple places. I do it like this:
//For all the elements that need to have the same image DO:
var img = loadedImages["<img_name>"];
$(this).html(img);
Problem: What happens is that as soon as the code puts the image in the SECOND element, the image gets removed from the FIRST element. When the image gets put in the THIRD element, it gets removed from the SECOND element. So what happens is that basically only the last element contains the image, while all the others are empty.
Question: How can I place the same image from my javascript dictionary (or any other javascript object) on multiple DOM elements?
Edit:When using something like
//For all the elements that need to have the same image DO:
var img = loadedImages["<img_name>"];
$(this).html($(img).clone());
as proposed by Tamil Vendhan and Atif Mohammed Ameenuddin, the image gets placed on all the elements and that is ok, but the browser requests the image from the server every time it comes to that line of code. So it is not really a good solution. Same goes when i use "cloneNode()"
Try using the clone method in jQuery
$(this).html($(img).clone());
Use jQuery.clone:
$(this).html($(img).clone());
Update:
Yes, browser will make the request. But it will use the cached image if it is already loaded.
Check your debugger's net panel to confirm this. You will see (from cache) under Size column.
Related
I'm after insight into how to avoid unwanted behaviour in loading images using promises. My real-world use is quite complex (a large threejs application) so I've boiled down my issue below to an easier to explain example.
I have a gallery div which shows an image. There are a group of thumbnails which the user can click which loads the image associated with that thumbnail and once loaded shows it in the gallery div (in the real application a promise is used here as we must load the image, then once loaded create a texture from it before passing that texture back to apply to a plane).
The issue I'm having is that if the user clicks multiple thumbnails quickly they are applied to the gallery div in the order they load which could mean that a user could click a large image to load, then a small image resulting in the small image being shown but then being overwritten by the larger image (even though it wasn't the last selected due to it being larger and therefore taking longer to load).
I'm at a loss on how to solve this issue elegantly and am hoping someone might be able to offer a suggestion on how other software/programs deal with this issue. Is it as simple as having a redundancy system to see if an image is still selected once it loads and if it isn't then abort?
There are a number of different algorithms for dealing with this issue and part of the selection process depends upon exactly what behavior you want. Based on your description it sounds like you want an image to be shown as soon as it is loaded, but to never overwrite an image that came after it and has already been displayed. That means that if images are requested in the order 1,2,3, but arrive in the order 2,1,3, then you will show image 2, then 3 and never show 1.
Assuming that is the desired algorithm, then a fairly simple way of doing things is to just assign each request a sequence number and just keep track of the last sequence number that you showed. Whenever any image finishes loading, you check if it's sequence number of above the last sequence displayed. If not, you don't show it because it's an old image that was surpassed by a newer image. If so, then you show it and update the lastShownSequence number to the sequence number of this image. This type of algorithm requires two lasting variables to keep track of the lastShownSequence number and the nextSequenceNumber to be assigned.
Here's a sample code implementation:
var lastShownImage = 0;
var nextSequenceNumber = 1;
// url is image url
// elem is image element in the page to replace with newly loaded image element
function loadImage(url, elem) {
let imageSequenceNumber = nextSequenceNumber++;
let img = new Image();
img.onload = function() {
// image loaded now
// see if we should display it or not
if (imageSequenceNumber > lastShownImage) {
// hide current image so there's never any flashing of two images
elem.style.display = "none";
// record the sequence number we are showing
lastShownImage = imageSequenceNumber;
// insert new image
let parent = elem.parentNode;
parent.insertBefore(img, elem);
// remove previous image
parent.removeChild(elem);
}
};
img.src = url;
}
If you don't want lastShownImage or sequenceNumber to be open scoped like this, then they can be encapsulated either in an IIFE or in an instance of a class that you create, but since I don't see how exactly you would use this from your code or see if you needed a more generalized multi-instance implementation, I didn't add any extra complication for that.
Currently I have thumbnails, when I click the them a large version of the pic appears in the div directly to the right of the thumbnails. What I now want to be able to do is click the larger pic in the div and then trigger a lightbox that shows an even larger version of the pic.
I'm not quite sure how to do what I'm thinking is the solution so I'm gonna try and explain. I'm thinking that when i click the div to trigger the lightbox I want to take the src of the pic being click and then somehow redirect it to another src in my images folder.
Example:
When I click image in div I get the src of pic lets say that the source is:
src="redpic.jpg"
Then lets say in my images folder I have a larger version of the pic selected with the source:
src="redpic_large.jpg"
Would it be possible to manipulate the the src of an first image img src="redpic.jpg" by adding _large to the end and then appending this to my
lightbox???
Everytime I try to do things with my images I always seem to be running into problems.
say the src="redpic.jpg" when I check in the console the src goes to something like //139.0.0.1:56328/img/dotted.jpg and it seems to cause me a lot of problems
Sure, you can get the source of the image like this :
$("img").on("click", function(){
var source = $(this).attr("src");
});
This will give you the complete path (redpic.jpg).
You can use split() to get an array of both parts (the name and the extension)
var parts = source.split(".");
Now, all that you have to do is append the "_large" to the first part of the source, combine them back together and set your other image's source as the newly assembled one.
parts[0] += "_large";
var newSource = parts.join(".");
You pass the period . to the join function so that it puts a period in betwen your elements, instead of the default comma , .
All that's left to do is to use newSource as the source attribute of your other image.
$(".other-image").attr("src", newSource);
I would like to know if it is possible to unload an image from an HTML page and free its memory occupation with some Javascript instructions. Say an image is already displayed on the screen. Say I need to unload it to save memory (reason is not relevant here). Can I do it with Javascript?
The comments on your question are correct, you can remove it from the DOM, but the browser will clear it from memory when it decides it's good and ready.
To clear it from the DOM, you would do something like this:
var badImage = document.querySelector("img#idOfImage");
//or "img[href='nameofimagefile.jpeg']"
//whatever you need to do to get the right element
//then, remove it:
badImage.parentElement.removeChild(badImage);
$('#myDiv').remove();
or
function removeElement(divNum) {
var d = document.getElementById('myDiv');
var olddiv = document.getElementById(divNum);
d.removeChild(olddiv);
}
Would remove it from the DOM however it won't free up any memory, or bandwidth or http requests...so performance wise it won't make much of a difference (not taking rendering into account).
However I believe if the image is removed from the DOM the memory it uses will eventually be managed and removed by the browser (garbage collection).
So in short no I don't think there is a specific way to remove it from memory because that is a browser-level concern..
You can free memory of an img element by assigning the src attribute to a 1x1 pixel before removing it.
const imgElement = document.querySelector(selector);
imgElement.setAttribute('src', '/images/pixel.gif');
imgElement.parentElement.removeChild(imgElement);
I have some images from another source that need to refresh from their offsite source every 30 seconds. I would like to use JavaScript to accomplish this so as to avoid an entire page reload.
Presently I've attempted something similar to this question: "reloading a page after every 10 sec in rails 3.1"
(This is a Rails application, but I probably don't need a Rails specific answer in this case.)
Notwithstanding, I am ending up with no appreciable result when I add a div around the link + image nor when I add a div to the image itself. I have attempted both solutions in this example by creating a element-reload.js.
The first solution that's marked as the answer simply reloads the page with nearly all of the page elements absent. The second solution makes the image that I'm trying to refresh actually disappear upon first refresh when I surround the link + image with a div, but when I place the id upon which it's acting on the actual image tag, it yields nothing.
I'm sure I'm missing something rather simple since JS is not a strong suit for me at the moment.
Finally, I do have a number of sources to refresh and would like to see an example of performing this for a class vs an id if possible, but having more granular control over each one may be best in the end for varied times for the refreshes.
If you're up for jQuery, this can be done quite easily:
$(function() {
setInterval(function() {
$('img').each(function() {
$this = $(this);
$this.attr('src', $this.getAttribute('src') + '?timestamp=' + new Date().getTime());
console.log($this.prop('src'));
});
}, 30 * 1000);
});
In order to prevent browser caching, you have to fool the browser and load the image with a GET request variable timestamp. It doesn't matter what the parameter is, but the image will load brand-new and not from cache because the URL changes.
jQuery is famous for its use of CSS-like selectors.
Replace $('img') with one of these:
$('img.yourClassName'); // Class
$('#your_id, #another_id, ...'); // ID(s). Omit the comma for a single id
$('img[id^="common_base_id"]'); // Selects all images with an id that starts with "common_base_id".
There's also the :not() selector, which can filter your results:
$('img.yourClassName:not(.do-not-reload)');
$('img.yourClassName:not([src="img/spinner-skip.gif"])');
we're using js to do png replacement, and we also have ajax updates on some of these elements. when the page fragment gets updated, the png fix gets lost, since the png fix traverses the dom and replaces png bg images when the document loads. is there a way to render the png replacement when the ajax update takes place, rather than only on document.onload? we're using jquery.
Are you using behavior?
If you are using iepngfix.htc, you might try setting the behavior inline
var myEl = document.getElementById('inbound-ajax-element');
myEl.style.behavior = 'url(iepngfix.htc)';
http://www.twinhelix.com/css/iepngfix/demo/
You should take a look here jQuery IE PNG Fix Plugin
jQuery(function($) {
$("img[#src$=png], #image-one, #image-two").pngfix();
});
You should run this on the images you just loaded.
http://abcoder.com/javascript/ie6-png-alpha-transparency-fix-for-dynamically-loaded-images-via-ajax/
The link above provides an example that attaches the PNG fix to the image's onload event, for example:
new_img.onload = function(){
ti.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + timg_src + "', sizingMethod='scale')";
ti.setAttribute('src', 'blank.gif');}
The reason it gets lost is that the pngfix is not something that is applied continually, it is applied on page load to the items present, and so if you change one of them or create new png's the pngfix will not be applied.
So in your javascript where you create the image, you need to follow it up by applying the pngfix to that item.
How that javascript will look is dependent on what kind of pngfix you're using. There are other answers here which give examples of what to apply after you add the new image.