Turtle Graphics

INTRODUCTION

Overview

Turtle Graphics is a Javascript implementation of the popular geometric drawing tools introduced in Logo, developed by Wally Feurzeig, Seymour Papert and Cynthia Solomon in 1967.

Imagine a robotic turtle starting at (0, 0) in the x-y plane. After creating a turtle, give it the command turtle.forward(15), and it moves (on-screen!) 15 pixels in the direction it is facing, drawing a line as it moves. Give it the command turtle.right(25), and it rotates in-place 25 degrees clockwise.

In this library, turtle graphics provides a representation of a physical “turtle” (a little robot with a pen) that draws on a sheet of paper on the floor.

Turtle drawing was originally created as an educational tool, to be used by teachers in the classroom. For the programmer who needs to produce some graphical output it can be a way to do that without the overhead of introducing more complex or external libraries into their work.

NOTE: This library is written entirely in Javascript and is not dependant on any other library. All examples use p5js as a simple application framework to demonstrate this library but users are free to choose an alternative if they wish.

INTRODUCTION

Creating our First Turtle

The first step is to create a turtle with the statement

let turtle = TG.getTurtle(400, 200);

The 2 parameters define the width and height of the graphics area the turtle can draw in. Although the turtle is not confined to this area anything drawn outside it will not be visible.

Once the turtle has been created we can command the turtle to move, turn, draw lines by adding tasks in the order that we want them to be performed. For instance the statement -

turtle.forward(20).right(25).forward(55).start();

will move the turtle 20 pixels in the direction it is facing, turn right 25° to the right, move forward 55 pixels all the time, drawing a line using the current pen color. The last task start() instructs the turtle to start performing the tasks in the specified order. If it is included in the list of tasks turtle animation starts immediately. Alternatively we can add the tasks then start the turtle at some later time.

There is no limit to the number of tasks that can be added to the turtle and the library includes over 40 unique tasks to choose from. They are all described in the Tasks section of this guide.

TASKS

Move and Draw

turtle.x(x, fill_gap = false)
turtle.y(y, fill_gap = false)
turtle.xy(x, y, fill_gap = false)

Move the turtle to an absolute position without drawing a line and without changing the turtle's heading. If currently filling, any existing fill shape will be filled before moving and a new fill shape will be started after moving.

This can be disabled with fill_gap = true, which makes the imaginary line traveled during movement part of the current fill shape.

The change of position is applied without any animation.

turtle.dxy(d_x, d_y, fill_gap = false)

Move the turtle to a position relative to the current poition without drawing a line and without changing the turtle's heading. If currently filling, any existing fill shape will be filled before moving and a new fill shape will be started after moving.

This can be disabled with fill_gap = true, which makes the imaginary line traveled during movement part of the current fill shape.

The change of position is applied without any animation.

turtle.face(angle)

Change the turtle's forward direction so it faces the specified angle.

The change of angle is applied without any animation.

turtle.forward(distance)
turtle.fd(distance)

Move the turtle in the direction it is headed by the distance pixels.

turtle.backward(distance)
turtle.back(distance)
turtle.bk(distance)

Move the turtle opposite to the direction it is headed by distance pixels. The turtle's heading is unchanged.

turtle.left(ang)
turtle.lt(ang)

Turn left by the specified angle. The default rotational unit is degrees (°) but chan be changed to radians.

Turn right by the specified angle. The default rotational unit is degrees (°) but chan be changed to radians.

turtle.heading(angle)
turtle.head(angle)

Change the turtle's heading to this angle. The default rotational unit is degrees (°) but be changed to radians.

turtle.home()

Move the turtle to its home position [0, 0].

turtle.goto(x, y)

Move turtle to an absolute position. If the pen is down then a line is drawn. The the turtle's heading will be changed to match the direction moved.

turtle.goby(dx, dy)

Move turtle to a position relative to the current postion. If the pen is down then a line is drawn. The the turtle's heading will be changed to match the direction moved.

turtle.dot(size = 6, fill_color = 'current', bdr_weight = 0, bdr_color = 'current')

