Capturing Mouse Events Part 1

One of the goals of Ajax technology is the Rich Internet Application - RIA. The idea is to try to make web applications as robust as desktop applications. Since desktop applications are primarily mouse driven, it makes sense incorporate controlling the mouse into Ajax-enabled applications. Please note that mouse functionality is NOT Ajax, per se. Rather, it is a way for you to fire Ajax events based on user input via the mouse. Web developers have been able to manipulate the mouse for a while. Having said that, in this lesson, I'll show you how to utilize mouse gestures and leave the Ajax out. You'll see where the events fire - and where you can add Ajax functionality.

1. Create a new Web Application in Netbeans. Name it MouseEvents and click Finish. You can delete the index.jsp file - we won't need it. Since all of the code needed to manipulate the mouse executes on the client, all of the files in this project will be HTML files.

2. Right-click the Web Pages node and choose New > HTML... Name the file pathGen and click Finish.

This project began as a re-write of some older code that I had written that was not cross-browser capable. The application is a way to create (X,Y) coordinates as an array for animation in a Path Animation. Users could click on the page and drag their mouse around. As the mouse moved, its coordinates on the screen were captured. The original application worked only in Internet Explorer. You can view the mechanics of Path Animation here. That code was written back in the bad old days of the browser war and is in dire need of an update. The Path Animation Generator we'll build here is the first step in the update process.

3. Add the following code to the <body> element:

<H1>Path Generator</H1>
<form>
<br>
x values:
<textarea id="xVals"></textarea>
<br>
y values:
<textarea id="yVals"></textarea>
</form>
<p><a href="javascript:clearValues()">Clear Values</a> | <a href="javascript:animate()">Preview</a></p>
<div id="bulb" width="32" height="64" style="position: absolute; top: 300; left: 0; z-index: 2;">
<img border="0" src="images/lightbulb.gif" width="32" height="64">
</div>

You'll need to create an images folder within your Web Pages node and copy the lightbulb.gif file into that folder.

4. Add the following <style> declaration to the <head> of the file:

<style>
body{
color: white;
background-color: black;
font: 12pt sans-serif;
}
a{
color: #ffffdd;
}
</style>

5. Add a <script> element to the <head> and add the following code:

<script type="text/javascript">

      var flag = false;
	  var xCoord = '';
	  var yCoord = '';
	  
	  function setFlagDown(){
	  	flag = true;
	  }
	  function setFlagUp(){
	  	flag = false;
	  }
	  function getMouseData(evt) {
        var e = new MouseEvent(evt);
		if(flag){
        	if(xCoord == ''){
				xCoord += e.x;
				yCoord += e.y;
			}else{
				xCoord += ', ' + e.x;
				yCoord += ', ' + e.y;
			}
			document.getElementById('bulb').style.left = e.x;
			document.getElementById('bulb').style.top = e.y;
		}
		document.getElementById("xVals").value = xCoord;
        document.getElementById("yVals").value = yCoord;
      }

      function MouseEvent(e)  {
        if(e) {
          this.e = e; 
        } else {
          this.e = window.event; 
        }
        if(e.pageX) {
          this.x = e.pageX; 
        } else {
          this.x = e.clientX; 
        }
        if(e.pageY) {
          this.y = e.pageY; 
        } else {
          this.y = e.clientY; 
        }
        if(e.target) {
          this.target = e.target; 
        } else {
          this.target = e.srcElement;
        } 
		if(e.which){
			this.button = e.which;
		} else {
			this.button = e.button;
		}
	}
	
	function clearValues(){
		xCoord = '';
		yCoord = '';
		document.getElementById("xVals").value = xCoord;
        document.getElementById("yVals").value = yCoord;
	}
	
function tokenizer(stringValue,delim){
//converts stringValue to array based on delim

	begin=0;
	end=stringValue.indexOf(delim);
	tokenCount = 0;
	while(stringValue.indexOf(delim,begin)>0){
	this[tokenCount] = parseInt(stringValue.substring(begin,end));
	tokenCount += 1;
	begin=end+1;
	end=stringValue.indexOf(delim,begin);

	this.length = tokenCount;
	}
}
var currentX = 0;
var currentY = 0;
function animate(){

	xPos = new tokenizer(xCoord,',');
	yPos = new tokenizer(yCoord,',');

	if(!xPos.length)
		return;
	
	if(currentX>xPos.length-1){
		currentX = 0;
		currentY=0;
		return;
	}

	document.getElementById('bulb').style.left = parseInt(xPos[currentX]);
	document.getElementById('bulb').style.top = parseInt(yPos[currentY]);
	currentX++;
	currentY++;
	setTimeout('animate()',10);
}
    </script>

The flag variable is a boolean. It will keep track of when the mouse is down and up. The setFlagDown() and setFlagUp() functions toggle the value of the flag. The xCoord and yCoord variables will hold the x and y coordinates of the mouse as it is dragged on the screen.

The getMouseData() function is where all the interesting stuff happens. First, a MouseEvent is created (more on that in a little bit). Then, the flag is checked. If the flag is true (i.e. the mouse is down) the location of the x and y coordinates is appended to the xCoord and yCoord variables. In addition, the lighbulb is moved around on the screen based on the location of the mouse. Finally, the values of the xCoord and yCoord variables are written to the appropriate text area.

The MouseEvent() function is crucial to the application. IT converts the mouse event generated by the browser into a standard format. In IE, you use the window.event object to get information about mouse events. In other browsers like Firefox, the event object is created for you and passed along in the method call. The MouseEvent() function abstracts out all of the data contained in a mouse event and allows you to access the required data regardless of which browser is used.

The clearValues() function is self-explanatory - it clears the xCoord and yCoord variables and the text stored ion the text areas. The tokenizer() function is a helper function that allows a string to be turned into an array based on the delimiter that separates its values.

The animate() function uses the currentX and currentY counter variables to loop through each pair of coordinates and move the lightbulb around the screen. The call to setTimeout is quasi-recursive. It makes a call to animate() but isn't technically recursive since it returns immediately rather than executing synchronously.

6. The last thing to do is to attach the events to the <body> element:

<body onmousemove="getMouseData(event)" onmousedown="setFlagDown()" onmouseup="setFlagUp()">

Note that the keyword event is passed to the getMouseData() function - that's the event object created by Firefox and other browsers. IE will simply pass a null object - which makes no difference in your script. One of the cool things about this application is that it is speed sensitive. That is, the faster you move the mouse around on the screen, the faster your animation will be. You can see it in action here.