JS: access image height after pulling it from an array - javascript

I've populated an array of images as seen here
$($target + " img").each(function() {
images.push(this);
});
I then want to access the first image in this array, specifically it's height
this.begin = function() {
var first = images[0];
};
However, when I try to access first.height and/or first.clientHeight, it's 0.
When I console.log(first); I get: <img src="img/1.jpg" class="sluider-img">.
When I console.log(images) I get: [img.sluider-img, img.sluider-img, img.sluider-img, img.sluider-img].
I can see that the target has a height / clientHeight by looking through the array seen in the above line.
Any reason I can't access the height of this element when I fetch it from the array, however I can see it while it's in the array?
I'm trying to access the height as follows
this.begin = function() {
var first = images[0];
console.log(first.clientHeight);
};
If so, how? Cheers guys.
EDIT:
When I console.log images array:
... className: "sluider-img"clientHeight: 647clientLeft: 0clientTop: 0clientWidth: 1478
... // repeat for each image element
When I console.log images[0]:
<img src="img/1.jpg" class="sluider-img">
When I do the following:
images.forEach(function(image) {
console.log(image);
});
>>
<img src="img/1.jpg" class="sluider-img">
<img src="img/2.jpg" class="sluider-img">
<img src="img/3.jpg" class="sluider-img">
<img src="img/4.jpg" class="sluider-img">
When I do the following:
images.forEach(function(image) {
console.log(image);
});
console.log(images); // this is new?
>>
sluider.js:37 img.sluider-img
sluider.js:37 img.sluider-img
sluider.js:37 img.sluider-img
sluider.js:37 img.sluider-img (it gets the image classes)
My full code
images = [];
prepare_image = function(image) {
var img = document.createElement("img");
img.setAttribute("src", image);
img.setAttribute("class", "sluider-img");
element.appendChild(img);
};
this.initialize = function(settings) {
/* creates the images and adds them into the
sluider container */
settings.images.forEach(function(image) {
this.prepare_image(image);
});
$(".sluider-img").each(function() {
images.push(this);
});
};
this.begin = function() {
/* at this point I need to get the height
of the tallest image so I can base the
container off of that. */
console.log(images);
};
And
var sluider = $($target).sluider().data($plugin);
sluider.initialize(
{
title: "TITLE",
target: $target,
images: [
"img/1.jpg",
"img/2.jpg",
"img/3.jpg",
"img/4.jpg"
]
}
);
sluider.begin();

How about checking if image was loaded?
var first = images[0];
if(first.complete){
console.log(first.height);
}else{
first.onload=function(){console.log(first.height);}
}

I do not know the EXACT scenario, but here is my answer based on understanding.
var images = [];
$.each($('.sluider-img'), function(i,d){
images.push(d);
});
var first = images[0];
var height = first.clientHeight;
alert(height);
See it working here
Basically, what you are doing is right, it is just that maybe you are not getting the value itself because of the way you are accessing the array and the value that you need (maybe because of the function that you created or you are not calling function begin)

