JavaScript Turtle Graphics

Tutorial for JavaScript Turtle Graphics

The Basics

JavaScript is an important language, because it is the language used in browsers to bring life to web pages. It dynamically resizes elements so that the same page can be used on a mobile phone or desktop computer. It dynamically loads data, like weather data or news stories, as it changes or as you move down on the page. It provides motion and interest to web pages. JavaScript also checks user inputs before a request is sent back to the server.

Learning JavaScript programming in a graphics environment is an easy way to get introduced to JavaScript. The JavaScript Turtle Graphics page at http://turtlegraphics.fun is written in JavaScript and it provides an environment for exploring JavaScript and its use of graphics using traditional turtle graphics functions.

This tutorial assumes that you have some basic knowledge. Go to JavaScript Tutorial or the Guide for the Integrated Development Environment (IDE) if you need more information.

In these lessons there are small programs to load and play with. It is important to type these programs in and to try them out. Typing reinforces the lesson with muscle memory of the act of typing and forcing you to recognize each character. Just reading the lesson is not enough. It is also necessary to play around with each lesson. Change some of the parameters or the way that the program works. You should be able to predict what will happen when you change things, so that you can change things to be the way you want them to be.

Hello World

When programmers are faced with a new language, the first thing that they do is to write a simple program that tests their understanding of the language, its syntax and the operation of the new language. Typically this is a "Hello World" program. For this environment such a program would be as follows:

write ("Hello World")

Click on the Run Demo button.

What happened? You should see Hello World printed on the canvas, but printed sideways. Text is written along the direction that the turtle is pointing without moving the turtle.

write() is a A function perform a desired action and are composed of instructions and possibly other functions. Functions allow a programmer to use them without having to worry about all of the underlying details. Turtle Graphics is written using functions that hide the details from the user.

Syntax

Syntax is a funny word. No, it is not a tax on your sins. It is the mechanics of the language. It is how you string words and punctuation or symbols together so that the intent of the language can be understood by humans and computers. Just as English has its rules for putting sentences together, JavaScript has its rules. The only thing to know is that computers are not as flexible as humans in being able to figure out what is meant if the syntax isn't correct. Preciseness is the rule in computer languages.

Case, as in upper case and lower case, is important to JavaScript, so Write is different than write and is different than wriTe. This property is called case sensitive. Most passwords are case sensitive. Can you think of other examples?

All functions in JavaScript are followed by open and close parentheses. This is the syntax that tells JavaScript that the preceding name is a function. If there is nothing between the parentheses, the function takes no parameters. The function write(string) does take a single parameter, a string that you want to put on the canvas, and that is put between the parentheses. Functions can take a number of parameters depending on the function. Any number of parameters is allowed, although it gets hard to remember the purpose of each parameter as the number increases.

A string is a set of characters The syntax for a string is to enclose a set of characters with quotation marks. This distinguishes the string from other characters which could be a function name, variable name, or other value. In English we use quotation marks to set off the spoken words or special words from other words in a sentence. JavaScript sets off strings. Either single or double quotes are acceptable, as long as it is the same type is used on both ends. Just about any character can be included in a string, but including a quotation mark requires some consideration. A simple way is to enclose the string with a quotation mark is to use the other kind of quotation marks to enclose the string. So, you could use "G'day world", if you want the Australian version of “Hello World.”

The program as it is, isn't quite right. The write() function displays a text string in the direction that the turtle is moving without moving the turtle. We want the text to go horizontally to make it easier to read. We need to rotate the text 90° in a clockwise direction. We can do that by turning the turtle before invoking the write() function, by invoking a right(90) function to ask it to turn 90 degrees to its right. Because this programming has more than one line, lets use the coding area, so we can edit the programs and make changes to it as necessary. The resulting program for the coding area is:

right (90) write ("Hello World")

Click on the Run Demo button, you should see something like the figure on the right.

The right() function also takes a parameter like write, but right's parameter is the number of degrees to turn right. Look at the parameters of the two functions. Write takes a string of characters or more simply just a string. A string is enclosed in either 'single quotes' or "double quotes." If you need to enclose a quote mark or apostrophe in a string, just use the other type of quote. You may also "escape" the quote mark with a backslash character '\'. Escaping is fairly common in program languages to allow a character to be used as itself (or as something completely different than its normal usage). As you learn programming you will probably encounter more examples of escaping or escape mechanisms.

right (90) write ("That's fun! Don't forget to try this at \"home.\"")

Part of JavaScript's syntax, is that white space is not too important so you can add spaces, tabs or carriage returns (sometimes called newlines) here or there to make the code easier to read. Each JavaScript statement is usually written in a single line, although an exceptions is made for long statements that read better with multiple lines. Each line in formal JavaScript must end in a semi-colon ';' as in:

right( 90); write ( "Hello World");

We are writing in a more casual syntax that does not require this semi-colon. Just beware that some syntax checkers will require more semi-colons. If multiple codes statements are placed on one line, the code statements must be separated with semi-colons.

Comments are important to remind you or the next reader what the code is attempting to do. (Sometimes the code misses the intent, so it is important to state the intent, and to keep that up to date as the code changes.). JavaScript has two types of comments. A comment that just tacks on the end of a line starts with a double slash // and goes to the end of the line. A multi-line comment starts with slash-star /* and ends with a star-slash */. Multi-line comments may not be nested, because the comment ends with the scanning of the first star-slash after the first slash-star. The second slash-star isn't seen by JavaScript because it is in a comment. The second star-slash doesn't have a lead in slash-star as far as JavaScript is concerned so it is a syntax error.

So both right() and write(), are functions. These hide the details of their implementation for their user. JavaScript allows its users to define their own functions. We can define a 'Hello World' function, ‘hi()’ as:

function hi () { right( 90); write ( "Hello World"); }

The word function is a key word in JavaScript that tells it that you want to define a function. Key words are words reserved by a language, JavaScript in this case, to signal some intent to the programming language. Key words cannot be used for other purposes. The key word function is followed by the name you want to give to the function. You should pick a unique name for the function, as this definition will override any previous definition. The open and close parentheses tell JavaScript that the function definition includes no parameters in this case. Even though there are no parameters, the parentheses are still needed. The open and close curly brace are used to mark the beginning and end of a block of statements to be executed when the hi() function is invoked.

Debugging

Try to execute the program by pressing on the Run Demo. You should get a error message about demo being undefined. This is because the Run Demo tries to invoked the demo() function, and it isn't defined in the coding area. So let's adds a demo() function to the program:

function hi () { right( 90); write ( "Hello World"); } function demo () { }

Now try to execute the program again by pressing on the Run Demo. The error has gone away, but nothing has executed. Why? We defined demo() as requested, but as defined, it does nothing. The hi() function was never called or invoked. Let's add a call or invocation to the hi() function in the demo() function.

function hi () { right( 90); write ( "Hello World"); } function demo () { hi() }

Now when you press the Run Demo button, the turtle should print "Hello World" on the canvas.

What happens if you press the Run Demo button more than once? Why?

We can fix that by clearing the screen by invoking the reset () function before writing to the canvas.

function hi () { right( 90); write ( "Hello World"); } function demo () { reset() helloWorld() } You can try to introduce other syntax errors in the program to see the error message the JavaScript produces. Sometimes the message does not say exactly what the problem is, only what JavaScript perceives the problem to be. Think of it as more of a hint or suggestion, rather than something specific. It is good to get an idea of how JavaScript reports the syntax problems the it detects for a known problem so that you get a better idea of what it is trying to tell you for a random error.

Your First Graphic

OK, but Turtle Graphics is a graphics program, shouldn’t we be doing some graphics? Let's see it draw some lines as sort of a graphical Hello World example. Let's try to do a simple square. forward(100) right(90) forward(100) right(90) forward(100) right(90) forward(100) right(90)

Ok, let’s do the same thing, but do it with by defining a function to draw the square, as we have learned previously.

function square1 () { forward(100) right(90) forward(100) right(90) forward(100) right(90) forward(100) right(90) } function demo () { reset() square1() }

