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>

Written by Arvind Bhardwaj

Arvind is a certified Magento 2 expert with more than 10 years of industry-wide experience.

Website: http://www.webspeaks.in/