Create Smiling Face in HTML5 Canvas

Today we will create an interactive smiling face in HTML 5 canvas. The eyes of the face will follow the movement of the mouse over the canvas. The concept is very simple, just to redraw the eyes according to the position of the cursor over the canvas. Here is the step by step tutorial to achieve this.
Smiling Face in HTML 5

Live Demo Download Script

The Html Markup:

<!doctype html>
<html lang="en">
<head>
    <title>Smiling Face</title>
    <meta charset="utf-8" />
    <style>
    div#main {
        margin:0 auto;
        text-align:center;
    }
    div.title {
        font-size: 40px;
        font-family:monospace;
    }
    canvas {
    }
</style>
</head>
<body>
 <div id="main">
  <canvas height="600" width="600" id="face" style="background-color:green">
   <p>You need canvas!</p>
  </canvas>
 </div>
</body>
</html>

Initialization:

First of all we need to create the object of the canvas and then create the context object from canvas. I have stored these objects in global variables for later use. I have also stored the height and width of the canvas in variables.
var canvas = null;   //The canvas object
var context = null;   //The canvas context
var c_width;   //Canvas width
var c_height;   //Canvas height

initFace();

function initFace() {
   canvas = document.getElementById("face");
   context = canvas.getContext("2d");

   c_width = canvas.offsetWidth;
   c_height = canvas.offsetHeight;

   //draw the face
   drawSmileyFace();
}

function drawSmileyFace() {
   drawFace();
   drawLeftEye();
   drawRightEye();
   drawNose();
   drawSmile();
}

Draw Face components:

I have used separate functions to draw the separate parts of the face. These functions are called inside drawSmileyFace(). Here are the functions:

Face:

function drawFace() {
   // face
   context.beginPath();
   context.arc(c_width/2,  // x   x,y is at the center
   c_height/2,              // y
   200,                  // arc radius
   0,                // starting angle
   degreesToRadians(360),   // ending angle
   true);                    // counter-clockwise
   context.fillStyle = "#FFFF00";
   context.fill();
   context.stroke();
}

The Left Eye

Here is the code to draw the left eye on the face:
//dx is deviation of center from left
//dy is the deviation of center from top
function drawLeftEye(dx, dy) {
   x = 200;
   y = 250;

   dx = dx || 0;
   x1 = x + parseFloat(dx);

   dy = dy || 0;
   y1 = y + parseFloat(dy);

   // left eye
   context.beginPath();
   context.arc(x, y, 25, 0, degreesToRadians(360), true);
   context.fillStyle = "#FFFFFF";
   context.fill();
   context.strokeStyle = '#000000';
   context.stroke();
   //inner left eye
   context.beginPath();
   context.arc(x1, y1, 20, 0, degreesToRadians(360), true);
   context.fillStyle = "#04B4AE";
   context.fill();
   context.strokeStyle = '#04B4AE';
   context.stroke();
}
The right eye can be created in the similar way.

The Nose

I have used the canvas line to create the nose. A rhombus has been drawn to represent the nose.
function drawNose() {
   // nose
   context.strokeStyle = '#000000';
   context.fillStyle = "#000000";
   context.beginPath();
   context.moveTo(300, 275);
   context.lineTo(325, 300);
   context.lineTo(300, 325);
   context.lineTo(275, 300);
   context.closePath();
   context.fill();
}

The Smile


function drawSmile() {
   // start angle is to the right of the center point. So to draw a
   // semi-circle that's open at the top, like for the mouth in a 
   // smile, you need to draw in a clockwise direction.
   // angle is the number of degrees we take off the edges of the 
   // semi circle to give a more realistic mouth look.
   context.beginPath();
   context.arc(300, 350, 75, degreesToRadians(0), degreesToRadians(180), false);
   context.stroke();
}

Getting the Mouse coordinates

function getMousePos(canvas, evt) {
   var rect = canvas.getBoundingClientRect();
   return {
     x: evt.clientX - rect.left,
     y: evt.clientY - rect.top
   };
}

Adding the Event Listener

The final step is to add the event listener to the code which will redraw the canvas on moving the mouse. This code reads the mouse coordinates and adjusts the center of the eyes accordingly.
canvas.addEventListener('mousemove', function(evt) {
   var mousePos = getMousePos(canvas, evt);
   context.clearRect(0, 0, canvas.width, canvas.height);
   var eyeY = 250;      //distance from top
   var leyeX = 200;   //distance of left eye from left
   var reyeX = 400;   //distance of right eye from left
   var ldx = 0;      //deviation of left eye from left
   var rdx = 0;      //deviation of right eye from left
   var ldy = 0;      //deviation of left eye from top

   if (eyeY > mousePos.y) {
      ldy = 100 - (mousePos.y/eyeY * 100);
      ldy = (ldy * 5) / 100;
      ldy = 0 - ldy;
   } else {
      ldy = 100 - ((c_height - mousePos.y)/(c_height - eyeY) * 100);
      ldy = (ldy * 5) / 100;
   }

   if (leyeX < mousePos.x) {
     //left eye
     ldx = 100 - ((c_width - mousePos.x)/(c_width - leyeX) * 100);
     ldx = (ldx * 5) / 100;

     //right eye
     rdx = 100 - ((c_width - mousePos.x)/(c_width - reyeX) * 100);
     rdx = (rdx * 5) / 100;
   } else {
     //left eye
     ldx = 100 - (mousePos.x/leyeX) * 100;
     ldx = (ldx * 5) / 100;
     ldx = 0 - ldx;

     //right eye
     rdx = 100 - (mousePos.x/reyeX) * 100;
     rdx = (rdx * 5) / 100;
     rdx = 0 - rdx;
   }

   drawFace();
   drawLeftEye(ldx, ldy);
   drawRightEye(rdx, ldy);
   drawNose();
   drawSmile();

}, false);

