Canvas and Nested Loops

Goals

In this lesson we will look into nested loops. Multiple iteration is merely a single nested structure where loops exist inside other loops. If you understood how loops work, understanding nested loops should not be difficult to grasp.

We will also learn how to render Java canvas elements with JavaScript.

  • Understanding the behavior of nested loops in a while statement.
  • Understanding the behavior of a nested for loop.
  • Understanding how to track changes in variables in nested loops
  • Understanding how to use three level or more nested loops effectively
  • Learning how to render Canvas elements with basic shapes such as circles and rectangles.
  • Drawing complicated figures on the canvas element

 

canvas and drawing

Before describing the canvas and rendering nested loops, let’s look into what the canvas element is as an element in HTML.

The canvas element

The canvas element is an element for securing a drawing area on a Web page. Below is an example on how to create a canvas element in HTML.

A drawing area of 200 × 200 is fixed when we create a canvas of size 200×200 pixels. “Rectangle drawing area” enclosed by tags is a character string displayed as an alternative when this page is displayed in browsers that do not support the canvas element. As long as you use the latest version of browsers such as Firefox or Safari, such a character string will never be displayed.

HTML

 <canvas id="canvas" width="200" height="200">Rectangular drawing space</canvas>

 

Just inserting the canvas element into an HTML document merely leaves space on the page. This space is now empty and only contains the placeholder text that we wrote. In order to actually utilize the canvas element, it is necessary to draw it using JavaScript.

Basics of drawing with JavaScript

In order to draw within the drawing space fixed by the canvas element using JavaScript , it is necessary to acquire the canvas element in the program and obtain the drawing context thereafter. The context is what allows us to manipulate the empty space in the canvas element for drawing.

HTML

<canvas id="canvas" width="200" height="200">Rectangular drawing space</canvas>

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.strokeRect(50, 50, 100, 100);

The above program draws a square using the canvas element. The canvas element is acquired in the first line of JavaScript. By acquiring the canvas element, we can perform actions such as drawing, using programming and basic mathematics.

In the second line, the context for two-dimensional rendering is acquired. The context may be difficult to understand, but it is used to define what kind of coordinates are used, what kind of graphics can be specified and what kind of sizes and colors are to be filled in. In other words, by specifying ‘2d’ here, we get a 2D rendering context. The fact that there are two dimensions means that if you write ‘3d’, you can also draw three dimensions, but unfortunately the only drawing context you can currently use is ‘2d’. In the future it may become possible to use 3D drawing contexts as well.

Once you get the drawing context of the canvas, you can change some of the properties that exist in it. For example, you can change the line color and thickness to suit your preference. In order to change the thickness of a line with JavaScript, after acquiring the drawing context ctx (We don’t have to name it ctx but let’s keep it that way for convenience), we can change the lineWidth property. Also, to change the line color, change the strokeStyle property. You can specify the color for filling, by changing the fillStyle property.

Look at the next program. Line thickness, color, and fill color are specified from line 4 to line 6 of JavaScript. Also, in the eighth and ninth lines, filled squares are drawn and rectangular boxes are drawn.

Looking at the HTML part of this program, usually the script element is contained in the header. This is to allow you to load the program after creating the canvas element. Normally, this kind of operation is not performed, and the onload event is used, but this time, please execute the program in this way.

HTML

<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8">
    <title>描画の例</title>
  </head>

  <body>
    <h1>描画の練習</h1>
    <canvas id="canvas" width="200" height="200">四角形を描画する領域</canvas>
    <script src="draw.js"></script>
  </body>
</html>

JavaScript(draw.js)

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

ctx.lineWidth = 10.0;
ctx.strokeStyle = 'black';
ctx.fillStyle = 'lightgrey';

ctx.fillRect(50, 50, 100, 100);
ctx.strokeRect(50, 50, 100, 100);

Basic drawing using JavaScript

When we render images onto our canvas we must understand what a path is. A path is used to draw complex figures by combining a number of mathematical and graphical methods. Imagine you are holding a pen and giving it instructions where to move and whether to touch the paper or not. In essence, the path is the journey traveled by a pen over the paper when making a drawing.

For example, the method for drawing hexagons does not exist in the two-dimensional drawing context, but you can draw a hexagon using a path.

  • Here, the path from the beginPath() method to the closePath() method is the part defining the path.
  • We use the moveTo() method (to move from start point to end point without touching the canvas) or the lineTo() method (to move ) to select a starting point and draw the first line.
  • We draw a hexagon by specifying the co-ordinates
  • We fill it with color with the fill() method
  • After that we color the line using the stroke () method.

Note that until you color it with the fill () method or the stroke () method, it does not actually look like a visible shape.

HTML

<canvas id="canvas" width="200" height="200">Hexagon is drawn here</canvas>

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var x = 100;  // X co-ordinate of the center
var y = 100;  // Y co-ordinate of the center
var r = 80;   // Radius

ctx.lineWidth = 3.0;
ctx.strokeStyle = 'black';
ctx.fillStyle = 'lightgrey';

ctx.beginPath();
ctx.moveTo(x + Math.sin(0 * 2 * Math.PI / 6) * r, y - Math.cos(0 * 2 * Math.PI / 6) * r);
ctx.lineTo(x + Math.sin(1 * 2 * Math.PI / 6) * r, y - Math.cos(1 * 2 * Math.PI / 6) * r);
ctx.lineTo(x + Math.sin(2 * 2 * Math.PI / 6) * r, y - Math.cos(2 * 2 * Math.PI / 6) * r);
ctx.lineTo(x + Math.sin(3 * 2 * Math.PI / 6) * r, y - Math.cos(3 * 2 * Math.PI / 6) * r);
ctx.lineTo(x + Math.sin(4 * 2 * Math.PI / 6) * r, y - Math.cos(4 * 2 * Math.PI / 6) * r);
ctx.lineTo(x + Math.sin(5 * 2 * Math.PI / 6) * r, y - Math.cos(5 * 2 * Math.PI / 6) * r);
ctx.lineTo(x + Math.sin(6 * 2 * Math.PI / 6) * r, y - Math.cos(6 * 2 * Math.PI / 6) * r);
ctx.closePath();
ctx.fill();
ctx.stroke();

There is another thing to be careful about here. In the normal graph, the number increases from left to right on the X axis and from the bottom to the top on the Y axis, but when drawing with the canvas element, the number increases from the top to the bottom on the Y axis. Please note this point when calculating the coordinates.

canvasの座標系
canvasの座標系

methods for drawing

Below is a summary of the representative methods used for drawing. These have been written for you by developers all over the world, so you are free to use them to draw in your own programs.

Method Explanation
fillRect(x, y, w, h) Draws a rectangle without filled boxes of width w and height h from the coordinates specified by (x, y) as a starting point. Unlike lineTo () etc., a rectangle is actually drawn without using stroke () method or fill () method.
strokeRect(x, y, w, h) Draws a rectangle with unfilled frame of width w and height h from the coordinates specified by (x, y) as a starting point. Unlike lineTo () etc., a rectangle is actually drawn without using stroke () method or fill () method.
clearRect(x, y, w, h) Deletes figures in the range of width w and height h from the coordinates specified by (x, y) as a starting point.
moveTo(x, y) With the pen tip raised, move the pen tip to the coordinates specified by (x, y).
lineTo(x, y) Draws a straight line from the position where the pen tip is present to the coordinate specified by (x, y).
rect(x, y, w, h) Draws a rectangle of width w and height h starting from the coordinates specified by (x, y).
arc(x, y, r, sAng, eAng, anticlockwise) Draws an arc of radius r from the angle specified by sAng centered on (x, y) to the angle specified by eAng. In addition, counterclockwise when anticlockwise true, and clockwise when false.
bezierCurveTo(x0, y0, x1, y1, x2, y2) Draw a cubic Bezier curve. Draws a Bezier curve with the current coordinates as the start point, (x 2, y 2) as the end point, (x 0, y 0) as the control point for the start point and (x 1, y 1) as the control point for the end point.
fillText(text, x, y) fillText (text, x, y) Write the character string specified by text to the coordinate (x, y). You can change the font by changing the font property of the drawing context like “ctx.font =” 20pt Mincho “;”

If you want to erase the entire canvas, you can use clearRect () to make it “ctx.clearRect (0, 0, canvas.width, canvas.height);”, where ctx is the drawing context. Also, canvas is a variable containing a canvas element. For canvas.width and canvas.height, the width of the canvas and the height of the canvas are automatically set.

Nested Loops

Two Level Nested Loops

Regarding iteration, we have already explained that while statements and for statements exist. However, using a while loop or for loop singly can sometimes run out of functionality. Consider using the previous canvas element to draw a pattern like the checker flag like this:

In order to draw such a pattern, of course, there is also a way to program it in HTML and JavaScript:

HTML

<canvas id="canvas" width="200" height="200">Canvas Element Here</canvas>

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

ctx.fillRect(  0,   0, 20, 20);
ctx.fillRect( 40,   0, 20, 20);
ctx.fillRect( 80,   0, 20, 20);
ctx.fillRect(120,   0, 20, 20);
ctx.fillRect(160,   0, 20, 20);
 
ctx.fillRect( 20,  20, 20, 20);
ctx.fillRect( 60,  20, 20, 20);
ctx.fillRect(100,  20, 20, 20);
ctx.fillRect(140,  20, 20, 20);
ctx.fillRect(180,  20, 20, 20);
 
ctx.fillRect(  0,  40, 20, 20);
ctx.fillRect( 40,  40, 20, 20);
ctx.fillRect( 80,  40, 20, 20);
ctx.fillRect(120,  40, 20, 20);
ctx.fillRect(160,  40, 20, 20);

...

However, it seems that computers can make this process faster and more efficient. If we automate some of the processes by using a loop we can make the program faster and easier to process. Look at the next program.

HTML

&amp;amp;amp;amp;amp;lt;canvas id="canvas" width="200" height="200"&amp;amp;amp;amp;amp;gt;四角形を描画する領域&amp;amp;amp;amp;amp;lt;/canvas&amp;amp;amp;amp;amp;gt;

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var y;
for (y=0; y&amp;amp;amp;amp;amp;lt;200; y = y + 20) {
  if (y % 40 == 0) {
    ctx.fillRect(  0, y, 20, 20);
    ctx.fillRect( 40, y, 20, 20);
    ctx.fillRect( 80, y, 20, 20);
    ctx.fillRect(120, y, 20, 20);
    ctx.fillRect(160, y, 20, 20);
  } else {
    ctx.fillRect( 20, y, 20, 20);
    ctx.fillRect( 60, y, 20, 20);
    ctx.fillRect(100, y, 20, 20);
    ctx.fillRect(140, y, 20, 20);
    ctx.fillRect(180, y, 20, 20);
  }
}

However, program also has parts that are redundant. We can make this process even simpler by adding another loop within this for loop.

HTML

<canvas id="canvas" width="200" height="200">四角形を描画する領域</canvas>

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var x, y;
for (y=0; y&amp;amp;amp;amp;amp;lt;200; y+=20) {
  for (x=0; x&amp;amp;amp;amp;amp;lt;200; x+=20) {
    if ((x+y)%40 == 0) {
      ctx.fillRect(x, y, 20, 20);
    }
  }
}

In this example, the loop controlled by the variable y contains a loop controlled by the variable x. This is a two level nested loop. A flowchart of this nested loop is shown below. It may seem complicated at first, but you should be able to understand it once you check each flow.

 

二重ループのフローチャート
二重ループのフローチャート

Exercise 7-1

  1. Create an HTML file marked * above and draw.js and run the program.
  2. Create a program that swaps  ctx.fillRect () with ctx.strokeRect () and see what happens.

Exercise 7-2

Create a program that draws n squares by entering n as shown below.

Exercise 7-3

Using the above program, create a program to find π by increasing the number of sides in a polygon and dividing the circumference by its diameter.

Exercise 7-4

Draw the asterisk as shown below.

Exercise 7-5

Draw the following figure.

Exercise 7-6

Draw the following figure

Exercise 7-7

Draw the following figure

Exercise 7-8

As shown below, create a program to find π by Monte Carlo method while displaying points. Also, be sure to increase accuracy as you press the button. In order to calculate π by the Monte Carlo method, consider the circle inscribed in a square, select an appropriate point, and check whether that point falls inside the circle. On that basis, π is calculated from the ratio of points entering the circle.