Can someone explain this piece of code to me - javascript

What does the strings in this code mean, Its part of a traffic light script and I dont know what each of the lines do.
var index = 0;
var variableLen = variable.length;
function nextvariableClick() {
index++;
if (index == variableLen)
index = 0;
var image = document.getElementById('starting_light');
image.src = variable[index];

It appears that variable is an array that stores references (URIs, or paths) to images, that is fed to the src attribute of an image element, <img>. The script simple does the following logic:
When the function is fired, it increments index by 1
If index is equal to the number of images, you return it to 0 (basically "cycling" through the array
You set the image source to the nth element of the variable array, by the index index
An intelligent guess would be that this is a image cycling function. When nextvariableClick is called it cycles through a list of images in the order they appear in the variable array.
Since the script is so simple, the best way to see what it does is to construct a functional code snippet:
// Define dummy image references
var variable = [
'https://placehold.it/500x300/e41a1c/ffffff',
'https://placehold.it/500x300/377eb8/ffffff',
'https://placehold.it/500x300/4daf4a/ffffff',
'https://placehold.it/500x300/984ea3/ffffff',
'https://placehold.it/500x300/ff7f00/ffffff'
];
/* Start of code you have provided */
var index = 0;
var variableLen = variable.length;
function nextvariableClick() {
index++;
if (index == variableLen)
index = 0;
var image = document.getElementById('starting_light');
image.src = variable[index];
}
/* End of code you have provided */
// We execute the function to start initialise it, and set a starting image
nextvariableClick();
window.setInterval(nextvariableClick, 1000);
<p>The function is called at runtime, and called every 1s. You should see cycling of image sources.</p>
<img id="starting_light" src="" />

Related

Why I cannot refer to the images array?

i try to swap the images continuously from the array, but the code does not get the image source, why this happened?
function nextPic(){
var picCollection =["pic_bulbon.gif","pic_bulboff.gif"];
for(i=0; i<picCollection.length; i++){
document.getElementById("myImage").src = picCollection[i].src;
}
}
function triggers(){
setInterval(nextPic,500);
}
Might be Your code should be
var picCollection =["pic_bulbon.gif","pic_bulboff.gif"];
var i=0;
var interval;
function nextPic(){
document.getElementById("myImage").src = picCollection[i];
// if you want to repeat for show image again and again tehn use below line
i= (i+1) % picCollection.length;
// if you want not to repeat again then use below line
// if(i+1>=picCollection.length) clearInterval(interval);
}
function triggers(){
interval=setInterval(nextPic,500);
}
Here you have to define the image name array in global which should be accessible in all desire functions. It is good if you store setInterval reference in variable and clear it by clearInterval.
You need create a global variable for picture number. Then use that inside callback passed to setInterval. The above code will only show the last image of array.
let pic = 0;
const picCollection =["pic_bulbon.gif","pic_bulboff.gif"];
function nextPic(){
document.getElementById("myImage").src = picCollection[pic];
console.log("The pic shown is ", picCollection[pic])
pic++;
if(pic === picCollection.length){
pic = 0;
}
}
function triggers(){
setInterval(nextPic,500);
}
triggers()
<img id="myImage"/>
There is no src key in your arrat. You can just use
document.getElementById("myImage").src = picCollection[i];
Your code should look something similar to below
function nextPic(){
var picCollection = ["./pic_bulbon.gif","./pic_bulboff.gif"];
for(i = 0; i < picCollection.length; i++){
document.getElementById("myImage").src = picCollection[i];
}
}
"./pic_bulbon.gif" may need to change based off of your file structure and where you are storing the gif you are trying to access.
If you could supply a screenshot of your file structure I could tell you exactly what you need
The other issue you are having is your trying to access picCollection[i].src
but picCollection[i] is only an array of string not objects.

how to set anchor tag individual item to an array images

I added dynamic images display in specific div but I could not set link (a href)for each image individually.Could you help me?
Here is my script which I used but not working:
<script>
var i;
var timerid = 0;
var images = ["img1.jpg",
"img2.jpg",
"img3.jpg","img4.jpg"];
var countimages = 0;
function startTime()
{
if(timerid)
{
timerid = 0;
}
var tDate = new Date();
if(countimages == images.length)
{
countimages = 0;
}
if(tDate.getSeconds() % 4 == 0)
{
document.getElementById("img1").src = images[countimages];
}
countimages++;
timerid = setTimeout("startTime()", 800);
switch(countimages){
case images[0]: images[0].setAttribute('href',"dhow-cruise-creek-dubai.html");
images[0].innerHTML="dhow-cruise-creek-dubai.html";
document.appendChild(images[0]);
break;
case images[1]: images[1].setAttribute('href',"dhow-cruise-creek-dubai.html");
images[1].innerHTML="dhow-cruise-creek-dubai.html";
document.appendChild(images[1]);
break;
case images[2]: images[2].setAttribute('href',"dhow-cruise-creek-dubai.html");
images[2].innerHTML="dhow-cruise-creek-dubai.html";
document.appendChild(images[2]);
}
}
</script>
Several things here:
1: Your function is incrementing an array index (countimages) and wrapping it when it reaches the end of the index range of the array it is intended to subscript (images). You currently have two lines of code to accomplish this task, which are separated by another line of code. The two lines are
countimages++;
which is executed immediately after the subscripting of the aforementioned array, and
if (countimages == images.length) countimages = 0;
which is executed just before.
It would be much better, both for human readability and for code simplicity, to locate these two operations at the same spot in the code, because together they represent a single isolated and inseparable action. Also, the length cap can be applied more idiomatically and concisely using a modulus operation. The end result is you should delete the second line I showed above, and change the first to this:
countimages = (countimages+1)%images.length;
2: You are incrementing countimages in every evaluation of the function. This is happening even when the modulus test fails, and therefore the image is not changed. I suspect this is a mistake. Therefore I would change
if (tDate.getSeconds()%4 == 0) {
document.getElementById("img1").src = images[countimages];
}
countimages = (countimages+1)%images.length;
to
if (tDate.getSeconds()%4 == 0) {
document.getElementById("img1").src = images[countimages];
countimages = (countimages+1)%images.length;
}
3: I don't see any point in zeroing the timerid variable at the start of the function. It will inevitably be overwritten by the return value of the setTimeout() call later in the function. So the statement
if (timerid) timerid = 0;
should be removed.
4: The setTimeout() function supports two overloads. The first argument to the function can be either a function reference or a string of code. The former is preferable, both for performance and security reasons. So you should change
timerid = setTimeout('startTime()',800);
to
timerid = setTimeout(startTime,800);
But see below.
5: The setInterval() function is preferable to setTimeout() for a continuously repeating function call. Under this design, the function does not even need to reference timerid, or concern itself with its own invocation. We can just call setInterval() once during page load to start the chain of calls.
6: The switch statement at the end of the function is switching on countimages, which is of numeric type, against various elements of the images array specified by literal index, i.e. images[0], images[1], and images[2]. The images array holds string values representing image URLs, not numbers. So obviously this switch statement is incorrect. Also, the final element (images[3]) is omitted, which may be a mistake. If your intention was to switch on the indexes of the array, your case values should be 0, 1, etc. But see below.
7: Each of the case branches in the switch statement is identical to the others, except for the literal index. That is, they all follow this pattern, where i is the literal index:
case images[i]:
images[i].setAttribute('href','dhow-cruise-creek-dubai.html');
images[i].innerHTML = 'dhow-cruise-creek-dubai.html';
document.appendChild(images[i]);
break;
except that the final break; statement is missing from the final case branch.
This is an example of duplicate code that should be simplified by proper parameterization; in this case, parameterizing on i. Observe that the literal index always corresponds to the current value of countimages, so that is our i. In other words, the entire switch statement can be replaced with the following, again, assuming you wanted to switch on the indexes of the array:
images[countimages].setAttribute('href','dhow-cruise-creek-dubai.html');
images[countimages].innerHTML = 'dhow-cruise-creek-dubai.html';
document.appendChild(images[countimages]);
But see below.
8: The above lines of code are incorrect because they appear to be treating images as an array of elements, when it is in fact an array of strings. You cannot call setAttribute() on a string, nor is there a meaningful innerHTML property of strings, and you cannot append strings to the DOM tree using appendChild() (because strings do not implement the interface Node).
This brings us to your question. Your code seems to be trying to append a new anchor link element at the bottom of the entire document every time the image is advanced, but I doubt that's what you really want. I'm guessing you want to advance a single fixed anchor link element to a new href attribute and innerHTML content corresponding to the new image. To do this, I would recommend you change the array of strings to an array of hashes and store the href and innerHTML alongside the image URL using three key/value pairs.
9: The design of advancing the image and link during every multiple of 4 seconds, but checking for such a condition every 800 milliseconds, is very questionable. In some cases the check will be true twice in a multiple-of-4 second, in some cases it will be true only once during the multiple-of-4 second. And the moments the function is executed will drift, since the interval duration is not guaranteed to be exact. This would lead to some strange behavior. I suppose you may want this behavior, but I'm doubtful. Instead, I suspect what you're going for is for the image and link to advance once every 4 seconds. You can achieve this by removing the entire time test and just setting the interval to 4 seconds, that is, 4000 milliseconds.
Hence, we have:
var imageSpecs = [
{imageURL:'https://www.gravatar.com/avatar/8062178f34c7107a67ef00b681921287?s=328&d=identicon&r=PG&f=1',linkRef:'#1',innerHTML:'one' },
{imageURL:'https://www.gravatar.com/avatar/b57bf879dbb25c837c2e2ae730cab2cc?s=328&d=identicon&r=PG&f=1',linkRef:'#2',innerHTML:'two' },
{imageURL:'https://www.gravatar.com/avatar/166ed38dafa219c53980bb06cfce40b6?s=328&d=identicon&r=PG&f=1',linkRef:'#3',innerHTML:'three'},
{imageURL:'https://www.gravatar.com/avatar/0c8ea1549ebeff7bab9a282c4b965fa4?s=328&d=identicon&r=PG', linkRef:'#4',innerHTML:'four' },
];
// preload all images
for (let imageSpec in imageSpecs) {
let img = new Image();
img.src = imageSpec.imageURL;
} // end for
var nextImageSpecIndex = 0;
function advanceImageSpec() {
let imageSpec = imageSpecs[nextImageSpecIndex];
let imgElem = document.getElementById('img1');
imgElem.setAttribute('src',imageSpec.imageURL);
let linkElem = document.getElementById('link1');
linkElem.setAttribute('href',imageSpec.linkRef);
linkElem.innerHTML = imageSpec.innerHTML;
nextImageSpecIndex = (nextImageSpecIndex+1)%imageSpecs.length;
} // end advanceImageSpec()
var timerId = setInterval(advanceImageSpec,4000);
advanceImageSpec(); // immediate call to display first image immediately
#img1 { width:100px; height:100px; }
<div>
<img id="img1"/><br/>
<a id="link1"></a>
</div>
I'm not really sure what you're trying to do, but I assume you want the image to be a link that goes somewhere. Try putting a link tag around the img element with id img1 and giving that link tag the id `link1' like so:
<img id="img1"/>
Then change the script to this:
<script>
var i;
var timerid = 0;
var images = ["img1.jpg",
"img2.jpg",
"img3.jpg"];
var links = ["dhow-cruise-creek-dubai.html",
"dhow-cruise-creek-dubai.html",
"dhow-cruise-creek-dubai.html"];
var countimages = 0;
function startTime()
{
if(timerid)
{
timerid = 0;
}
var tDate = new Date();
if(countimages == images.length)
{
countimages = 0;
}
if(tDate.getSeconds() % 4 == 0)
{
document.getElementById("link1").href = links[countimages];
document.getElementById("img1").src = images[countimages];
}
countimages++;
timerid = setTimeout("startTime()", 800);
}
</script>
There's more that could be improved, but I'm sure you get where I'm going.

Is it possible to store both a number and name for a value in an array?

I'm currently writing a function to pre-load all images used by a small game to draw on an array. Currently I store the paths to the sources in two different array to solve this, but would it be possible to have an array that can use both a number i or a name n when getting a value from it? This would help it be easier to use the value to assign as a search on my pictures later on, and using gameimage[153] as a source value doesn't look very tidy and I'd rather use gameimage["snakehead"]
current code example:
//add images to the gameimages array to be loaded before gamestart
//add the snake images
var gameimages = [];
gameimages.push("snake30px.png", "snake30pxdown.png", "snake30pxup.png","snake30pxauch.png");
var gameimagesnumber = gameimages.length;
//start the startGame() when all images in the gameimages array is loaded, to avoid albino snake and lack of stuff to crash into
//NOTE: This is kinda "hackish" as the images is just loaded to make sure it is cached in browser...
//they're not actually used, but seem to have the same effect :x
for(var i = 0; i < gameimagesnumber; i++){
console.log("Loading " + gameimages[i]);
var image = new Image();
image.onload = function(){
//add the image in gameimagesnames for easier use in the code when needed
gameimagesnames[this.src.substring(this.src.lastIndexOf("/") + 1,this.src.length - 4)] = this.src;
checkforgamestart();
};
image.src = "images/" + gameimages[i];
}
//checking for gamestart
function checkforgamestart(){
if(gameimagesnumber > 1) gameimagesnumber--;
else startGame();
}
Absolutely!
In JS, you can make an array of any data type. You also have access to objects. So let's combine those.
var obj = {
name: 'a test name',
value: 1
}
var array = [obj];
array[0].name; // == 'a test name'
array[0].value; // == 1
var anotherObj = {
name: 'another name',
value: 7
}
array.push(anotherObj);
array[1].name; // == 'another name'
array[1].value; // == 7
Reading your question in more detail, I see you're also looking to have a get method that can pull from either value. That's a bit trickier.
The other answer provided will do this, but stores the data in two separate locations in the object (not an array), and also loses the array prototypes.
To better solve this within the Array class type, let's just take advantage of Array.filter!
array.filter(function(item) { return item.name === 'another name' })
This will provide you with a subArray of elements that meet whatever criteria you provide within the given callback function. In this case, using my array above, it would pass back an array with one element in it; anotherObj.
If you want to access by both, use object
var arr = {}
arr[1] = arr['myKey'] = 'myValue'
Then you can access them both by number and by key.

How to avoid reference to last index in a for loop while sending index as parameter for a function?

I have written this code:
function(targetSliderObject, images){
// create thumbs container
var thumbsContainer = $("<div></div>").addClass(defaultOptions.thumbsContainerClass);
// add thumbs
for(i in images)
{
thumb = $("<img />").addClass(defaultOptions.thumbItemClass).addClass(i);
thumb.attr("src", images[i]);
thumb.click(function(){
methods.slideNext(targetSliderObject, i);
});
thumb.appendTo(thumbsContainer);
}
// add thumbs container to container
targetSliderObject.append(thumbsContainer);
}
What I intend to do is calling method.slideNext() with a different number each time, but insted I get to send a reference to i as parameter for the function which, in the end, is the last index of my array for all my thumbs.
What trick can I use to accomplish what I want ?
Thank you!
"Anchor" the value of i:
(function(i) {
// code that uses i
})(i);

Get a limit on arrays (Javascript)

I've a problem with set a limit into my own lightbox for a gallery
<script>
var imagenumber = 0;
function btnleft(){
load = imagenumber-=1;
document.getElementById('lightboxcontent').innerHTML=imagelist[load];
}
function btnright(){
load = imagenumber+=1;
if (load==undefined){load=imagenumber-=1}
document.getElementById('lightboxcontent').innerHTML=imagelist[load];
}
</script>
Then the array
var imagelist=new Array(); // regular array (add an optional integer
imagelist[0]="image1.jpg"; // argument to control array's size)
imagelist[1]="image2.jpg";
imagelist[2]="image3.jpg";
When I click more then 3 times on the next button I got the error-message "undefined".
How should I do to get a limit on my arrays?
Try it with
function btnleft(){
var load = imagelist[imagenumber-=1];
if (load) // imagenumber in array boundaries
document.getElementById('lightboxcontent').innerHTML = load;
else
imagenumber = 0;
}
function btnright(){
var load = imagelist[imagenumber+=1];
if (load) // imagenumber in array boundaries
document.getElementById('lightboxcontent').innerHTML = load;
else
imagenumber = imagelist.length-1;
}
Yet, Arrays in Javascript have no limited size, they are more like (infinite) lists. You can hardly set a limit on their length - espcially not with the constructor, whose number argument is just for initialisation purposes.
You can use the length property of an array to check whether your index is in the array boundaries: i >= 0 && i < arr.length. My code just checks whether there is an item at that index (as your second function seems to intend, too) and resets the index otherwise.
I assume that clicking on the "next button" calls the btnright() function.
If that is the case then you are testing the wrong value for undefined. You could rewrite your function as:
function btnright(){
load = imagenumber += 1;
// Test the value at the index of the array, not your index variable.
if (imagelist[load] === undefined) {
load = imagenumber-= 1;
}
document.getElementById('lightboxcontent').innerHTML = imagelist[load];
}
Stylistically this is still no the best. Your load variable is not required since its value always duplicates imagenumber. You could refactor the function such:
function btnright() {
// If we have a new array value do something.
if (imagelist[imagenumber + 1] !== undefined) {
// Increment the index and load the new image.
document.getElementById('lightboxcontent').innerHTML = imagelist[++imagenumber];
}
}
function btnleft() {
// If we're not on the first image do something.
if (imagenumber !== 0) {
// Decrement the index and load the new image.
document.getElementById('lightboxcontent').innerHTML = imagelist[--imagenumber];
}
}

Categories