How to use JS to get HTML img height and set it as a variable? - javascript

In the following snippet, I'm trying to get the height of any image nested inside a particular class. Once that image height is gathered, I need to store it in a variable to be used elsewhere.
The two issues I'm running into are:
The second image is coming back as 0px
Storing the dynamic image height result as a variable
let getImgHeight = (()=> {
let images = document.querySelectorAll('.wistia img');
images.forEach(image => console.log(`${image.clientHeight}px`));
})();
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
<img src="https://www.thedesignwork.com/wp-content/uploads/2011/10/Random-Pictures-of-Conceptual-and-Creative-Ideas-02.jpg" alt="">
</div>

You get zero because you check the image height before it was loaded. You can easily check it if you wrap your function in some long timeout.
The better approach is to wait for all the loading images (ignoring ones that are already loaded) and after that get their height.
Here is an example below:
let getImgHeight = (()=> {
let images = document.querySelectorAll('.wistia img');
Promise.all(Array.from(images)
.filter(img => !img.complete)
.map(img => new Promise(resolve => {
img.onload = img.onerror = resolve; })
)
).then(() => {
images.forEach(image => console.log(`${image.clientHeight}px`));
});
})();
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
<img src="https://www.thedesignwork.com/wp-content/uploads/2011/10/Random-Pictures-of-Conceptual-and-Creative-Ideas-02.jpg" alt="">
</div>
UPDATE 1
As long as you want
to set the height of the parent container
I'd suggest rewriting your code as follows:
const images = document.querySelectorAll('.wistia img');
for (const image of Array.from(images)) {
if (image.complete) {
image.parentElement.style.height = image.clientHeight + 'px';
} else {
image.onload = () => {
image.parentElement.style.height = image.clientHeight + 'px';
}
}
}
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
</div>

The issue is most likely that you're trying to get the height of an image that hasn't finished loading. The best way to deal with that is to use the load event listener. You can then store the height as a data-attribute which is one way of making it a dynamic variable.
document.addEventListener('DOMContentLoaded', () => {
let images = document.querySelectorAll('.wistia img');
images.forEach(image => {
image.addEventListener('load', e => {
e.target.setAttribute('data-height', `${image.clientHeight}px`)
console.log(`${e.target.clientHeight}px`);
if (document.querySelectorAll('.wistia img[data-height]').length === images.length) {
console.log("ALL IMAGES LOADED");
}
});
});
});
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
<img src="https://www.thedesignwork.com/wp-content/uploads/2011/10/Random-Pictures-of-Conceptual-and-Creative-Ideas-02.jpg" alt="">
</div>

I tried your code in JSFiddle and it worked as expected. Check the version of jQuery you're using.

Related

Change image on texthover