I tried to do the same and i obtain some interesting results:
var images = [];
$('.sluider-img img').each(function(){
images.push(this)
});
console.log(images[0]);
console.log(images[0].clientHeight + " " + $(images[0]).height());
By executing the same code 20 times on Chrome I obtain, on the same image, sometimes:
0 0 (wrong)
others:
220 220 (correct heights)
Images are loaded and the code results are correct or wrong in random order.
Unfortunately I can't explain the source of this problem, but probably is the source of your frustration..
(sorry, I meant to comment but I can't because of low reputation)

Related

How to change image source on hover using javascript, but applies to each individual photo

I would like to change the image source of each image when it is hovered. I will have the original url that exists before the hover (represented by yes.png), and the new url that exists after the hover (represented by yes2.png). The whole point is that the new url is the same as the original except a 2 is added to it on hover. And I would like this done in javascript. I'm new at javascript, but how do I add onto this?
The whole thing that makes this different is that the source of the image is different for each image, yet it works for every image.
var url = getElementsByClassName ('card-img-top').src
var newImg = url+2
You can do this relatively easily. You can find where .png is in the string and insert a 2 before it on mouseenter and remove the 2 on mouseout.
I'm not sure if you just want the image that is being hovered over to change or all images so I'll include an example of how to do both. First and probably what you are looking for I'll change only the image that is being hovered over:
const imgs = document.getElementsByTagName('img');
[...imgs].forEach(img => {
img.addEventListener('mouseenter', () => {
const newSrc = img.src.slice(0, img.src.indexOf('.png')) + 2 + img.src.slice(img.src.indexOf('.png'));
console.log(newSrc);
img.src = newSrc;
})
img.addEventListener('mouseout', () => {
const newSrc = img.src.slice(0, img.src.indexOf('.png') - 1) + img.src.slice(img.src.indexOf('.png'));
console.log(newSrc);
img.src = newSrc;
})
});
img {
height: 100px;
width: 100px;
}
<img src="pic.png">
<img src="img.png">
Second I'll change the src of all img tags whenever one is hovered over:
const imgs = document.getElementsByTagName('img');
[...imgs].forEach(img => {
img.addEventListener('mouseenter', () => {
[...imgs].forEach(img => {
const newSrc = img.src.slice(0, img.src.indexOf('.png')) + 2 + img.src.slice(img.src.indexOf('.png'));
console.log(newSrc);
img.src = newSrc;
})
})
img.addEventListener('mouseout', () => {
[...imgs].forEach(img => {
const newSrc = img.src.slice(0, img.src.indexOf('.png') - 1) + img.src.slice(img.src.indexOf('.png'));
console.log(newSrc);
img.src = newSrc;
})
})
});
img {
height: 100px;
width: 100px;
}
<img src="pic.png">
<img src="img.png">
Not sure why you are changing the source.
However, could you try using a sprite as the background image and change background position with :hover css pseudo-selector
This another SO question could help you: Creating CSS Sprite :hover Roll Over Image Links
Add listeners for the mouseover and mouseout events.
getElementsByClassName returns a collection, you have to loop over it to add handlers for all the elements.
const cards = getElementsByClassName('card-img-top');
Array.from(cards).forEach(card => {
card.addEventListener("mouseover", function() {
let url = this.src;
let newImg = url + "2";
this.src = newImg;
});
card.addEventListener("mouseout", function() {
let url = this.src;
let newImg = url.substr(0, -1);
this.src = newImg;
});
});

refresh multiple images using Javascript

I have built a page that pulls in multiple images from various webcams that we use the office to monitor road networks.
We want the images to update automatically every 30 seconds, ut my JavaScript isn't brilliant I'm afraid.
I know I can refresh the whole page easily, and I can refresh a single image just fine too. But multiple images from different URLs is proving more difficult.
The camera images are the only images on the page, if that's useful, and are displayed in HTML like such:
<figure class="fluid tiles">
<img src="cam/17002.php" alt="M" onerror="this.src = 'camoffline.png';" />
<figcaption class="textStyle">M20 00/1A J10-11<br /><small>Camera: 17002</small></figcaption>
</figure>
// get all of the images from the page
const images = document.getElementsByTagName( 'img' );
// perform this function every 30,000 ms (30 sec)
const timer = setInterval( function(){
// go through each image and reference a custom attribute
// 'data-source' to preserve the original image's src
for( var i=0, x=images.length; i<x; i++ ){
// select each image, individually
let image = images[i];
let source = image.getAttribute( 'data-source' );
// if 'data-source' does not exist, create it
if( !source ){
source = image.src;
image.setAttribute( 'data-source', source );
// give 'data-source' the original image path
}
// Add a timestamp to the image source to help mitigate
// browser caching
image.src = source + '?t=' + Date.now();
}
}, 30000 );
img{ height: 150px; }
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
Use .getElementsByTagName('img') to collect all the images that exist on your page.
Then, in an interval (setInterval: code that will continue to execute every ### miliseconds) create a for-loop that will iterate through the HTML collection captured with .getElementsByTagName()
One idea is to create a new attribute on each image on your page, 'data-source' (data- attributes can really be anything). 'data-source' will keep the original information for the path to the image file.
Then, using the value from the original image path, reassign that image path value to the image, but add in a timestamp as a query parameter. This is to help the browser load a new image (browser's love caching content, where they can). The browser sees image.jpeg?t=1234 and thinks it is a different image than image.jpeg?t=1233
I want to propose a slightly modified solution that uses a <canvas>. This will paint all of your sources in a fixed width container and, if they are offline, draw the "Offline" text where the source should have been.
Click the checkbox to test the offline functionality.
const sources = [
"https://cdn.sstatic.net/Sites/stackoverflow/img/sprites.svg",
"https://cdn.sstatic.net/Sites/stackoverflow/img/sprites.svg"
];
function getSources(offline = false) {
return !offline ?
sources.map(src => `${src}?cb=${Date.now()}`) :
sources.map(() => "");
}
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener("load", () => resolve(img));
img.addEventListener("error", () => reject(`Problem loading ${src}`));
img.src = src;
})
}
const offlineCheckbox = document.getElementsByTagName("input")[0],
canvas = document.getElementsByTagName("canvas")[0],
ctx = canvas.getContext("2d");
const {
width,
height
} = canvas;
function refresh() {
console.log("Updating");
getSources(offlineCheckbox.checked).forEach((source, idx, arr) => {
const w = width / arr.length,
dx = w * idx,
dWidth = w * (idx + 1);
loadImage(source)
.then(img => {
ctx.clearRect(dx, 0, dWidth, height);
ctx.drawImage(img, dx, 0, dWidth, height);
})
.catch(err => {
ctx.clearRect(dx, 0, dWidth, height);
ctx.strokeText("Offline", dx, height * 0.5, dWidth);
})
});
setTimeout(() => refresh(), 3 * 1000);
}
refresh();
<main>
<div>
<label><input type="checkbox"> Pretend to be offline</label>
</div>
<div>
<canvas width="400" height="400"></canvas>
</div>
</main>
You can use a timer to reset the src of the image every 30 seconds:
var img = document.querySelector("img.cam");
setInterval(function(){
// I'm appending # and a date to ensure we don't use a cached version of the file
img.src = "https://picsum.photos/200/300/?random#" + new Date() ;
}, 2000); // number is in milliseconds
img { width: 100px; }
<figure class="fluid tiles">
<img class="cam" src="cam/17002.php" alt="M" onerror="this.src='camoffline.png';" />
<figcaption class="textStyle">M20 00/1A J10-11<br /><small>Camera: 17002</small></figcaption>
</figure>

