We will initially complete some of the activities from the previous lecture
Also, we apologize for the readings for today. It wasn't what we intended, and we didn't discover the trouble until too late. We'll rewrite them and re-post.
By the end of today, you'll have had some experience with using loops to process simple lists of numbers. You'll see how functions and event handlers can make for pages with interactive sound playing. We'll also have a fun egg-hunting game.
Let's first recap the new concepts and techniques that we saw in the reading:
document.querySelectorAll()
is a companion to
the document.querySelector()
that we are already familiar
with.
#words img
and adds an event handler to each
one.
src
to an audio
element
(that has autoplay
set) will cause the MP3 to be loaded
and played.
The example in the reading used these techniques to add click-handlers to pronounce the words that were next to the audio elements.
First, let's see that example again, here in a slightly different form. example that uses a Javascript function to add an audio element on the fly to a page.
Observations:
.js
file sets up the page,
adding an onclick
event handler to each icon
The playSound
function is like this:
function playSound() { var word = this.previousSibling.innerHTML; console.log("word is: "+word); // here's the interesting stuff var audio = this.nextSibling; var url = "https://ssl.gstatic.com/dictionary/static/sounds/de/0/" + word + ".mp3"; audio.setAttribute("src",url); }
Below is the structure of each paragraph in the page:
<p><span>apple</span><img src="icons/play.png" alt="sound icon"><audio></audio></p>
What would happen if we rearranged some of the elements in each paragraph, such as putting the audio element before the icon?
this
would have the
wrong value
playSound
would not get invoked.
this
would be different elements.
Let's consider alternative ways to do a page like this
Is it possible to make the words clickable instead of the icons?
span
elements
Do we need four audio elements?
For fun, Scott and Eni have built a very cool egg hunt game.
Let's look at the materials of the game, starting with the game images
Next, a quick look at the important CSS:
div {float: left; width: 100px; height: 100px; border: 1px red solid; margin: 2px; } div img {width: 100px; visibility: hidden;} div.shown img { visibility: visible; }
So, any img
inside a div
is hidden, but we
can make it visible by adding the shown
class to
the div
.
Now it's time to understand the code.
Let's look at some of the functions, in turn. The first prepares the game board by hiding some images in randomly selected cells:
function prepare_game() { var cellsCount = create_grid(); // randomly select the number of total images var filesCount = fileNames.length; var imageLimit = Math.min(filesCount,cellsCount); var totalImages = Math.floor(Math.random()*imageLimit); document.querySelector("#total").innerHTML = totalImages; document.querySelector("#found").innerHTML = foundByUser; // randomly select the image indices var imageIdxArr = getArrayRandomNumbers(totalImages, filesCount); // randomly select the div indices to hold the images var divIdxArr = getArrayRandomNumbers(totalImages, cellsCount); setImages(imageIdxArr, divIdxArr); }
That code is pretty complicated, so we'll walk through it step by step.
(Note that the create_grid
function creates all the cells
(as many as it can, depending on how big our window is), and tells us
(by returning a value) how many cells there are. We won't look at the
details of that.)
filesCount
)
Suppose that totalImages
is a number like 3. The last two
lines pick 3 images out of the set of egg images, and they also pick 3
cells out of the grid (however many there turn out to be), to put the 3
images into.
Which of the following is okay?
Let's look at how the eggs are hidden:
function setImages(imgArr, divArr) { console.log("inside setImages"); if( imgArr.length != divArr.length ) { console.log("something has gone wrong: array lengths don't match"); return; } for (var i=0; i < imgArr.length; i++) { var imgIdx = imgArr[i]; var divId = divArr[i]; setOneImage(imgIdx, divId); } }
This is pretty much our standard loop, being applied in a slightly
different way. All the interesting work is in
the setOneImage
function:
function setOneImage(imageIndex, divId) { console.log("image "+imageIndex+" will go in cell "+divId); var div = document.querySelector("#i_"+divId); var imgEl = document.createElement("img"); var filename = fileNames[imageIndex]; imgEl.setAttribute("src", "eggs/"+filename+".png"); imgEl.setAttribute("alt", filename); div.appendChild(imgEl); div.onclick = showImage; }
This function creates an image element, sets the src
depending on the imageIndex
and puts the image into the div
with the id given by divId
.
By having this as a separate function, we can test it by hand. Let's do that! Open up a console and reload the page a few times until you get a small number of images, so there are lots of empty cells. The JS console will tell you which cells are in use, so you can play a perfect game if you want. But suppose cells 0, 1 and 2 are empty. Do this:
setOneImage(0,0); setOneImage(0,1); setOneImage(0,2);
That puts the same image (the first image) in all three cells. Now, click on those cells.
Now, let's look at what happens when you click on a cell:
function showImage() { // find div that was clicked to show in console var divId = this.getAttribute("id"); console.log("Found "+divId); // alert("Found you!"); this.classList.add("shown"); // makes the image visible foundByUser += 1; document.querySelector("#found").innerHTML = foundByUser; }
Here's where we use the CSS trick to make the hidden image visible.
How could we count the number of clicks the person took?
How could we cheat and get the page to say "Found 10 out of 9"
document.querySelector("#found").innerHTML = "10 of 9";
document.querySelector("#total").innerHTML = "10 of 9";
document.querySelector("#total").innerHTML = 9; document.querySelector("#found").innerHTML = 10;
document.querySelector("#total").innerHTML = 10; document.querySelector("#found").innerHTML = 9;
We hope that after these activities you have a good understanding of: