How to set img attributes with JS - javascript

So I am trying to set attributes (width and height) of my all images on page.
So i do something like that:
const images = document.querySelectorAll('img');
const setImagesAttributes = () => {
images.forEach(img => {
img.setAttribute('width', img.clientWidth);
img.setAttribute('height', img.clientHeight);
})
}
window.onload = () => {
setImagesAttributes();
window.addEventListener('resize', debounce(setImagesAttributes));
}
And now something weird happen. So I think 90% of images work correct, the behave in same way like before adding script. But some images have very low height, idk what happend. Why one image behave normally, others not.
Before adding script:
After script:
But as i sad over 90% of images works correct. After adding script they have W & H attributes and work fine

Related

DOM element to image generates only white image

I'm using html2canvas to create images from the DOM element.
The code looks like this.
const node = document.getElementById('domElement')
html2canvas(node, {
windowWidth: node.scrollWidth,
windowHeight: node.scrollHeight,
}).then(canvas => {
const image = canvas.toDataURL()
})
But its only rendering an image that is fully white. The image size (l*b) is accurate.
But when I try to render the image of the full body it shows the image but with blank white screen on top.
i.e. when,
const node = document.body
How will the elements be added properly and not the blank white screen on the image?
The code is inside an antd design modal.
This statement solved my problem.
window.scrollTo(0, 0)
The final code looks like
window.scrollTo(0, 0)
const node = document.getElementById('domElement')
html2canvas(node, {
windowWidth: node.scrollWidth,
windowHeight: node.scrollHeight,
}).then(canvas => {
const image = canvas.toDataURL()
})

Get image width and height. src is proxy

I have a Vue component, in it I have an img, I need to get that image dimensions, preferably before showing the image (to fit in the container either by width or height).
this.img = new Image();
this.img.src = this.payload.src;
this.img.onload = () => {
let width = this.img.naturalWidth;
let height = this.img.naturalHeight;
}
That code might not work, the image src can return 401 (not sure yet), we use proxy and get that file from a storage bucket on the server. like /api/getStorageResource?blob=
What can I do?
Having the link, can I somehow fetch image through axios and set it as an element, instead of <img src=".." />
As an option I see that I can probably have the element as it is now <img src="/api/getStorageResource?blob=" /> and getElementById it and get the width and height... Not sure what my options here.
You can use a combination of async/await and the fetch api inside a try/catch block to get the image URL from your server and then you can proceed with creating the <img> element, assign the retrieved image URL to the img element src and finally set the width and height of the container equal to the img element's width and height.
In the following example Code Snippet, I have added a button which will add the image to the container on click so you can see how the container has the retrieved image dimensions even before the image is rendered on the DOM:
const imgDiv = document.querySelector('#imgDiv');
const btn = document.querySelector('#imgBtn');
//The fetchImg function will fetch the image URL from the server and log error to console if file not found
const fetchImg = async () => {
try {
// replace the following example url with "this.payload.src"
const imgURL = await fetch('https://picsum.photos/id/237/200/200');
return imgURL;
} catch (err) {
// do something here if image not found
console.log('Image not found!');
}
}
fetchImg().then((res) => {
// create a new image element with the URL as the src
const img = new Image();
img.src = res.url; // change ".url" according to how the data you get from your server is structured
// assign the retrieved width and height of img to container
img.addEventListener('load', () => {
imgDiv.style.width = img.naturalWidth + 'px';
imgDiv.style.height = img.naturalHeight + 'px';
});
btn.addEventListener('click', () => imgDiv.appendChild(img));
});
html, body {margin: 0;padding: 10px;width: 100%; height: 100%;text-align: center;}
#imgDiv {background-color: #222;margin: 0 auto;}
<button id="imgBtn">Add Image</button>
<div id="imgDiv"></div>
JSFiddle with above code: https://jsfiddle.net/AndrewL64/2hu3yxtq/104/

Redrawing background using ResizeObserver causes flashing in FireFox