Javascript display dynamic changing image

I want to refresh an image every 1 second. This picture is dynamically generated by my webcam, but this script sometimes display broken images when browser didnt yet load a picture before display. How to detect when picture is loaded and then change the diplay picture?
I have a code like this:
<img id="image" src="webcam.jpg">
<script>
setInterval(function() {
var myImageElement = document.getElementById('image');
myImageElement.src = 'webcam.jpg?rand=' + Math.random();
}, 1000);
</script>
You should wait for the image to be loaded first, before replacing it.
For this, you can use different approaches. What I usually do, is to create another image which is not visible and replace the one visible once the previous image is loaded.
Your code should look like this if you want to follow this approach:
<img id="image" src="webcam.jpg">
<script>
setInterval(function() {
var url = 'webcam.jpg?rand=' + Math.random();
var img = new Image();
img.src = url;
img.addEventListener('load', function() {
var myImageElement = document.getElementById('image');
myImageElement.src = url;
});
}, 1000);
</script>
What you can also do is play with css styles to make the image hidden or visible depending on the state, but that would make your image appear and disappear which is a bit ugly...
I hope it helps :)
I think you can use something like this:
var _img = document.getElementById('pic'),
urlToImage = 'pic.jpg',
modified = false, lastModified = 0;
setInterval(function(){
fetch(urlToImage)
.then(function(resp){
var f = new File([resp],"file");
switch(true) {
case modified === false:
lastModified = f.lastModified;
modified = true; break;
default:
modified = false;
if(lastModified < f.lastModified) {
modified = true;
}
}
return resp.blob();
})
.then(function(blobdata){
switch(true) {
case modified === true:
var obj_url = URL.createObjectURL(blobdata);
_img.src = obj_url;
break;
}
});
},1000);
<img src="" id="pic" alt="LOCAL pic here"/>
I think that looking at lastModified time in File properties is a good way to assume image was finished written on the server.
Hope this helps.
Try using this after loading the document
$( document ).ready(function() {
setInterval(function() {
var myImageElement = document.getElementById('image');
myImageElement.src = 'webcam.jpg?rand=' + Math.random();
}, 500);
});
Hope this helps

Get image dimensions with JavaScript using innerHTML