Let's see some of the power of a function with a simple change to draw three squares rotated 30° about the starting point. Change the demo () function as follows:

function square1 () { forward(100) right(90) forward(100) right(90) forward(100) right(90) forward(100) right(90) } function demo () { reset() square1() right(30) square1() right(30) square1() }

Repeating

Great! Now looking at the function square1(), there is a lot of repetition. There are a couple of ways to do this. Using the Turtle Graphics function repeat(), the code would look something like:

// square with repeat function el () { forward (100) right (90) } function square () { repeat (4, el) } function demo () { reset() square() }

But the repeat function is messy and not really the JavaScript way of doing things. Let's not use the repeat() function and use a with a while statement instead. The simplest JavaScript program using a while statement is something like:

var i = 0; while ( i < 4) { i = i + 1 }

What does this do? The key word var is used to define a variable, or more specifically where a variable is defined. i is the name of a variable being declared. The statement i = 0, is an assignment of the value 0 to the variable i. This could be read as: "set variable i to 0." The JavaScript statement i = 0 is just a short hand form of that. This is definitely not the way normal arithmetic symbols are used, because here '=' means 'assign' or 'set', even though after the assignment, i is equal to 0.

Sometimes a variable is declared without setting it to an initial value, so its value would be undefined. In general this is a fairly bad idea. It is definitely an error to use a variable before its value is assigned.

The next statement is the while statement. while is a key word that signals to repeat the following statement or group of statements surrounded by an open and close curly brace, while the condition enclosed between the open and close parentheses evaluates to true. The only statement within the curly brackets is i = i + 1.

So what happens when this is run.

This is all hard to see, so let's make it more visible. Let's print the value of i inside of the loop. Since the write() function doesn't move the turtle, we need to do that as well by drawing the now familiar square. By the way, printing a variable during execution is a common tool used by programmers to see what is happening inside of a program to help debug the program.

The program uses a while loop to repeat four times: write a number, draw a side, turn the corner, and increment the number of sides.

function square() { var i = 0 while ( i < 4) { write (i) forward (100) right(90) i = i + 1 } } function demo() { reset() square() }

JavaScript has two other common looping techniques. One is a do...while statement. The block of code to be repeated is after the do key word and the while is after the repeated block of code. So the block is always executed at least once where in a while statement the block may not be executed at all. The equivalent code for drawing a square is shown below.

function square(side) { var i = 0 do { forward( 50); right( 90) i = i + 1 } while (i < 4) } function demo() { reset() square() }

This pattern for looping through a block of code is very common in programming, so JavaScript uses a technique used in other languages like C to do a for loop. A for loop allows the programmer to do the three required steps of a loop in a single statement. These parts are separated with semicolons, just as multiple statements on a line would be separated. The code for a for loop to draw a square is as follows:

