Skip to content
May 17, 2012 / geeksretreat

HTML 5 Canvas: An animated Caesar Cipher

ceasar_cipher_html5_canvas

HTML5′s canvas implementation allows you to draw whatever takes you fancy; be it a thermometer, speedometermap 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. We’ll 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.


ceasar_cipher_html5_canvas_rotation

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 function’s 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 miss-aligned. 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.


HTML5 Caesar Cipher dial

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
About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 159 other followers

%d bloggers like this: