Turtle graphics library in Blazor using the HTML canvas tag

Pier-Luc Bonneville
Pier-Luc Bonneville
Being technical is important at the leadership level in a world where IT is eating the world.
Dec 6, 2020 4 min read
thumbnail for this post
Photo by Me

Introduction

The Turtle graphics libraries, first introduced in the Logo programming language are useful tools to teach programming principals to children and novice programmers. With it, you can explore these four concepts:

  1. Loops for, foreach, do/while, while
  2. Conditions if/else
  3. Functions/Methods
  4. Recursion

Getting Started - Creating a Blazor Turtle Graphics App

Create a new Blazor application.

Install the TurtleGraphics.BlazorCanvas NuGet package NuGet version (TurtleGraphics.BlazorCanvas).

In your index.html file (WebAssembly Apps) or _Host.cshtml (Server Apps) file, place a reference to the Blazor.Extensions.Canvas library script file:

<script src="_content/Blazor.Extensions.Canvas/blazor.extensions.canvas.js"></script>

Then, in your _Imports.razor file add the following using entry:

@using TurtleGraphics.BlazorCanvas

Lastly, we’ll register the TurtleJsInterop as a service in Program.cs.

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("#app");

        builder.Services.AddScoped(
            sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

        builder.Services.AddScoped<TurtleJsInterop>();

        await builder.Build().RunAsync();
    }
}

In the component/page where you want to place the canvas element, add a <Turtle> component. Make sure to set the @ref to a field on your component.

For example, in your Index.razor page,

@page "/"

<Turtle @ref="_turtle" Width="600" Height="400" />

@code {
	private Turtle _turtle;
}

Here is a demo running as a Blazor WebAssembly application

Here is the code from these few examples:

  1. Triangle

    private async Task Triangle()
    {
        _turtle.PenSize = 1;
        await _turtle.Rotate(30);
        _turtle.PenColor = Color.Black;
        _turtle.Delay = 150;
    
        DrawTriangle(100);
    }
    
    private async Task DrawTriangle(int length)
    {
        for (int i = 0; i < 3; i++)
        {
            await _turtle.Forward(length);
            await _turtle.Rotate(120);
        }
    }
    
  2. Green star

    private async Task GreenStar()
    {
        _turtle.Delay = 200;
        _turtle.PenColor = Color.Green;
        for (int i = 0; i < 5; i++)
        {
            await _turtle.Forward(100);
            await _turtle.Rotate(144);
        }
    }
    
  3. Spiral

    private async Task Spiral()
    {
        _turtle.Delay = 100;
        _turtle.PenColor = Color.DarkGreen;
        for (int i = 0; i < 20; i++)
        {
            await _turtle.Forward(i * 5);
            await _turtle.Rotate(60);
        }
    }
    
  4. Color wheel

    private async Task ColorWheel()
    {
        _turtle.PenSize = 4;
        _turtle.Delay = 10;
    
        var rand = new Random();
    
        for (int i = 0; i < 36; i++)
        {
            // System.Drawing.KnownColor: only use range from `28` to `167`
            _turtle.PenColor = Color.FromKnownColor((KnownColor)rand.Next(28, 167));
    
            _turtle.PenUp();
            await _turtle.Forward(65);
            _turtle.PenDown();
    
            await _turtle.Forward(65);
            await _turtle.Backward(65);
    
            await _turtle.Rotate(170);
        }
    }
    
  5. Sierpiński triangle (a Triforce)

    private async Task DrawTriforce()
    {
        //  ▲
        // ▲ ▲
        int length = 100;
        await _turtle.Rotate(30);
        _turtle.PenColor = Color.Gold;
        _turtle.Delay = 150;
    
        await DrawTriangle(length / 2);
        await _turtle.Forward(length / 2);
        await DrawTriangle(length / 2);
        await _turtle.Rotate(120); await _turtle.Forward(length / 2); await _turtle.Rotate(-120);
        await DrawTriangle(length / 2);
        await _turtle.Rotate(-120); await _turtle.Forward(length / 2); await _turtle.Rotate(120);
    }
    
  6. Circle

    private async Task DrawCircle()
    {
        _turtle.PenColor = Color.DarkViolet;
        _turtle.Delay = 10;
    
        for (int i = 0; i < 36; i++)
        {
            await _turtle.Forward(10);
            await _turtle.Rotate(10);
        }
    }
    

TurtleGraphics.BlazorCanvas - Developer’s Reference

  • Forward(distance) - moves the turtle forward in the current direction by the specified distance. If the pen is down, the turtle draws a line from the current to the new position, otherwise it just moves without leaving a track.
  • Backward(distance) - moves the turtle in backward direction and draws a line if the pen is down.
  • MoveTo(x, y) - moves the turtle to the specified position and draws a line if the pen is down.
  • Rotate(angle) - rotates the turtle relatively to the current direction. The rotation angle is given in degrees (e.g. 45, -30, 315, …).
  • RotateTo(angle) - rotates the turtle to the specified angle in degrees (e.g. 0, 45, 180, 315, …).
  • PenUp() - moves the pen up (makes further moves invisible). Further calls to Forward(distance) / Backward(distance) / MoveTo(x, y) will move the turtle without drawing a line.
  • PenDown() - moves the pen down (makes further moves visible). Further calls to Forward(distance) / Backward(distance) / MoveTo(x, y) will draw a line from the current to the new position.
  • X - gets / sets the current turtle horizontal position. The initial turtle position is the screen center {0, 0}. Increasing X will move the turtle right.
  • Y - gets / sets the current turtle vertical position. The initial turtle position is the screen center {0, 0}. Increasing Y will move the turtle up.
  • Angle - gets / sets the current turtle direction (angle in degrees). The value of 0 means up, 90 means right, 180 means down and 270 means left. The Angle is always kept in the range (0…360). Initially the angle is 0.
  • PenColor - gets / sets the color of the pen. The default pen color is “blue”.
  • PenSize - gets / sets the size of the pen (in pixels). The default pen size is 7.
  • PenVisible - gets / sets the visibility of the pen. The default pen size is true. True means the pen is down (draws a line when the turtle moves). False means the pen is up (no line is drawn when the turtle moves).
  • ShowTurtle - gets / sets whether the turtle is visible. By default it is visible.
  • Delay - gets / sets the turtle delay in milliseconds after moving / rotating. By default the delay is 0 (no delay). Setting the delay to 100-300 will simulate a pleasant “animation effect”. Delay is preserved after Reset().