I want to change an image when the user hovers over a certain text. I found this question on stackoverflow (Change Image On Hover Javascript), but here the image is changed when the user hovers the image not the text. So I tried to adapt the code of the answer, so that the image is cahnged on texthover (I just put the "onmouseover" and "onmouseout" into the h1 instead of the img).
This is the code of the answer which changes the image when the user hovers the image:
<img
onmouseover="this.src='images/Logo white transparent.png'"
onmouseout="this.src='images/Logo black transparent.png'"
height="100px"
src="images/Logo black transparent.png"
/>
And this is the code I tried in order to change the image when the text is hovered:
<img
height="100px"
src="images/Logo black transparent.png"
/>
<h1
onmouseover="this.src='images/Logo white transparent.png'"
onmouseout="this.src='images/Logo black transparent.png'"
>
Hello
</h1>
your h1 is not an image tag so src will not work there
<img
height="100px"
src="https://www.littlethings.info/wp-content/uploads/2014/04/dummy-image-green-e1398449160839.jpg"
/>
<h1
onmouseover="change()"
onmouseout="changeBack()"
>
Hello
</h1>
add extra js:
let img = document.querySelector("img")
function change() {
img.src = "https://picsum.photos/200/301"
}
function changeBack() {
img.src = "https://www.littlethings.info/wp-content/uploads/2014/04/dummy-image-green-e1398449160839.jpg"
}
maybe this website can be refference :
https://www.tutorialrepublic.com/faq/how-to-change-image-on-hover-with-css.php
good luck
Solution 1
Create a function with two different events:
const toggleImg = () => {
// Get the target elements
let el = document.getElementById('el');
let img = document.getElementById('img');
// On mouseover:
el.addEventListener("mouseover", () => {
img.src = 'https://www.w3schools.com/images/lamp.jpg';
});
// On mouseout:
el.addEventListener("mouseout", () => {
img.src = 'https://www.w3schools.com/images/stickman.gif';
});
};
// Call the function
toggleImg();
h1 {
width: fit-content;
}
<h1 id="el">Hover</h1>
<img id="img" src="https://www.w3schools.com/images/stickman.gif" />
Solution 2
Create a function and check the event (condition):
const toggleImg = (e) => {
// Get the target elements
let el = document.getElementById('el');
let img = document.getElementById('img');
// Save the images in variables
isOver = 'https://www.w3schools.com/images/lamp.jpg';
isOut = 'https://www.w3schools.com/images/stickman.gif';
// Toggle
e.type == 'mouseover' ? img.src = isOver : e.type == 'mouseout' ? img.src = isOut : '';
};
// Add the event
el.onmouseover = el.onmouseout = toggleImg;
h1 {
width: fit-content;
}
<h1 id="el">Hover</h1>
<img id="img" src="https://www.w3schools.com/images/stickman.gif" />

Images written in my HTML are not visible

I am creating a gallery on my first webpage and have seen a template i would like to use. Some of these images will show once, but when the page has refreshed the image shows for a second but then disappears. It is still on the page as the cursor changes to a pointer when you hover over where the image should be.
I have had a look a the Javascript and CSS but as i am still new at web development i am unsure which line it is that is causing the image to not be visible. I have created a codepen for you to see. https://codepen.io/Jaderianne/pen/KjLGqd
HTML:
<div class="gallery" id="gallery">
<div class="gallery-item">
<div class="content"><img src="http://turbophoto.com/Free-Stock-
Images/Images/Ancient%20Horse%20-%2027%20Years%20Old.jpg" alt=""></div>
</div>
<div class="gallery-item">
<div class="content"><img
src="https://source.unsplash.com/random/?tech,substance" alt=""></div>
</div>
<div class="gallery-item">
<div class="content"><img
src="https://source.unsplash.com/random/?tech,choose" alt=""></div>
</div>
</div>
JAVASCRIPT:
var gallery = document.querySelector('#gallery');
var getVal = function (elem, style) { return
parseInt(window.getComputedStyle(elem).getPropertyValue(style)); };
var getHeight = function (item) { return
item.querySelector('.content').getBoundingClientRect().height; };
var resizeAll = function () {
var altura = getVal(gallery, 'grid-auto-rows');
var gap = getVal(gallery, 'grid-row-gap');
gallery.querySelectorAll('.gallery-item').forEach(function (item) {
var el = item;
el.style.gridRowEnd = "span " + Math.ceil((getHeight(item) + gap) /
(altura + gap));
});
};
gallery.querySelectorAll('img').forEach(function (item) {
item.classList.add('byebye');
if (item.complete) {
console.log(item.src);
}
else {
item.addEventListener('load', function () {
var altura = getVal(gallery, 'grid-auto-rows');
var gap = getVal(gallery, 'grid-row-gap');
var gitem = item.parentElement.parentElement;
gitem.style.gridRowEnd = "span " + Math.ceil((getHeight(gitem) +
gap) / (altura + gap));
item.classList.remove('byebye');
});
}
});
window.addEventListener('resize', resizeAll);
gallery.querySelectorAll('.gallery-item').forEach(function (item) {
item.addEventListener('click', function () {
item.classList.toggle('full');
});
});
I would like the images to be visible at all times even when the page has been refreshed.
The first img has got the class "byebye" which sets its opacity to 0, which is why it appears invisible. This is added by a line in a foreach:
gallery.querySelectorAll('img').forEach(function (item) {
item.classList.add('byebye');
The code then checks if the image has finished loading:
if (item.complete) {
If it has finished loading, it does nothing except log data to the console. If it hasn't finished loading it adds a event listener to wait for the image to load. When that event fires, it runs code which (among other things) removes the "byebye" class.
The problem seems to be that your first image has already finished loading when this code runs, so the event handler never gets added and so the "byebye" class is never removed.
This can be fixed by making it trigger the same code in either case (whether the image is already loaded or not):
gallery.querySelectorAll("img").forEach(function(item) {
item.classList.add("byebye");
if (item.complete) {
console.log(item.src);
loaded(item);
} else {
item.addEventListener("load", function() {
loaded(item);
});
}
});
//...
function loaded(item) {
var altura = getVal(gallery, "grid-auto-rows");
var gap = getVal(gallery, "grid-row-gap");
var gitem = item.parentElement.parentElement;
gitem.style.gridRowEnd =
"span " + Math.ceil((getHeight(gitem) + gap) / (altura + gap));
item.classList.remove("byebye");
}
CodePen: https://codepen.io/ADyson82/pen/OeYBZe

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>

Know offset of a div placed after lazy load images

I have a div wrapper in which lazy load images are present. Then I have a div below those images and I want to make it Sticky.
<div id="someWrapper">
<img class="lazy" data-original="someImageURL"></img>
<img class="lazy" data-original="someImageURL"></img>
<img class="lazy" data-original="someImageURL"></img>
<img class="lazy" data-original="someImageURL"></img>
<div class="sticky">SomeContents</div> <!-- want to make this sticky on scrool -->
</div>
In order to make them sticky I need offset of the div. Problem is offset is not fixed on the page because of lazy load images that keep pushing the div downward. Image heights are unknown. No of images are 4. Tried using appear event on the last load element but its not giving me accurate results. Please help me how to solve this problem. I want to get offset of the sticky div so I can make a check on the scroll event.
After playing around and some research achieved the desired like this:
function activateStickyScrollEvent(offSetValue){
//code to activate scroll event
}
var lazyLength=$('#someWrapper lazy').length;
var lazyCount=0;
$('#someWrapper lazy').one('appear',function(){
++lazyCount;
if(lazyCount===lazyLength){
var getWrapperOffset=$('#someWrapper').offSet().top;
activateStickyScrollEvent(getWrapperOffset);
})
So, as I said, you may have to check if the last image in the set has been loaded, and then check for the element's offset. Here is a demo of how it could be done. Feel free to adapt the code to suit your needs.
//Ref to the wrapper
var $wrapper = $("#someWrapper");
//Ref to the last image in the set
var lastImgSrc = $wrapper.find(" > img:last").attr("data-original");
var image = new Image();
image.onload = function () {
//do something on load...
var offset = $wrapper.find(".sticky").offset();
alert (offset.top);
}
image.onerror = function () {
//do something on error...
}
image.src = lastImgSrc;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="someWrapper">
<img class="lazy" data-original="someImageURL" />
<img class="lazy" data-original="someImageURL" />
<img class="lazy" data-original="http://dreamatico.com/data_images/sea/sea-4.jpg" src="http://dreamatico.com/data_images/sea/sea-4.jpg" width="100%" />
<img class="lazy" data-original="http://dreamatico.com/data_images/sea/sea-3.jpg" src="http://dreamatico.com/data_images/sea/sea-3.jpg" width="100%" />
<div class="sticky">SomeContents</div> <!-- want to make this sticky on scrool -->
</div>
Hope that helps.
You can count images to load, and the get the offset (OFFSET in my example) :
$(function() {
function imageLoaded() {
counter--;
if( counter === 0 ) {
// Here All your "lazy" images are loaded
var OFFSET = $('#someWrapper').offset().top; <---- you can get offset
}
}
var images = $('.lazy'),
counter = images.length; // initialize the counter
images.each(function() {
if( this.complete ) {
imageLoaded.call( this );
} else {
$(this).one('load', imageLoaded);
}
});
});

Categories

Resources