From b33a89a74da29ef5d649b668aec7144dae1a55ea Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Oct 2018 21:56:14 +0200 Subject: [PATCH 001/299] Fix misspelled crow nest name --- 13_browser.md | 2 +- 16_game.md | 4 ++-- 18_http.md | 14 +++++++------- 19_paint.md | 8 ++++---- code/crow-tech.js | 4 ++-- code/journal.js | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/13_browser.md b/13_browser.md index 04b4b5bea..45086c421 100644 --- a/13_browser.md +++ b/13_browser.md @@ -19,7 +19,7 @@ no one would ever have paid any attention to it. {{index decentralization, compatibility}} -Web technology has, from the start, been decentralized, not just +Web technology has been decentralized from the start, not just technically but also in the way it evolved. Various browser vendors have added new functionality in ad hoc and sometimes poorly thought-out ways, which then, sometimes, ended up being adopted by others—and diff --git a/16_game.md b/16_game.md index 418192ebf..a9e8ed9b4 100644 --- a/16_game.md +++ b/16_game.md @@ -407,7 +407,7 @@ Coin.prototype.size = new Vec(0.6, 0.6); In [Chapter ?](dom#sin_cos), we saw that `Math.sin` gives us the y-coordinate of a point on a circle. That coordinate goes back and -forth in a smooth wave form as we move along the circle, which makes +forth in a smooth waveform as we move along the circle, which makes the sine function useful for modeling a wavy motion. {{index pi}} @@ -1151,7 +1151,7 @@ second). When the browser tab or window with our page is hidden, `requestAnimationFrame` calls will be suspended until the tab or window is shown again. In this case, the difference between `lastTime` and `time` will be the entire time in which the page was hidden. -Advancing the game by that much in a single step will look silly and +Advancing the game by that much in a single step would look silly and might cause weird side effects, such as the player falling through the floor. diff --git a/18_http.md b/18_http.md index ad27c1a6d..a778e3322 100644 --- a/18_http.md +++ b/18_http.md @@ -747,11 +747,11 @@ the example, and have our program handle the input, possibly using {{index "value attribute", "input (HTML tag)", "text field", "textarea (HTML tag)"}} -Fields created by `` tags with a type of `text` or `password`, -as well as ` @@ -884,17 +620,11 @@ delay), the timeout from the previous event will be canceled. {{index "sloppy programming"}} -Giving an undefined value to `clearTimeout` or calling it on a timeout -that has already fired has no effect. Thus, we don't have to be -careful about when to call it, and we simply do so for every event. +Giving an undefined value to `clearTimeout` or calling it on a timeout that has already fired has no effect. Thus, we don't have to be careful about when to call it, and we simply do so for every event. {{index "mousemove event"}} -We can use a slightly different pattern if we want to space responses -so that they're separated by at least a certain length of ((time)) but -want to fire them _during_ a series of events, not just afterward. For -example, we might want to respond to `"mousemove"` events by showing -the current coordinates of the mouse but only every 250 milliseconds. +We can use a slightly different pattern if we want to space responses so that they're separated by at least a certain length of ((time)) but want to fire them _during_ a series of events, not just afterward. For example, we might want to respond to `"mousemove"` events by showing the current coordinates of the mouse but only every 250 milliseconds. ```{lang: "text/html"} ``` -After creating the context object, the example draws a red -((rectangle)) 100 ((pixel))s wide and 50 pixels high, with its top-left -corner at coordinates (10,10). +After creating the context object, the example draws a red ((rectangle)) 100 ((pixel))s wide and 50 pixels high, with its top-left corner at coordinates (10,10). {{if book @@ -153,10 +104,7 @@ if}} {{index SVG, coordinates}} -Just like in HTML (and SVG), the coordinate system that the canvas -uses puts (0,0) at the top-left corner, and the positive y-((axis)) -goes down from there. So (10,10) is 10 pixels below and to the right -of the top-left corner. +Just like in HTML (and SVG), the coordinate system that the canvas uses puts (0,0) at the top-left corner, and the positive y-((axis)) goes down from there. So (10,10) is 10 pixels below and to the right of the top-left corner. {{id fill_stroke}} @@ -164,36 +112,23 @@ of the top-left corner. {{index filling, stroking, drawing, SVG}} -In the ((canvas)) interface, a shape can be _filled_, meaning its area -is given a certain color or pattern, or it can be _stroked_, which -means a ((line)) is drawn along its edge. The same terminology is used -by SVG. +In the ((canvas)) interface, a shape can be _filled_, meaning its area is given a certain color or pattern, or it can be _stroked_, which means a ((line)) is drawn along its edge. The same terminology is used by SVG. {{index "fillRect method", "strokeRect method"}} -The `fillRect` method fills a ((rectangle)). It takes first the x- and -y-((coordinates)) of the rectangle's top-left corner, then its width, -and then its height. A similar method, `strokeRect`, draws the -((outline)) of a rectangle. +The `fillRect` method fills a ((rectangle)). It takes first the x- and y-((coordinates)) of the rectangle's top-left corner, then its width, and then its height. A similar method, `strokeRect`, draws the ((outline)) of a rectangle. {{index [state, "of canvas"]}} -Neither method takes any further parameters. The color of the fill, -thickness of the stroke, and so on, are not determined by an argument -to the method (as you might reasonably expect) but rather by -properties of the context object. +Neither method takes any further parameters. The color of the fill, thickness of the stroke, and so on, are not determined by an argument to the method (as you might reasonably expect) but rather by properties of the context object. {{index filling, "fillStyle property"}} -The `fillStyle` property controls the way shapes are filled. It can be -set to a string that specifies a ((color)), using the color notation -used by ((CSS)). +The `fillStyle` property controls the way shapes are filled. It can be set to a string that specifies a ((color)), using the color notation used by ((CSS)). {{index stroking, "line width", "strokeStyle property", "lineWidth property", canvas}} -The `strokeStyle` property works similarly but determines the color -used for a stroked line. The width of that line is determined by the -`lineWidth` property, which may contain any positive number. +The `strokeStyle` property works similarly but determines the color used for a stroked line. The width of that line is determined by the `lineWidth` property, which may contain any positive number. ```{lang: "text/html"} @@ -208,8 +143,7 @@ used for a stroked line. The width of that line is determined by the {{if book -This code draws two blue squares, using a thicker line for the second -one. +This code draws two blue squares, using a thicker line for the second one. {{figure {url: "img/canvas_stroke.png", alt: "Two stroked squares",width: "5cm"}}} @@ -217,19 +151,13 @@ if}} {{index "default value", [canvas, size]}} -When no `width` or `height` attribute is specified, as in the example, -a canvas element gets a default width of 300 pixels and height of 150 -pixels. +When no `width` or `height` attribute is specified, as in the example, a canvas element gets a default width of 300 pixels and height of 150 pixels. ## Paths {{index [path, canvas], [interface, design], [canvas, path]}} -A path is a sequence of ((line))s. The 2D canvas interface takes a -peculiar approach to describing such a path. It is done entirely -through ((side effect))s. Paths are not values that can be stored and -passed around. Instead, if you want to do something with a path, you -make a sequence of method calls to describe its shape. +A path is a sequence of ((line))s. The 2D canvas interface takes a peculiar approach to describing such a path. It is done entirely through ((side effect))s. Paths are not values that can be stored and passed around. Instead, if you want to do something with a path, you make a sequence of method calls to describe its shape. ```{lang: "text/html"} @@ -246,12 +174,7 @@ make a sequence of method calls to describe its shape. {{index canvas, "stroke method", "lineTo method", "moveTo method", shape}} -This example creates a path with a number of horizontal ((line)) -segments and then strokes it using the `stroke` method. Each segment -created with `lineTo` starts at the path's _current_ position. That -position is usually the end of the last segment, unless `moveTo` was -called. In that case, the next segment would start at the position -passed to `moveTo`. +This example creates a path with a number of horizontal ((line)) segments and then strokes it using the `stroke` method. Each segment created with `lineTo` starts at the path's _current_ position. That position is usually the end of the last segment, unless `moveTo` was called. In that case, the next segment would start at the position passed to `moveTo`. {{if book @@ -263,12 +186,7 @@ if}} {{index [path, canvas], filling, [path, closing], "fill method"}} -When filling a path (using the `fill` method), each ((shape)) is -filled separately. A path can contain multiple shapes—each `moveTo` -motion starts a new one. But the path needs to be _closed_ (meaning -its start and end are in the same position) before it can be filled. -If the path is not already closed, a line is added from its end to its -start, and the shape enclosed by the completed path is filled. +When filling a path (using the `fill` method), each ((shape)) is filled separately. A path can contain multiple shapes—each `moveTo` motion starts a new one. But the path needs to be _closed_ (meaning its start and end are in the same position) before it can be filled. If the path is not already closed, a line is added from its end to its start, and the shape enclosed by the completed path is filled. ```{lang: "text/html"} @@ -282,10 +200,7 @@ start, and the shape enclosed by the completed path is filled. ``` -This example draws a filled triangle. Note that only two of the -triangle's sides are explicitly drawn. The third, from the -bottom-right corner back to the top, is implied and wouldn't be there -when you stroke the path. +This example draws a filled triangle. Note that only two of the triangle's sides are explicitly drawn. The third, from the bottom-right corner back to the top, is implied and wouldn't be there when you stroke the path. {{if book @@ -295,26 +210,17 @@ if}} {{index "stroke method", "closePath method", [path, closing], canvas}} -You could also use the `closePath` method to explicitly close a path -by adding an actual ((line)) segment back to the path's start. This -segment _is_ drawn when stroking the path. +You could also use the `closePath` method to explicitly close a path by adding an actual ((line)) segment back to the path's start. This segment _is_ drawn when stroking the path. ## Curves {{index [path, canvas], canvas, drawing}} -A path may also contain ((curve))d ((line))s. These are unfortunately -a bit more involved to draw. +A path may also contain ((curve))d ((line))s. These are unfortunately a bit more involved to draw. {{index "quadraticCurveTo method"}} -The `quadraticCurveTo` method draws a curve to a given point. To -determine the curvature of the line, the method is given a ((control -point)) as well as a destination point. Imagine this control point as -_attracting_ the line, giving it its curve. The line won't go through -the control point, but its direction at the start and end points will -be such that a straight line in that direction would point toward the -control point. The following example illustrates this: +The `quadraticCurveTo` method draws a curve to a given point. To determine the curvature of the line, the method is given a ((control point)) as well as a destination point. Imagine this control point as _attracting_ the line, giving it its curve. The line won't go through the control point, but its direction at the start and end points will be such that a straight line in that direction would point toward the control point. The following example illustrates this: ```{lang: "text/html"} @@ -340,20 +246,11 @@ if}} {{index "stroke method"}} -We draw a ((quadratic curve)) from the left to the right, with (60,10) -as control point, and then draw two ((line)) segments going through -that control point and back to the start of the line. The result -somewhat resembles a _((Star Trek))_ insignia. You can see the effect -of the control point: the lines leaving the lower corners start off in -the direction of the control point and then ((curve)) toward their -target. +We draw a ((quadratic curve)) from the left to the right, with (60,10) as control point, and then draw two ((line)) segments going through that control point and back to the start of the line. The result somewhat resembles a _((Star Trek))_ insignia. You can see the effect of the control point: the lines leaving the lower corners start off in the direction of the control point and then ((curve)) toward their target. {{index canvas, "bezierCurveTo method"}} -The `bezierCurveTo` method draws a similar kind of curve. Instead of a -single ((control point)), this one has two—one for each of the -((line))'s endpoints. Here is a similar sketch to illustrate the -behavior of such a curve: +The `bezierCurveTo` method draws a similar kind of curve. Instead of a single ((control point)), this one has two—one for each of the ((line))'s endpoints. Here is a similar sketch to illustrate the behavior of such a curve: ```{lang: "text/html"} @@ -370,9 +267,7 @@ behavior of such a curve: ``` -The two control points specify the direction at both ends of the -curve. The farther they are away from their corresponding point, the -more the curve will "bulge" in that direction. +The two control points specify the direction at both ends of the curve. The farther they are away from their corresponding point, the more the curve will "bulge" in that direction. {{if book @@ -382,26 +277,15 @@ if}} {{index "trial and error"}} -Such ((curve))s can be hard to work with—it's not always clear how to -find the ((control point))s that provide the ((shape)) you are looking -for. Sometimes you can compute them, and sometimes you'll just have to -find a suitable value by trial and error. +Such ((curve))s can be hard to work with—it's not always clear how to find the ((control point))s that provide the ((shape)) you are looking for. Sometimes you can compute them, and sometimes you'll just have to find a suitable value by trial and error. {{index "arc method", arc}} -The `arc` method is a way to draw a line that curves along the edge of -a circle. It takes a pair of ((coordinates)) for the arc's center, a -radius, and then a start angle and end angle. +The `arc` method is a way to draw a line that curves along the edge of a circle. It takes a pair of ((coordinates)) for the arc's center, a radius, and then a start angle and end angle. {{index pi, "Math.PI constant"}} -Those last two parameters make it possible to draw only part of the -circle. The ((angle))s are measured in ((radian))s, not ((degree))s. -This means a full ((circle)) has an angle of 2π, or `2 * Math.PI`, -which is about 6.28. The angle starts counting at the point to the -right of the circle's center and goes clockwise from there. You can -use a start of 0 and an end bigger than 2π (say, 7) to draw a full -circle. +Those last two parameters make it possible to draw only part of the circle. The ((angle))s are measured in ((radian))s, not ((degree))s. This means a full ((circle)) has an angle of 2π, or `2 * Math.PI`, which is about 6.28. The angle starts counting at the point to the right of the circle's center and goes clockwise from there. You can use a start of 0 and an end bigger than 2π (say, 7) to draw a full circle. ```{lang: "text/html"} @@ -418,11 +302,7 @@ circle. {{index "moveTo method", "arc method", [path, " canvas"]}} -The resulting picture contains a ((line)) from the right of the full -circle (first call to `arc`) to the right of the quarter-((circle)) -(second call). Like other path-drawing methods, a line drawn with -`arc` is connected to the previous path segment. You can call `moveTo` -or start a new path to avoid this. +The resulting picture contains a ((line)) from the right of the full circle (first call to `arc`) to the right of the quarter-((circle)) (second call). Like other path-drawing methods, a line drawn with `arc` is connected to the previous path segment. You can call `moveTo` or start a new path to avoid this. {{if book @@ -436,12 +316,9 @@ if}} {{index "pie chart example"}} -Imagine you've just taken a ((job)) at EconomiCorp, Inc., and your -first assignment is to draw a pie chart of its customer satisfaction -((survey)) results. +Imagine you've just taken a ((job)) at EconomiCorp, Inc., and your first assignment is to draw a pie chart of its customer satisfaction ((survey)) results. -The `results` binding contains an array of objects that represent the -survey responses. +The `results` binding contains an array of objects that represent the survey responses. ```{sandbox: "pie", includeCode: true} const results = [ @@ -454,12 +331,7 @@ const results = [ {{index "pie chart example"}} -To draw a pie chart, we draw a number of pie slices, each made up of -an ((arc)) and a pair of ((line))s to the center of that arc. We can -compute the ((angle)) taken up by each arc by dividing a full circle -(2π) by the total number of responses and then multiplying that number -(the angle per response) by the number of people who picked a given -choice. +To draw a pie chart, we draw a number of pie slices, each made up of an ((arc)) and a pair of ((line))s to the center of that arc. We can compute the ((angle)) taken up by each arc by dividing a full circle (2π) by the total number of responses and then multiplying that number (the angle per response) by the number of people who picked a given choice. ```{lang: "text/html", sandbox: "pie"} @@ -492,17 +364,13 @@ This draws the following chart: if}} -But a chart that doesn't tell us what the slices mean isn't very -helpful. We need a way to draw text to the ((canvas)). +But a chart that doesn't tell us what the slices mean isn't very helpful. We need a way to draw text to the ((canvas)). ## Text {{index stroking, filling, "fillStyle property", "fillText method", "strokeText method"}} -A 2D canvas drawing context provides the methods `fillText` and -`strokeText`. The latter can be useful for outlining letters, but -usually `fillText` is what you need. It will fill the outline of the -given ((text)) with the current `fillStyle`. +A 2D canvas drawing context provides the methods `fillText` and `strokeText`. The latter can be useful for outlining letters, but usually `fillText` is what you need. It will fill the outline of the given ((text)) with the current `fillStyle`. ```{lang: "text/html"} @@ -514,48 +382,25 @@ given ((text)) with the current `fillStyle`. ``` -You can specify the size, style, and ((font)) of the text with the -`font` property. This example just gives a font size and family name. -It is also possible to add `italic` or `bold` to the start of the -string to select a style. +You can specify the size, style, and ((font)) of the text with the `font` property. This example just gives a font size and family name. It is also possible to add `italic` or `bold` to the start of the string to select a style. {{index "fillText method", "strokeText method", "textAlign property", "textBaseline property"}} -The last two arguments to `fillText` and `strokeText` provide the -position at which the font is drawn. By default, they indicate the -position of the start of the text's alphabetic baseline, which is the -line that letters "stand" on, not counting hanging parts in letters -such as _j_ or _p_. You can change the horizontal position by setting the -`textAlign` property to `"end"` or `"center"` and the vertical -position by setting `textBaseline` to `"top"`, `"middle"`, or -`"bottom"`. +The last two arguments to `fillText` and `strokeText` provide the position at which the font is drawn. By default, they indicate the position of the start of the text's alphabetic baseline, which is the line that letters "stand" on, not counting hanging parts in letters such as _j_ or _p_. You can change the horizontal position by setting the `textAlign` property to `"end"` or `"center"` and the vertical position by setting `textBaseline` to `"top"`, `"middle"`, or `"bottom"`. {{index "pie chart example"}} -We'll come back to our pie chart, and the problem of ((label))ing the -slices, in the [exercises](canvas#exercise_pie_chart) at the end of -the chapter. +We'll come back to our pie chart, and the problem of ((label))ing the slices, in the [exercises](canvas#exercise_pie_chart) at the end of the chapter. ## Images {{index "vector graphics", "bitmap graphics"}} -In computer ((graphics)), a distinction is often made between _vector_ -graphics and _bitmap_ graphics. The first is what we have been doing -so far in this chapter—specifying a picture by giving a logical -description of ((shape))s. Bitmap graphics, on the other hand, don't -specify actual shapes but rather work with ((pixel)) data (rasters of -colored dots). +In computer ((graphics)), a distinction is often made between _vector_ graphics and _bitmap_ graphics. The first is what we have been doing so far in this chapter—specifying a picture by giving a logical description of ((shape))s. Bitmap graphics, on the other hand, don't specify actual shapes but rather work with ((pixel)) data (rasters of colored dots). {{index "load event", "event handling", "img (HTML tag)", "drawImage method"}} -The `drawImage` method allows us to draw ((pixel)) data onto a -((canvas)). This pixel data can originate from an `` element or -from another canvas. The following example creates a detached `` -element and loads an image file into it. But it cannot immediately -start drawing from this picture because the browser may not have -loaded it yet. To deal with this, we register a `"load"` event handler -and do the drawing after the image has loaded. +The `drawImage` method allows us to draw ((pixel)) data onto a ((canvas)). This pixel data can originate from an `` element or from another canvas. The following example creates a detached `` element and loads an image file into it. But it cannot immediately start drawing from this picture because the browser may not have loaded it yet. To deal with this, we register a `"load"` event handler and do the drawing after the image has loaded. ```{lang: "text/html"} @@ -573,42 +418,27 @@ and do the drawing after the image has loaded. {{index "drawImage method", scaling}} -By default, `drawImage` will draw the image at its original size. You -can also give it two additional arguments to set a different width -and height. +By default, `drawImage` will draw the image at its original size. You can also give it two additional arguments to set a different width and height. -When `drawImage` is given _nine_ arguments, it can be used to draw -only a fragment of an image. The second through fifth arguments -indicate the rectangle (x, y, width, and height) in the source image -that should be copied, and the sixth to ninth arguments give the -rectangle (on the canvas) into which it should be copied. +When `drawImage` is given _nine_ arguments, it can be used to draw only a fragment of an image. The second through fifth arguments indicate the rectangle (x, y, width, and height) in the source image that should be copied, and the sixth to ninth arguments give the rectangle (on the canvas) into which it should be copied. {{index "player", "pixel art"}} -This can be used to pack multiple _((sprite))s_ (image elements) into -a single image file and then draw only the part you need. For example, -we have this picture containing a game character in multiple -((pose))s: +This can be used to pack multiple _((sprite))s_ (image elements) into a single image file and then draw only the part you need. For example, we have this picture containing a game character in multiple ((pose))s: {{figure {url: "img/player_big.png", alt: "Various poses of a game character",width: "6cm"}}} {{index [animation, "platform game"]}} -By alternating which pose we draw, we can show an animation that -looks like a walking character. +By alternating which pose we draw, we can show an animation that looks like a walking character. {{index "fillRect method", "clearRect method", clearing}} -To animate a ((picture)) on a ((canvas)), the `clearRect` method is -useful. It resembles `fillRect`, but instead of coloring the -rectangle, it makes it ((transparent)), removing the previously drawn -pixels. +To animate a ((picture)) on a ((canvas)), the `clearRect` method is useful. It resembles `fillRect`, but instead of coloring the rectangle, it makes it ((transparent)), removing the previously drawn pixels. {{index "setInterval function", "img (HTML tag)"}} -We know that each _((sprite))_, each subpicture, is 24 ((pixel))s wide -and 30 pixels high. The following code loads the image and then sets -up an interval (repeated timer) to draw the next ((frame)): +We know that each _((sprite))_, each subpicture, is 24 ((pixel))s wide and 30 pixels high. The following code loads the image and then sets up an interval (repeated timer) to draw the next ((frame)): ```{lang: "text/html"} @@ -634,11 +464,7 @@ up an interval (repeated timer) to draw the next ((frame)): {{index "remainder operator", "% operator", [animation, "platform game"]}} -The `cycle` binding tracks our position in the animation. For each -((frame)), it is incremented and then clipped back to the 0 to 7 range -by using the remainder operator. This binding is then used to compute -the x-coordinate that the sprite for the current pose has in the -picture. +The `cycle` binding tracks our position in the animation. For each ((frame)), it is incremented and then clipped back to the 0 to 7 range by using the remainder operator. This binding is then used to compute the x-coordinate that the sprite for the current pose has in the picture. ## Transformation @@ -646,15 +472,11 @@ picture. {{indexsee flipping, mirroring}} -But what if we want our character to walk to the left instead of to -the right? We could draw another set of sprites, of course. But we can -also instruct the ((canvas)) to draw the picture the other way round. +But what if we want our character to walk to the left instead of to the right? We could draw another set of sprites, of course. But we can also instruct the ((canvas)) to draw the picture the other way round. {{index "scale method", scaling}} -Calling the `scale` method will cause anything drawn after it to be -scaled. This method takes two parameters, one to set a horizontal -scale and one to set a vertical scale. +Calling the `scale` method will cause anything drawn after it to be scaled. This method takes two parameters, one to set a horizontal scale and one to set a vertical scale. ```{lang: "text/html"} @@ -670,8 +492,7 @@ scale and one to set a vertical scale. {{if book -Because of the call to `scale`, the circle is drawn three times as wide -and half as high. +Because of the call to `scale`, the circle is drawn three times as wide and half as high. {{figure {url: "img/canvas_scale.png", alt: "A scaled circle",width: "6.6cm"}}} @@ -679,54 +500,29 @@ if}} {{index mirroring}} -Scaling will cause everything about the drawn image, including the -((line width)), to be stretched out or squeezed together as specified. -Scaling by a negative amount will flip the picture around. The -flipping happens around point (0,0), which means it will also flip the -direction of the coordinate system. When a horizontal scaling of -1 is -applied, a shape drawn at x position 100 will end up at what used to -be position -100. +Scaling will cause everything about the drawn image, including the ((line width)), to be stretched out or squeezed together as specified. Scaling by a negative amount will flip the picture around. The flipping happens around point (0,0), which means it will also flip the direction of the coordinate system. When a horizontal scaling of -1 is applied, a shape drawn at x position 100 will end up at what used to be position -100. {{index "drawImage method"}} -So to turn a picture around, we can't simply add `cx.scale(-1, 1)` -before the call to `drawImage` because that would move our picture -outside of the ((canvas)), where it won't be visible. You could adjust -the ((coordinates)) given to `drawImage` to compensate for this by -drawing the image at x position -50 instead of 0. Another solution, -which doesn't require the code that does the drawing to know about the -scale change, is to adjust the ((axis)) around which the scaling -happens. +So to turn a picture around, we can't simply add `cx.scale(-1, 1)` before the call to `drawImage` because that would move our picture outside of the ((canvas)), where it won't be visible. You could adjust the ((coordinates)) given to `drawImage` to compensate for this by drawing the image at x position -50 instead of 0. Another solution, which doesn't require the code that does the drawing to know about the scale change, is to adjust the ((axis)) around which the scaling happens. {{index "rotate method", "translate method", transformation}} -There are several other methods besides `scale` that influence the -coordinate system for a ((canvas)). You can rotate subsequently drawn -shapes with the `rotate` method and move them with the `translate` -method. The interesting—and confusing—thing is that these -transformations _stack_, meaning that each one happens relative to the -previous transformations. +There are several other methods besides `scale` that influence the coordinate system for a ((canvas)). You can rotate subsequently drawn shapes with the `rotate` method and move them with the `translate` method. The interesting—and confusing—thing is that these transformations _stack_, meaning that each one happens relative to the previous transformations. {{index "rotate method", "translate method"}} -So if we translate by 10 horizontal pixels twice, everything will be -drawn 20 pixels to the right. If we first move the center of the -coordinate system to (50,50) and then rotate by 20 ((degree))s (about -0.1π ((radian))s), that rotation will happen _around_ point (50,50). +So if we translate by 10 horizontal pixels twice, everything will be drawn 20 pixels to the right. If we first move the center of the coordinate system to (50,50) and then rotate by 20 ((degree))s (about 0.1π ((radian))s), that rotation will happen _around_ point (50,50). {{figure {url: "img/transform.svg", alt: "Stacking transformations",width: "9cm"}}} {{index coordinates}} -But if we _first_ rotate by 20 degrees and _then_ translate by -(50,50), the translation will happen in the rotated coordinate system -and thus produce a different orientation. The order in which -transformations are applied matters. +But if we _first_ rotate by 20 degrees and _then_ translate by (50,50), the translation will happen in the rotated coordinate system and thus produce a different orientation. The order in which transformations are applied matters. {{index axis, mirroring}} -To flip a picture around the vertical line at a given x position, we -can do the following: +To flip a picture around the vertical line at a given x position, we can do the following: ```{includeCode: true} function flipHorizontally(context, around) { @@ -738,26 +534,15 @@ function flipHorizontally(context, around) { {{index "flipHorizontally method"}} -We move the y-((axis)) to where we want our ((mirror)) to be, apply -the mirroring, and finally move the y-axis back to its proper place in -the mirrored universe. The following picture explains why this works: +We move the y-((axis)) to where we want our ((mirror)) to be, apply the mirroring, and finally move the y-axis back to its proper place in the mirrored universe. The following picture explains why this works: {{figure {url: "img/mirror.svg", alt: "Mirroring around a vertical line",width: "8cm"}}} {{index "translate method", "scale method", transformation, canvas}} -This shows the coordinate systems before and after mirroring across -the central line. The triangles are numbered to illustrate each step. -If we draw a triangle at a positive x position, it would, by default, -be in the place where triangle 1 is. A call to `flipHorizontally` -first does a translation to the right, which gets us to triangle 2. It -then scales, flipping the triangle over to position 3. This is not -where it should be, if it were mirrored in the given line. The second -`translate` call fixes this—it "cancels" the initial translation and -makes triangle 4 appear exactly where it should. +This shows the coordinate systems before and after mirroring across the central line. The triangles are numbered to illustrate each step. If we draw a triangle at a positive x position, it would, by default, be in the place where triangle 1 is. A call to `flipHorizontally` first does a translation to the right, which gets us to triangle 2. It then scales, flipping the triangle over to position 3. This is not where it should be, if it were mirrored in the given line. The second `translate` call fixes this—it "cancels" the initial translation and makes triangle 4 appear exactly where it should. -We can now draw a mirrored character at position (100,0) by flipping -the world around the character's vertical center. +We can now draw a mirrored character at position (100,0) by flipping the world around the character's vertical center. ```{lang: "text/html"} @@ -778,41 +563,19 @@ the world around the character's vertical center. {{index "side effect", canvas, transformation}} -Transformations stick around. Everything else we draw after -((drawing)) that mirrored character would also be mirrored. That might -be inconvenient. +Transformations stick around. Everything else we draw after ((drawing)) that mirrored character would also be mirrored. That might be inconvenient. -It is possible to save the current transformation, do some drawing and -transforming, and then restore the old transformation. This is usually -the proper thing to do for a function that needs to temporarily -transform the coordinate system. First, we save whatever -transformation the code that called the function was using. Then the -function does its thing, adding more transformations on top of the -current transformation. Finally, we revert to the -transformation we started with. +It is possible to save the current transformation, do some drawing and transforming, and then restore the old transformation. This is usually the proper thing to do for a function that needs to temporarily transform the coordinate system. First, we save whatever transformation the code that called the function was using. Then the function does its thing, adding more transformations on top of the current transformation. Finally, we revert to the transformation we started with. {{index "save method", "restore method", [state, "of canvas"]}} -The `save` and `restore` methods on the 2D ((canvas)) context do this -((transformation)) management. They conceptually keep a stack of -transformation states. When you call `save`, the current state is -pushed onto the stack, and when you call `restore`, the state on top -of the stack is taken off and used as the context's current -transformation. You can also call `resetTransform` to fully reset the -transformation. +The `save` and `restore` methods on the 2D ((canvas)) context do this ((transformation)) management. They conceptually keep a stack of transformation states. When you call `save`, the current state is pushed onto the stack, and when you call `restore`, the state on top of the stack is taken off and used as the context's current transformation. You can also call `resetTransform` to fully reset the transformation. {{index "branching recursion", "fractal example", recursion}} -The `branch` function in the following example illustrates what you -can do with a function that changes the transformation and then calls -a function (in this case itself), which continues drawing with -the given transformation. +The `branch` function in the following example illustrates what you can do with a function that changes the transformation and then calls a function (in this case itself), which continues drawing with the given transformation. -This function draws a treelike shape by drawing a line, moving the -center of the coordinate system to the end of the line, and calling -itself twice—first rotated to the left and then rotated to the right. -Every call reduces the length of the branch drawn, and the recursion -stops when the length drops below 8. +This function draws a treelike shape by drawing a line, moving the center of the coordinate system to the end of the line, and calling itself twice—first rotated to the left and then rotated to the right. Every call reduces the length of the branch drawn, and the recursion stops when the length drops below 8. ```{lang: "text/html"} @@ -844,12 +607,7 @@ if}} {{index "save method", "restore method", canvas, "rotate method"}} -If the calls to `save` and `restore` were not there, the second -recursive call to `branch` would end up with the position and rotation -created by the first call. It wouldn't be connected to the current -branch but rather to the innermost, rightmost branch drawn by the -first call. The resulting shape might also be interesting, but it is -definitely not a tree. +If the calls to `save` and `restore` were not there, the second recursive call to `branch` would end up with the position and rotation created by the first call. It wouldn't be connected to the current branch but rather to the innermost, rightmost branch drawn by the first call. The resulting shape might also be interesting, but it is definitely not a tree. {{id canvasdisplay}} @@ -857,26 +615,15 @@ definitely not a tree. {{index "drawImage method"}} -We now know enough about ((canvas)) drawing to start working on a -((canvas))-based ((display)) system for the ((game)) from the -[previous chapter](game). The new display will no longer be showing -just colored boxes. Instead, we'll use `drawImage` to draw pictures -that represent the game's elements. +We now know enough about ((canvas)) drawing to start working on a ((canvas))-based ((display)) system for the ((game)) from the [previous chapter](game). The new display will no longer be showing just colored boxes. Instead, we'll use `drawImage` to draw pictures that represent the game's elements. {{index "CanvasDisplay class", "DOMDisplay class", [interface, object]}} -We define another display object type called `CanvasDisplay`, -supporting the same interface as `DOMDisplay` from [Chapter -?](game#domdisplay), namely, the methods `syncState` and `clear`. +We define another display object type called `CanvasDisplay`, supporting the same interface as `DOMDisplay` from [Chapter ?](game#domdisplay), namely, the methods `syncState` and `clear`. {{index [state, "in objects"]}} -This object keeps a little more information than `DOMDisplay`. Rather -than using the scroll position of its DOM element, it tracks its own -((viewport)), which tells us what part of the level we are currently -looking at. Finally, it keeps a `flipPlayer` property so that even -when the player is standing still, it keeps facing the direction it -last moved in. +This object keeps a little more information than `DOMDisplay`. Rather than using the scroll position of its DOM element, it tracks its own ((viewport)), which tells us what part of the level we are currently looking at. Finally, it keeps a `flipPlayer` property so that even when the player is standing still, it keeps facing the direction it last moved in. ```{sandbox: "game", includeCode: true} class CanvasDisplay { @@ -903,8 +650,7 @@ class CanvasDisplay { } ``` -The `syncState` method first computes a new viewport and then draws -the game scene at the appropriate position. +The `syncState` method first computes a new viewport and then draws the game scene at the appropriate position. ```{sandbox: "game", includeCode: true} CanvasDisplay.prototype.syncState = function(state) { @@ -917,19 +663,11 @@ CanvasDisplay.prototype.syncState = function(state) { {{index scrolling, clearing}} -Contrary to `DOMDisplay`, this display style _does_ have to redraw the -background on every update. Because shapes on a canvas are just -((pixel))s, after we draw them there is no good way to move them (or -remove them). The only way to update the canvas display is to clear it -and redraw the scene. We may also have scrolled, which requires the -background to be in a different position. +Contrary to `DOMDisplay`, this display style _does_ have to redraw the background on every update. Because shapes on a canvas are just ((pixel))s, after we draw them there is no good way to move them (or remove them). The only way to update the canvas display is to clear it and redraw the scene. We may also have scrolled, which requires the background to be in a different position. {{index "CanvasDisplay class"}} -The `updateViewport` method is similar to `DOMDisplay`'s -`scrollPlayerIntoView` method. It checks whether the player is too -close to the edge of the screen and moves the ((viewport)) when this -is the case. +The `updateViewport` method is similar to `DOMDisplay`'s `scrollPlayerIntoView` method. It checks whether the player is too close to the edge of the screen and moves the ((viewport)) when this is the case. ```{sandbox: "game", includeCode: true} CanvasDisplay.prototype.updateViewport = function(state) { @@ -954,14 +692,9 @@ CanvasDisplay.prototype.updateViewport = function(state) { {{index boundary, "Math.max function", "Math.min function", clipping}} -The calls to `Math.max` and `Math.min` ensure that the viewport does -not end up showing space outside of the level. `Math.max(x, 0)` makes -sure the resulting number is not less than zero. `Math.min` -similarly guarantees that a value stays below a given bound. +The calls to `Math.max` and `Math.min` ensure that the viewport does not end up showing space outside of the level. `Math.max(x, 0)` makes sure the resulting number is not less than zero. `Math.min` similarly guarantees that a value stays below a given bound. -When ((clearing)) the display, we'll use a slightly different -((color)) depending on whether the game is won (brighter) or lost -(darker). +When ((clearing)) the display, we'll use a slightly different ((color)) depending on whether the game is won (brighter) or lost (darker). ```{sandbox: "game", includeCode: true} CanvasDisplay.prototype.clearDisplay = function(status) { @@ -979,9 +712,7 @@ CanvasDisplay.prototype.clearDisplay = function(status) { {{index "Math.floor function", "Math.ceil function", rounding}} -To draw the background, we run through the tiles that are visible in -the current viewport, using the same trick used in the `touches` -method from the [previous chapter](game#touches). +To draw the background, we run through the tiles that are visible in the current viewport, using the same trick used in the `touches` method from the [previous chapter](game#touches). ```{sandbox: "game", includeCode: true} let otherSprites = document.createElement("img"); @@ -1011,46 +742,25 @@ CanvasDisplay.prototype.drawBackground = function(level) { {{index "drawImage method", sprite, tile}} -Tiles that are not empty are drawn with `drawImage`. The -`otherSprites` image contains the pictures used for elements other -than the player. It contains, from left to right, the wall tile, the -lava tile, and the sprite for a coin. +Tiles that are not empty are drawn with `drawImage`. The `otherSprites` image contains the pictures used for elements other than the player. It contains, from left to right, the wall tile, the lava tile, and the sprite for a coin. {{figure {url: "img/sprites_big.png", alt: "Sprites for our game",width: "1.4cm"}}} {{index scaling}} -Background tiles are 20 by 20 pixels since we will use the same scale -that we used in `DOMDisplay`. Thus, the offset for lava tiles is 20 -(the value of the `scale` binding), and the offset for walls is 0. +Background tiles are 20 by 20 pixels since we will use the same scale that we used in `DOMDisplay`. Thus, the offset for lava tiles is 20 (the value of the `scale` binding), and the offset for walls is 0. {{index drawing, "load event", "drawImage method"}} -We don't bother waiting for the sprite image to load. Calling -`drawImage` with an image that hasn't been loaded yet will simply do -nothing. Thus, we might fail to draw the game properly for the first -few ((frame))s, while the image is still loading, but that is not a -serious problem. Since we keep updating the screen, the correct scene -will appear as soon as the loading finishes. +We don't bother waiting for the sprite image to load. Calling `drawImage` with an image that hasn't been loaded yet will simply do nothing. Thus, we might fail to draw the game properly for the first few ((frame))s, while the image is still loading, but that is not a serious problem. Since we keep updating the screen, the correct scene will appear as soon as the loading finishes. {{index "player", [animation, "platform game"], drawing}} -The ((walking)) character shown earlier will be used to represent the -player. The code that draws it needs to pick the right ((sprite)) and -direction based on the player's current motion. The first eight -sprites contain a walking animation. When the player is moving along a -floor, we cycle through them based on the current time. We want to -switch frames every 60 milliseconds, so the ((time)) is divided by 60 -first. When the player is standing still, we draw the ninth sprite. -During jumps, which are recognized by the fact that the vertical speed -is not zero, we use the tenth, rightmost sprite. +The ((walking)) character shown earlier will be used to represent the player. The code that draws it needs to pick the right ((sprite)) and direction based on the player's current motion. The first eight sprites contain a walking animation. When the player is moving along a floor, we cycle through them based on the current time. We want to switch frames every 60 milliseconds, so the ((time)) is divided by 60 first. When the player is standing still, we draw the ninth sprite. During jumps, which are recognized by the fact that the vertical speed is not zero, we use the tenth, rightmost sprite. {{index "flipHorizontally function", "CanvasDisplay class"}} -Because the ((sprite))s are slightly wider than the player object—24 -instead of 16 pixels to allow some space for feet and arms—the method -has to adjust the x-coordinate and width by a given amount -(`playerXOverlap`). +Because the ((sprite))s are slightly wider than the player object—24 instead of 16 pixels to allow some space for feet and arms—the method has to adjust the x-coordinate and width by a given amount (`playerXOverlap`). ```{sandbox: "game", includeCode: true} let playerSprites = document.createElement("img"); @@ -1083,8 +793,7 @@ CanvasDisplay.prototype.drawPlayer = function(player, x, y, }; ``` -The `drawPlayer` method is called by `drawActors`, which is -responsible for drawing all the actors in the game. +The `drawPlayer` method is called by `drawActors`, which is responsible for drawing all the actors in the game. ```{sandbox: "game", includeCode: true} CanvasDisplay.prototype.drawActors = function(actors) { @@ -1105,17 +814,11 @@ CanvasDisplay.prototype.drawActors = function(actors) { }; ``` -When ((drawing)) something that is not the ((player)), we look at its -type to find the offset of the correct sprite. The ((lava)) tile is -found at offset 20, and the ((coin)) sprite is found at 40 (two times -`scale`). +When ((drawing)) something that is not the ((player)), we look at its type to find the offset of the correct sprite. The ((lava)) tile is found at offset 20, and the ((coin)) sprite is found at 40 (two times `scale`). {{index viewport}} -We have to subtract the viewport's position when computing the actor's -position since (0,0) on our ((canvas)) corresponds to the top left of -the viewport, not the top left of the level. We could also have used -`translate` for this. Either way works. +We have to subtract the viewport's position when computing the actor's position since (0,0) on our ((canvas)) corresponds to the top left of the viewport, not the top left of the level. We could also have used `translate` for this. Either way works. {{if interactive @@ -1135,8 +838,7 @@ if}} {{index [game, screenshot], [game, "with canvas"]}} -That concludes the new ((display)) system. The resulting game looks -something like this: +That concludes the new ((display)) system. The resulting game looks something like this: {{figure {url: "img/canvas_game.png", alt: "The game as shown on canvas",width: "8cm"}}} @@ -1146,105 +848,53 @@ if}} ## Choosing a graphics interface -So when you need to generate graphics in the browser, you can choose -between plain HTML, ((SVG)), and ((canvas)). There is no single -_best_ approach that works in all situations. Each option has -strengths and weaknesses. +So when you need to generate graphics in the browser, you can choose between plain HTML, ((SVG)), and ((canvas)). There is no single _best_ approach that works in all situations. Each option has strengths and weaknesses. {{index "text wrapping"}} -Plain HTML has the advantage of being simple. It also integrates well -with ((text)). Both SVG and canvas allow you to draw text, but they -won't help you position that text or wrap it when it takes up more -than one line. In an HTML-based picture, it is much easier to include -blocks of text. +Plain HTML has the advantage of being simple. It also integrates well with ((text)). Both SVG and canvas allow you to draw text, but they won't help you position that text or wrap it when it takes up more than one line. In an HTML-based picture, it is much easier to include blocks of text. {{index zooming, SVG}} -SVG can be used to produce ((crisp)) ((graphics)) that look good at -any zoom level. Unlike HTML, it is designed for drawing -and is thus more suitable for that purpose. +SVG can be used to produce ((crisp)) ((graphics)) that look good at any zoom level. Unlike HTML, it is designed for drawing and is thus more suitable for that purpose. {{index [DOM, graphics], SVG, "event handling", ["data structure", tree]}} -Both SVG and HTML build up a data structure (the DOM) that -represents your picture. This makes it possible to modify elements -after they are drawn. If you need to repeatedly change a small part of -a big ((picture)) in response to what the user is doing or as part of -an ((animation)), doing it in a canvas can be needlessly expensive. -The DOM also allows us to register mouse event handlers on every -element in the picture (even on shapes drawn with SVG). You can't do -that with canvas. +Both SVG and HTML build up a data structure (the DOM) that represents your picture. This makes it possible to modify elements after they are drawn. If you need to repeatedly change a small part of a big ((picture)) in response to what the user is doing or as part of an ((animation)), doing it in a canvas can be needlessly expensive. The DOM also allows us to register mouse event handlers on every element in the picture (even on shapes drawn with SVG). You can't do that with canvas. {{index performance, optimization}} -But ((canvas))'s ((pixel))-oriented approach can be an advantage when -drawing a huge number of tiny elements. The fact that it does not -build up a data structure but only repeatedly draws onto the same -pixel surface gives canvas a lower cost per shape. +But ((canvas))'s ((pixel))-oriented approach can be an advantage when drawing a huge number of tiny elements. The fact that it does not build up a data structure but only repeatedly draws onto the same pixel surface gives canvas a lower cost per shape. {{index "ray tracer"}} -There are also effects, such as rendering a scene one pixel at a time -(for example, using a ray tracer) or postprocessing an image with -JavaScript (blurring or distorting it), that can be realistically -handled only by a ((pixel))-based approach. +There are also effects, such as rendering a scene one pixel at a time (for example, using a ray tracer) or postprocessing an image with JavaScript (blurring or distorting it), that can be realistically handled only by a ((pixel))-based approach. -In some cases, you may want to combine several of these techniques. -For example, you might draw a ((graph)) with ((SVG)) or ((canvas)) but -show ((text))ual information by positioning an HTML element on top -of the picture. +In some cases, you may want to combine several of these techniques. For example, you might draw a ((graph)) with ((SVG)) or ((canvas)) but show ((text))ual information by positioning an HTML element on top of the picture. {{index display}} -For nondemanding applications, it really doesn't matter much which -interface you choose. The display we built for our game in this -chapter could have been implemented using any of these three -((graphics)) technologies since it does not need to draw text, handle -mouse interaction, or work with an extraordinarily large number of -elements. +For nondemanding applications, it really doesn't matter much which interface you choose. The display we built for our game in this chapter could have been implemented using any of these three ((graphics)) technologies since it does not need to draw text, handle mouse interaction, or work with an extraordinarily large number of elements. ## Summary -In this chapter we discussed techniques for drawing graphics in the -browser, focusing on the `` element. +In this chapter we discussed techniques for drawing graphics in the browser, focusing on the `` element. -A canvas node represents an area in a document that our program may -draw on. This drawing is done through a drawing context object, -created with the `getContext` method. +A canvas node represents an area in a document that our program may draw on. This drawing is done through a drawing context object, created with the `getContext` method. -The 2D drawing interface allows us to fill and stroke various shapes. -The context's `fillStyle` property determines how shapes are filled. -The `strokeStyle` and `lineWidth` properties control the way lines are -drawn. +The 2D drawing interface allows us to fill and stroke various shapes. The context's `fillStyle` property determines how shapes are filled. The `strokeStyle` and `lineWidth` properties control the way lines are drawn. -Rectangles and pieces of text can be drawn with a single method call. -The `fillRect` and `strokeRect` methods draw rectangles, and the -`fillText` and `strokeText` methods draw text. To create custom -shapes, we must first build up a path. +Rectangles and pieces of text can be drawn with a single method call. The `fillRect` and `strokeRect` methods draw rectangles, and the `fillText` and `strokeText` methods draw text. To create custom shapes, we must first build up a path. {{index stroking, filling}} -Calling `beginPath` starts a new path. A number of other methods add -lines and curves to the current path. For example, `lineTo` can add a -straight line. When a path is finished, it can be filled with the -`fill` method or stroked with the `stroke` method. +Calling `beginPath` starts a new path. A number of other methods add lines and curves to the current path. For example, `lineTo` can add a straight line. When a path is finished, it can be filled with the `fill` method or stroked with the `stroke` method. -Moving pixels from an image or another canvas onto our canvas is done -with the `drawImage` method. By default, this method draws the whole -source image, but by giving it more parameters, you can copy a -specific area of the image. We used this for our game by copying -individual poses of the game character out of an image that contained -many such poses. +Moving pixels from an image or another canvas onto our canvas is done with the `drawImage` method. By default, this method draws the whole source image, but by giving it more parameters, you can copy a specific area of the image. We used this for our game by copying individual poses of the game character out of an image that contained many such poses. -Transformations allow you to draw a shape in multiple orientations. A -2D drawing context has a current transformation that can be changed -with the `translate`, `scale`, and `rotate` methods. These will affect -all subsequent drawing operations. A transformation state can be saved -with the `save` method and restored with the `restore` method. +Transformations allow you to draw a shape in multiple orientations. A 2D drawing context has a current transformation that can be changed with the `translate`, `scale`, and `rotate` methods. These will affect all subsequent drawing operations. A transformation state can be saved with the `save` method and restored with the `restore` method. -When showing an animation on a canvas, the `clearRect` method can be -used to clear part of the canvas before redrawing it. +When showing an animation on a canvas, the `clearRect` method can be used to clear part of the canvas before redrawing it. ## Exercises @@ -1268,16 +918,11 @@ Write a program that draws the following ((shape))s on a ((canvas)): {{figure {url: "img/exercise_shapes.png", alt: "The shapes to draw",width: "8cm"}}} -When drawing the last two, you may want to refer to the explanation of -`Math.cos` and `Math.sin` in [Chapter ?](dom#sin_cos), which describes -how to get coordinates on a circle using these functions. +When drawing the last two, you may want to refer to the explanation of `Math.cos` and `Math.sin` in [Chapter ?](dom#sin_cos), which describes how to get coordinates on a circle using these functions. {{index readability, "hard-coding"}} -I recommend creating a function for each shape. Pass the position, and -optionally other properties such as the size or the number of points, -as parameters. The alternative, which is to hard-code numbers all over -your code, tends to make the code needlessly hard to read and modify. +I recommend creating a function for each shape. Pass the position, and optionally other properties such as the size or the number of points, as parameters. The alternative, which is to hard-code numbers all over your code, tends to make the code needlessly hard to read and modify. {{if interactive @@ -1296,43 +941,23 @@ if}} {{index [path, canvas], "shapes (exercise)"}} -The ((trapezoid)) (1) is easiest to draw using a path. Pick suitable -center coordinates and add each of the four corners around the center. +The ((trapezoid)) (1) is easiest to draw using a path. Pick suitable center coordinates and add each of the four corners around the center. {{index "flipHorizontally function", rotation}} -The ((diamond)) (2) can be drawn the straightforward way, with a path, -or the interesting way, with a `rotate` ((transformation)). To use -rotation, you will have to apply a trick similar to what we did in the -`flipHorizontally` function. Because you want to rotate around the -center of your rectangle and not around the point (0,0), you must -first `translate` to there, then rotate, and then translate back. +The ((diamond)) (2) can be drawn the straightforward way, with a path, or the interesting way, with a `rotate` ((transformation)). To use rotation, you will have to apply a trick similar to what we did in the `flipHorizontally` function. Because you want to rotate around the center of your rectangle and not around the point (0,0), you must first `translate` to there, then rotate, and then translate back. -Make sure you reset the transformation after drawing any shape that -creates one. +Make sure you reset the transformation after drawing any shape that creates one. {{index "remainder operator", "% operator"}} -For the ((zigzag)) (3) it becomes impractical to write a new call to -`lineTo` for each line segment. Instead, you should use a ((loop)). -You can have each iteration draw either two ((line)) segments (right -and then left again) or one, in which case you must use the evenness -(`% 2`) of the loop index to determine whether to go left or right. +For the ((zigzag)) (3) it becomes impractical to write a new call to `lineTo` for each line segment. Instead, you should use a ((loop)). You can have each iteration draw either two ((line)) segments (right and then left again) or one, in which case you must use the evenness (`% 2`) of the loop index to determine whether to go left or right. -You'll also need a loop for the ((spiral)) (4). If you draw a series -of points, with each point moving further along a circle around the -spiral's center, you get a circle. If, during the loop, you vary the -radius of the circle on which you are putting the current point and go -around more than once, the result is a spiral. +You'll also need a loop for the ((spiral)) (4). If you draw a series of points, with each point moving further along a circle around the spiral's center, you get a circle. If, during the loop, you vary the radius of the circle on which you are putting the current point and go around more than once, the result is a spiral. {{index "quadraticCurveTo method"}} -The ((star)) (5) depicted is built out of `quadraticCurveTo` lines. -You could also draw one with straight lines. Divide a circle into -eight pieces for a star with eight points, or however many pieces you -want. Draw lines between these points, making them curve toward the -center of the star. With `quadraticCurveTo`, you can use the center as -the control point. +The ((star)) (5) depicted is built out of `quadraticCurveTo` lines. You could also draw one with straight lines. Divide a circle into eight pieces for a star with eight points, or however many pieces you want. Draw lines between these points, making them curve toward the center of the star. With `quadraticCurveTo`, you can use the center as the control point. hint}} @@ -1342,15 +967,9 @@ hint}} {{index label, text, "pie chart example"}} -[Earlier](canvas#pie_chart) in the chapter, we saw an example program -that drew a pie chart. Modify this program so that the name of each -category is shown next to the slice that represents it. Try to find a -pleasing-looking way to automatically position this text that would -work for other data sets as well. You may assume that categories are -big enough to leave ample room for their labels. +[Earlier](canvas#pie_chart) in the chapter, we saw an example program that drew a pie chart. Modify this program so that the name of each category is shown next to the slice that represents it. Try to find a pleasing-looking way to automatically position this text that would work for other data sets as well. You may assume that categories are big enough to leave ample room for their labels. -You might need `Math.sin` and `Math.cos` again, which are described in -[Chapter ?](dom#sin_cos). +You might need `Math.sin` and `Math.cos` again, which are described in [Chapter ?](dom#sin_cos). {{if interactive @@ -1383,19 +1002,11 @@ if}} {{index "fillText method", "textAlign property", "textBaseline property", "pie chart example"}} -You will need to call `fillText` and set the context's `textAlign` and -`textBaseline` properties in such a way that the text ends up where -you want it. +You will need to call `fillText` and set the context's `textAlign` and `textBaseline` properties in such a way that the text ends up where you want it. -A sensible way to position the labels would be to put the text on the -line going from the center of the pie through the middle of the slice. -You don't want to put the text directly against the side of the pie -but rather move the text out to the side of the pie by a given number -of pixels. +A sensible way to position the labels would be to put the text on the line going from the center of the pie through the middle of the slice. You don't want to put the text directly against the side of the pie but rather move the text out to the side of the pie by a given number of pixels. -The ((angle)) of this line is `currentAngle + 0.5 * sliceAngle`. The -following code finds a position on this line 120 pixels from the -center: +The ((angle)) of this line is `currentAngle + 0.5 * sliceAngle`. The following code finds a position on this line 120 pixels from the center: ```{test: no} let middleAngle = currentAngle + 0.5 * sliceAngle; @@ -1403,19 +1014,11 @@ let textX = Math.cos(middleAngle) * 120 + centerX; let textY = Math.sin(middleAngle) * 120 + centerY; ``` -For `textBaseline`, the value `"middle"` is probably appropriate when -using this approach. What to use for `textAlign` depends on which side -of the circle we are on. On the left, it should be `"right"`, and on -the right, it should be `"left"`, so that the text is positioned away -from the pie. +For `textBaseline`, the value `"middle"` is probably appropriate when using this approach. What to use for `textAlign` depends on which side of the circle we are on. On the left, it should be `"right"`, and on the right, it should be `"left"`, so that the text is positioned away from the pie. {{index "Math.cos function"}} -If you are not sure how to find out which side of the circle a given -angle is on, look to the explanation of `Math.cos` in [Chapter -?](dom#sin_cos). The cosine of an angle tells us which x-coordinate it -corresponds to, which in turn tells us exactly which side of the -circle we are on. +If you are not sure how to find out which side of the circle a given angle is on, look to the explanation of `Math.cos` in [Chapter ?](dom#sin_cos). The cosine of an angle tells us which x-coordinate it corresponds to, which in turn tells us exactly which side of the circle we are on. hint}} @@ -1423,10 +1026,7 @@ hint}} {{index [animation, "bouncing ball"], "requestAnimationFrame function", bouncing}} -Use the `requestAnimationFrame` technique that we saw in [Chapter -?](dom#animationFrame) and [Chapter ?](game#runAnimation) to draw a -((box)) with a bouncing ((ball)) in it. The ball moves at a constant -((speed)) and bounces off the box's sides when it hits them. +Use the `requestAnimationFrame` technique that we saw in [Chapter ?](dom#animationFrame) and [Chapter ?](game#runAnimation) to draw a ((box)) with a bouncing ((ball)) in it. The ball moves at a constant ((speed)) and bounces off the box's sides when it hits them. {{if interactive @@ -1457,26 +1057,15 @@ if}} {{index "strokeRect method", animation, "arc method"}} -A ((box)) is easy to draw with `strokeRect`. Define a binding that -holds its size or define two bindings if your box's width and height -differ. To create a round ((ball)), start a path and call `arc(x, y, -radius, 0, 7)`, which creates an arc going from zero to more than a -whole circle. Then fill the path. +A ((box)) is easy to draw with `strokeRect`. Define a binding that holds its size or define two bindings if your box's width and height differ. To create a round ((ball)), start a path and call `arc(x, y, radius, 0, 7)`, which creates an arc going from zero to more than a whole circle. Then fill the path. {{index "collision detection", "Vec class"}} -To model the ball's position and ((speed)), you can use the `Vec` -class from [Chapter ?](game#vector)[ (which is available on this -page)]{if interactive}. Give it a starting speed, preferably one that -is not purely vertical or horizontal, and for every ((frame)) multiply -that speed by the amount of time that elapsed. When the ball gets -too close to a vertical wall, invert the x component in its speed. -Likewise, invert the y component when it hits a horizontal wall. +To model the ball's position and ((speed)), you can use the `Vec` class from [Chapter ?](game#vector)[ (which is available on this page)]{if interactive}. Give it a starting speed, preferably one that is not purely vertical or horizontal, and for every ((frame)) multiply that speed by the amount of time that elapsed. When the ball gets too close to a vertical wall, invert the x component in its speed. Likewise, invert the y component when it hits a horizontal wall. {{index "clearRect method", clearing}} -After finding the ball's new position and speed, use `clearRect` to -delete the scene and redraw it using the new position. +After finding the ball's new position and speed, use `clearRect` to delete the scene and redraw it using the new position. hint}} @@ -1484,38 +1073,21 @@ hint}} {{index optimization, "bitmap graphics", mirror}} -One unfortunate thing about ((transformation))s is that they slow down -the drawing of bitmaps. The position and size of each ((pixel)) has to be -transformed, and though it is possible that ((browser))s will get -cleverer about transformation in the ((future)), they currently cause a -measurable increase in the time it takes to draw a bitmap. +One unfortunate thing about ((transformation))s is that they slow down the drawing of bitmaps. The position and size of each ((pixel)) has to be transformed, and though it is possible that ((browser))s will get cleverer about transformation in the ((future)), they currently cause a measurable increase in the time it takes to draw a bitmap. -In a game like ours, where we are drawing only a single transformed -sprite, this is a nonissue. But imagine that we need to draw hundreds -of characters or thousands of rotating particles from an explosion. +In a game like ours, where we are drawing only a single transformed sprite, this is a nonissue. But imagine that we need to draw hundreds of characters or thousands of rotating particles from an explosion. -Think of a way to allow us to draw an inverted character without -loading additional image files and without having to make transformed -`drawImage` calls every frame. +Think of a way to allow us to draw an inverted character without loading additional image files and without having to make transformed `drawImage` calls every frame. {{hint {{index mirror, scaling, "drawImage method"}} -The key to the solution is the fact that we can use a ((canvas)) -element as a source image when using `drawImage`. It is possible to -create an extra `` element, without adding it to the document, -and draw our inverted sprites to it, once. When drawing an actual -frame, we just copy the already inverted sprites to the main canvas. +The key to the solution is the fact that we can use a ((canvas)) element as a source image when using `drawImage`. It is possible to create an extra `` element, without adding it to the document, and draw our inverted sprites to it, once. When drawing an actual frame, we just copy the already inverted sprites to the main canvas. {{index "load event"}} -Some care would be required because images do not load instantly. We -do the inverted drawing only once, and if we do it before the image -loads, it won't draw anything. A `"load"` handler on the image can be -used to draw the inverted images to the extra canvas. This canvas can -be used as a drawing source immediately (it'll simply be blank until -we draw the character onto it). +Some care would be required because images do not load instantly. We do the inverted drawing only once, and if we do it before the image loads, it won't draw anything. A `"load"` handler on the image can be used to draw the inverted images to the extra canvas. This canvas can be used as a drawing source immediately (it'll simply be blank until we draw the character onto it). hint}} diff --git a/18_http.md b/18_http.md index 3f0713ca4..e920454a1 100644 --- a/18_http.md +++ b/18_http.md @@ -4,10 +4,7 @@ {{quote {author: "Roy Fielding", title: "Architectural Styles and the Design of Network-based Software Architectures", chapter: true} -Communication must be stateless in nature [...] such that each request -from client to server must contain all of the information necessary to -understand the request, and cannot take advantage of any stored -context on the server. +Communication must be stateless in nature [...] such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. quote}} @@ -17,22 +14,13 @@ quote}} {{index [browser, environment]}} -The _Hypertext Transfer Protocol_, already mentioned in [Chapter -?](browser#web), is the mechanism through which data is requested and -provided on the ((World Wide Web)). This chapter describes the -((protocol)) in more detail and explains the way browser -JavaScript has access to it. +The _Hypertext Transfer Protocol_, already mentioned in [Chapter ?](browser#web), is the mechanism through which data is requested and provided on the ((World Wide Web)). This chapter describes the ((protocol)) in more detail and explains the way browser JavaScript has access to it. ## The protocol {{index "IP address"}} -If you type _eloquentjavascript.net/18_http.html_ into your browser's -((address bar)), the ((browser)) first looks up the ((address)) of the -server associated with _eloquentjavascript.net_ and tries to open a -((TCP)) ((connection)) to it on ((port)) 80, the default port for -((HTTP)) traffic. If the ((server)) exists and accepts the connection, -the browser might send something like this: +If you type _eloquentjavascript.net/18_http.html_ into your browser's ((address bar)), the ((browser)) first looks up the ((address)) of the server associated with _eloquentjavascript.net_ and tries to open a ((TCP)) ((connection)) to it on ((port)) 80, the default port for ((HTTP)) traffic. If the ((server)) exists and accepts the connection, the browser might send something like this: ```{lang: http} GET /18_http.html HTTP/1.1 @@ -52,14 +40,11 @@ Last-Modified: Mon, 08 Jan 2018 10:29:45 GMT ... the rest of the document ``` -The browser takes the part of the ((response)) after the blank line, -its _body_ (not to be confused with the HTML `` tag), and -displays it as an ((HTML)) document. +The browser takes the part of the ((response)) after the blank line, its _body_ (not to be confused with the HTML `` tag), and displays it as an ((HTML)) document. {{index HTTP}} -The information sent by the client is called the _((request))_. It -starts with this line: +The information sent by the client is called the _((request))_. It starts with this line: ```{lang: http} GET /18_http.html HTTP/1.1 @@ -67,42 +52,19 @@ GET /18_http.html HTTP/1.1 {{index "DELETE method", "PUT method", "GET method", [method, HTTP]}} -The first word is the _method_ of the ((request)). `GET` means -that we want to _get_ the specified resource. Other common methods are -`DELETE` to delete a resource, `PUT` to create or replace it, and `POST` to send -information to it. Note that the ((server)) is not obliged to carry -out every request it gets. If you walk up to a random website and tell -it to `DELETE` its main page, it'll probably refuse. +The first word is the _method_ of the ((request)). `GET` means that we want to _get_ the specified resource. Other common methods are `DELETE` to delete a resource, `PUT` to create or replace it, and `POST` to send information to it. Note that the ((server)) is not obliged to carry out every request it gets. If you walk up to a random website and tell it to `DELETE` its main page, it'll probably refuse. {{index [path, URL], GitHub, [file, resource]}} -The part after the method name is the path of the _((resource))_ the -request applies to. In the simplest case, a resource is simply a -file on the ((server)), but the protocol doesn't require it to be. -A resource may be anything that can be transferred _as if_ it is a -file. Many servers generate the responses they produce on the fly. For -example, if you open -[_https://github.com/marijnh_](https://github.com/marijnh), the server looks -in its database for a user named "marijnh", and if it finds one, it -will generate a profile page for that user. - -After the resource path, the first line of the request mentions -`HTTP/1.1` to indicate the ((version)) of the ((HTTP)) ((protocol)) it -is using. - -In practice, many sites use HTTP version 2, which supports the same -concepts as version 1.1 but is a lot more complicated so that it can -be faster. Browsers will automatically switch to the appropriate -protocol version when talking to a given server, and the outcome of a -request is the same regardless of which version is used. Because version -1.1 is more straightforward and easier to play around with, we'll -focus on that. +The part after the method name is the path of the _((resource))_ the request applies to. In the simplest case, a resource is simply a file on the ((server)), but the protocol doesn't require it to be. A resource may be anything that can be transferred _as if_ it is a file. Many servers generate the responses they produce on the fly. For example, if you open [_https://github.com/marijnh_](https://github.com/marijnh), the server looks in its database for a user named "marijnh", and if it finds one, it will generate a profile page for that user. + +After the resource path, the first line of the request mentions `HTTP/1.1` to indicate the ((version)) of the ((HTTP)) ((protocol)) it is using. + +In practice, many sites use HTTP version 2, which supports the same concepts as version 1.1 but is a lot more complicated so that it can be faster. Browsers will automatically switch to the appropriate protocol version when talking to a given server, and the outcome of a request is the same regardless of which version is used. Because version 1.1 is more straightforward and easier to play around with, we'll focus on that. {{index "status code"}} -The server's ((response)) will start with a version as well, followed -by the status of the response, first as a three-digit status code and -then as a human-readable string. +The server's ((response)) will start with a version as well, followed by the status of the response, first as a three-digit status code and then as a human-readable string. ```{lang: http} HTTP/1.1 200 OK @@ -110,20 +72,13 @@ HTTP/1.1 200 OK {{index "200 (HTTP status code)", "error response", "404 (HTTP status code)"}} -Status codes starting with a 2 indicate that the request succeeded. -Codes starting with 4 mean there was something wrong with the -((request)). 404 is probably the most famous HTTP status code—it means -that the resource could not be found. Codes that start with 5 mean an -error happened on the ((server)) and the request is not to blame. +Status codes starting with a 2 indicate that the request succeeded. Codes starting with 4 mean there was something wrong with the ((request)). 404 is probably the most famous HTTP status code—it means that the resource could not be found. Codes that start with 5 mean an error happened on the ((server)) and the request is not to blame. {{index HTTP}} {{id headers}} -The first line of a request or response may be followed by any number -of _((header))s_. These are lines in the form `name: value` that -specify extra information about the request or response. These headers -were part of the example ((response)): +The first line of a request or response may be followed by any number of _((header))s_. These are lines in the form `name: value` that specify extra information about the request or response. These headers were part of the example ((response)): ```{lang: null} Content-Length: 65585 @@ -133,46 +88,27 @@ Last-Modified: Thu, 04 Jan 2018 14:05:30 GMT {{index "Content-Length header", "Content-Type header", "Last-Modified header"}} -This tells us the size and type of the response document. In this -case, it is an HTML document of 65,585 bytes. It also tells us when -that document was last modified. +This tells us the size and type of the response document. In this case, it is an HTML document of 65,585 bytes. It also tells us when that document was last modified. {{index "Host header", domain}} -For most ((header))s, the client and server are free to decide whether -to include them in a ((request)) or ((response)). But a few are -required. For example, the `Host` header, which specifies the -hostname, should be included in a request because a ((server)) might -be serving multiple hostnames on a single ((IP address)), and without -that header, the server won't know which hostname the client is trying -to talk to. +For most ((header))s, the client and server are free to decide whether to include them in a ((request)) or ((response)). But a few are required. For example, the `Host` header, which specifies the hostname, should be included in a request because a ((server)) might be serving multiple hostnames on a single ((IP address)), and without that header, the server won't know which hostname the client is trying to talk to. {{index "GET method", "DELETE method", "PUT method", "POST method", "body (HTTP)"}} -After the headers, both requests and responses may include a blank -line followed by a body, which contains the data being sent. `GET` and -`DELETE` requests don't send along any data, but `PUT` and `POST` -requests do. Similarly, some response types, such as error responses, -do not require a body. +After the headers, both requests and responses may include a blank line followed by a body, which contains the data being sent. `GET` and `DELETE` requests don't send along any data, but `PUT` and `POST` requests do. Similarly, some response types, such as error responses, do not require a body. ## Browsers and HTTP {{index HTTP, [file, resource]}} -As we saw in the example, a ((browser)) will make a request when we -enter a ((URL)) in its ((address bar)). When the resulting HTML page -references other files, such as ((image))s and JavaScript files, -those are also retrieved. +As we saw in the example, a ((browser)) will make a request when we enter a ((URL)) in its ((address bar)). When the resulting HTML page references other files, such as ((image))s and JavaScript files, those are also retrieved. {{index parallelism, "GET method"}} -A moderately complicated ((website)) can easily include anywhere from -10 to 200 ((resource))s. To be able to fetch those quickly, browsers -will make several `GET` requests simultaneously, rather than waiting -for the responses one at a time. +A moderately complicated ((website)) can easily include anywhere from 10 to 200 ((resource))s. To be able to fetch those quickly, browsers will make several `GET` requests simultaneously, rather than waiting for the responses one at a time. -HTML pages may include _((form))s_, which allow the user to fill out -information and send it to the server. This is an example of a form: +HTML pages may include _((form))s_, which allow the user to fill out information and send it to the server. This is an example of a form: ```{lang: "text/html"}
@@ -184,16 +120,9 @@ information and send it to the server. This is an example of a form: {{index form, "method attribute", "GET method"}} -This code describes a form with two ((field))s: a small one asking for -a name and a larger one to write a message in. When you click the Send -((button)), the form is _submitted_, meaning that the content of its -field is packed into an HTTP request and the browser navigates to the -result of that request. +This code describes a form with two ((field))s: a small one asking for a name and a larger one to write a message in. When you click the Send ((button)), the form is _submitted_, meaning that the content of its field is packed into an HTTP request and the browser navigates to the result of that request. -When the `` element's `method` attribute is `GET` (or is -omitted), the information in the form is added to the end of the -`action` URL as a _((query string))_. The browser might make a request -to this URL: +When the `` element's `method` attribute is `GET` (or is omitted), the information in the form is added to the end of the `action` URL as a _((query string))_. The browser might make a request to this URL: ```{lang: null} GET /example/message.html?name=Jean&message=Yes%3F HTTP/1.1 @@ -201,24 +130,11 @@ GET /example/message.html?name=Jean&message=Yes%3F HTTP/1.1 {{index "ampersand character"}} -The ((question mark)) indicates the end of the path part of the URL -and the start of the query. It is followed by pairs of names and -values, corresponding to the `name` attribute on the form field -elements and the content of those elements, respectively. An ampersand -character (`&`) is used to separate the pairs. +The ((question mark)) indicates the end of the path part of the URL and the start of the query. It is followed by pairs of names and values, corresponding to the `name` attribute on the form field elements and the content of those elements, respectively. An ampersand character (`&`) is used to separate the pairs. {{index [escaping, "in URLs"], "hexadecimal number", "encodeURIComponent function", "decodeURIComponent function"}} -The actual message encoded in the URL is "Yes?", but the question mark -is replaced by a strange code. Some characters in query strings must -be escaped. The question mark, represented as `%3F`, is one of those. -There seems to be an unwritten rule that every format needs its own -way of escaping characters. This one, called _((URL encoding))_, uses -a ((percent sign)) followed by two hexadecimal (base 16) digits that -encode the character code. In this case, 3F, which is 63 in decimal -notation, is the code of a question mark character. JavaScript -provides the `encodeURIComponent` and `decodeURIComponent` functions -to encode and decode this format. +The actual message encoded in the URL is "Yes?", but the question mark is replaced by a strange code. Some characters in query strings must be escaped. The question mark, represented as `%3F`, is one of those. There seems to be an unwritten rule that every format needs its own way of escaping characters. This one, called _((URL encoding))_, uses a ((percent sign)) followed by two hexadecimal (base 16) digits that encode the character code. In this case, 3F, which is 63 in decimal notation, is the code of a question mark character. JavaScript provides the `encodeURIComponent` and `decodeURIComponent` functions to encode and decode this format. ``` console.log(encodeURIComponent("Yes?")); @@ -229,10 +145,7 @@ console.log(decodeURIComponent("Yes%3F")); {{index "body (HTTP)", "POST method"}} -If we change the `method` attribute of the HTML form in the example we -saw earlier to `POST`, the ((HTTP)) request made to submit the -((form)) will use the `POST` method and put the ((query string)) in -the body of the request, rather than adding it to the URL. +If we change the `method` attribute of the HTML form in the example we saw earlier to `POST`, the ((HTTP)) request made to submit the ((form)) will use the `POST` method and put the ((query string)) in the body of the request, rather than adding it to the URL. ```{lang: http} POST /example/message.html HTTP/1.1 @@ -242,16 +155,9 @@ Content-type: application/x-www-form-urlencoded name=Jean&message=Yes%3F ``` -`GET` requests should be used for requests that do not have ((side -effect))s but simply ask for information. Requests that change -something on the server, for example creating a new account or posting -a message, should be expressed with other methods, such as `POST`. -Client-side software such as a browser knows that it shouldn't blindly -make `POST` requests but will often implicitly make `GET` requests—for -example to prefetch a resource it believes the user will soon need. +`GET` requests should be used for requests that do not have ((side effect))s but simply ask for information. Requests that change something on the server, for example creating a new account or posting a message, should be expressed with other methods, such as `POST`. Client-side software such as a browser knows that it shouldn't blindly make `POST` requests but will often implicitly make `GET` requests—for example to prefetch a resource it believes the user will soon need. -We'll come back to forms and how to interact with them from JavaScript -[later in the chapter](http#forms). +We'll come back to forms and how to interact with them from JavaScript [later in the chapter](http#forms). {{id fetch}} @@ -259,9 +165,7 @@ We'll come back to forms and how to interact with them from JavaScript {{index "fetch function", "Promise class", [interface, module]}} -The interface through which browser JavaScript can make HTTP -requests is called `fetch`. Since it is relatively new, it -conveniently uses promises (which is rare for browser interfaces). +The interface through which browser JavaScript can make HTTP requests is called `fetch`. Since it is relatively new, it conveniently uses promises (which is rare for browser interfaces). ```{test: no} fetch("example/data.txt").then(response => { @@ -274,35 +178,17 @@ fetch("example/data.txt").then(response => { {{index "Response class", "status property", "headers property"}} -Calling `fetch` returns a promise that resolves to a `Response` object -holding information about the server's response, such as its status -code and its headers. The headers are wrapped in a `Map`-like object -that treats its keys (the header names) as case insensitive because -header names are not supposed to be case sensitive. This means -`headers.get("Content-Type")` and `headers.get("content-TYPE")` will -return the same value. +Calling `fetch` returns a promise that resolves to a `Response` object holding information about the server's response, such as its status code and its headers. The headers are wrapped in a `Map`-like object that treats its keys (the header names) as case insensitive because header names are not supposed to be case sensitive. This means `headers.get("Content-Type")` and `headers.get("content-TYPE")` will return the same value. -Note that the promise returned by `fetch` resolves successfully even -if the server responded with an error code. It _might_ also be -rejected if there is a network error or if the ((server)) that the -request is addressed to can't be found. +Note that the promise returned by `fetch` resolves successfully even if the server responded with an error code. It _might_ also be rejected if there is a network error or if the ((server)) that the request is addressed to can't be found. {{index [path, URL], "relative URL"}} -The first argument to `fetch` is the URL that should be requested. -When that ((URL)) doesn't start with a protocol name (such as _http:_), -it is treated as _relative_, which means it is interpreted relative -to the current document. When it starts with a slash (/), it replaces -the current path, which is the part after the server name. When it -does not, the part of the current path up to and including its last -((slash character)) is put in front of the relative URL. +The first argument to `fetch` is the URL that should be requested. When that ((URL)) doesn't start with a protocol name (such as _http:_), it is treated as _relative_, which means it is interpreted relative to the current document. When it starts with a slash (/), it replaces the current path, which is the part after the server name. When it does not, the part of the current path up to and including its last ((slash character)) is put in front of the relative URL. {{index "text method", "body (HTTP)", "Promise class"}} -To get at the actual content of a response, you can use its `text` -method. Because the initial promise is resolved as soon as the -response's headers have been received and because reading the response body -might take a while longer, this again returns a promise. +To get at the actual content of a response, you can use its `text` method. Because the initial promise is resolved as soon as the response's headers have been received and because reading the response body might take a while longer, this again returns a promise. ```{test: no} fetch("example/data.txt") @@ -313,16 +199,11 @@ fetch("example/data.txt") {{index "json method"}} -A similar method, called `json`, returns a promise that -resolves to the value you get when parsing the body as ((JSON)) or -rejects if it's not valid JSON. +A similar method, called `json`, returns a promise that resolves to the value you get when parsing the body as ((JSON)) or rejects if it's not valid JSON. {{index "GET method", "body (HTTP)", "DELETE method", "method property"}} -By default, `fetch` uses the `GET` method to make its request and -does not include a request body. You can configure it differently by -passing an object with extra options as a second argument. For -example, this request tries to delete `example/data.txt`: +By default, `fetch` uses the `GET` method to make its request and does not include a request body. You can configure it differently by passing an object with extra options as a second argument. For example, this request tries to delete `example/data.txt`: ```{test: no} fetch("example/data.txt", {method: "DELETE"}).then(resp => { @@ -333,15 +214,11 @@ fetch("example/data.txt", {method: "DELETE"}).then(resp => { {{index "405 (HTTP status code)"}} -The 405 status code means "method not allowed", an HTTP server's way -of saying "I can't do that". +The 405 status code means "method not allowed", an HTTP server's way of saying "I can't do that". {{index "Range header", "body property", "headers property"}} -To add a request body, you can include a `body` option. To set -headers, there's the `headers` option. For example, this request -includes a `Range` header, which instructs the server to return only -part of a response. +To add a request body, you can include a `body` option. To set headers, there's the `headers` option. For example, this request includes a `Range` header, which instructs the server to return only part of a response. ```{test: no} fetch("example/data.txt", {headers: {Range: "bytes=8-19"}}) @@ -350,11 +227,7 @@ fetch("example/data.txt", {headers: {Range: "bytes=8-19"}}) // → the content ``` -The browser will automatically add some request ((header))s, such as -"Host" and those needed for the server to figure out the size of the -body. But adding your own headers is often useful to include things -such as authentication information or to tell the server which file -format you'd like to receive. +The browser will automatically add some request ((header))s, such as "Host" and those needed for the server to figure out the size of the body. But adding your own headers is often useful to include things such as authentication information or to tell the server which file format you'd like to receive. {{id http_sandbox}} @@ -362,25 +235,13 @@ format you'd like to receive. {{index sandbox, [browser, security]}} -Making ((HTTP)) requests in web page scripts once again raises -concerns about ((security)). The person who controls the script might -not have the same interests as the person on whose computer it is -running. More specifically, if I visit _themafia.org_, I do not want -its scripts to be able to make a request to _mybank.com_, using -identifying information from my browser, with instructions to -transfer all my money to some random account. +Making ((HTTP)) requests in web page scripts once again raises concerns about ((security)). The person who controls the script might not have the same interests as the person on whose computer it is running. More specifically, if I visit _themafia.org_, I do not want its scripts to be able to make a request to _mybank.com_, using identifying information from my browser, with instructions to transfer all my money to some random account. -For this reason, browsers protect us by disallowing scripts to make -HTTP requests to other ((domain))s (names such as _themafia.org_ and -_mybank.com_). +For this reason, browsers protect us by disallowing scripts to make HTTP requests to other ((domain))s (names such as _themafia.org_ and _mybank.com_). {{index "Access-Control-Allow-Origin header", "cross-domain request"}} -This can be an annoying problem when building systems that want to -access several domains for legitimate reasons. Fortunately, -((server))s can include a ((header)) like this in their ((response)) -to explicitly indicate to the browser that it is okay for the request -to come from another domain: +This can be an annoying problem when building systems that want to access several domains for legitimate reasons. Fortunately, ((server))s can include a ((header)) like this in their ((response)) to explicitly indicate to the browser that it is okay for the request to come from another domain: ```{lang: null} Access-Control-Allow-Origin: * @@ -390,110 +251,55 @@ Access-Control-Allow-Origin: * {{index client, HTTP, [interface, HTTP]}} -When building a system that requires ((communication)) between a -JavaScript program running in the ((browser)) (client-side) and a -program on a ((server)) (server-side), there are several different -ways to model this communication. +When building a system that requires ((communication)) between a JavaScript program running in the ((browser)) (client-side) and a program on a ((server)) (server-side), there are several different ways to model this communication. {{index [network, abstraction], abstraction}} -A commonly used model is that of _((remote procedure call))s_. In this -model, communication follows the patterns of normal function calls, -except that the function is actually running on another machine. -Calling it involves making a request to the server that includes the -function's name and arguments. The response to that request contains -the returned value. +A commonly used model is that of _((remote procedure call))s_. In this model, communication follows the patterns of normal function calls, except that the function is actually running on another machine. Calling it involves making a request to the server that includes the function's name and arguments. The response to that request contains the returned value. -When thinking in terms of remote procedure calls, HTTP is just a -vehicle for communication, and you will most likely write an -abstraction layer that hides it entirely. +When thinking in terms of remote procedure calls, HTTP is just a vehicle for communication, and you will most likely write an abstraction layer that hides it entirely. {{index "media type", "document format", [method, HTTP]}} -Another approach is to build your communication around the concept of -((resource))s and ((HTTP)) methods. Instead of a remote procedure -called `addUser`, you use a `PUT` request to `/users/larry`. Instead -of encoding that user's properties in function arguments, you define a -JSON document format (or use an existing format) that represents a -user. The body of the `PUT` request to create a new resource is then -such a document. A resource is fetched by making a `GET` request to -the resource's URL (for example, `/user/larry`), which again returns -the document representing the resource. - -This second approach makes it easier to use some of the features that -HTTP provides, such as support for caching resources (keeping a copy -on the client for fast access). The concepts used in HTTP, which are -well designed, can provide a helpful set of principles to design your -server interface around. +Another approach is to build your communication around the concept of ((resource))s and ((HTTP)) methods. Instead of a remote procedure called `addUser`, you use a `PUT` request to `/users/larry`. Instead of encoding that user's properties in function arguments, you define a JSON document format (or use an existing format) that represents a user. The body of the `PUT` request to create a new resource is then such a document. A resource is fetched by making a `GET` request to the resource's URL (for example, `/user/larry`), which again returns the document representing the resource. + +This second approach makes it easier to use some of the features that HTTP provides, such as support for caching resources (keeping a copy on the client for fast access). The concepts used in HTTP, which are well designed, can provide a helpful set of principles to design your server interface around. ## Security and HTTPS {{index "man-in-the-middle", security, HTTPS, [network, security]}} -Data traveling over the Internet tends to follow a long, dangerous -road. To get to its destination, it must hop through anything from -coffee shop Wi-Fi hotspots to networks controlled by various companies and -states. At any point along its route it may be inspected or even -modified. +Data traveling over the Internet tends to follow a long, dangerous road. To get to its destination, it must hop through anything from coffee shop Wi-Fi hotspots to networks controlled by various companies and states. At any point along its route it may be inspected or even modified. {{index tampering}} -If it is important that something remain secret, such as the -((password)) to your ((email)) account, or that it arrive at its -destination unmodified, such as the account number you transfer money -to via your bank's website, plain HTTP is not good enough. +If it is important that something remain secret, such as the ((password)) to your ((email)) account, or that it arrive at its destination unmodified, such as the account number you transfer money to via your bank's website, plain HTTP is not good enough. {{index cryptography, encryption}} {{indexsee "Secure HTTP", HTTPS, [browser, security]}} -The secure ((HTTP)) protocol, used for ((URL))s starting with _https://_, -wraps HTTP traffic in a way that makes it harder to read and tamper -with. Before exchanging data, the client verifies that the server is -who it claims to be by asking it to prove that it has a cryptographic -((certificate)) issued by a certificate authority that the browser -recognizes. Next, all data going over the ((connection)) is encrypted -in a way that should prevent eavesdropping and tampering. - -Thus, when it works right, ((HTTPS)) prevents other people from -impersonating the website you are trying to talk to and from -snooping on your communication. It is not perfect, and there have been -various incidents where HTTPS failed because of forged or stolen -certificates and broken software, but it is a _lot_ safer than plain -HTTP. +The secure ((HTTP)) protocol, used for ((URL))s starting with _https://_, wraps HTTP traffic in a way that makes it harder to read and tamper with. Before exchanging data, the client verifies that the server is who it claims to be by asking it to prove that it has a cryptographic ((certificate)) issued by a certificate authority that the browser recognizes. Next, all data going over the ((connection)) is encrypted in a way that should prevent eavesdropping and tampering. + +Thus, when it works right, ((HTTPS)) prevents other people from impersonating the website you are trying to talk to and from snooping on your communication. It is not perfect, and there have been various incidents where HTTPS failed because of forged or stolen certificates and broken software, but it is a _lot_ safer than plain HTTP. {{id forms}} ## Form fields -Forms were originally designed for the pre-JavaScript Web to allow -web sites to send user-submitted information in an HTTP request. This -design assumes that interaction with the server always happens by -navigating to a new page. +Forms were originally designed for the pre-JavaScript Web to allow web sites to send user-submitted information in an HTTP request. This design assumes that interaction with the server always happens by navigating to a new page. {{index [DOM, fields]}} -But their elements are part of the DOM like the rest of the page, -and the DOM elements that represent form ((field))s support a number -of properties and events that are not present on other elements. These -make it possible to inspect and control such input fields with -JavaScript programs and do things such as adding new functionality to -a form or using forms and fields as building blocks in a JavaScript -application. +But their elements are part of the DOM like the rest of the page, and the DOM elements that represent form ((field))s support a number of properties and events that are not present on other elements. These make it possible to inspect and control such input fields with JavaScript programs and do things such as adding new functionality to a form or using forms and fields as building blocks in a JavaScript application. {{index "form (HTML tag)"}} -A web form consists of any number of input ((field))s grouped in a -`` tag. HTML allows several different styles of fields, ranging -from simple on/off checkboxes to drop-down menus and fields for text -input. This book won't try to comprehensively discuss all field types, -but we'll start with a rough overview. +A web form consists of any number of input ((field))s grouped in a `` tag. HTML allows several different styles of fields, ranging from simple on/off checkboxes to drop-down menus and fields for text input. This book won't try to comprehensively discuss all field types, but we'll start with a rough overview. {{index "input (HTML tag)", "type attribute"}} -A lot of field types use the -`` tag. This tag's `type` attribute is used to select the -field's style. These are some commonly used `` types: +A lot of field types use the `` tag. This tag's `type` attribute is used to select the field's style. These are some commonly used `` types: {{index "password field", checkbox, "radio button", "file field"}} @@ -507,11 +313,7 @@ field's style. These are some commonly used `` types: {{index "value attribute", "checked attribute", "form (HTML tag)"}} -Form fields do not necessarily have to appear in a `` tag. You -can put them anywhere in a page. Such form-less fields cannot be -((submit))ted (only a form as a whole can), but when responding to -input with JavaScript, we often don't want to submit our fields -normally anyway. +Form fields do not necessarily have to appear in a `` tag. You can put them anywhere in a page. Such form-less fields cannot be ((submit))ted (only a form as a whole can), but when responding to input with JavaScript, we often don't want to submit our fields normally anyway. ```{lang: "text/html"}

(text)

@@ -531,16 +333,11 @@ The fields created with this HTML code look like this: if}} -The JavaScript interface for such elements differs with the type of -the element. +The JavaScript interface for such elements differs with the type of the element. {{index "textarea (HTML tag)", "text field"}} -Multiline text fields have their own tag, `` -closing tag and uses the text between those two, instead of the -`value` attribute, as starting text. +Multiline text fields have their own tag, `` closing tag and uses the text between those two, instead of the `value` attribute, as starting text. ```{lang: "text/html"} @@ -800,23 +530,13 @@ tag with an event handler that, when you press F2, inserts the string {{index "replaceSelection function", "text field"}} -The `replaceSelection` -function replaces the currently selected part of a text field's -content with the given word and then moves the ((cursor)) after that -word so that the user can continue typing. +The `replaceSelection` function replaces the currently selected part of a text field's content with the given word and then moves the ((cursor)) after that word so that the user can continue typing. {{index "change event", "input event"}} -The `"change"` event for a ((text -field)) does not fire every time something is typed. Rather, it -fires when the field loses ((focus)) after its content was changed. -To respond immediately to changes in a text field, you should register -a handler for the `"input"` event instead, which fires for every -time the user types a character, deletes text, or otherwise manipulates -the field's content. +The `"change"` event for a ((text field)) does not fire every time something is typed. Rather, it fires when the field loses ((focus)) after its content was changed. To respond immediately to changes in a text field, you should register a handler for the `"input"` event instead, which fires for every time the user types a character, deletes text, or otherwise manipulates the field's content. -The following example shows a text field and a counter displaying the -current length of the text in the field: +The following example shows a text field and a counter displaying the current length of the text in the field: ```{lang: "text/html"} length: 0 @@ -833,8 +553,7 @@ current length of the text in the field: {{index "input (HTML tag)", "checked attribute"}} -A ((checkbox)) field is a binary toggle. Its value can be extracted or -changed through its `checked` property, which holds a Boolean value. +A ((checkbox)) field is a binary toggle. Its value can be extracted or changed through its `checked` property, which holds a Boolean value. ```{lang: "text/html"}