The Comlpete Code

<!doctype html>
<html lang="en">
<head>
<title>Smiling Face</title>
<meta charset="utf-8" />
<style>
div#main {
   margin:0 auto;
   text-align:center;
}
div.title {
   font-size: 40px;
   font-family:monospace;
}
canvas {
}
</style>
<script src="jquery1.10.min.js"></script>
</head>
<body>
   <div id="main">
     <canvas height="600" width="600" id="face" style="background-color:green">
       <p>You need canvas!</p>
     </canvas>
    <div class="title">Smiling Face in HTML 5</div>
   </div>

<script>
var canvas = null;   //The canvas object
var context = null;   //The canvas context
var c_width;   //Canvas width
var c_height;   //Canvas height

initFace();

function initFace() {
   canvas = document.getElementById("face");
   context = canvas.getContext("2d");

   c_width = canvas.offsetWidth;
   c_height = canvas.offsetHeight;

   //draw the face
   drawSmileyFace();
}

function drawSmileyFace() {
   drawFace();
   drawLeftEye();
   drawRightEye();
   drawNose();
   drawSmile();
}

function drawFace() {
   // face
   context.beginPath();
   context.arc(c_width/2,   // x   x,y is at the center
         c_height/2,   // y
         200,      // arc radius
         0,         // starting angle
         degreesToRadians(360), // ending angle
         true);        // counter-clockwise
   context.fillStyle = "#FFFF00";
   context.fill();
   context.stroke();
}
function drawLeftEye(dx, dy) {
   x = 200;
   y = 250;

   dx = dx || 0;
   x1 = x + parseFloat(dx);

   dy = dy || 0;
   y1 = y + parseFloat(dy);

   // left eye
   context.beginPath();
   context.arc(x, y, 25, 0, degreesToRadians(360), true);
   context.fillStyle = "#FFFFFF";
   context.fill();
   context.strokeStyle = '#000000';
   context.stroke();
   //inner left eye
   context.beginPath();
   context.arc(x1, y1, 20, 0, degreesToRadians(360), true);
   context.fillStyle = "#04B4AE";
   context.fill();
   context.strokeStyle = '#04B4AE';
   context.stroke();
}

function drawRightEye(dx, dy) {
   x = 400;
   y = 250;

   dx = dx || 0;
   x1 = x + parseFloat(dx);

   dy = dy || 0;
   y1 = y + parseFloat(dy);

   // right eye
   context.beginPath();
   context.arc(x, y, 25, 0, degreesToRadians(360), true);
   context.fillStyle = "#FFFFFF";
   context.fill();
   context.strokeStyle = '#000000';
   context.stroke();
   //inner right eye
   context.beginPath();
   context.arc(x1, y1, 20, 0, degreesToRadians(360), true);
   context.fillStyle = "#04B4AE";
   context.fill();
   context.strokeStyle = '#04B4AE';
   context.stroke();
}
function drawNose() {
   // nose
   context.strokeStyle = '#000000';
   context.fillStyle = "#000000";
   context.beginPath();
   context.moveTo(300, 275);
   context.lineTo(325, 300);
   context.lineTo(300, 325);
   context.lineTo(275, 300);
   context.closePath();
   context.fill();
}
function drawSmile() {
   // start angle is to the right of the center point. So to draw a
   // semi-circle that's open at the top, like for the mouth in a 
   // smile, you need to draw in a clockwise direction.
   // angle is the number of degrees we take off the edges of the 
   // semi circle to give a more realistic mouth look.
   context.beginPath();
   context.arc(300, 350, 75, degreesToRadians(0), degreesToRadians(180), false);
   context.stroke();
}

function getMousePos(canvas, evt) {
   var rect = canvas.getBoundingClientRect();
   return {
     x: evt.clientX - rect.left,
     y: evt.clientY - rect.top
   };
}
canvas.addEventListener('mousemove', function(evt) {
   var mousePos = getMousePos(canvas, evt);
   context.clearRect(0, 0, canvas.width, canvas.height);
   var eyeY = 250;     //distance from top
   var leyeX = 200;   //distance of left eye from left
   var reyeX = 400;   //distance of right eye from left
   var ldx = 0;     //deviation of left eye from left
   var rdx = 0;     //deviation of right eye from left
   var ldy = 0;     //deviation of left eye from top

   if (eyeY > mousePos.y) {
     ldy = 100 - (mousePos.y/eyeY * 100);
     ldy = (ldy * 5) / 100;
     ldy = 0 - ldy;
   } else {
     ldy = 100 - ((c_height - mousePos.y)/(c_height - eyeY) * 100);
     ldy = (ldy * 5) / 100;
   }

   if (leyeX < mousePos.x) {
    //left eye
    ldx = 100 - ((c_width - mousePos.x)/(c_width - leyeX) * 100);
    ldx = (ldx * 5) / 100;

    //right eye
    rdx = 100 - ((c_width - mousePos.x)/(c_width - reyeX) * 100);
    rdx = (rdx * 5) / 100;
   } else {
    //left eye
    ldx = 100 - (mousePos.x/leyeX) * 100;
    ldx = (ldx * 5) / 100;
    ldx = 0 - ldx;

    //right eye
    rdx = 100 - (mousePos.x/reyeX) * 100;
    rdx = (rdx * 5) / 100;
    rdx = 0 - rdx;
   }

   drawFace();
   drawLeftEye(ldx, ldy);
   drawRightEye(rdx, ldy);
   drawNose();
   drawSmile();

}, false);

function degreesToRadians(degrees) {
   radians = (degrees * Math.PI)/180;
   return radians;
}

</script>

</body>
</html>

We would love to hear from you...

back to top