Working with HTML5 Canvas

Introduction

One of the reasons for the popularity of the web is the graphical user interface offered to the end users. Images, animations, fonts and other interactive effects make a website appealing from an end user's perspective. However, one limitation that website developers often encounter is drawing graphics in the browser. As a solution, developers often resort to Flash or Silverlight based plug-ins or generate graphics on the fly at server side and then send it to the client. HTML5 does a great job in client side graphic rendering by offering what is known as canvas. The actual drawing can be carried out using JavaScript code and certain new graphic objects. Understanding HTML5 canvas and associated JavaScript objects is important for any ASP.NET developer and this article teaches you just that.

What is HTML5 Canvas?

HTML5 canvas is very similar to a real life drawing canvas in that it allows you to draw shapes, text, backgrounds and many other drawing operations. Of course, HTML5 canvas is browser based and is measured in pixels. At HTML markup level, canvas is represented by the <canvas> tag. A basic usage of <canvas> tag is shown below:

<canvas id="myCanvas" width="500" height="500"></canvas>

The canvas tag, by itself, will not draw anything on the screen. You will need to use some JavaScript code to draw on the canvas. Note that although the above example sets the width and height properties in the markup itself, you can also set them via canvas DOM element or CSS.

Canvas can be of great use while rendering graphics on the client side dynamically. For example, consider that you are allowing the end user to design simple logos or charts dynamically. Users can play with the data (such as logo text, height and width or values to be plotted on the chart) and the result is immediately visible on the screen. You can then save the user inputs on the server side once the drawing process is complete.

Rendering Context Object

At the heart of drawing on the canvas is a rendering context object. Rendering context object is responsible for displaying shapes and text on the canvas. There can be more than one rendering context (say 2D context and 3D context). Your JavaScript code can get hold of the rendering context using the getContext() DOM method. The following piece of code shows how:

var myCanvas = document.getElementById('myCanvas');

var myContext = myCanvas.getContext("2d");

As you can see the getContext() method takes a type of context to use (2D in this case) as its parameter. Once a rendering context is available, your code can call various drawing methods on the context. The following table lists some of the common methods of rendering context object:

Method 

Description 

fillRect()

Draws a filled rectangle 

strokeRect() 

Draws a rectangular outline 

clearRect() 

Clears a rectangular region of the canvas 

lineTo() 

Draws a straight line 

arc() 

Draws an arc or circle

moveTo() 

Moves the current drawing point to a specified location 

beginPath() 

Initiates drawing a path 

closePath() 

Marks the end of the path drawing operation 

stroke() 

Perform actual drawing of a path in outline fashion 

fill() 

Perform actual drawing of a path in filled fashion 

fillText()

Draws a string of characters on the canvas

Drawing on Canvas

Now that you have some idea about HTML5 canvas and various drawing operations, let's develop a simple web page that makes use of many of the above drawing methods. 

Create a new web page in any text editor or HTML designer (such as Microsoft Expression Web) and add the <canvas> tag as shown previously. Then add the following <script> block in the head section of the page.

window.onload = function () {

   var myCanvas = document.getElementById('myCanvas');

   var context = myCanvas.getContext('2d');

   ...

}

To begin with, you will draw a rectangle with left and top coordinates equal to (10,10) and width and height of 200 and 100 pixels respectively. Remember that these coordinates are with respect to the canvas you defined earlier.

context.fillRect(10,10, 200, 100);

The fillRect() method takes x coordinate, y coordinate, width and height of the rectangle and draws a filled rectangle as shown below:

The fillRect() method draws a filled rectangle
Figure 1: The fillRect() method draws a filled rectangle

To draw a circle with radius 50 and center at coordinates 100 and 200 you will write the following piece of code:

 context.arc(100, 200, 50, 0, 2 * Math.PI, false);

context.fill();

The arc() method draws an arc as per the given specifications. The first two parameters indicate the coordinates of the center. The third parameter is the radius of the circle. The next two parameters (0 and 2* Math.PI) represent the start angle and end angle for the start and end points of the arc in radians as measured from the X axis. The last boolean parameter decides whether the arc will be drawn in anticlockwise direction (true) or clockwise direction (false).