Draw a circular dot with specified radius.

turtle.arrow(size = 6, fill_color = 'current', bdr_weight = 0, bdr_color = 'current')

Draw an arrow head (triangle) so its tip is at the current pen position and it is facing the current heading.

turtle.circle(rad_b, extent = 0, turnDir = RT, steps = 0)
turtle.oval(rad_a, rad_b, extent = 0, turnDir = RT, steps = 0)

Follow a circular or oval path. The path can be smooth or created from a number of straight lines, (chords)

folllowing an oval path
Following an oval arc path

The turtle paths shown in the picture above were created with the following code -

turtle.rt(25).fd(55).arrow(6)
  .oval(25, 15, 150, RT, 0).arrow(6)
  .fd(130).arrow(6)

The curve drawn depends on the turtle's mode as shown in the image. The default mode is 'display'

turtle.sleep(duration)

Pause the turtle animation for duration milliseconds.

turtle.write(text, align = 'left', move = false, font : optional)

Draw the string representation of text at the current turtle position. This image shows the affect of the parameter values passed to the task.

shows text alignment options
Shows text alignment options.

In the diagram the blue arrows indicate the position and heading of the turtle just before the text is drawn. The text baseline (dashed line) is perpendicular to the tutle's heading. The text can be aligned "left", "center" or "right" to this position. Once the text is drawn the move parameter determines whether the turtle is moved along the baseline to the end of the text.

No matter which options are chosen the turtle's heading is unchanged and is shown by the red dashed line.

If no font descriptor is provided (font) then the default font is used.

turtle.font(style)

Set the default font style for this turtle. This style will be used in future write tasks until changed.

TASKS

Pen Control

turtle.penup()
turtle.pu()
turtle.up()

Lift the pen up so there is no drawing when moving.

turtle.pendown()
turtle.pd()
turtle.down()

Put the pen down so there is drawing when moving.

turtle.pensize(width = 2)

Changes the line-width used when drawing.

turtle.dash(pattern[line_len, gap_size ...] : optional)

The parameter is an array of numbers representing the dash pattern to be used. The numbers are in pairs where the first is the line-length and the second the gap size, addition number pairs can be included to create more complex patterns.

shows line dash examples
Line dash examples.

If pattern is an empty array or is not provided then all subsequent lines will be solid until a new dash pattern is specified.

turtle.pencap(cap)
turtle.cap(cap)

Changes the line-cap used at the end of a line. Valid options are BUTT, SQUARE or ROUND. The default value is ROUND.

shows line caps options
Shows the 3 line-cap options.

turtle.pencolor(color)

Changes the color used to draw lines.

turtle.fillcolor(color)

Changes the color used to fill shapes created by the turtle.

turtle.push_pen()

Push (save) the current pen's position and style on the stack. This includes the following information :-

Pen position:-

Pen style:-

turtle.pop_pen(what = STYLE_POS)

Restore the pen status saved by the last push_pen() statement. The parameter, what, determines which attributes are restored -

TASKS

Turtle Control

turtle.turtle(cursor)

This default cursor is called DART but the library has several predefined cursors to choose from they are :-

library cursors
Predefined library cursors.

To change the turtle cursor to a star then use turtle.turtle(STAR).

As well as the library cursors, this task will also accept user defined cursors.

turtle.showturtle()
turtle.st()

Show the turtle cursor.

turtle.hideturtle()
turtle.ht()

Hide the turtle cursor.

turtle.tilt(angle : optional)

If angle is not provided then the turtle cursor is rotated to match the current forward direction and the current tilt angle is ignored. If a value is provided then it is used to rotate the cursor irrespective of the turtle's heading.

turtle.speed(linear, angular)

This task can be used to change either or both the

If either parameter value is NaN then the current value is unchanged. The default rotational unit is degrees (°) but can be changed to radians.

TASKS

Filling and Tracking

turtle.begin_fill()

Start remembering vertices for a shape that is to be filled later.

turtle.end_fill(close = false)

