/**
* Gets fired when an AxAnimationElement is ready to render a frame
* @callback AxAnimationElementRender
*/
/**
* Utilizes the canvas element which will be used for rendering
* Provides useful functionality for continuous rendering, mouse and keyboard input
* @param {String|HTMLCanvasElement} canvas The id of the HTML canvas element or the canvas element object itself.
* @param {AxAnimationElementRender} onRenderEvent The method which to perform rendering of a frame
* @param {!Boolean} startRendering Denotes whether to start rendering immediately. If omitted, assumes a default value of false
* @param {!Boolean} enableContextMenu Denotes whether to enable the default context menu on the canvas element. If omitted, assumes a default value of false
* @param {!Boolean} touchScrollingEnabled Denotes whether to enable scrolling the page when touching the canvas in a touchscreen device
* @constructor
*/
function AxAnimationElement(canvas, onRenderEvent, startRendering, enableContextMenu, touchScrollingEnabled)
{
if (AxUtils.IsUndefinedOrNull(startRendering))
startRendering = false;
if (AxUtils.IsUndefinedOrNull(enableContextMenu))
enableContextMenu = false;
if (AxUtils.IsUndefinedOrNull(touchScrollingEnabled))
touchScrollingEnabled = false;
this.renderingEnabled = false;
this.contextMenuEnabled = enableContextMenu;
this.touchScrollingEnabled = touchScrollingEnabled;
this.OnRender = null;
this.RequestAniamtionFrame;
this.canvas = null;
this.buttons = new Array(256);
for (var i = 0; i < this.buttons.length; i++)
this.buttons[i] = false;
this.mouseButtons = 0;
this.mouse = { x: 0, y: 0, lastX: 0, lastY: 0, deltaX: 0, deltaY: 0, originalX: 0, originalY: 0, wheel: 0, wheelHorizontal: 0, left: false, right: false, middle: false, back: false, forward: false };
this.OnMouseMove = function(x, y) { };
this.OnMouseDown = function(x, y, button) { };
this.OnMouseUp = function(x, y, button) { };
this.OnKeyDown = function(key) { };
this.OnKeyUp = function(key) { };
if (!AxUtils.IsUndefinedOrNull(canvas))
this.Initialize(canvas);
if (!AxUtils.IsUndefinedOrNull(onRenderEvent))
this.OnRender = onRenderEvent;
if (startRendering)
this.StartRendering();
}
AxAnimationElement.MouseButtonNone = 0;
AxAnimationElement.MouseButtonLeft = 1;
AxAnimationElement.MouseButtonRight = 2;
AxAnimationElement.MouseButtonMiddle = 4;
AxAnimationElement.MouseButtonBack = 8;
AxAnimationElement.MouseButtonForward = 16;
/**
* Provides managment for the element which will be used for rendering
* requestAnimationFrame in a cross browser way.
* @param {String|HTMLCanvasElement} canvas The id of the HTML canvas element or the canvas element object itself.
*/
AxAnimationElement.prototype.Initialize = function(canvas)
{
if (AxUtils.IsInstanceOf(canvas, HTMLCanvasElement))
this.canvas = canvas;
else
this.canvas = document.getElementById(canvas);
if (AxUtils.IsUndefinedOrNull(this.canvas) || (this.canvas.tagName.toLowerCase() !== 'canvas'))
throw 'AxWebRendering.Initialize error: Element ' + canvas + ' is not a valid canvas';
// Canvas context passed for mouse events
this.canvas.axWebRendering = this;
this.canvas.width = this.canvas.offsetWidth;
this.canvas.height = this.canvas.offsetHeight;
this.canvas.addEventListener('mousemove', AxAnimationElement.CanvasMouseMoveEvent, false);
this.canvas.addEventListener('mousedown', AxAnimationElement.CanvasMouseButtonEvent, false);
this.canvas.addEventListener('mouseup', AxAnimationElement.CanvasMouseButtonEvent, false);
this.canvas.addEventListener('mouseleave', AxAnimationElement.CanvasMouseLeaveEvent, false);
this.canvas.addEventListener('wheel', AxAnimationElement.CanvasMouseWheelEvent, false);
this.canvas.addEventListener('touchmove', AxAnimationElement.CanvasTouchMoveEvent, false);
this.canvas.addEventListener('touchstart', AxAnimationElement.CanvasTouchStartEvent, false);
this.canvas.addEventListener('touchend', AxAnimationElement.CanvasTouchEndEvent, false);
// Document context passed for keyboar events
document.axWebRendering = this;
document.addEventListener('keydown', AxAnimationElement.CanvasKeyDownEvent, false);
document.addEventListener('keyup', AxAnimationElement.CanvasKeyUpEvent, false);
// Handle context menu
//this.canvas.addEventListener('contextmenu', CanvasContextMenuEvent, false);
this.canvas.oncontextmenu = AxAnimationElement.CanvasContextMenuEvent;
var requestAnimationFrameCandidates =
[
window.requestAnimationFrame,
window.webkitRequestAnimationFrame,
window.mozRequestAnimationFrame,
window.oRequestAnimationFrame,
window.msRequestAnimationFrame,
function(callback)
{
window.setTimeout(callback, 1000 / 60);
}
];
for (var i = 0; AxUtils.IsUndefinedOrNull(this.RequestAniamtionFrame); i++)
this.RequestAniamtionFrame = requestAnimationFrameCandidates[i];
window.axWebRendering = this;
};
/**
* Initiates continuous rendering onto the canvas
*/
AxAnimationElement.prototype.StartRendering = function()
{
if (this.renderingEnabled)
return;
this.renderingEnabled = true;
this.Render();
};
/**
* Stops continuous rendering
*/
AxAnimationElement.prototype.StopRendering = function()
{
this.renderingEnabled = false;
};
/**
* Performs various routines to handle the element input and renders s frame using the OnRender method
* This method is called when rendering continuously
* This method uses the OnRender method to draw a frame on the canvas element
*/
AxAnimationElement.prototype.Render = function()
{
var instance = window.axWebRendering;
if (!instance.renderingEnabled)
return;
// Calling directly instance.RequestAniamtionFrame fails, need to call through a local variable
var requestAnimationFrame = instance.RequestAniamtionFrame;
requestAnimationFrame(instance.Render);
if (!AxUtils.IsUndefinedOrNull(instance.OnRender))
instance.OnRender();
instance.mouse.deltaX = instance.mouse.x - instance.mouse.lastX;
instance.mouse.deltaY = instance.mouse.y - instance.mouse.lastY;
instance.mouse.lastX = instance.mouse.x;
instance.mouse.lastY = instance.mouse.y;
};
// Element event subscribtion callbacks
AxAnimationElement.CanvasMouseMoveEvent = function(args)
{
var instance = this.axWebRendering;
var rect = this.getBoundingClientRect();
var x = args.clientX - rect.left;
var y = args.clientY - rect.top;
instance.OnMouseMove(x, y);
instance.mouse.x = x;
instance.mouse.y = y;
if (!instance.touchScrollingEnabled)
args.preventDefault();
};
AxAnimationElement.CanvasMouseButtonEvent = function(args)
{
var instance = this.axWebRendering;
var rect = this.getBoundingClientRect();
var x = args.clientX - rect.left;
var y = args.clientY - rect.top;
var buttonsDown = (instance.mouseButtons ^ args.buttons) & args.buttons;
var buttonsUp = (instance.mouseButtons ^ args.buttons) & (~args.buttons);
if (buttonsDown !== 0)
{
instance.OnMouseDown(x, y, buttonsDown);
instance.mouse.originalX = instance.mouse.x;
instance.mouse.originalY = instance.mouse.y;
}
if (buttonsUp !== 0)
instance.OnMouseUp(x, y, buttonsUp);
instance.mouse.left = (args.buttons & AxAnimationElement.MouseButtonLeft) !== 0;
instance.mouse.right = (args.buttons & AxAnimationElement.MouseButtonRight) !== 0;
instance.mouse.middle = (args.buttons & AxAnimationElement.MouseButtonMiddle) !== 0;
instance.mouse.back = (args.buttons & AxAnimationElement.MouseButtonBack) !== 0;
instance.mouse.forward = (args.buttons & AxAnimationElement.MouseButtonForward) !== 0;
instance.mouseButtons = args.buttons;
if (!instance.touchScrollingEnabled)
args.preventDefault();
};
AxAnimationElement.CanvasMouseLeaveEvent = function(args)
{
var instance = this.axWebRendering;
var buttons = AxAnimationElement.MouseButtonNone;
var buttonsUp = (instance.mouseButtons ^ buttons) & (~buttons);
if (buttonsUp !== 0)
instance.OnMouseUp(instance.mouse.x, instance.mouse.y, buttonsUp);
instance.mouse.left = false;
instance.mouse.right = false;
instance.mouse.middle = false;
instance.mouse.back = false;
instance.mouse.forward = false;
instance.mouseButtons = buttons;
if (!instance.touchScrollingEnabled)
args.preventDefault();
};
AxAnimationElement.CanvasMouseWheelEvent = function(args)
{
var instance = this.axWebRendering;
var delta = AxMath.Sign(-args.deltaY);
var deltaH = AxMath.Sign(-args.deltaX);
instance.mouse.wheel += delta;
instance.mouse.wheelHorizontal += deltaH;
if (!instance.touchScrollingEnabled)
args.preventDefault();
};
AxAnimationElement.CanvasTouchMoveEvent = function(args)
{
if (args.touches)
{
if (args.touches.length === 1)
{
var instance = this.axWebRendering;
var touch = args.touches[0];
var x = touch.pageX - touch.target.offsetLeft;
var y = touch.pageY - touch.target.offsetTop;
instance.mouse.x = x / instance.context.viewportWidth;
instance.mouse.y = -y / instance.context.viewportHeight;
if (!instance.touchScrollingEnabled)
args.preventDefault();
}
}
};
AxAnimationElement.CanvasTouchStartEvent = function(args)
{
if (args.touches)
{
if (args.touches.length === 1)
{
var instance = this.axWebRendering;
var touch = args.touches[0];
var x = touch.pageX - touch.target.offsetLeft;
var y = touch.pageY - touch.target.offsetTop;
instance.mouse.x = x;
instance.mouse.y = -y;
instance.mouse.lastX = instance.mouse.x;
instance.mouse.lastY = instance.mouse.y;
instance.mouse.originalX = instance.mouse.x;
instance.mouse.originalY = instance.mouse.y;
instance.OnMouseDown(x, y, AxAnimationElement.MouseButtonLeft);
instance.mouse.left = true;
if (!instance.touchScrollingEnabled)
args.preventDefault();
}
}
};
AxAnimationElement.CanvasTouchEndEvent = function(args)
{
var instance = this.axWebRendering;
if (args.touches)
{
if (args.touches.length === 1)
{
var touch = args.touches[0];
var x = touch.pageX - touch.target.offsetLeft;
var y = touch.pageY - touch.target.offsetTop;
instance.OnMouseUp(x, y, AxAnimationElement.MouseButtonLeft);
}
}
instance.mouse.left = false;
};
AxAnimationElement.CanvasContextMenuEvent = function(args)
{
var instance = this.axWebRendering;
return instance.contextMenuEnabled;
};
AxAnimationElement.CanvasKeyDownEvent = function(args)
{
var instance = this.axWebRendering;
instance.OnKeyDown(args.keyCode);
if (args.keyCode < instance.buttons.length)
instance.buttons[args.keyCode] = true;
};
AxAnimationElement.CanvasKeyUpEvent = function(args)
{
var instance = this.axWebRendering;
instance.OnKeyUp(args.keyCode);
if (args.keyCode < instance.buttons.length)
instance.buttons[args.keyCode] = false;
};