First steps with Canvas and HTML5


I've been postponing experimenting with HTML5 for quite a while, so today I finally set aside a few hours to play with it. This is a very simple example of the graphic effects you can create using JavaScript and the HTML5 canvas element.

Note that the examples below will work only on HTML5-compatible browsers, such as the latest versions of Chrome or Firefox.

1. Setting up a canvas and drawing some lines on it

This is easily done using the moveTo and lineTo functions. Let's create a simple symmetrical geometrical shape.

Your browser does not support the canvas element.

var c=document.getElementById("myCanvas1"); var cxt=c.getContext("2d"); var i=0;

for (i=1;i<=5;i++) { cxt.moveTo(0, 400); cxt.lineTo(100, i \* 40); cxt.lineTo(300, i \* 60); cxt.lineTo(400, i \* 30); cxt.lineTo(500, i \* 60); cxt.lineTo(700, i \* 40); cxt.lineTo(800, 400); }

cxt.stroke();

Here's the source code:

<!DOCTYPE HTML>
<html\>
<body\>

<canvas id\="myCanvas1" width\="800" height\="400" style\="border:1px dashed #c3c3c3;"\>
Your browser does not support the canvas element.
</canvas\>

<script type="text/javascript"\>

var c\=document.getElementById("myCanvas1");
var cxt\=c.getContext("2d");
var i\=0;

for (i\=1;i<=5;i++)
{
cxt.moveTo(0, 400);
cxt.lineTo(100, i \* 40);
cxt.lineTo(300, i \* 60);
cxt.lineTo(400, i \* 30);
cxt.lineTo(500, i \* 60);
cxt.lineTo(700, i \* 40);
cxt.lineTo(800, 400);
}

cxt.stroke();

</script\>

</body\>
</html\>

2. Creating a mirroring effect

Now we can increase the size of the canvas to 800 and replicate these lines at the bottom of the canvas to achieve a 'mirroring' effect. Since we know the maximum Y value of the canvas (800), let's just add another loop that draws the same lines but inverts the Y position. This is easily achieved by subtracting the constant-dependent parameter from the maximum value of Y.

var c=document.getElementById("myCanvas2"); var cxt=c.getContext("2d"); var i=0;

for (i=1;i<=5;i++) { cxt.moveTo(0, 400); cxt.lineTo(100, i \* 40); cxt.lineTo(300, i \* 60); cxt.lineTo(400, i \* 30); cxt.lineTo(500, i \* 60); cxt.lineTo(700, i \* 40); cxt.lineTo(800, 400); }

for (i=5;i>=1;i--) { cxt.moveTo(0, 400); cxt.lineTo(100, 800 - (i \* 40)); cxt.lineTo(300, 800 - (i \* 60)); cxt.lineTo(400, 800 - (i \* 30)); cxt.lineTo(500, 800 - (i \* 60)); cxt.lineTo(700, 800 - (i \* 40)); cxt.lineTo(800, 400); }

cxt.stroke();

This is how the new source code looks like:

var c\=document.getElementById("myCanvas2");
var cxt\=c.getContext("2d");
var i\=0;

for (i\=1;i<=5;i++)
{
cxt.moveTo(0, 400);
cxt.lineTo(100, i \* 40);
cxt.lineTo(300, i \* 60);
cxt.lineTo(400, i \* 30);
cxt.lineTo(500, i \* 60);
cxt.lineTo(700, i \* 40);
cxt.lineTo(800, 400);
}

for (i\=5;i\>=1;i\--)
{
cxt.moveTo(0, 400);
cxt.lineTo(100, 800 \- (i \* 40));
cxt.lineTo(300, 800 \- (i \* 60));
cxt.lineTo(400, 800 \- (i \* 30));
cxt.lineTo(500, 800 \- (i \* 60));
cxt.lineTo(700, 800 \- (i \* 40));
cxt.lineTo(800, 400);
}

cxt.stroke();

3. Adding more graphical interest

Finally, let's parameterize the construction of this geometrical pattern a bit more by including everything in another loop and using this new counter to increment the points' ordinate position. We'll add a new variable y and use it to run the external loop 20 times. Here's the result:

var c=document.getElementById("myCanvas3"); var cxt=c.getContext("2d"); var i=0; var y=0;

for (y=1;y<=20;y++) { for (i=1;i<=5;i++) { cxt.moveTo(0, 400+y); cxt.lineTo(100, i \* (40+y)); cxt.lineTo(300, i \* (60+y)); cxt.lineTo(400, i \* (30+y)); cxt.lineTo(500, i \* (60+y)); cxt.lineTo(700, i \* (40+y)); cxt.lineTo(800, 400+y); }

for (i=5;i>=1;i--) { cxt.moveTo(0, 400); cxt.lineTo(100, 800 - (i \* (40+y))); cxt.lineTo(300, 800 - (i \* (60+y))); cxt.lineTo(400, 800 - (i \* (30+y))); cxt.lineTo(500, 800 - (i \* (60+y))); cxt.lineTo(700, 800 - (i \* (40+y))); cxt.lineTo(800, 400+y); }

}

cxt.stroke();

Not too bad, right? This last modification to the code looks like this:

var c\=document.getElementById("myCanvas3");
var cxt\=c.getContext("2d");
var i\=0;
var y\=0;

for (y\=1;y<=20;y++)
{

    for (i\=1;i<=5;i++)
    {
    cxt.moveTo(0, 400+y);
    cxt.lineTo(100, i \* (40+y));
    cxt.lineTo(300, i \* (60+y));
    cxt.lineTo(400, i \* (30+y));
    cxt.lineTo(500, i \* (60+y));
    cxt.lineTo(700, i \* (40+y));
    cxt.lineTo(800, 400+y);
    }

    for (i\=5;i\>=1;i\--)
    {
    cxt.moveTo(0, 400);
    cxt.lineTo(100, 800 \- (i \* (40+y)));
    cxt.lineTo(300, 800 \- (i \* (60+y)));
    cxt.lineTo(400, 800 \- (i \* (30+y)));
    cxt.lineTo(500, 800 \- (i \* (60+y)));
    cxt.lineTo(700, 800 \- (i \* (40+y)));
    cxt.lineTo(800, 400+y);
    }

}

cxt.stroke();

Cool! I'd like to know more

Yes, I agree. This opens up a new world for web-based graphics, and I've just scratched the surface! In particular, I'd like to see how this type of graphical component can be used to compose visualizations in the digital humanities—provided more interactivity is added to them.

Here are a couple of learning resources I found useful:

Cite this blog post:


Michele Pasin. First steps with Canvas and HTML5. Blog post on www.michelepasin.org. Published on Aug. 25, 2011.

Comments via Github:


See also:

2017


paper  Data integration and disintegration: Managing Springer Nature SciGraph with SHACL and OWL

Industry Track, International Semantic Web Conference (ISWC-17), Vienna, Austria, Oct 2017.



paper  Fitting Personal Interpretation with the Semantic Web: lessons learned from Pliny

Digital Humanities Quarterly, Jan 2017. Volume 11 Number 1


2007


paper  PhiloSURFical: browse Wittgensteinʼs Tractatus with the Semantic Web

Wittgenstein and the Philosophy of Information - Proceedings of the 30th International Ludwig Wittgenstein Symposium, Kirchberg, Austria, Aug 2007. pp. 319-335