I have 3 images on my page. I have assigned eventListener to check for a click, once a click has occurred on one of the images, everything else gets blurred (including the other two images).
Any help is appreciated, thanks.
function showInfo() {
const images = document.getElementsByTagName("img");
const container = document.getElementsByClassName("container");
for (let i = 0; i < images.length; i++) {
images[i].addEventListener("click", (evt) => {
// images[i].style.
})
}
}
showInfo();
You can do it using forEach(). That means if you click on each of them, it must run the command. But don't forget that this method is only possible for more than one HTML tag. (You have 3 images).
After clicking on each element, you must write a for..in loop (modern ecmascript-edition) so you can choose all of the images and apply the blur.
const images = document.querySelectorAll('img');
images.forEach(e => {
// e here means each image, no matter which one is the purpose
e.addEventListener('click', () => {
for (let i in images) {
images[i].style.filter = 'blur(8px)';
i++;
}
})
})
img {
margin-block: 10px
}
<img src="https://picsum.photos/300/200" />
<img src="https://picsum.photos/300/200" />
<img src="https://picsum.photos/300/200" />
Related
i try to créate a javascript class for zoom in and zoom out some pictures.
But all pictures of the page zoom in and zoom out. I think it's a javascript loop's problem but i cant do it.
This is my Class , someone see the problem ?
class Image {
constructor() {
this.ip = document.getElementsByClassName("image_petite");
this.images = [];
}
agrandir() {
for (let i=0; i < this.ip.length; i++) {
this.images.push(this.ip[i]);
};
console.log(this.images);
for (let j=0; j < this.images.length; j++) {
if (this.images[j].classList == "image_petite") {
this.images[j].classList.remove('image_petite');
this.images[j].classList.add('image_grande');
} else if (this.images[j].classList == "image_grande") {
this.images[j].classList.remove('image_grande');
this.images[j].classList.add('image_petite');
}
}
}
}
let image = new Image();
this.images[j].classList == "image_petite" isn't how you check to see if an element has a class. Instead, you use contains:
if (this.images[j].classList.contains("image_petite")) {
// ...
}
Separately, though, you've used a loop, which intentionally processes everything in the this.images array. It's hard to say what you should do instead without knowing what the DOM structure (loosely, the HTML) looks like, but if you're trying to handle resizing one image, you'll need to identify the image you want to resize, which nothing in that code does.
Here's a simple example using a click handler:
// This example uses event delegation
document.body.addEventListener("click", event => {
const image = event.target.closest("img");
if (image && event.currentTarget.contains(image)) {
// This is the image to enlarge or toggle
if (image.classList.contains("image_grand")) {
// Toggling it from big back to small
image.classList.remove("image_grand");
image.classList.add("image_petite");
} else {
// Making this the one big one
const big = document.querySelector(".image_grand");
if (big) {
// Make the current big one small again
big.classList.remove("image_grand");
big.classList.add("image_petite");
}
// Make this one big
image.classList.add("image_grand");
image.classList.remove("image_petite");
}
}
});
.image_petite {
width: 75px;
height: 75px;
}
.image_grand {
width: 150px;
height: 150px;
}
<div>
<img class="image_petite" src="https://via.placeholder.com/150/0000FF/808080 ?text=1">
</div>
<div>
<img class="image_petite" src="https://via.placeholder.com/150/0000FF/808080 ?text=2">
</div>
<div>
<img class="image_petite" src="https://via.placeholder.com/150/0000FF/808080 ?text=3">
</div>
That said, I think I'd use just a single class and add/remove that class, rather than two classes.
I have an array of URIs that represent .png elements, e.g., "./img/diamond-red-solid-1.png".
I want to assign each element of the array "gameDeck[0], gameDeck[1], etc. to div ids in HTML. Do I need to identify the elements as = SRC.IMG?
var gameDeck[];
var gameBoardCards = function () {
for (let cardArr of cardsToLoad)
gameDeck.push("./img/" + cardArr + ".png");
}
gameBoardCards();
document.addEventListener('DOM Content Loaded', function () {
gameDeck[0] = document.getElementById("card1");
gameDeck[1] = document.getElementById("card2");
etc.
});
The way I'm understanding your question is that you would like to target the divs in your HTML with ids of card1, card2, card3... card12 etc.
You would like to insert an img tag into each of these divs with the src being the URIs of the gameDeck array.
The following code achieves this. I've tested it and it works fine. Hope it helps :)
document.addEventListener('DOMContentLoaded', function () {
//iterate through the gameDeck array.
for (let x = 0;x < gameDeck.length;x++){
//create an img tag for each gameDeck element
var imgElement = document.createElement("img");
//set the source of the img tag to be the current gameDeck element (which will be a URI of a png file)
imgElement.src = gameDeck[x];
//target the div with id "card(x + 1)"
var cardID = "card" + (x + 1);
var cardElement = document.getElementById(cardID);
//append the img tag to the card element
cardElement.appendChild(imgElement);
}
//log the HTML to the console to check it
console.log(document.getElementById('body').innerHTML);
});
Here is a way that you can either insert images as background images, or as <img /> elements into the divs you are referring to:
<div id="card0" style="width: 100px; height: 100px;"></div>
<div id="card1" style="width: 100px; height: 100px;"></div>
let loadedImage = [];
function preloadImages(urls, allImagesLoadedCallback) {
let loadedCounter = 0;
let toBeLoadedNumber = urls.length;
urls.forEach(function(url) {
preloadImage(url, function() {
loadedCounter++;
console.log(`Number of loaded images: ${loadedCounter}`);
if (loadedCounter == toBeLoadedNumber) {
allImagesLoadedCallback();
}
});
});
function preloadImage(url, anImageLoadedCallback) {
img = new Image();
img.src = url;
img.onload = anImageLoadedCallback;
loadedImage.push(img);
}
}
function gameBoardCards() {
for (let i = 0; i < loadedImage.length; i++) {
document.getElementById(`card${i}`).style.backgroundImage = `url('${loadedImage[i].src}')`;
// document.getElementById(`card${i}`).appendChild(loadedImage[i]);
}
}
preloadImages([
`https://upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Color_icon_green.svg/2000px-Color_icon_green.svg.png`, `https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/225px-Solid_blue.svg.png`
], function() {
console.log(`all images were loaded`);
gameBoardCards();
// continue your code
});
It may seem like a bit much for what you are trying to accomplish, but I threw in a proper image-loading handler there. The preloadImages function will handle the loading of images, that way they are properly preloaded, and can render to the DOM. Often times, we try to use images before they are properly loaded, resulting in them sometimes not being displayed, despite no errors are being thrown.
The rest of the code is straight forward, in the for loop, it loops through the existing divs and you can either use the current active line document.getElementById(`card${i}`).style.backgroundImage = `url('${loadedImage[i].src}')`; to use the loadedImage[i] image src to load that as the divs's background image. Or you can use the commented-out line directly below that document.getElementById(`card${i}`).appendChild(loadedImage[i]); to insert an <img /> element into that div. Just use either one that works for you.
You can see the code in action in this JS Fiddle demo.
Hope this helps :)
I am building a website, and I need to 'implement' a gallery on a group of photos. Since I'm using Spring MVC, my images are with 'img src..' tag and regular js and jquery addons don't work. Is there any plugin/library that can help me do this? If not, suggestions for making my way around it are also welcome. Here is the html, if it can somehow help.
<div id="img-slider">
<img class="slider-img" src="/LBProperties/img/bisc.jpg"/>
<img class="slider-img" src="/LBProperties/img/bisc1.jpg"/>
</div>
Thank you !
You can hide all of the images with CSS:
img {
width: 100px;
height: 100px;
display: none;
}
Get handlers to the images:
var slider = document.querySelector('#img-slider');
var images = slider.getElementsByTagName('img');
Set an index to 0:
var index = 0;
Then show the first image:
images[index].style.display = 'block';
Add a button to your HTML:
<div>
<button id="next">Next</button>
</div>
Get it with script and add a click handler:
var button = document.querySelector('#next');
button.addEventListener('click', function() {
for (var ix = 0; ix < images.length; ix++) {
images[ix].style.display = 'none';
}
index++;
if (index >= images.length) index = 0;
images[index].style.display = 'block';
});
The click handler loops through the images and hides them, increases the index, checks to make sure the index didn't go over the number of images (reset it to 0 if it does), then shows the next image.
Putting it all together:
https://jsfiddle.net/subterrane/osszqoLe/
Maybe a silly question but here goes anyway.
Example: Let's say I have one non-looping animated GIF and I have two img elements.
<img src="" id="slot1" />
<img src="" id="slot2" />
So I use a little javascript to change the source of the slot1.
function changE(x)
{var image=document.getElementById (x);
image.src="animated.gif";
}
someButtonGotClicked=changE('slot1');
that works fine. Gif plays from start to end but if I then change the src of slot2 to the same gif:
changE('slot2');
slot1 resets it's gif back to the start to sync with slot2 starting it's gif.
Now i'm aware I could copy the gif and have 2 seperate files to use and I know about sprite sheets but I'm curious If I can use one copy of a gif and have it used multiple times on a page without all instances of the gif being restarted everytime another img element recieves the same file as it's src?
Hope that wasn't confusing. Thanks.
Once an image is loaded in memory, all other objects that request that image, using the same URL, get a reference to the image from the browser cache. This avoids loading the same image multiple times. In the case of a gif, one of the meta data to be kept track of is the current frame, which is stored not at the <img> dom element, but rather at the browser level in the structure it uses to store that gif.
On load, that frame index is reset. So, while the browser is processing the gif loop, a second image loading sets the current frame index to the beginning, hence both images synchronize.
This is a browser implementation, and it seems most browsers follow this implementation. One advantage to this is that if you have thousands of little gifs (from the same URL) in one page, the browser would do a lot less computation to render them, because it would only change one frame index, not thousands.
Edit:
To fix your code you'd have to basically add something random at the end of your image.
function changE(x)
{var image=document.getElementById (x);
image.src="animated.gif?" + Math.random();
}
So the browser thinks this is a different image (i.e. different URL).
Try using a solution like so:
<img src="" id="slot1" class="animate" />
<img src="" id="slot2" class="animate" />
(function(doc, w) {
var changE, getElementsByClassName;
changE = function(img) {
img.src = "animated.gif";
};
getElementsByClassName = function(node, classname) {
if (node.getElementsByClassName) { // use native implementation if available
return node.getElementsByClassName(classname);
} else {
return (function getElementsByClass(searchClass, node) {
if (node == null)
node = doc;
var classElements = [],
els = node.getElementsByTagName("*"),
elsLen = els.length,
pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)"), i, j;
for (i = 0, j = 0; i < elsLen; i++) {
if (pattern.test(els[i].className)) {
classElements[j] = els[i];
j++;
}
}
return classElements;
})(classname, node);
}
};
w.onload = function() {
var imgs, i = 0, l;
imgs = getElementsByClassName(doc, 'animate');
l = imgs.length;
for (i; i < l; i++) {
imgs[i].onclick = function(e) { changE(this); };
}
};
})(document, window);
This will set a clicke event for each image with the calss name animate and the click event will only effect the specific image clicked.
I am making an image slideshow using native JS.
I decided to make it myself because it needs to run at ~100ms intervals, and without any special transition effects (see it here), so I figured it was unnecessary to include a big library like JQuery just for just a simple application.
This is the code I am currently using [edit: original code - now modified]:
// JavaScript Document
function preloadimages(arr){ // the preloadimages() function is adapted from http://www.javascriptkit.com/javatutors/preloadimagesplus.shtml
var newimages = [], loadedimages = 0;
var postaction = function() {};
var arr = (typeof arr != "object") ? [arr] : arr;
function imageloadpost() {
loadedimages++;
if (loadedimages == arr.length) {
postaction(newimages); //call postaction and pass in newimages array as parameter
}
}
for (var i = 0; i < arr.length; i++) {
newimages[i] = new Image();
newimages[i].src = arr[i];
newimages[i].onload = function() {
imageloadpost();
}
newimages[i].onerror = function() {
imageloadpost();
}
}
return { //return blank object with done() method
done: function(f) {
postaction = f || postaction; //remember user defined callback functions to be called when images load
}
}
}
/* USAGE:
preloadimages(['ed.jpg', 'fei.jpg', 'budapest.gif', 'duck.jpg']).done(function(images) {
images.sort(function(a, b) {
return a.width - b.width; //sort images by each image's width property, ascending
});
alert(images[0].src); //alerts the src of the smallest image width wise
});
*/
function animateSlideshow() {
var num = window.imgNum + 1 ;
if (num >= d['imgs'].length) {
num = 0;
}
window.imgNum = num;
imgTag.src = d['imgs'][num];
var t = window.setTimeout(function(){animateSlideshow(imgNum, imgTag, d)}, 100);
}
var d;
var imgTag;
var imgNum = 0;
$.onDomReady (function () { // This is not JQuery, it's a simple cross-browser library which you can read here: http://assets.momo40k.ch/common/js/$.js
// data is an array that should be already defined on the calling page,
// containing all the necessary information to generate all the rotation slideshows on the page
for (i = 0; i < data.length; i++) {
d = data[i];
var div = document.getElementById(d['id']);
imgTag = $.Elements.getElementsByClassName('theImage', div)[0];
// preload the images...
preloadimages(d['imgs']).done(function(images) {
imgTag.src = d['imgs'][0];
animateSlideshow();
});
}
});
<!-- HTML calling JS Scripts -->
... HTML document ...
<script src="http://assets.momo40k.ch/common/js/$-min.js" language="javascript" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
var data = [];
// I would have an index for each slideshow on the page
data[0] = [];
data[0]['id'] = 'rotation2';// the ID of the tag the initial image is in
data[0]['imgs'] = ['http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic1.png',
'http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic2.png',
'http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic3.png',
'... all the images ... '];
</script>
<script src="js/rotation.js" language="javascript" type="text/javascript"></script>
</body>
</html>
This is what the tag the initial image is in looks like:
<div id="rotation2" class="rotation blackbg">
<img src="http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic1.png" width="300" title="" class="theImage" />
</div>
Now for the question:
this script only allows me to have one single 'slideshow' on the page - because in each iteration of the loop it overrides the imgNum variable. Is there an other, better way of doing this slideshow (if possible without JQuery, otherwise OK), even in a completely different way?
Thank you
EDIT: I have remade the script following Jared Farrish's answer and it's now working fine!
There were some issues I saw with your code or approach, so I decided to redo it with the approach I would take. For instance:
I would use document.images to get all images and, for ones that have the rotator-specific className, to identify (domElement.parentNode) and obtain the containing div, which will give me it's id.
I would use the parentNode.id of the class="rotation" images to create an object with sets (by container ids) I can use to store references to the img nodes.
Use closure scope to stay out of the global scope, as well as be able to share variables between the closure-scoped functions.
Use variable functions to setup the handler and callback functions.
Let me know if you have any questions or find something that doesn't work.
<div id="rotator1" class="rotation blackbg">
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/6/6e/Brandenburger_Tor_2004.jpg" />
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/a/ad/Cegonha_alsaciana.jpg" />
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/d/da/CrayonLogs.jpg" />
</div>
<div id="rotator2" class="rotation blackbg">
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/1/17/Bobbahn_ep.jpg" />
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/9/90/DS_Citro%C3%ABn.jpg" />
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/f/f0/DeutzFahr_Ladewagen_K_7.39.jpg" />
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/c/c7/DenglerSW-Peach-faced-Lovebird-20051026-1280x960.jpg" />
<img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/4/4d/FA-18F_Breaking_SoundBarrier.jpg" />
</div>
var slideshows = function(){
var timeouts = {},
imgs;
function preloadImages(list){
var loading = list,
img,
loaded = {},
newimages = [];
var imageloaded = function(){
// this here is one of the new Image()s we created
// earlier; it's not the "real" image on the screen.
// So I put the reference to the actual image it represents
// on the screen in the rel attribute so I can use it's
// reference; I just have to use this.rel to get it.
var parent = this.rel.parentNode;
// Keeping track of the individual sets loaded.
loaded[parent.id]++;
// Here is where this/self gets it's context from, when
// we .call(parent, 0). It's the parentNode to the image
// we've referenced above. This should only run once,
// when the last image has loaded for the set.
if (loaded[parent.id] == loading[parent.id].length) {
animateSlideshow.call(parent, 0);
}
};
var imagenotloaded = function(){
// this.rel is the reference to the actual image we
// have in the DOM, so we'll set the error flag on it.
this.rel['imageerror'] = true;
imageloaded.call(this);
};
for (var load in loading) {
// loaded is equivalent to imgs.sets, so load is the
// id for the container.
loaded[load] = [];
// Now we're going to loop over every image in the
// current set, creating a Javascript image object
// to initiate the download of the file and tell us
// when it's finished. Not the newimages[i].rel = img
// part.
for (var i = 0, l = loading[load].length; i < l; i++) {
img = loading[load][i];
newimages[i] = new Image();
newimages[i].onload = imageloaded;
newimages[i].onerror = imagenotloaded;
newimages[i].rel = img;
newimages[i].src = img.src;
}
}
}
var animateSlideshow = function(current) {
// this could be used instead of self. I was doing
// something else at first, but making this copy
// of the context (this) is not necessary with this
// code. It doesn't hurt either.
var self = this;
// Our current context is the containing div, so
// this.id/self.id will give us the key to the correct
// group in imgs.sets, and the current argument will
// tell us with image in that list we're currently
// working with. First, we hide the last displayed
// image.
imgs.sets[self.id][current].style.display = 'none';
// Increment to get the next image.
current++;
// If we're at the end, let's move back to the
// beginning of the list.
if (current >= imgs.sets[self.id].length) {
current = 0;
}
// This skips images which had an error on load. The
// test for this in the markup above is the third image
// in rotator1, which is not an image url.
if (imgs.sets[self.id][current].imageerror == true) {
// See how I'm passing self using .call()? This sets
// the context for the next animateSlideshow() call,
// which allows this/self to work on the correct div
// container.
animateSlideshow.call(self, current);
return;
}
imgs.sets[self.id][current].style.display = 'inline';
// Everything is organized by the self.id key, event
// saving the references to the timeouts.
timeouts[self.id] = setTimeout(function(){
animateSlideshow.call(self, current);
}, 100);
};
function getImages(){
var list = document.images,
img,
data = {sets: {}, allimages: []},
parent;
// document.images gives me an array of references to all
// img elements on the page. Let's loop through and create
// an array of the relevant img elements, keying/grouping on the
// parent element's id attribute.
for (var i = 0, l = list.length; i < l; i++){
img = list[i];
parent = img.parentNode;
// parent should now be a reference to the containing div
// for the current img element. parent.id should give us
// rotator1 or rotator2 in the demo markup.
if (parent.className.indexOf('rotation') !== -1) {
if (!data.sets[parent.id]) {
data.sets[parent.id] = [];
}
// Let's put the img reference into the appropriate
// imgs.sets. I also put the img.src into an index
// container in data.allimages; this is also a remnant
// of a previous approach I took. It could probably be
// removed unless you need it.
data.sets[parent.id].push(img);
data.allimages.push(img.src);
}
}
return data;
}
function initializeSlideshows(){
imgs = getImages();
preloadImages(imgs.sets);
}
initializeSlideshows();
};
$.onDomReady(slideshows);
http://jsfiddle.net/DLz92/1