Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

HTML5 Eyes that Follow the Mouse

5.00/5 (2 votes)
9 Jan 2012CPOL1 min read 24.9K  
HTML5 Eyes that follow the mouse

NellyI 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.:

HTML
<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).

JavaScript
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:

JavaScript
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:

JavaScript
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:

JavaScript
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)