Note that you must call fill() method to draw the arc (or stroke() method if you wish just the outline rather than filled arc). The following figure shows the circle drawn as a result of the preceding code:

The circle drawn as a result of the preceding code
Figure 2: The circle drawn as a result of the preceding code

To draw a line at coordinates 125,125 you will write:

context.moveTo(125,125);

context.lineTo(125,45);

context.stroke();

Note that the coordinates of the start point of the line are governed by the "current" position on the canvas. In the above code the moveTo() method marks the current drawing position to 125,125. The lineTo() method accepts the coordinates of the end point of the line. Thus the start point of the line is at 125,125 and end point at 125, 45. The stroke() method performs the actual drawing operation.

The stroke() method performs the actual drawing operation.
Figure 3: The stroke() method performs the actual drawing operation.

Now let's draw a triangle using a path operation.

context.beginPath();

context.moveTo(125,350);

context.lineTo(100,600);

context.lineTo(45,450);

context.closePath();

context.stroke();

The beginPath() method initializes drawing of the path. The first call to moveTo() method shifts the current drawing position to 125,350. The two calls to lineTo() method then draw two sides of the triangle. The closePath() method completes the triangle by completing the path.

The closePath() method completes the triangle by completing the path
Figure 4: The closePath() method completes the triangle by completing the path

Finally, let's draw some text on the canvas.

context.font = '20pt Arial';

context.fillText('Drawing text on the Canvas', 0, 100);

The fillText() method does the job of outputting specified string at a specific location (0,100). Notice that the font and font size of the text can be controlled by setting the font property.

Draw some text on the canvas
Figure 5: Draw some text on the canvas

In the above example, you used the default rendering properties for the shapes. You can customize the look and feel of the shapes with the help of various properties. Have a look at the following fragment of code:

context.fillStyle = 'blue';

context.strokeStyle = 'blue';

context.lineWidth = 10;

context.shadowOffsetX = 5;

context.shadowOffsetY = 5;

context.shadowBlur = 10;

context.shadowColor = 'black';

context.font = '20pt Arial';

...

The above code sets the drawing color to blue using fillStyle and strokeStyle properties. The lineWidth property governs the width of the line used to draw shapes. The shadowOffsetX, shaddowOffsetY, shadowBlur and shadowColor properties decide the respective behavior of shadow. The following figure shows some of the above shapes after applying the styling properties.

Applying the styling properties
Figure 6: Applying the styling properties

Drawing Charts Using Canvas

Now let's develop a more realistic example by plotting a pie chart on the canvas. The pie chart will be drawn with some default values initially when the page loads but you can get the values from the server via a web service or WCF service. Begin by creating a new website in Visual Studio 2010. Add a new web form and enter the following HTML markup into it (the following markup has been trimmed to save some space. You can get the complete markup from the code download.).

<!DOCTYPE html>

<html lang="en">

<head>

...

<script src="Scripts/jquery-1.4.4.js" type="text/javascript"></script>

...

<div>

<input type="button" value="Get Chart Data" id="Button1" />

...

<canvas id="myCanvas" width="400" height="500"></canvas>

...

<script type="text/javascript">

    var chartColors = ['red', 'green', 'blue', 'yellow', 'orange'];

    var chartData = [10, 20, 30, 40, 50];

    var chartLabels = ['Part 1', 'Part 2', 'Part 3', 'Part 4', 'Part 5'];

 

    function GetTotal() {

        var total = 0;

        for (var j = 0; j < chartData.length; j++) {

            total += chartData[j];

        }

        return total;

    }

 

    function DrawChart() {

        var canvas;

        var context;

        var angle = 0;

        var total = GetTotal();

 

        canvas = document.getElementById("myCanvas");

        context = canvas.getContext("2d");

        context.clearRect(0, 0, canvas.width, canvas.height);

 

        for (var i = 0; i < chartData.length; i++) {

            context.fillStyle = chartColors[i];

            context.beginPath();

            context.moveTo(200, 150);

            context.arc(200, 150, 150, angle, angle + (Math.PI * 2 * (chartData[i] / total)), false);

            context.lineTo(200, 150);

            context.fill();

            angle += Math.PI * 2 * (chartData[i] / total);

        }

 

        var offset = 350;

        for (var i = 0; i < chartColors.length; i++) {

            context.fillStyle = chartColors[i];

            context.font = '10pt Arial';

            context.fillRect(10, offset, 20, 20);

            context.fillText(chartLabels[i] + ' - ' + chartData[i], 40, offset + 15);

            offset += 30;

        }

    }

 

    DrawChart();

