Main content
Computer programming - JavaScript and the web
Course: Computer programming - JavaScript and the web > Unit 4
Lesson 6: TransformationsMultiple transformations
Now that you've seen the basics of translation, rotation, and scaling, let's talk about using all of them together, and some of the complexities we brushed over at the beginning.
Order matters
When you do multiple transformations, the order makes a difference. A rotation followed by a translate followed by a scale will not give the same results as a translate followed by a rotate by a scale. Here is an example program that demonstrates that:
Which order you use depends on what your desired effect is. Just keep in mind that you're moving the graph paper, not the object itself, and you should find an order that works for you.
The transformation matrix
Every time you do a rotation, translation, or scaling, the information required to do the transformation is accumulated into a table of numbers. This table, or matrix has only a few rows and columns, yet, through the miracle of mathematics, it contains all the information needed to do any series of transformations. And that’s why the
pushMatrix()
and popMatrix()
have that word in their name.What about the push and pop part of the names? These come from a computer concept known as a stack, which works like a spring-loaded tray dispenser in a cafeteria. When someone returns a tray to the stack, its weight pushes the platform down. When someone needs a tray, he takes it from the top of the stack, and the remaining trays pop up a little bit.
In a similar manner,
pushMatrix()
puts the current status of the coordinate system at the top of a memory area, and popMatrix()
pulls that status back out. The preceding example used pushMatrix()
and popMatrix()
to make sure that the coordinate system was "clean" before each part of the drawing. In all of the other examples, the calls to those two functions weren’t really necessary because there were no subsequent transformations, but it doesn’t hurt anything to save and restore the grid status. As a best practice, always use those functions when you're doing any transformations.There is also a
resetMatrix()
function that resets the matrix back to its very original state (the "identity matrix"), but the push and pop functions are nearly always the better approach.Want to learn or review how matrices work in Algebra? You can go through Matrices on Khan Academy, in particular, the Geometric transforms with matrices section.
This article is an adaptation of 2D Transformations by J David Eisenberg, used under a Creative Commons Attribution-NonCommercial-ShareAlike License.
Want to join the conversation?
- in the next challenge i am stuck on the last step it says my translations is incorrect but thats not true heres my code please answer
angleMode = "degrees";
var backgroundColor = color(135, 206, 250);
var sunColor = color(255, 255, 0);
var sunStrokeColor = color(200, 200, 0);
var sunDiameter = 100;
var drawCloud = function() {
noStroke();
fill(255, 255, 255);
ellipse(0, 0, 126, 97);
ellipse(60, 0, 70, 60);
ellipse(-60, 0, 70, 60);
};
var drawSunRay = function() {
fill(sunColor);
noStroke();
triangle(0, 90, -40, 0, 40, 0);
};
var drawSun = function() {
//draw sun rays
for(var i = 0; i < 342; i+=30) {
pushMatrix();
translate(200,200);
rotate(i);
drawSunRay();
popMatrix();
}
//draw center of sun
fill(sunColor);
stroke(sunStrokeColor);
ellipse(width/2, height/2, sunDiameter, sunDiameter);
};
//draw background
background(backgroundColor);
//draw sun
var scaleF = 2;
pushMatrix();
translate(5-5*41,5-40*5);
scale(scaleF);
drawSun();
popMatrix();
//draw clouds
pushMatrix();
translate(300,268);
drawCloud();
popMatrix();(36 votes)- You always want the sun to be in the center (200, 200) regardless of scaleF
Try
translate(200 - 200 * scaleF , 200 - 200 * scaleF);
because when the sun is scaled, the new center is 200*scaleF. To get it back to (200, 200), you have to translate it back scaleF*200-200. because translating towards the origin is negative, it should be 200 - 200*scaleF(20 votes)
- Do the width and height variables change if I change the scale?(22 votes)
- In the challenge: optical illusion, why do we have to translate and do all that stuff when we can simply draw the circles at 200, 200?(4 votes)
- Because that is the purpose of the challenge: To practice transformation functions.(39 votes)
- Will a colorMode function call between pushMatrix and popMatrix affect the color mode of the stuff after popMatrix?(10 votes)
- Yes , it will.
colorMode
wrapped withpushStyle
andpopStyle
will not.(13 votes)
- On Challenge: Shining Scaling Sun I need help! I did steps 1 & 2 myself but I am stuck on step three. I used the help code. I have the following code:
var scaleF = function() { //scale factor
pushMatrix();
translate(___-_____*___,_____-___*_____);
scale(scaleF);
drawSun();
popMatrix();
};
and i can't seem to find the values to use in thetranslate();
function. The page is also saying that my sun is either too big or too small and thet i should set the existing variable scaleF to a value between 1 and 3 but I cannot seem to find it.(9 votes)- translate(200-200*scaleF,200-200*scaleF);(7 votes)
- plz correct me if I am wrong: resetMatrix() would take us to the very start of the code and push/pop would take us to the last time they were used for a transformation, hence better practice to use these,right?(5 votes)
- Correct.
resetMatrix
is rarely the correct call. It is another transformation function, and not a restoration matrix function.(7 votes)
- It says: The preceding example used pushMatrix() and popMatrix() to make sure that the coordinate system was "clean" before each part of the drawing.
But really, doesn't popMatrix() restore the "clean" version after our drawing is done, not before?(5 votes)- It's talking about the next iteration of drawing, by saving the matrix and then restoring it, the next time the drawing is performed the matrix is unchanged from what it was before the first drawing. It could probably be reworded (to make sure it was 'clean' you'd technically use resetMatrix() as mentioned, otherwise you are expecting it to be 'clean' and simply not 'dirtying' it (by pushing and popping it); the distinction matters more if you are using other people's code (because if you call someone else's code, they may not have used pushMatrix() and popMatrix() to prevent changing the matrix).(7 votes)
- Does the Khan Academy library have a "reflect" function ?(3 votes)
- You can set
scale
to a negative value. Look:var img = getImage("avatars/avatar-team");
imageMode(CENTER);
image(img, 100, 200, img.width / 2, img.height / 2);
pushMatrix();
translate(300, 200); // we translate the image to our ideal spot
scale(-1, 1); // we set the x-scale to -1 and the y-scale to 1, flipping the image
image(img, 0, 0, img.width / 2, img.height / 2); // we display the image
popMatrix();
// dashed line
for(var i = 0; i < height; i += 10) {
line(width / 2, i, width / 2, i + 2);
}
To see a live example, go here: https://www.khanacademy.org/computer-programming/flipped-images-example/4571085845889024(11 votes)
- Can someone help me with the translation part of the Challenge: Shining scaling sun I don't know what to do... translation( _ - _ * _ , _ - _ *)
= what I don't know what to put there.(4 votes)- I found the translations! They include the number 200 twice and the variable scaleF once for each parameter of the translate() command.(2 votes)
- What is the advantage of pushMatrix and popMatrix over resetMatrix if we are storing the "clean" matrix using these first 2? Is it just to make the program clearer to humans, with the two matrix codes acting like brackets around the translation?(2 votes)
- It makes it exportable. You can insert the code into sequences that already have some pushMatrixes and translations done without affecting them. If you insert something with resetMatrix it might destroy something.(6 votes)