I am trying to learn JavaScript and have made a website which randomizes gifs onclick from an array.
What I would like to do now is insert a while loop so that it will compare the currentgif to the next randomized image so no duplicates are shown but I can't quite figure out what I am doing wrong, most likely a syntax issue.
HTML
<!DOCTYPE html>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<html>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="js/rand.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css">
<head>
<title>Randomizer</title>
</head>
<body>
<p>This image is random</p>
<a href="#" class="click">
<section>
<img>
<script>
getRandomImage()
</script>
</img>
</section>
</a>
</body>
</html>
JavaScript
var randomImage = new Array();
randomImage[0] = "images/1.gif";
randomImage[1] = "images/2.gif";
randomImage[2] = "images/3.gif";
function getRandomImage() {
var number = Math.floor(Math.random()*randomImage.length);
document.write('<img src="'+randomImage[number]+'" />');
}
$(function() {
$('a.click').click(function(e) {
e.preventDefault();
var number = Math.floor(Math.random()*randomImage.length);
$(this).html('<img src="'+randomImage[number]+'" />');
});
});
You first need to get which image it is:
function returnImgNum(){
var imgNum = parseInt($('img').attr('src').split("/")[1].replace('.gif', ""));
return imgNum;
}
Then make a loopable function (or just make a while loop, I like doing it this way)
function placeRand(number){
if(number != returnImgNum()){
document.write('<img src="'+randomImage[number]+'" />');
} else {
placeRand(number){
}
}
Then add that comparator loop to your function:
function getRandomImage() {
var number = Math.floor(Math.random()*randomImage.length);
placeRand(number);
}
var random_images_array = ['smile.gif', 'frown.gif', 'grim.gif', 'bomb.gif'];
function getRandomImage(imgAr, path) {
path = path || 'images/'; // default path here
var num = Math.floor( Math.random() * imgAr.length );
var img = imgAr[ num ];
var imgStr = '<img src="' + path + img + '" alt = "">';
document.write(imgStr); document.close();
}
Check out this link. It tells you everything you need to know.
http://www.dyn-web.com/code/basics/random_image/random_img_js.php
Create array, put inside all image names (or their indexes if it's better for you) and then use something like this:
var images = ["/first.png", "/second.png", "/third.png", "/fourth.png", "/fifth.png"];
function takeImage() {
// if there is no more images in array, do something or return placeholder image
//if (!images.length) doSomething();
var image = images.splice(Math.floor(Math.random() * images.length), 1);
return image[0];
}
Basically, this function on each call will return one random image name (or index if you want) until there will be no images left in this array.
Simple, you save the last image out of the function. This makes a global variable. A global variable is a variable that exists in all functions, as a local variable only exists in the function itself (other functions cant use it).
// Define it outside of the function so the next time the called
// function gets it still has a value:
var lastNumber=0;
var imagesLength = randomImage.length; // don't recalc the amount of images every time
function getRandomImage(){
var number=0; // start a local variable
while( number == lastNumber){
number = Math.floor(Math.random()*imagesLength );
}
document.write('<img src="'+randomImage[number]+'" />');
}
To expand a bit on the local/global variables, lastNumber is global and can therefor be accessed in the function. var number however is local, it only exists in the function, console.log(number); outside the function would be undefined
To make a suggestion for improvement, document.write is best to be avoided. Browsers don't like them (*can't find doc's to support, feel free to edit), pre-create an image, even if its blank:
<img id="RandomImage" src="transparant.png" />
Now you make a global variable (this can only be done if the javascript is loaded after the image in the source, or with a document ready) to store the image, and use that:
// save reference to image, global (before the function):
var Image2Random = document.getElementById('RandomImage');
// place this instead of the document write.
Image2Random.src = randomImage[number];
This will be a lot faster. Javascript now knows what image to change, it doesn't have to create a new one every call (inserting elements to the DOM is expensive in resources), and the .src is really fast to change just the source.
Related
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";
}
I have an image - image1.png. When I click a button the first time, I want it to change to image2.png. When I click the button for a second time, I want it to change to another image, image3.png.
So far I've got it to change to image2 perfectly, was easy enough. I'm just stuck finding a way to change it a second time.
HTML:
<img id="image" src="image1.png"/>
<button onclick=changeImage()>Click me!</button>
JavaScript:
function changeImage(){
document.getElementById("image").src="image2.png";
}
I'm aware I can change the image source with HTML within the button code, but I believe it'll be cleaner with a JS function. I'm open to all solutions though.
You'll need a counter to bump up the image number. Just set the maxCounter variable to the highest image number you plan to use.
Also, note that this code removes the inline HTML event handler, which is a very outdated way of hooking HTML up to JavaScript. It is not recommended because it actually creates a global wrapper function around your callback code and doesn't follow the W3C DOM Level 2 event handling standards. It also doesn't follow the "separation of concerns" methodology for web development. It's must better to use .addEventListener to hook up your DOM elements to events.
// Wait until the document is fully loaded...,
window.addEventListener("load", function(){
// Now, it's safe to scan the DOM for the elements needed
var b = document.getElementById("btnChange");
var i = document.getElementById("image");
var imgCounter = 2; // Initial value to start with
var maxCounter = 3; // Maximum value used
// Wire the button up to a click event handler:
b.addEventListener("click", function(){
// If we haven't reached the last image yet...
if(imgCounter <= maxCounter){
i.src = "image" + imgCounter + ".png";
console.log(i.src);
imgCounter++;
}
});
}); // End of window.addEventListener()
<img id="image" src="image1.png">
<button id="btnChange">Click me!</button>
For achieve your scenario we have to use of counter flag to assign a next image. so we can go throw it.
We can make it more simple
var cnt=1;
function changeImage(){
cnt++;
document.getElementById("image").src= = "image" + cnt + ".png";
}
try this
function changeImage(){
var img = document.getElementById("image");
img.src = img.src == 'image1.png' ? "image2.png" : "image3.png";
}
Just use an if statement to determine what the image's source currently is, like so:
function changeImage(){
var imageSource = document.getElementById("image").src;
if (imageSource == "image1.png"){
imageSource = "image2.png";
}
else if (imageSource == "image2.png"){
imageSource = "image3.png";
}
else {
imageSource = "image1.png";
}
}
This should make the image rotate between 3 different image files (image1.png, image2.png and image3.png). Bear in mind this will only work if you have a finite number of image files that you want to rotate through, otherwise you'd be better off using counters.
Hope this helps.
Check the below code if you make it as a cyclic:
JS
var imgArray = ["image1.png", "image2.png", "image3.png"];
function changeImage(){
var img = document.getElementById("image").src.split("/"),
src = img[img.length-1];
idx = imgArray.indexOf(src);
if(idx == imgArray.length - 1) {
idx = 0;
}
else{
idx++;
}
document.getElementById("image").src = imgArray[idx];
}
html
<button onclick=changeImage();>Click me!</button>
function changeImage(){
document.getElementById("image").attr("src","image2.png");
}
First Question on this site so I hope I do this right! I have a javascript function that I want to display an image (image1.jpg) when the page is loaded, and then every 2 seconds change the image by going through the loop. However only the first image is showing so it seems the JS function is not being called. Can anyone tell me if I am doing something wrong here because it looks fine to me so can't understand why it won't work. Thanks
<html>
<head>
<script type="text/javascript">
function displayImages(){
var images = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
var i = 1;
if(i>images.length-1){
this.src=images[0];
i=1;
}else{
this.src=images[i];
i++;
}
setTimeout("displayImages()", 2000);
}
</script>
</head>
<body onload="displayImages();">
<img id="myButton" src="image1.jpg" />
</body>
</html>
You need to move the line
var i = 1;
outside the displayImages -function or it will start from one each time!
EDIT: But using a global variable is not considered good practice, so you could use closures instead. Also as noted in other answers, you are referencing this which does not refer to the image object, so I corrected that as well as simplified the logic a bit:
<script type="text/javascript">
function displayImages( i ){
var images = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
var img = document.getElementById('myButton');
img.src = images[i];
i = (i+1) % images.length;
setTimeout( function() { displayImages(i); }, 2000 );
}
</script>
<body onload="displayImages(0);">
You need the value of i to be available at each call, it can be kept in a closure using something like:
var displayImages = (function() {
var i = 0;
var images = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
return function() {
document.getElementById('myButton').src = images[i++ % images.length];
setTimeout(displayImages, 2000);
}
}());
Also, since this isn't set by the call, it will default to the global/window object, so you need to get a reference to the image. That too could be held in a closure.
There are a couple of issues here that are stopping this from working.
First the var i = 1; needs to be moved outside the function to make the increment work. Also note that the first item in an array is 0, not 1.
Second you're using this to refer to change the image's src, but this is not a reference to the image. The best thing to do is use here is document.getElementById instead.
var i, button;
i = 0;
button = document.getElementById('myButton');
function displayImages() {
var images = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
if (i > images.length - 1){
button.src = images[0];
i = 0;
}
else{
button.src = images[i];
i++;
}
setTimeout(displayImages, 2000);
}
There's still some room for improvement and optimisation, but this should work.
You are reinitializing value of i every time, so change the following:
function displayImages(){
var images = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
if(!displayImages.i || displayImages.i >= images.length) displayImages.i = 0;
document.getElementById('myButton').src = images[displayImages.i];
displayImages.i++;
setTimeout(displayImages, 2000);
}
Functions are objects in JS and because of this:
you can pass them by reference and not as a string improving performance and readability
you can add fields and even methods to a function object like I did with displayImages.i
EDIT: I've realized that there was one more issue src was not being set for button.
Now I've fixed this and also made other improvements.
Here is the fiddle http://jsfiddle.net/aD4Kj/3/ Only image URLs changed to actually show something.
<script type="text/javascript">
var i = 1;
function displayImages(){
.......
........
Just make "i" Global. so that whenever displayImages being called it will not redefined to 1.
<html>
<head>
<script type="text/javascript">
var i = 1;
function displayImages() {
var images = ['img1.jpg', 'img2.jpg', 'img3.jpg'];
i++;
if (i > images.length - 1) {
i = 0;
}
$('#myButton').attr('src', images[i]);
setTimeout(displayImages, 2000);
}
</script></head>
<body onload="displayImages();">
<img id="myButton" src="img1.jpg" height="150px" width="150px"/>
</body>
</html>
Make i global.
here your are using displayImages() recursively and variable for index i. e i assign as local variable in function displayImages() , you need to assign it global variable i.e outside of the function also initialize it from i=0 as array index always start from 0,
your code become
var i = 0; // assign i global
function displayImages(){
var images = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
if(i>images.length-1){
document.getElementById('myButton').src=images[0]; //get img by id
i=0; // to get first image
}
else{
document.getElementById('myButton').src=images[i]; //get img by id
i++;
}
setTimeout("displayImages()", 2000);
}
I'm working on making a JS script that will go in the header div and display a few pictures. I looked into JQuery Cycle, but it was out of my league. The code I wrote below freezes the browser, should I be using the for loop with the timer var?
<script type="text/JavaScript" language="JavaScript">
var timer;
for (timer = 0; timer < 11; timer++) {
if (timer = 0) {
document.write('<img src="images/one.png">');
}
if (timer = 5) {
document.write('<img src="images/two.png">');
}
if (timer = 10) {
document.write('<img src="images/three.png">');
}
}
</script>
Thanks!
Assuming you want a script to rotate images and not just write them to the page as your code will do, you can use something like this:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="target"></div>
<script>
var ary = ["images/one.png","images/two.png","images/three.png"];
var target = document.getElementById("target");
setInterval(function(){
target.innerHTML = "<img src=\""+ary[0]+"\" />";
ary.push(ary.shift());
},2000);
</script>
</body>
</html>
Of course the above code has no effects (like fading) which jQuery will give yous, but it also doesn't require loading the entire jQuery library for something so basic.
How about just running the script after the page loads?
<script>
// in <head> //
function load() {
var headDiv = document.getElementById("head");
var images = ["images/one.png", "images/two.png"];
for(var i = 0; i<images.length; i++) {
image = document.createElement("img");
image.src = images[i];
headDiv.appendChild(image);
}
}
</script>
Then use <body onload="load();"> to run the script.
Edit
To add in a delay loading images, I rewrote the code:
<script>
// in <head> //
var displayOnLoad = true; // Set to true to load the first image when the script runs, otherwise set to false to delay before loading the first image
var delay = 2.5; // seconds to delay between loading images
function loadImage(url) {
image = document.createElement("img");
image.src = images[i];
headDiv.appendChild(image);
}
function load() {
var headDiv = document.getElementById("head");
var images = ["images/one.png", "images/two.png"];
for(var i = 0; i<images.length; i++) {
setTimeout(loadImage(images[i]), (i+displayOnLoad)*(delay*1000));
}
}
</script>
Set displayOnLoad = false; if you want to wait the specified delay before loading the first image. The delay is set in seconds. I recommend waiting over a single second between images, as they may take some time to download (depending on the user's internet speed).
As with the first snippet, I haven't tested the code, so please tell me if an error occurs, and I will take a look.
Since you used the jquery tag on your question, I assume you are OK with using jQuery. In which case, you can do something like this:
In your static HTML, include the img tag and set its id to something (in my example, it's set to myImg) and set its src attribute to the first image, e.g.:
<img id="myImg" src="images/one.png">
Next, use jQuery to delay execution of your script until the page has finished loading, then use setTimeout to create a further delay so that the user can actually spend a few seconds looking at the image before it changes:
<script>
var imgTimeoutMsecs = 5000; // Five seconds between image cycles
$(function() {
// Document is ready
setTimeout(function() {
// We will get here after the first timer expires.
// Change the image src property of the existing img element.
$("#myImg").prop("src", "images/two.png");
setTimeout(function() {
// We will get here after the second, nested, timer expires.
// Again, change the image src property of the existing img element.
$("#myImg").prop("src", "images/three.png");
}, imgTimeoutMsecs);
}, imgTimeoutMsecs);
});
</script>
Of course, that approach doesn't scale very well, so if you are using more than three images total, you want to modify the approach to something like this:
var imgTimeoutMsecs = 5000; // Five seconds between image cycles
// Array of img src attributes.
var images = [
"images/one.png",
"images/two.png",
"images/three.png",
"images/four.png",
"images/five.png",
];
// Index into images array.
var iCurrentImage = 0;
function cycleImage() {
// Increment to the next image, or wrap around.
if (iCurrentImage >= images.length) {
iCurrentImage = 0;
}
else {
iCurrentImage += 1;
}
$("#myImg").prop("src", images[iCurrentImage]);
// Reset the timer.
setTimeout(cycleImages, imgTimeoutMsecs);
}
$(function() {
// Document is ready.
// Cycle images for as long as the page is loaded.
setTimeout(cycleImages, imgTimeoutMsecs);
});
There are many improvements that can be made to that example. For instance, you could slightly simplify this code by using setInterval instead of setTimer.
The code you've provided simply iterates through the for loop, writing the images to the browser as it does so. I suggest you take a look at JavaScript setTimeout function.
JS Timing
Hi sorry if the name of my question is not correct.
i am trying to create an image rotator, but i would like to be able to re-use it more than once in a page, so i am trying to create it as an object/class.
I have about 5 or 6 images on a page.
i would like to have each image as a rotator, displaying a new image every 2 seconds or so.
<img src="uploads/Range_Images/p6-7.jpg" class="myclass1"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass2"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass3"/>
<script type=text/javascript>
$Rotator1 = new imageRotator1('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass1');
setInterval($Rotator1.rotateImage(), 1000);
$Rotator2 = new imageRotator1('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass2');
setInterval($Rotator2.rotateImage(), 1000);
$Rotator3 = new imageRotator1('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass3');
setInterval($Rotator3.rotateImage(), 1000);
</script>
Thats the code i am using to display the images and to create an instance of my rotator class
I can think of a few issues i am not sure of the answers too despite googling for hours!
Firstly here is my code (i am mixing javascript with jquery which is probably where i am going wrong to start with...
<script type="text/javascript">
$(document).ready(function(){ // maybe this should not be used when creating a object/class???
// i want to use this function as a class if possible
function imageRotator($images_str, $class){
// set up the vars
this.myImg = $images_str; //string containing image names
this.myClass = $class; //string containing class of image to change
this.imagelist = this.myImg.split(':'); //split the image string into an array
this.index = 1; // set the current index count
// maybe this is where i am going wrong, as in jquery $(this) refers to the current selector and maybe this.myclass (from from the imageRotator object does not work??
// is it possible to reference a value from an object in jquery?
function prototype.rotateImage(){
$(this.myclass).fadeOut('fast', function(){
$(this).attr('src', this.imagelist[this.index]);
$(this).fadeIn('fast', function(){
if (this.index == this.imagelist.length-1){
this.index = 0;
}else{
this.index++;
};
});
});
};
};
});
</script>
I am by no means an expert in programming, but i am sure this should be possible somehow.
any help would be much appreciated :P
update:
ok have modified the code slightly as per castrohenges reply:
<script type="text/javascript">
$(document).ready(function(){
var imageRotator = function($images_str, $class){
// set up the vars
this.myImg = $images_str; //string containing image names
this.myClass = $class; //string containing class of image to change
this.imagelist = this.myImg.split(':'); //split the image string into an array
this.index = 1; // set the current index count
};
function imageRotator.prototype.rotateImage(){
$(this.myclass).fadeOut('fast', function(){
$(this).attr('src', this.imagelist[this.index]);
$(this).fadeIn('fast', function(){
if (this.index == this.imagelist.length-1){
this.index = 0;
}else{
this.index++;
};
});
});
};
});
</script>
</head>
<body>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass1"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass2"/>
<img src="uploads/Range_Images/p6-7.jpg" class="myclass3"/>
<script type=text/javascript>
$(document).ready(function(){
$Rotator1 = new imageRotator('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass1');
setInterval($Rotator1.rotateImage(), 1000);
$Rotator2 = new imageRotator('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass2');
setInterval($Rotator2.rotateImage(), 1000);
$Rotator3 = new imageRotator('p12-13.jpg:p18-19.jpg:p4-5.jpg:p8-9.jpg:p6-7.jpg:p10-11.jpg:p14-15.jpg:p16-17.jpg', '.myclass3');
setInterval($Rotator3.rotateImage(), 1000);
});
</script>
</body>
i was getting an error: image rotator not defined on line 45
hence changing it to
var imageRotator = function($images_str, $class){....};
but the error is still there?
will try recreating this script following the plug-in guidelines and see where i get....
If you want to use prototyping you need to change
function prototype.rotateImage(){
and place it outside of the imageRotator function. Like so:
function imageRotator($images_str, $class){ ... }
imageRotator.prototype.rotateImage = function() { ... }
Alternatively you could also take a look at this jQuery plugin http://malsup.com/jquery/cycle/ - this is the first one I found, but I'm sure there will be more out there.
If you do want to use your own custom code I recommend wrapping it up as a jQuery plugin - http://docs.jquery.com/Plugins/Authoring. That way you don't have to worry to much about class architecture and everything will be nicely encapsulated in the jQuery object.