Skip to content
Newer
Older
100644 503 lines (358 sloc) 30.1 KB
c9442c7 @subelsky readd readme
authored May 5, 2011
1 <h1>HTML5: Beyond the Buzzwords</h1>
2
3 <h1>GOALS</h1>
4
5 <p>I am aiming to expand your imagination about the kinds of features that can be added to modern web applications without adding any dependencies
6 or friction to your codebase. I want to provide you with just enough knowledge that you could start to take advantage of these
7 capabilities in your own apps.</p>
8
9 <h1>PREREQUISITES</h1>
10
11 <ul>
12 <li><p>These instructions were built using the latest version of Chrome, but will also work with the latest version of Safari or Firefox. Some of the exercises do not work perfectly in Firefox due to limitations in the browser.
13 I have not tested them with IE or Opera but much of the code should still work.</p></li>
14 <li><p>Your browser should have a built-in JavaScript console. Chrome and Safari have a built-in JavaScript console. If you are using Firefox, be sure to install <a href="http://getfirebug.com">Firebug</a>.</p></li>
15 <li><p>You need some kind of basic text editor (Vi, Emacs, Textmate, Notepad, etc.) to make changes to the project files.</p></li>
16 </ul>
17
18 <h1>SETUP</h1>
19
20 <ol>
21 <li><p>Copy the directory named <code>start</code> from this project to a new location on your machine. This will form the basis for the game we are building
22 and includes all necessary dependencies.</p></li>
23 <li><p>In your project, examine the index.html file you copied from <code>start</code>. This skeleton is heavily stripped down from the <a href="http://html5boilerplate.com/">HTML5 Boilerplate project</a>. The <a href="https://github.com/paulirish/html5-boilerplate/blob/master/index.html">full template</a>
24 is a good way to learn some state of the art HTML5 practices.</p>
25
26 <p>Note the doctype that starts this file. That's all you need to do to indicate to the browser that you want to use the latest, greatest version of HTML.
27 The boilerplate also shows the use of new HTML5 semantic tags <code>&lt;header&gt;</code> and <code>&lt;footer&gt;</code>. You can use these instead of less semantic code such as <code>&lt;div id=&quot;header&quot;&gt;&lt;/div&gt;</code>.</p></li>
28 <li><p>Open up the index.html file in your browser. Then activate your JavaScript console (in Chrome, go to the View menu, choose Developer, then choose JavaScript console; in Safari, hit option-Apple-C). You should see the message &quot;You have a working console&quot;. If you don't see this message you should install Firebug or switch to a different browser.
29 You will have a hard time completing this tutorial without a working console.</p>
30
31 <p>That message was created by the file <code>js/tutorial.js</code>. I'll be using that file for all of our application code.</p></li>
32 </ol>
33
34 <h1>EXERCISE ONE</h1>
35
36 <h2>Feature Detection</h2>
37
38 <ol>
39 <li><p>Examine <code>js/libs/modernizr</code>. This is the <a href="http://www.modernizr.com/">Modernizr</a> library that performs browser feature detection and helps style new HTML5 semantic elements. Because you can't yet
40 rely on users having fully-capable browsers, feature detection is essential for providing useful error messages and fallbacks.</p></li>
41 <li><p>To activate Modernizr, use your favorite text editor to add this line to the <code>&lt;HEAD&gt;</code> tag of <code>index.html</code>.</p>
42
43 <p><code>&lt;script src=&quot;js/libs/modernizr-1.7.js&quot;&gt;&lt;/script&gt;</code></p>
44
45 <p>Then add the class <code>no-js</code> to the <code>&lt;HTML&gt;</code> tag on the second line of the index.html file.</p></li>
46 <li><p>Open up <code>index.html</code> in your browser and inspect the <code>&lt;HTML&gt;</code> tag. Notice that <code>no-js</code> has been replaced by several CSS declarations that can be used to style fallback content, reveal error messages, etc.</p></li>
47 <li><p>Open up a JavaScript console and inspect the Modernizr object. To be able to complete all of the exercises in this tutorial, you'll need to see true values for all of these properties:</p>
48
49 <ul>
50 <li>Modernizr.canvas</li>
51 <li>Modernizr.websockets</li>
52 <li>Modernizr.audio</li>
53 <li>Modernizr.geolocation</li>
54 <li>Modernizr.localstorage</li>
55 </ul>
56
57 <p>If you don't see &quot;true&quot; for all of these you should go ahead and install the <a href="http://www.google.com/chrome">Chrome</a> browser.</p></li>
58 </ol>
59
60 <h2>Extra Credit</h2>
61
62 <p>Using only CSS and HTML, use the <code>&lt;HTML&gt;</code> classes <code>touch</code> and <code>no-touch</code> to reveal a message to the user indicating whether or not they have a touch interface. If you have a mobile OS simulator installed (such as iOS Simulator) you can
63 test both messages.</p>
64
65 <h1>EXERCISE TWO</h1>
66
67 <h2>Basic Canvas Drawing</h2>
68
69 <ol>
70 <li><p>Add <code>&lt;canvas id=&quot;main&quot; width=&quot;400&quot; height=&quot;400&quot;&gt;&lt;/canvas&gt;</code> just after the opening of the <code>&lt;body&gt;</code> tag in your <code>index.html</code> file.</p></li>
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
71 <li><p>To draw a rectangle in the canvas, add this code to js/tutorial.js:
72 <pre>var canvas = document.getElementById(&quot;main&quot;);
73 var context = canvas.getContext(&quot;2d&quot;);
74 context.fillRect(0,0,20,20);</pre></p>
c9442c7 @subelsky readd readme
authored May 5, 2011
75
76 <p>All drawing operations happen on the canvas context, not the canvas itself. Right now &quot;2d&quot; is the only available context, but a future HTML spec may define a 3d context.</p></li>
77 <li><p>Open <code>index.html</code> in your browser. You should see a black rectangle!</p></li>
78 <li><p>Change the <code>fillRect</code> call to <code>strokeRect</code> and reload your browser. Now the rectangle is not filled-in.</p></li>
79 <li><p>Set the context's <code>fillStyle</code> property to a CSS color like &quot;red&quot;, then reload the page to see a red rectangle.</p>
80
81 <pre>context.fillStyle = "red";</pre></li>
82 <li><p>To draw text, add lines like this to <code>tutorial.js</code> and reload.</p>
83
84 <pre>context.font = "bold 24px sans-serif";
85 context.fillStyle = "blue";
86 context.fillText("HTML5",100,100);</pre></li>
87 </ol>
88
89 <h2>Extra Credit</h2>
90
91 <p>Try filling your rectangle with a gradient. You'll need to create a gradient object as explained in <a href="http://diveintohtml5.org/canvas.html#gradients">Dive Into HTML5</a>, then set your fillStyle to that gradient.</p>
92
93 <h1>EXERCISE THREE</h1>
94
95 <h2>Canvas Image Manipulation</h2>
96
97 <ol>
98 <li><p>Copy the file <code>media/water.jpg</code> from the tutorial project to your project's <code>media</code> directory. (This image is <a href="http://www.flickr.com/photos/50183640@N05/5616041841/">Creative Commons-licensed</a>)</p></li>
99 <li><p>Draw this image using the canvas by adding these lines to your <code>tutorial.js</code> file:</p>
100
101 <pre>var img = new Image();
102 img.src = "media/water.jpg";
103 img.onload = function() {
104 context.drawImage(img,0,110);
105 };</pre></li>
106 <li><p>Reload your browser to see the image.</p></li>
107 <li><p>Now add two additional parameters, a destination width and height, after the original 3 parameters:</p>
108
109 <pre>context.drawImage(img,0,110,200,100);</pre></li>
110 <li><p>Reload the browser and observe the image scaled to a different size.</p></li>
111 <li><p>Copy the sprite file we'll be using for our simple game, <code>media/characters.jpg</code> to the <code>media</code> folder of your project. (I got this CC-licensed file by David E. Gervais from the <a href="http://pousse.rapiere.free.fr/tome/">TomeTik</a> project)</p></li>
112 <li><p>Use the 9 argument version of drawImage to slice out one character from the characters file and project it onto the canvas:</p>
113
114 <pre>drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh);</pre>
115
116 <p>The 9 arguments are explained in this image:
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
117 <img src="http://images.whatwg.org/drawImage.png" alt="drawImage arguments">
118 </p>
c9442c7 @subelsky readd readme
authored May 5, 2011
119
120 <p>Each sprite is 32 pixels wide and 32 pixels high. So if you want to slice out the 2nd character in the top row, with the red hood, you would start with these parameters:</p>
121
122 <ul>
123 <li>sx = 33</li>
124 <li>sy = 0</li>
125 <li>sw = 32</li>
126 <li>sh = 32</li>
127 </ul>
128
129 <p>Choose dx, dy, dw, and dh to your taste, then reload the browser. Consult the solution in <code>ex3</code> if you get confused.</p></li>
130 </ol>
131
132 <h1>EXERCISE FOUR</h1>
133
134 <h2>Basic Animation</h2>
135
136 <ol>
137 <li><p>Copy <code>js/libs/jquery-1.5.2.js</code> to the <code>js/libs</code> directory in your project. We'll be using jQuery to bind keyboard events and to perform other tasks.</p></li>
138 <li><p>Add a this tag to the bottom of your index.html file, before the <code>tutorial.js</code> file is loaded, to load the jQuery library:</p>
139
140 <p><code>&lt;script src=&quot;js/libs/jquery-1.5.2.js&quot;&gt;&lt;/script&gt;</code></p></li>
141 <li><p>Comment out most of the drawing code we had been working with so the page starts clean. The only working code in your <code>tutorial.js</code> should look like this:</p>
142
143 <pre>var canvas = document.getElementById("main");
144 var context = canvas.getContext("2d");
145
146 var characters = new Image();
147 characters.src = "media/characters.gif";</pre></li>
148 <li><p>Initialize two variables, <code>x</code> and <code>y</code>, to zero. We'll use these to keep track of the user's current position.</p></li>
149 <li><p>Initialize variables to store the height and width of the canvas. Later we'll be changing the size of the canvas dynamically so it makes sense to not hard code these values.</p>
150
151 <p><pre>var height = $(canvas).height();</pre>
152 <pre>var width = $(canvas).width();</pre></p></li>
153 <li><p>Setup another onload function for the characters object. When the characters image has loaded, we want to bind keyboard events to a function we'll write next:</p>
154
155 <pre>$(window).keyup(move);</pre></li>
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
156 <li><p>Write a move function that updates the character position on screen based on which arrow key was pressed. Using the binding from the above step, your move function should
c9442c7 @subelsky readd readme
authored May 5, 2011
157 accept one argument passed by jQuery: an event object. That object has a &quot;which&quot; property containing the code for the key that was pressed.</p>
158
159 <p>The key codes are:</p>
160
161 <ul>
162 <li>Up = 38</li>
163 <li>Down = 40</li>
164 <li>Left = 37</li>
165 <li>Right = 39</li>
166 </ul>
167
168 <p>Increment or decrement x or y by 10, depending on which key was pressed. Be sure to guard against x or y going out of bounds (less than zero or greater than the canvas size).</p>
169
170 <p>If you get confused check out <code>ex4/js/tutorial.js</code> for an example move function.</p></li>
171 <li><p>At the end of your move function, call <code>context.drawImage</code> to slice out one of the sprites from our file and project it on the screen at the coordinates stored
172 in x and y.</p>
173
174 <p>If you get confused check out <code>ex4/js/tutorial.js</code> to see what this looks like.</p></li>
175 <li><p>Reload your browser and try it out. You should see your character tracking across the screen slowly.</p></li>
176 <li><p>Let's make this look nicer by clearing the screen before each draw command. Add this before your drawImage call:</p>
177
178 <pre>context.clearRect(0,0,width,height);</pre></li>
179 <li><p>You may also want to increase the number of pixels that the character travels per key press.</p></li>
180 </ol>
181
182 <h2>Extra Credit</h2>
183
184 <p>Try setting up an animation loop that redraws the screen a few times per second. This will let you decouple the keyboard events from the drawing. You'll need something like this
185 to start your loop:</p>
186
187 <p><code>setInterval(runLoopFunction,interval);</code></p>
188
189 <p>Where runLoopFunction is the name of your function and interval is the number of milliseconds the browser should wait in between calls to that function.</p>
190
191 <h1>EXERCISE FIVE</h1>
192
193 <h2>Fun With Forms</h2>
194
195 <ol>
196 <li><p>When we link this game up with other players we want to know who's who. So let's add a username field that takes advantage of new HTML5 form features. Add this line to your <code>index.html</code> file:</p>
197
198 <p><code>&lt;input id=&quot;username&quot; placeholder=&quot;Your name&quot;&gt;</code></p></li>
199 <li><p>Reload the page. If you don't see any placerholder text, check the value of <code>Modernizr.input.placeholder</code> in your JavaScript console.</p></li>
200 <li><p>Now add the <code>autofocus</code> attribute to that input field and reload. If your browser supports it, the field will automatically receive the focus. </p></li>
201 <li><p>Let's try out a new form element, a slider we can use to control the size of our character. Add this to your <code>index.html</code> file (1):</p>
202
203 <p><code>&lt;input id=&quot;size&quot; type=&quot;range&quot; min=&quot;4&quot; max=&quot;320&quot; step=&quot;8&quot; value=&quot;32&quot;&gt;</code></p></li>
204 <li><p>Bind changes to that slider to a function in <code>tutorial.js</code> that will control the destination width and height of your drawImage call. The binding should look like this:</p>
205
206 <p><code>$('#size').change(function() { ... });</code></p>
207
208 <p>To get the value of the slider, use <code>$('#size').val()</code></p></li>
209 </ol>
210
211 <p>(1) This element does not render in Firefox. Try it out in Safari or Chrome.</p>
212
213 <h2>Extra Credit</h2>
214
215 <p>Try out some of the other input elements listed in the <a href="http://diveintohtml5.org/forms.html">Dive Into HTML5 book</a>, like the color picker!</p>
216
217 <h1>EXERCISE SIX</h1>
218
219 <h2>Local Storage</h2>
220
221 <p><strong>Note</strong>: this exercise will not work well in Firefox because of a bug in the way Firefox handles file:// URLs. If you want this to work in Firefox you'll need to serve up your code from a web server
222 on your development machine. <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=507361">Details</a></p>
223
224 <ol>
225 <li><p>At your JavaScript console, set a localStorage value:</p>
226
227 <pre>localStorage.setItem('shaz','bot')</pre></li>
228 <li><p>Close the page completely, then reopen it in a new window and type this at your JavaScript console:</p>
229
230 <pre>localStorage.getItem('shaz')</pre>
231
232 <p>If your browser supports localStorage, you should get the value of <code>shaz</code> back.</p></li>
233 <li><p>Try the above steps with the sessionStorage object. How does sessionStorage differ from localStorage? What about when you merely reload a page? Do they perform in the same way?</p></li>
234 <li><p>Call <code>localStorage.clear()</code> and try getting the 'shaz' item again.</p></li>
235 <li><p>Bind a new function to the change event of the username input field we added in exercise 5, like this:</p>
236
237 <pre>$('#username').change(function() { ... });</pre></li>
238 <li><p>In that bound function, use localStorage to store the user's name. You may need to change the focus by clicking elsewhere on the page to get this event to fire. To fetch the value of the username field, use <code>$(&quot;#username&quot;).val()</code>.</p></li>
239 <li><p>Add a line of code to <code>tutorial.js</code> to fetch the user's name from localStorage (which you stored in the above step) when the page loads. If there is a previously-stored username, set the value of the username field
240 to the pre-stored field like this: <code>$(&quot;#username&quot;).val(nameStr)</code>.</p></li>
241 <li><p>Reload the page. Type in a username, tab away from the username field (to make sure the change event fires), then reload the page. Your username should already be filled-in, instead of the placerholder text.</p></li>
242 <li><p>Try setting and getting numbers and hashes in localStorage. Does localStorage preserve type?</p></li>
243 </ol>
244
245 <p><em>Your JavaScript console may also have an inspector for local and session storage. In WebKit's inspector, it's Storage tab.</em></p>
246
247 <h2>Extra Credit</h2>
248
249 <ol>
250 <li><p>Bind the window object's <code>storage</code> event to keep track of when new items are added to localStorage. See <a href="http://diveintohtml5.org/storage.html#storage-event">Dive Into HTML5</a> if you get stuck.</p></li>
251 <li><p>What happens when you try to get an item that has not been previously set from localStorage?</p></li>
252 </ol>
253
254 <h1>EXERCISE 7</h1>
255
256 <h2>Canvas Cleanup</h2>
257
258 <ol>
259 <li><p>Let's make things a little nicer before we add multi-player features to this &quot;game&quot;. First, let's set a dark background for our canvas. Add this declaration to the <code>&lt;head&gt;</code> section of <code>index.html</code>:</p>
260
261 <pre><code>&lt;style&gt;
262 canvas {
263 background-color: black;
264 }
265
266 input { display: block; }
267 &lt;/style&gt;
268 </code></pre></li>
269 <li><p>You may also want to increase the width and height of your canvas element.</p></li>
270 <li><p>Increase the step size for your character so it moves 5 or 10 pixels at a time.</p></li>
271 </ol>
272
273 <h1>EXERCISE 8</h1>
274
275 <h2>Web Sockets</h2>
276
277 <p><strong>Note</strong>: WebSockets are disabled in Firefox. You may be able to get something working by using <a href="http://socket.io/">socket.io</a>.</p>
278
279 <ol>
d9db2b7 @subelsky fix ex8 instructions
authored May 9, 2011
280 <li><p>Let's connect to a websocket server in order to exchange information with other players. Add the following code to your <code>tutorial.js</code> file. I noticed that I would sometimes get errors
281 if this code fired before the <code>characters.gif</code> image file loaded, so you may want to stick this in the onload handler for that object. See the exercise 8 solution if this is confusing.</p>
c9442c7 @subelsky readd readme
authored May 5, 2011
282
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
283 <pre>var ws = new WebSocket("ws://exp.subelsky.com:8011");
c9442c7 @subelsky readd readme
authored May 5, 2011
284 ws.onmessage = handleMessage;
285
286 function handleMessage(event) {
287 console.info(event.data);
288 }</pre></li>
289 <li><p>Reload your browser. Every 10 seconds you should see a &quot;ping&quot; message from the server. Note that this is a JSON string that we'll need to unmarshal before we can work with it.</p></li>
290 <li><p>Check out the Ruby code in <code>server/server.rb</code> to see what you're connecting to with that string.</p></li>
291 <li><p>Modify the <code>handleMessage</code> function to parse the JSON string. If your browser does not have a native JSON implementation, you'll need to add the script <code>js/libs/json2.js</code> to your project for this code to work.</p>
292
293 <pre>var msg = JSON.parse(event.data);
294 console.info(msg);</pre></li>
295 <li><p>Reload your browser, wait 10 seconds, then check your console. You should see the de-marshalled JSON object displayed.</p></li>
296 <li><p>Modify your <code>move</code> function to send a JavaScript object out on the websocket every time you move your character. Use the websocket.send method like this:</p>
297
298 <pre>ws.send(JSON.stringify({ name: name, x: x, y: y, type: "move" }));</pre></li>
299 <li><p>Check out the server log being tailed on the screen. You should see your movement messages showing up every time you push a key.</p></li>
300 </ol>
301
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
302 <p>If you are thinking of building an app with websockets, definitely check out <a href="http://pusherapp.com/">Pusher</a> which may save you the trouble of writing your own server.</p>
c9442c7 @subelsky readd readme
authored May 5, 2011
303
304 <h2>Extra Credit</h2>
305
306 <p>The server is broadcasting all movement events to the whole class. To display other student positions on your screen, you'll need to keep track of their usernames and x and y positions (probably
307 with a hash, where the keys are user names and the values are coordinates). Modify your handleMessage message to display multiple players, displaying a different image for your own sprite vs.
308 other users. </p>
309
310 <p>Also, we're not doing anything to ensure uniqueness of usernames, so make sure you pick a name that won't collide with anyone else's name.</p>
311
312 <h1>EXERCISE 9</h1>
313
314 <h2>Embedded Media (and Data Attributes)</h2>
315
316 <p>Let's add some sound effects to our game and take advantage of HTML5's data attributes to simplify our controls.</p>
317
318 <ol>
319 <li><p>Add this list element to your <code>index.html</code> body:</p>
320
321 <pre><code>&lt;ul&gt;
322 &lt;li&gt;&lt;a href=&quot;#&quot; data-soundname='bubble'&gt;Play Bubble&lt;/a&gt;&lt;/li&gt;
323 &lt;li&gt;&lt;a href=&quot;#&quot; data-soundname='ray_gun'&gt;Play Ray Gun&lt;/a&gt;&lt;/li&gt;
324 &lt;/ul&gt;
325 </code></pre></li>
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
326 <li><p>Use jQuery to bind the <code>&lt;a&gt;</code> tag's <code>click</code> event. You can figure out which soundname the user wants by inspecting the click event's data attribute, as below. I've
c9442c7 @subelsky readd readme
authored May 5, 2011
327 included the cross-browser version as well as the version provided for in the <a href="http://dev.w3.org/html5/spec/elements.html#embedding-custom-non-visible-data">HTML5 spec</a>, which only Chrome seems to support.</p>
328
329 <pre><code>$('a').click(function(evt) {
330 // this spec version is not as pretty but works across browsers
331 $('#'+evt.target.getAttribute('data-soundname'))[0].play();
332
333 // the HTML5 spec provides a nicer API, but this version only seems to work in Chrome
334 // $('#'+evt.target.dataset.soundname)[0].play();
335 });
336 </code></pre>
337
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
338 <p>Note that data attributes are different from micro-data, because they are not intended for external consumption. See <a href="http://diveintohtml5.org/extensibility.html">Dive Into HTML5</a> for more details about microdata.</p></li>
c9442c7 @subelsky readd readme
authored May 5, 2011
339 <li><p>Reload the page. Click each link to verify that you can read the <code>dataset</code> property and are getting the correct soundname.</p></li>
340 <li><p>Playing audio and video in HTML5 involves a lot of codec hassles. You usually have to provide your content in multiple formats. To make things simple, I've included these two
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
341 sound files in four different formats. Copy the sound files from the <code>media</code> directory to your project. If you are serving these files through a web server (and not viewing them via a file:// URL), you may have
342 to fiddle with your MIME settings because HTML5 will choke if your audio files aren't served with the proper MIME type. See <a href="http://diveintohtml5.org/video.html#video-mime-types">MIME Types</a> for details.</p>
c9442c7 @subelsky readd readme
authored May 5, 2011
343
344 <p>The following audio embed should work for most people, though. The spec says that the browser should pick the first listed source that it can play.</p>
345
346 <pre><code>&lt;div style=&quot;display:hidden&quot;&gt;
347 &lt;audio id=&quot;bubble&quot; preload&gt;
348 &lt;source src=&quot;media/bubble.ogg&quot;&gt;
349 &lt;source src=&quot;media/bubble.mp3&quot;&gt;
350 &lt;source src=&quot;media/bubble.wav&quot;&gt;
351 &lt;/audio&gt;
352
353 &lt;audio id=&quot;ray_gun&quot; preload&gt;
354 &lt;source src=&quot;media/ray_gun.ogg&quot;&gt;
355 &lt;source src=&quot;media/ray_gun.mp3&quot;&gt;
356 &lt;source src=&quot;media/ray_gun.wav&quot;&gt;
357 &lt;/audio&gt;
358 &lt;/div&gt;
359 </code></pre>
360
361 <p>I chose to embed these directly on the page so we could take advantage of the browser's content fallback selection. You can also create audio objects just like we did with Image objects earlier:</p>
362
363 <pre><code>var audio = new Audio;
364 audio.src = &quot;http://...&quot;;
365 </code></pre></li>
366 <li><p>Reload your page, then try playing both sounds at the console:</p>
367
368 <pre>$('#bubble')[0].play()
369 $('#ray_gun')[0].play()</pre></li>
370 <li><p>Modify your anchor click event handler to automatically play the requested sound using the above technique.</p></li>
371 <li><p>To see what basic HTML5 audio controls look like, remove <code>display:hidden</code> from the <code>&lt;div&gt;</code> and add the <code>controls</code> attribute next to <code>preload</code>, then reload the page.</p></li>
372 <li><p>Video embedding works the same way. We need to provide multiple versions of video files to ensure compatibility across modern browsers. Copy the files <code>short.mov</code>, <code>short.mp4</code>, <code>short.ogv</code>, and <code>short.webm</code> from the <code>media</code> directory to your project's <code>media</code> directory.</p>
373
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
374 <p>These files were created from a QuickTime movie using <code>ffmpeg2theora</code>, <code>ffmpeg</code> and <code>HandBrakeCLI</code>, using settings from <a href="http://diveintohtml5.org/video.html">Dive Into HTML5</a>.</p></li>
c9442c7 @subelsky readd readme
authored May 5, 2011
375 <li><p>Add this to the bottom of your <code>index.html</code> page:</p>
376
377 <pre><code> &lt;video width=&quot;320&quot; height=&quot;240&quot; preload controls&gt;
378 &lt;source src=&quot;media/short.ogg&quot; type='video/ogg; codecs=&quot;theora, vorbis&quot;' /&gt;
379 &lt;source src=&quot;media/short.mp4&quot; /&gt;
380 &lt;source src=&quot;media/short.mov&quot; /&gt;
381 &lt;/video&gt;
382 </code></pre></li>
383 <li><p>Reload the page. One of those four formats should display in your browser.</p>
384
385 <p>For a cool example of how to use the canvas to manipulate images from a video, check out <a href="http://html5demos.com/video-canvas">this demo</a>. There's also a good demonstration of using embedded media events to show a timer
386 in <a href="http://html5demos.com/video">this demo</a>.</p></li>
387 </ol>
388
389 <h2>Extra Credit</h2>
390
391 <p>Use the <a href="http://flowplayer.org/">FlowPlayer</a> Flash-based video player as the ultimate fallback for this content (you'll need to embed a <code>&lt;object&gt;</code> tag after the <code>&lt;source&gt;</code> tags. The technique is explained
392 at <a href="http://camendesign.com/code/video_for_everybody">Video for Everybody</a>.</p>
393
394 <h1>EXERCISE TEN</h1>
395
396 <h2>Geolocation</h2>
397
398 <ol>
399 <li><p>At the JavaScript console, type the following command:</p>
400
401 <pre>navigator.geolocation.getCurrentPosition(function(loc) { console.info(loc.coords) }, function(err) { console.error(err) })</pre></li>
402 <li><p>Inspect the location object in the console. If you lookup those coordinates in Google Maps you should get a result fairly close to the convention center! It's very easy to integrate this info
403 with Google Maps to show a map at the user's location, but unfortunately this can't be done from localhost due to Google Maps API authentication issues.
404 <a href="http://html5demos.com/geo">This link</a> has a simple demo - be sure to view source on the page.</p>
405
406 <p>The first callback gets fired if the browser can guess its location. The second callback fires if it can't. For me, the second callback fired in
407 Safari when I ran it on a machine with an Ethernet connection.</p></li>
408 </ol>
409
410 <h2>Extra Credit</h2>
411
412 <p>Check out <a href="https://simplegeo.com/docs/tutorials/javascript">SimpleGeo</a> for some examples of other cool things you can do when you know a user's approximate location.</p>
413
414 <h1>EXERCISE ELEVEN</h1>
415
416 <h2>Web Workers</h2>
417
418 <ol>
419 <li><p>Examine the file <code>js/worker.js</code> and then copy it to your project. This is a simple brute-force algorithm to find all the factors of a given integer.</p></li>
420 <li><p>Reload the page, then type these lines at your JavaScript console:</p>
421
422 <pre>var worker = new Worker('js/worker.js');
423
424 worker.addEventListener('message', function(e) {
425 console.info(e.data);
426 },false);
427
428 worker.postMessage(100);</pre>
429
430 <p><strong>If you are using Chrome</strong>, you will get a security exception if you are loading index.html as a file:// URI. You can reopen Chrome with a command-line flag to circumvent the exception, though.
431 This is what worked for me on OS X:</p>
432
433 <pre>open -n -a 'Google Chrome.app' --args --allow-file-access-from-files</pre>
434
435 <p>Or just use a different browser.</p></li>
436 <li><p>You should see the worker immediately post a response to the console. Try increasing the size of the number you pass to worker.postMessage until you get something that takes awhile to run (like 1,000,000). Notice
437 that your web page continues to be responsive even as this task runs in the background.</p></li>
438 </ol>
439
440 <p>Here's a <a href="http://nerget.com/rayjs-mt/rayjs.html">more complicated webworker example</a>.</p>
441
442 <h1>EXERCISE TWELVE</h1>
443
444 <h2>Offline Apps</h2>
445
446 <ol>
447 <li><p>Examine the <code>index.html</code> file in the <code>manifest</code> directory. This is a stripped-down version of the exercise 11 solution. Check out the <code>&lt;html&gt;</code> tag which now includes a reference to <code>demo.manifest.</code></p></li>
448 <li><p>Examine <code>demo.manifest</code>.</p></li>
449 <li><p>If you have a packet sniffer, start it sniffing on port 80. Otherwise, make sure your JavaScript console is recording network traffic.</p></li>
450 <li><p>Now visit <a href="http://files.subelsky.com/manifestdemo/index.html">http://files.subelsky.com/manifestdemo/index.html</a></p></li>
451 <li><p>In your packet sniffer or JavaScript console, note that all files are being downloaded, and note the MIME type of the <code>demo.manifest</code> file (<code>text/cache-manifest</code>).</p></li>
452 <li><p>Now reload the page. If all goes well, the only traffic you'll see moving along the wire is a request to check the demo.manifest file, which doesn't even get downloaded since it is unchanged
453 (because of the <code>304</code> HTTP response status code).</p>
454
bbc0ef0 @subelsky fix tutorial copy
authored May 12, 2011
455 <p>This is the same technique you can use to make an HTML5 app &quot;installable&quot; on a smart phone.</p></li>
c9442c7 @subelsky readd readme
authored May 5, 2011
456 </ol>
457
458 <h2>Extra Credit</h2>
459
460 <p>Get <code>manifest/index.html</code> running on your dev machine. All you need to do is serve up the directory from the webserver (vs. from <code>file://</code>), and make sure the manifest file has the right MIME type. In Apache,
461 I added this directive to <code>httpd.conf</code>:</p>
462
463 <pre><code>AddType text/cache-manifest .manifest
464 </code></pre>
465
466 <h1>THAT WAS TOO EASY?</h1>
467
468 <p>Here are some other &quot;HTML5-ish&quot; features that you should be aware of that didn't fit into this tutorial or are too bleeding-edge to be used reliably:</p>
469
470 <ul>
471 <li><p><a href="http://diveintohtml5.org/extensibility.html">Microdata</a></p></li>
472 <li><p><a href="http://www.queness.com/post/7459/8-stunning-javascript-webgl-demonstrations">WebGL</a></p></li>
473 <li><p><a href="http://html5demos.com/history/">HTML5 History API</a></p></li>
474 <li><p><a href="http://html5doctor.com/methods-of-communication/">Alternatives to websockets</a></p></li>
475 <li><p><a href="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills">Polyfills to get HTML5 features working across browsers</a> and also <a href="http://html5doctor.com/how-to-get-all-the-browsers-playing-ball/">Uber</a></p></li>
476 <li><p><a href="http://www.css3.com/">Various CSS3 capabilities like rounded corners, 2D transforms, etc.</a></p></li>
477 </ul>
478
479 <h1>USEFUL URLs</h1>
480
481 <ul>
482 <li><p><a href="http://diveintohtml5.org/">Dive Into HTML5</a></p></li>
483 <li><p><a href="http://html5doctor.com/">HTML5 Doctor</a></p></li>
484 <li><p><a href="http://html5demos.com/">HTML5 Demos</a></p></li>
485 <li><p><a href="http://www.html5rocks.com/">HTML5 Rocks</a></p></li>
486 <li><p><a href="https://developer.mozilla.org/en/Canvas_tutorial">Mozilla Canvas Tutorials</a></p></li>
487 <li><p><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/">WHATWG Living Standard</a></p></li>
488 </ul>
489
490 <h1>ACKNOWLEDGEMENTS</h1>
491
492 <p>Thanks to <a href="http://jumpstartlab.com/">Jeff Casimir</a> for helping me organize this material, and to <a href="http://diveintomark.org/">Mark Pilgrim</a> for writing Dive Into HTML5 which was a big help. Any mistakes are my own of course!</p>
493
494 <h1>KEEP IN TOUCH</h1>
495
496 <p>Thanks for coming to my tutorial. I'm <a href="mailto:mike@subelsky.com">mike@subelsky.com</a> or <a href="http://twitter.com/subelsky">@subelsky</a>
497 on Twitter. I love talking about HTML5, so email me if you have
498 questions or want to discuss interesting challenges.</p>
499
500 <p>Most of the techniques I discuss in this tutorial I learned building
501 an HTML5-powered game for programmers named EXP. We're accepting beta
502 testers now, visit <a href="http://exp.subelsky.com/">exp.subelsky.com</a> to signup!</p>
Something went wrong with that request. Please try again.