Sie sind auf Seite 1von 5

HTML 5 Canvas: An animated Caesar Cipher

HTML5s canvas implementation allows you to draw whatever takes you fancy; be it
a thermometer, speedometer, map or compass. This post takes my previous posts
one step further and mixes together the techniques used in the aforementioned
posts to draw an interactive animated Caesar cipher. In cryptography, a Caesar
cipher is one of the simplest and most widely known encryption techniques. It is a
substitution cipher in which letters are replaced by a letter some fixed number of
positions down the alphabet. For example, with a shift of 4, A would be replaced by
E, B would become F, and so on. The method is named after Julius Caesar, who used
it in his private correspondence. In this post one will explain how to draw a Caesar
Cipher gauge. The gauge will allow a user to input the desired shift. When a shift value is input the Caesar Cipher
dial will rotate to represent the new shift.

The HTML Source


The following code is stripped to the minimum in order to draw the dial:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Animated Caesar Cipher Wheel</title>
<script src='caesar_cipher.js'></script>
<link rel="stylesheet" type="text/css" href="caesar_cipher.css" media="all" />
</head>
<body onload='init();'>
<canvas id="caesar" width="500" height="500"></canvas>
<input id="shift" type="text" value="00" maxlength="2" onChange="handleShiftChange(this.value)" />
</body>
</html>

The HTML is straight forward. The items of interest are the canvas element, the onload event for the
body, the script tag and the css link include. For those who are not familiar with HTML let me explain
how we draw the dial onto the canvas. When any HTML page loads the browser will run the JavaScript
code attached to the onload event of the body tag e.g.
<body onload='init();'>
<script src='caesar_cipher.js'></script>

In order to understand how the init function work we need to understand how the browsers locates it.
The browser will load any JavaScript code included in a script tag prior to displaying the page to the user
e.g.
<script src='caesar_cipher.js'></script>

Therefore, the content of my script caesar_cipher.js will be loaded, and thus, the function called init
will be available. If you were to look inside the aforementioned script you will be able to see the code
e.g.
function init()
{
// Grab the compass element
var canvas = document.getElementById('caesar');
// Canvas supported?
if(canvas.getContext('2d'))
{
ctx = canvas.getContext('2d');
// Load the needle image
dial = new Image();
dial.src = 'caesar_cipher_dial.png';
// Load the compass image
img = new Image();
img.src = 'caesar_cipher.png';
img.onload = draw;
// Start the change input monitor timer
setInterval(checkForShiftChange, 1000);
}
else
{
alert("Canvas not supported!");
}
}

The content of the function is quite readable and the code is ordered in logic steps. The first step is to
obtain a handle to the canvas element. If the canvas element is found we then proceed to ensure that
the browser supports the canvas implementation. Assuming support is implemented the second step is
to load the inner and outer dial image resources. The second image the dial with the letters in the
shifted position is created with an onload event attached. This event informs the browser to call the
JavaScript function draw directly after the image has loaded. Well cover the content of the draw
function latter in this post. The final step of the init function is to start a timer:
// Start the change input monitor timer
setInterval(checkForShiftChange, 1000);

The timer basically tells the JavaScript engine to execute the function checkForShiftChange every
second (1000 milliseconds). This function contains the following:
function checkForShiftChange()
{
// Get the angle related to the shift value
var iExpectedAngle = getRequiredAngle();
// If the currect angle is not the expected angle start the timer
if(iExpectedAngle != degrees)
{
if(bTurning)

stopTimer();
// Determine which way the rotation for move
bClockwise = iExpectedAngle > degrees;
// Star the timer
timer = setInterval(draw, 50);
bTurning = true;
}
}

The purpose of the function is to obtain the current shift value from the input box and then convert it to
the angle which represents the rotation factor that the outer dial needs to be rotated in order to display
the letters in the correct location. The function responsible for converting the shift value to the related
angle is called getRequiredAngle. This contains the following:
function getRequiredAngle()
{
// Grab a handle to the shift input
var shift = document.getElementById('shift');
var iExpectedAngle = 0;
var iShiftInput = 0;
if(shift != null)
{
// Make sure we have a number
iShiftInput = shift.value * 1.0;
// Calculate the expected angle for the shift
iExpectedAngle = Math.floor(((360/26) * (iShiftInput % 26)),0);
}
return iExpectedAngle;
}