I'm working on an AJAX function that receives image URLs. However, I won't be using a node append to insert it. I'm using innerHTML, which makes it difficult to get the file dimensions.
At the moment, I'm using a function which is returning somewhat mixed results. Sometimes it gets the actual dimensions, other times it returns "0" as the image dimensions.
This is my function:
var url = "http://placekitten.com.s3.amazonaws.com/homepage-samples/408/287.jpg";
var width = getDimensions(url)[0];
var height = getDimensions(url)[1];
var insert = '<img src="'+url+'" width="'+width+'" height="'+height+'" />';
function getDimensions(path) {
var img = new Image();
img.src = path;
return [img.width, img.height];
}
Not sure why it's acting inconsistently though. Does anyone have any suggestions?
I was thinking it might be something to do with the AJAX inserting the image before it loads the dimensions, although not really sure.
Here's a fiddle, which seems to work as expected, but like I said, it's inconsistent.
http://jsfiddle.net/aH5re/1/
EDIT
Here is a second fiddle with a much larger image. I noticed it's a lot more inconsistent than a smaller image file
http://jsfiddle.net/aH5re/2/
You'll have to wait for the image to finish loading before you can get the dimensions properly and reliably. What's currently happening is that it's returning the dimensions before the image is potentially fully loaded. If you have it already cached you may be getting correct dimensions but on a large image uncached you're not going to get reliable results.
Have a look at this demo about how you could perhaps achieve that.
http://jsfiddle.net/robschmuecker/aH5re/5/
Javascript:
var url = "http://www.hdwallpapers.in/download/transformers_4_age_of_extinction-2560x1440.jpg";
var div = document.querySelector('div');
alert('loading image now');
var button = document.querySelector('.test');
getDimensions(url);
button.addEventListener('click', function () {
div.innerHTML = insert;
});
function getDimensions(path) {
var img = new Image();
img.src = path;
img.onload = function () {
alert('loaded');
var width = img.width;
var height = img.height;
insert = '<img src="' + url + '" width="' + width + '" height="' + height + '" />';
button.disabled = false
};
}

Using a JS function to add images from hidden section in HTML to JS array, and drawing all elements from array onto canvas

I have the following function, which I'm using to load images from the hidden section in my HTML into a JavaScript array:
window.onload = function(){
console.log("src " + document.getElementById("building").src);
var sources = {};
sources[0] = document.getElementById("building").src,
sources[1] = document.getElementById("chair").src,
//sources[2] = document.getElementById("drink").src
loadImages(sources, drawImage);
};
Once the images have been loaded into the JS array, I call the 'loadImages' function:
function loadImages(sources, callback){
var imagesDir = "";
var images = {};
var loadedImages = 0;
var numImages = 0;
console.log("length " + sources.length);
for (var src in sources){
numImages++;
}
console.log("Num Images " + numImages);
var index=0;
console.log("length " + sources.length);
for (index=0;index < numImages ;index++){
console.log(index);
images[index] = new Image();
images[index].src = imagesDir + sources[index];
console.log("Adding " + sources[index]);
callback(images[index]);
}
stage.add(imagesLayer); // should only be added once!!
}
which, in turn, calls the drawImage() method:
function drawImage(imageObj) {
//var layer = new Kinetic.Layer();
var canvasImage = new Kinetic.Image({
image: imageObj,
width: 50,
height: 50,
// puts the image in teh middle of the canvas
x: stage.getWidth() / 2 - 50 / 2,
y: stage.getHeight() / 2 - 50 / 2,
draggable: true
});
// add cursor styling
canvasImage.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
canvasImage.on('mouseout', function() {
document.body.style.cursor = 'default';
});
imagesLayer.add(canvasImage);
}
This method draws the images to the centre of the canvas, and sets their 'draggable' property to true, so that they can be dragged and dropped around the canvas.
The JavaScript is all in the of my page, and in the I have a hidden section, where all of the images I want to draw to canvas are being loaded first. I've done this because it makes the images load and display in the browser much more quickly than if you load them directly from the source into the JavaScript.
The images are loaded with the following HTML:
<img id="building" src="images/assets/building.png" alt="Asset" />
<img id="chair" src="images/assets/chair.gif" alt="Asset" />
<img id="drink" src="images/assets/drink.gif" alt="Asset" />
<img id="food" src = "images/assets/food.gif" alt="Asset"/>
and I am loading around 40 or so images into the HTML
Currently I have this drawing two images to the canvas, "building" and "chair", but for some reason, when I uncomment the line sources[2] = document.getElementById("drink").src to draw the third image to the canvas, and view the page in the browser, my canvas doesn't display on the screen, and I get a console error that says,
uncaught exception: [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMCanvasRenderingContext2D.drawImage]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://www.html5canvastutorials.com/libraries/kinetic-v4.1.2.js :: :: line 4222" data: no]
I am using the Kinetic.js library (http://kineticjs.com/), and it appears to me as if this error is in the library...
Does anyone know if this is the case? Or is there something that I'm doing wrong in my code that's causing this error to occur?
It's not an error in the library, it's an error with that image. Either it's getting the wrong src property or that image doesn't exist at that location. Make sure you've got the url, filetype/name correct.
try this
var img = new Image();
img.onload = function()
{
// some code here
}
img.src = 'assets/.../image.png';

Categories

Resources