I'm trying to write a simply image gallery element for a website and I'm having trouble with the code for silly reasons. I've never gotton on with JavaScript and have always found it a headache. I've tried various other image galleries but can't for the life of me get them to actually work correctly either
My current HTML code is like this:
<!DOCTYPE html>
<html>
<head>
<title> Test of slider </title>
<script type="text/javascript" src="slider.js"></script>
</head>
<body>
<div class="slider" id="main">
<img src="#" class="mainImage" />
<div class="sliderImages" style="display: none;">
<img src="companion.jpg"/>
<img src="cookie.jpg" />
<img src="orange.jpg" />
<img src="orangeWhole.jpg" />
</div>
<div class="sliderButtons">
Previous
Next
</div>
</div>
</body>
</html>
with the javascript like this:
this.Slider = new function(){
// Stores the indices for each slider on the page, referenced by their ID's
var indices = {};
var limits = {};
var images = {};
// Call this function after a major DOM change/change of page
this.SetUp = function(){
// obtain the sliders on the page
// TODO restrict to those within body
var sliders = document.getElementsByClassName('slider');
// assign the indices for each slider to 0
for(var i = 0; i < sliders.length; i++){
indices[sliders[i].id] = 0;
var sliderImages = document.getElementsByClassName('sliderImages');
var imagesTemp = sliderImages[0].getElementsByTagName('img');
images[sliders[i].id] = imagesTemp;
limits[sliders[i].id] = imagesTemp.length;
}
}
// advances a certain slider by the given amount (usually 1 or -1)
this.Slide = function(id, additive){
if(indices && id){
indices[id] = indices[id] + additive;
// Check limits
if(indices[id] < 0){
indices[id] = limits[id] - 1;
}
if(indices[id] >= limits[id]){
indices[id] = 0;
}
// alter img to be the new index
document.getElementById(id).getElementsByClassName('mainImage')[0].src = images[id][indices[id]].src;
}
}
}
for(var slider in sliders)
{
// here slider is the index of the array. to get the object use sliders[slider]
}
then you can use 'getElementsByClassName' function
edit
U have included the slider.js on the top of the html. So first it loads the the js and tries to access the elements which are not yet created..Move the tag to the bottom of the page.
sliderImages is an array of divs with classname sliderImages. there is only one that satisfies.
var sliderImages // is a array with 1 item.
// to get the images use sliderImages[0].getElementsByTagName('img');
change
this.Slide = new function(id, additive){
to
this.Slide = function(id, additive){ // otherwise it will be called when the page is loaded with undefined values.
onclick of the link call with quotes
Slider.Slide('main', 1)
You are using a methode I do not know (or you forgot the "s")
var sliderImages = slider.getElementByClassName('sliderImages');
I would use something like the code below. It is important sliderImages will be an array of anything that is of the class "silderImages"
var sliderImages =slider.getElementsByClassName("sliderImages")
Related
I'm making a slideshow in javascript for a class assignment and I have the slideshow working but it's not displaying the images. I can see that the image icon changes but the actual image is not showing.
<script type="text/javascript">
//put images in array
var pics = new Array();
pics[0] = new Image();
pics[0].src = "images/forest.jpg";
pics[1] = new Image();
pics[1].src = "images/mountains.jpg";
pics[2] = new Image();
pics[2].src = "images/nature.jpg";
pics[3] = new Image();
pics[3].src = "images/snowtops.jpg";
var index = 0; //start point
var piclength = pics.length - 1;
function slideshow() {
document.slide.src = pics[index];
if (index < piclength) {
index++;
}
else {
index = 0;
}
}
function slide() {
setInterval(slideshow, 3000);
}
</script>
<body onload="slide()">
<h1>Nature Photography</h1>
<main>
<section>
<p>I am an enthusiastic about nature photography. Here is a slideshow of my
works.</p>
<aside> <img id="myImage" src="images/forest.jpg" name="slide" width="95%">
</aside>
First, I would put the script tag after your HTML. This will allow you to cache DOM elements without waiting for the "DOMContentLoaded" event or the "load" (window) event to be fired.
Second, you should cache the "myImage" element. Something like const slider = document.getElementById('myImage').
Third, check your console. Maybe your image URLs are wrong? And make sure your HTML is valid. From what you posted, you are missing a lot of things (doctype, html/head tags, you didn't close body tag and similar)
Why doesn't the second (hawk) image appear when the button is clicked? It goes straight to the else statement showing the ant image.
<!DOCTYPE html>
<html>
<body>
<script>
function changeImg() {
if (document.getElementById("cycle").src == "fox.jpg") {
document.getElementById("cycle").src = "hawk.jpg";
} else {
document.getElementById("cycle").src = "ant.jpg";
}
}
</script>
<button onclick = "changeImg()">change image</button>
<img id ="cycle" src ="fox.jpg"/>
</body>
</html>
Please add your script tags at the end of the body to make sure that your dom is rendered before accessing any elements. (like in my example)
The problem with your code is, that you need to add a new if for every new image you add. As you noticed yourself, it becomes hard to understand and debug.
For something like cycling, use an array and modulo operation on the index of that array.
With this solution, you can add as many images to the images array as you like, without touching the code/logic;
<!DOCTYPE html>
<html>
<body>
<button onclick="changeImg()">change image</button>
<img id="cycle" />
<script>
var imageElement = document.getElementById("cycle");
var images = ["fox.jpg", "hawk.jpg", "ant.jpg"]; // add as many images as you want
var counter = 0;
imageElement.src = images[counter] // set the initial image
function changeImg() {
counter = (counter + 1) % images.length;
imageElement.src = images[counter];
}
</script>
</body>
</html>
document.getElementById("cycle").src always has full url of image (example:https://example.loc/example/fox.jpg) and this is not similar from fox.jpg.
You need try another solution.Try use
cycle.getAttribute('src')
Example code:
function changeImg() {
let cycle = document.getElementById("cycle");
console.log(cycle.src,cycle.getAttribute('src')); // show real value and taribute
if (cycle.getAttribute('src') == "fox.jpg") {
cycle.src = "hawk.jpg";
} else {cycle.src = "ant.jpg";
}
}
Use getAttribute('src') if you want to access the actual contents of the attribute. Otherwise you get the resolved URL.
var cycle = document.getElementById("cycle");
if (cycle.getAttribute('src') == "fox.jpg") {
cycle.src = "hawk.jpg";
} else {
cycle.src = "ant.jpg";
}
So I have this gallery page where I have multiple <img> tags with a unique picture. Clicking on the picture should take you to a another webpage with more info on that specific picture. Hence, all onclick()s are unique, depending on the src of the image.
Now, given the fact that all these <img> tags are virtually same save for picture, I decided to use JavaScript to make all of them in a loop, as seen below:
loadImageGalleryData
for (var i = 0; i < 21; i++) {
var imgSrc = "http://localhost:63342/Performance%20Task/Website/imgs/gallery/img/" + i + ".jpg";
console.log(imgSrc);
var imgDiv = document.createElement('div');
imgDiv.className = "img";
var descDiv = document.createElement('div');
descDiv.className = "desc";
var imgView = document.createElement('img');
imgView.src = imgSrc;
imgView.onclick = (function() {{openWebpage(imgSrc);}})();
console.log(imgSrc);
imgView.width = 300;
imgView.height = 200;
imgDiv.appendChild(imgView);
imgDiv.appendChild(descDiv);
document.getElementsByTagName('body')[0].appendChild(imgDiv);
}
The openWebpage() function in particular is this one:
openWebpage()
function openWebpage(src) {
var orig = window.document.title;
window.document.title = src;
open("imagePage.html");
}
The imagePage has a jscript which tells ITS OWN img and div tag to display the image, whose source is received from window.document.opener.title or somethign like that.
All the images get built, but the onclick() doesn't register. A peek in the developer mode in Chrome, and the images don't have an onlick() attribute.
Also, if I change this snippet of code:
imgView.onclick = (function() {{openWebpage(imgSrc);}})();
into this:
imgView.onclick = function() {openWebpage(imgSrc);};
The onlick() DOES register, but for every image simultaneously, with the src of the last image created. So when I click on Picture 1, it goes to the information of Picture 22. Same goes for every other picture. It's all the same info.
What am I doing wrong here?
EDIT: ADDITIONAL INFO
imagePage.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/imagePage.css"/>
<script src="jscript/imageData.js"></script>
<script src="jscript/loadImageData.js"></script>
</head>
<ul>
<li>Home</li>
<li>Gallery</li>
<li>About</li>
<li>Contact</li>
</ul>
<body>
<div>
<h1 id="imageTitle">TESTTITLE</h1>
</div>
<div>
<img id="imageView">
</div>
<div class="boxed" id="imageDesc">
</div>
</body>
</html>
loadImageData
window.onload = function() {
var imageSrc = opener.document.title;
var imageDesc = map[imageSrc];
var imageView = document.getElementById("imageView");
var imageDescView = document.getElementById("imageDesc");
imageView.src = imageSrc;
imageDescView.innerHTML = imageDesc;
};
On the last iteration of your loop, you set imgSrc to the url of picture 22. So on the click event your function openWebPage fires with that url in the argument.
Try this.
imgView.addEventListener("click", function() {openWebpage(imgSrc);});
as the title says I'm trying to figure out how to call this javascript function in my webpage. It's for my business, and the template is just a basic, free one. I'm sure for someone more experienced than me it's probably just a simple matter of formatting it correctly. Here's what I'm working with.
Code that goes in the HEAD portion of the webpage:
var theImages = new Array()
theImages[0] = 'splash1.jpg'
theImages[1] = 'splash2.jpg'
theImages[2] = 'splash3.jpg'
theImages[3] = 'splash4.jpg'
theImages[4] = 'splash5.jpg'
theImages[5] = 'splash6.jpg'
var j = 0
var p = theImages.length;
var preBuffer = new Array()
for (i = 0; i < p; i++){
preBuffer[i] = new Image()
preBuffer[i].src = theImages[i]
}
var whichImage = Math.round(Math.random()*(p-1));
function showImage(){
document.write('<img src="'+theImages[whichImage]+'">');
}
</script>
Now to call the function I use:
<SCRIPT LANGUAGE="JavaScript">
showImage();
</script>
Here's the page in which I'm trying to implement it:
http://coloradopp.com/index4.html
Instead of just displaying an image, I would like to call that function. Splash 1-6 are all the same size as the original image.
Here's the code snippet:
<div id="splash">
<img class="pic" src="images/splash1.jpg" width="870" height="374" alt="" />
</div>
As you can tell the page calls on a style sheet (style.css) for all the formatting.
Can anyone offer any tips on how to make this work? From what I've gathered, one cannot implement javascript into css sheets. Thanks in advance.
Do something like this:
showImage() {
var theImages = [ 'splash1.jpg', 'splash2.jpg', 'splash3.jpg', 'splash4.jpg', 'splash4.jpg' ];
var img = theImages[Math.round(Math.random() * (theImages.length - 1))];
document.getElementById('splash').innerHTML = '<img src="' + img + '">');
}
First move your javascript code inside the function something like:
function showImage(){ ...your code goes here...}
And then you can initiate the function on page load like this:
<body onload="showImage()">
You can set the images dynamically as background-image and place something like this
<script>
document.write('<style>#splash{ background-image:url(\'images/splash'+Math.round(Math.random()*5+1)+'.jpg\');}</style>');
</script>
at the head of your page. With this solution you have to set fix dimensions for your div tag (870x374)
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