I want to add an image by Javascript, then calculating the html element width as
window.onload=function(){
document.getElementById('x').addEventListener('click', function(e){
var el = document.getElementById('xx');
el.innerHTML = '<img src="img.jpg" />';
var width = el.offsetWidth;
.....
}, false);
}
but since JavaScript conduct all processes simultaneously, I will get the width of the element before loading the image. How can I make sure that the image has been loaded into the content; then calculating the element width?
UPDATE: Thanks for the answers, but I think there is a misunderstanding. img src="img.jpg" /> does not exist in the DOM document. It will be added later by Javascript. Then, when trying to catch the element by Id, it is not there probably.
You can give the img an ID and do the following :-
var heavyImage = document.getElementById("my-img");//assuming your img ID is my-img
heavyImage.onload = function(){
//your code after image is fully loaded
}
window.onload=function(){
document.getElementById('x').addEventListener('click', function(e){
var el = document.getElementById('xx');
var img = new Image();//dynamically create image
img.src = "img.jpg";//set the src
img.alt = "alt";
el.appendChild(img);//append the image to the el
img.onload = function(){
var width = el.offsetWidth;
}
}, false);
}
This is untested, but if you add the image to the DOM, set an onload/load event-handler and then assign the src of the image, the event-handling should fire (once it's loaded) and allow you to find the width.
This is imperfect, though, since if the image is loaded from the browser's cache the onload/load event may not fire at all (particularly in Chromium/Chrome, I believe, though this is from memory of a bug that may, or may not, have since been fixed).
For the chrome bug you can use the following:-
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';//create a blank source
var tImg = document.getElementById("my-img");//get the image
var origSrc = tImg.src;//get the original src
tImg.src = BLANK;//change the img src to blank.
tImg.src = origSrc;//Change it back to original src. This will lead the chrome to load the image again.
tImg.onload= function(){
//your code after the image load
}
You can use a library called PreloadJS or you can try something like this:
//Somewhere in your document loading:
loadImage(yourImage, callbackOnComplete);
function loadImage(image, callbackOnComplete){
var self = this;
if(!image.complete)
window.content.setTimeout(
function() { self.loadImage(image, callbackOnComplete)}
,1000);
else callbackOnComplete();
}
I did this when I worked with images base64 which delay on loading.
Related
Please answer this question, as I am struggling a lot with it.
I am trying to change image source on mouse over. I am able to do it, but image is not displaying on page.
I am trying to change image source to cross domain URL. I can see that in DOM image source is changing but on page its not.
I have tried all solutions mentioned in LINK, but none of them is working.
Please let me solution to problem.
NOTE:
I can see in network tab image is taking some time to download (about 1 sec).
It is an intermediate issue, sometime image is loading and sometimes its not
CODE:
document.getElementsByTagName('img')[0].addEventListener('mouseover', function()
{
document.getElementsByTagName('img')[0].setAttribute('src', 'url/of/the/image');
});
have you tried loading images before everything else?
function initImages(){
var imC = 0;
var imN = 0;
for ( var i in Images ) imN++;
for(var i in Images){
var t=Images[i];
Images[i]=new Image();
Images[i].src=t;
Images[i].onload = function (){
imC++;
if(imC == imN){
console.log("Load Completed");
preloaded = 1;
}
}
}
}
and
var Images = {
one image: "path/to/1.png",
....
}
then
if( preloaded == 1 ){
start_your_page();
}
Here the code that will remove the img tag and replace it with a new one:
document.getElementsByTagName('img')[0].addEventListener('mouseover', function() {
var parent = document.getElementsByTagName('img')[0].parentElement;
parent.removeChild(document.getElementsByTagName('img')[0]);
var new_img = document.createElement("img");
new_img.src = "https://upload.wikimedia.org/wikipedia/commons/6/69/600x400_kastra.jpg";
parent.appendChild(new_img);
});
<img src="https://www.w3schools.com/w3images/fjords.jpg">
I resolved the issue using code:
function displayImage() {
let image = new image();
image.src="source/of/image/returned/from/service";
image.addEventListener('load', function () {
document.getElementsByTagName('img')[0].src = image.src;
},false);
}
Here in code, I am attaching load event to image, source of image will be changed after image is loaded.
I wanted to implement a swapImage on my site that would swap one image on mouseover, and another image on mouseout. Essentially, with the solution I found I could also probably swap different images for mousedown and mouseup even.
I have this happening in 8 different nested tabs, all of which are on the same page.
The javascript looks like this:
<script type="text/javascript">
function swapImageFiat(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function swapImageHarley(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function swapImageHotWheels(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function swapImageVoltron(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function swapImageBenchmade(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function swapImageCrew(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function swapImageReuters(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function swapImageMarsVolta(imgID, imgSrc) {
var theImage = document.getElementById(imgID)
theImage.src = imgSrc;
}
function preLoadImages() {
for(var i = 0; i < arguments.length; i++) {
var theImage = new Image();
theImage.src = arguments[i];
}
}
</script>
And the inline code for each image would be essentially this:
<img class="diagram" src="img/fiat.gif" id="imgToSwapFiat" alt="Diagram" data-title="Fiat Diagram" onClick="swapImageFiat('imgToSwapFiat', 'img/fiat-animated.gif')" onmouseout="swapImageFiat('imgToSwapFiat', 'fiat.gif')" height="189" width="358" />
I would like to be able to use less IDs, less of the same repetitive script, and shorter inline code.
But I also want the flexibility of being able to just change the images and their IDs, rather than fussing with JQuery or other script. This is why I'm using getElementById.
Is there a more efficient way for me to write that JavaScript, and/or Inline code?
Also
Is there a way for the image to swap back to the original after the animation stops playing, rather than on mouse-out?
Use this instead of the element ID since your function eventually need the actual element object.
The script example:
function swapImageFiat(imgEle, imgSrc) {
imgEle.src = imgSrc;
}
The image HTML example:
<img src="initial.jpg" onclick="swapImageFiat(this, 'clicked.jpg')" onmouseover="swapImageFiat(this, 'hovered.jpg')" onmouseout="swapImageFiat(this, 'left.jpg')" />
Yeah, sure there is. As Jan mentions - all of your functions are identical. There's no need to duplicate them all. Also, you can remove the inline event-handler code from your html, simply attaching the mouseover/mouseout or mousedown/mouseup.
Simply add a new attribute to each image that you wish to have the effect for, then runs some js on page-load to attach the handler.
Here, I've just used (and checked for the existance of) custom attributes. If the image has them, I attach handlers. If not, it's no different to any other normal image. This should be nice an re-usable and little effort to use.
As for resetting the image once the animated gif has played, I'd probably look at Jan's first suggestion. A slight modification on the idea would be to make the last frame transparent, then simply position the animated image over (z-index higher) the static one.
When it's done, you'll see the original image again. You'll have to decide on a system for refreshing these images, should they need to be re-played. I'm not sure, perhaps setting their src to '', before setting it back to the animated.gif would cause the animation to play from the start again - you'd have to check if to decided to attempt such an approach.
<!DOCTYPE html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e);}
function mInit()
{
var imgList = document.getElementsByTagName('img');
var i, n = imgList.length;
for (i=0; i<n; i++)
{
if (imgList[i].hasAttribute('img2'))
imgList[i].addEventListener('click', imgClick, false);
if (imgList[i].hasAttribute('img3'))
imgList[i].addEventListener('mouseover', imgHover, false);
if (imgList[i].hasAttribute('img4'))
imgList[i].addEventListener('mouseout', imgOut, false);
}
}
// because these function are attached with addEventListener, the 'this'
// keyword refers to the image element itself. No need for IDs..
function imgClick()
{
this.src = this.getAttribute('img2');
}
function imgHover()
{
this.src = this.getAttribute('img3');
}
function imgOut()
{
this.src = this.getAttribute('img4');
}
window.addEventListener('load', mInit, false);
</script>
<style>
</style>
</head>
<body>
<img src='img/gladiators.png'> <!-- this image won't be touched, as it doesn't have img1, img2 or img3 attributes -->
<img src='img/opera.svg' img2='img/chromeEyes.svg' img3='img/rss16.png' img4='img/girl2.png'/>
</body>
</html>
Jay has a good suggestion for your functions, which all do the same thing. If you remove the names from your functions you'll see they are otherwise identical. And the function name makes no difference at all, in this case it's just the arguments you pass to the function that matters.
Is there a way for the image to swap back to the original after the
animation stops playing, rather than on mouse-out?
You could make the gifs non-looping and make the last frame of the animation the same as the original image. AFAIK there's no way to detect which frame an animated gif is on through Javascript.
If you really want it to return to the original image, you could animate the image completely through Javascript: Write a function that preloads all the images (or a spritemap) and then load them frame by frame.
As I hover a small img, I read it's larger image attribute, and create that image to display.
The problem is that I want to set Timeout before to display the image.
And while waiting for that timeout, we suppose to already have set an src to make it load early.
For some reason it never works in IE. ie, it only triggers the load even on the second time I hover the small image. I've no idea what has gone wrong with it, I had very similar animation on the other page it has been working just fine with a timeout.
Any ideas?..
$(document).ready(function(){
var nn_pp_trail=0;
$('div.nn_pp_in').hover(function(){
var limg=$(this).children('img').attr('limg');
var img=new Image();
//img.src=limg;
img.className='nn_pp_z';
img.src=limg;
var a=(function(img,par,limg){
return function(){
nn_pp_trail=window.setTimeout(showtrail,50);
$(img).one('load',(function(par){ //.attr('src',limg).
return function(){
// alert('loaded');
window.clearTimeout(nn_pp_trail);
hidetrail();
var width=this.width;
var height=this.height;
var coef=width/313;
var newHeight=height/coef;
var newHpeak=newHeight*1.7;
var nn=par.parents('.tata_psychopata').nextAll('.nn_wrap').first();
var pheight=nn.height();
var ptop=nn.position().top-2+pheight/2-1;
var pleft=nn.position().left+90+157-1;
$(this).appendTo(nn).css('left',pleft+'px').css('top',ptop+'px')
.animate({opacity:0.6},0)
.animate({opacity:1,top:'-='+newHpeak/2+'px',height:'+='+(newHpeak)+'px',left:'-=10px',width:'+=20px'},130,(function(newHeight,newHpeak){
return function(){
$(this).animate({left:'-='+(156-10)+'px',width:'+='+(313-20)+'px',height:newHeight+'px',top:'+='+(newHpeak-newHeight)/2+'px'},200,function(){});
}
})(newHeight,newHpeak)
);
}
})(par)
).each(function(){
if(this.complete || this.readyState == 4 || this.readyState == "complete" || (jQuery.browser.msie && parseInt(jQuery.browser.version) <=6))
$(this).trigger("load");}); ;
}
})(img,$(this),limg);
window.setTimeout(a,20); //if I set 0 - it loads all the time.
//if I set more than 0 timeout
//the load triggers only on the 2nd time I hover.
$(this).data('img',$(img));
},function(){
});
});
img.src=limg;
This was the problem, in IE we need not to set src as we create an image object, but first attach load event to it, and only then set attr src, and then trigger complete with an each, eg:
img.one(load, function(){}).attr('src','i.png').each(function(){ /*loaded? then it's complete*/ });
Hope someone learn on my mistakes :-)
Thank you, this helped me a lot. I had a similar situation.
As you said: First the "load"-event, then the "src" for IE.
// This was not working in IE (all other Browsers yes)
var image = new Image();
image.src = "/img/mypic.jpg";
$(image).load(function() {
//pic is loaded: now display it
});
// This was working well also in IE
var image = new Image();
imagSrc = "/img/mypic.jpg";
$(image).load(function() {
//pic is loaded: now resize and display
}).attr('src',imageSrc);
It's easy to keep javascript waiting for some images to load if those are classic HTML images.
But I can't figure how to do the same if the image is loaded as a CSS backuground-image!
Is it possible?
The jQuery .load() method doesn't seem to apply.. and I'm short of ideas
It looks for elements with src attribute or backgroundImage css property and calls an action function when theirs images loaded.
/**
* Load and wait for loading images.
*/
function loadImages(images, action){
var loaded_images = 0;
var bad_tags = 0;
$(images).each(function() {
//alert($(this).get(0).tagName+" "+$(this).attr("id")+" "+$(this).css("display"));
var image = new Image();
var src = $(this).attr("src");
var backgroundImage = $(this).css("backgroundImage");
// Search for css background style
if(src == undefined && backgroundImage != "none"){
var pattern = /url\("{0,1}([^"]*)"{0,1}\)/;
src = pattern.exec(backgroundImage)[1];
}else{
bad_tags++;
}
// Load images
$(image).load(function() {
loaded_images++;
if(loaded_images == ($(images).length - bad_tags))
action();
})
.attr("src", src);
});
}
One alternate approach would be to fetch the image data via AJAX as a base64 encoded png and apply it to the element's background-image property.
For example:
$.get('/getmyimage', function(data) {
// data contains base64 encoded image
// for ex: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==
$('#yourElement').css('background-image', 'url("' + data + '")');
});
You will also need a server side script that reads the image, converts it into base64 encoded png (and cache it maybe) and return the same.
Try this one...
Its a jQuery-Plugin which gives you control to wait for images to be loaded
Project-Home
Thread # SO
Official way to ask jQuery wait for all images to load before executing something
Answer # SO
(ShortLink)
this is untested code but try this:
$(document).ready(
function()
{
var imgSrc = $('theTargerElement').css('background-image');
var imgTag = $('<img>').attr('src',imgSrc).appendTo( 'body' );
}
);
$(document)
.load(
function()
{
// do stuff
}
);
I'm trying to create a very simple gallery using javascript. There are thumbnails, and when they're clicked the big image's source gets updated. Everything works fine, except when I try it in IE the images' size stays the same as the inital image's size was. Let's say initial image is 200x200 and I click on a thumbnail of a 100x100 image, the image is displayed but it is streched to 200x200. I don't set any width or height values, so I guess the browser should use image's normal size, and so does for example FF.
here's some code:
function showBigImage(link)
{
var source = link.getAttribute("href");
var bigImage = document.getElementById("bigImage");
bigImage.setAttribute("src", source);
return false; /* prevent normal behaviour of <a> element when clicked */
}
and html looks like this:
<ul id="gallery">
<li>
<a href="images/gallery/1.jpg">
<img src="images/gallery/1thumb.jpg">
</a>
</li>
(more <li> elements ...)
</ul>
the big image is created dynamically:
function createBigImage()
{
var bigImage = document.createElement("img");
bigImage.setAttribute("id", "bigImage");
bigImage.setAttribute("src", "images/gallery/1.jpg");
var gal = document.getElementById("gallery");
var gal_parent = gal.parentNode;
gal_parent.insertBefore(bigImage, gal);
}
There's also some code setting the onclick events on the links, but I don't think it's relevant in this situaltion. As I said the problem is only with IE. Thanks in advance!
Sounds like IE is computing the width and height attributes for #bigImage when it is created and then not updating them when the src is changed. The other browsers are probably noting that they had to compute the image dimensions themselves so they recompute them when the src is changed. Both approaches are reasonable enough.
Do you know the proper size of the image inside showBigImage()? If you do, then set the width and height attributes explicitly when you change the src:
function showBigImage(link) {
var source = link.getAttribute("href");
var bigImage = document.getElementById("bigImage");
bigImage.setAttribute("src", source);
bigImage.setAttribute("width", the_proper_width);
bigImage.setAttribute("height", the_proper_height);
return false;
}
If you don't know the new dimensions then change showBigImage() to delete #bigImage and create a new one:
function createBigImage(src) {
var bigImage = document.createElement("img");
bigImage.setAttribute("id", "bigImage");
bigImage.setAttribute("src", src || "images/gallery/1.jpg");
var gal = document.getElementById("gallery");
gal.parentNode.insertBefore(bigImage, gal);
}
function showBigImage(link) {
var bigImage = document.getElementById("bigImage");
if(bigImage)
bigImage.parentNode.removeChild(bigImage);
createBigImage(link.getAttribute("href"););
return false;
}