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.
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\>
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();
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();
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:
Comments via Github:
2021
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
2015
2013
paper Fitting Personal Interpretations with the Semantic Web
Digital Humanities 2013, University of Nebraska–Lincoln, Jul 2013.
2012
2011
2010
2009
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