Transformations

Our next topic will be transformations. Similar to other canvas methods ,and like I have said before, you should keep in mind canvas is one solid object. When ever a transformation is made on the canvas the entire canvas is altered. In order to be able to draw a shape that is transformed, say for instance an oval, We have two methods save() and restore(). Save and restore work like a stack with a FILO(First In Last Out) order. Imagine if you had three sheets of paper. Now the first time you use the save() method you are placing one sheet on your desk. If you use the save() method again your are placing a second sheet of paper on your desk on top of the first one. If you use save() once more you are placing a third sheet on top of the other two. Now to get to the first sheet you have to remove the two sheets above it. This is what is meant when we say first in last out. The restore() method is us removing those sheets of paper. Each time you call it without calling save() again you are taking the top sheet of paper off of the pile. Another way to look at it is like an array. In this example push() would be save and pop() would be restore. Now unlike the sheets of plain paper when we add to our drawing stack using save() we are saving the configuration of the canvas at that time. Things like fillStyle, strokeWidth, font, and our transformations will be saved in the stack. So whenever we do transformations it is important that before we do the transformation we use save() to save our normal canvas state then do our transformation and after use restore to restore us to the normal canvas. If you do not anything that you draw after the point of using the transformation will be altered by that transformation. Now you can always use the same transformation again to manually set the canvas back to normal but the save() method is much much easier. So let's begin

Translate

Our first transform will be translate(). This method takes our canvas and moves the origin point, (0,0) or the top left corner of our canvas, and moves it to a point we indicate in the method parameters. So if we were to fill our canvas with a black rect after using translate with (50,50) as the x and y values respectivly you will see that our black rect that should be the size of the canvas will not touch the top left corner of the window. This is because we set our origin to x: 50 and y: 50. As you can see in the next pen it will literally move the whole thing. I have also added a save() and restore() method to show you how you would save the canvas state and restore it so the drawings following would not be affected by translate.

The code for this is simple

  
ctx.save();
ctx.translate(50,50);
// Paint our canvas black
// since it has been translated
// it will start at (50,50)
// even though notice our fillRect starts at (0,0)
ctx.fillStyle = "#000";
ctx.fillRect(0,0,W,H);

// This red box shows you that anything drawn
// after the translate will be affected by it
ctx.fillStyle = "#F00";
ctx.fillRect(5,5,100,100);


/* but if we restore it notice how
the blue box is no longer confined to
 an origin set at (50,50)*/
ctx.restore();
ctx.fillStyle = "#00F";
ctx.fillRect(5,5,45,45);


Now just for fun let's use translate to build a mess of boxes. As you can see from the next script, using translate() and a simple loop I can create the same shape 6 times in a different position

  var x = 0;
var y = 0;

ctx.fillStyle = "#F00";

for(var i = 0; i < 6; i++){
  ctx.save();
  ctx.translate(x,y);
  ctx.fillRect(0,0,100,100);
  ctx.restore();
  x += 105;
  y += 105;
}

Scale

Next we will learn about scale(). This method will take and scale up or down any values in relations to the amount of x or y scale that you enter in as it's parameters. For instance

  // ctx.scale(x-scale, y-scale)
ctx.scale(2,2);

This will double anything that you put in so if you set a width and height of 100 it will come out as 200 if you set an x coord at 100 it will come out as 200.As you can see in the next pen:

You can also scale in only one direction or reduce a scale in a direction. For instance if you were to set scale like so:

  ctx.scale(2, 0.5);

This would set anything along the x axis, like the width, to double the normal amount and anything along the y axis to half of the amount.

Rotate

Now to rotate. To start off with make life easier on yourself. Use translate to move the origin point before you rotate. Just like with all the rest this will change to position of your entire canvas. If you leave the origin at the top left of the screen you are rotating around that point. Moving the origin makes life a lot easier as you will then be rotating around that new origin point. Rotation also works like arc does. The method takes one parameter, the angle at which you wish to rotate in radians. If you recall in our previous lesson converting to radians from degress is degs * Math.PI / 180. So if we want to rotate our canvas 45 deg we would do a little something like this:

  ctx.save();
ctx.translate(W/2,H/2);
ctx.rotate(45 * Math.PI/ 180);

This will put our origin in the middle of you canvas and rotate 45 degrees clockwise. It will look like this:

Now in mine I added some additional rects to use for refrence the white one is a rect non translated and rotated, the blue rect is the new position of the canvas after the rotation and the red rect represents the shape we are drawing rotated.

Once again a little creative programming we can use this to create interesting shapes and even animate our shapes (which we will get more into later).

Custom Transformations

Other transformations such as skewing a shape are done by custom transformations. Now in this lesson I will not be going into the matrix math that is actually used in this. It will be covered at one point but not today. If you want a general overview of how matrix transformations work you are welcome to peruse this. This image here

transformation Matrix

is also the transformation matrix used along with the transform() method. However, i will be covering this in greater detail later once we get into vector math. The thing right now to remember is the parameters for the transform() method.

  
ctx.transform(scaleX, skewX, skewY, scaleY, translateX, translateY );


The scaleX and scaleY translateX and translateY work just the same as we saw earlier. To explain skew (or shear) I want you to think of a ladder. Each rung on that ladder is a line drawn at a y coordinate. Now imagine if on one side of that ladder we removed all of the rungs and connected them one rung below where it was supposed to go. The farther we get away from the side that is in a normal correct spot the greater the distance from where that point on the rung should be to where it actually is. Basically it defines a slope. If we were to draw a line all the way accross say y: 50 and our skew is 1 then point (0,50) is normal but the next point we would draw would be at (1,51) the next would be at (1,52) and so on and so forth. Now I say this so that you can imagine what this is doing however, because we are skewing our entire canvas the truth is that the points draw are actually (0,50) (1,50) and (2,50) and so on. It is just that we happened to move where y: 50 is plotted.

Here is a nice quick example of custom transforms skewing a rectangle:

and code

  ctx.transform(1, 1, 0, 1, W/2 - 50, H/2 - 50);
ctx.fillStyle = "#F00";
ctx.fillRect(0,0,100,100)

Just something to keep in mind as well if you set the transform to

  ctx.transform(1,0,0,1,0,0)

That resets the transformation of the canvas.

Ovals and mirroring

Today lastly we will be quickly going over how to make an oval and how to mirror a shape using our transforms. We will start with the Oval. So what happens when you draw a circle but scale every y change up to say double. Well you get an oval as you can see here

  ctx.beginPath();
ctx.translate(W/2, H/2);
ctx.scale(2,1);
ctx.arc(0, 0, 50, 0, Math.PI * 2);
ctx.fill();

Similarly scaling the canvas to a -x or -y will flip the canvas vertically or horizontally and will mirror the shape being drawn.

  ctx.fillStyle= "#F00";
ctx.translate(W/2,H/2);
ctx.font = "30px Arial;"
ctx.scale(-1,1);
ctx.fillText("Hello peoples", 0,0);

Thanks for sticking with it next week we will be going over canvas composition. Things like opacity clipping what happens when to shapes are drawn over each other. Lots of fun stuff. After that I will put up some exersices to let you practice on and Chapter 1 will be done with. You will know all the basics you really need to know. Exciting huh? See you next week.


1,759 0 0