</script>

...

The above markup defines a canvas of size 400 X 500. It also has a button at the top that you will put to use later. The JavaScript code defines three global arrays viz. chartColors, chartData and chartLabels. As the names suggest they store colors of individual sectors of the chart, data with which the pie chart is to be plotted and labels explaining sector colors. In the above example you are using 5 values but you can easily increase or decrease them by adding or removing values from these three arrays.

The GetTotal() function simply sums up the data values from the chartData array. The total is later used in the DrawChart() function.

The DrawChart() function iterates through the chartData array and draws individual arcs with the help of arc() function. Notice the use of beginPath(), moveTo(), lineTo() and fill() methods we discussed earlier. Another for loop iterates through chartColors array and draws legends for various sectors of the chart. The following figure shows a sample run of the web form.

The DrawChart() function
Figure 7: The DrawChart() function

So far, you are using fixed set of values to plot the chart. Let's change our code so that it fetches the values by invoking a web method instead. The web method that returns the chart data as an array of integers looks like this:

<script runat="server">

    [WebMethod]

    public static int[] GetChartData()

    {

        Random r = new Random();

        int[] data = new int[5];

        for (int i = 0; i < 5; i++)

        {

            data[i] = r.Next(10, 100);

        }

        return data;

    }

</script>

The GetChartData() web method fills an integer array with random integers between 10 and 100. Of course, in a more real world scenario you will pick the values from a database. 

You will invoke the web method using jQuery so ensure that you have added jQuery library to your website.

<script src="Scripts/jquery-1.4.4.js" type="text/javascript"></script>

Then wire the click event handler for the "Get Chart Data" button as shown below:

$(document).ready(function () {

    $("#Button1").click(OnGetData);

})

The OnGetData() function calls the GetChartData() web method as shown below:

function OnGetData(event) {

    var url = "default.aspx/GetChartData";

    successHandler = function (results) {

        chartData = results.d;

        DrawChart();

    }

    $.ajax({

        type: "POST",

        url: url,

        contentType: "application/json; charset=utf-8",

        dataType: "json",

        success: successHandler,

        error: function (err) {

            alert(err.status + " - " + err.statusText);

        }

    })

}

The OnGetData() function makes use of $.ajax() function to call the web method. Notice how URL to the web method is specified as <web form>/<web method name>. Once the web method returns, the code as specified by successHandler will be invoked. The successHandler code simply assigns the array returned by the web method to chartData global variable. The chart is then redrawn by calling the DrawChart() method. (NOTE: Detailed explanation of calling web methods using jQuery is beyond the scope of this article.)

Run the web form and try clicking on the button a few times. Every time the chart is re-drawn with new random values returned by the web method. 

Summary

Canvas and drawing features of HTML5 make it easy for developers to draw shapes and text via client side JavaScript code. The <canvas> tag defines an HTML5 canvas. Drawing operations can then be performed on the canvas using various rendering context methods. This article gave you a peek inside these drawing features. You also learned to draw a pie chart that fetches its values from a web method.



About the Author

Bipin Joshi

Bipin Joshi is a blogger and writes about apparently unrelated topics - Yoga & technology! A former Software Consultant by profession, Bipin has been programming since 1995 and has been working with the .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. He was a well known technology author, trainer and an active member of Microsoft developer community before he decided to take a backseat from the mainstream IT circle and dedicate himself completely to spiritual path. Having embraced Yoga way of life he now codes for fun and writes on his blogs. He can also be reached there.

Related Articles

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • Live Event Date: September 16, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you starting an on-premise-to-cloud data migration project? Have you thought about how much space you might need for your online platform or how to handle data that might be related to users who no longer exist? If these questions or any other concerns have been plaguing you about your migration project, check out this eSeminar. Join our speakers Betsy Bilhorn, VP, Product Management at Scribe, Mike Virnig, PowerSucess Manager and Michele …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds