JavaScript Turtle Graphics

Basic JavaScript Grammar

This is a brief tutorial on JavaScript. Read as much as you can, but come back to review or to learn a new concept. If you need more depth, there are other tutorials and guides on JavaScript on the internet or in your library.

Comments

A comment is a note left by the developer to others, including the developer, about some aspect of the code. This makes the code easier to understand. Comments are not executed by the JavaScript interpreter, so they provide no functionality. Yet they are very (important as a way to communicate intent. Comments can also be used to turn off sections of code during testing.

JavaScript has two kinds of comments.

Functions

JavaScript allows the programmer to define blocks of code that can be used over and over. These blocks are called functions. Some functions may take arguments as inputs, others do not. It is up to the programmer to decide what the function will do, whether it takes parameters and whether it returns a result. A function may be called a procedure, a subroutine, or other names. These names are generally talking about the same thing that JavaScript calls a function. A function is invoked in a statement by using its name followed by a opening and closing parentheses '(' and ')'. There may be arguments between the parentheses.

A simple example could be a function that draws a square on the canvas. The turtle is moved to where the shape is required and the function is invoked.

// define the square function function square () { forward (100); right (90); forward (100); right (90); forward (100); right (90); forward (100); right (90); } square () { // invoke the square function right(30) // invoke the Turtle Graphic right() function // with the distance argument 30 square () { // invoke the square function again right(30) // invoke the Turtle Graphic right() function again square () { // invoke the square function once again

Good functions have no side effects, that is, they should not change the value of global variables. So a function that draws a shape should leave the turtle in the same position as it was when the function was called and pointing in the same direction. Of course there are exceptions like a function that draws a fancy corner. The point is, the function should be predictable and not have a side effect which would manifest itself as a nasty bug down the road.

Variables

Variables are used to store a value for later use. Sometimes it is for convenience. For instance, it is a lot easier to remember and type pi, than it is to remember and type 3.141596... Sometimes a variable is used is to remember a partial result, like how many times has the race car gone around the track or how many brothers and sisters do you have.

a = 1; // assign the value of the integer '1' to the variable 'a'. a = 1.0; // assign the value of the number '1.0' to the variable 'a'. a = "cabbage"; // assign the string "cabbage" to the variable 'a'. a = true; // assign the Boolean value true to the variable 'a'.

Variable names that have a clear meaning make code easier to read and understand. For example: lapsCompleted = 3 is easy to understand. l = 3 can be difficult to understand. What is l" and how is it being used? Is that the letter l or the digit 1. Variables have some restrictions on naming:

So the following are acceptable as variable names:

The following are unacceptable as variable names:

Variable names are case sensitive, so Dog and dog and doG are different names. It usually is not a good idea to use names with the only difference being the case of the letter.

Variables are declared with the var keyword. Variables may be initialized or assigned at the same time as they are declared. JavaScript is not strict about declaring variables, but it is a good idea to do so.

var lapsCompleted; // declared but not initialized var lapsToGo = 50; //declared and initialized lapsToGo = 51; //previously declared, now assigned

Each variables should be declared only once by using the reserved key word var and should be declared before they are used elsewhere.

Data Types

JavaScript has four primitive data types. They are:

A primitive data type is only composed of itself or data types like it, e.g., 1.1 is 1 + .1; "hi" is "h" + "i". Boolean values cannot be combined, they are simply either true or they are false. A variable is undefined if it is not initialized or assigned prior to using its value. It can also happen when setting a variable to the results of a function that does not return a value. Some functions return undefined when they can't return what was requested, for instance when something isn't found. Undefined can be very useful and very hard to debug in some cases.

a = 1 // variable a is defined to be 1 var b // variable b is declared but undefined var c = 1 // variable c is declared and set to 1

Additionally JavaScript has compound data types including a array, e.g., [1,2,3, "fish"] is an array of data elements, each element may be a different data type.

// assigning an array to a variable a = [1, 2, 3, 5]; //a is list of numbers // access an element of an array b = a[1]; // b is second element of list a, so it is 2

Another compound JavaScript data element is object. An object is similar to a list in that it is a collection of values, but in an object each value or attribute is named. Let's say you want an object to define the characteristics of a dog. You might define a dog object as in the following code.

dog = { name: "Fido", breed: "dalmatian", color: "white and black", gender: "M", age: 3 } // accessing an element of the object breedOfDog = dog.breed // breedOfDog = "dalmatian" ageOfDog = dog["age"] // ageOfDog = 3

An object may be a collection of primitive data types and compound data types like lists and other objects. Internally all data within JavaScript is handled as an object. Even a JavaScript function is treated as an object.

JavaScript is said to be typeless. This really means that the language doesn't check the type of a variable when setting it. So you can set variable a to 1 and a while later set a to "hi." JavaScript doesn't mind a bit, but this can lead to errors especially when unintentionally reusing a variable or having a number when you expect a string.

Functions with Parameters

A more powerful version of a function is a function that is called with one or more parameters. A parameter is named like a variable and may be any data type. It may be just about anything that the function needs to complete its task. There is no limit to the number of parameters that a function can use, but it is usually wise to keep the number down to the minimum required for the particular function.

function square (size) { // size is a single parameter forward (size); // here it is used in the forward function call right (90); forward (size); // here it is used in the forward function call right (90); forward (size); // here it is used in the forward function call right (90); forward (size); // here it is used in the forward function call right (90); }

A function is invoked with its name and supplying arguments as needed. The value of the arguments is passed to the function parameters. Notice how inside a function, the passed values are called parameters and when the function is invoked, the values are called arguments. In JavaScript functions are said to be called by value, so the value is copied from the argument to the parameter. The function cannot affect the value of the arguments in the caller. (There is an exception to this with passing objects in a certain way, but that is left as an exercise for the reader.)

square (10) // invokes the square function with one argument '10' // to produce a square with each side equal to 10.

A function may also return a value by using the return key word. For example let's say you want a function that produces the cube of a number. Such code would look like the following.

function cube( number) { return number * number * number } b = cube (2) // b = 8 c = cube (10) // c = 1000

Expressions

Expressions are a way of combining variables, numbers, strings and Boolean values into other forms. Expressions have operators that act upon one or more operands. Much of this is familiar. Adding two numbers to produce a sum. Subtracting one number from another to find a difference. Dividing one number by another to get get a dividend, proportion or ratio.

Assignment Operators

Assignment operators are used to assign values to variables. You can't change the value of number or a string as these are constantor immutable (unchangeable).

Operator Use Example Result
= assign a=4 a is the number 4
(white space: space, tab, new lines, comments) increase readability a = 4 a is 4, white space has no effect
= assign a = "Hello, World" a is the string "Hello, World"
= assign a = true a is the Boolean true
= assign b = a b has the current value of the variable a

Number Operators

Number operators are used to manipulate numbers to get sums, differences, products, dividends, remainders, etc.

Operator Use Example Result
_ add 1+3 4
- subtract 5-3 2
* multiply 5-3 2
/ divide 5/4 1.25
% mod or modulo (remainder after division) 5%4 1
- negate -5 -5

String Operators

There is a operator to manipulate strings.

Operator Use Example Result
+ concatenate or join "tom" + "cat" "tomcat"

Boolean Operators

There are a set of operators to manipulate Boolean values. Remember that a Boolean can only be either true or false.

Operator Use Example Result
&& logical AND a && b true if both a and b are true, else false
|| logical OR a || b true if either a or b is true, else false
! logical NOT !a true if a is false, else true

Comparison Operators

Comparison operators are used to compare two operands to result in a Boolean true or false value. Not that equality is similar to assignment.

Operator Use Example Result
== equality a == b true if a evaluates to b, else false. Be careful with this when comparing different types.
1 == "1" true, both evaluate to "1"
=== strict equality a === b true if a is same type as b and a equals b, else false
1 === "1" false, different data types
!= inequality a != b true if a does not evaluate to b, else false
!== strict inequality a !== b true if a is a different type than b or a is not equals b, else true
< less than a < b when a and b are numbers, true if a is less than b, else false
a < b where a and b are strings, true if a is alphabetically before b, else false. Note that the ASCII order is used, so all upper case letters are less than any lower case letter.
> greater than a > b true if a is greater than b, else false
<= less than or equal a <<= b true if a is less than or equal to b, else false
>= greater than or equal a >= b true if a is greater than or equal to b, else false
<== strict less than or equal a <<= b true if a is of the same type as b and a is less than or equal to b, else false
>== strict greater than or equal a >== b true if a is of the same type as b and a is greater than or equal to b, else false

The following is a list of things to consider when doing comparisons. (from the Mozilla development foundation).

Simplified Operator Precedence

JavaScript has some twenty levels of precedence that is described more fully in the advanced section of this document. The precedence of the operators discussed up to this point is summarized in the following table.

Precedence Operator type Associativity Individual operators
20 Grouping n/a ( … )
19 Member Access left-to-right … . …
Computed Member Access left-to-right … [ … ]
16 Logical NOT right-to-left ! …
Unary Plus + …
Unary Negation - …
15 Exponentiation right-to-left … ** …
14 Multiplication left-to-right … * …
Division … / …
Remainder … % …
13 Addition left-to-right … + …
Subtraction … - …
11 Less Than left-to-right … < …
Less Than Or Equal … <= …
Greater Than … > …
Greater Than Or Equal … >= …
10 Equality left-to-right … == …
Inequality … != …
Strict Equality … === …
Strict Inequality … !== …
6 Logical AND left-to-right … && …
5 Logical OR left-to-right … || …
3 Assignment right-to-left … = …

Statements

Usually there is one JavaScript statement per line, but you can put more on a line as long as each statement is separated with a semicolon ';'. In modern browsers this semicolon is optional. Some programmers like to end each statement with a semi-colon anyway. Some statements may span more than one line, especially complex assignment statements. JavaScript determines the end of a statement explicitly with the presence of the semi-colon or it guesses the end of statement by the context of the various lines of code as in the following example.

a = 1; // statement with ending semicolon a = 1 // statement without the ending semicolon a = 1; b = 2 // two statements on a line a = 1 // could be the end or not depending on what follows + 1 // appended to preceding line + 1 // appended to the preceding lines + 2 // appended to the preceding lines, so a = 5 b = 3 // another statement

Now let's try some Turtle Graphics functions. These statements are simple function calls. turn the turtle the right 90 degrees, right(90), and move the turtle forward 10 units, forward(10).

right(90) forward(10) right(90) forward(10) right(90) forward(10) right(90)

This tells the turtle to move and turn, move and turn, move and turn, move and turn to complete a square as in the following figure.

Some of JavaScript's constructs come in pairs. Strings are enclosed in pair of single quotes (apostrophes) or a pair of double quotes. A single quote may appear in a string set off with double quotes and a double quote may appear in a string set of with single quotes. An opening parentheses, square bracket, or curly brace (brace), must be matched with the closing parentheses, square bracket or curly brace.

r = 'string' // string of characters a = "string" // string of characters b = ' another string' // string of characters b = (2 + 3) * 5 // parentheses to affect order of calculation // b = 25 b = 2 + 3 * 5 // without parentheses, multiplication // take precedence over addition, so b = 17 d = [a, b, c] // list of variables function foo (a, b, c) // group of parameters { statement, statement, statement} ; // group of statements in a function f = foo (1, 2, 3) // group of arguments 1,2,3 { a=1; b=2; c=a+b} // group of statements dog = { breed: "dalmatian", //object with 4 attributes color: "white and black", gender: "M", age:2 }

Basic JavaScript Concepts

Conditionals

A conditional is code that is executed when some Boolean condition is true or false. Conditionals start with an if key word followed by an expression, called the condition, contained within parentheses which evaluates to a Boolean value, either true or false. This is followed by a single statement or a block of statements surrounded by curly braces that is executed if the condition is true. This statement or group of statements is sometimes called the then clause of the conditional. Many programmers always use the curly brackets to make their code more consistent, even if there is only a single statement. The if statement can be followed immediately by the else keyword followed with a single statement or a block of statements surrounded by curly braces. This statement or group of statements is sometimes called the else clause of the conditional. The else clause is executed if the condition is false.

function square() { for (i=0; i<4; i=i+1) { if (i % 2 == 0) { //i is even color (blue); width (4); } else { color (black); width (.5); } forward(50); right(90); } }

Note: JavaScript allows the use of the short cuts i++ instead of "=i+1 and i-- instead of i=i-1. The long form is used here and most of the examples to make the code easier to understand and less prone to errors.

Iteration

Computer science calls the process of doing things over and over, iteration. Turtle graphics give you a way to do iteration with the repeat(count, function) statement. This lets you execute a defined function a number of times.

function square (size) { repeat (4, function () { forward (size); right (90); }) }

So in using a while statement, there are three things you need to do:

In the example, the condition being tested is the turtle running off of the screen. Since its path is enlarged each loop, eventually it should run off the screen and prevent an infinite loop.

function spiral () { var i = 0; while ( i < 10) { forward (i + i); right (90 - i); i = i + 1; } }

In this example, the condition is initialized with i = 0. The continuing condition is i > 10, so the stopping condition would be i >= 10. The condition is changed within the loop with i = i + 1.

Sometimes you want the repetition to continue until some other criteria is met. Below is an example of a spiral that will expand until it moves off of the canvas. This example also shows a variable that is increased in value for each loop to make the length of the sides increase. The condition for continuing the loop is whether the turtle remains withing the bounds of the canvas. This is inherently initialized when the program starts. It is changed every iteration when the turtle moves. It should be noted that if the turtle does not move in bigger and bigger paths, the program will get stuck in an infinite loop.

function spiral () { wrap(false); var i = 1; while ( turtle.pos.x < maxX() && turtle.pos.x > minX() && turtle.pos.y < maxY() && turtle.pos.y > minY()) { forward (i + i); right (90 - i); i = i + 1; } }

JavaScript has other way of doing iteration loops, but a commonly used one is the for loop. It uses the for key word followed by three sub-statements enclosed in parentheses and separate with semi-colons. The three sub-statements: initialization, while condition, and iterator. Initialization is used to initialize the value of the iteration variable or iterator. This variable is commonly named 'i', but any valid variable name can be used. Make sure to include a declaration for the iterator using the keyword var somewhere within the function. The second part, the while condition is an expression that is evaluated before every loop and must evaluate to true for the loop to be executed. The third and last part is the iterator where something is done to change the looping variable at the bottom of the loop. Most of the time the parts are fairly simple as in the following now familiar example:

function square() { for (i=0; i<4; i=i+1) { forward(20); right(90); } }

Scope of Variables

Variables declared within a function are local to that function and can only be accessed within that function. These variables are called local variables. Variables declared outside functions and variables that are not declared with the var can be accessed by any function. These variables are called global variables. Most programmers try to avoid global variables to limit the number of functions that can change the value of a variable.

Let's say you want to use the variable i within an iteration to keep track of how many times the loop has been executed as is common practice. If you don't declare i with var within each function, i will default to being a global variable, accessible by all functions that don't declare i locally. Let's say you want to draw 3 squares using a square function that draws the four sides. The code looks like:

function square (side) { for (i=0; i<4; i=i+1) { forward( side) right( 90) } } for (i=0; i<3; i=i+1) { square( 100) right(30) }

So what happens when this is executed? For the first loop of the main program the variable i is set to zero and the function square is called. Square also sets the variable i is also set to zero. No problem yet, but as the sides are drawn, i is incremented to 1, 2, 3 and finally 4. When the square function returns, the variable i is 4. When the code loops back to the for instruction for the loop check, i being 4 is not less than 3, so the looping stops and only one square is drawn. Not exactly what was intended.

To fix this, one might try to declare i with the var instruction. If the declaration is outside of the functions, at it is in the following block of code, i is declared as a global. Since any undeclared variable is a global by default, this declaration has no effect.

function square (side) { for (i=0; i<4; i=i+1) { forward( side) right( 90) } } var i; // declares i as a global variable for (i=0; i<3; i=i+1) { square( 100) right(30) }

The proper way to fix this is to either change the variable names so there is no conflict or to declare the variable within the function to make it a local variable. Changing the name can be difficult for large programs, so let's learn to use local variables when we can. In the following block of code, the variable i is declared as a local within the square() function (that is, within the outer most curly braces of the function definition). Now it is as if there were two variables named i and they are totally independent of each other, one local to the square function and one global. The code will draw the three squares as desired.

function square (side) { var i; // declares i as a local variable for (i=0; i<4; i=i+1) { forward( side) right( 90) } } var i; // declares i as a global variable // even though not necessary, it is // good practice to declare all variables. for (i=0; i<3; i=i+1) { square( 100) right(30) }

In general programmers try to avoid using global variables. This is because they can get changed by any function and sometimes it is hard to know which function is affecting the variables. Local variables are only affected within the function so it is easier to find the culprit.

As a side note. In the above example, the parameters for a function are automatically local variables, declared with the function definition. So side is a local variable within the square() function.

Advanced JavaScript Concepts

Advanced Assignment Operators

We talked about the assignment operator =. There are other more specialized assignment operators. In general these should be avoided because they do cause some confusion and may lead to bugs if the symbols are interchanged. (+= is an assignment adding the right hand side to the left hand side of the expression. =+ is an assignment of the positive value of the right hand side to the left hand side of the expression.)

Operator Use Example Result
+= add assign lapCount += 1 lapCount is upped by 1 to be 3
+= subtract assign lapCount -= 1 lapCount is down by 1 to be 2
*= multiply assign lapCount *= 2 lapCount is doubled to be 4
/= divide assign lapCount /= 2 lapCount is halved to be 2

Bit-wise Operators

There are operators to perform bit-wise operations on numbers. These numbers are restricted to 32 bits, which is smaller than normal integers and floating point numbers (52 bits). Some of these operations are similar to the Boolean operators, except that they work on individual bits instead of the value as a whole. While this is a more advanced topic, it is nice to know that more exists in case you encounter them, or need them for a particular problem. The bit-wise operators are shown in the following table. The binary equivalents of the decimal numbers are shown in parentheses.

Operator Use Example Result
>> shift right 4>>2 (0b0100>> 2) 1 (0b0001)
<< shift right 4<<2 (0b00100) 16 (0b10000)
<< bit-wise AND 5&4 (0b0101 & 0b0100) 4 (0b0100)
<< bit-wise OR 5|2 (0b0101 | 0b0010) 7 (0b0111)
^ bit-wise exclusive OR 5|2 (0b0101 | 0b0010) 7 (0b0111)
~ bit-wise NOT ~1 (~0b0000000000000001) -2 (0b1111111111111110)

Grouping Operator and Order of Precedence

Using a set of parentheses is used to group operands and operators to affect the order of evaluation. Operators have an order of precedence that dictates the order in which the operators are evaluated, e.g., multiplication takes precedence over addition, so multiplications are done before additions. The grouping operator takes precedence over other operators, so what is within the parentheses is evaluated before what is outside the parentheses. Parentheses may be nested. When in doubt and order matters, use parentheses.

The following table is ordered from highest (20) to lowest (1) precedence (taken from the Mozilla.org. This is the full set of precedence. Many of the operators are beyond the scope of this simple introduction, but are included to inspire you to learn more (not to scare you).

Precedence Operator type Associativity Individual operators
20 Grouping n/a ( … )
19 Member Access left-to-right … . …
Computed Member Access left-to-right … [ … ]
new (with argument list) n/a new … ( … )
Function Call left-to-right … ( )
18 new (without argument list) right-to-left new …
17 Postfix Increment n/a … ++
Postfix Decrement … --
16 Logical NOT right-to-left ! …
Bit-wise NOT ~ …
Unary Plus + …
Unary Negation - …
Prefix Increment ++ …
Prefix Decrement -- …
typeof typeof …
void void …
delete/ delete …
await await …
15 Exponentiation right-to-left … ** …
14 Multiplication left-to-right … * …
Division … / …
Remainder … % …
13 Addition left-to-right … + …
Subtraction … - …
12 Bit-wise Left Shift left-to-right … << …
Bit-wise Right Shift … >> …
Bit-wise Unsigned Right Shift … >>> …
11 Less Than left-to-right … < …
Less Than Or Equal … <= …
Greater Than … > …
Greater Than Or Equal … >= …
in … in …
instanceof … instanceof …
10 Equality left-to-right … == …
Inequality … != …
Strict Equality … === …
Strict Inequality … !== …
9 Bit-wise AND left-to-right … & …
8 Bit-wise XOR left-to-right … ^ …
7 Bit-wise OR left-to-right … | …
6 Logical AND left-to-right … && …
5 Logical OR left-to-right … || …
4 Conditional right-to-left … ? … : …
3 Assignment right-to-left … = …
… += …
… -= …
… **= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …
2 Arrow function with inline-body (not technically an operator) right-to-left … => …
yield yield …
yield* yield* …
1 Comma / Sequence left-to-right … , …

Recursion

Recursion is special way to to something over and over again. It is similar to iteration in that regard. The main difference is that iteration is a loop within a single routine that is executed over and over. Recursion is a function that calls itself until some criteria is met. A T-shirt sums it up nicely: "If you don't understand recursion, read again." Some problems are easier to solve with iteration and some are easier to solve with recursion. So recursion is another tool for your toolkit.

Consider a Koch line. Take a line of a given length. Divide that line into thirds. Where the middle third is, draw an equilateral triangle (a triangle with all three sides the same length and the corner angles are also all the same, 60 degrees). Erase the middle segment, leaving four segments each of the same length. Repeat the process for the remaining four segments and so on until the segment length is 2 pixels. The following code does just that.

function kochForward (length) { if (length <= 20) { forward (length); } else { kochForward (length/3); left(60); kochForward (length/3); right(120); kochForward (length/3); left(60); kochForward (length/3); } } setpos(minX() + 20, minY() + 20); // go toward bottom left of canvas angle(90); kochForward(maxX() + maxX() - 40); // draw a Koch line most of the width of the canvas

Hint: you can change the value in the conditional (the 20) to other values to show more or less detail. The Koch line is the basis for the Koch Snowflake that uses three Koch lines.

There are several more complex examples of recursion here. The Koch Snowflakes, the Sierpinski Curve and the Symmetrical Tree.

Animation

Animation is the process to bring a drawing to life. Animation presents drawings that are slightly different. The differences are perceived as motion. The two main ways to do animation is to either incrementally add to a drawing more and more complex parts or to completely redraw the figure. The drawing that is presented is called a frame The human eye will blend motion between two different frames that are presented quick enough. Movies are about 24 frames a second and television is 30 frames a second (or 1/30 of a second per frame also called .033 seconds or 33 milliseconds per frame). Making changes too quickly may be invisible to the human eye. Changes should be made consistently to avoid a jerky appearance.

This turtle graphics provide two functions for animation: animate() and delay() that are discussed more thoroughly below.

Animate

The animate() function is used to call the same function over and over at a fixed period of time. The Turtle Graphics analog clock is an example that uses the animate function to redraw the clock and its hands every second.

Delay

The delay() function is used to call a function once after a period of time. For an animation there can be a series of functions that are invoked in a time sequence to provide the animation.

The Dividing a Circle example uses the delay() function to draw a set of circles around a preceding set of circles. This is an example of building up a drawing of more and more complex parts.

The Koch Snowflake example uses the delay() function to draw successive drawings. This example shows the power of using both the delay function to draw a snowflake of a particular order and recursion to build the snowflake of a desired order.

Under the Hood

Source Code

More can be learned by looking at the JavaScript source code that implements the turtle graphic functions. While the functions are designed to hide the details of the mathematics (mostly trigonometry) that are necessary to plot a line of a given angle and length on a canvas that only understands the x and y coordinates of a Cartesian coordinate system.

The source code for this page can be found in several ways. (Browsers change all the time, so you may need to search around the menus to find the option.)

The following modules provide the basic functionality of the JavaScript Turtle Graphics.

The source code for all of the tools and the examples may also be viewed directly at https://www.github.com/kirkcarlson/js-turtle.