Here is just an example of what I'm trying to achieve.
So I looked online on how to get the average color of an image and the solution I found works pretty well. The only problem is that it doesn't work well when you decide to lazy load the images.
For the purpose of this question, here is a basic HTML structure with images.
<div id="block">
<img id="img" src="http://localhost:90/avg-color-of-img/Archive.jpg">
</div>
<div id="block">
<img id="img" src="http://localhost:90/avg-color-of-img/Archive.jpg">
</div>
<div id="block">
<img id="img" src="http://localhost:90/avg-color-of-img/Archive.jpg">
</div>
And here is the javascript that picks the average color from the images:
function averageColor(imageElement) {
// Create the canavs element
var canvas = document.createElement('canvas'),
// Get the 2D context of the canvas
context
= canvas.getContext &&
canvas.getContext('2d'),
imgData, width, height,
length,
// Define variables for storing
// the individual red, blue and
// green colors
rgb = { r: 0, g: 0, b: 0 },
// Define variable for the
// total number of colors
count = 0;
// Set the height and width equal
// to that of the canvas and the image
height = canvas.height =
imageElement.naturalHeight ||
imageElement.offsetHeight ||
imageElement.height;
width = canvas.width =
imageElement.naturalWidth ||
imageElement.offsetWidth ||
imageElement.width;
// Draw the image to the canvas
context.drawImage(imageElement, 0, 0);
// Get the data of the image
imgData = context.getImageData(
0, 0, width, height);
// Get the length of image data object
length = imgData.data.length;
for (var i = 0; i < length; i = 4) {
// Sum all values of red colour
rgb.r = imgData.data[i];
// Sum all values of green colour
rgb.g = imgData.data[i 1];
// Sum all values of blue colour
rgb.b = imgData.data[i 2];
// Increment the total number of
// values of rgb colours
count ;
}
// Find the average of red
rgb.r = Math.floor(rgb.r / count);
// Find the average of green
rgb.g = Math.floor(rgb.g / count);
// Find the average of blue
rgb.b = Math.floor(rgb.b / count);
return rgb;
}
// Function to set the background color of the second div as
// calculated average color of image
var rgb;
var imgg = document.getElementsByClassName("cimg");
var blocks = document.getElementsByClassName("block");
var i;
for (i = 0; i < imgg.length; i ) {
rgb = averageColor(imgg[I]);
blocks[i].style.backgroundColor =
'rgb(' rgb.r ','
rgb.g ','
rgb.b ')';
}
Everything worked fine until I decided to use 'lazysizes' to lazyload the images.
For the lazy loading to work I had to use data-src
to get the images instead of the regular src
attribute and now because there isn't an image in the src
attribute, the code to pick the average color doesn't work well.
Please is there any possible way to lazy load images and still get their average color? Thanks :)
CodePudding user response:
You can create a load event listener for each image, so once each image loads you get the color. Your code can be written thus:
var imgg = document.getElementsByClassName("cimg");
var blocks = document.getElementsByClassName("block");
for (var i = 0; i < imgg.length; i ) {
setColor(i);
}
function setColor(i) {
var $img = imgg[i];
// once the lazy-loaded image loads:
$img.addEventListener("load", e => {
// get average color and set
var rgb = averageColor($img);
blocks[i].style.backgroundColor =
'rgb(' rgb.r ','
rgb.g ','
rgb.b ')';
});
}