/*
 * MouseModulator
 * Version 1.0, 12/11/2001
 * 
 * Copyright (c) 2001 by Netzministerium.de
 * Written by Till Nagel and René Sander.
 * Distributed under the terms of the GNU Lesser General Public. (See licence.txt for details)
 */

 
/* 
 * Constructs a MouseModulator.
 * This modulator returns a transformation matrix depending on mouse interactions.
 * 
 * When a mouseUp event occurs the rotation will fade to null (spins the object).
 *
 * Parameters:
 *   String name - the name of the variable storing this object
 *                 e.g. var myMouseModulator = new MouseModulator("myMouseModulator"); 
 *   int mode - the interaction mode of the modulator, use MouseModulator.MODE_xxx
 *   constants here. You can rotate around x and y (MODE_ROTATE), just on of them
 *   (MODE_ROTATE_X and MODE_ROTATE_Y), or move the model (MODE_MOVE).
 *
 * Returns:
 *   MouseModulator - a new MouseModulator instance
 */
function MouseModulator(name, mode) {
	
	// the name of the variable storing this object
	this.name = name;
	
	// interaction mode
	this.mode = mode ? mode : MouseModulator.MODE_ROTATE;

	this.matrix = new Matrix();

	// mouse coordinates
	this.mouseX = 0;
	this.mouseY = 0;
	
	// to store old mouse coordinates
	this.oldX = 0;
	this.oldY = 0;
	this.oldX2 = 0;
	this.oldY2 = 0;
	// flag to show if the mouse is down
	this.isDown = false;
	
	// responsible for deceleration
	this.decSteps = 0;
	// spinning speed
	this.spinDX = 0;
	this.spinDY = 0;
	
	this.getMatrix = MouseModulatorGetMatrix;
	this.animate = MouseModulatorAnimate;
	this.render = MouseModulatorRender;
	
	this.move = MouseModulatorMove;
	this.up = MouseModulatorUp;
	this.down = MouseModulatorDown;
	
	return this;
}

/*
 * Constants specifying the possible interaction modes.
 * Use these when setting the modulator's mode, e.g.
 * myMouseModulator.setMode(MouseModulator.MODE_ROTATE);
 */
MouseModulator.MODE_ROTATE = 0;
MouseModulator.MODE_MOVE = 1;
MouseModulator.MODE_ROTATE_X = 2;
MouseModulator.MODE_ROTATE_Y = 3;

/*
 * Returns the (rotation) matrix to transform with.
 *
 * Returns:
 *   Matrix - The matrix to transform with.
 */
function MouseModulatorGetMatrix() {
	// #1 WORKS
	m = this.matrix;
	// m = this.matrix.getCopy(); // would be no difference
	this.matrix = new Matrix();
	return m;
	
	// #2 doesn't work
	// because of the two render()-calls. one direct in animate() to spin.
	// and a triggered call in move() to rotate the mouse when dragging.
	// it is triggered to decouple mouse events and
	// looped call of the main animate method in the using application.
	// ** return this.matrix;
}

/*
 * MouseModulator.animate
 * Updates the modulator's matrix according to mouse movements.
 */
function MouseModulatorAnimate() {
	// spins the model
	if (this.decSteps > 1) {
	
		// decreases by factor 0.9
		this.decSteps *= 0.9;
		
		this.spinDX *= 0.9;
		this.spinDY *= 0.9;
      
		this.render(this.spinDX, this.spinDY);
    
	} else {
	
		if (this.isDown) {
		
			// resets spinning speed (the difference of two old mouse positions)
			// each animate call because there is no event mouseNotMove.
			this.oldX2 = this.oldX;
			this.oldY2 = this.oldY;
		}
	}
}

/*
 * MouseModulator.up
 * The mouseUp eventhandler. Pass the event object e when calling
 * this method in the page's event handler.
 *
 * Parameters
 *   Event e - the event object, just pass this on from your original handler
 */
