- 浏览: 23593 次
- 性别:
- 来自: 杭州
最新评论
以下为引用文档:
引用地址为:https://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes
具体内容如下:
Unlike SVG, canvas only supports one primitive shape - rectangles. All other shapes must be created by combining one or more paths. Luckily, we have a collection of path drawing functions which make it possible to compose very complex shapes.
Rectangles
First let's look at the rectangle. There are three functions that draw rectangles on the canvas:
fillRect(x,y,width,height) : Draws a filled rectangle
strokeRect(x,y,width,height) : Draws a rectangular outline
clearRect(x,y,width,height) : Clears the specified area and makes it fully transparent
Each of these three functions takes the same parameters. x and y specify the position on the canvas (relative to the origin) of the top-left corner of the rectangle. width and height are pretty obvious. Let's see these functions in action.
Below is the draw() function from the previous page, but now I've added the three functions above.
Rectangular shape example
View this example
01 function draw(){
02 var canvas = document.getElementById('tutorial');
03 if (canvas.getContext){
04 var ctx = canvas.getContext('2d');
05
06 ctx.fillRect(25,25,100,100);
07 ctx.clearRect(45,45,60,60);
08 ctx.strokeRect(50,50,50,50);
09 }
10 }
The result should look something like the image on the right. The fillRect function draws a large black square 100x100 pixels. The clearRect function removes a 60x60 pixels square from the center and finally the strokeRect draws a rectangular outline 50x50 pixels inside the cleared square. In the following pages we'll see two alternative methods for the clearRect function and we'll also see how to change the color and stroke style of the rendered shapes.
Unlike the path functions we'll see in the next section, all three rectangle functions draw immediately to the canvas.
Drawing paths
To make shapes using paths, we need a couple of extra steps.
beginPath()
closePath()
stroke()
fill()
The first step to create a path is calling the beginPath method. Internally, paths are stored as a list of sub-paths (lines, arcs, etc) which together form a shape. Every time this method is called, the list is reset and we can start drawing new shapes.
Note: When the current path is empty, such as immediately after calling beginPath(), or on a newly created canvas, the first path construction command is always treated as a moveTo(), regardless of what it actually is. For that reason, you will almost always want to specifically set your starting position after resetting a path.
The second step is calling the methods that actually specify the paths to be drawn. We'll see these shortly.
The third, and an optional step, would be to call the closePath method. This method tries to close the shape by drawing a straight line from the current point to the start. If the shape has already been closed or there's only one point in the list, this function does nothing.
The final step will be calling the stroke and/or fill methods. Calling one of these will actually draw the shape to the canvas. stroke is used to draw an outlined shape, while fill is used to paint a solid shape.
Note: When calling the fill method, any open shapes will be closed automatically and it isn't necessary to use the closePath method.
For example, the code for drawing a triangle would look something like this:
1 ctx.beginPath();
2 ctx.moveTo(75,50);
3 ctx.lineTo(100,75);
4 ctx.lineTo(100,25);
5 ctx.fill();
moveTo
One very useful function, which doesn't actually draw anything, but is part of the path list described above, is the moveTo function. You can probably best think of this as lifting a pen or pencil from one spot on a piece of paper and placing it on the next.
moveTo(x, y)
The moveTo function takes two arguments, x and y, which are the coordinates of the new starting point.
When the canvas is initialized or the beginPath method is called, you typically will want to use the moveTo method to place the starting point somewhere else. We could also use the moveTo method to draw unconnected paths. Take a look at the smiley face on the right. I've marked the places where I used the moveTo method (the red lines).
To try this for yourself, you can use the code snippet below. Just paste it into the draw function we saw earlier.
moveTo example
View this example
1 ctx.beginPath();
2 ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
3 ctx.moveTo(110,75);
4 ctx.arc(75,75,35,0,Math.PI,false); // Mouth (clockwise)
5 ctx.moveTo(65,65);
6 ctx.arc(60,65,5,0,Math.PI*2,true); // Left eye
7 ctx.moveTo(95,65);
8 ctx.arc(90,65,5,0,Math.PI*2,true); // Right eye
9 ctx.stroke();
Note: remove the moveTo methods to see the connecting lines.
Note: For a description of the arc function and its parameters look below.
Lines
For drawing straight lines we use the lineTo method.
lineTo(x, y)
This method takes two arguments - x and y, - which are the coordinates of the line's end point. The starting point is dependent on previous drawn paths, where the end point of the previous path is the starting point for the following, etc. The starting point can also be changed by using the moveTo method.
lineTo example
In the example below two triangles are drawn, one filled and one outlined. (The result can be seen in the image on the right). First the beginPath method is called to begin a new shape path. We then use the moveTo method to move the starting point to the desired position. Below this two lines are drawn which make up two sides of the triangle.
You'll notice the difference between the filled and stroked triangle. This is, as mentioned above, because shapes are automatically closed when a path is filled, but not when they are stroked. If we would have left out the closePath() for the stroked triangle, only two lines would have been drawn, not a complete triangle.
View this example
01 // Filled triangle
02 ctx.beginPath();
03 ctx.moveTo(25,25);
04 ctx.lineTo(105,25);
05 ctx.lineTo(25,105);
06 ctx.fill();
07
08 // Stroked triangle
09 ctx.beginPath();
10 ctx.moveTo(125,125);
11 ctx.lineTo(125,45);
12 ctx.lineTo(45,125);
13 ctx.closePath();
14 ctx.stroke();
Arcs
For drawing arcs or circles we use the arc method. The specification also describes the arcTo method, which is supported by Safari and Firefox, but wasn't implemented in the older Gecko browsers.
arc(x, y, radius, startAngle, endAngle, anticlockwise)
This method takes five parameters: x and y are the coordinates of the circle's center. Radius is self explanatory. The startAngle and endAngle parameters define the start and end points of the arc in radians. The starting and closing angle are measured from the x axis. The anticlockwise parameter is a Boolean value which when true draws the arc anticlockwise, otherwise in a clockwise direction.
Note: Angles in the arc function are measured in radians, not degrees. To convert degrees to radians you can use the following JavaScript expression: var radians = (Math.PI/180)*degrees.
arc example
The following example is a little more complex than the ones we've seen above. I've drawn 12 different arcs all with different angles and fills. If I would have written this example just like the smiley face above, firstly this would have become a very long list of statements and secondly, when drawing arcs, I would need to know every single starting point. For arcs of 90, 180 and 270 degrees, like the ones I used here, this wouldn't be to much of a problem, but for more complex ones this becomes way too difficult.
The two for loops are for looping through the rows and columns of arcs. For every arc I start a new path using beginPath. Below this I've written out all the parameters as variables, so it's easier to read what's going on. Normally this would be just one statement. The x and y coordinates should be clear enough. radius and startAngle are fixed. The endAngle starts of as 180 degrees (first column) and is increased with steps of 90 degrees to form a complete circle (last column). The statement for the clockwise parameter results in the first and third row being drawn as clockwise arcs and the second and fourth row as counterclockwise arcs. Finally, the if statement makes the top half stroked arcs and the bottom half filled arcs.
View this example
01 for(var i=0;i<4;i++){
02 for(var j=0;j<3;j++){
03 ctx.beginPath();
04 var x = 25+j*50; // x coordinate
05 var y = 25+i*50; // y coordinate
06 var radius = 20; // Arc radius
07 var startAngle = 0; // Starting point on circle
08 var endAngle = Math.PI+(Math.PI*j)/2; // End point on circle
09 var anticlockwise = i%2==0 ? false : true; // clockwise or anticlockwise
10
11 ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
12
13 if (i>1){
14 ctx.fill();
15 } else {
16 ctx.stroke();
17 }
18 }
19 }
Bezier and quadratic curves
The next type of paths available are Bézier curves, available in the cubic and quadratic varieties. These are generally used to draw complex organic shapes.
quadraticCurveTo(cp1x, cp1y, x, y) // BROKEN in Firefox 1.5 (see work around below)
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
The difference between these can best be described using the image on the right. A quadratic Bézier curve has a start and an end point (blue dots) and just one control point (red dot) while a cubic Bézier curve uses two control points.
The x and y parameters in both these methods are the coordinates of the end point. cp1x and cp1y are the coordinates of the first control point, and cp2x and cp2y are the coordinates of the second control point.
Using quadratic and cubic Bézier curves can be quite challenging, because unlike vector drawing software like Adobe Illustrator, we don't have direct visual feedback as to what we're doing. This makes it pretty hard to draw complex shapes. In the following example, we'll be drawing some simple organic shapes, but if you have the time and, most of all, the patience, much more complex shapes can be created.
There's nothing very difficult in these examples. In both cases we see a succession of curves being drawn which finally result in a complete shape.
quadraticCurveTo example
View this example
01 // Quadratric curves example
02 ctx.beginPath();
03 ctx.moveTo(75,25);
04 ctx.quadraticCurveTo(25,25,25,62.5);
05 ctx.quadraticCurveTo(25,100,50,100);
06 ctx.quadraticCurveTo(50,120,30,125);
07 ctx.quadraticCurveTo(60,120,65,100);
08 ctx.quadraticCurveTo(125,100,125,62.5);
09 ctx.quadraticCurveTo(125,25,75,25);
10 ctx.stroke();
It is possible to convert any quadratic Bézier curve to a cubic Bézier curve by correctly computing both cubic Bézier control points from the single quadratic Bézier control point, although the reverse is NOT true. An exact conversion of a cubic Bézier curve to a quadratic Bézier curve is only possible if the cubic term is zero, more commonly a subdivision method is used to approximate a cubic Bézier using multiple quadratic Bézier curves.
bezierCurveTo example
View this example
01 // Bezier curves example
02 ctx.beginPath();
03 ctx.moveTo(75,40);
04 ctx.bezierCurveTo(75,37,70,25,50,25);
05 ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
06 ctx.bezierCurveTo(20,80,40,102,75,120);
07 ctx.bezierCurveTo(110,102,130,80,130,62.5);
08 ctx.bezierCurveTo(130,62.5,130,25,100,25);
09 ctx.bezierCurveTo(85,25,75,37,75,40);
10 ctx.fill();
Firefox 1.5 quadraticCurveTo() bug workaround
There is a bug in the Firefox 1.5 implementation of quadatricCurveTo(). It does NOT draw a quadratic curve, as it is just calling the same cubic curve function bezierCurveTo() calls, and repeating the single quadratic control point (x,y) coordinate twice. For this reason quadraticCurveTo() will yield incorrect results. If you require the use of quadraticCurveTo() you must convert your quadratic Bézier curve to a cubic Bézier curve yourself, so you can use the working bezierCurveTo() method.
01 var currentX, currentY; // set to last x,y sent to lineTo/moveTo/bezierCurveTo or quadraticCurveToFixed()
02
03 function quadraticCurveToFixed( cpx, cpy, x, y ) {
04 /*
05 For the equations below the following variable name prefixes are used:
06 qp0 is the quadratic curve starting point (you must keep this from your last point sent to moveTo(), lineTo(), or bezierCurveTo() ).
07 qp1 is the quadratic curve control point (this is the cpx,cpy you would have sent to quadraticCurveTo() ).
08 qp2 is the quadratic curve ending point (this is the x,y arguments you would have sent to quadraticCurveTo() ).
09 We will convert these points to compute the two needed cubic control points (the starting/ending points are the same for both
10 the quadratic and cubic curves.
11
12 The exact equations for the two cubic control points are:
13 cp0 = qp0 and cp3 = qp2
14 cp1 = qp0 + (qp1 - qp0) * ratio
15 cp2 = cp1 + (qp2 - qp0) * (1 - ratio)
16 where ratio = (sqrt(2) - 1) * 4 / 3 exactly (approx. 0.5522847498307933984022516322796)
17 if the quadratic is an approximation of an elliptic arc, and the cubic must approximate the same arc, or
18 ratio = 2.0 / 3.0 for keeping the same quadratic curve.
19
20 In the code below, we must compute both the x and y terms for each point separately.
21
22 cp1x = qp0x + (qp1x - qp0x) * ratio;
23 cp1y = qp0y + (qp1y - qp0y) * ratio;
24 cp2x = cp1x + (qp2x - qp0x) * (1 - ratio);
25 cp2y = cp1y + (qp2y - qp0y) * (1 - ratio);
26
27 We will now
28 a) replace the qp0x and qp0y variables with currentX and currentY (which *you* must store for each moveTo/lineTo/bezierCurveTo)
29 b) replace the qp1x and qp1y variables with cpx and cpy (which we would have passed to quadraticCurveTo)
30 c) replace the qp2x and qp2y variables with x and y.
31 which leaves us with:
32 */
33 var ratio = 2.0 / 3.0; // 0.5522847498307933984022516322796 if the Bezier is approximating an elliptic arc with best fitting
34 var cp1x = currentX + (cpx - currentX) * ratio;
35 var cp1y = currentY + (cpy - currentY) * ratio;
36 var cp2x = cp1x + (x - currentX) * (1 - ratio);
37 var cp2y = cp1y + (y - currentY) * (1 - ratio);
38
39 // and now call cubic Bezier curve to function
40 bezierCurveTo( cp1x, cp1y, cp2x, cp2y, x, y );
41
42 currentX = x;
43 currentY = y;
44 }
Rectangles
Besides the three methods we saw above which draw rectangular shapes directly to the canvas, we also have a method rect which adds a rectangular path to the path list.
rect(x, y, width, height)
This method takes four arguments. The x and y parameters define the coordinate of the top left corner of the new rectangular path. width and height define the width and the height of the rectangle.
When this method is executed, the moveTo method is automatically called with the parameters (0,0) (i.e. it resets the starting point to its default location).
Making combinations
In all examples on this page I've only used one type of path function per shape. However there's absolutely no limitation to the amount or type of paths you can use to create a shape. So in this last example I've tried to combine all of the path functions to make a set of very famous game characters.
Example
I'm not going to run through this complete script, but the most important things to note are the function roundedRect and the use of the fillStyle property. It can be very usefull and time saving to define your own functions to draw more complex shapes. In this script it would have taken me twice as many lines of code as I have now.
We will look at the fillStyle property in greater depth later in this tutorial. Here I'm using it to change the fill color from the default black, to white, and back again.
View this example
01 function draw() {
02 var ctx = document.getElementById('canvas').getContext('2d');
03 roundedRect(ctx,12,12,150,150,15);
04 roundedRect(ctx,19,19,150,150,9);
05 roundedRect(ctx,53,53,49,33,10);
06 roundedRect(ctx,53,119,49,16,6);
07 roundedRect(ctx,135,53,49,33,10);
08 roundedRect(ctx,135,119,25,49,10);
09
10 ctx.beginPath();
11 ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false);
12 ctx.lineTo(31,37);
13 ctx.fill();
14 for(var i=0;i<8;i++){
15 ctx.fillRect(51+i*16,35,4,4);
16 }
17 for(i=0;i<6;i++){
18 ctx.fillRect(115,51+i*16,4,4);
19 }
20 for(i=0;i<8;i++){
21 ctx.fillRect(51+i*16,99,4,4);
22 }
23 ctx.beginPath();
24 ctx.moveTo(83,116);
25 ctx.lineTo(83,102);
26 ctx.bezierCurveTo(83,94,89,88,97,88);
27 ctx.bezierCurveTo(105,88,111,94,111,102);
28 ctx.lineTo(111,116);
29 ctx.lineTo(106.333,111.333);
30 ctx.lineTo(101.666,116);
31 ctx.lineTo(97,111.333);
32 ctx.lineTo(92.333,116);
33 ctx.lineTo(87.666,111.333);
34 ctx.lineTo(83,116);
35 ctx.fill();
36 ctx.fillStyle = "white";
37 ctx.beginPath();
38 ctx.moveTo(91,96);
39 ctx.bezierCurveTo(88,96,87,99,87,101);
40 ctx.bezierCurveTo(87,103,88,106,91,106);
41 ctx.bezierCurveTo(94,106,95,103,95,101);
42 ctx.bezierCurveTo(95,99,94,96,91,96);
43 ctx.moveTo(103,96);
44 ctx.bezierCurveTo(100,96,99,99,99,101);
45 ctx.bezierCurveTo(99,103,100,106,103,106);
46 ctx.bezierCurveTo(106,106,107,103,107,101);
47 ctx.bezierCurveTo(107,99,106,96,103,96);
48 ctx.fill();
49 ctx.fillStyle = "black";
50 ctx.beginPath();
51 ctx.arc(101,102,2,0,Math.PI*2,true);
52 ctx.fill();
53 ctx.beginPath();
54 ctx.arc(89,102,2,0,Math.PI*2,true);
55 ctx.fill();
56 }
57 function roundedRect(ctx,x,y,width,height,radius){
58 ctx.beginPath();
59 ctx.moveTo(x,y+radius);
60 ctx.lineTo(x,y+height-radius);
61 ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
62 ctx.lineTo(x+width-radius,y+height);
63 ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
64 ctx.lineTo(x+width,y+radius);
65 ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
66 ctx.lineTo(x+radius,y);
67 ctx.quadraticCurveTo(x,y,x,y+radius);
68 ctx.stroke();
69 }
引用地址为:https://developer.mozilla.org/en/Canvas_tutorial/Drawing_shapes
具体内容如下:
Unlike SVG, canvas only supports one primitive shape - rectangles. All other shapes must be created by combining one or more paths. Luckily, we have a collection of path drawing functions which make it possible to compose very complex shapes.
Rectangles
First let's look at the rectangle. There are three functions that draw rectangles on the canvas:
fillRect(x,y,width,height) : Draws a filled rectangle
strokeRect(x,y,width,height) : Draws a rectangular outline
clearRect(x,y,width,height) : Clears the specified area and makes it fully transparent
Each of these three functions takes the same parameters. x and y specify the position on the canvas (relative to the origin) of the top-left corner of the rectangle. width and height are pretty obvious. Let's see these functions in action.
Below is the draw() function from the previous page, but now I've added the three functions above.
Rectangular shape example
View this example
01 function draw(){
02 var canvas = document.getElementById('tutorial');
03 if (canvas.getContext){
04 var ctx = canvas.getContext('2d');
05
06 ctx.fillRect(25,25,100,100);
07 ctx.clearRect(45,45,60,60);
08 ctx.strokeRect(50,50,50,50);
09 }
10 }
The result should look something like the image on the right. The fillRect function draws a large black square 100x100 pixels. The clearRect function removes a 60x60 pixels square from the center and finally the strokeRect draws a rectangular outline 50x50 pixels inside the cleared square. In the following pages we'll see two alternative methods for the clearRect function and we'll also see how to change the color and stroke style of the rendered shapes.
Unlike the path functions we'll see in the next section, all three rectangle functions draw immediately to the canvas.
Drawing paths
To make shapes using paths, we need a couple of extra steps.
beginPath()
closePath()
stroke()
fill()
The first step to create a path is calling the beginPath method. Internally, paths are stored as a list of sub-paths (lines, arcs, etc) which together form a shape. Every time this method is called, the list is reset and we can start drawing new shapes.
Note: When the current path is empty, such as immediately after calling beginPath(), or on a newly created canvas, the first path construction command is always treated as a moveTo(), regardless of what it actually is. For that reason, you will almost always want to specifically set your starting position after resetting a path.
The second step is calling the methods that actually specify the paths to be drawn. We'll see these shortly.
The third, and an optional step, would be to call the closePath method. This method tries to close the shape by drawing a straight line from the current point to the start. If the shape has already been closed or there's only one point in the list, this function does nothing.
The final step will be calling the stroke and/or fill methods. Calling one of these will actually draw the shape to the canvas. stroke is used to draw an outlined shape, while fill is used to paint a solid shape.
Note: When calling the fill method, any open shapes will be closed automatically and it isn't necessary to use the closePath method.
For example, the code for drawing a triangle would look something like this:
1 ctx.beginPath();
2 ctx.moveTo(75,50);
3 ctx.lineTo(100,75);
4 ctx.lineTo(100,25);
5 ctx.fill();
moveTo
One very useful function, which doesn't actually draw anything, but is part of the path list described above, is the moveTo function. You can probably best think of this as lifting a pen or pencil from one spot on a piece of paper and placing it on the next.
moveTo(x, y)
The moveTo function takes two arguments, x and y, which are the coordinates of the new starting point.
When the canvas is initialized or the beginPath method is called, you typically will want to use the moveTo method to place the starting point somewhere else. We could also use the moveTo method to draw unconnected paths. Take a look at the smiley face on the right. I've marked the places where I used the moveTo method (the red lines).
To try this for yourself, you can use the code snippet below. Just paste it into the draw function we saw earlier.
moveTo example
View this example
1 ctx.beginPath();
2 ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
3 ctx.moveTo(110,75);
4 ctx.arc(75,75,35,0,Math.PI,false); // Mouth (clockwise)
5 ctx.moveTo(65,65);
6 ctx.arc(60,65,5,0,Math.PI*2,true); // Left eye
7 ctx.moveTo(95,65);
8 ctx.arc(90,65,5,0,Math.PI*2,true); // Right eye
9 ctx.stroke();
Note: remove the moveTo methods to see the connecting lines.
Note: For a description of the arc function and its parameters look below.
Lines
For drawing straight lines we use the lineTo method.
lineTo(x, y)
This method takes two arguments - x and y, - which are the coordinates of the line's end point. The starting point is dependent on previous drawn paths, where the end point of the previous path is the starting point for the following, etc. The starting point can also be changed by using the moveTo method.
lineTo example
In the example below two triangles are drawn, one filled and one outlined. (The result can be seen in the image on the right). First the beginPath method is called to begin a new shape path. We then use the moveTo method to move the starting point to the desired position. Below this two lines are drawn which make up two sides of the triangle.
You'll notice the difference between the filled and stroked triangle. This is, as mentioned above, because shapes are automatically closed when a path is filled, but not when they are stroked. If we would have left out the closePath() for the stroked triangle, only two lines would have been drawn, not a complete triangle.
View this example
01 // Filled triangle
02 ctx.beginPath();
03 ctx.moveTo(25,25);
04 ctx.lineTo(105,25);
05 ctx.lineTo(25,105);
06 ctx.fill();
07
08 // Stroked triangle
09 ctx.beginPath();
10 ctx.moveTo(125,125);
11 ctx.lineTo(125,45);
12 ctx.lineTo(45,125);
13 ctx.closePath();
14 ctx.stroke();
Arcs
For drawing arcs or circles we use the arc method. The specification also describes the arcTo method, which is supported by Safari and Firefox, but wasn't implemented in the older Gecko browsers.
arc(x, y, radius, startAngle, endAngle, anticlockwise)
This method takes five parameters: x and y are the coordinates of the circle's center. Radius is self explanatory. The startAngle and endAngle parameters define the start and end points of the arc in radians. The starting and closing angle are measured from the x axis. The anticlockwise parameter is a Boolean value which when true draws the arc anticlockwise, otherwise in a clockwise direction.
Note: Angles in the arc function are measured in radians, not degrees. To convert degrees to radians you can use the following JavaScript expression: var radians = (Math.PI/180)*degrees.
arc example
The following example is a little more complex than the ones we've seen above. I've drawn 12 different arcs all with different angles and fills. If I would have written this example just like the smiley face above, firstly this would have become a very long list of statements and secondly, when drawing arcs, I would need to know every single starting point. For arcs of 90, 180 and 270 degrees, like the ones I used here, this wouldn't be to much of a problem, but for more complex ones this becomes way too difficult.
The two for loops are for looping through the rows and columns of arcs. For every arc I start a new path using beginPath. Below this I've written out all the parameters as variables, so it's easier to read what's going on. Normally this would be just one statement. The x and y coordinates should be clear enough. radius and startAngle are fixed. The endAngle starts of as 180 degrees (first column) and is increased with steps of 90 degrees to form a complete circle (last column). The statement for the clockwise parameter results in the first and third row being drawn as clockwise arcs and the second and fourth row as counterclockwise arcs. Finally, the if statement makes the top half stroked arcs and the bottom half filled arcs.
View this example
01 for(var i=0;i<4;i++){
02 for(var j=0;j<3;j++){
03 ctx.beginPath();
04 var x = 25+j*50; // x coordinate
05 var y = 25+i*50; // y coordinate
06 var radius = 20; // Arc radius
07 var startAngle = 0; // Starting point on circle
08 var endAngle = Math.PI+(Math.PI*j)/2; // End point on circle
09 var anticlockwise = i%2==0 ? false : true; // clockwise or anticlockwise
10
11 ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
12
13 if (i>1){
14 ctx.fill();
15 } else {
16 ctx.stroke();
17 }
18 }
19 }
Bezier and quadratic curves
The next type of paths available are Bézier curves, available in the cubic and quadratic varieties. These are generally used to draw complex organic shapes.
quadraticCurveTo(cp1x, cp1y, x, y) // BROKEN in Firefox 1.5 (see work around below)
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
The difference between these can best be described using the image on the right. A quadratic Bézier curve has a start and an end point (blue dots) and just one control point (red dot) while a cubic Bézier curve uses two control points.
The x and y parameters in both these methods are the coordinates of the end point. cp1x and cp1y are the coordinates of the first control point, and cp2x and cp2y are the coordinates of the second control point.
Using quadratic and cubic Bézier curves can be quite challenging, because unlike vector drawing software like Adobe Illustrator, we don't have direct visual feedback as to what we're doing. This makes it pretty hard to draw complex shapes. In the following example, we'll be drawing some simple organic shapes, but if you have the time and, most of all, the patience, much more complex shapes can be created.
There's nothing very difficult in these examples. In both cases we see a succession of curves being drawn which finally result in a complete shape.
quadraticCurveTo example
View this example
01 // Quadratric curves example
02 ctx.beginPath();
03 ctx.moveTo(75,25);
04 ctx.quadraticCurveTo(25,25,25,62.5);
05 ctx.quadraticCurveTo(25,100,50,100);
06 ctx.quadraticCurveTo(50,120,30,125);
07 ctx.quadraticCurveTo(60,120,65,100);
08 ctx.quadraticCurveTo(125,100,125,62.5);
09 ctx.quadraticCurveTo(125,25,75,25);
10 ctx.stroke();
It is possible to convert any quadratic Bézier curve to a cubic Bézier curve by correctly computing both cubic Bézier control points from the single quadratic Bézier control point, although the reverse is NOT true. An exact conversion of a cubic Bézier curve to a quadratic Bézier curve is only possible if the cubic term is zero, more commonly a subdivision method is used to approximate a cubic Bézier using multiple quadratic Bézier curves.
bezierCurveTo example
View this example
01 // Bezier curves example
02 ctx.beginPath();
03 ctx.moveTo(75,40);
04 ctx.bezierCurveTo(75,37,70,25,50,25);
05 ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
06 ctx.bezierCurveTo(20,80,40,102,75,120);
07 ctx.bezierCurveTo(110,102,130,80,130,62.5);
08 ctx.bezierCurveTo(130,62.5,130,25,100,25);
09 ctx.bezierCurveTo(85,25,75,37,75,40);
10 ctx.fill();
Firefox 1.5 quadraticCurveTo() bug workaround
There is a bug in the Firefox 1.5 implementation of quadatricCurveTo(). It does NOT draw a quadratic curve, as it is just calling the same cubic curve function bezierCurveTo() calls, and repeating the single quadratic control point (x,y) coordinate twice. For this reason quadraticCurveTo() will yield incorrect results. If you require the use of quadraticCurveTo() you must convert your quadratic Bézier curve to a cubic Bézier curve yourself, so you can use the working bezierCurveTo() method.
01 var currentX, currentY; // set to last x,y sent to lineTo/moveTo/bezierCurveTo or quadraticCurveToFixed()
02
03 function quadraticCurveToFixed( cpx, cpy, x, y ) {
04 /*
05 For the equations below the following variable name prefixes are used:
06 qp0 is the quadratic curve starting point (you must keep this from your last point sent to moveTo(), lineTo(), or bezierCurveTo() ).
07 qp1 is the quadratic curve control point (this is the cpx,cpy you would have sent to quadraticCurveTo() ).
08 qp2 is the quadratic curve ending point (this is the x,y arguments you would have sent to quadraticCurveTo() ).
09 We will convert these points to compute the two needed cubic control points (the starting/ending points are the same for both
10 the quadratic and cubic curves.
11
12 The exact equations for the two cubic control points are:
13 cp0 = qp0 and cp3 = qp2
14 cp1 = qp0 + (qp1 - qp0) * ratio
15 cp2 = cp1 + (qp2 - qp0) * (1 - ratio)
16 where ratio = (sqrt(2) - 1) * 4 / 3 exactly (approx. 0.5522847498307933984022516322796)
17 if the quadratic is an approximation of an elliptic arc, and the cubic must approximate the same arc, or
18 ratio = 2.0 / 3.0 for keeping the same quadratic curve.
19
20 In the code below, we must compute both the x and y terms for each point separately.
21
22 cp1x = qp0x + (qp1x - qp0x) * ratio;
23 cp1y = qp0y + (qp1y - qp0y) * ratio;
24 cp2x = cp1x + (qp2x - qp0x) * (1 - ratio);
25 cp2y = cp1y + (qp2y - qp0y) * (1 - ratio);
26
27 We will now
28 a) replace the qp0x and qp0y variables with currentX and currentY (which *you* must store for each moveTo/lineTo/bezierCurveTo)
29 b) replace the qp1x and qp1y variables with cpx and cpy (which we would have passed to quadraticCurveTo)
30 c) replace the qp2x and qp2y variables with x and y.
31 which leaves us with:
32 */
33 var ratio = 2.0 / 3.0; // 0.5522847498307933984022516322796 if the Bezier is approximating an elliptic arc with best fitting
34 var cp1x = currentX + (cpx - currentX) * ratio;
35 var cp1y = currentY + (cpy - currentY) * ratio;
36 var cp2x = cp1x + (x - currentX) * (1 - ratio);
37 var cp2y = cp1y + (y - currentY) * (1 - ratio);
38
39 // and now call cubic Bezier curve to function
40 bezierCurveTo( cp1x, cp1y, cp2x, cp2y, x, y );
41
42 currentX = x;
43 currentY = y;
44 }
Rectangles
Besides the three methods we saw above which draw rectangular shapes directly to the canvas, we also have a method rect which adds a rectangular path to the path list.
rect(x, y, width, height)
This method takes four arguments. The x and y parameters define the coordinate of the top left corner of the new rectangular path. width and height define the width and the height of the rectangle.
When this method is executed, the moveTo method is automatically called with the parameters (0,0) (i.e. it resets the starting point to its default location).
Making combinations
In all examples on this page I've only used one type of path function per shape. However there's absolutely no limitation to the amount or type of paths you can use to create a shape. So in this last example I've tried to combine all of the path functions to make a set of very famous game characters.
Example
I'm not going to run through this complete script, but the most important things to note are the function roundedRect and the use of the fillStyle property. It can be very usefull and time saving to define your own functions to draw more complex shapes. In this script it would have taken me twice as many lines of code as I have now.
We will look at the fillStyle property in greater depth later in this tutorial. Here I'm using it to change the fill color from the default black, to white, and back again.
View this example
01 function draw() {
02 var ctx = document.getElementById('canvas').getContext('2d');
03 roundedRect(ctx,12,12,150,150,15);
04 roundedRect(ctx,19,19,150,150,9);
05 roundedRect(ctx,53,53,49,33,10);
06 roundedRect(ctx,53,119,49,16,6);
07 roundedRect(ctx,135,53,49,33,10);
08 roundedRect(ctx,135,119,25,49,10);
09
10 ctx.beginPath();
11 ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false);
12 ctx.lineTo(31,37);
13 ctx.fill();
14 for(var i=0;i<8;i++){
15 ctx.fillRect(51+i*16,35,4,4);
16 }
17 for(i=0;i<6;i++){
18 ctx.fillRect(115,51+i*16,4,4);
19 }
20 for(i=0;i<8;i++){
21 ctx.fillRect(51+i*16,99,4,4);
22 }
23 ctx.beginPath();
24 ctx.moveTo(83,116);
25 ctx.lineTo(83,102);
26 ctx.bezierCurveTo(83,94,89,88,97,88);
27 ctx.bezierCurveTo(105,88,111,94,111,102);
28 ctx.lineTo(111,116);
29 ctx.lineTo(106.333,111.333);
30 ctx.lineTo(101.666,116);
31 ctx.lineTo(97,111.333);
32 ctx.lineTo(92.333,116);
33 ctx.lineTo(87.666,111.333);
34 ctx.lineTo(83,116);
35 ctx.fill();
36 ctx.fillStyle = "white";
37 ctx.beginPath();
38 ctx.moveTo(91,96);
39 ctx.bezierCurveTo(88,96,87,99,87,101);
40 ctx.bezierCurveTo(87,103,88,106,91,106);
41 ctx.bezierCurveTo(94,106,95,103,95,101);
42 ctx.bezierCurveTo(95,99,94,96,91,96);
43 ctx.moveTo(103,96);
44 ctx.bezierCurveTo(100,96,99,99,99,101);
45 ctx.bezierCurveTo(99,103,100,106,103,106);
46 ctx.bezierCurveTo(106,106,107,103,107,101);
47 ctx.bezierCurveTo(107,99,106,96,103,96);
48 ctx.fill();
49 ctx.fillStyle = "black";
50 ctx.beginPath();
51 ctx.arc(101,102,2,0,Math.PI*2,true);
52 ctx.fill();
53 ctx.beginPath();
54 ctx.arc(89,102,2,0,Math.PI*2,true);
55 ctx.fill();
56 }
57 function roundedRect(ctx,x,y,width,height,radius){
58 ctx.beginPath();
59 ctx.moveTo(x,y+radius);
60 ctx.lineTo(x,y+height-radius);
61 ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
62 ctx.lineTo(x+width-radius,y+height);
63 ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
64 ctx.lineTo(x+width,y+radius);
65 ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
66 ctx.lineTo(x+radius,y);
67 ctx.quadraticCurveTo(x,y,x,y+radius);
68 ctx.stroke();
69 }
相关推荐
标题中提到的“HTML 5 CANVAS游戏开发实战”涉及到的知识点包括了HTML 5技术、CANVAS元素以及游戏开发方面的实战应用。HTML 5是最新版本的超文本标记语言,它引入了诸多新的特性来增强网页的表现性能和实现更丰富的...
Canvas是HTML5中的一个核心元素,允许在网页上动态绘制图形,就像一个画布。JavaScript作为客户端脚本语言,与HTML5和Canvas结合,可以创建出丰富的交互式用户界面,包括图像处理功能,如头像的缩放和裁剪。 头像...
HTML5 Canvas是Web开发中的一个强大工具,它允许开发者在网页上进行动态图形绘制,创造出丰富的交互式2D图形和...这个压缩包对于初学者和有经验的开发者都是宝贵的参考资料,可以加深对Canvas的理解,提升Web开发技能。
HTML5 Canvas API 是一个强大的网页图形绘制工具,它允许...提供的HTML5CanvasAPI.htm文件可能包含了这些知识点的实例代码,可以作为学习和参考的宝贵资源。而Image文件可能用于演示如何在Canvas上处理和绘制图像。
### Foundation.Html5.Canvas #### HTML5 Canvas:权威指南与应用实践 HTML5 Canvas 是一种用于在网页上绘制图形的技术,它通过 ...对于希望深入了解 HTML5 Canvas 技术的开发者来说,本书是一本不可多得的参考资料。
本手册提供Html5--Canvas标签绘图的完全参考; 其中包括标准函数,数据结构及样式枚举等元素的使用说明; 注明了Html5-Canvas中文教程、源码、样例的资源地址;以及函数参考的日文网站;但是本手册只做为开发人员参考...
通过阅读《HTML5 Canvas经典学习教程》和参考《HTML5 Canvas Cheat.pdf》的速查指南,你可以系统地学习并掌握这些知识,从而在网页开发中充分利用Canvas的强大功能,创造出令人惊叹的交互式Web应用。
这些例子对于初学者来说是非常宝贵的参考资料,能快速上手并理解html2canvas的基本用法。 其次,“html2canvas-0.4.1.zip”是该版本的源码包,解压后我们可以查看源代码,进一步学习其内部实现机制。开发者们可以...
本文实例讲述了javascript+HTML5的canvas实现七夕情人节3D玫瑰花效果。分享给大家供大家参考。具体如下: 下面的玫瑰绘制用到了HTML 5的canvas,所以你的浏览器需要支持HTML 5。个人还是比较推荐chrome,这个效果在...
《HTML5 Canvas Cookbook》这本书通过实例讲解,不仅适合初学者快速入门,也为有经验的开发者提供了许多实用的解决方案和灵感,是一本值得深入研究的HTML5 Canvas参考资料。通过阅读和实践书中的示例,读者将能够...
炫酷的HTML5 canvas效果展示, 代码结构简单,有利于开发者参考使用。
在这个"html5+canvas+jquery拼图游戏实例"中,我们看到的是如何利用这些技术来创建一个有趣的游戏体验。Canvas是HTML5的一个核心元素,它允许开发者在网页上进行动态图形绘制,而jQuery则是一个流行的JavaScript库,...
它对于学习和理解HTML5的图形编程,尤其是Canvas的应用,具有很高的参考价值。同时,这个项目也表明了Web技术在金融领域的广泛应用,证明了Web技术不仅可以构建静态网页,也能承载复杂的动态应用。
HTML5 Canvas是一个强大的Web绘图接口,允许开发者在网页上直接进行像素级别的图像处理和动态图形绘制。这个“HTML5 Canvas绘图示例.rar”压缩包包含了一个具体的应用实例,教你如何利用Canvas API来画直线、图形...
这些源码实例为学习和掌握HTML5 Canvas提供了一手的实践资料。 首先,我们来深入了解HTML5 Canvas的基本概念。Canvas是一个基于矢量图形的画布元素,通过JavaScript API可以进行像素级别的操作。它提供了丰富的绘图...
HTML5 Canvas是Web开发中的一个强大工具,它允许开发者在网页上进行动态图形绘制,创造出丰富的交互式用户体验。在这个特定的场景中,我们讨论的是如何使用Canvas来制作一个随机流动的粒子动画背景特效。这个特效...
HTML5 Canvas Cookbook是关于HTML5 Canvas技术的实践指南书籍,由Eric Rowell撰写,Packt Publishing出版。本书提供超过80个实用的配方,旨在通过使用HTML5 Canvas技术革新网页体验。它由Packt Publishing在2011年11...