The function simply grabs the value input into the shift input tag (user driven input). It then converts
this to an angle by multiplying it by a factor of 360 divided by 26. The result is then returned to the
calling interface. This returned value is used by the checkForShiftChange function, it first checks
whether the value has changed e.g. do we need to rotate the dial? If a rotation is required the function
determines whether the it would be quicker to turn the dial clockwise or anti-clockwise. With this
information to hand it then starts another timer which calls the draw function every 50 milliseconds. In
reality we could simply redraw the dial in at the desired angle; however, it is far more realistic to
animate the transition. Thus, the draw function increments the angle of the outer dial by 3 degrees
every-time the draw function is called e.g.

Once the required angle has been reached, the function stops the timer. As stated above the draw function is
called once during the initial load and then subsequently for every transition. The code within the draw function is:
function draw()
{
var iExpectedAngle = getRequiredAngle();
calculateNewAngle(iExpectedAngle);
clearCanvas();
// Draw the background onto the canvas
ctx.drawImage(img, 0, 0);
// Save the current drawing state
ctx.save();
// Now move across and down half the image
ctx.translate(245, 264);
// Rotate around this point
ctx.rotate(degrees * (Math.PI / 180));
// Draw the shifted letters
ctx.drawImage(dial, -245, -264);
// Restore the previous drawing state
ctx.restore();
}

The content of the function ascertains the new rotation angle. It then passes the angle into the
calculateNewAngle function. This function performs a few sanity checks before adjusting the current
angle in either a clockwise, or, anti-clockwise direction. The function includes the following:
function calculateNewAngle(iExpectedAngle)
{
// If we've hit the right place stop the timer
if(iExpectedAngle == degrees)
{
stopTimer();
return;
}
if(bClockwise)
{
// Increment the angle of the needle by 5 degrees
degrees += 3;
// Check if we have passed the 0/360 point and adjust
if(degrees > 360)
degrees = 0;
// Check if we have moved past the target

if(degrees > iExpectedAngle)


degrees = iExpectedAngle
}
else
{
// Decrement the angle of the needle by 5 degrees
degrees -= 3;
// Check if we have passed the 0/360 point and adjust
if(degrees < 0)
{
if(iExpectedAngle == 0)
degrees = 0;
else
degrees = 360;
}
// Check if we have moved past the target
if(degrees < iExpectedAngle)
degrees = iExpectedAngle
}
}

This functions first task is to check whether the target angle has been reached, or, in other terms we
have positioned the outer dial in the correct shifted position. If the angle has been reached the function
stops the timer and exits. If the later is not true the function then adjusts the current angle in the
desired location and returns to the calling interface.
The remainder of the draw function above then clears the canvas. The background image is then
rendered to the canvas and a call to the save context function is made. This saves the drawing state of
canvas. The canvas drawing state is basically a snapshot of all the attributes that have been applied to
the canvas including the transformations, styles, line widths and clipping regions. By default, none of
these are set; thus, we are simply saving the defaults applied to our canvas so we can revert back to
them later. The next step deals with the animation. This involves two steps. The first step performs the
following translation:
// Now move across and down half the image
ctx.translate(245, 264);

This translation moves the centre point to the middle of the image which happens to be 245 x 264
pixels. By default the rotation is performed on the canvas with the rotation centred at position 0, 0. If
we were to simply ask the canvas to rotate at increments of 3 degrees the dials would become missaligned. Both images are the same size, thus, they share the same centre point; therefore, by rotating
around this common centre point we can move the outer dial to the correct location. The last part of the
draw function is to restore context back to the default.
That concludes this post. A working version of this post can be viewed here here this includes the PSD
file used to create the image for the dial. The code and my previous HTML canvas projects are now
available on Git Hub https://github.com/rheh/HTML5-canvas-projects/tree/master/caesar_cipher

Das könnte Ihnen auch gefallen