function MouseModulatorUp(e) {

	// gets the speed (the difference of two old mouse positions)
	// at the moment of mouseUp
	this.decSteps = 100;
	this.spinDX = (this.oldX - this.oldX2) / 20;
	this.spinDY = (this.oldY2 - this.oldY) / 20;
	
	// starts spinning
	this.animate();
	
    // stores old coordinates (mouseX and mouseY are set in mouseMove() )
	this.oldX = this.mouseX;
    this.oldY = this.mouseY;

	// to prohibit moveHandler to render
    this.isDown = false;
}

/*
 * MouseModulator.down
 * The mouseDown eventhandler. Pass the event object e when calling
 * this method in the page's event handler.
 *
 * Parameters
 *   Event e - the event object, just pass this on from your original handler
 */
function MouseModulatorDown(e) {

	if (ns || ie || ns6) {
	    this.mouseX = (ns || ns6) ? e.pageX : event.x;
	    this.mouseY = (ns || ns6) ? e.pageY : event.y;
	}
    // stores old coordinates
	this.oldX = this.mouseX;
    this.oldY = this.mouseY;

    this.decSteps = 0;

	// to allow moveHandler to render
    this.isDown = true;
}

/*
 * MouseModulator.move
 * The mouseMove eventhandler. Pass the event object e when calling
 * this method in the page's event handler.
 *
 * Parameters
 *   Event e - the event object, just pass this on from your original handler
 */
// MouseModulator.prototype.move = function(e) {
function MouseModulatorMove(e) {

	// Just calculates new phi if mouse is down
	if (this.isDown) {
	
		// gets mouse coordinates
		if (ns || ie || ns6) {
			this.mouseX = (ns || ns6) ? e.pageX : event.x;
			this.mouseY = (ns || ns6) ? e.pageY : event.y;
		}
		
		//status = "mX=" + mouseX + ", mY=" + mouseY + ", oldX=" + this.oldX + ", oldY=" + this.oldY;
		
		// calculates phi (rotation degree)
		var dX = ((this.mouseX - this.oldX) / 20) // Math.max( Math.min(((mouseX - oldX) / 20), 0.1), -0.1);
		var dY = ((this.oldY - this.mouseY) / 20) //Math.max( Math.min(((oldY - mouseY) / 20), 0.1), -0.1);
		
		// stores the old coordinates (see MouseModulatorUp)
		this.oldX2 = this.oldX;
		this.oldY2 = this.oldY;
		// stores the new coordinates
		this.oldX = this.mouseX;
		this.oldY = this.mouseY;
		
		// pings render method
		setTimeout(this.name + ".render(" + dX + "," + dY + ")", 1);
		//this.render(dX, dY);
	}
}

/*
 * MouseModulator.render
 * In the render method, the modulator's matrix 
 * is computed using the current control values.
 *
 * The way the connected object can be rotated
 * and/or moved depends on the interaction mode.
 *
 * Paramters
 *   int dX - x distance amount
 *   int dY - y distance amount
 */
function MouseModulatorRender(dX, dY) {
	// As Netscape 4.x cannot handle case statements
	// with variables (!), we're using plain numbers
	// instead of the respective MouseModulator.MODE_XXX constants.
	
	switch (this.mode) {
		// Rotate and Spin
		// MouseModulator.MODE_ROTATE == 0
		case 0 : 
			var mx = new Matrix();
			mx.rotateX(dY);
			mx.rotateY(dX);
			this.matrix = mx;
			break;

		// Rotate and Spin X
		// MouseModulator.MODE_ROTATE_X == 2
		case 2 :
			mx = new Matrix();
			// correct, because changing the y coordinate gives you 
			// the amount of rotation (which is done along the x-axis)
			mx.rotateX(dY); 
			this.matrix = mx;
			break;

		// Rotate and Spin Y
		// MouseModulator.MODE_ROTATE_Y == 3
		case 3 :
			mx = new Matrix();
			mx.rotateY(dX);
			this.matrix = mx;
			break;
			
		// Move and Slide
		// MouseModulator.MODE_MOVE == 1
		case 1 :
			mt = new Matrix();
			mt.translate(dX*20, -dY*20, 0);
			this.matrix = mt ;
			break;
		default :
	}
}


Syntax highlighted by Code2HTML, v. 0.9, modified by Netzministerium, 2001.