Fill the shape drawn after the last call to begin_fill() with the current fill-color. If close is true then a line is drawn to the start of the fill, closing ths shape.

Whether or not overlap regions for self-intersecting polygons or multiple shapes are filled depends on the operating system graphics, type of overlap, and number of overlaps.

turtle.begin_poly()

Start recording the vertices of a polygon. Current turtle position is first vertex of polygon.

turtle.end_poly(id)

Stop recording the vertices of a polygon keeping the current turtle position as the last vertex. A unique identifier (id) must be provided so the polygon vertices can be retrieved later with -

turtle.getPoly(id);

The polygon returned is an array of [x,y] tuples.

turtle.begin_record()

Start recording the tasks assigned to this turtle.

turtle.end_record(id)

Stop recording the tasks assigned to this turtle. A unique identifier (id) must be provided so the task-list can be executed by this, or any other turtle using the do task like this -

turtle.do(id);
any_other_turtle.do(id)

turtle.do(...action)

The parameter action comprises one or more comma seperated values. The first value is either

TASKS

Graphics Control

turtle.animateon()
turtle.animateoff()

If animation is switched off then all tasks will be completed as fast as possible ignoring the current speed values. Switching it back on re-enables the turtle animation.

turtle.clear()

This will erase all graphics created by this turtle leaving a blank canvas. The turtle's position, heading and other attributes are unchanged.

turtle.reset()

As well as erasing the current canvas; the turtle's position, heading and all other attributes are returned to their initial values.

turtle.snapshot(id)

Store a copy of the current turtle-graphics image. A unique identifier (id) must be provided so the snapshot can be retrieved later with - turtle.getSnapshot(id);

CORE SETTINGS

Animation Control

turtle.start()

This will cause the turtle to immediately start processing any queued tasks. If there are no tasks to process then the turtle will wait and process new tasks as and when they are added to the task queue.

turtle.stop()

This will stop the turtle processing any queued tasks. To restart processing the start method should be executed manually with -

turtle.start();

CORE SETTINGS

Graphic Modes

This library supports 3 modes each having its own coordinate system they are DISPLAY, STANDARD and LOGO. The turtle's mode is specified by adding one of these options as a third parameter when creating the turtle e.g.

let turtle = TG.getTurtle(200, 200, STANDARD);

The standard and logo modes are included for compatability with earlier turtle graphic libraries. If the mode is not specified then the turtle uses the DISPLAY option.

image showing 3 graphic modes available
Coordinate system and rotation directions
Mode X axis direction Y axis direction 0° direction increasing angle
display East South East Clockwise
standard East North East Counterclockwise
logo East North North Clockwise

Movement and rotation depends on the mode coordinate system for that turtle, Turning left or right is not dependant on the forward direction, instead right turns increase the heading angle and left turns decrease the heading angle.

turtle.degrees()

Set angle measurement units to degrees. This applies to all angles expected by and returned from the turtle functions. It is the default unit for new turtles.

turtle.radians()

Set angle measurement units to radians. This applies to all angles expected by and returned from the turtle functions.

turtle.getModeXY(x, y, cx = 0, cy = 0)

Convert the screen coordinates x and y to the equivalent position in mode space. The parameters cx and cy represent the screen position for the center of the turtle graphics. The turtle position is unchanged.

The mode coordinates are returned as a tuple [mx, my].

turtle.getModeH(screenH)

Given a screen heading (screenA) get the equivalent mode heading. The turtle heading is unchanged.

turtle.getScreenXY(cx = 0, cy = 0)

Convert the current pen coordinates to the equivalent position on the screen. The parameters cx and cy represent the screen position for the center of the turtle graphics.

The screen coordinates are returned as a tuple [sx, sy].

turtle.getScreenH()

Get the current pen heading after converting to the equivalent screen angle.

TURTLE ATTRIBUTES

About

Unlike tasks which are queued and then performed in sequence later, these functions are used to set the turtles's attributes with immediate effect; although most have a matching task which can be used instead.

These methods support the creation of user defined tasks based on the current state of the turtle. Assume we want a task that doubles the pensize and halves its speed, there is no task that does this but it is possible to solve this problem. In this example we create a task called foo_task that does just that.

function foo_task(turtle, data){
    let psize = turtle.getPensize();
    let speed = turtle.getSpeed();
    turtle.setPensize(psize * 2);
    turtle.setSpeed(speed[0] / 2, speed[1] / 2);
}

turtle.do(foo_task, 25); // perform our user defined task

TURTLE ATTRIBUTES

Position and Heading

turtle.getX()

Return the turtle's x position.

turtle.setX(x)

Sets the turtle's x position.

turtle.getY()

Return the turtle's y position.

turtle.setY(y)

Sets both the turtle's y position.

turtle.getXY()

Return the turtle's position as a tupple:- [x, y].

turtle.setXY(x, y)

Sets both the turtle's x and y position.

turtle.getHeading()
turtle.getH()

Return the turtle's heading.

turtle.setHeading(angle)
turtle.setH(angle)

Set the turtle's heading to this angle. The default rotational unit is degrees (°) but be changed to radians.

TURTLE ATTRIBUTES

Pen Control

turtle.getPenSize()

Return the turtle's pen size.

turtle.setPenSize(size)

Sets the turtle's pen size.

turtle.getPenColor()

Return the color used for drawing lines.

turtle.setPenColor(color)

Sets the color used to draw lines.

turtle.getDash()

Return the current dash pattern as an array. (see setDash below for details)

turtle.setDash(pattern[line_len, gap_size ...] : optional)

The parameter is an array of numbers representing the dash pattern to be used. The numbers are in pairs where the first is the line-length and the second the gap size, addition number pairs can be included to create more complex patterns.

shows line dash examples
Line dash examples.

If pattern is an empty array or is not provided then all subsequent lines will be solid until a new dash pattern is specified.

turtle.getCap()

Return the current line-end style.

turtle.setCap(style)

Sets the line-cap used at the end of a line. Valid options are BUTT, SQUARE or ROUND.

shows line caps options
Shows the 3 line-cap options.

turtle.getFillColor()

Return the color used for filling shapes.

turtle.setFillColor(color)

Sets the color used to fill shapes.

TURTLE ATTRIBUTES

Turtle Control

turtle.getSpeed()

Return the turtle's position as a tupple:- [x, y].

turtle.setSpeed(linear, angular)

Sets either or both the

If either parameter value is NaN then the current value is unchanged. The default rotational unit is degrees (°) but chan be changed to radians.

turtle.setTurtle()
turtle.setCursor()

Change the turtle's cursor. The parameter cursor can be a library or user defined cursor.

library cursors
Predefined library cursors.

TURTLE ATTRIBUTES

Graphics Control

turtle.getPoly(id)

Get the vertices for a recorded polygon with the specified id. The points will be transformed to DISPLAY mode coordinates irrespective of the turtle's mode so they correspond to the vertex positions as displayed on the computer screen.

The vertices are are stored in an array of tuples:-
[ [x0, y0], [x1, y1], [x2, y2], ...   ]

If this turtle has no polygon named id then this function returns undefined

turtle.getSnapshot(id)

Get the saved image with the specified id. The returned image will be of type OffscreenCanvas.

If this turtle has no image named id then this function returns undefined

turtle.getImageFromOsc(osc, p)

A p5js helper function to convert a OffscreenCanvas (osc) image to a Processing image. The second parameter, p, is a reference to the Processing sketch.

The returned image will be of type p5.Image

TURTLE ATTRIBUTES

Cursors

Modified library cursors

library cursors
Predefined library cursors.

It is possible to create new cursors based on these shapes but with user defined size and colors.

// modified TURTLE shape
cursor = csrTURTLE(size, skin_col, shell_col, sw, scol);

// all other shapes (replace ??? by library cursor name e.g. ARROW)
cursor = csr???(size, fcol, sw, scol);

Where -

To change the turtle cursor to a white star with a strong red border use -

