-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathpage3.html
415 lines (294 loc) · 11.4 KB
/
page3.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
<!doctype html>
<head>
<title>Curriculum — page 3</title>
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Averia+Serif+Libre:300,400">
<link rel="stylesheet" href="style.css">
<meta charset="utf-8">
</head>
<h1>Curriculum: page 3, moving pictures</h1>
<p>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. </p>
<h2 class="step">Including a JavaScript file</h2>
<h3 class=goal>Goal</h3>
<p>To see how to set up a JavaScript environment.</p>
<h3 class=inst>Instructions</h3>
<p>In your editor, create a new file and save it with the name
“slideshow.js” in your <span class="filename">slideshow</span> directory.</p>
<p>In your <span class="filename">slideshow.js</span>, add the line that creates a
reference to film roll:</p>
<pre>
var filmroll = document.getElementById('the-film-roll');
</pre>
<p>In your <code>index.html</code>, include this new file at the very
<strong>end</strong>:</p>
<pre>
<script src="slideshow.js"></script>
</pre>
<p>Back in the browser, refresh the page. Type the following in the
console:</p>
<pre>
filmroll.style.left = '-100px';
</pre>
<h3 class=ex>Explanation</h3>
<p>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!</p>
<h2 class="step">Create a function to move the film roll</h2>
<h3 class=goal>Goal</h3>
<p>To use <code>setInterval</code> to create a simple animation.</p>
<h3 class=inst>Instructions</h3>
<p>Yesterday we saw that <code>setInterval</code> could be used to run
a function every n milliseconds. We can also stop the function using
<code>clearInterval</code>. Update your <span class="filename">slideshow.js</span>
file to contain this code, and then refresh the browser:</p>
<pre>
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);
</pre>
<p>Why can’t we use a <code>for</code> or <code>while</code> loop
for this effect?</p>
<p>Try to speed up the scrolling effect. There are two ways. Which one
works better?</p>
<p>Update the <code>move</code> function to move the film roll 20
pixels every 50 milliseconds.<p>
<p>What if you want to move exactly 110 pixels? Update your function
so that it goes to exactly the end and not more.<p>
<p>Tip: <code>Math.min</code> is a function that takes any number of
arguments, and returns the one that is smallest. Try this:<p>
<pre>
current = Math.min(current + 20, end);
</pre>
<p>Make the photos scroll to the left instead of right.</p>
<p>How much do you have to move the film roll to make it scroll from
the first photo to the second photo?</p>
<p>What happens if your photo width is not a multiple of 20? How can
you fix the problem?<p>
<p>Update the <code>move</code> function so that the direction of
scrolling is only controlled by changing the start and end values.</p>
<h3 class=ex>Explanation</h3>
<p>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.</p>
<p>We used to use <code>setInterval</code> instead of a
<code>while</code> (or <code>for</code>) loop so we could add time
between the loops instead of doing many thousands and thousands of
loops.</p>
<p>In the end, your function might look something like this:</p>
<pre>
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);
}
}
</pre>
<p>By using the <code>Math.min</code> and <code>Max.max</code>
functions, we can guarantee that the <code>current</code> value never
goes beyond the <code>end</code> (either bigger or smaller, depending
on direction)</p>
<h2 class="step">Create a scroll function</h2>
<h3 class=goal>Goal</h3>
<p>Create a re-usable scroll function that can be called multiple
times.</p>
<h3 class=inst>Instructions</h3>
<p>Create a function called <code>scroll</code> that accepts a start position,
and an end position.</p>
<pre>
function scroll(start, end) {
// now what?
}
</pre>
<p>Move the <code>current</code> counter, your <code>move</code>
function and <code>setInterval</code> inside of <code>scroll</code>.
You no longer need to define start and end variables. Your
<span class="filename">slideshow.js</span> file will look like this:</p>
<pre>
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);
}
</pre>
<p>Refresh the browser.</p>
<p>Use the <code>scroll</code> function to slide to the second photo by typing in
the console type:</p>
<pre>
scroll(0, -500);
</pre>
<p>(… but replace <code>500</code> with the width of one of your photos.)</p>
<p>Use the <code>scroll</code> function to slide from the second photo to the
third.</p>
<p>Scroll back to the second photo.</p>
<h3 class=ex>Explanation</h3>
<p>Now we have a single function we can use to scroll left and right
from any starting position to any ending position. Yay!</p>
<h2 class="step">Add a keydown event listener</h2>
<h3 class=goal>Goal</h3>
<p>To see that we can give control of the slide show to the user.</p>
<h3 class=inst>Instructions</h3>
<p>In <span class="filename">slideshow.js</span>, add an <em>EventListener</em>
called <code>handleEvent</code> to the <code>document</code> that triggers on
a <code>keydown</code> event, like this:</p>
<pre>
function handleEvent(e) {
console.log(e, e.keyCode);
}
document.addEventListener('keydown', handleEvent);
</pre>
<p>In Chrome, be sure you have the Console tab open in the Developer
Tools.</p>
<p>Refresh the page.</p>
<p>Begin pressing any of the keys, and while you do, watch the
output that is logged in the console.</p>
<p>What are the <code>keyCode</code>s for the left and right arrow
keys?</p>
<p>Update the <code>handleEvent</code> function to call a function
that scrolls left or right when the left or right arrow is
pressed:</p>
<pre>
function handleEvent(e) {
backAndForth(e.keyCode);
}
function backAndForth(keyCode) {
if (keyCode == 37) {
scroll(500, 0);
}
if (keyCode == 39) {
scroll(0, 500);
}
}
</pre>
<p>(… but replace <code>500</code> with the width of one of your photos.)</p>
<p>Try out this new functionality in Chrome. Remember to always
refresh the page when you change your JavaScript code.</p>
<p>Why doesn’t it keep scrolling in the same direction when you press
the same arrow?</p>
<p>Store the current scrolling position in a variable, and after
calling the <code>scroll</code> function, update the value of the
current position. Always use the current position as the <code>start</code>
value when you call the <code>scroll</code> function.</p>
<p>Try it first! But if you need help, take a peek below:</p>
<pre>
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;
}
}
</pre>
<h3 class=ex>Explanation</h3>
<p>When JavaScript runs in your browser (which is all the time, unless
you shut off JavaScript), it is always “listening” to <em>events</em>, 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 <code>document</code>, and by the
<code>document</code> itself. In this example, we are only listening
to <code>keydown</code> events emitted by the <code>document</code>.</p>
<p>By listening to the events emitted, we can know when the person
viewing the page has <em>interacted</em> 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”.</p>
<p>By listening to <em>input</em> from the person looking at the page,
we can allow the person to control the page.</p>
<p>Pretty cool! And very powerful.</p>
<h2 class="step">Correct buggy behaviour</h2>
<h3 class=goal>Goal</h3>
<p>To see how to prevent events from having an effect when it is not
desirable.</p>
<h3 class=inst>Instructions</h3>
<p>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.</p>
<p>Do you know what is causing it? What can we do to stop it?</p>
<p>Try to fix this bug.</p>
<h3 class=ex>Explanation</h3>
<p>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).</p>
<p>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.</p>
<p>Did you find a solution? This is one way to fix the bug:</p>
<pre>
<strong>var scrolling = false;</strong>
function scroll(start, end) {
var current = start;
var move = function () {
filmroll.style.left = current + 'px';
<strong>
if (current == end) {
clearInterval(loop);
scrolling = false;
}
</strong>
if (end > start) {
current = Math.min(current + 20, end);
} else {
current = Math.max(current - 20, end);
}
}
var loop = setInterval(move, 50);
<strong>scrolling = true;</strong>
}
function handleEvent(e) {
<strong>if (!scrolling) {
backAndForth(e.keyCode);
}</strong>
}
</pre>
<p>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.</p>
<p>You will notice that this solution uses an exclamation mark in the
<code>if (!scrolling)</code> conditional statement (inside the
<code>handleEvent</code> function). The exclamation mark is called the logical
NOT operator in JavaScript, so the <code>if (!scrolling)</code>
conditional statement has the meaning "if the <code>scrolling</code> variable
is not true".</p>
<p>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?</p>
<h2>Next!</h2>
<p>Now that we’ve changed CSS, let’s change the HTML too!</p>
<p><a href="page4.html">→ To the fourth page</a>.</p>