function square(side) { for( var i = 0; i < 4; i = i + 1) { // init; test; and change i forward( 100) // block of code is within curly braces right( 90) } } function demo() { reset() square() }
The bottom line is that the inner group of statements is executed exactly 4 times. This type of loop is also called an iterative loop as it is executed a counted number of times. The control variable, i in this case, is sometimes called an iterator.

Function Parameters and Arguments

Wow! OK. Let's say we want to draw another square, but of a different size. We can copy the square() function code, change the function name, say to square200(), change the forward(100) to the size you want say, forward(200).

Now if you want to draw a square of 100 or 200 points, you are set. But if you want another size, you have to do the copy and change routine all over again. There is a better way. That is to a parameter to the basic square() function. We'll tell JavaScript that we want to pass a value in the function definition by including the parameter name or names within the parentheses as in the following code.

function square(side) { for( i=0; i<4; i=i+1) { forward( side); right( 90) } } function demo () { reset() square(100) // 100 is an argument }

When the program is executed the value of side is used in the forward( side) statement. To use that value, we just pass an argument to the square function by placing the argument, say '100,' within the parentheses, as in: square (100).

Putting the two together, the code should look something like the figure to the right. We also need to modify the function call in the demo() function to use the new arguments. When the function is invoked, it is supplied with arguments. The value of the arguments is passed to the parameter in the corresponding position defined with the function. Of all this there can be no argument, or was that a parameter.

function square(side) { // side is a parameter var i = 0; while ( i < 4) { forward (side) // here the parameter is accessed // it is like a variable local // to the function square() right(90) i = i + 1 } } function demo () { reset() square(100) // 100 is an argument }

Hey, isn’t that just like we did before. That was a lot of work to change the code, just to do the same thing. Why would you do that? To show off the power of a function with parameters, we can now use the iterator, so let's put in an iterator into the demo program that turns the square while changing its size. Let's do this one step at a time. First just turn it.

function square(side) { var i = 0; while ( i < 4) { forward (side) right(90) i = i + 1 } } function demo () { reset() var i = 0 while (i < 12) { square(75) turn (30) // turn the square i = i + 1 } }

The next modification to the code also changes the size of the squares and their color with each iteration within the while loop of the demo() function.

function square(side) { var i = 0; while ( i < 4) { forward (side) right(90) i = i + 1 } } function demo () { reset() var i = 0 while ( i < 12) { color (i) square(i * 10) turn (30) i = i + 1 } }

Scope

Great. You may have noticed something funny. Both the square() and demo*()functions use the same variable name i for the iterator. Don't they conflict? No. In this case i is defined as a local variable within the curly braces of each function with the var. This means the variables only have meaning within the local context of the function in which they are defined.

If i had been defined outside of the functions at the global level as in the following code, there would be trouble.

var i; function square(side) { i = 0; while ( i < 4) { forward (side) right(90) i = i + 1 } } function demo () { reset() i = 0 while ( i < 12) { color (i) square(i * 10) turn (30) i = i + 1 } }

Both functions would access the same variable and this would make the routines much harder to debug because both functions would be changing the value of i. The general sequence of what happens in the code is:

If you run this program on the IDE, it will lock up. The easy way to get out of this is to wait for the browser to detect that a web page is taking too much time and it issues and alert box asking to stop the window or to continue. You should stop the window and reload the IDE page. It probably is a good idea to recognize when something is wrong and what to do to fix it.

In general it is better to use local variables than ones defined globally for several reasons:

  1. The same name can be used without conflict in other functions.
  2. Only the code within the function can access the local variable.

Sometimes global variables are necessary when you need to share data between functions or when a variable needs to last longer than just the time that a function is called (a property called persistence). A local variable within a function is created each time the function is run, so it has no knowledge of previous executions. A global variable lives outside of the function so it is not affected by individual function invocations, although to be useful, the function may be changing that value for its own benefit. If other functions mess with that variable, and there is nothing to stop them from doing so except for programmer discipline, the variable may not work as expected.

Variables default to being global, if you do not use the var key word to define them. A variable can be made local by declaring the variable with the var key word within the curly braces of a function definition. Think of the location of the var variable declaration as the location of the variable. Inside a function: it is local to that function; outside the functions: it is global to all.

This example also introduced the color() function. It works with simple numbered colors like a numbered box of crayons. It is limited to a number between 0 and 15. This works great in this case, except for white, which is number 7, doesn't show up well on a white background.

Review

Review a bit, we have:

Randomness

So far we have drawn things with attributes that we assign in the code. What about having the program make up values and use them on the fly. Let’s try to place random-colored, random-sized squares at random places on the canvas. It sounds like we need a random number generating function. The random() function fills the need. This has two forms: one with one number and one with two numbers. The single number form generates an integer between 0 and the value supplied. The two number form generates an integer between the two numbers.

We used the color() function in the last exercise. It works on a number between 0 and 15, so random( 15) will work for a random color (as long has you are happy with crayon colors).

To position the start of the square anywhere on the canvas, the goto(x,y) function can be used. A Cartesian coordinate system is used with x=0, y=0 at the center of the canvas. (see example of Cartesian coordinates.) The values at the edges of the canvas will vary from machine to machine and with the size of the particular window. There are functions to retrieve the minimum and maximum X values, minX() and maxX() respectively. minX() returns the left most x point and maxX() returns the right most x point. The minY() and maxY() functions do the same for the Y values. These functions are necessary because the screen size is different for different devices and can change at will on laptops and desktop machines as the browser window is changed.

We need to pick a random number for a random x and a random y on the canvas for the goto(). random( minX(), maxX()) will pick a suitable x value and random( minY(), maxY()) will pick a suitable y value. This is put altogether in the following code. Note that the x and y parameter positions in the definition of the goto() function definition determine the order of the arguments when invoking the goto() function.

function square(side) { i = 0; while ( i < 4) { forward (side) right(90) i = i + 1 } } function demo(){ var i reset() for (i=0; i<20; i= i + 1) { color( random(15)) goto (random( minX(), maxX()), random(minY(), maxY())) square( random( 15,150)) } }

Simple Animated Build

Simple animations can be done with the animate() function. The function just repeats calls to the function named in its first argument after a delay of the number of milliseconds (1/1000 second) specified by the second argument. By not clearing or resetting the canvas between calls, the effects just build on the canvas. The program can be stopped by pressing the Stop button.

Let's use the same basic program that we used in the last exercise. We need to break the demo() function into two parts, because animate needs to call a function that draws something on the canvas. The iteration is no longer needed, because that is effectively done by the animate() function. The reset() should only be done in the demo function as well as the animate() function. Everything else can be put into a randomSquare() function.

function square(side) { i = 0; while ( i < 4) { forward (side) right(90) i = i + 1 } } function randomSquare(){ color( random(15)) goto (random( minX(), maxX()), random(minY(), maxY())) square( random( 15,150)) } function demo(){ reset() animate( randomSquare, 100) // pass address of function, // not results of the function }

A funny thing is happening with the reference of randomSquare in the demo() function above. This is passing the address of the randomSquare() function to the animate() function. Animate executes the function at the address passed to it. By dropping the parentheses from the demo2() function, the address of the function is used rather than to attempt to invoke the function immediately as is done with the random(), minX(), minY(), maxX(), maxY() functions elsewhere in the code.

The squares can be rotated as well by throwing in a turn (random(something)) into the mix.

function square(side) { i = 0; while ( i < 4) { forward (side) right(90) i = i + 1 } } function randomSquare(){ color( random(15)) goto (random( minX(), maxX()), random(minY(), maxY())) right(random( 5, 30)) square( random( 15,150)) } function demo(){ reset() animate( randomSquare, 100) // pass address of function, // not results of the function }

The line widths of squares can also be varied by throwing in width function. So in keeping with the randomness theme, why not make the lines a random width with width (random(something)) into the mix. You may not want lines that are too thin (zero?) or too wide, so limit the range of the widths. This code looks something like the following.

function square(side) { i = 0; while ( i < 4) { forward (side) right(90) i = i + 1 } } function randomSquare(){ color( random(15)) goto (random( minX(), maxX()), random(minY(), maxY())) right(random( 5, 30)) width( random( 1, 6)) square( random( 15,150)) } function demo(){ reset() animate( randomSquare, 100) // pass address of function, // not results of the function }

By adding minor changes to the code, we are able to have some fairly dramatic changes to the generated graphic. Most programming is like this. Start out with some thing that works and then add more functionality in little steps until it is what you want.

Polygons

Generalizing the square function for a polygon function

We can generalize the square() function to make it can make polygons. Generalize here means to take the basic idea of a function and make it so that it can do more easily. We've already generalize a simple square function into one that you can specify the length of its sides. Now we want to generalize the square() function so that it so that it can generate a polygon.

The answers are on the next page if you get stuck, but try to solve these without looking.

For the square, take 360°, divided by 4 gives 90° for each angle. For a triangle, take 360°, divided by 3 gives 120° for each angle. This is the outside angle, not the inside angle. Some of you may know that an equilateral triangle, has three sides of the same length and three 60° angles. Generalizing for polygons, take 360° and divide by the number of sides to get the angle. This would mean that a general polygon can be generated by the length of its sides and the number of sides required.

function polygon (size, n) { var i = 0 while (i < n) { write (i) forward (size) right (360/n) i = i + 1 } } function demo() { reset() for (var i=3; i < 10; i = i+1) { polygon( 40+2*i, i) } }

Now let's go one step further and try to draw pointed stars, that we will call spikeys. What about a five-pointed star? It has a lot of similarities as the polygon. Both end up in the same place and same direction as the start. Both have five corners and the corners are in the same place. One difference is a spikey is concave between points, where a polygon is flat. Another difference is that in drawing a polygon, the turtle only goes around the center point once. When drawing a star, the turtle would have to go around twice.

  • In a polygon, how many times to you go around the center point.
  • In a five-pointed star, how many times do you go around the center point?
  • Can you use that number to calculate the angle that you need to turn?
  • Can you generalize this?
  • Are there exceptions?
  • Is there a maximum?
  • times and still end up in the same starting position and angle?

    When you draw the star free hand, you go around the center point twice and you make 5 turns. You can use that to determine the angle. Twice around the center is twice 360° or 720°. Dividing this by the number of points, 5, yields 144°. Remember this is the turning angle for the turtle. The inside angle is 180° minus the turning angle or 36°.

    The limit to the number of times that you can go around the center point is n/2 where n is the number of points in the star. Going around more than n/2 times, produces the same result as a lower number, but the figure is in the opposite direction. If the number of points is divisible by the number of revolutions, the figure will close prematurely. So n works best if it is prime. With the number of revolutions close to n/2, the figure is most spikey. As n gets smaller, the opening in the center gets bigger and bigger and the outer ring gets narrower and narrower.

    function spikey (size,n,revs) { var i = 0 while (i < n) { write (i) forward (size) right (revs*360/n) i = i + 1 } } function star (size) { backward (size/2) spikey (size, 5, 2) } function demo () { reset() star(200) }
    function spikey (size,n,revs) { var i = 0 while (i < n) { write (i) forward (size) right (revs*360/n) i = i + 1 } } function polygon (size, sides) { spikey (size, sides, 1) } function demo () { reset() polygon(20, 20) }
    function spikey (size,n,revs) { var i = 0 while (i < n) { write (i) forward (size) right (revs*360/n) i = i + 1 } } function starN ( size, points) { reset() backward (size/2) spikey (size, points, Math.floor(points/2)) } function demo () { reset() starN (200, 21) }

    Other variations to try…

    //spikey( 200, 41, 20) //spikey( 200, 41, 20) //spikey( 200, 47, 23) //spikey( 200, 51, 25) //n must be not be divisible by revs //revs is best at about n/2

    Next Step???

    What should you do next? Here are some ideas that may help you in your next coding adventure.

      • Set up a demo of finding pi with a random number generator. Hint: use a square that is 1 unit by 1 unit and a quarter of a circle with a radius of 1 unit. Remember the Pythagorean theorem.
      • Play with random colors. Hint: color (random(15)) or even more colors if you use individual red, green and blue color codes like color ("rgb(" + random(255) + "," + random(255) + "," + random(255) + ")" ).
      • Play with color around a color wheel to change colors more subtly. Hint: color("hsl(" + i/n*360 + ", 100%, 50%")
      • Investigate other fractals and draw them. Many can be found on Wikipedia.
      • Investigate tessellations and draw them. Many can be found on Wikipedia. Some can be found on wall paper, shower curtains or floor tiles.
      • Do an animated graphics demonstration. Write a story or build up a story graphically.
      • Make the page web accessible for people with various challenges.
      • Add to a server, perhaps on a Raspberry Pi with Apache.

      Learn more about JavaScript, HTML, and CSS using resources:

      • Read a book like JavaScript for Kids.
      • Take a online JavaScript course like Khan Academy. More ideas on the nerd link page.
      • Get hands on experience with Code.org.
      • Find other examples of graphics and code in Turtle Graphics
      • Find out about a particular JavaScript feature at W3School.
      • Learn about code development tools
        • Browser based debugging tools.
        • “jslint” programs to check JavaScript, CSS and HTML syntax. Lint programs find inconsistencies in coding style that may lead to undetected bugs.
        • “minify” programs to make your final code smaller for downloads.