cursor = csrSTAR(30, 'white', 2, 'red');
turtle.turtle(cursor);

From JS OffsceenCanvas

A cursor can be created from any predefined image (of type OffscreenCanvas) using the function

cursor = new Cursor(osc, fx, fy);

Where -

The values fx and fy are in the range 0.0 to 1.0 and if multiplied by the image width and height respectively gives the pixel position of the hit spot.

From p5js image

A p5js helper function to create a cursor from any predefined image (of type p5.Image).

cursor = getCursorFromImage(p5image, fx, fy);

Where -

The values fx and fy are in the range 0.0 to 1.0 and if multiplied by the image width and height respectively gives the pixel position of the hit spot.

TURTLE ATTRIBUTES

Fonts

Font descriptors

The font descriptor is a string variable which contains either 3 or 4 font attributes. The format is

"WEIGHT STYLE SIZE FAMILY_NAME"

WEIGHT - any value in the range 1 and 1000 inclusive is valid but it is usually a multiple of 100. Normal weight is 400 and bold 700.

STYLE - If not included in the descriptor then plain text is used. Valid values include 'italic' and ' oblique' both have the effect of making the text lean to the right.

SIZE - This is the font size, examples include 12px 40em ...

FAMILY_NAME - There are two types of font family names:

Font descriptor examples include:

For more information about CSS fonts clck here.

TURTLE ATTRIBUTES

Colors

Color descriptors

In this library there are several tasks that expect color-values to be passed as string parameters. Based on CSS guidelines these strings can be named-colors, color-functions or hex-coded.

Named colors:

CSS defines a large set of named colors, so that common colors can be written and read more easily. Apart from the expected 'white', 'black', 'yellow' there are over 160 named colors which you can see here. There is also a named color 'transparent'.

Color functions (modern syntax):

The functions for three common color spaces are described here -

Parameters Valid ranges (inclusive)
r   g   b 0 -> 255    or    0% -> 100%
h 0 -> 360
s   l   w   b 0 -> 100    or    0% -> 100%
a 0.0 -> 1.0    or    0% -> 100%

Note that the parameters are separated by whitespace and the optional alpha term is separated by a solidus ("/").

Valid examples of color descriptors include 'rgb(90% 95% 10%)', 'hsl(330 50 90 / 0.5)', 'hwb(270 20 35 / 30%)'

RGB hexadecimal coded:

A color value is created by specifying each channel as a hexadecimal number in the range 00 to FF (0 to 255 in decimal) then concatenating them into a string preceeded with a hash (#) i.e. '#RRGGBB'. To include the channel its hexadecimal value must alse be concatenateed i.e. '#RRGGBBAA'

A full description of RGB hexadecimal code values can be found here.

TURTLE ATTRIBUTES

Properties (getters)

turtle.mode

Returns the mode type  -  DISPLAY, STANDARD, LOGO.

turtle.mode$

Returns the mode type as a string  -  "DISPLAY", "STANDARD", "LOGO".

turtle.hasTasks

Returns true if the turtle still has tasks to complete.

turtle.nbrTasks

Returns the number of tasks still to complete.

turtle.isActive

Returns true if the turtle is still being updated.

turtle.isAnimating

Returns true if animation is turned on.

turtle.isVisible

Returns true if the turtle cursor is visible.

turtle.isPenDown

Returns true if the pen is down and drawing lines.

turtle.nbrStyles

Returns the number of styles remaining on the stack.

MISCCELLANEOUS

Methods

turtle.doClear()

This will erase all graphics created by this turtle leaving a blank canvas. The turtle's position, heading and other attributes are unchanged.

turtle.doReset()

As well as erasing the current canvas; the turtle's position, heading and all other attributes are returned to their initial values.

turtle.setUpdateInterval()

The turtle's state is updated every 25 milliseconds (default value). In most cases this is perfectly adequate but if the application has a lot of turtles it may improve performance if the interval is increased.

The animation speed is independant of the update interval but my appear jerky at high intervals.

turtle.spawn()

Returns a duplicate of this turtle.