I made a cute flash movie of an elephant ages ago. Among other things, the eyes of the elephant followed the cursor. Unfortunately, subsequent flash security updates broke the functionality (if you want mouse move events outside the flash control, you need special permissions). So, I decided to convert it to HTML5. To see the result in action, you need to go to the original blog entry.
How It’s Done
I use an onload
event handler somewhere in the HTML file which calls the init()
function. E.g.:
<body onload="init()">
In the init()
function, the images are loaded and the canvas resized and then the render loop is started via requestAnimFrame
. All images are stored in the one PNG (this is known as an image atlas).
function init()
{
canvas = document.getElementById('nelly');
if (canvas.getContext)
{
context = canvas.getContext('2d');
}
else
{
return;
}
logElement = document.getElementById('log');
atlas = new Image();
atlas.src = 'http://astronautz.com/wordpress/nelly0.png';
atlas.onload = function()
{
window.addEventListener ("mousemove", getCoords, true);
xCanvas = canvas.offsetLeft;
yCanvas = canvas.offsetTop;
var elem = canvas.offsetParent;
while (elem)
{
xCanvas += elem.offsetLeft;
yCanvas += elem.offsetTop;
elem = elem.offsetParent;
}
backWidth = 97;
backHeight = 150;
canvas.width = backWidth;
canvas.height = backHeight;
eyeRight.setSize(4, 4);
eyeRight.setMin(44, 30);
eyeRight.setMax(54, 52);
eyeRight.setAtlas(97, 0);
eyeRight.init();
eyeLeft.setSize(4, 4);
eyeLeft.setMin(34, 30);
eyeLeft.setMax(39, 52);
eyeLeft.setAtlas(97, 0);
eyeLeft.init();
requestAnimFrame(render);
};
}
Note that I create an event handler which stores the mouse coordinates in two global variables:
var xMouse = 0;
var yMouse = 0;
...
function getCoords(event)
{
xMouse = event.clientX;
yMouse = event.clientY + window.pageYOffset;
};
...
window.addEventListener ("mousemove", getCoords, true);
Each eye is controlled by an Eye
object. It takes a min
, max
as parameters:
It also needs the size of the eye image and its position within the image atlas before you initialise:
eyeRight.setSize(4, 4);
eyeRight.setMin(44, 30);
eyeRight.setMax(54, 52);
eyeRight.setAtlas(97, 0);
eyeRight.init();
The eye movement is calculated by getting the slope of the angle between the eyeball center and the current mouse position. Then you need to calculate the position taking into account the quadrant:
this.update = function()
{
var xDiff = xMouse-(xCanvas+this.m_xOrig);
var yDiff = yMouse-(yCanvas+this.m_yOrig);
if (yDiff == 0)
{
if (xDiff > 0)
{
this.m_x = this.m_xMax;
}
else
{
this.m_x = this.m_xMin;
}
this.m_y = this.m_yOrig;
}
else
{
var slope = xDiff/yDiff;
if (yDiff > 0)
{
this.m_x = slope*(this.m_xMax-this.m_xMin) + this.m_xMin;
}
else
{
this.m_x = -slope*(this.m_xMax-this.m_xMin) + this.m_xMin;
}
}
if (xDiff == 0)
{
if (yDiff > 0)
{
this.m_y = this.m_yMax;
}
else
{
this.m_y = this.m_yMin;
}
this.m_x = this.m_xOrig;
}
else
{
var slope = yDiff/xDiff;
if (xDiff > 0)
{
this.m_y = slope*(this.m_yMax-this.m_yMin) + this.m_yMin;
}
else
{
this.m_y = -slope*(this.m_yMax-this.m_yMin) + this.m_yMin;
}
}
if (this.m_x > this.m_xMax)
{
this.m_x = this.m_xMax;
}
else if (this.m_x < this.m_xMin)
{
this.m_x = this.m_xMin;
}
if (this.m_y > this.m_yMax)
{
this.m_y = this.m_yMax;
}
else if (this.m_y < this.m_yMin)
{
this.m_y = this.m_yMin;
}
}
The full source code can be downloaded here.