Files
Superalgos/Canvas.js
T
2018-02-14 13:00:19 +01:00

415 lines
12 KiB
JavaScript

/*
Whithin this system, the canvas object represents a layer on top of the browser canvas object, and it is the one who should interact with it.
Graphically, the system has 3 spaces:
1) The "Chart Space": It is where the charts are plotted.
2) The "Floating Space": It is where floating elements live. There is a physics engine for this layer that allows these elements to flow.
3) The "Control Panel": It is where the main controls are. This is a fix panel that sits on top of everything else.
All these spaces are child objects of the Canvas object.
*/
var browserCanvas; // This is the canvas object of the browser.
var browserCanvasContext; // The context of the canvas object.
let stepsInitializationCounter = 0; // This counter the initialization steps required to be able to turn off the splash screen.
let marketInitializationCounter = 0; // This counter the initialization of markets required to be able to turn off the splash screen.
let splashScreenNeeded = true;
function newCanvas() {
/* Mouse event related variables. */
var containerDragStarted = false;
var ballDragStarted = false;
var ballBeingDragged;
var containerBeingDragged;
var viewPortBeingDragged = false;
var dragVector = {
downX: 0,
downY: 0,
upX: 0,
upY: 0
};
/* canvas object */
var canvas = {
eventHandler: undefined,
chartSpace: undefined,
floatingSpace: undefined,
animation: undefined,
initialize: initialize
};
canvas.eventHandler = newEventHandler();
let splashScreen;
return canvas;
function initialize() {
initializeBrowserCanvas();
addCanvasEvents();
/* The canvas has one ChartSpace child. Here is where we get it. */
var chartSpace = newChartSpace();
chartSpace.initialize();
this.chartSpace = chartSpace;
var floatingSpace = newFloatingSpace();
floatingSpace.initialize();
this.floatingSpace = floatingSpace;
splashScreen = newSplashScreen();
splashScreen.initialize();
var animation = newAnimation();
animation.initialize(clearBrowserCanvas);
this.animation = animation;
animation.addCallBackFunction("Chart Space", this.chartSpace.draw);
animation.addCallBackFunction("Floating Space", this.floatingSpace.physicsLoop);
animation.addCallBackFunction("Splash Screen", splashScreen.draw);
animation.start();
}
function initializeBrowserCanvas() {
browserCanvas = document.getElementById('canvas');
browserCanvasContext = browserCanvas.getContext('2d');
var body = document.getElementById('body');
browserCanvas.width = window.innerWidth;
browserCanvas.height = window.innerHeight;
browserCanvas.style.border = "none";
viewPort.initialize();
}
function clearBrowserCanvas() {
browserCanvasContext.clearRect(0, 0, browserCanvas.width, browserCanvas.height);
}
function addCanvasEvents() {
/* Mouse down and up events to control the drag of the canvas. */
browserCanvas.addEventListener('mousedown', onMouseDown, false);
browserCanvas.addEventListener('mouseup', onMouseUp, false);
browserCanvas.addEventListener('mousemove', onMouseMove, false);
browserCanvas.addEventListener('click', onMouseClick, false);
/* Mouse wheel events. */
if (browserCanvas.addEventListener) {
// IE9, Chrome, Safari, Opera
browserCanvas.addEventListener("mousewheel", onMouseWheel, false);
// Firefox
browserCanvas.addEventListener("DOMMouseScroll", onMouseWheel, false);
}
// IE 6/7/8
else browserCanvas.attachEvent("onmousewheel", onMouseWheel);
}
function onMouseDown(event) {
dragVector.downX = event.pageX;
dragVector.downY = event.pageY;
/* We check first if the mouse is over a ball/ */
ballBeingDragged = isInside(event.pageX, event.pageY);
if (ballBeingDragged >= 0) {
ballDragStarted = true;
} else {
/* If it is not, then we check if it is over any of the existing containers. */
var point = {
x: event.pageX,
y: event.pageY
};
var container = canvas.chartSpace.getContainer(point);
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container;
containerDragStarted = true;
} else {
viewPortBeingDragged = true;
}
}
}
function onMouseClick(event) {
dragVector.downX = event.pageX;
dragVector.downY = event.pageY;
/* We check first if the mouse is over a ball/ */
var ballBeingClicked = isInside(event.pageX, event.pageY);
if (ballBeingClicked >= 0) {
/* Right now we do nothing with this. */
} else {
/* If it is not, then we check if it is over any of the existing containers. */
var point = {
x: event.pageX,
y: event.pageY
};
var container = canvas.chartSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
/* We deliver the event to the container that is waiting for it. */
container.eventHandler.raiseEvent('onMouseClick', event);
}
}
}
function onMouseUp(event) {
if (containerDragStarted || viewPortBeingDragged || ballDragStarted) {
canvas.eventHandler.raiseEvent("Drag Finished", undefined);
}
/* Turn off all the possible things that can be dragged. */
containerDragStarted = false;
ballDragStarted = false;
viewPortBeingDragged = false;
containerBeingDragged = undefined;
browserCanvas.style.cursor = "auto";
}
function onMouseMove(event) {
viewPort.mousePosition.x = event.pageX;
viewPort.mousePosition.y = event.pageY;
if (containerDragStarted === true || ballDragStarted === true || viewPortBeingDragged === true) {
if (ballDragStarted === true) {
if (isInsideBall(ballBeingDragged, event.pageX, event.pageY) === false) {
/* This means that the user stop moving the mouse and the ball ball out of the pointer.
In this case we cancell the drag operation . */
ballDragStarted = false;
browserCanvas.style.cursor = "auto";
return;
}
}
dragVector.upX = event.pageX;
dragVector.upY = event.pageY;
checkDrag();
}
}
function checkDrag() {
if (containerDragStarted === true || ballDragStarted === true || viewPortBeingDragged === true) {
browserCanvas.style.cursor = "grabbing";
canvas.eventHandler.raiseEvent("Dragging", undefined);
var targetBall = isInside(event.pageX, event.pageY);
if (ballDragStarted) {
var ball = balls[ballBeingDragged];
ball.currentPosition.x = dragVector.upX;
ball.currentPosition.y = dragVector.upY;
/* Now we estimate if the drag was towards the Target Point of the ball or not. */
var distDown = distance(dragVector.downX, dragVector.downY, ball.targetPosition.x, ball.targetPosition.y);
var distUp = distance(dragVector.upX, dragVector.upY, ball.targetPosition.x, ball.targetPosition.y);
var mZoomValue;
if (distDown < distUp) {
mZoomValue = 1;
} else {
mZoomValue = -1;
}
ball.container.zoom.mZoom(mZoomValue); // Zoom is applied to ball mass of all balls in the same container.
}
if (containerDragStarted || viewPortBeingDragged) {
/* The parameters received have been captured with zoom applied. We must remove the zoom in order to correctly modify the displacement. */
var downCopy = {
x: dragVector.downX,
y: dragVector.downY
};
var downCopyNoTransf;
downCopyNoTransf = viewPort.unzoomThisPoint(downCopy);
//downCopyNoTransf = containerBeingDragged.zoom.unzoomThisPoint(downCopyNoTransf);
var upCopy = {
x: dragVector.upX,
y: dragVector.upY
};
var upCopyNoTranf;
upCopyNoTranf = viewPort.unzoomThisPoint(upCopy);
//upCopyNoTranf = containerBeingDragged.zoom.unzoomThisPoint(upCopyNoTranf);
/*
let displaceVector = {
x: upCopyNoTranf.x - downCopyNoTransf.x,
y: upCopyNoTranf.y - downCopyNoTransf.y
};
*/
let displaceVector = {
x: dragVector.upX - dragVector.downX,
y: dragVector.upY - dragVector.downY
};
if (viewPortBeingDragged) {
viewPort.displace(displaceVector);
}
if (containerBeingDragged !== undefined) {
containerBeingDragged.frame.position.x = containerBeingDragged.frame.position.x + displaceVector.x;
containerBeingDragged.frame.position.y = containerBeingDragged.frame.position.y + displaceVector.y;
}
/*
if (containerBeingDragged.displacement.displace(diffX, diffY) === true) {
updateBallsTargets(); // TODO: this should not be here
} else
{
// If the displacement can not be performed, then we dont abort the dragging operation, just allow the user to move the mouse in some other direction.
}
*/
}
/* Finally we set the starting point of the new dragVector at this current point. */
dragVector.downX = dragVector.upX;
dragVector.downY = dragVector.upY;
}
}
function onMouseWheel(event) {
// cross-browser wheel delta
var event = window.event || event; // old IE support
var delta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail));
var ballIndex = isInside(event.pageX, event.pageY);
if (ballIndex >= 0) {
/* We need to apply the Radius zoom to the cointainer of the ball where the zoom was made, for that reason, we need the ball. */
balls[ballIndex].container.zoom.rZoom(delta); // Zoom is applied to ball radius.
} else {
/* We check if the mouse is over any of the existing containers. */
var point = {
x: event.pageX,
y: event.pageY
};
/*
var container = canvas.chartSpace.getContainer(point);
if (container !== undefined && container.isZoomeable === true) {
if (container.zoom.xyZoom(delta) === true) {
updateBallsTargets();
}
} */
viewPort.applyZoom(delta);
}
return false; // This instructs the browser not to take the event and scroll the page.
}
}