You’ve written your HTML and CSS. We got a taste of how to use JavaScript to move around the content. Now, we’ll learn how to include your program when the HTML is loaded, so we can make the content dynamic and interactive.
To see how to set up a JavaScript environment.
In your editor, create a new file and save it with the name “slideshow.js” in your slideshow directory.
In your slideshow.js, add the line that creates a reference to film roll:
var filmroll = document.getElementById('the-film-roll');
In your index.html
, include this new file at the very
end:
<script src="slideshow.js"></script>
Back in the browser, refresh the page. Type the following in the console:
filmroll.style.left = '-100px';
Whoa! Just like images and style sheets, you can load JavaScript code when you load a web page. Instead of typing by hand on the console, we can prepare a program, and send it along with the HTML, CSS or images. Nice!
To use setInterval
to create a simple animation.
Yesterday we saw that setInterval
could be used to run
a function every n milliseconds. We can also stop the function using
clearInterval
. Update your slideshow.js
file to contain this code, and then refresh the browser:
var filmroll = document.getElementById('the-film-roll'); var start = 0; var end = 200; var current = start; function move() { filmroll.style.left = current + 'px'; current = current + 1; if (current > end) { clearInterval(loop); // This stops the loop } } var loop = setInterval(move, 40);
Why can’t we use a for
or while
loop
for this effect?
Try to speed up the scrolling effect. There are two ways. Which one works better?
Update the move
function to move the film roll 20
pixels every 50 milliseconds.
What if you want to move exactly 110 pixels? Update your function so that it goes to exactly the end and not more.
Tip: Math.min
is a function that takes any number of
arguments, and returns the one that is smallest. Try this:
current = Math.min(current + 20, end);
Make the photos scroll to the left instead of right.
How much do you have to move the film roll to make it scroll from the first photo to the second photo?
What happens if your photo width is not a multiple of 20? How can you fix the problem?
Update the move
function so that the direction of
scrolling is only controlled by changing the start and end values.
To control how fast or slow a loop is performed, we can change the time between loops, or we can change how big an effect each loop has.
We used to use setInterval
instead of a
while
(or for
) loop so we could add time
between the loops instead of doing many thousands and thousands of
loops.
In the end, your function might look something like this:
function move() { filmroll.style.left = current + 'px'; if (current == end) { clearInterval(loop); } if (end > start) { current = Math.min(current + 20, end); } else { current = Math.max(current - 20, end); } }
By using the Math.min
and Max.max
functions, we can guarantee that the current
value never
goes beyond the end
(either bigger or smaller, depending
on direction)
Create a re-usable scroll function that can be called multiple times.
Create a function called scroll
that accepts a start position,
and an end position.
function scroll(start, end) { // now what? }
Move the current
counter, your move
function and setInterval
inside of scroll
.
You no longer need to define start and end variables. Your
slideshow.js file will look like this:
var filmroll = document.getElementById('the-film-roll'); function scroll(start, end) { var current = start; function move() { filmroll.style.left = current + 'px'; if (current == end) { clearInterval(loop); } if (end > start) { current = Math.min(current + 20, end); } else { current = Math.max(current - 20, end); } } var loop = setInterval(move, 50); }
Refresh the browser.
Use the scroll
function to slide to the second photo by typing in
the console type:
scroll(0, -500);
(… but replace 500
with the width of one of your photos.)
Use the scroll
function to slide from the second photo to the
third.
Scroll back to the second photo.
Now we have a single function we can use to scroll left and right from any starting position to any ending position. Yay!
To see that we can give control of the slide show to the user.
In slideshow.js, add an EventListener
called handleEvent
to the document
that triggers on
a keydown
event, like this:
function handleEvent(e) { console.log(e, e.keyCode); } document.addEventListener('keydown', handleEvent);
In Chrome, be sure you have the Console tab open in the Developer Tools.
Refresh the page.
Begin pressing any of the keys, and while you do, watch the output that is logged in the console.
What are the keyCode
s for the left and right arrow
keys?
Update the handleEvent
function to call a function
that scrolls left or right when the left or right arrow is
pressed:
function handleEvent(e) { backAndForth(e.keyCode); } function backAndForth(keyCode) { if (keyCode == 37) { scroll(500, 0); } if (keyCode == 39) { scroll(0, 500); } }
(… but replace 500
with the width of one of your photos.)
Try out this new functionality in Chrome. Remember to always refresh the page when you change your JavaScript code.
Why doesn’t it keep scrolling in the same direction when you press the same arrow?
Store the current scrolling position in a variable, and after
calling the scroll
function, update the value of the
current position. Always use the current position as the start
value when you call the scroll
function.
Try it first! But if you need help, take a peek below:
var current = 0; function backAndForth(keyCode) { if (keyCode == 37) { scroll(current, current - 500); current = current - 500; } if (keyCode == 39) { scroll(current, current + 500); current = current + 500; } }
When JavaScript runs in your browser (which is all the time, unless
you shut off JavaScript), it is always “listening” to events, like
whether you type something, or move your mouse. These events have
names like “keydown”, “keyup”, and “click”, and are emitted by all
kinds of elements in the document
, and by the
document
itself. In this example, we are only listening
to keydown
events emitted by the document
.
By listening to the events emitted, we can know when the person viewing the page has interacted with the page. We can look at what the person did (what they typed, or what they clicked on) and then we can do something. In this example, we moved the film roll to the left when the person pressed “left” and we moved it right when the person pressed “right”.
By listening to input from the person looking at the page, we can allow the person to control the page.
Pretty cool! And very powerful.
To see how to prevent events from having an effect when it is not desirable.
Our functions for listening to events and scrolling have a bug in them. Maybe you already noticed it. To recreate the bug, try pressing the left and right arrows faster than the film roll can slide. (So, start the film roll sliding, and then press either left or right again before it is finished sliding). You’ll see an ugly flickering effect.
Do you know what is causing it? What can we do to stop it?
Try to fix this bug.
Lots of times when we write code, we forget that our users might do things that don’t “make sense” at first, or will try to do things we didn’t think of. Oops. We think our job is done, but then we find out our code has a bug and we have to correct it (or tell the users “Don’t do that!” which is sort of rude).
First we have to figure out that the bug exists. Then we have to figure out why the bug is happening. Then we have to figure out how to fix it. Lots of programmers think fixing bugs is fun :), since they are new puzzles to solve.
Did you find a solution? This is one way to fix the bug:
var scrolling = false; function scroll(start, end) { var current = start; var move = function () { filmroll.style.left = current + 'px'; if (current == end) { clearInterval(loop); scrolling = false; } if (end > start) { current = Math.min(current + 20, end); } else { current = Math.max(current - 20, end); } } var loop = setInterval(move, 50); scrolling = true; } function handleEvent(e) { if (!scrolling) { backAndForth(e.keyCode); } }
We created a variable that remembers whether or not we are already scrolling, and if we are, we ignore the keydown event from the user.
You will notice that this solution uses an exclamation mark in the
if (!scrolling)
conditional statement (inside the
handleEvent
function). The exclamation mark is called the logical
NOT operator in JavaScript, so the if (!scrolling)
conditional statement has the meaning "if the scrolling
variable
is not true".
Maybe this solution to the problem does not fit with what the user expects. What is reasonable for the user to expect? How can we change the code to do what the user expects?
Now that we’ve changed CSS, let’s change the HTML too!