I'm using Trianglify to create backgrounds for a div element. I wanted to write the function to regenerate the background anytime the window is resized.
Here is the function that adds the generated png to the div.
const header = document.querySelector('#header');
const addBackground = target =>{
const dimensions = target.getClientRects()[0];
const pattern = Trianglify({
width: dimensions.width,
height: dimensions.height,
cell_size: Math.random()*200 + 40
});
target.style['background-image'] = 'url(' + pattern.png() + ')';
}
addBackground(header);
And here is the ResizeObserver
const ro = new ResizeObserver( () => {
addBackground(header);
});
ro.observe(header);
This works fine in chrome and edge but it creates an effect in FireFox where the background image isn't generated until the user is done resizing. This would be fine if it didn't clear the background during the resizing.
I've created a fiddle that recreates the issue.
Link to Fiddle

Issue with image load recursive chain on slow network/mobile

So basically I have a page with a few sections. Each sections contains 5-30 image icons that are fairly small in size but large enough that I want to manipulate the load order of them.
I'm using a library called collagePlus which allows me to give it a list of elements which it will collage into a nice image grid. The idea here is to start at the first section of images, load the images, display the grid, then move on to the next section of images all the way to the end. Once we reach the end I pass a callback which initializes a gallery library I am using called fancybox which simply makes all the images interactive when clicked(but does not modify the icons state/styles).
var fancyCollage = new function() { /* A mixed usage of fancybox.js and collagePlus.js */
var collageOpts = {
'targetHeight': 200,
'fadeSpeed': 2000,
'allowPartialLastRow': true
};
// This is just for the case that the browser window is resized
var resizeTimer = null;
$(window).bind('resize', function() {
resetCollage(); // resize all collages
});
// Here we apply the actual CollagePlus plugin
var collage = function(elems) {
if (!elems)
elems = $('.Collage');
elems.removeWhitespace().collagePlus(collageOpts);
};
var resetCollage = function(elems) {
// hide all the images until we resize them
$('.Collage .Image_Wrapper').css("opacity", 0);
// set a timer to re-apply the plugin
if (resizeTimer) clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
collage(elems);
}, 200);
};
var setFancyBox = function() {
$(".covers").fancybox({/*options*/});
};
this.init = function(opts) {
if (opts != null) {
if (opts.height) {
collageOpts.targetHeight = opts.height;
}
}
$(document).ready(function() {
// some recursive functional funk
// basically goes through each section then each image in each section and loads the image and recurses onto the next image or section
function loadImage(images, imgIndex, sections, sectIndex, callback) {
if (sectIndex == sections.length) {
return callback();
}
if (imgIndex == images.length) {
var c = sections.eq(sectIndex);
collage(c);
images = sections.eq(sectIndex + 1).find("img.preload");
return loadImage(images, 0, sections, sectIndex + 1, callback);
}
var src = images.eq(imgIndex).data("src");
var img = new Image();
img.onload = img.onerror = function() {
images[imgIndex].src = src; // once the image is loaded set the UI element's source
loadImage(images, imgIndex + 1, sections, sectIndex, callback)
};
img.src = src; // load the image in the background
}
var firstImgList = $(".Collage").eq(0).find("img.preload");
loadImage(firstImgList, 0, $(".Collage"), 0, setFancyBox);
});
}
}
From my galleries I then call the init function.
It seems like my recursive chain being triggered by img.onload or img.onerror is not working properly if the images take a while to load(on slow networks or mobile). I'm not sure what I'm missing here so if anyone can chip in that would be great!
If it isn't clear what is going wrong from the code I posted you can see a live example here: https://www.yuvalboss.com/albums/olympic-traverse-august-2017
It works quite well on my desktop, but on my Nexus 5x it does not work and seems like the finally few collage calls are not happening. I've spent too long on this now so opening this up to see if I can get some help. Thanks everyone!
Whooooo I figured it out!
Was getting this issue which I'm still unsure about what it means
[Violation] Forced reflow while executing JavaScript took 43ms
Moved this into the callback that happens only once all images are loaded
$(window).bind('resize', function() {
resetCollage(); // resize all collages
});
For some reason it was getting called early even if the browser never resized causing collage to get called when no elements existed yet.
If anyone has any informative input as to why I was getting this js violation would be great to know so I can make a better fix but for now this works :):):)

Changing source of image with an image of different size, won't resize in IE

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;
}

Categories

Resources