Initial commit

This commit is contained in:
Luis Fernando Molina committed 2018-11-16 12:22:37 +01:00
commit 9e6cd3c0aa
122 files changed
+16070

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
+7
View File
@@ -0,0 +1,7 @@
.vs/*
obj/*
bin/*
node_modules/*
this.server.config.json
+171
View File
@@ -0,0 +1,171 @@
function newAnimation() {
const MODULE_NAME = "Animation";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
/*
Essentially, what the animation object does, is to call several functions in order to draw the content of each frame.
To do that, it has an array of functions that need to be called, and it just goes one by one through them. His parent object
is responsible for providing more functions to call, or removing functions from its list when they are not longer needed.
*/
let animationLoopHandle; // This is the handle to the animation loop. With this handle we can cancel the loop, for instance.
let callBackFunctions = new Map();
let thisObject = {
start: start,
stop: stop,
addCallBackFunction: addCallBackFunction,
removeCallBackFunction: removeCallBackFunction,
initialize: initialize
};
return thisObject;
function initialize(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
/* Nothing to do here yet. */
callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function start(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] start -> Entering function."); }
animationLoop(); // Inside this function the animation process is started, and at the same time it creates a loop.
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] start -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function stop(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] stop -> Entering function."); }
window.cancelAnimationFrame(animationLoopHandle);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] stop -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function addCallBackFunction(key, callBack, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] addCallBackFunction -> Entering function."); }
callBackFunctions.set(key, callBack);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] addCallBackFunction -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function removeCallBackFunction(key, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] removeCallBackFunction -> Entering function."); }
callBackFunctions.delete(key);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] removeCallBackFunction -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function animationLoop() {
try {
if (INFO_LOG === true) { logger.write("[INFO] animationLoop -> Entering function."); }
if (window.canvasApp.visible === true) {
/* We set the canvas to its normal width and height */
browserCanvas.width = window.innerWidth;
browserCanvas.height = window.innerHeight - window.canvasApp.topMargin;
/* First thing is to clear the actual canvas */
clearBrowserCanvas();
/* We loop through the callback functions collections and execute them all. */
callBackFunctions.forEach(function (callBackFunction) {
callBackFunction();
});
} else {
browserCanvas.width = 1;
browserCanvas.height = 1;
}
/* We request the next frame to be drawn, and stablishing a loop */
animationLoopHandle = window.requestAnimationFrame(animationLoop);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] animationLoop -> err = " + err); }
}
}
function clearBrowserCanvas() {
if (INFO_LOG === true) { logger.write("[INFO] clearBrowserCanvas -> Entering function."); }
browserCanvasContext.beginPath();
browserCanvasContext.rect(0, 0, browserCanvas.width, browserCanvas.height);
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)';
browserCanvasContext.closePath();
browserCanvasContext.fill();
}
}
+130
View File
@@ -0,0 +1,130 @@
function newChartAspectRatio() {
let thisObject = {
aspectRatio: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
thisObject.container.frame.width = 50;
thisObject.container.frame.height = BOTTOM_SPACE_HEIGHT;
resize();
container.isDraggeable = false;
container.isClickeable = false;
container.isWheeleable = true;
thisObject.aspectRatio = {};
const INITIAL_Y_ASPECT_RATIO = 5 / 10;
const MIN_Y_ASPECT_RATIO = 1 / 10;
const MAX_Y_ASPECT_RATIO = 10 / 10;
thisObject.aspectRatio.x = 1;
thisObject.aspectRatio.y = INITIAL_Y_ASPECT_RATIO;
canDrawIcon = false;
return thisObject;
function initialize() {
icon = new Image();
icon.onload = onImageLoad;
function onImageLoad() {
canDrawIcon = true;
}
icon.src = window.canvasApp.urlPrefix + "Images/Icons/chart-scale.png";
thisObject.container.eventHandler.listenToEvent('Mouse Wheel', onMouseWheel);
window.canvasApp.eventHandler.listenToEvent("Browser Resized", resize);
}
function resize() {
container.frame.position.x = viewPort.visibleArea.topRight.x - thisObject.container.frame.width;
container.frame.position.y = viewPort.visibleArea.bottomLeft.y;
}
function onMouseWheel(pDelta) {
if (viewPort.isMinZoom() === false) { return; } // We only make this button to work at the min zoom level.
if (pDelta < 0) {
pDelta = -0.1;
} else {
pDelta = 0.1;
}
thisObject.aspectRatio.y = thisObject.aspectRatio.y + pDelta;
thisObject.aspectRatio.y = Math.round(thisObject.aspectRatio.y * 100) / 100;
if (thisObject.aspectRatio.y < MIN_Y_ASPECT_RATIO) {
thisObject.aspectRatio.y = MIN_Y_ASPECT_RATIO;
}
if (thisObject.aspectRatio.y > MAX_Y_ASPECT_RATIO) {
thisObject.aspectRatio.y = MAX_Y_ASPECT_RATIO;
}
thisObject.container.eventHandler.raiseEvent("Chart Aspect Ratio Changed", thisObject.aspectRatio);
}
function getContainer(point) {
let container;
/* First we check if this point is inside this object UI. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
}
function draw() {
thisObject.container.frame.draw(false, false);
if (canDrawIcon === false) { return; }
if (viewPort.isMinZoom() === false) { return; } // We only show this button at the min zoom level.
let breakpointsHeight = 15;
let imageHeight = 15;
let imageWidth = 15;
let imagePoint = {
x: 10,
y: thisObject.container.frame.height / 2 - imageHeight / 2 + breakpointsHeight
};
imagePoint = thisObject.container.frame.frameThisPoint(imagePoint);
browserCanvasContext.drawImage(icon, imagePoint.x, imagePoint.y, imageWidth, imageHeight);
}
}
+336
View File
@@ -0,0 +1,336 @@
function newDeleteTradingHistory() {
const MODULE_NAME = "Delete Trading History";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
var thisObject = {
container: undefined,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
};
var container = newContainer();
container.initialize();
thisObject.container = container;
thisObject.container.frame.width = 50;
thisObject.container.frame.height = BOTTOM_SPACE_HEIGHT;
resize();
container.isDraggeable = false;
container.isClickeable = true;
let icon;
let canDrawIcon = false;
return thisObject;
function initialize(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
icon = new Image();
icon.onload = onImageLoad;
function onImageLoad() {
canDrawIcon = true;
}
icon.src = window.canvasApp.urlPrefix + "Images/Icons/trash.png";
thisObject.container.eventHandler.listenToEvent("onMouseClick", onClick);
window.canvasApp.eventHandler.listenToEvent("Browser Resized", resize);
if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE); }
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err.message = " + err.message); }
if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE); }
}
}
function resize() {
container.frame.position.x = viewPort.visibleArea.topRight.x;
container.frame.position.y = viewPort.visibleArea.bottomLeft.y;
}
function onClick() {
try {
if (INFO_LOG === true) { logger.write("[INFO] onClick -> Entering function."); }
let sessionToken = window.localStorage.getItem('sessionToken');
if (sessionToken === null || sessionToken === "") {
/* not logged in */
return;
}
/*
To delete the trading history we will follow these steps:
1. Get the status report of that bot.
2. Iterate through all the entries for the startMode received by parameters.
3. For each entry, get the execution history file belonging to that entry.
4. Iterate on each entry of each execution history file to get the date of each execution that we will use to locate the
execution context file.
6. Delete every execution context file found.
7. Delete the execution history file after finishing the interation.
8. Delete the Sequence file belonging to the received Start Mode.
9. Save the Status Report without the records of this Start Mode.
*/
let storage = AzureStorage.Blob;
let readOnlyBlobService;
let writeOnlyBlobService;
let deleteOnlyBlobService;
let readConnectionString = window.USER_PROFILE.storagePermissions.get(window.DEV_TEAM + "." + "READ");
if (readConnectionString !== undefined) {
readOnlyBlobService = storage.createBlobService(readConnectionString);
}
let writeConnectionString = window.USER_PROFILE.storagePermissions.get(window.DEV_TEAM + "." + "WRITE");
if (writeConnectionString !== undefined) {
writeOnlyBlobService = storage.createBlobService(writeConnectionString);
}
let deleteConnectionString = window.USER_PROFILE.storagePermissions.get(window.DEV_TEAM + "." + "DELETE");
if (deleteConnectionString !== undefined) {
deleteOnlyBlobService = storage.createBlobService(deleteConnectionString);
}
let containerName = window.DEV_TEAM.toLowerCase();
let statusReportFilePath = window.DEV_TEAM + "/" + window.CURRENT_BOT_CODE_NAME + ".1.0" + "/" + "AACloud.1.1" + "/" + "Poloniex" + "/" + "dataSet.V1" + "/" + "Reports" + "/" + "Trading-Process";
let statusReportFileName = window.CURRENT_START_MODE + "." + "Status.Report.USDT_BTC.json";
readOnlyBlobService.getBlobToText(containerName, statusReportFilePath + "/" + statusReportFileName, onStatusReport);
function onStatusReport(err, text, response) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onClick -> onStatusReport -> Entering function."); }
if (err && err.code === 'BlobNotFound') {
console.log(statusReportFilePath + "/" + statusReportFileName + " not found. No history detected for this start mode.");
return;
}
let statusReport = JSON.parse(text);
let toBeDeleted = 0;
let deleted = 0;
for (let i = 0; i < statusReport.runs.length; i++) {
/* For each record, we will get the execution history file. */
let filePath = window.DEV_TEAM + "/" + window.CURRENT_BOT_CODE_NAME + ".1.0" + "/" + "AACloud.1.1" + "/" + "Poloniex" + "/" + "dataSet.V1" + "/" + "Output" + "/" + "Trading-Process";
let fileName = "Execution.History." + window.CURRENT_START_MODE + "." + i + ".json";
readOnlyBlobService.getBlobToText(containerName, filePath + "/" + fileName, onExecutionHistory);
function onExecutionHistory(err, text, response) {
let executionHistory = JSON.parse(text);
for (let j = 0; j < executionHistory.length; j++) {
let dateTime = new Date(executionHistory[j][0]);
let datePath = dateTime.getUTCFullYear() + "/" + pad(dateTime.getUTCMonth() + 1, 2) + "/" + pad(dateTime.getUTCDate(), 2) + "/" + pad(dateTime.getUTCHours(), 2) + "/" + pad(dateTime.getUTCMinutes(), 2);
let filePath = window.DEV_TEAM + "/" + window.CURRENT_BOT_CODE_NAME + ".1.0" + "/" + "AACloud.1.1" + "/" + "Poloniex" + "/" + "dataSet.V1" + "/" + "Output" + "/" + "Trading-Process" + "/" + datePath;
let fileName = "Execution.Context." + window.CURRENT_START_MODE + "." + i + ".json";
deleteOnlyBlobService.deleteBlob(containerName, filePath + "/" + fileName, onDeleted);
toBeDeleted++;
function onDeleted(err, text, response) {
if (err) {
console.log(filePath + "/" + fileName + " NOT deleted.");
console.log("err.message = " + err.message);
} else {
console.log(filePath + "/" + fileName + " deleted.");
}
deleted++;
if (toBeDeleted === deleted) {
updateStatusReport();
}
}
}
/* Now we delete the execution history file. */
deleteOnlyBlobService.deleteBlob(containerName, filePath + "/" + fileName, onExecutionHistoryDeleted);
function onExecutionHistoryDeleted(err, text, response) {
console.log(filePath + "/" + fileName + " deleted.");
}
}
}
function updateStatusReport() {
try {
if (INFO_LOG === true) { logger.write("[INFO] onClick -> onStatusReport -> updateStatusReport -> Entering function."); }
statusReport.runs = [];
/* Here is where we update the current Status Report file with the new version without records for the current Start Mode. */
let fileContent = JSON.stringify(statusReport);
writeOnlyBlobService.createBlockBlobFromText(containerName, statusReportFilePath + "/" + statusReportFileName, fileContent, onStatusReportUpdated);
function onStatusReportUpdated(err, text, response) {
console.log(statusReportFilePath + "/" + statusReportFileName + " updated.");
}
/* Finally we delete the sequence file. */
let filePath = window.DEV_TEAM + "/" + window.CURRENT_BOT_CODE_NAME + ".1.0" + "/" + "AACloud.1.1" + "/" + "Poloniex" + "/" + "dataSet.V1" + "/" + "Output" + "/" + "Trading-Process";
let fileName = "Execution.History." + window.CURRENT_START_MODE + "." + "Sequence" + ".json";
deleteOnlyBlobService.deleteBlob(containerName, filePath + "/" + fileName, onDeleted);
function onDeleted(err, text, response) {
console.log(filePath + "/" + fileName + " deleted.");
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onClick -> onStatusReport -> updateStatusReport -> err.message = " + err.message); }
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onClick -> onStatusReport -> err.message = " + err.message); }
}
}
function pad(str, max) {
str = str.toString();
return str.length < max ? pad("0" + str, max) : str;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onClick -> err.message = " + err.message); }
}
}
function getContainer(point) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getContainer -> Entering function."); }
let container;
/* First we check if this point is inside this object UI. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getContainer -> err.message = " + err.message); }
}
}
function draw() {
try {
if (INFO_LOG === true) { logger.write("[INFO] draw -> Entering function."); }
let sessionToken = window.localStorage.getItem('sessionToken');
if (sessionToken === null || sessionToken === "") {
/* not logged in */
return;
}
thisObject.container.frame.draw(false, false);
if (canDrawIcon === false) { return; }
let breakpointsHeight = 14;
let imageHeight = 15;
let imageWidth = 15;
let imagePoint = {
x: 10,
y: thisObject.container.frame.height / 2 - imageHeight / 2 + breakpointsHeight
};
imagePoint = thisObject.container.frame.frameThisPoint(imagePoint);
browserCanvasContext.drawImage(icon, imagePoint.x, imagePoint.y, imageWidth, imageHeight);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err.message = " + err.message); }
}
}
}
+164
View File
@@ -0,0 +1,164 @@
function newPlayStopButton() {
var thisObject = {
container: undefined,
setDatetime: setDatetime,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
};
var container = newContainer();
container.initialize();
thisObject.container = container;
thisObject.container.frame.width = 50;
thisObject.container.frame.height = BOTTOM_SPACE_HEIGHT;
resize();
container.isDraggeable = false;
container.isClickeable = true;
let play;
let stop;
let canDraw = false;
let showing = "Play";
let image;
let datetime;
let timePeriod;
return thisObject;
function initialize() {
play = new Image();
play.onload = onImageLoad;
function onImageLoad() {
image = play;
canDraw = true;
}
play.src = window.canvasApp.urlPrefix + "Images/Icons/play.png";
stop = new Image();
stop.src = window.canvasApp.urlPrefix + "Images/Icons/pause.png";
thisObject.container.eventHandler.listenToEvent("onMouseClick", onClick);
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
timePeriod = INITIAL_TIME_PERIOD;
window.canvasApp.eventHandler.listenToEvent("Browser Resized", resize);
}
function resize() {
container.frame.position.x = viewPort.visibleArea.topLeft.x + 150 * 4;
container.frame.position.y = viewPort.visibleArea.bottomLeft.y;
}
function onClick() {
let sessionToken = window.localStorage.getItem('sessionToken');
if (sessionToken === null || sessionToken === "") {
/* not logged in */
return;
}
switch (showing) {
case "Play": {
image = stop;
showing = "Stop";
let UI_COMMANDS = {
beginDatetime: datetime,
endDatetime: undefined,
timePeriod: timePeriod,
startMode: window.CURRENT_START_MODE,
eventHandler: thisObject.container.eventHandler
};
cloudVM.onBotPlayPressed(UI_COMMANDS);
break;
}
case "Stop": {
image = play;
showing = "Play";
cloudVM.onBotStopPressed();
break;
}
}
}
function onZoomChanged(event) {
timePeriod = recalculatePeriod(event.newLevel);
}
function setDatetime(pDatetime) {
datetime = new Date(pDatetime);
}
function getContainer(point) {
let container;
/* First we check if this point is inside this object UI. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
}
function draw() {
let sessionToken = window.localStorage.getItem('sessionToken');
if (sessionToken === null || sessionToken === "") {
/* not logged in */
return;
}
thisObject.container.frame.draw(false, false);
let breakpointsHeight = 14;
if (canDraw === false) { return; }
let imageHeight = 20;
let imageWidth = 20;
let imagePoint = {
x: thisObject.container.frame.width / 2 - imageWidth / 2,
y: thisObject.container.frame.height / 2 - imageHeight / 2 + breakpointsHeight
};
imagePoint = thisObject.container.frame.frameThisPoint(imagePoint);
browserCanvasContext.drawImage(image, imagePoint.x, imagePoint.y, imageWidth, imageHeight);
}
}
+219
View File
@@ -0,0 +1,219 @@
function newBreakpointsBar() {
var thisObject = {
setDatetime: setDatetime,
container: undefined,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
};
var container = newContainer();
container.initialize();
thisObject.container = container;
thisObject.container.frame.width = browserCanvasContext.width;
thisObject.container.frame.height = 15;
container.frame.position.x = 0;
container.frame.position.y = viewPort.visibleArea.bottomRight.y;
container.isDraggeable = false;
container.isClickeable = true;
let logo;
let canDrawLogo = false;
let datetime;
let timePeriod;
let timeLineCoordinateSystem;
let chartContainer;
let breakpointsByTimePeriod = new Map();
return thisObject;
function initialize(pChartContainer, pTimeLineCoordinateSystem) {
timeLineCoordinateSystem = pTimeLineCoordinateSystem;
chartContainer = pChartContainer;
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
timePeriod = INITIAL_TIME_PERIOD;
thisObject.container.eventHandler.listenToEvent("onMouseClick", onClick);
for (let i = 0; i < marketFilesPeriods.length; i++) {
let breakpointsMap = new Map();
breakpointsByTimePeriod.set(marketFilesPeriods[i][0], breakpointsMap);
}
for (let i = 0; i < dailyFilePeriods.length; i++) {
let breakpointsMap = new Map();
breakpointsByTimePeriod.set(dailyFilePeriods[i][0], breakpointsMap);
}
}
function onClick(pPoint) {
let point = {
x: pPoint.x,
y: pPoint.y
};
let miliSeconds = getMilisecondsFromPoint(point, chartContainer, timeLineCoordinateSystem);
miliSeconds = normalizeX(miliSeconds); // We are now exactly at the middle of the "candle" correspondind to the point clicked.
let breakpointsMap = breakpointsByTimePeriod.get(timePeriod);
let breakpoint = breakpointsMap.get(miliSeconds);
if (breakpoint === undefined) {
/* The breakpoint didnt exist, then we create one. */
breakpointsMap.set(miliSeconds, 1);
} else {
/* The breakpoint existed, so we remove it. */
breakpointsMap.set(miliSeconds, undefined);
}
}
function normalizeX(pX) {
return Math.trunc(pX / timePeriod) * timePeriod + timePeriod / 2;
}
function onZoomChanged(event) {
timePeriod = recalculatePeriod(event.newLevel);
}
function setDatetime(pDatetime) {
datetime = new Date(pDatetime);
}
function getContainer(point) {
let container;
/* First we check if this point is inside this object UI. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
}
function draw() {
/*
To draw the breakpoints, we will calculate the miliseconds for the first x pixel of the breakpoint bar, and for the last x pixel. Once we have that
we can create an array with all the possible points for breack points. Finally we can see if brealpoints exists at those points. We plot only the ones
that exists.
*/
let breakpointsMap = breakpointsByTimePeriod.get(timePeriod);
let beginX = {
x: viewPort.visibleArea.bottomLeft.x,
y: 0
};
let endX = {
x: viewPort.visibleArea.bottomRight.x,
y: 0
};
let beginMiliseconds = getMilisecondsFromPoint(beginX, chartContainer, timeLineCoordinateSystem);
let endMiliseconds = getMilisecondsFromPoint(endX, chartContainer, timeLineCoordinateSystem);
beginMiliseconds = normalizeX(beginMiliseconds);
endMiliseconds = normalizeX(endMiliseconds);
window.AT_BREAKPOINT = false;
for (let miliSeconds = beginMiliseconds; miliSeconds < endMiliseconds; miliSeconds = miliSeconds + timePeriod) {
let breakpoint = breakpointsMap.get(miliSeconds);
if (breakpoint !== undefined) {
let point1 = {
x: miliSeconds,
y: 0
}
point1 = timeLineCoordinateSystem.transformThisPoint(point1);
point1 = transformThisPoint(point1, chartContainer);
let point2 = {
x: miliSeconds,
y: thisObject.container.frame.height / 2 + 1
}
point2 = thisObject.container.frame.frameThisPoint(point2);
let point = {
x: point1.x,
y: point2.y
}
let isCurrentRecord = false;
if (datetime !== undefined) {
let dateValue = datetime.valueOf();
if (dateValue >= miliSeconds - timePeriod / 2 && dateValue <= miliSeconds + timePeriod / 2 - 1) {
isCurrentRecord = true;
}
}
let radius = 5;
let opacity = '0.5';
browserCanvasContext.lineWidth = 1;
/* Outer Circle */
browserCanvasContext.beginPath();
browserCanvasContext.strokeStyle = 'rgba(123, 50, 40, ' + opacity + ')';
if (isCurrentRecord === false) {
browserCanvasContext.fillStyle = 'rgba(223, 70, 60, ' + opacity + ')';
} else {
browserCanvasContext.fillStyle = 'rgba(255, 233, 31, ' + opacity + ')'; /* highlight the current record */
window.AT_BREAKPOINT = true; // We are hitting a breakpoint!
}
browserCanvasContext.arc(point.x, point.y, radius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
if (point.x < viewPort.visibleArea.topLeft.x + 50 || point.x > viewPort.visibleArea.bottomRight.x - 50) {/*we leave this history without fill. */ } else {
browserCanvasContext.fill();
}
browserCanvasContext.stroke();
}
}
}
}
+46
View File
@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at feedback at advancedalgos dot org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+51
View File
@@ -0,0 +1,51 @@
# Contributing
We are thrilled you are interested in contributing to the CanvasApp. Your help may be essential to the project's success and we want you in!
Advanced Algos is a startup, currently at a very early stage. Although CanvasApp is not open source software yet, we do welcome contributions from the community.
Contributions are deemed _work for hire_ and --as such-- are compensated on a case by case basis, with ALGO tokens. Contributors agree to provide an express grant of patent rights for their contributions. Our Balanced Contributor Intellectual Property Agreement is a direct implementation of GitHub's [Balanced Employee Intellectual Property Agreement 1.0.1](https://github.com/github/balanced-employee-ip-agreement/blob/master/Balanced_Employee_IP_Agreement.md).
# Balanced Contributor Intellectual Property Agreement 1.0.1
This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person named below and Advanced Algos ("Company").
**What is this?** This is the Company's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Company.
**Why is this?** The Company needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Company having the legal rights to the products and services it is providing so that the Company can continue operating and doing business.
The Company also believes that it's important to be clear on what it doesn't own. The Company doesn't want you looking over your shoulder every time you work on something personal or worrying that the Company will someday seize your open source non-lethal mousetrap simulation software. In other words, the Company isn't interested in appropriating your personal projects.
**Read this.** Please read this document and be sure you understand it before you sign it. Due to legal risk and corporate obligations, the Company cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Company's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on.
Cool? Then, by signing this Agreement, and as a condition of your contribution, you agree to the following:
1. **What the Company owns.** The Company owns any IP ("Company IP") that you create, or help create _as its contributor or contractor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Company product or service at the time you developed, invented, or created it, (ii) developed for use by the Company, or (iii) developed or promoted with existing Company IP or with the Company's endorsement. You hereby grant and assign, and will grant and assign, to the Company all rights and interests in all Company IP.
"Company IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship.
2. **What the Company doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Company doesn't own it. In other words, the Company doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1. This is true regardless of the computer you use to develop your IP, including the one furnished to you by the Company.
3. **Contribution of your IP to Company projects.** If you include your own IP – such as IP you created prior to working for the Company – into a Company product or service, it's still yours, of course, but you grant the Company a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Company would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well.
4. **Your contributions to non-Company projects.** The Company recognizes that you may be engaged in work that requires you to submit IP to entities other than the Company, such as open source projects used by the Company. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Company and so should be run through Legal first.
5. **Works made for hire.** All Company IP that you are involved with or create as part of your work for the Company is [work made for hire](http://www.copyright.gov/circs/circ09.pdf) under copyright law and compensated by your regular salary or pay.
6. **No conflicts.** You agree that you don't have any outstanding agreements or obligations that conflict with those in this Agreement, and that you won't enter into conflicting agreements in the future.
7. **IP protection.** The Company might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Company IP or IP under License (together, "All IP"), and, if the Company asks, to provide those records to the Company. You agree to help the Company secure and defend its rights in All IP, including after you leave the Company. For your help the Company will compensate you at a reasonable rate. If the Company is unable to secure your help, you authorize the Company to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP.
8. **Confidentiality.** As an contributor or contractor of the Company, you will have access to sensitive confidential information that is important to the Company's business. You are responsible for keeping this information confidential, including after you end your work for the Company.
"Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Company because it is not publicly known.
The Company's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Company's Confidential Information for the purpose of performing your job and for the benefit of the Company. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise.
Print Name: _____________
Sign: ________________
Date: ________________
+17
View File
@@ -0,0 +1,17 @@
function newCandle() {
var candle = {
open: undefined,
close: undefined,
min: 10000000000000,
max: 0,
begin: undefined,
end: undefined,
direction: undefined,
beginId: undefined,
endId: undefined
};
return candle;
}
+741
View File
@@ -0,0 +1,741 @@
let 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() {
const MODULE_NAME = "Canvas";
const INFO_LOG = false;
const ERROR_LOG = true;
const INTENSIVE_LOG = false;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
/* Mouse event related variables. */
let containerDragStarted = false;
let floatingObjectDragStarted = false;
let floatingObjectBeingDragged;
let containerBeingDragged;
let viewPortBeingDragged = false;
let dragVector = {
downX: 0,
downY: 0,
upX: 0,
upY: 0
};
/* canvas object */
let thisObject = {
eventHandler: undefined,
topSpace: undefined,
chartSpace: undefined,
floatingSpace: undefined,
panelsSpace: undefined,
bottomSpace: undefined,
animation: undefined,
initialize: initialize
};
thisObject.eventHandler = newEventHandler();
let splashScreen;
return thisObject;
/*
The canvas object represents a layer on top of the browser canvas object.
Graphically, thiscanvas object has 4 spaces:
1. The "Top Space": It is where Team and User information is displayed.
2. The "Chart Space": It is where the charts are plotted.
3. The "Floating Space": It is where floating elements live. There is a physics engine for this layer that allows these elements to flow.
4. The "Panels Space": It is where panels live. --> This space has yet to be develop, currently pannels are somehow at the Chart Space.
5. The "Bottom Space": Includes the breakpoint bar and a toolbar.
All these spaces are child objects of the Canvas object.
Canvas
|
|
---> topSpace
|
|
---> chartSpace
|
|
---> flaotingSpace
|
|
---> panelsSpace
|
|
---> bottomSpace
*/
function initialize(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
initializeBrowserCanvas();
addCanvasEvents();
/* Instantiate all the children spaces of Canvas object */
thisObject.topSpace = newTopSpace();
thisObject.topSpace.initialize();
thisObject.bottomSpace = newBottomSpace();
thisObject.bottomSpace.initialize();
thisObject.panelsSpace = newPanelsSpace();
thisObject.panelsSpace.initialize();
thisObject.floatingSpace = newFloatingSpace();
thisObject.floatingSpace.initialize();
thisObject.chartSpace = newChartSpace();
thisObject.chartSpace.initialize(onCharSpaceInitialized);
function onCharSpaceInitialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCharSpaceInitialized -> Entering function."); }
viewPort.raiseEvents(); // These events will impacts on objects just initialized.
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onCharSpaceInitialized -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
/* Splash Screen */
splashScreen = newSplashScreen();
splashScreen.initialize();
let animation = newAnimation();
animation.initialize(onAnimationInitialized);
function onAnimationInitialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onAnimationInitialized -> Entering function."); }
thisObject.animation = animation;
/* Here we add all the functions that will be called during the animation cycle. */
animation.addCallBackFunction("Chart Space", thisObject.chartSpace.draw, onFunctionAdded);
animation.addCallBackFunction("Floating Space", thisObject.floatingSpace.floatingLayer.physicsLoop, onFunctionAdded);
animation.addCallBackFunction("Panels Space", thisObject.panelsSpace.draw, onFunctionAdded);
animation.addCallBackFunction("Splash Screen", splashScreen.draw, onFunctionAdded);
animation.addCallBackFunction("ViewPort Animate", viewPort.animate, onFunctionAdded);
animation.addCallBackFunction("ViewPort Draw", viewPort.draw, onFunctionAdded);
animation.addCallBackFunction("Bottom Space", thisObject.bottomSpace.draw, onFunctionAdded);
animation.addCallBackFunction("Top Space", thisObject.topSpace.draw, onFunctionAdded);
animation.start(onStart);
function onFunctionAdded(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onAnimationInitialized -> onFunctionAdded -> Entering function."); }
if (err.result === GLOBAL.DEFAULT_FAIL_RESPONSE.result) {
animation.stop();
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onAnimationInitialized -> onFunctionAdded -> Animation Stopped since a vital funtion could not be added."); }
/* Display some Error Page here. */
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onAnimationInitialized -> onFunctionAdded -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function onStart(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onAnimationInitialized -> onStart -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onAnimationInitialized -> onStart -> Received OK Response."); }
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
return;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onAnimationInitialized -> onStart -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onAnimationInitialized -> onStart -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onAnimationInitialized -> onStart -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onAnimationInitialized -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function initializeBrowserCanvas() {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeBrowserCanvas -> Entering function."); }
browserCanvasContext = browserCanvas.getContext('2d');
viewPort.initialize();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeBrowserCanvas -> err = " + err); }
}
}
function addCanvasEvents() {
try {
if (INFO_LOG === true) { logger.write("[INFO] addCanvasEvents -> Entering function."); }
/* 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);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] addCanvasEvents -> err = " + err); }
}
}
function onMouseDown(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onMouseDown -> Entering function."); }
/*
There are four types of elements that can be dragged.
1. Panels.
2. Floating Elements (Currently only FloatingObjects).
3. Charts.
4. The Viewport.
We eveluate each space in order to see if they are holding the element being dragged, and we fallout at the Viewport.
*/
let point = {
x: event.pageX,
y: event.pageY - window.canvasApp.topMargin
};
dragVector.downX = point.x;
dragVector.downY = point.y;
let container;
/* We check if the mouse is over an element of the Top Space / */
container = thisObject.topSpace.getContainer(point);
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container;
containerDragStarted = true;
return;
}
/* We check if the mouse is over an element of the Bottom Space / */
container = thisObject.bottomSpace.getContainer(point);
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container;
containerDragStarted = true;
return;
}
/* We check if the mouse is over a panel/ */
container = thisObject.panelsSpace.getContainer(point);
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container;
containerDragStarted = true;
return;
}
/* We check if the mouse is over a floatingObject/ */
floatingObjectBeingDragged = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y);
if (floatingObjectBeingDragged >= 0) {
floatingObjectDragStarted = true;
return;
}
/* If it is not, then we check if it is over any of the existing containers at the Chart Space. */
container = thisObject.chartSpace.getContainer(point);
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container;
containerDragStarted = true;
return;
}
viewPortBeingDragged = true;
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMouseDown -> err = " + err); }
}
}
function onMouseClick(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onMouseClick -> Entering function."); }
let point = {
x: event.pageX,
y: event.pageY - window.canvasApp.topMargin
};
let container;
/* We check if the mouse is over an element of the Top Space / */
container = thisObject.topSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point);
return;
}
/* We check if the mouse is over an element of the Bottom Space / */
container = thisObject.bottomSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point);
return;
}
/* We check if the mouse is over a panel/ */
container = thisObject.panelsSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point);
return;
}
/* We check if the mouse is over a floatingObject/ */
let floatingObjectBeingClicked = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y);
if (floatingObjectBeingClicked >= 0) {
let floatingObject = thisObject.floatingSpace.floatingLayer.getFloatingObject(undefined, floatingObjectBeingClicked);
floatingObject.eventHandler.raiseEvent('onMouseClick', point);
return;
}
/* If it is not, then we check if it is over any of the existing containers at the Chart Space. */
container = thisObject.chartSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point);
return;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMouseClick -> err = " + err); }
}
}
function onMouseUp(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onMouseUp -> Entering function."); }
if (containerDragStarted || viewPortBeingDragged || floatingObjectDragStarted) {
thisObject.eventHandler.raiseEvent("Drag Finished", undefined);
}
/* Turn off all the possible things that can be dragged. */
containerDragStarted = false;
floatingObjectDragStarted = false;
viewPortBeingDragged = false;
containerBeingDragged = undefined;
browserCanvas.style.cursor = "auto";
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMouseUp -> err = " + err); }
}
}
function onMouseMove(event) {
try {
if (INTENSIVE_LOG === true) { logger.write("[INFO] onMouseMove -> Entering function."); }
let point = {
x: event.pageX,
y: event.pageY - window.canvasApp.topMargin
};
viewPort.mousePosition.x = point.x;
viewPort.mousePosition.y = point.y;
if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) {
if (floatingObjectDragStarted === true) {
if (thisObject.floatingSpace.floatingLayer.isInsideFloatingObject(floatingObjectBeingDragged, point.x, point.y) === false) {
/* This means that the user stop moving the mouse and the floatingObject floatingObject out of the pointer.
In this case we cancell the drag operation . */
floatingObjectDragStarted = false;
browserCanvas.style.cursor = "auto";
return;
}
}
dragVector.upX = point.x;
dragVector.upY = point.y;
checkDrag(event);
} else {
onMouseOver(event);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMouseMove -> err = " + err); }
}
}
function onMouseOver(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onMouseOver -> Entering function."); }
/* First we raise the event signaling theat the mouse is potentially over another item, so that the current item can turn itself off. */
thisObject.eventHandler.raiseEvent("onMouseNotOver");
/* Then we check who is the current object underneeth the mounse. */
let point = {
x: event.pageX,
y: event.pageY - window.canvasApp.topMargin
};
let container;
/* We check if the mouse is over an element of the Top Space / */
container = thisObject.topSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseOver', point);
return;
}
/* We check if the mouse is over an element of the Bottom Space / */
container = thisObject.bottomSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseOver', point);
return;
}
/* We check if the mouse is over a panel/ */
container = thisObject.panelsSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseOver', point);
return;
}
/* We check if the mouse is over a floatingObject/ */
let floatingObjectBeingClicked = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y);
if (floatingObjectBeingClicked >= 0) {
let floatingObject = thisObject.floatingSpace.floatingLayer.getFloatingObject(undefined, floatingObjectBeingClicked);
floatingObject.eventHandler.raiseEvent('onMouseOver', point);
return;
}
/* If it is not, then we check if it is over any of the existing containers at the Chart Space. */
container = thisObject.chartSpace.getContainer(point);
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseOver', point);
return;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMouseOver -> err = " + err); }
}
}
function onMouseWheel(event) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onMouseWheel -> Entering function."); }
// cross-browser wheel delta
var event = window.event || event; // old IE support
let delta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail));
/* We try first with panels. */
let point = {
x: event.pageX,
y: event.pageY - window.canvasApp.topMargin
};
let panelContainer = canvas.panelsSpace.getContainer({ x: point.x, y: point.y });
if (panelContainer !== undefined && panelContainer.isWheelable === true) {
panelContainer.eventHandler.raiseEvent("Mouse Wheel", event.wheelDelta);
return false; // This instructs the browser not to take the event and scroll the page.
}
/* We try second with floating objects. */
let floatingObjectIndex = canvas.floatingSpace.floatingLayer.isInside(point.x, point.y);
if (floatingObjectIndex > 0) {
canvas.floatingSpace.floatingLayer.changeTargetRepulsion(event.wheelDelta);
return false; // This instructs the browser not to take the event and scroll the page.
}
/* We try the Bottom Space. */
let bottomContainer = canvas.bottomSpace.getContainer({ x: point.x, y: point.y });
if (bottomContainer !== undefined && bottomContainer.isWheeleable === true) {
bottomContainer.eventHandler.raiseEvent("Mouse Wheel", event.wheelDelta);
return false; // This instructs the browser not to take the event and scroll the page.
}
/* Finally we try the Chart Space. */
let chartContainer = canvas.chartSpace.getContainer({ x: point.x, y: point.y });
if (chartContainer !== undefined && chartContainer.isWheeleable === true) {
chartContainer.eventHandler.raiseEvent("Mouse Wheel", event.wheelDelta);
return false; // This instructs the browser not to take the event and scroll the page.
} else {
/* If all the above fails, we fallback into applying zoom to the viewPort */
viewPort.applyZoom(delta);
return false; // This instructs the browser not to take the event and scroll the page.
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onMouseWheel -> err = " + err); }
}
}
function checkDrag(event) {
try {
if (INTENSIVE_LOG === true) { logger.write("[INFO] checkDrag -> Entering function."); }
if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) {
let point = {
x: event.pageX,
y: event.pageY - window.canvasApp.topMargin
};
browserCanvas.style.cursor = "grabbing";
thisObject.eventHandler.raiseEvent("Dragging", undefined);
let targetFloatingObject = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y);
if (floatingObjectDragStarted) {
let floatingObject = thisObject.floatingSpace.floatingLayer.getFloatingObject(undefined, floatingObjectBeingDragged);
floatingObject.currentPosition.x = dragVector.upX;
floatingObject.currentPosition.y = dragVector.upY;
}
if (containerDragStarted || viewPortBeingDragged) {
/* The parameters received have been captured with zoom applied. We must remove the zoom in order to correctly modify the displacement. */
let downCopy = {
x: dragVector.downX,
y: dragVector.downY
};
let downCopyNoTransf;
downCopyNoTransf = viewPort.unzoomThisPoint(downCopy);
//downCopyNoTransf = containerBeingDragged.zoom.unzoomThisPoint(downCopyNoTransf);
let upCopy = {
x: dragVector.upX,
y: dragVector.upY
};
let upCopyNoTranf;
upCopyNoTranf = viewPort.unzoomThisPoint(upCopy);
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;
}
}
/* Finally we set the starting point of the new dragVector at this current point. */
dragVector.downX = dragVector.upX;
dragVector.downY = dragVector.upY;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] checkDrag -> err = " + err); }
}
}
}
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "Project", "Project.njsproj", "{3EF11619-DE26-4B8B-819D-A413DF220B76}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3EF11619-DE26-4B8B-819D-A413DF220B76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EF11619-DE26-4B8B-819D-A413DF220B76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EF11619-DE26-4B8B-819D-A413DF220B76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EF11619-DE26-4B8B-819D-A413DF220B76}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {92DF2F3B-B37A-407F-B313-3897AEFCCAFC}
EndGlobalSection
EndGlobal
+150
View File
@@ -0,0 +1,150 @@
function getSideDays(timePeriod) {
let daysOnSides;
if (timePeriod < _1_HOUR_IN_MILISECONDS) {
daysOnSides = 1;
}
if (timePeriod === _1_HOUR_IN_MILISECONDS) {
daysOnSides = 9;
}
if (timePeriod === _2_HOURS_IN_MILISECONDS) {
daysOnSides = 10;
}
if (timePeriod === _3_HOURS_IN_MILISECONDS) {
daysOnSides = 12;
}
if (timePeriod === _4_HOURS_IN_MILISECONDS) {
daysOnSides = 20;
}
if (timePeriod === _6_HOURS_IN_MILISECONDS) {
daysOnSides = 35;
}
if (timePeriod === _8_HOURS_IN_MILISECONDS) {
daysOnSides = 44;
}
if (timePeriod === _12_HOURS_IN_MILISECONDS) {
daysOnSides = 56;
}
if (timePeriod === ONE_DAY_IN_MILISECONDS) {
daysOnSides = 154;
}
return daysOnSides;
}
function getCondenseFactor(timePeriod) {
switch (timePeriod) {
case _1_MINUTE_IN_MILISECONDS: return 1;
case _5_MINUTES_IN_MILISECONDS: return 5;
case _10_MINUTES_IN_MILISECONDS: return 10;
case _30_MINUTES_IN_MILISECONDS: return 50;
case _1_HOUR_IN_MILISECONDS: return 100;
}
}
function getTransparenceFactor(timePeriod) {
switch (timePeriod) {
case _1_MINUTE_IN_MILISECONDS: return "0.12";
case _5_MINUTES_IN_MILISECONDS: return "0.10";
case _10_MINUTES_IN_MILISECONDS: return "0.08";
case _30_MINUTES_IN_MILISECONDS: return "0.06";
case _1_HOUR_IN_MILISECONDS: return "0.04";
}
}
function recalculatePeriod(zoomLevel) {
//console.log(" recalculatePeriod > " + zoomLevel);
if (zoomLevel > 200) {
return _1_MINUTE_IN_MILISECONDS;
}
if (zoomLevel > 120) {
return _2_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > 80) {
return _3_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > 60) {
return _4_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > 15) {
return _5_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > - 7) {
return _10_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > - 10) {
return _15_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > - 13) {
return _20_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > - 15) {
return _30_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > - 16) {
return _40_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > - 17) {
return _45_MINUTES_IN_MILISECONDS;
}
if (zoomLevel > - 18) {
return _1_HOUR_IN_MILISECONDS;
}
if (zoomLevel > - 24) {
return _2_HOURS_IN_MILISECONDS;
}
if (zoomLevel > - 25) {
return _3_HOURS_IN_MILISECONDS;
}
if (zoomLevel > - 27) {
return _4_HOURS_IN_MILISECONDS;
}
if (zoomLevel > - 27.5) {
return _6_HOURS_IN_MILISECONDS;
}
if (zoomLevel > - 27.75) {
return _8_HOURS_IN_MILISECONDS;
}
if (zoomLevel > - 28) {
return _12_HOURS_IN_MILISECONDS;
}
if (zoomLevel <= - 28) {
return ONE_DAY_IN_MILISECONDS;
}
}
+61
View File
@@ -0,0 +1,61 @@
function newCloudRequire(bot, logger) {
const INFO_LOG = true;
const LOG_FILE_CONTENT = false;
const MODULE_NAME = "Cloud Require";
let thisObject = {
downloadBot: downloadBot,
downloadCommons: downloadCommons
};
return thisObject;
function downloadBot(pCloudStorage, pFilePath, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write(MODULE_NAME, "[INFO] downloadBot -> Entering function."); }
let filePath = window.canvasApp.urlPrefix + "Bots" + "/" + pFilePath + "/" + "User.Bot.js";
downloadModule(filePath, onDownloaded)
function onDownloaded(pModule) {
callBackFunction(window.DEFAULT_OK_RESPONSE, pModule);
return;
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] downloadBot -> err = " + err.message);
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
}
}
function downloadCommons(pCloudStorage, pFilePath, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write(MODULE_NAME, "[INFO] downloadCommons -> Entering function."); }
let filePath = window.canvasApp.urlPrefix + "Bots" + "/" + pFilePath + "/" + "Commons.js";
downloadModule(filePath, onDownloaded)
function onDownloaded(pModule) {
callBackFunction(window.DEFAULT_OK_RESPONSE, pModule);
return;
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] downloadCommons -> err = " + err.message);
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
}
}
};
+143
View File
@@ -0,0 +1,143 @@
/*
This module is for enabling the AACloud to run at the browser.
When running at the clode on NodeJS some things work diffently that at the browser. That gap will be fixed by the functions at this module.
*/
function webRequire(pModulePath) {
switch (pModulePath) {
case './AzureStorage': {
let MODULE = {};
MODULE.newAzureStorage = newAzureStorage;
return MODULE;
function newAzureStorage() {
return AzureStorage.Blob;
}
}
case './EventHandler': {
let MODULE = {};
MODULE.newEventHandler = newEventHandler;
return MODULE;
}
case './BlobStorage': {
let MODULE = {};
MODULE.newBlobStorage = newBlobStorage;
return MODULE;
}
case './DebugLog': {
let MODULE = {};
MODULE.newDebugLog = newDebugLog;
return MODULE;
}
case './TradingBotProcessMainLoop': {
let MODULE = {};
MODULE.newTradingBotProcessMainLoop = newTradingBotProcessMainLoop;
return MODULE;
}
case './ExtractionBotProcessMainLoop': {
let MODULE = {};
MODULE.newExtractionBotProcessMainLoop = newExtractionBotProcessMainLoop;
return MODULE;
}
case './IndicatorBotProcessMainLoop': {
let MODULE = {};
MODULE.newIndicatorBotProcessMainLoop = newIndicatorBotProcessMainLoop;
return MODULE;
}
case './CloudUtilities': {
let MODULE = {};
MODULE.newCloudUtilities = newCloudUtilities;
return MODULE;
}
case './PoloniexAPIClient': {
let MODULE = {};
MODULE.newPoloniexAPIClient = newPoloniexAPIClient;
return MODULE;
}
case './Exchange/ExchangeAPI': {
let MODULE = {};
MODULE.newExchangeAPI = newExchangeAPI;
return MODULE;
}
case './Context': {
let MODULE = {};
MODULE.newContext = newContext;
return MODULE;
}
case './Assistant': {
let MODULE = {};
MODULE.newAssistant = newAssistant;
return MODULE;
}
case './StatusReport': {
let MODULE = {};
MODULE.newStatusReport = newStatusReport;
return MODULE;
}
case './DataSet': {
let MODULE = {};
MODULE.newDataSet = newDataSet;
return MODULE;
}
case './StatusDependencies': {
let MODULE = {};
MODULE.newStatusDependencies = newStatusDependencies;
return MODULE;
}
case './DataDependencies': {
let MODULE = {};
MODULE.newDataDependencies = newDataDependencies;
return MODULE;
}
case './CloudRequire': {
let MODULE = {};
MODULE.newCloudRequire = newCloudRequire;
return MODULE;
}
default: {
console.log(pModulePath + " not found. ");
}
}
}
function downloadModule(pPath, callBackFunction) {
/* We will need this to load individual bots modules. */
REQUIREJS([pPath], onRequired);
function onRequired(pModule) {
console.log("CloudVM " + pPath + " downloaded.");
let MODULE = {};
MODULE.newUserBot = newUserBot;
callBackFunction(MODULE);
}
}
+152
View File
@@ -0,0 +1,152 @@
function newCloudVM() {
const MODULE_NAME = "CloudVM";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
var thisObject = {
onBotPlayPressed: onBotPlayPressed,
onBotStopPressed: onBotStopPressed
};
let root = newRoot();
let intervalHandler;
let previousBotCode = "";
let errorsCheckingForBotCodeChanges = 0;
return thisObject;
function onBotPlayPressed(pUI_COMMANDS) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onBotPlayPressed -> Entering function."); }
window.SHALL_BOT_STOP = false;
errorsCheckingForBotCodeChanges = 0;
window.CURRENT_ENVIRONMENT = "Develop";
window.CURRENT_EXECUTION_AT = "Browser";
window.STORAGE_PERMISSIONS = ecosystem.getStoragePermissions();
window.EXCHANGE_NAME = "Poloniex";
window.MARKET = {
assetA: "USDT",
assetB: "BTC"
};
/*
When running at the browser, the AACloud VM will look for this data, in this case it does not contain any key or secret, since the browser only know the
session token the user received when he logged in.
*/
window.EXCHANGE_KEYS = {
Poloniex: {
Key: "",
Secret: ""
}
}
root.initialize(pUI_COMMANDS, onInitialized);
function onInitialized() {
try {
if (INFO_LOG === true) { logger.write("[INFO] onBotPlayPressed -> Entering function."); }
root.start();
intervalHandler = setInterval(checkForChangesInBotCode, 10000);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onBotPlayPressed -> onInitialized -> err.message = " + err.message); }
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onBotPlayPressed -> err.message = " + err.message); }
}
}
function onBotStopPressed() {
if (INFO_LOG === true) { logger.write("[INFO] onBotStopPressed -> Entering function."); }
window.SHALL_BOT_STOP = true;
errorsCheckingForBotCodeChanges = 0;
}
function checkForChangesInBotCode() {
try {
if (INFO_LOG === true) { logger.write("[INFO] checkForChangesInBotCode -> Entering function."); }
let botFunction = newUserBot;
if (botFunction !== undefined) {
let currentBotCode = botFunction.toString();
if (previousBotCode !== "") {
if (currentBotCode !== previousBotCode) {
console.log("CloudVM -> Bot code changes detected.");
let path = window.canvasApp.urlPrefix
+ "AABrowserAPI" + "/"
+ "saveBotCode" + "/"
+ window.DEV_TEAM + "/"
+ "members" + "/"
+ window.USER_LOGGED_IN + "/"
+ window.CURRENT_BOT_REPO + "/"
+ window.CURRENT_PROCESS + "/"
+ "User.Bot.js"
;
callServer(currentBotCode, path, onServerResponse);
function onServerResponse(err) {
err = JSON.parse(err);
if (INFO_LOG === true) { logger.write("[INFO] checkForChangesInBotCode -> onServerResponse -> Entering function."); }
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
if (ERROR_LOG === true) { logger.write("[ERROR] checkForChangesInBotCode -> onServerResponse -> err.message = " + err.message); }
console.log("CloudVM -> Changes in code NOT saved. Plase check the error log and try again.");
return;
}
console.log("CloudVM -> Changes in code saved.");
}
}
}
previousBotCode = currentBotCode;
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] checkForChangesInBotCode -> err.message = " + err.message); }
errorsCheckingForBotCodeChanges++;
if (errorsCheckingForBotCodeChanges > 2) {
if (ERROR_LOG === true) { logger.write("[ERROR] checkForChangesInBotCode -> Giving up."); }
clearInterval(intervalHandler);
}
}
}
}
+71
View File
@@ -0,0 +1,71 @@
function newWebFS() {
const MODULE_NAME = "Web FS";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
/*
This is the module emulates the NodeJS 'fs'.
*/
var thisObject = {
readFileSync: readFileSync,
appendFileSync: appendFileSync,
mkdirSync: mkdirSync,
statSync: statSync,
readdir: readdir,
readdirSync: readdirSync,
readFile: readFile
};
return thisObject;
function readFileSync(pPath, pEncoding) {
switch (pPath) {
case '': {
break;
}
}
}
function appendFileSync(pPath, pText) {
/* We will ignore this since we can not and dont want to really write something on disk while we are at the browser. */
}
function readdir(pPath, callBackFunction) {
/* We will return an empty array of files. */
callBackFunction([]);
}
function readdirSync(pPath, callBackFunction) {
}
function mkdirSync(pPath) {
/* Again we do nothing. */
}
function readFile(pPath) {
/* Again we do nothing. */
}
function statSync(pPath) {
let stats
stats.size = 0;
return stats
}
}
+156
View File
@@ -0,0 +1,156 @@
function newCompetitionStorage(pName) {
const MODULE_NAME = "Competition Storage";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
competitorsSequences: [],
eventHandler: undefined,
initialize: initialize
}
thisObject.eventHandler = newEventHandler();
/* We name the event Handler to easy debugging. */
thisObject.eventHandler.name = "Storage-" + pName;
let fileSequences = [];
return thisObject;
function initialize(pHost, pCompetition, pExchange, pMarket, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + pHost.codeName + "-" + pCompetition.codeName); }
let dataSetsToLoad = 0;
let dataSetsLoaded = 0;
fileSequences = [];
for (let j = 0; j < pCompetition.participants.length; j++) {
let devTeam = ecosystem.getTeam(pCompetition.participants[j].devTeam);
let bot = ecosystem.getBot(devTeam, pCompetition.participants[j].bot)
let product = ecosystem.getProduct(bot, "Competition Trading History");
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + devTeam.codeName + "-" + bot.codeName + "-" + product.codeName); }
for (let i = 0; i < product.dataSets.length; i++) {
let thisSet = product.dataSets[i];
switch (thisSet.type) {
case 'File Sequence': {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> File Sequence -> key = " + pHost.codeName + "-" + pCompetition.codeName + "-" + devTeam.codeName + "-" + bot.codeName + "-" + product.codeName); }
let fileSequence = newFileSequence();
fileSequence.initialize(devTeam, bot, product, thisSet, pExchange, pMarket, onFileSequenceReady);
fileSequences.push(fileSequence);
dataSetsToLoad++;
}
break;
}
function onFileSequenceReady(err, pCaller) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> key = " + pHost.codeName + "-" + pCompetition.codeName + "-" + devTeam.codeName + "-" + bot.codeName + "-" + product.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> err.message = " + err.message); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> This bot has not starting competing yet."); }
break;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
let event = {
totalValue: pCaller.getExpectedFiles(),
currentValue: pCaller.getFilesLoaded()
}
thisObject.eventHandler.raiseEvent('File Sequence Loaded', event);
if (event.currentValue === event.totalValue) {
dataSetsLoaded++;
checkInitializeComplete();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onFileSequenceReady -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function checkInitializeComplete() {
try {
if (INFO_LOG === true) { logger.write("[INFO] checkInitializeComplete -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] checkInitializeComplete -> key = " + pHost.codeName + "-" + pCompetition.codeName + "-" + devTeam.codeName + "-" + bot.codeName + "-" + product.codeName); }
if (dataSetsLoaded === dataSetsToLoad) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> checkInitializeComplete -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
}
thisObject.competitorsSequences.push(fileSequences);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
+36
View File
@@ -0,0 +1,36 @@
function newContainer() {
var container = {
frame: undefined,
displacement: undefined,
eventHandler: undefined,
parentContainer: undefined,
isDraggeable: true,
isClickeable: false,
isWheelable: false,
name: undefined,
initialize: initialize
};
return container;
function initialize() {
var frame = newFrame();
frame.initialize();
this.frame = frame;
frame.container = container;
var eventHandler = newEventHandler();
eventHandler.initialize();
eventHandler.name = container.name;
this.eventHandler = eventHandler;
var displacement = newDisplacement();
this.displacement = displacement;
displacement.container = container;
}
}
+307
View File
@@ -0,0 +1,307 @@
let canvas;
let markets;
let ecosystem = newEcosystem();
let cloudVM = newCloudVM();
let INITIAL_ZOOM_LEVEL = -26; // This is the zoom level at the view port in which the APP starts.
let INITIAL_TIME_PERIOD = recalculatePeriod(INITIAL_ZOOM_LEVEL); // This value will be overwritten at the viewPort.initialize if the user had a prevous session with this same browser.
let viewPort = newViewPort();
function newDashboard() {
const MODULE_NAME = "Dashboard";
const INFO_LOG = false;
const ERROR_LOG = true;
const INTENSIVE_LOG = false;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
start: start
};
const DEBUG_START_UP_DELAY = 0; //3000; // This is a waiting time in case there is a need to debug the very first steps of initialization, to be able to hit F12 on time.
return thisObject;
function start() {
try {
if (INFO_LOG === true) { logger.write("[INFO] start -> Entering function."); }
/* Here we will setup the global eventHandler that will enable the Canvas App to react to events happening outside its execution scope. */
window.canvasApp.eventHandler = newEventHandler();
window.canvasApp.eventHandler.listenToEvent("User Profile Changed", userProfileChanged);
window.canvasApp.eventHandler.listenToEvent("Browser Resized", browserResized);
loadImages(onImagesLoaded);
function onImagesLoaded() {
if (INFO_LOG === true) { logger.write("[INFO] start -> onImagesLoaded -> Entering function."); }
/* Next we start the App*/
setTimeout(delayedStart, DEBUG_START_UP_DELAY);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] start -> err = " + err); }
}
}
function delayedStart() {
try {
if (INFO_LOG === true) { logger.write("[INFO] delayedStart -> Entering function."); }
/* For now, we are supporting only one market. */
let market = {
id: 2,
assetA: "USDT",
assetB: "BTC"
};
markets = new Map();
markets.set(market.id, market);
canvas = newCanvas();
canvas.initialize();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] delayedStart -> err = " + err); }
}
}
function userProfileChanged() {
try {
if (INFO_LOG === true) { logger.write("[INFO] userProfileChanged -> Entering function."); }
canvas.topSpace.initialize();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] userProfileChanged -> err = " + err); }
}
}
function browserResized() {
try {
if (INFO_LOG === true) { logger.write("[INFO] browserResized -> Entering function."); }
browserCanvas = document.getElementById('canvas');
browserCanvas.width = window.innerWidth;
browserCanvas.height = window.innerHeight - window.canvasApp.topMargin;
viewPort.initialize();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] browserResized -> err = " + err); }
}
}
function loadImages(callBack) {
try {
if (INFO_LOG === true) { logger.write("[INFO] loadImages -> Entering function."); }
const accessToken = "";
/*
Soon, we will need to get images from the Financial Beings Module. I live this core here as a sample for that:
const apolloClient = new Apollo.lib.ApolloClient({
networkInterface: Apollo.lib.createNetworkInterface({
uri: window.canvasApp.graphQL.masterAppApiUrl,
transportBatching: true,
}),
connectToDevTools: true,
})
const QUERY = Apollo.gql`
query($authId: String){
users_UserByAuthId (authId: $authId){
id
referrerId
alias
firstName
middleName
lastName
bio
email
emailVerified
isDeveloper
isDataAnalyst
isTrader
avatarHandle
avatarChangeDate
sessionToken
role {
id
}
}
}
`
const getUser = () => {
return new Promise((resolve, reject) => {
apolloClient.query({
query: QUERY,
variables: {
authId: authId
}
})
.then(response => {
sessionToken = response.data.users_UserByAuthId.sessionToken;
window.localStorage.setItem('loggedInUser', JSON.stringify(response.data.users_UserByAuthId));
resolve({ user: response.data.users_UserByAuthId })
})
.catch(error => {
console.log("apolloClient error getting user query", error)
reject(error)
});
});
}
*/
const networkInterfaceTeams = Apollo.lib.createNetworkInterface({
uri: window.canvasApp.graphQL.masterAppApiUrl
});
networkInterfaceTeams.use([{
applyMiddleware(req, next) {
req.options.headers = {
authorization: `Bearer ${accessToken}`
};
next();
}
}]);
const apolloClientTeams = new Apollo.lib.ApolloClient({
networkInterface: networkInterfaceTeams,
connectToDevTools: true,
});
const ALL_TEAMS_QUERY = Apollo.gql`
{
teams_Teams{
edges{
node{
id
name
slug
profile {
avatar
banner
description
motto
updatedAt
}
fb {
id
name
slug
avatar
kind
status {
status
reason
createdAt
}
}
}
}
}
}
`
let teams;
const getTeams = () => {
return new Promise((resolve, reject) => {
apolloClientTeams.query({
query: ALL_TEAMS_QUERY
})
.then(response => {
teams = response.data.teams_Teams;
window.localStorage.setItem('Teams', JSON.stringify(response.data.teams_Teams));
resolve({ teams: response.data.teams_Teams })
})
.catch(err => {
if (ERROR_LOG === true) { logger.write("[ERROR] loadImages -> getTeams -> Error fetching data from Teams Module."); }
if (ERROR_LOG === true) { logger.write("[ERROR] loadImages -> getTeams -> err = " + err); }
reject(err)
});
})
}
// To avoid race conditions, add asynchronous fetches to array
let fetchDataPromises = [];
fetchDataPromises.push(/*getUser(),*/ getTeams()); // <-- Here we must add the function calll to the Financial Beings module.
// When all asynchronous fetches resolve, authenticate user or throw error.
Promise.all(fetchDataPromises).then(result => {
/* All good, we will go through the results creating a map with all the Images URLs */
let teamProfileImages = new Map();
let fbProfileImages = new Map();
for (let i = 0; i < teams.edges.length; i++) {
let team = teams.edges[i].node;
teamProfileImages.set(team.slug, team.profile.avatar);
if (team.fb.length > 0) {
fbProfileImages.set(team.slug + "-" + team.fb[0].slug, team.fb[0].avatar);
}
}
window.canvasApp.context.teamProfileImages = teamProfileImages;
window.canvasApp.context.fbProfileImages = fbProfileImages;
callBack();
}, err => {
if (ERROR_LOG === true) { logger.write("[ERROR] loadImages -> Error fetching data from Teams Module."); }
if (ERROR_LOG === true) { logger.write("[ERROR] loadImages -> err = " + err); }
});
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] loadImages -> err = " + err); }
}
}
}
+81
View File
@@ -0,0 +1,81 @@
/*
We call displacement to the offset we can produce to the object which the displcement object is is a child from.
The displacement is a vector that displaces everything static drawn on on the context of the parent object.
*/
function newDisplacement() {
var displacement = {
containerName: "", // This is for debugging purposes only.
parentDisplacement: undefined, // Here we store the displacement object of the parent cointainer, if exists.
container: undefined,
x: 0, // This is the actual x displacement.
y: 0, // This is the actual y displacement.
displace: displace,
undisplaceThisPoint: undisplaceThisPoint,
displaceThisPoint: displaceThisPoint
};
return displacement;
function displace(amountX, amountY) {
/* First we check if by allowing this displacement we would produce the current frame to be beyond its limit. */
tempDisplacement = newDisplacement();
tempDisplacement.x = amountX;
tempDisplacement.y = amountY;
if (this.container.frame.canYouMoveHere(tempDisplacement)) {
/* Now we displace */
displacement.x = displacement.x + amountX;
displacement.y = displacement.y + amountY;
return true;
}
return false;
}
function displaceThisPoint(point) {
if (this.parentDisplacement !== undefined) {
point = this.parentDisplacement.displaceThisPoint(point);
}
point.x = point.x + displacement.x;
point.y = point.y + displacement.y;
return point;
}
function undisplaceThisPoint(point) {
if (this.parentDisplacement !== undefined) {
point = this.parentDisplacement.undisplaceThisPoint(point);
}
point.x = point.x - displacement.x;
point.y = point.y - displacement.y;
return point;
}
}
+93
View File
@@ -0,0 +1,93 @@
function newEventHandler() {
const CONSOLE_LOG = false;
let thisObject = {
name: undefined, // This is for debugging purposes only.
parentEventHandler: undefined, // Here we store the parent cointainer zoom object.
listenToEvent: listenToEvent,
stopListening: stopListening,
raiseEvent: raiseEvent,
initialize: initialize
};
var eventHandlers = []; // Here we store all the functions we will call when an event is comming.
return thisObject;
function initialize() {
}
function listenToEvent(eventType, handler, extraData) {
eventHandlers.push([eventType, handler, extraData]);
if (thisObject.name !== undefined && CONSOLE_LOG === true) {
console.log("Event Handler named " + thisObject.name + " received a request to listenToEvent " + eventType + " and call " + (handler.toString()).substring(0, 50));
}
}
function stopListening(pEventType, pHandler) {
if (thisObject.name !== undefined && CONSOLE_LOG === true) {
console.log("Event Handler named " + thisObject.name + " received a request to stop listening to an the event " + pEventType + " with this handler: " + pHandler);
}
for (let i = 0; i < eventHandlers.length; i++) {
let record = eventHandlers[i];
let eventType = record[0];
let handler = record[1];
if (pEventType === eventType && pHandler.toString() === handler.toString()) {
eventHandlers.splice(i, 1);
if (thisObject.name !== undefined && CONSOLE_LOG === true) {
console.log("Evethandler found and deleted.");
}
return;
}
}
}
function raiseEvent(eventType, event) {
if (thisObject.name !== undefined && CONSOLE_LOG === true) {
console.log("Event Handler named " + thisObject.name + " received a request to raiseEvent " + eventType + " with this data " + (event.toString()).substring(0, 50));
}
for (var i = 0; i < eventHandlers.length; i++) {
/* We will execute all the functions listening to this event type. */
if (eventHandlers[i][0] === eventType) {
var handler = eventHandlers[i][1];
var extraData = eventHandlers[i][2];
if (thisObject.name !== undefined && CONSOLE_LOG === true) {
console.log("Event Handler named " + thisObject.name + " received a request to raiseEvent " + eventType + " and will call this handler: " + (handler.toString()).substring(0,50));
}
handler(event, extraData);
}
}
}
}
+166
View File
@@ -0,0 +1,166 @@
function newExchangeAPI() {
const INFO_LOG = true;
const LOG_FILE_CONTENT = true;
const MODULE_NAME = "CloudVM -> Exchange API";
const SERVER_URL = window.canvasApp.urlPrefix + "ExchangeAPI/";
let thisObject = {
initialize: initialize,
getTicker: getTicker,
getOpenPositions: getOpenPositions,
getExecutedTrades: getExecutedTrades,
putPosition: putPosition,
movePosition: movePosition,
getPublicTradeHistory: getPublicTradeHistory
};
return thisObject;
function initialize(callBackFunction) {
/* When this initialized is called from the Browser, there is no need to send it to the server since the server will
anyways initialize this library at each method call. */
callBackFunction(window.DEFAULT_OK_RESPONSE);
}
function getTicker(pMarket, callBackFunction) {
let authToken = window.localStorage.getItem('access_token');
let path = SERVER_URL
+ CURRENT_BOT_CODE_NAME + "/"
+ "getTicker" + "/"
+ authToken
;
callServer(undefined, path + "/NO-LOG", onServerResponse);
function onServerResponse(pServerResponse) {
let response = JSON.parse(pServerResponse);
if (response.result === window.DEFAULT_FAIL_RESPONSE.result)
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
else
callBackFunction(window.DEFAULT_OK_RESPONSE, response);
}
}
function getOpenPositions(pMarket, callBackFunction) {
let authToken = window.localStorage.getItem('access_token');
let path = SERVER_URL
+ CURRENT_BOT_CODE_NAME + "/"
+ "getOpenPositions" + "/"
+ authToken
;
callServer(undefined, path + "/NO-LOG", onServerResponse);
function onServerResponse(pServerResponse) {
let response = JSON.parse(pServerResponse);
if (response.result === window.DEFAULT_FAIL_RESPONSE.result)
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
else
callBackFunction(window.DEFAULT_OK_RESPONSE, response);
}
}
function getExecutedTrades(pPositionId, callBackFunction) {
let authToken = window.localStorage.getItem('access_token');
let path = SERVER_URL
+ CURRENT_BOT_CODE_NAME + "/"
+ "getExecutedTrades" + "/"
+ authToken + "/"
+ pPositionId
;
callServer(undefined, path + "/NO-LOG", onServerResponse);
function onServerResponse(pServerResponse) {
let response = JSON.parse(pServerResponse);
if (response.result === window.DEFAULT_FAIL_RESPONSE.result)
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
else
callBackFunction(window.DEFAULT_OK_RESPONSE, response);
}
}
function putPosition(pMarket, pType, pRate, pAmountA, pAmountB, callBackFunction) {
let authToken = window.localStorage.getItem('access_token');
let path = SERVER_URL
+ CURRENT_BOT_CODE_NAME + "/"
+ "putPosition" + "/"
+ authToken + "/"
+ pType + "/"
+ pRate + "/"
+ pAmountA + "/"
+ pAmountB
;
callServer(undefined, path + "/NO-LOG", onServerResponse);
function onServerResponse(pServerResponse) {
let response = JSON.parse(pServerResponse);
if (response.result === window.DEFAULT_FAIL_RESPONSE.result)
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
else
callBackFunction(window.DEFAULT_OK_RESPONSE, response);
}
}
function movePosition(pPositionId, pNewRate, pPositionAmountB, callBackFunction) {
let authToken = window.localStorage.getItem('access_token');
let path = SERVER_URL
+ CURRENT_BOT_CODE_NAME + "/"
+ "movePosition" + "/"
+ authToken + "/"
+ pPositionId + "/"
+ pNewRate + "/"
+ pPositionAmountB
;
callServer(undefined, path + "/NO-LOG", onServerResponse);
function onServerResponse(pServerResponse) {
let response = JSON.parse(pServerResponse);
if (response.result === window.DEFAULT_FAIL_RESPONSE.result)
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
else
callBackFunction(window.DEFAULT_OK_RESPONSE, response);
}
}
function getPublicTradeHistory(pMarket, startTime, endTime, callBackFunction) {
let authToken = window.localStorage.getItem('access_token');
let path = SERVER_URL
+ CURRENT_BOT_CODE_NAME + "/"
+ "getPublicTradeHistory" + "/"
+ authToken + "/"
+ startTime + "/"
+ endTime
;
callServer(undefined, path + "/NO-LOG", onServerResponse);
function onServerResponse(pServerResponse) {
let response = JSON.parse(pServerResponse);
if (response.result === window.DEFAULT_FAIL_RESPONSE.result)
callBackFunction(window.DEFAULT_FAIL_RESPONSE);
else
callBackFunction(window.DEFAULT_OK_RESPONSE, response);
}
}
}
+392
View File
@@ -0,0 +1,392 @@
function newDailyFiles() {
const MODULE_NAME = "Daily Files";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
getFileCursor: getFileCursor,
setDatetime: setDatetime,
setTimePeriod: setTimePeriod,
getExpectedFiles: getExpectedFiles,
getFilesLoaded: getFilesLoaded,
initialize: initialize,
finalize: finalize
}
let filesLoaded = 0;
let expectedFiles = 0;
let fileCloud;
let fileCursors = new Map;
let callBackWhenFileReceived;
return thisObject;
function finalize() {
try {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> Entering function."); }
filesLoaded = undefined;
expectedFiles = undefined;
fileCloud = undefined;
fileCursors.forEach(finalizeEach);
function finalizeEach(item, key, mapObj) {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> finalizeEach -> Entering function."); }
item.finalize();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err); }
}
}
function initialize(pDevTeam, pBot, pProduct, pSet, pExchange, pMarket, pDatetime, pTimePeriod, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
callBackWhenFileReceived = callBackFunction;
let exchange = ecosystem.getExchange(pProduct, pExchange);
if (exchange === undefined) {
throw "Exchange not supoorted by this product of the ecosystem! - pDevTeam.codeName = " + pDevTeam.codeName + ", pBot.codeName = " + pBot.codeName + ", pProduct.codeName = " + pProduct.codeName + ", pExchange = " + pExchange;
}
fileCloud = newFileCloud();
fileCloud.initialize(pBot);
/* First we will get the Data Range */
fileCloud.getFile(pDevTeam, pBot, pSet, exchange, pMarket, undefined, undefined, undefined, true, onDataRangeReceived);
function onDataRangeReceived(err, pFile) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Entering function."); }
let beginDateRange;
let endDateRange;
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received OK Response."); }
beginDateRange = new Date(pFile.begin);
endDateRange = new Date(pFile.end);
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> err.message = " + err.message); }
if (err.message === "File does not exist.") {
if (INFO_LOG === true) { logger.write("[WARN] initialize -> onFileReceived -> No Date Range file found. maxDate will be set to current datetime. "); }
endDateRange = new Date();
break;
}
if (err.message === "Missing Configuration.") {
if (ERROR_LOG === true) { logger.write("[WARN] initialize -> onFileReceived -> The needed configuration for the dateRange at the dataSet of the product was not found."); }
if (ERROR_LOG === true) { logger.write("[WARN] initialize -> onFileReceived -> maxDate will be set to current datetime."); }
endDateRange = new Date();
break;
}
/* If none of the previous conditions are met, the we return the err to the caller. */
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
/* Now we will get the daily files */
for (i = 0; i < dailyFilePeriods.length; i++) {
let periodTime = dailyFilePeriods[i][0];
let periodName = dailyFilePeriods[i][1];
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> periodTime = " + periodTime); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> periodName = " + periodName); }
if (pSet.validPeriods.includes(periodName) === true) {
let fileCursor = newFileCursor();
fileCursor.initialize(fileCloud, pDevTeam, pBot, pSet, exchange, pMarket, periodName, periodTime, pDatetime, pTimePeriod, beginDateRange, endDateRange, onInitialized);
function onInitialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> onInitialized -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> onInitialized -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> onInitialized -> Received FAIL Response."); }
callBackWhenFileReceived(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> onInitialized -> Received Unexpected Response."); }
callBackWhenFileReceived(err);
return;
}
}
fileCursors.set(periodTime, fileCursor);
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> onInitialized -> expectedFiles = " + expectedFiles); }
expectedFiles = expectedFiles + fileCursor.getExpectedFiles();
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> onInitialized -> expectedFiles = " + expectedFiles); }
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onFileReceived -> onInitialized -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
}
loadThemAll();
function loadThemAll() {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> loadThemAll -> Entering function."); }
for (i = 0; i < dailyFilePeriods.length; i++) {
let periodTime = dailyFilePeriods[i][0];
let periodName = dailyFilePeriods[i][1];
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> loadThemAll -> periodTime = " + periodTime); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> loadThemAll -> periodName = " + periodName); }
if (pSet.validPeriods.includes(periodName) === true) {
let fileCursor = fileCursors.get(periodTime);
fileCursor.reload(onFileReceived);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onFileReceived -> loadThemAll -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function onFileReceived(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] onFileReceived -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] onFileReceived -> Received FAIL Response."); }
callBackWhenFileReceived(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] onFileReceived -> err.message = " + err.message); }
callBackWhenFileReceived(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] onFileReceived -> Received Unexpected Response."); }
callBackWhenFileReceived(err);
return;
}
}
filesLoaded++;
if (INFO_LOG === true) { logger.write("[INFO] onFileReceived -> filesLoaded = " + filesLoaded); }
callBackWhenFileReceived(GLOBAL.DEFAULT_OK_RESPONSE, thisObject); // Note that the call back is called for every file loaded at each cursor.
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] onFileReceived -> err = " + err); }
callBackWhenFileReceived(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function getFileCursor(pPeriod) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFileCursor -> Entering function."); }
return fileCursors.get(pPeriod);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFileCursor -> err = " + err); }
}
}
function setDatetime(pDatetime) {
try {
if (INFO_LOG === true) { logger.write("[INFO] setDatetime -> Entering function."); }
filesLoaded = 0;
expectedFiles = 0;
fileCursors.forEach(setDatetimeToEach)
function setDatetimeToEach(fileCursor, key, map) {
fileCursor.setDatetime(pDatetime);
if (INFO_LOG === true) { logger.write("[INFO] setDatetime -> expectedFiles = " + expectedFiles); }
expectedFiles = expectedFiles + fileCursor.getExpectedFiles();
if (INFO_LOG === true) { logger.write("[INFO] setDatetime -> expectedFiles = " + expectedFiles); }
fileCursor.reload(onFileReceived);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setDatetime -> err = " + err); }
}
}
function setTimePeriod(pTimePeriod, pDatetime) {
try {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> Entering function."); }
filesLoaded = 0;
expectedFiles = 0;
fileCursors.forEach(setTimePeriodToEach)
function setTimePeriodToEach(fileCursor, key, map) {
fileCursor.setTimePeriod(pTimePeriod, pDatetime);
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> expectedFiles = " + expectedFiles); }
expectedFiles = expectedFiles + fileCursor.getExpectedFiles();
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> expectedFiles = " + expectedFiles); }
fileCursor.reload(onFileReceived);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimePeriod -> err = " + err); }
}
}
function getExpectedFiles() {
if (INFO_LOG === true) { logger.write("[INFO] getExpectedFiles -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] getExpectedFiles -> expectedFiles = " + expectedFiles); }
return expectedFiles;
}
function getFilesLoaded() {
if (INFO_LOG === true) { logger.write("[INFO] getFilesLoaded -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] getFilesLoaded -> filesLoaded = " + filesLoaded); }
return filesLoaded;
}
}
+252
View File
@@ -0,0 +1,252 @@
function newFileCloud() {
const MODULE_NAME = "File Cloud";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
/*
This is the module in the system that actually connects to the cloud storage and grabs from there the needed files.
*/
var thisObject = {
getFile: getFile,
initialize: initialize
};
let blobService;
return thisObject;
function initialize(pBot) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> pBot = " + pBot.codeName); }
blobService = AzureStorage.Blob.createBlobServiceWithSas(pBot.storage.fileUri, pBot.storage.sas);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
//callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE); TODO> Handle this callback.
}
}
function getFile(pDevTeam, pBot, pSet, pExchange, pMarket, pPeriodName, pDatetime, pSequence, pDataRange, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFile -> Entering function."); }
const MAX_RETRIES = 3;
getFileRecursively(0, pDevTeam, pBot, pSet, pExchange, pMarket, pPeriodName, pDatetime, pSequence, pDataRange, callBackFunction)
function getFileRecursively(pRetryCounter, pDevTeam, pBot, pSet, pExchange, pMarket, pPeriodName, pDatetime, pSequence, pDataRange, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pSet.filePath + "-" + pSet.fileName); }
let fileName;
let filePath;
if (pDataRange === undefined) {
fileName = pSet.fileName;
filePath = pSet.filePath;
} else {
if (pSet.dataRange !== undefined) {
fileName = pSet.dataRange.fileName;
filePath = pSet.dataRange.filePath;
} else {
let customErr = {
result: GLOBAL.CUSTOM_FAIL_RESPONSE.result,
message: "Missing Configuration."
};
if (ERROR_LOG === true) { logger.write("[WARN] getFile -> getFileRecursively -> onFileReceived -> customErr.message = " + customErr.message); }
if (ERROR_LOG === true) { logger.write("[WARN] getFile -> getFileRecursively -> onFileReceived -> Data Range configuration could not be found. "); }
callBackFunction(customErr);
return;
}
}
if (fileName === undefined) {
logger.write("[ERROR] getFile -> getFileRecursively -> Inconsistant data. Check the following: ");
logger.write("[ERROR] getFile -> getFileRecursively -> pDevTeam = " + JSON.stringify(pDevTeam));
logger.write("[ERROR] getFile -> getFileRecursively -> pBot = " + JSON.stringify(pBot));
logger.write("[ERROR] getFile -> getFileRecursively -> pSet = " + JSON.stringify(pSet));
logger.write("[ERROR] getFile -> getFileRecursively -> pExchange = " + JSON.stringify(pExchange));
logger.write("[ERROR] getFile -> getFileRecursively -> pMarket = " + JSON.stringify(pMarket));
logger.write("[ERROR] getFile -> getFileRecursively -> pPeriodName = " + JSON.stringify(pPeriodName));
throw ("Inconsistant data received.");
}
if (pMarket !== undefined) {
fileName = fileName.replace("@AssetA", pMarket.assetA);
fileName = fileName.replace("@AssetB", pMarket.assetB);
}
if (pDevTeam !== undefined) {
filePath = filePath.replace("@DevTeam", pDevTeam.codeName);
}
if (pBot !== undefined) {
filePath = filePath.replace("@Bot", pBot.codeName);
}
if (pExchange !== undefined) {
filePath = filePath.replace("@Exchange", pExchange.name);
}
filePath = filePath.replace("@Period", pPeriodName);
if (pDatetime !== undefined) {
filePath = filePath.replace("@Year", pDatetime.getUTCFullYear());
filePath = filePath.replace("@Month", pad(pDatetime.getUTCMonth() + 1, 2));
filePath = filePath.replace("@Day", pad(pDatetime.getUTCDate(), 2));
filePath = filePath.replace("@Hour", pad(pDatetime.getUTCHours(), 2));
filePath = filePath.replace("@Minute", pad(pDatetime.getUTCMinutes(), 2));
}
if (pSequence !== undefined) {
fileName = fileName.replace("@Sequence", pSequence);
}
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> filePath = " + filePath); }
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> fileName = " + fileName); }
let containerName;
containerName = pDevTeam.codeName.toLowerCase();
blobService.getBlobToText(containerName, filePath + "/" + fileName, onFileReceived);
function onFileReceived(err, text, response) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> onFileReceived -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> onFileReceived -> filePath = " + filePath); }
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> onFileReceived -> fileName = " + fileName); }
let data;
if (err) {
if (err.code === "BlobNotFound" | err.code === "FileNotFound" | err.code === "ParentNotFound") {
let customErr = {
result: GLOBAL.CUSTOM_FAIL_RESPONSE.result,
message: "File does not exist."
};
if (INFO_LOG === true) { logger.write("[WARN] getFile -> getFileRecursively -> onFileReceived -> customErr.message = " + customErr.message); }
callBackFunction(customErr);
return;
}
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> containerName = " + containerName); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> filePath = " + filePath); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> fileName = " + fileName); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> Unexpected Error Ocurred."); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> err = " + err); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> text = " + text); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> response = " + response); }
if (err.message === "XHR error") {
if (pRetryCounter < MAX_RETRIES) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> Retrying to get this file. "); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> MAX_RETRIES = " + MAX_RETRIES); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> pRetryCounter = " + pRetryCounter); }
getFileRecursively(pRetryCounter + 1, pDevTeam, pBot, pSet, pExchange, pMarket, pPeriodName, pDatetime, pSequence, pDataRange, callBackFunction)
return;
} else {
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> Could not get this file from storage. "); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> MAX_RETRIES = " + MAX_RETRIES); }
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> pRetryCounter = " + pRetryCounter); }
}
}
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
} else {
try {
data = JSON.parse(text);
if (INFO_LOG === true) { logger.write("[INFO] getFile -> getFileRecursively -> onFileReceived -> Data received is valid JSON."); }
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, data);
return;
} catch (err) {
if (INFO_LOG === true) { logger.write("[WARN] getFile -> getFileRecursively -> onFileReceived -> err = " + err); }
let customErr = {
result: GLOBAL.CUSTOM_OK_RESPONSE.result,
message: "Data not in JSON Format."
};
if (INFO_LOG === true) { logger.write("[WARN] getFile -> getFileRecursively -> onFileReceived -> customErr.message = " + customErr.message); }
callBackFunction(customErr, text);
return;
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> onFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> getFileRecursively -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFile -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
+688
View File
@@ -0,0 +1,688 @@
function newFileCursor() {
const MODULE_NAME = "File Cursor";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let cursorDate;
let thisObject = {
reload: reload,
setDatetime: setDatetime,
setTimePeriod: setTimePeriod,
files: new Map,
getExpectedFiles: getExpectedFiles,
initialize: initialize,
finalize: finalize
};
let minCursorSize = 10;
let maxCursorSize = 30;
let market;
let exchange;
let fileCloud;
let devTeam;
let bot;
let thisSet;
let periodName;
let timePeriod;
let beginDateRange;
let endDateRange;
let intervalHandle;
return thisObject;
function finalize() {
try {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> Entering function."); }
clearInterval(intervalHandle);
thisObject.files = undefined;
cursorDate = undefined;
fileCloud = undefined;
periodName = undefined;
timePeriod = undefined;
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err); }
}
}
function initialize(pFileCloud, pDevTeam, pBot, pSet, pExchange, pMarket, pPeriodName, pTimePeriod, pCursorDate, pCurrentTimePeriod, pBeginDateRange, pEndDateRange, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pSet.codeName + "-" + pPeriodName); }
market = pMarket;
exchange = pExchange;
fileCloud = pFileCloud;
devTeam = pDevTeam;
bot = pBot;
thisSet = pSet;
periodName = pPeriodName;
cursorDate = pCursorDate;
timePeriod = pTimePeriod;
beginDateRange = pBeginDateRange;
endDateRange = pEndDateRange;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> market = " + market); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> periodName = " + periodName); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> cursorDate = " + cursorDate); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> beginDateRange = " + beginDateRange); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> endDateRange = " + endDateRange); }
setTimePeriod(pCurrentTimePeriod, pCursorDate);
intervalHandle = setInterval(updateFiles , timePeriod);
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function updateFiles() {
try {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> Entering function."); }
/*
In order to know if we need to update any file we follow this logic:
1. If the current date is already a file in the cursor, we need to update it.
2. If the current date is one day ahead of a file in the cursor, we need to add this one to the cursor.
*/
let targetDate;
let dateString;
let file;
/* Situation 1 */
targetDate = new Date();
dateString = targetDate.getUTCFullYear() + '-' + pad(targetDate.getUTCMonth() + 1, 2) + '-' + pad(targetDate.getUTCDate(), 2);
file = thisObject.files.get(dateString);
if (file !== undefined) {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> File found at the cursor, proceeding to update."); }
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, periodName, targetDate, undefined, undefined, onFileReceived);
return;
}
/* Situation 2 */
targetDate = new Date( (new Date()).valueOf() - ONE_DAY_IN_MILISECONDS);
dateString = targetDate.getUTCFullYear() + '-' + pad(targetDate.getUTCMonth() + 1, 2) + '-' + pad(targetDate.getUTCDate(), 2);
file = thisObject.files.get(dateString); // This is from yesterday
targetDate = new Date();
dateString = targetDate.getUTCFullYear() + '-' + pad(targetDate.getUTCMonth() + 1, 2) + '-' + pad(targetDate.getUTCDate(), 2);
if (file !== undefined) {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> Previous day file found at the cursor, proceeding to add current date."); }
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, periodName, targetDate, undefined, undefined, onFileReceived);
return;
}
function onFileReceived(err, file) {
try {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Received FAIL Response."); }
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Received Unexpected Response."); }
return;
}
}
thisObject.files.set(dateString, file);
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> File updated."); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> devTeam = " + devTeam.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> bot = " + bot.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> thisSet = " + thisSet.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> dateString = " + dateString); }
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] updateFiles -> onFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] updateFiles -> err = " + err); }
}
}
function setTimePeriod(pTimePeriod, pDatetime) {
try {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> Entering function."); }
/*
We are implementing here an algorithm designed to save bandwidth, memory and processing power at the browser.
We say there is a saving mode where the cursor is running at a minimum size. When the end user aproaches the time period the cursor
is set, then it should exit the saving mode and go to its actual size.
To do this we are going to measure the distance from the Time Period received to the one the cursors was initialized with.
If these periods are consecutive, it means that the cursor should exit saving mode and load its full size.
*/
cursorDate = pDatetime; // Adjust the cursor date to the one received.
let positionA;
for (let i = 0; i < dailyFilePeriods.length; i++) {
let period = dailyFilePeriods[i];
if (period[0] === pTimePeriod) {
positionA = i;
}
if (period[0] === timePeriod) {
positionB = i;
}
}
if (Math.abs(positionB - positionA) <= 1) {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> Will EXIT Saving Mode."); }
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> pTimePeriod = " + convertTimePeriodToName(pTimePeriod)); }
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> timePeriod = " + convertTimePeriodToName(timePeriod)); }
exitSavingMode();
} else {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> Will ENTER Saving Mode."); }
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> pTimePeriod = " + convertTimePeriodToName(pTimePeriod)); }
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> timePeriod = " + convertTimePeriodToName(timePeriod)); }
enterSavingMode();
}
function enterSavingMode() {
try {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> enterSavingMode -> Entering function."); }
switch (timePeriod) {
case _45_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 30;
}
break;
case _40_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 20;
}
break;
case _30_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _20_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _15_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _10_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _5_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _4_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _3_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _2_MINUTES_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
case _1_MINUTE_IN_MILISECONDS:
{
minCursorSize = 3;
maxCursorSize = 15;
}
break;
default:
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimePeriod -> enterSavingMode -> err = " + err); }
}
}
function exitSavingMode() {
try {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> exitSavingMode -> Entering function."); }
switch (timePeriod) {
case _45_MINUTES_IN_MILISECONDS:
{
minCursorSize = 15;
maxCursorSize = 30;
}
break;
case _40_MINUTES_IN_MILISECONDS:
{
minCursorSize = 13;
maxCursorSize = 20;
}
break;
case _30_MINUTES_IN_MILISECONDS:
{
minCursorSize = 11;
maxCursorSize = 15;
}
break;
case _20_MINUTES_IN_MILISECONDS:
{
minCursorSize = 9;
maxCursorSize = 15;
}
break;
case _15_MINUTES_IN_MILISECONDS:
{
minCursorSize = 7;
maxCursorSize = 15;
}
break;
case _10_MINUTES_IN_MILISECONDS:
{
minCursorSize = 7;
maxCursorSize = 15;
}
break;
case _5_MINUTES_IN_MILISECONDS:
{
minCursorSize = 5;
maxCursorSize = 15;
}
break;
case _4_MINUTES_IN_MILISECONDS:
{
minCursorSize = 5;
maxCursorSize = 15;
}
break;
case _3_MINUTES_IN_MILISECONDS:
{
minCursorSize = 5;
maxCursorSize = 15;
}
break;
case _2_MINUTES_IN_MILISECONDS:
{
minCursorSize = 5;
maxCursorSize = 15;
}
break;
case _1_MINUTE_IN_MILISECONDS:
{
minCursorSize = 5;
maxCursorSize = 15;
}
break;
default:
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimePeriod -> exitSavingMode -> err = " + err); }
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setTimePeriod -> err = " + err); }
}
}
function setDatetime(pDatetime) {
try {
if (INFO_LOG === true) { logger.write("[INFO] setDatetime -> Entering function."); }
if (pDatetime === undefined) {
if (ERROR_LOG === true) { logger.write("[ERROR] setDatetime -> Received undefined datetime."); }
return;
}
cursorDate = pDatetime;
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] setDatetime -> err = " + err); }
}
}
function reload(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] reload -> Entering function."); }
getFiles(callBackFunction);
collectGarbage(callBackFunction);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] reload -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function getFiles(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> Entering function."); }
let i = 0;
let j = 0;
let dateString;
getNextFile();
function getNextFile() {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> getNextFile -> Entering function."); }
let targetDate = new Date(cursorDate);
targetDate.setUTCDate(targetDate.getUTCDate() + j);
/* Small algorith to allow load first the current date, then alternate between the most forwad and the most backwards ones. */
if (j === 0) { j++; }
else {
if (j < 0) {
j = -j;
j++;
}
else {
j = -j;
}
}
let compareTargetDate = new Date(targetDate.toDateString());
if (beginDateRange !== undefined) {
let compareBeginDate = new Date(beginDateRange.toDateString());
if (compareTargetDate.valueOf() < compareBeginDate.valueOf()) {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> getNextFile -> compareTargetDate < compareBeginDate -> Not loading the file for this date."); }
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> getNextFile -> compareTargetDate < compareBeginDate -> compareTargetDate = " + compareTargetDate); }
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> getNextFile -> compareTargetDate < compareBeginDate -> compareBeginDate = " + compareBeginDate); }
controlLoop();
return;
}
}
if (endDateRange !== undefined) {
let compareEndDate = new Date(endDateRange.toDateString());
if (compareTargetDate.valueOf() > compareEndDate.valueOf()) {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> getNextFile -> compareTargetDate > compareEndDate -> Not loading the file for this date."); }
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> getNextFile -> compareTargetDate > compareEndDate -> compareTargetDate = " + compareTargetDate); }
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> getNextFile -> compareTargetDate > compareEndDate -> compareEndDate = " + compareEndDate); }
controlLoop();
return;
}
}
dateString = targetDate.getUTCFullYear() + '-' + pad(targetDate.getUTCMonth() + 1, 2) + '-' + pad(targetDate.getUTCDate(), 2);
let currentDay = Math.trunc((new Date()).valueOf() / (24 * 60 * 60 * 1000));
let targetDay = Math.trunc(targetDate.valueOf() / (24 * 60 * 60 * 1000));
if (targetDay > currentDay) {
controlLoop();
} else {
if (thisObject.files.get(dateString) === undefined) { // We dont reload files we already have.
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, periodName, targetDate, undefined, undefined, onFileReceived);
} else {
controlLoop();
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFiles -> getNextFile -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function onFileReceived(err, file) {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> onFileReceived -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> onFileReceived -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> onFileReceived -> err.message = " + err.message); }
if (err.message === "File does not exist.") {
controlLoop();
return;
} else {
callBackFunction(err);
return;
}
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> onFileReceived -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
thisObject.files.set(dateString, file);
controlLoop();
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFiles -> onFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function controlLoop() {
try {
if (INFO_LOG === true) { logger.write("[INFO] getFiles -> controlLoop -> Entering function."); }
if (callBackFunction !== undefined) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
}
i++;
if (i < minCursorSize) {
getNextFile();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFiles -> controlLoop -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] getFiles -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function collectGarbage(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] collectGarbage -> Entering function."); }
date = removeTime(cursorDate);
let minDate = date.valueOf() - maxCursorSize * ONE_DAY_IN_MILISECONDS / 2;
let maxDate = date.valueOf() + maxCursorSize * ONE_DAY_IN_MILISECONDS / 2;
for (let key of thisObject.files.keys()) {
let keyDate = new Date(key);
if (keyDate.valueOf() < minDate || keyDate.valueOf() > maxDate) {
thisObject.files.delete(key);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] collectGarbage -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function getExpectedFiles() {
if (INFO_LOG === true) { logger.write("[INFO] getExpectedFiles -> Entering function."); }
return minCursorSize;
}
}
+385
View File
@@ -0,0 +1,385 @@
function newFileSequence() {
const MODULE_NAME = "File Sequence";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
eventHandler: undefined,
getFile: getFile,
getExpectedFiles: getExpectedFiles,
getFilesLoaded: getFilesLoaded,
initialize: initialize,
finalize: finalize
}
let filesLoaded = 0;
let fileCloud;
let files = new Map;
let maxSequence = -1; // This is replaced by the content of the sequence file, which contains an index that starts on zero. In the case that the sequence file is not found the default value is -1 so when you add 1 it gives you the amount of files in the sequence, zero.
let market;
let devTeam;
let bot;
let thisSet;
let product;
thisObject.eventHandler = newEventHandler();
let intervalHandle;
return thisObject;
function finalize() {
try {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] finalize -> devTeam = " + devTeam.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] finalize -> bot = " + bot.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] finalize -> thisSet = " + thisSet.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] finalize -> intervalHandle = " + intervalHandle); }
clearInterval(intervalHandle);
filesLoaded = undefined;
fileCloud = undefined;
files = undefined;
maxSequence = undefined;
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err); }
}
}
function initialize(pDevTeam, pBot, pProduct, pSet, pExchange, pMarket, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
exchange = ecosystem.getExchange(pProduct, pExchange);
if (exchange === undefined) {
throw "Exchange not supoorted by this pProduct of the ecosystem! - pDevTeam.codeName = " + pDevTeam.codeName + ", pBot.codeName = " + pBot.codeName + ", pProduct.codeName = " + pProduct.codeName + ", pExchange = " + pExchange;
}
intervalHandle = setInterval(updateFiles, _1_MINUTE_IN_MILISECONDS);
if (INFO_LOG === true) { logger.write("[INFO] initialize -> intervalHandle = " + intervalHandle); }
market = pMarket;
devTeam = pDevTeam;
bot = pBot;
thisSet = pSet;
product = pProduct;
fileCloud = newFileCloud();
fileCloud.initialize(bot);
/* First we will get the sequence max number */
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, undefined, undefined, "Sequence", undefined, onSequenceFileReceived);
function onSequenceFileReceived(err, file) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> key = " + devTeam.codeName + "-" + bot.codeName + "-" + product.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> Received CUSTOM OK Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> err.message = " + err.message); }
callBackFunction(err);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> err.message = " + err.message); }
callBackFunction(err, thisObject);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
maxSequence = Number(file);
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> maxSequence = " + maxSequence); }
/* Now we will get the sequence of files */
for (let i = 0; i <= maxSequence; i++) {
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, undefined, undefined, i, undefined, onFileReceived);
function onFileReceived(err, file) {
try {
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> onFileReceived -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> onFileReceived -> err.message = " + err.message); }
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSequenceFileReceived -> onFileReceived -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
files.set(i, file);
filesLoaded++;
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, thisObject); // Note that the callback is called for every file loaded.
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onSequenceFileReceived -> onFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onSequenceFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function updateFiles() {
try {
let updateFiles = 0;
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> Entering function."); }
/*
To keep this data structure up-to-date we need to:
1. Re-read the sequence file.
2. Re-load the current last file.
3. Re-load all new files after our last one.
*/
let currentMaxSequence = maxSequence;
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> currentMaxSequence = " + currentMaxSequence); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> intervalHandle = " + intervalHandle); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> devTeam = " + devTeam.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> bot = " + bot.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> thisSet = " + thisSet.codeName); }
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, undefined, undefined, "Sequence", undefined, onSequenceFileReceived);
function onSequenceFileReceived(err, file) {
try {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> key = " + devTeam.codeName + "-" + bot.codeName + "-" + product.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> Received FAIL Response."); }
return;
}
case GLOBAL.CUSTOM_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> Received CUSTOM OK Response."); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> err.message = " + err.message); }
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> err.message = " + err.message); }
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> Received Unexpected Response."); }
return;
}
}
maxSequence = Number(file);
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> maxSequence = " + maxSequence); }
/* Now we will get the sequence of files, but in this case only from the currentMaxSequence and above. */
for (let i = currentMaxSequence; i <= maxSequence; i++) {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> i = " + i); }
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, undefined, undefined, i, undefined, onFileReceived);
function onFileReceived(err, file) {
try {
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> Received FAIL Response."); }
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> err.message = " + err.message); }
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> Received Unexpected Response."); }
return;
}
}
files.set(i, file);
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> File Updated."); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> i = " + i); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> file.length = " + file.length); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> filesLoaded = " + filesLoaded); }
if (i !== currentMaxSequence) {
filesLoaded++;
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> filesLoaded = " + filesLoaded); }
}
if (filesLoaded === maxSequence + 1) {
thisObject.eventHandler.raiseEvent("Files Updated", undefined);
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onSequenceFileReceived -> onFileReceived -> Files Updated event Raised."); }
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] updateFiles -> onSequenceFileReceived -> onFileReceived -> err = " + err); }
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] updateFiles -> onSequenceFileReceived -> err = " + err); }
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] updateFiles -> err = " + err); }
}
}
function getFile(pSequence) {
if (INFO_LOG === true) { logger.write("[INFO] getFile -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] getFile -> pSequence = " + pSequence); }
return files.get(pSequence);
}
function getExpectedFiles() {
if (INFO_LOG === true) { logger.write("[INFO] getExpectedFiles -> Entering function."); }
return maxSequence + 1;
}
function getFilesLoaded() {
if (INFO_LOG === true) { logger.write("[INFO] getFilesLoaded -> Entering function."); }
return filesLoaded;
}
}
+253
View File
@@ -0,0 +1,253 @@
function newMarketFiles() {
const MODULE_NAME = "Market Files";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
eventHandler: undefined,
getFile: getFile,
getExpectedFiles: getExpectedFiles,
getFilesLoaded: getFilesLoaded,
initialize: initialize,
finalize: finalize
}
let filesLoaded = 0;
let fileCloud;
let files = new Map;
let market;
let exchange;
let devTeam;
let bot;
let thisSet;
let periodName;
thisObject.eventHandler = newEventHandler();
let intervalHandle;
return thisObject;
function finalize() {
try {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> Entering function."); }
clearInterval(intervalHandle);
filesLoaded = undefined;
files = undefined;
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err); }
}
}
function initialize(pDevTeam, pBot, pProduct, pSet, pExchange, pMarket, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
exchange = ecosystem.getExchange(pProduct, pExchange);
if (exchange === undefined) {
throw "Exchange not supoorted by this pProduct of the ecosystem! - pDevTeam.codeName = " + pDevTeam.codeName + ", pBot.codeName = " + pBot.codeName + ", pProduct.codeName = " + pProduct.codeName + ", pExchange = " + pExchange;
}
intervalHandle = setInterval(updateFiles, _10_MINUTES_IN_MILISECONDS);
market = pMarket;
devTeam = pDevTeam;
bot = pBot;
thisSet = pSet;
fileCloud = newFileCloud();
fileCloud.initialize(pBot);
/* Now we will get the market files */
for (let i = 0; i < marketFilesPeriods.length; i++) {
let periodTime = marketFilesPeriods[i][0];
let periodName = marketFilesPeriods[i][1];
if (thisSet.validPeriods.includes(periodName) === true) {
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, periodName, undefined, undefined, undefined, onFileReceived);
function onFileReceived(err, file) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> err.message = " + err.message); }
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
files.set(periodTime, file);
filesLoaded++;
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, thisObject); // Note that the callback is called for every file loaded.
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function updateFiles() {
try {
let updateFiles = 0;
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> Entering function."); }
/* Now we will get the market files */
for (let i = 0; i < marketFilesPeriods.length; i++) {
let periodTime = marketFilesPeriods[i][0];
let periodName = marketFilesPeriods[i][1];
if (thisSet.validPeriods.includes(periodName) === true) {
fileCloud.getFile(devTeam, bot, thisSet, exchange, market, periodName, undefined, undefined, undefined, onFileReceived);
function onFileReceived(err, file) {
try {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Received FAIL Response."); }
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> err.message = " + err.message); }
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> Received Unexpected Response."); }
return;
}
}
files.set(periodTime, file);
updateFiles++;
if (updateFiles === marketFilesPeriods.length) {
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> All files received. "); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> devTeam = " + devTeam.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> bot = " + bot.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] updateFiles -> onFileReceived -> thisSet = " + thisSet.codeName); }
thisObject.eventHandler.raiseEvent("Files Updated", undefined);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] updateFiles -> onFileReceived -> err = " + err); }
}
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] updateFiles -> err = " + err); }
}
}
function getFile(pPeriod) {
if (INFO_LOG === true) { logger.write("[INFO] getFile -> Entering function."); }
return files.get(pPeriod);
}
function getExpectedFiles() {
if (INFO_LOG === true) { logger.write("[INFO] getExpectedFiles -> Entering function."); }
return marketFilesPeriods.length;
}
function getFilesLoaded() {
if (INFO_LOG === true) { logger.write("[INFO] getFilesLoaded -> Entering function."); }
return filesLoaded;
}
}
+105
View File
@@ -0,0 +1,105 @@
function newSingleFile() {
const MODULE_NAME = "Single File";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
getFile: getFile,
initialize: initialize
}
let fileCloud;
let file;
return thisObject;
function initialize(pDevTeam, pBot, pProduct, pSet, pExchange, pMarket, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
let exchange = ecosystem.getExchange(pProduct, pExchange);
if (pExchange !== undefined && exchange === undefined) { // We support no exchange as a parameter, but if provided, then it must be at the list of exchanges of that product.
throw "Exchange not supoorted by this pProduct of the ecosystem! - pDevTeam.codeName = " + pDevTeam.codeName + ", pBot.codeName = " + pBot.codeName + ", pProduct.codeName = " + pProduct.codeName + ", pExchange = " + pExchange;
}
fileCloud = newFileCloud();
fileCloud.initialize(pBot);
/* Now we will get the file */
fileCloud.getFile(pDevTeam, pBot, pSet, exchange, pMarket, undefined, undefined, undefined, undefined, onFileReceived);
function onFileReceived(err, pFile) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> err.message = " + err.message); }
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileReceived -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
file = pFile;
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onFileReceived -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function getFile() {
if (INFO_LOG === true) { logger.write("[INFO] getFile -> Entering function."); }
return file;
}
}
File diff suppressed because it is too large. Load diff
+274
View File
@@ -0,0 +1,274 @@
function newFloatingObject() {
const MODULE_NAME = "Floating Object";
const INFO_LOG = false;
const INTENSIVE_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
var thisObject = {
physicsLoop: physicsLoop,
eventHandler: undefined,
payload: undefined, // This is a reference to an object controlled by a Plotter. The plotter can change its internal value and we will see them from here.
type: undefined, // Currently there are two types of Floating Objects: Profile Balls, and Notes.
physicsEnabled: false,
initializeMass: initializeMass,
initializeRadius: initializeRadius,
initializeImageSize: initializeImageSize,
initializeFontSize: initializeFontSize,
imageId: undefined,
currentPosition: 0, // Current x,y position of the floating object at the floating object's layer, where there is no displacement or zoom. This position is always changing towards the target position.
currentSpeed: 0, // This is the current speed of the floating object.
currentRadius: 0, // This is the current radius of the floating object, including its zoom applied.
currentMass: 0, // This is the current mass of the floating object, including its zoom applied.
friction: 0, // This is a factor that will ultimatelly desacelerate the floating object.
rawMass: 0, // This is the mass value without zoom.
rawRadius: 0, // This is the radius of this floating object without zoom.
targetRadius: 0, // This is the target radius of the floating object with zoom applied. It should be animated until reaching this value.
fillStyle: '',
labelStrokeStyle: '',
radomizeCurrentPosition: radomizeCurrentPosition,
radomizeCurrentSpeed: radomizeCurrentSpeed,
drawBackground: drawBackground,
drawForeground: drawForeground,
updateMass: updateMass, // Function to update the mass when the zoom level changed.
updateRadius: updateRadius, // Function to update the radius when the zoom level changed.
linkedObject: undefined, // This is a reference to the object that this floating object is representing.
linkedObjectType: "", // Since there might be floating objects for different types of objects, here we store the type of object we are linking to.
container: undefined, // This is a pointer to the object where the floating object belongs to.
initialize: initialize
};
let underlayingObject;
thisObject.eventHandler = newEventHandler();
return thisObject;
function initialize(pType, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
switch (pType) {
case "Profile Ball": {
underlayingObject = newProfileBall();
underlayingObject.initialize(onInitialized);
function onInitialized(err) {
}
break;
}
case "Note": {
underlayingObject = newNote();
underlayingObject.initialize(onInitialized);
function onInitialized(err) {
}
break;
}
default: {
break;
}
}
thisObject.type = pType;
thisObject.eventHandler.listenToEvent("onMouseOver", onMouseOver);
canvas.eventHandler.listenToEvent("onMouseNotOver", onMouseNotOver);
thisObject.eventHandler.listenToEvent("onMouseClick", onMouseClick);
if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE); }
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err.message = " + err.message); }
if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE); }
}
}
function physicsLoop(callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
underlayingObject.physicsLoop();
if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE); }
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] physicsLoop -> err.message = " + err.message); }
if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE); }
}
}
function onMouseOver() {
thisObject.targetRadius = thisObject.rawRadius * 1.5;
thisObject.targetImageSize = thisObject.rawImageSize * 1.5;
thisObject.targetFontSize = thisObject.rawFontSize * 1.5;
underlayingObject.onMouseOver();
}
function onMouseNotOver() {
thisObject.targetRadius = thisObject.rawRadius * 1;
thisObject.targetImageSize = thisObject.rawImageSize * 1;
thisObject.targetFontSize = thisObject.rawFontSize * 1;
underlayingObject.onMouseNotOver();
}
function onMouseClick(pPoint) {
underlayingObject.onMouseClick(pPoint, thisObject);
}
function drawBackground() {
underlayingObject.drawBackground(thisObject);
}
function drawForeground() {
underlayingObject.drawForeground(thisObject);
}
function initializeMass(suggestedValue) {
var mass = suggestedValue;
if (mass < 0.1) {
mass = 0.1;
}
thisObject.rawMass = mass;
thisObject.currentMass = mass;
}
function initializeRadius(suggestedValue) {
var radius = suggestedValue;
if (radius < 2) {
radius = 2;
}
thisObject.rawRadius = radius;
thisObject.targetRadius = radius;
thisObject.currentRadius = radius / 3;
}
function initializeImageSize(suggestedValue) {
var size = suggestedValue;
if (size < 2) {
size = 2;
}
thisObject.rawImageSize = size;
thisObject.targetImageSize = size;
thisObject.currentImageSize = size / 3;
}
function initializeFontSize(suggestedValue) {
var size = suggestedValue;
if (size < 3) {
size = 3;
}
thisObject.rawFontSize = size;
thisObject.targetFontSize = size;
thisObject.currentFontSize = size / 3;
}
function radomizeCurrentPosition(arroundPoint) {
var position = {
x: Math.floor((Math.random() * (200) - 100)) + arroundPoint.x,
y: Math.floor((Math.random() * (200) - 100)) + arroundPoint.y
};
thisObject.currentPosition = position;
}
function radomizeCurrentSpeed() {
var initialXDirection;
var randomX = Math.floor((Math.random() * 10) + 1);
if (randomX > 5) {
initialXDirection = 1;
} else {
initialXDirection = - 1;
}
var initialYDirection;
var randomY = Math.floor((Math.random() * 10) + 1);
if (randomY > 5) {
initialYDirection = 1;
} else {
initialYDirection = - 1;
}
var velocity = {
x: initialXDirection * Math.floor((Math.random() * 300) + 1) / 100,
y: initialYDirection * Math.floor((Math.random() * 300) + 1) / 100
};
thisObject.currentSpeed = velocity;
}
function updateMass() {
//thisObject.currentMass = thisObject.rawMass + thisObject.rawMass * thisObject.container.zoom.incrementM * thisObject.container.zoom.levelM;
}
function updateRadius() {
//thisObject.targetRadius = thisObject.rawRadius + thisObject.rawRadius * thisObject.container.zoom.incrementR * thisObject.container.zoom.levelR;
}
}
+336
View File
@@ -0,0 +1,336 @@
function newNote() {
var thisObject = {
physicsLoop: physicsLoop,
onMouseOver: onMouseOver,
onMouseClick: onMouseClick,
onMouseNotOver: onMouseNotOver,
drawBackground: drawBackground,
drawForeground: drawForeground,
initialize: initialize
};
return thisObject;
function initialize(callBackFunction) {
callBackFunction();
}
function physicsLoop() {
}
function onMouseOver() {
}
function onMouseNotOver() {
}
function onMouseClick(pPoint, pFloatingObject) {
}
function drawBackground(pFloatingObject) {
let point = {
x: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].position.x,
y: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].position.y
};
point = viewPort.fitIntoVisibleArea(point);
if (pFloatingObject.currentRadius > 1) {
/* Target Line */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y);
browserCanvasContext.lineTo(point.x, point.y);
browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)';
browserCanvasContext.setLineDash([4, 2]);
browserCanvasContext.lineWidth = 1;
browserCanvasContext.stroke();
browserCanvasContext.setLineDash([0, 0]);
}
if (pFloatingObject.currentRadius > 0.5) {
/* Target Spot */
var radius = 1;
browserCanvasContext.beginPath();
browserCanvasContext.arc(point.x, point.y, radius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(30, 30, 30, 1)';
browserCanvasContext.fill();
}
}
function drawForeground(pFloatingObject) {
const BUBBLE_CORNERS_RADIOUS = 5;
const TITLE_BAR_HEIGHT = 14;
const BUBBLE_WIDTH = BUBBLE_CORNERS_RADIOUS + pFloatingObject.currentRadius * 4;
const BUBBLE_HEIGHT = BUBBLE_CORNERS_RADIOUS + pFloatingObject.currentRadius * 2;
let borderPoint1;
let borderPoint2;
let borderPoint3;
let borderPoint4;
let intialDisplace = {
x: pFloatingObject.currentPosition.x - BUBBLE_WIDTH / 2,
y: pFloatingObject.currentPosition.y - BUBBLE_HEIGHT / 2
}
if (pFloatingObject.currentRadius > 5) {
/* Rounded Background */
borderPoint1 = {
x: intialDisplace.x + BUBBLE_CORNERS_RADIOUS,
y: intialDisplace.y + BUBBLE_CORNERS_RADIOUS
};
borderPoint2 = {
x: intialDisplace.x + BUBBLE_WIDTH - BUBBLE_CORNERS_RADIOUS,
y: intialDisplace.y + BUBBLE_CORNERS_RADIOUS
};
borderPoint3 = {
x: intialDisplace.x + BUBBLE_WIDTH - BUBBLE_CORNERS_RADIOUS,
y: intialDisplace.y + BUBBLE_HEIGHT - BUBBLE_CORNERS_RADIOUS
};
borderPoint4 = {
x: intialDisplace.x + BUBBLE_CORNERS_RADIOUS,
y: intialDisplace.y + + BUBBLE_HEIGHT - BUBBLE_CORNERS_RADIOUS
};
titleBarPoint1 = {
x: intialDisplace.x + 0,
y: intialDisplace.y + TITLE_BAR_HEIGHT
};
titleBarPoint2 = {
x: intialDisplace.x + BUBBLE_WIDTH,
y: intialDisplace.y + TITLE_BAR_HEIGHT
};
/* We paint the panel background first */
browserCanvasContext.fillStyle = 'rgba(255, 249, 196, 0.75)';
browserCanvasContext.beginPath();
browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, BUBBLE_CORNERS_RADIOUS, 1.0 * Math.PI, 1.5 * Math.PI);
browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - BUBBLE_CORNERS_RADIOUS);
browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, BUBBLE_CORNERS_RADIOUS, 1.5 * Math.PI, 2.0 * Math.PI);
browserCanvasContext.lineTo(borderPoint3.x + BUBBLE_CORNERS_RADIOUS, borderPoint3.y);
browserCanvasContext.arc(borderPoint3.x, borderPoint3.y, BUBBLE_CORNERS_RADIOUS, 0 * Math.PI, 0.5 * Math.PI);
browserCanvasContext.lineTo(borderPoint4.x, borderPoint4.y + BUBBLE_CORNERS_RADIOUS);
browserCanvasContext.arc(borderPoint4.x, borderPoint4.y, BUBBLE_CORNERS_RADIOUS, 0.5 * Math.PI, 1.0 * Math.PI);
browserCanvasContext.lineTo(borderPoint1.x - BUBBLE_CORNERS_RADIOUS, borderPoint1.y);
browserCanvasContext.closePath();
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK + ', 0.75)';
browserCanvasContext.stroke();
/* We paint the title bar now */
browserCanvasContext.fillStyle = 'rgba(244, 224, 44, 0.75)';
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(titleBarPoint1.x, titleBarPoint1.y);
browserCanvasContext.lineTo(borderPoint1.x - BUBBLE_CORNERS_RADIOUS, borderPoint1.y);
browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, BUBBLE_CORNERS_RADIOUS, 1.0 * Math.PI, 1.5 * Math.PI);
browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - BUBBLE_CORNERS_RADIOUS);
browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, BUBBLE_CORNERS_RADIOUS, 1.5 * Math.PI, 2.0 * Math.PI);
browserCanvasContext.lineTo(titleBarPoint2.x, titleBarPoint2.y);
browserCanvasContext.closePath();
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 0.75)';
browserCanvasContext.stroke();
}
if (pFloatingObject.currentRadius > 0.5) {
/* Image */
let imagePosition = {
x: pFloatingObject.currentPosition.x,
y: pFloatingObject.currentPosition.y + BUBBLE_HEIGHT / 2
};
if (pFloatingObject.payloadImageId !== undefined) {
let image = document.getElementById(pFloatingObject.payloadImageId);
if (image !== null) {
browserCanvasContext.drawImage(image, imagePosition.x - pFloatingObject.currentImageSize / 2, imagePosition.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize, pFloatingObject.currentImageSize);
}
}
/* Image Contourn */
browserCanvasContext.beginPath();
browserCanvasContext.arc(imagePosition.x, imagePosition.y, pFloatingObject.currentImageSize / 2, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(30, 30, 30, 0.25)';
browserCanvasContext.lineWidth = 1;
browserCanvasContext.stroke();
/* Labels */
if (pFloatingObject.currentRadius > 6) {
browserCanvasContext.strokeStyle = pFloatingObject.labelStrokeStyle;
const SIZE_PERCENTAGE = Math.trunc(pFloatingObject.currentRadius / pFloatingObject.targetRadius * 100) / 100;
let ALPHA;
if (pFloatingObject.targetRadius > 0) {
ALPHA = 0.5 - (1 - SIZE_PERCENTAGE) * 5;
} else { // Object is dying...
ALPHA = Math.trunc((0.5 - (100 - pFloatingObject.currentRadius / 100) ) * 100) / 100;
if (ALPHA < 0) { ALPHA = 0}
}
let labelPoint;
let fontSize = 10;
let label;
/* print the title */
label = pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].title;
if (label !== undefined) {
if (SIZE_PERCENTAGE > 0.9) {
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO;
let yOffset = (TITLE_BAR_HEIGHT - fontSize) / 2 + 2;
labelPoint = {
x: intialDisplace.x + BUBBLE_WIDTH / 2 - xOffset,
y: intialDisplace.y + TITLE_BAR_HEIGHT - yOffset
};
browserCanvasContext.fillStyle = 'rgba(30, 30, 30, ' + ALPHA + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
}
/* Message Body */
label = pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].body;
if (label !== undefined) {
const WORDS_PER_ROW = 5;
const TOTAL_ROWS = 5;
if (SIZE_PERCENTAGE > 0.9) {
let rawLabelArray = label.split(" ");
let labelArray = [];
/* Lets check when words are to long we add an empty space to the same line so as to roll all other words forward. */
for (let i = 0; i < rawLabelArray.length; i++) {
let word = rawLabelArray[i];
labelArray.push(word);
if (word.length > 8) {
labelArray.push("");
}
if (word.length > 10) {
labelArray.push("");
}
}
/* Calculate each ROW */
let labelRows = [];
for (let i = 0; i < TOTAL_ROWS; i++) {
let labelRow = "";
for (let j = 0; j < WORDS_PER_ROW; j++) {
let newWord = labelArray[j + i * WORDS_PER_ROW];
if (newWord !== undefined && newWord !== "") {
labelRow = labelRow + " " + newWord;
}
}
if (labelRow !== "") {
labelRows.push(labelRow);
}
}
/* Now we plot each row. */
for (let i = 0; i < labelRows.length; i++) {
let labelRow = labelRows[i];
let startingPosition = {
x: pFloatingObject.currentPosition.x,
y: pFloatingObject.currentPosition.y - labelRows.length / 2 * (fontSize * FONT_ASPECT_RATIO + 10)
};
labelPoint = {
x: startingPosition.x - labelRow.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: startingPosition.y + (i + 1) * (fontSize * FONT_ASPECT_RATIO + 10)
};
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, ' + ALPHA + ')'
browserCanvasContext.fillText(labelRow, labelPoint.x, labelPoint.y);
}
}
}
}
}
}
}
+373
View File
@@ -0,0 +1,373 @@
function newNoteSets() {
/*
Different plotters will identify sets of notes whithin the data they are plotting. They will create with them arrays of Notes data.
On the other hand the floating space, and a floting layer in particular, manages Notes floating objects, which are visible entities
that floats on the screen. These entities are animated at a certain peace, and their life cycle differs from the life cycle of the
arrays of raw data plotters have.
The purpose of this module, is to provide a mechnism of syncronization between the raw data and the visible floating objects and a
data structure wheere to store these floating objects.
A NoteSet in this context is an array of Notes floating objects belonging to the same owner, which could be a certain bot for instance.
This module is capable of managing an array of NoteSets.
*/
const MODULE_NAME = "Note Sets";
const INFO_LOG = false;
const INFO_WARN = true;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let thisObject = {
createNoteSet: createNoteSet,
destroyNoteSet: destroyNoteSet,
initialize: initialize
};
let noteSets = [];
let floatingLayer;
return thisObject;
function initialize(pFloatingLayer, callBackFunction) {
/*
During the initialization process, we receive the floatingLayer where all the floatingObjects we will be creating here will live at.
*/
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
floatingLayer = pFloatingLayer;
callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function createNoteSet(pPayload, pEventHandler, callBackFunction) {
try {
/*
During the creating of a NoteSet, no floating objects are created yet. What we do here is to create the data structure which will allocate
the Notes floating objects, once we receive the array of notes raw data from the plotter. This array will come as an event raised by the
plotter everytime it's set of raw data changes. Remember that the plotter is not only filtering out notes based on how far they are from the
position the user gives to the viewport, but also, the plotter can be receiving actually new notes from its datasource.
*/
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> Entering function."); }
let noteSet = {
imageId: pPayload.profile.imageId,
floatingNotes: [],
payload: pPayload,
handle: Math.floor((Math.random() * 10000000) + 1)
};
noteSets.push(noteSet);
pEventHandler.listenToEvent("Notes Changed", onNotesChanged, noteSets.length - 1)
callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE, noteSet.handle);
function onNotesChanged(pNewNotes, pNoteSetIndex) {
try {
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> pNewNotes.length = " + pNewNotes.length); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> pNoteSetIndex = " + pNoteSetIndex); }
let noteSet = noteSets[pNoteSetIndex];
let found = false;
let newFloatingNotes;
/*
First we remove the old notes. This means that we are going to scan all the floating objects that we have, and see one by one if they
are still present on the raw data sent by the plotter. If it is not there, that means that the floating object must be discarded.
*/
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes."); }
newFloatingNotes = []; // We will create a new array of Floating Notes as a result of this operation.
/*
Here we scan the curren array of floating objects. We use the date + rate to create a unique key for each one, in order to be able to
compare it with the raw data. You will notice that instead of deleting from the current array what we actually do is to add the ones
that are still at the raw data array to a new array, and not adding the ones that are not.
*/
for (let j = 0; j < noteSet.floatingNotes.length; j++) {
found = false;
let floatingNote = noteSet.floatingNotes[j];
let floatingNoteKey = floatingNote.date.toString() + floatingNote.rate.toString();
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> j = " + j); }
let i;
for (i = 0; i < pNewNotes.length; i++) {
let plotterNote = pNewNotes[i];
let plotterNoteKey = plotterNote.date.toString() + plotterNote.rate.toString();
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> i = " + i); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingNoteKey = " + floatingNoteKey); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> plotterNoteKey = " + plotterNoteKey); }
if (plotterNoteKey === floatingNoteKey) {
found = true;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> found = " + found); }
break;
}
}
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> End of For i."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> found = " + found); }
if (found === false) {
/*
Each time we identify a floatingObject that is not at the raw data anymore, we request the floatinglayer to kill it.
*/
floatingLayer.killFloatingObject(floatingNote.floatingHandle, onObjectKilled);
function onObjectKilled(err) {
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
if (ERROR_LOG === true) { logger.write("[ERROR] createNoteSet -> onNotesChanged -> Remove old Notes -> Floating Object Not Found."); }
if (ERROR_LOG === true) { logger.write("[ERROR] createNoteSet -> onNotesChanged -> Remove old Notes -> Floating Object cannot be killed."); }
if (ERROR_LOG === true) { logger.write("[ERROR] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingNote.floatingHandle = " + floatingNote.floatingHandle); }
return;
}
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingNote.floatingHandle = " + floatingNote.floatingHandle); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> Removed from Layer."); }
}
} else {
newFloatingNotes.push(floatingNote);
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingNote.floatingHandle = " + floatingNote.floatingHandle); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> Added to newFloatingNotes."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> newFloatingNotes.length = " + newFloatingNotes.length); }
/*
We set a property at each floatingObject of which is the index of the note at the raw data array, so that it can later evaluate its position or its visibility.
*/
let floatingObject = floatingLayer.getFloatingObject(floatingNote.floatingHandle);
floatingObject.payloadNoteIndex = i;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingObject index updated."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingObject.payloadNoteIndex = " + i); }
}
}
/*
We replace the current array, with the new one that only contains the surviving floating objects, meaning the ones that are still at the raw data received.
*/
noteSet.floatingNotes = newFloatingNotes;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> noteSet.floatingNotes.length = " + noteSet.floatingNotes.length); }
/*
Second we add the new notes. There might be new notes at the raw data received that we didnt have before at the NodeSet array. To figure out which
ones are, we need to scan the raw data array and compare each element with the ones of the NodeSet array. Whenever we find one that is not there,
we add it.
*/
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes."); }
newFloatingNotes = []; // We will create a new array of Floating Notes as a result of this operation.
/*
We are using the date and rate as a unique key to identify each note. To prevent the cases of duplicate keys, we will check that at
least to consecutive records dont have the same key, and if they do, will ignore the second one.
*/
let lastPlotterKey = "";
for (let i = 0; i < pNewNotes.length; i++) {
found = false;
let plotterNote = pNewNotes[i];
let plotterNoteKey = plotterNote.date.toString() + plotterNote.rate.toString();
let floatingNote;
let floatingNoteKey;
if (lastPlotterKey === plotterNoteKey) {
if (INFO_WARN=== true) { logger.write("[WARN] createNoteSet -> onNotesChanged -> Add new Notes -> Duplicate record detected. Discarding it."); }
if (INFO_WARN === true) { logger.write("[WARN] createNoteSet -> onNotesChanged -> Add new Notes -> i = " + i); }
continue;
}
lastPlotterKey = plotterNoteKey;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> i = " + i); }
for (let j = 0; j < noteSet.floatingNotes.length; j++) {
floatingNote = noteSet.floatingNotes[j];
floatingNoteKey = floatingNote.date.toString() + floatingNote.rate.toString();
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> j = " + j); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> floatingNoteKey = " + floatingNoteKey); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> plotterNoteKey = " + plotterNoteKey); }
if (plotterNoteKey === floatingNoteKey) {
found = true;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> found = " + found); }
break;
}
}
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> End of For j."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> found = " + found); }
if (found === false) {
/*
Before adding a new item to the array, we need to create a floatingObject of type Note. Once we set its basic parameters
we can it to our array and to the floating layer.
*/
let floatingObject = newFloatingObject();
floatingObject.initialize("Note", onInitialized);
function onInitialized(err) {
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> Entering function."); }
floatingObject.payload = noteSet.payload;
floatingObject.payloadNoteIndex = i;
floatingObject.payloadImageId = noteSet.imageId;
floatingObject.friction = .995;
floatingObject.initializeMass(200);
//let bodyText = pNewNotes[i].body;
let radius;
/*
if (bodyText.length < 100) {
radius = 100;
} else {
radius = bodyText.length;
}
*/
radius = 50;
floatingObject.initializeRadius(radius);
floatingObject.initializeImageSize(15);
floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 0.5)';
floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)';
floatingLayer.addFloatingObject(floatingObject);
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> New Note added to Layer."); }
plotterNote.floatingHandle = floatingObject.handle;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> plotterNote.floatingHandle = " + plotterNote.floatingHandle); }
newFloatingNotes.push(plotterNote);
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> Added to newFloatingNotes."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> newFloatingNotes.length = " + newFloatingNotes.length); }
}
} else {
newFloatingNotes.push(floatingNote);
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> Old Note Kept."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> floatingNote.floatingHandle = " + floatingNote.floatingHandle); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> Added to newFloatingNotes."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> newFloatingNotes.length = " + newFloatingNotes.length); }
let floatingObject = floatingLayer.getFloatingObject(floatingNote.floatingHandle);
floatingObject.payloadNoteIndex = i;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> floatingObject index updated."); }
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> floatingObject.payloadNoteIndex = " + i); }
}
}
noteSet.floatingNotes = newFloatingNotes;
if (INFO_LOG === true) { logger.write("[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> noteSet.floatingNotes.length = " + noteSet.floatingNotes.length); }
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] createNoteSet -> onNotesChanged -> err = " + err); }
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] createNoteSet -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function destroyNoteSet(pHandle) {
try {
/*
Usually when a bot is disabled by the end user, or the zoom level changes to one where the notes must not be seen, this method
to destroy an entire NoteSet is executed. What we do in this situation is to localize the NoteSet to be destroyed and we need to
kill, one by one the floating objects in it. Finally we remove this NoteSet item from the NoteSets array.
*/
if (INFO_LOG === true) { logger.write("[INFO] destroyNoteSet -> Entering function."); }
for (let i = 0; i < noteSets.length; i++) {
let noteSet = noteSets[i];
if (noteSet.handle === pHandle) {
for (let j = 0; j < noteSet.floatingNotes.length; j++) {
let floatingNote = noteSet.floatingNotes[j];
floatingLayer.killFloatingObject(floatingNote.floatingHandle);
}
noteSets.splice(i, 1); // Delete item from array.
return;
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] destroyNoteSet -> err = " + err); }
}
}
}
+356
View File
@@ -0,0 +1,356 @@
function newProfileBall() {
let thisObject = {
physicsLoop: physicsLoop,
onMouseOver: onMouseOver,
onMouseClick: onMouseClick,
onMouseNotOver: onMouseNotOver,
drawBackground: drawBackground,
drawForeground: drawForeground,
initialize: initialize
};
let ballStringMenu = [
{
visible: false,
imagePathOn: "Images/menu.icon.on.1.gif",
imagePathOff: "Images/menu.icon.off.1.gif",
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
angle: 60
},
{
visible: false,
imagePathOn: "Images/menu.icon.on.2.gif",
imagePathOff: "Images/menu.icon.off.2.gif",
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
angle: 20 * 1
},
{
visible: false,
imagePathOn: "Images/menu.icon.on.3.gif",
imagePathOff: "Images/menu.icon.off.3.gif",
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
angle: -20
},
{
visible: false,
imagePathOn: "Images/menu.icon.on.4.gif",
imagePathOff: "Images/menu.icon.off.4.gif",
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
angle: -60
}
];
return thisObject;
function initialize(callBackFunction) {
for (let i = 0; i < ballStringMenu.length; i++) {
let menuItem = ballStringMenu[i];
menuItem.iconOn = new Image();
menuItem.iconOn.onload = onImageLoad;
function onImageLoad() {
menuItem.iconOff = new Image();
menuItem.iconOff.onload = onImageLoad;
function onImageLoad() {
menuItem.canDrawIcon = true;
}
menuItem.iconOff.src = window.canvasApp.urlPrefix + menuItem.imagePathOff;
}
menuItem.iconOn.src = window.canvasApp.urlPrefix + menuItem.imagePathOn;
menuItem.icon = menuItem.iconOn; // The default value is ON.
}
callBackFunction();
}
function physicsLoop() {
// The menuItems also have a target.
for (let i = 0; i < ballStringMenu.length; i++) {
let menuItem = ballStringMenu[i];
if (Math.abs(menuItem.currentRadius - menuItem.targetRadius) >= 0.5) {
if (menuItem.currentRadius < menuItem.targetRadius) {
menuItem.currentRadius = menuItem.currentRadius + 0.5;
} else {
menuItem.currentRadius = menuItem.currentRadius - 0.5;
}
}
}
}
function onMouseOver() {
for (let i = 0; i < ballStringMenu.length; i++) {
let menuItem = ballStringMenu[i];
menuItem.targetRadius = menuItem.rawRadius * 1.5;
}
}
function onMouseNotOver() {
for (let i = 0; i < ballStringMenu.length; i++) {
let menuItem = ballStringMenu[i];
menuItem.targetRadius = menuItem.rawRadius * 0 - i * 5;
}
}
function onMouseClick(pPoint, pFloatingObject) {
/* What we need to do here is to check which menu item was clicked, if any. */
let menuItemIndex;
for (let i = 0; i < ballStringMenu.length; i++) {
let menuItem = ballStringMenu[i];
if (menuItem.canDrawIcon === true && menuItem.currentRadius > 1) {
let position = {
x: pFloatingObject.currentPosition.x + pFloatingObject.currentImageSize / 2 * Math.cos(toRadians(menuItem.angle)),
y: pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2 * Math.sin(toRadians(menuItem.angle))
};
browserCanvasContext.drawImage(menuItem.icon, position.x, position.y, menuItem.currentRadius * 2, menuItem.currentRadius * 2);
let distance = Math.sqrt(Math.pow(position.x - pPoint.x, 2) + Math.pow(position.y - pPoint.y, 2));
if (distance < menuItem.currentRadius) {
menuItemIndex = i;
}
}
}
if (menuItemIndex !== undefined) {
switch (menuItemIndex) {
case 0: { // This menu item is to turn ON / OFF the plotting of this bot.
if (pFloatingObject.payload.profile.plot === true) {
pFloatingObject.payload.profile.plot = false;
let menuItem = ballStringMenu[0];
menuItem.icon = menuItem.iconOff;
} else {
pFloatingObject.payload.profile.plot = true;
let menuItem = ballStringMenu[0];
menuItem.icon = menuItem.iconOn;
}
break;
}
case 1: { // This menu item is to turn ON the Debug Log pannel for the bot.
break;
}
}
}
}
function drawBackground(pFloatingObject) {
let point = {
x: pFloatingObject.payload.profile.position.x,
y: pFloatingObject.payload.profile.position.y
};
point = viewPort.fitIntoVisibleArea(point);
if (pFloatingObject.currentRadius > 1) {
/* Target Line */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y);
browserCanvasContext.lineTo(point.x, point.y);
browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)';
browserCanvasContext.setLineDash([4, 2]);
browserCanvasContext.lineWidth = 1;
browserCanvasContext.stroke();
browserCanvasContext.setLineDash([0, 0]);
}
if (pFloatingObject.currentRadius > 0.5) {
/* Target Spot */
var radius = 1;
browserCanvasContext.beginPath();
browserCanvasContext.arc(point.x, point.y, radius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = 'rgba(30, 30, 30, 1)';
browserCanvasContext.fill();
}
}
function drawForeground(pFloatingObject) {
if (pFloatingObject.currentRadius > 5) {
/* Contourn */
browserCanvasContext.beginPath();
browserCanvasContext.arc(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y, pFloatingObject.currentRadius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(30, 30, 30, 0.75)';
browserCanvasContext.lineWidth = 1;
browserCanvasContext.stroke();
}
if (pFloatingObject.currentRadius > 0.5) {
/* Main FloatingObject */
var alphaA;
if (pFloatingObject.currentRadius < 3) {
alphaA = 1;
} else {
alphaA = 0.75;
}
alphaA = 0.75;
browserCanvasContext.beginPath();
browserCanvasContext.arc(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y, pFloatingObject.currentRadius, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = pFloatingObject.fillStyle;
browserCanvasContext.fill();
}
/* Image */
if (pFloatingObject.payload.profile.imageId !== undefined) {
let image = pFloatingObject.payload.profile.botAvatar;
if (image !== null && image !== undefined) {
browserCanvasContext.save();
browserCanvasContext.beginPath();
browserCanvasContext.arc(pFloatingObject.currentPosition.x , pFloatingObject.currentPosition.y , pFloatingObject.currentImageSize / 2, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.clip();
browserCanvasContext.drawImage(image, pFloatingObject.currentPosition.x - pFloatingObject.currentImageSize / 2, pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize, pFloatingObject.currentImageSize);
browserCanvasContext.beginPath();
browserCanvasContext.arc(pFloatingObject.currentPosition.x - pFloatingObject.currentImageSize / 2, pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize / 2, 0, Math.PI * 2, true);
browserCanvasContext.clip();
browserCanvasContext.closePath();
browserCanvasContext.restore();
}
}
/* StringBall Menu */
for (let i = 0; i < ballStringMenu.length; i++) {
let menuItem = ballStringMenu[i];
if (menuItem.canDrawIcon === true && menuItem.currentRadius > 1) {
let position = {
x: pFloatingObject.currentPosition.x + pFloatingObject.currentImageSize / 2 * Math.cos(toRadians(menuItem.angle)),
y: pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2 * Math.sin(toRadians(menuItem.angle))
};
browserCanvasContext.drawImage(menuItem.icon, position.x - menuItem.currentRadius, position.y - menuItem.currentRadius, menuItem.currentRadius * 2, menuItem.currentRadius * 2);
}
}
/* Label Text */
if (pFloatingObject.currentRadius > 6) {
browserCanvasContext.strokeStyle = pFloatingObject.labelStrokeStyle;
let labelPoint;
let fontSize = pFloatingObject.currentFontSize;
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
let label;
label = pFloatingObject.payload.profile.upLabel;
if (label !== undefined) {
labelPoint = {
x: pFloatingObject.currentPosition.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2 - fontSize * FONT_ASPECT_RATIO - 10
};
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = pFloatingObject.labelStrokeStyle;
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
label = pFloatingObject.payload.profile.downLabel;
if (label !== undefined) {
labelPoint = {
x: pFloatingObject.currentPosition.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: pFloatingObject.currentPosition.y + pFloatingObject.currentImageSize / 2 + fontSize * FONT_ASPECT_RATIO + 15
};
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = pFloatingObject.labelStrokeStyle;
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
}
}
}
+77
View File
@@ -0,0 +1,77 @@
function newProfileBalls() {
const MODULE_NAME = "Profile Balls";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
/*
This object deals with Profile Balls, a type of Floating Object that shows profile info in a floating ball.
*/
let thisObject = {
createNewProfileBall: createNewProfileBall,
destroyProfileBall: destroyProfileBall,
initialize: initialize
}
let floatingLayer;
return thisObject;
function initialize(pFloatingLayer, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
floatingLayer = pFloatingLayer;
callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function createNewProfileBall(pPayload, callBackFunction) {
let floatingObject = newFloatingObject();
floatingObject.initialize("Profile Ball", onInitialized);
function onInitialized(err) {
floatingObject.payload = pPayload;
floatingObject.friction = .995;
floatingObject.initializeMass(100);
floatingObject.initializeRadius(30);
floatingObject.initializeImageSize(50);
floatingObject.initializeFontSize(10);
floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 0.5)';
floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)';
floatingLayer.addFloatingObject(floatingObject);
callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE, floatingObject.handle);
}
}
function destroyProfileBall(pFloatingObjectHandle) {
floatingLayer.killFloatingObject(pFloatingObjectHandle);
}
}
+590
View File
@@ -0,0 +1,590 @@
function newFrame() {
const PANEL_CORNERS_RADIOUS = 5;
const TITLE_BAR_HEIGHT = 14; // this must be grater than radius
var frame = {
containerName: "", // This is for debugging purposes only.
parentFrame: undefined, // Here we store the parent cointainer zoom object.
width: browserCanvas.width,
height: browserCanvas.height,
position: undefined,
getBodyHeight: getBodyHeight,
draw: draw,
container: undefined,
frameThisPoint: frameThisPoint, // This function changes the actual frame coordinate system to the screen coordinate system.
unframeThisPoint: unframeThisPoint,
fitIntoFrame: fitIntoFrame,
isThisPointHere: isThisPointHere, // This function return true is the point received as parameter lives within this frame.
isInViewPort: isInViewPort,
canYouMoveHere: canYouMoveHere,
canYouZoomHere: canYouZoomHere,
initialize: initialize
};
return frame;
function initialize() {
var position = {
x: 0,
y: 0
};
this.position = position;
}
function getBodyHeight() {
return frame.height - TITLE_BAR_HEIGHT;
}
function isInViewPort() {
point1 = {
x: 0,
y: 0
};
point3 = {
x: frame.width,
y: frame.height
};
/* Now the transformations. */
point1 = transformThisPoint(point1, frame.container);
point3 = transformThisPoint(point3, frame.container);
if (point1.x < viewPort.visibleArea.topRight.x && point1.y < viewPort.visibleArea.bottomRight.y && point3.x > viewPort.visibleArea.bottomLeft.x && point3.y > viewPort.visibleArea.topLeft.y ) {
return true;
} else {
return false;
}
}
function fitIntoFrame(point) {
/* Here we check the boundaries of the resulting points, so they dont go out of the visible area. */
if (point.x > frame.width) {
point.x = frame.width;
}
if (point.x < 0) {
point.x = 0;
}
if (point.y > frame.height) {
point.y = frame.height;
}
if (point.y < 0) {
point.y = 0;
}
return point;
}
function frameThisPoint(point) {
if (this.parentFrame !== undefined) {
point = this.parentFrame.frameThisPoint(point);
}
point.x = point.x + frame.position.x;
point.y = point.y + frame.position.y;
return point;
}
function unframeThisPoint(point) {
if (this.parentFrame !== undefined) {
point = this.parentFrame.unframeThisPoint(point);
}
point.x = point.x - this.position.x;
point.y = point.y - this.position.y;
return point;
}
function canYouMoveHere(tempDisplacement) {
/*
The current frame has a position and a displacement. We need to check that none of the boundaries points of the frame fall outside of its container frame.
First we apply the theoreticall displacement.
*/
point1 = {
x: this.position.x,
y: this.position.y
};
point2 = {
x: this.position.x + this.width,
y: this.position.y
};
point3 = {
x: this.position.x + this.width,
y: this.position.y + this.height
};
point4 = {
x: this.position.x,
y: this.position.y + this.height
};
/* Now the transformations. */
if (this.parentFrame !== undefined) { // If there is not a parent then there is no point to check bounderies.
point1 = this.parentFrame.frameThisPoint(point1);
point2 = this.parentFrame.frameThisPoint(point2);
point3 = this.parentFrame.frameThisPoint(point3);
point4 = this.parentFrame.frameThisPoint(point4);
/* We apply the temporary displacement. */
point1 = tempDisplacement.displaceThisPoint(point1);
point2 = tempDisplacement.displaceThisPoint(point2);
point3 = tempDisplacement.displaceThisPoint(point3);
point4 = tempDisplacement.displaceThisPoint(point4);
/* We add the actual displacement. */
point1 = this.container.displacement.displaceThisPoint(point1);
point2 = this.container.displacement.displaceThisPoint(point2);
point3 = this.container.displacement.displaceThisPoint(point3);
point4 = this.container.displacement.displaceThisPoint(point4);
if (this.parentFrame.isThisPointHere(point1) === false) {
return false;
}
if (this.parentFrame.isThisPointHere(point2) === false) {
return false;
}
if (this.parentFrame.isThisPointHere(point3) === false) {
return false;
}
if (this.parentFrame.isThisPointHere(point4) === false) {
return false;
}
}
return true;
}
function canYouZoomHere(tempZoom) {
point1 = {
x: this.position.x,
y: this.position.y
};
point2 = {
x: this.position.x + this.width,
y: this.position.y
};
point3 = {
x: this.position.x + this.width,
y: this.position.y + this.height
};
point4 = {
x: this.position.x,
y: this.position.y + this.height
};
/* Now the transformations. */
if (this.parentFrame !== undefined) { // If there is not a parent then there is no point to check bounderies.
point1 = this.parentFrame.frameThisPoint(point1);
point2 = this.parentFrame.frameThisPoint(point2);
point3 = this.parentFrame.frameThisPoint(point3);
point4 = this.parentFrame.frameThisPoint(point4);
/* We add the actual displacement. */
point1 = this.container.displacement.displaceThisPoint(point1);
point2 = this.container.displacement.displaceThisPoint(point2);
point3 = this.container.displacement.displaceThisPoint(point3);
point4 = this.container.displacement.displaceThisPoint(point4);
/* We temp zoom. */
point1 = tempZoom.zoomThisPoint(point1);
point2 = tempZoom.zoomThisPoint(point2);
point3 = tempZoom.zoomThisPoint(point3);
point4 = tempZoom.zoomThisPoint(point4);
if (this.parentFrame.isThisPointHere(point1) === false) {
return false;
}
if (this.parentFrame.isThisPointHere(point2) === false) {
return false;
}
if (this.parentFrame.isThisPointHere(point3) === false) {
return false;
}
if (this.parentFrame.isThisPointHere(point4) === false) {
return false;
}
}
return true;
}
function isThisPointHere(point, outsideViewPort) { // The second parameter is usefull when you want to check a point that you already know is outside the viewport.
/* We need not to modify the point received, so me make a copy of it. */
var checkPoint = {
x: point.x,
y: point.y
};
/* The point received is on the screen coordinates system, which already has zoom and displacement applied. We need to remove the zoom and displacement
in order to have the point on the containers coordinate system and be able to compare it with its dimmensions. */
if (outsideViewPort === true) {
checkPoint = this.container.displacement.undisplaceThisPoint(checkPoint);
checkPoint = this.container.frame.unframeThisPoint(checkPoint);
} else {
checkPoint = unTransformThisPoint(checkPoint, frame.container);
}
/* Now we check if the resulting point is whin the current Frame. */
if (checkPoint.x < 0 || checkPoint.y < 0 || checkPoint.x > frame.width || checkPoint.y > frame.height) {
/* The point received is not in this frame */
return false;
} else {
/* The point is within this frame. */
return true;
}
}
function draw(drawGrid, drawBorders, drawBackground) {
if (drawBorders === true) {
borders();
}
if (drawGrid === true) {
grid();
}
if (drawBackground === true) {
background();
}
}
function background() {
borderPoint1 = {
x: PANEL_CORNERS_RADIOUS,
y: PANEL_CORNERS_RADIOUS
};
borderPoint2 = {
x: frame.width - PANEL_CORNERS_RADIOUS,
y: PANEL_CORNERS_RADIOUS
};
borderPoint3 = {
x: frame.width - PANEL_CORNERS_RADIOUS,
y: frame.height - PANEL_CORNERS_RADIOUS
};
borderPoint4 = {
x: PANEL_CORNERS_RADIOUS,
y: frame.height - PANEL_CORNERS_RADIOUS
};
titleBarPoint1 = {
x: 0,
y: TITLE_BAR_HEIGHT
};
titleBarPoint2 = {
x: frame.width,
y: TITLE_BAR_HEIGHT
};
/* Now the transformations. */
borderPoint1 = frameThisPoint(borderPoint1);
borderPoint2 = frameThisPoint(borderPoint2);
borderPoint3 = frameThisPoint(borderPoint3);
borderPoint4 = frameThisPoint(borderPoint4);
titleBarPoint1 = frameThisPoint(titleBarPoint1);
titleBarPoint2 = frameThisPoint(titleBarPoint2);
/* We paint the panel background first */
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 0.75)';
browserCanvasContext.beginPath();
browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, PANEL_CORNERS_RADIOUS, 1.0 * Math.PI, 1.5 * Math.PI);
browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - PANEL_CORNERS_RADIOUS);
browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, PANEL_CORNERS_RADIOUS, 1.5 * Math.PI, 2.0 * Math.PI);
browserCanvasContext.lineTo(borderPoint3.x + PANEL_CORNERS_RADIOUS, borderPoint3.y);
browserCanvasContext.arc(borderPoint3.x, borderPoint3.y, PANEL_CORNERS_RADIOUS, 0 * Math.PI, 0.5 * Math.PI);
browserCanvasContext.lineTo(borderPoint4.x, borderPoint4.y + PANEL_CORNERS_RADIOUS);
browserCanvasContext.arc(borderPoint4.x, borderPoint4.y, PANEL_CORNERS_RADIOUS, 0.5 * Math.PI, 1.0 * Math.PI);
browserCanvasContext.lineTo(borderPoint1.x - PANEL_CORNERS_RADIOUS, borderPoint1.y);
browserCanvasContext.closePath();
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 0.75)';
browserCanvasContext.stroke();
/* We paint the title bar now */
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 0.75)';
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(titleBarPoint1.x, titleBarPoint1.y);
browserCanvasContext.lineTo(borderPoint1.x - PANEL_CORNERS_RADIOUS, borderPoint1.y);
browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, PANEL_CORNERS_RADIOUS, 1.0 * Math.PI, 1.5 * Math.PI);
browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - PANEL_CORNERS_RADIOUS);
browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, PANEL_CORNERS_RADIOUS, 1.5 * Math.PI, 2.0 * Math.PI);
browserCanvasContext.lineTo(titleBarPoint2.x, titleBarPoint2.y);
browserCanvasContext.closePath();
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 0.75)';
browserCanvasContext.stroke();
/* print the title */
let labelPoint;
let fontSize = 10;
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
let label = frame.containerName;
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO;
let yOffset = (TITLE_BAR_HEIGHT - fontSize) / 2 + 2;
labelPoint = {
x: frame.width / 2 - xOffset,
y: TITLE_BAR_HEIGHT - yOffset
};
labelPoint = frame.frameThisPoint(labelPoint);
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
function borders() {
/* Lest get the important points of the drawing so as to apply the needed transformations. */
point1 = {
x: 0,
y: 0
};
point2 = {
x: frame.width,
y: 0
};
point3 = {
x: frame.width,
y: frame.height
};
point4 = {
x: 0,
y: frame.height
};
/* Now the transformations. */
point1 = transformThisPoint(point1, frame.container);
point2 = transformThisPoint(point2, frame.container);
point3 = transformThisPoint(point3, frame.container);
point4 = transformThisPoint(point4, frame.container);
/* Lets start the drawing. */
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
browserCanvasContext.lineTo(point1.x, point1.y);
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(150, 150, 150, 1)';
browserCanvasContext.lineWidth = 1;
browserCanvasContext.stroke();
browserCanvasContext.closePath();
}
function grid(smallLines) {
if (smallLines === true) {
/* Small Lines */
var step = frame.width / 100;
browserCanvasContext.beginPath();
for (var i = 0; i < frame.width; i = i + step) {
for (var j = 0; j < frame.height; j = j + step) {
let point1 = {
x: 0,
y: j
};
let point2 = {
x: frame.width,
y: j
};
point1 = transformThisPoint(point1, frame.container);
point2 = transformThisPoint(point2, frame.container);
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
}
let point3 = {
x: frame.width,
y: frame.height
};
let point4 = {
x: 0,
y: frame.height
};
point3 = transformThisPoint(point3, frame.container);
point4 = transformThisPoint(point4, frame.container);
browserCanvasContext.moveTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
}
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(150, 150, 150, 0.1)';
browserCanvasContext.lineWidth = 1;
browserCanvasContext.stroke();
}
/* Main Lines */
var step = frame.width / 20;
browserCanvasContext.beginPath();
for (var i = 0; i < frame.width; i = i + step) {
for (var j = 0; j < frame.height; j = j + step) {
let point1 = {
x: 0,
y: j
};
let point2 = {
x: frame.width,
y: j
};
point1 = transformThisPoint(point1, frame.container);
point2 = transformThisPoint(point2, frame.container);
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
}
let point3 = {
x: i,
y: 0
};
let point4 = {
x: i,
y: frame.height
};
point3 = transformThisPoint(point3, frame.container);
point4 = transformThisPoint(point4, frame.container);
browserCanvasContext.moveTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
}
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(100, 100, 100, 0.2)';
browserCanvasContext.lineWidth = 1;
browserCanvasContext.stroke();
}
}
+171
View File
@@ -0,0 +1,171 @@
/* User Interface Colors */
UI_COLOR = {
DARK: "48, 48, 54",
LIGHT: "234, 226, 222",
WHITE: "255, 255, 255",
GOLDEN_ORANGE: "240, 162, 2",
RUSTED_RED: "204, 88, 53",
GREEN: "188, 214, 67",
RED: "223, 70, 60",
PATINATED_TURQUOISE: "27,153,139",
TITANIUM_YELLOW: "244,228,9",
MANGANESE_PURPLE: "91,80,122"
};
/* User Interface Fonts */
UI_FONT = {
PRIMARY: "Saira",
SECONDARY: "Source Code Pro"
};
FONT_ASPECT_RATIO = 0.45;
/* User Interface Panels */
UI_PANEL = {
WIDTH: {
SMALL: 100,
NORMAL: 150,
LARGE: 350
},
HEIGHT: {
SMALL: 65,
NORMAL: 300,
LARGE: 450
}
};
let marketFilesPeriods =
'[' +
'[' + 24 * 60 * 60 * 1000 + ',' + '"24-hs"' + ']' + ',' +
'[' + 12 * 60 * 60 * 1000 + ',' + '"12-hs"' + ']' + ',' +
'[' + 8 * 60 * 60 * 1000 + ',' + '"08-hs"' + ']' + ',' +
'[' + 6 * 60 * 60 * 1000 + ',' + '"06-hs"' + ']' + ',' +
'[' + 4 * 60 * 60 * 1000 + ',' + '"04-hs"' + ']' + ',' +
'[' + 3 * 60 * 60 * 1000 + ',' + '"03-hs"' + ']' + ',' +
'[' + 2 * 60 * 60 * 1000 + ',' + '"02-hs"' + ']' + ',' +
'[' + 1 * 60 * 60 * 1000 + ',' + '"01-hs"' + ']' + ']';
marketFilesPeriods = JSON.parse(marketFilesPeriods);
let dailyFilePeriods =
'[' +
'[' + 45 * 60 * 1000 + ',' + '"45-min"' + ']' + ',' +
'[' + 40 * 60 * 1000 + ',' + '"40-min"' + ']' + ',' +
'[' + 30 * 60 * 1000 + ',' + '"30-min"' + ']' + ',' +
'[' + 20 * 60 * 1000 + ',' + '"20-min"' + ']' + ',' +
'[' + 15 * 60 * 1000 + ',' + '"15-min"' + ']' + ',' +
'[' + 10 * 60 * 1000 + ',' + '"10-min"' + ']' + ',' +
'[' + 05 * 60 * 1000 + ',' + '"05-min"' + ']' + ',' +
'[' + 04 * 60 * 1000 + ',' + '"04-min"' + ']' + ',' +
'[' + 03 * 60 * 1000 + ',' + '"03-min"' + ']' + ',' +
'[' + 02 * 60 * 1000 + ',' + '"02-min"' + ']' + ',' +
'[' + 01 * 60 * 1000 + ',' + '"01-min"' + ']' + ']';
dailyFilePeriods = JSON.parse(dailyFilePeriods);
function convertTimePeriodToName(pTimePeriod) {
for (let i = 0; i < dailyFilePeriods.length; i++) {
let period = dailyFilePeriods[i];
if (period[0] === pTimePeriod) {
return period[1];
}
}
for (let i = 0; i < marketFilesPeriods.length; i++) {
let period = marketFilesPeriods[i];
if (period[0] === pTimePeriod) {
return period[1];
}
}
}
window.AT_BREAKPOINT = false;
const INITIAL_DEFAULT_MARKET = 2; // This is the market that will be shown when loading the site for the first time.
const DEFAULT_EXCHANGE = "Poloniex";
const DEFAULT_MARKET = {
assetA: "USDT",
assetB: "BTC",
};
const USDT_BTC_HTH = 19900; // This is needed to know the scale of the market time line.
const WIDHTER_VOLUME_BAR_BASE_FACTOR = 2.5;
const LESS_WIDHTER_VOLUME_BAR_TOP_FACTOR = 1 / 4;
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
const _12_HOURS_IN_MILISECONDS = 12 * 60 * 60 * 1000;
const _8_HOURS_IN_MILISECONDS = 8 * 60 * 60 * 1000;
const _6_HOURS_IN_MILISECONDS = 6 * 60 * 60 * 1000;
const _4_HOURS_IN_MILISECONDS = 4 * 60 * 60 * 1000;
const _3_HOURS_IN_MILISECONDS = 3 * 60 * 60 * 1000;
const _2_HOURS_IN_MILISECONDS = 2 * 60 * 60 * 1000;
const _1_HOUR_IN_MILISECONDS = 1 * 60 * 60 * 1000;
const _45_MINUTES_IN_MILISECONDS = 45 * 60 * 1000;
const _40_MINUTES_IN_MILISECONDS = 40 * 60 * 1000;
const _30_MINUTES_IN_MILISECONDS = 30 * 60 * 1000;
const _20_MINUTES_IN_MILISECONDS = 20 * 60 * 1000;
const _15_MINUTES_IN_MILISECONDS = 15 * 60 * 1000;
const _10_MINUTES_IN_MILISECONDS = 10 * 60 * 1000;
const _5_MINUTES_IN_MILISECONDS = 5 * 60 * 1000;
const _4_MINUTES_IN_MILISECONDS = 4 * 60 * 1000;
const _3_MINUTES_IN_MILISECONDS = 3 * 60 * 1000;
const _2_MINUTES_IN_MILISECONDS = 2 * 60 * 1000;
const _1_MINUTE_IN_MILISECONDS = 1 * 60 * 1000;
const EARLIEST_DATE = new Date(2014, 0, 18, 4, 26, 8);
const TOP_SPACE_HEIGHT = 5;
const BOTTOM_SPACE_HEIGHT = 35;
const PRODUCT_CARD_STATUS = {
ON: 'on',
LOADING: 'loading',
OFF: 'off'
};
/* Here we list the valid Time Periods: */
const PERIOD_24_HS = "24-hs";
const PERIOD_12_HS = "12-hs";
const PERIOD_06_HS = "06-hs";
const PERIOD_03_HS = "03-hs";
const PERIOD_01_HS = "01-hs";
const PERIOD_30_MIN = "30-min";
const PERIOD_10_MIN = "10-min";
const PERIOD_05_MIN = "05-min";
const PERIOD_01_MIN = "01-min";
let INITIAL_DATE = new Date(); // This value will be overwritten at the viewPort.initialize if the user had a prevous session with this same browser.
var maxDate = new Date();
maxDate.setMilliseconds(0);
maxDate.setDate(maxDate.getDate() + 10);
const MAX_PLOTABLE_DATE = maxDate;
/*
We define here the size of the chartSpace. It has to bee enough big in order to accomodate all the charts we expect to display in this space.
*/
const CHART_SPACE_WIDTH = browserCanvas.width * 1000;
const CHART_SPACE_HEIGHT = browserCanvas.height * 100;
function toRadians(angle) {
return angle * (Math.PI / 180);
}
+127
View File
@@ -0,0 +1,127 @@
function newImageButton() {
var thisObject = {
container: undefined,
draw: draw,
status: 'neutral',
type: undefined,
getContainer: getContainer,
initialize: initialize
};
var container = newContainer();
container.initialize();
container.isDraggeable = false;
container.isClickeable = true;
thisObject.container = container;
let idNeutralImage;
let idOnImage;
let idOffImage;
let idDisabledImage;
return thisObject;
function initialize(pX, pY, pWidth, pHeight, pIdNeutralImage, pIdOnImage, pIdOffImage, pIdDisabledImage) {
idNeutralImage = pIdNeutralImage;
idOnImage = pIdOnImage;
idOffImage = pIdOffImage;
idDisabledImage = pIdDisabledImage;
/* Lets set the basic dimensions of this thisObject. */
var position = {
x: pX,
y: pY
};
thisObject.container.frame.position = position;
thisObject.container.frame.width = pWidth;
thisObject.container.frame.height = pHeight;
/* Now we start listening to the onClick event from the mouse, so that we can allow users operate this thisObject. */
thisObject.container.eventHandler.listenToEvent('onMouseClick', buttonPressed, undefined);
}
function getContainer(point) {
var container;
/* First we check if this point is inside this space. */
if (this.container.frame.isThisPointHere(point, true) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
}
function buttonPressed(event, extraData) {
switch (thisObject.status) {
case 'neutral':
browserCanvasContext.fillStyle = onFillStyle;
return;
case 'on':
thisObject.status = 'off';
break;
case 'off':
thisObject.status = 'on';
break;
case 'disabled':
return;
}
}
function draw() {
drawImage();
}
function drawImage() {
let image;
let imagePoint = {
x: 0,
y: 0
};
imagePoint = thisObject.container.frame.frameThisPoint(imagePoint);
switch (thisObject.status) {
case 'neutral':
image = document.getElementById(idNeutralImage);
break;
case 'on':
image = document.getElementById(idOnImage);
break;
case 'off':
image = document.getElementById(idOffImage);
break;
case 'disabled':
image = document.getElementById(idDisabledImage);
break;
}
browserCanvasContext.drawImage(image, imagePoint.x, imagePoint.y, thisObject.container.frame.width, thisObject.container.frame.height);
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

+48
View File
@@ -0,0 +1,48 @@
COPYRIGHT NOTICE
© Copyright 2018 Advanced Algos
LICENSE NOTICE
Advanced Algos is a startup, currently at a very early stage. Because certain aspects of
the business are still not clearly defined, we have chosen to --temporarily-- grant a
restrictive license for the use of CanvasApp, until those business aspects are clarified
and a proper open source license can be granted.
Advanced Algos is publishing the code of this software for several reasons. However,
it shall not be considered free software yet. Advanced Algos is a for-profit company
in the crypto space and CanvasApp is still proprietary software.
The reasons for opening up the code of CanvasApp at this stage are the following:
* We believe that transparency is paramount to achieving our goals, so we want everyone
to be able to understand what CanvasApp does and how. Opening up the code of CanvasApp allows
anyone to take a close look.
* We welcome contributions from the community. Contributions are compensated on a case
by case basis with ALGO tokens. Contributions are deemed _work for hire_ and contributors
agree to provide an express grant of patent rights for their contributions.
* We wish the community to be able to create their own bots and watch their activity in CanvasApp, thus we grant
a development and testing license so that developers can test their bots in their local
environment.
LICENSE WORDING
Advanced Algos grants a limited license for the following uses:
1. CODE REVIEW AND AUDITS. You are granted permission to clone the CanvasApp repository to analyze,
review or audit the code.
2. COLLABORATING WITH ADVANCED ALGOS. You are granted permission to fork the CanvasApp repository
with the sole purpose of correcting bugs and developing functionality in agreement with
Advanced Algos. Before your contributions are merged into our repository, you will be requested
to sign a Contributors Work for Hire Agreement.
3. DEVELOPMENT AND TESTING OF TRADING BOTS. You are granted permission to clone the CanvasApp
repository and use the software in your local environment to develop and test trading bots.
+240
View File
@@ -0,0 +1,240 @@
function newProductsPanel() {
var thisObject = {
container: undefined,
getLoadingProductCards: getLoadingProductCards,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
};
/* Cointainer stuff */
var container = newContainer();
container.name = "Indicators and Algobots Product Panel";
container.initialize();
container.isDraggeable = true;
container.isWheelable = true;
thisObject.container = container;
thisObject.container.frame.containerName = "Indicators and Algobots's Products";
let isInitialized = false;
let productCards = [];
let visibleProductCards = [];
let firstVisibleCard = 1;
/* Needed Variables */
var lastY = 5;
return thisObject;
function initialize() {
thisObject.container.frame.width = UI_PANEL.WIDTH.LARGE;
thisObject.container.frame.height = viewPort.visibleArea.bottomLeft.y - viewPort.visibleArea.topLeft.y; //UI_PANEL.HEIGHT.LARGE;
var position = {
x: viewPort.visibleArea.topLeft.x,
y: viewPort.visibleArea.bottomLeft.y - thisObject.container.frame.height
};
thisObject.container.frame.position = position;
/* First thing is to build the productCards array */
let devTeams = ecosystem.getTeams();
for (let i = 0; i < devTeams.length; i++) {
let devTeam = devTeams[i];
for (let j = 0; j < devTeam.bots.length; j++) {
let bot = devTeam.bots[j];
if (bot.products !== undefined) {
for (let k = 0; k < bot.products.length; k++) {
let product = bot.products[k];
/* Now we create Product objects */
let productCard = newProductCard();
productCard.devTeam = devTeam;
productCard.bot = bot;
productCard.product = product;
productCard.code = devTeam.codeName + '-' + bot.codeName + '-' + product.codeName;
/* Initialize it */
productCard.initialize();
/* Container Stuff */
productCard.container.displacement.parentDisplacement = thisObject.container.displacement;
productCard.container.frame.parentFrame = thisObject.container.frame;
productCard.container.parentContainer = thisObject.container;
productCard.container.isWheelable = true;
/* Positioning within thisObject Panel */
let position = {
x: 10,
y: thisObject.container.frame.height - thisObject.container.frame.getBodyHeight()
};
productCard.container.frame.position.x = position.x;
productCard.container.frame.position.y = position.y + lastY;
lastY = lastY + productCard.container.frame.height;
/* Add to the Product Array */
productCards.push(productCard);
/* Add to Visible Product Array */
if (productCard.container.frame.position.y + productCard.container.frame.height < thisObject.container.frame.height) {
visibleProductCards.push(productCard);
}
/* Listen to Status Changes Events */
productCard.container.eventHandler.listenToEvent('Status Changed', onProductCardStatusChanged);
productCard.container.eventHandler.listenToEvent('Mouse Wheel', onMouseWheel);
}
}
}
}
thisObject.container.eventHandler.listenToEvent("Mouse Wheel", onMouseWheel);
isInitialized = true;
}
function onMouseWheel(pDelta) {
if (pDelta > 0) {
pDelta = -1;
} else {
pDelta = 1;
}
firstVisibleCard = firstVisibleCard + pDelta;
let availableSlots = visibleProductCards.length;
if (firstVisibleCard < 1) { firstVisibleCard = 1; }
if (firstVisibleCard > (productCards.length - availableSlots + 1)) { firstVisibleCard = productCards.length - availableSlots + 1; }
visibleProductCards = [];
var lastY = 5;
for (let i = 0; i < productCards.length; i++) {
if (i + 1 >= firstVisibleCard && i + 1 < firstVisibleCard + availableSlots) {
let productCard = productCards[i];
/* Positioning within thisObject Panel */
let position = {
x: 10,
y: thisObject.container.frame.height - thisObject.container.frame.getBodyHeight()
};
productCard.container.frame.position.x = position.x;
productCard.container.frame.position.y = position.y + lastY;
lastY = lastY + productCard.container.frame.height;
/* Add to Visible Product Array */
visibleProductCards.push(productCard);
}
}
}
function onProductCardStatusChanged(pProductCard) {
thisObject.container.eventHandler.raiseEvent('Product Card Status Changed', pProductCard);
}
function getLoadingProductCards() {
/* Returns all productCards which status is LOADING */
let onProducts = [];
for (let i = 0; i < productCards.length; i++) {
if (productCards[i].status === PRODUCT_CARD_STATUS.LOADING) {
onProducts.push(productCards[i]);
}
}
return onProducts;
}
function getContainer(point) {
var container;
/* First we check if thisObject point is inside thisObject space. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
/* Now we see which is the inner most container that has it */
for (var i = 0; i < visibleProductCards.length; i++) {
container = visibleProductCards[i].getContainer(point);
if (container !== undefined) {
/* We found an inner container which has the point. We return it. */
return container;
}
}
/* The point does not belong to any inner container, so we return the current container. */
return thisObject.container;
} else {
/* This point does not belong to thisObject space. */
return undefined;
}
}
function draw() {
if (isInitialized === false) {return;}
thisObject.container.frame.draw(false, false, true);
for (let i = 0; i < visibleProductCards.length; i++) {
visibleProductCards[i].draw();
}
}
}
+177
View File
@@ -0,0 +1,177 @@
function newTimeControlPanel() {
let thisObject = {
container: undefined,
setDatetime: setDatetime,
datetimeDisplay: undefined,
stepDisplay: undefined,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
};
let container = newContainer();
container.initialize();
container.isDraggeable = true;
thisObject.container = container;
thisObject.container.frame.containerName = "Current Datetime";
let timePeriod;
return thisObject;
function initialize() {
thisObject.container.frame.width = UI_PANEL.WIDTH.SMALL;
thisObject.container.frame.height = UI_PANEL.HEIGHT.SMALL;
let position = {
x: (viewPort.visibleArea.topRight.x - viewPort.visibleArea.topLeft.x) / 2 - thisObject.container.frame.width / 2,
y: viewPort.visibleArea.bottomLeft.y - thisObject.container.frame.height
};
thisObject.container.frame.position = position;
let buttonPosition;
let buttonNames = ['Fast Backwards', 'Play Backwards', 'Step Backwards', 'Pause', 'Step Forward', 'Play Forward', 'Fast Forward'];
let lastX = 0;
let datetime = INITIAL_DATE;
let datetimeDisplay = {
currentDatetime: datetime,
addTime: addTime,
draw: drawTimeDisplay
};
thisObject.datetimeDisplay = datetimeDisplay;
/* Here we will listen to the event when time was changed due to a Bot Execution. */
canvas.bottomSpace.playStopButton.container.eventHandler.listenToEvent("Bot Execution Changed Datetime", onBotChangedTime);
canvas.bottomSpace.playStopButton.setDatetime(datetime);
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
timePeriod = INITIAL_TIME_PERIOD;
}
function onBotChangedTime(pNewDatetime) {
let newDatetime = new Date(pNewDatetime);
thisObject.container.eventHandler.raiseEvent("Datetime Changed", newDatetime);
}
function onZoomChanged(event) {
timePeriod = recalculatePeriod(event.newLevel);
}
function getContainer(point) {
let container;
/* First we check if thisObject point is inside thisObject space. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
/* The point does not belong to any inner container, so we return the current container. */
return thisObject.container;
} else {
/* This point does not belong to thisObject space. */
return undefined;
}
}
function setDatetime(pDatetime) {
thisObject.datetimeDisplay.currentDatetime = new Date(pDatetime);
canvas.bottomSpace.playStopButton.setDatetime(pDatetime);
}
function addTime(seconds) {
let newDate = thisObject.datetimeDisplay.currentDatetime;
newDate.setSeconds(newDate.getSeconds() + seconds);
thisObject.datetimeDisplay.currentDatetime = newDate;
}
function draw() {
thisObject.container.frame.draw(false, false, true);
thisObject.datetimeDisplay.draw();
}
function drawTimeDisplay() {
let fontSize = 10;
let label = thisObject.datetimeDisplay.currentDatetime.toUTCString();
let labelArray = label.split(" ");
label = labelArray[0] + " " + labelArray[1] + " " + labelArray[2] + " " + labelArray[3];
/* Now we transform x on the actual coordinate on the canvas. */
let labelPoint = {
x: thisObject.container.frame.width / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: thisObject.container.frame.height * 4.4 / 10
};
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint);
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
/* The time */
label = labelArray[4] + " " + labelArray[5];
/* Now we transform x on the actual coordinate on the canvas. */
labelPoint = {
x: thisObject.container.frame.width / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: thisObject.container.frame.height * 6.5 / 10
};
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint);
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
if (timePeriod > _45_MINUTES_IN_MILISECONDS) {
label = timePeriod / _1_HOUR_IN_MILISECONDS + ' hs';
} else {
label = timePeriod / _1_MINUTE_IN_MILISECONDS + ' min';
}
/* Now we transform x on the actual coordinate on the canvas. */
labelPoint = {
x: thisObject.container.frame.width / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: thisObject.container.frame.height * 8.5 / 10
};
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint);
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
}
+806
View File
@@ -0,0 +1,806 @@
function newPlottersManager() {
const MODULE_NAME = "Plotters Manager";
const INFO_LOG = false;
const INTENSIVE_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
let productPlotters = [];
let competitionPlotters = [];
let timePeriod = INITIAL_TIME_PERIOD;
let datetime = INITIAL_DATE;
let thisObject = {
setDatetime: setDatetime,
setTimePeriod: setTimePeriod,
positionAtDatetime: positionAtDatetime,
container: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
container.displacement.containerName = "Plotter Manager";
container.frame.containerName = "Plotter Manager";
let initializationReady = false;
let productsPanel;
return thisObject;
function initialize(pProductsPanel, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
/* Remember the Products Panel */
productsPanel = pProductsPanel;
/* Listen to the event of change of status */
productsPanel.container.eventHandler.listenToEvent("Product Card Status Changed", onProductCardStatusChanged);
initializeCompetitionPlotters(onCompetitionPlottersInitialized);
canvas.bottomSpace.chartAspectRatio.container.eventHandler.listenToEvent("Chart Aspect Ratio Changed", onAspectRatioChanged);
function onAspectRatioChanged(pAspectRatio) {
thisObject.container.frame.height = CHART_SPACE_HEIGHT * pAspectRatio.y;
/* First the Product Plotters. */
for (let i = 0; i < productPlotters.length; i++) {
let productPlotter = productPlotters[i];
productPlotter.plotter.container.frame.width = thisObject.container.frame.width;
productPlotter.plotter.container.frame.height = thisObject.container.frame.height;
if (productPlotter.plotter.recalculateScale !== undefined) {
productPlotter.plotter.recalculateScale();
}
}
/* Then the competition plotters. */
for (let i = 0; i < competitionPlotters.length; i++) {
let competitionPlotter = competitionPlotters[i];
competitionPlotter.plotter.container.frame.width = thisObject.container.frame.width;
competitionPlotter.plotter.container.frame.height = thisObject.container.frame.height;
if (competitionPlotter.plotter.recalculateScale !== undefined) {
competitionPlotter.plotter.recalculateScale();
}
}
}
function onCompetitionPlottersInitialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileCursorReady -> Received Unexpected Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
}
initializeProductPlotters(onProductPlottersInitialized);
function onProductPlottersInitialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> onProductPlottersInitialized -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> onProductPlottersInitialized -> Received OK Response."); }
initializationReady = true;
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> onProductPlottersInitialized -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onCompetitionPlottersInitialized -> onProductPlottersInitialized -> Received Unexpected Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onCompetitionPlottersInitialized -> onProductPlottersInitialized -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onCompetitionPlottersInitialized -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function initializeCompetitionPlotters(callBack) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> Entering function."); }
/* At this current version of the platform, we will support only one competition with only one plotter. */
const COMPETITION_HOST = "AAArena";
const COMPETITION = "Weekend-Deathmatch";
let objName = COMPETITION_HOST + "-" + COMPETITION;
let storage = newCompetitionStorage(objName);
let host = ecosystem.getHost(COMPETITION_HOST);
let competition = ecosystem.getCompetition(host, COMPETITION);
storage.initialize(host, competition, DEFAULT_EXCHANGE, DEFAULT_MARKET, onCompetitionStorageInitialized);
function onCompetitionStorageInitialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> Received FAIL Response."); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> Received Unexpected Response."); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
}
/* Now we have all the initial data loaded and ready to be delivered to the new instance of the plotter. */
let plotter = getNewPlotter(competition.plotter.host, competition.plotter.codeName, competition.plotter.moduleName);
plotter.container.displacement.parentDisplacement = thisObject.container.displacement;
plotter.container.frame.parentFrame = thisObject.container.frame;
plotter.container.parentContainer = thisObject.container;
plotter.container.frame.width = thisObject.container.frame.width * 1;
plotter.container.frame.height = thisObject.container.frame.height * 1;
plotter.container.frame.position.x = thisObject.container.frame.width / 2 - plotter.container.frame.width / 2;
plotter.container.frame.position.y = thisObject.container.frame.height / 2 - plotter.container.frame.height / 2;
/* We add the profile picture of each participant, because the plotter will need it. */
for (let k = 0; k < competition.participants.length; k++) {
let participant = competition.participants[k];
let devTeam = ecosystem.getTeam(participant.devTeam);
let bot = ecosystem.getBot(devTeam, participant.bot);
participant.profilePicture = bot.profilePicture;
}
plotter.initialize(competition, storage, datetime, timePeriod, onPlotterInizialized);
function onPlotterInizialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> onPlotterInizialized -> Entering function."); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> onPlotterInizialized -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> onPlotterInizialized -> Received FAIL Response."); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> onPlotterInizialized -> Received Unexpected Response."); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
}
let competitionPlotter = {
plotter: plotter,
storage: storage
};
/* Add the new Active Protter to the Array */
competitionPlotters.push(competitionPlotter);
/* Create The Profie Picture FloatingObject */
if (competitionPlotter.plotter.payload !== undefined) {
for (let k = 0; k < competition.participants.length; k++) {
let participant = competition.participants[k];
let devTeam = ecosystem.getTeam(participant.devTeam);
let bot = ecosystem.getBot(devTeam, participant.bot);
let imageId = participant.devTeam + "." + participant.profilePicture;
const TEAM = devTeam.codeName.toLowerCase();
const BOT = bot.codeName.toLowerCase();
let botAvatar = new Image();
botAvatar.src = window.canvasApp.context.fbProfileImages.get(TEAM + "-" + BOT);
competitionPlotter.plotter.payload[k].profile.downLabel = bot.displayName;
competitionPlotter.plotter.payload[k].profile.imageId = imageId;
competitionPlotter.plotter.payload[k].profile.botAvatar = botAvatar;
canvas.floatingSpace.profileBalls.createNewProfileBall(competitionPlotter.plotter.payload[k], onProfileBallCreated)
function onProfileBallCreated(err, pProfileHandle) {
competitionPlotter.plotter.payload[k].profile.handle = pProfileHandle;
}
}
}
callBack(GLOBAL.DEFAULT_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> onPlotterInizialized -> err = " + err); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeCompetitionPlotters -> onCompetitionStorageInitialized -> err = " + err); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeCompetitionPlotters -> err = " + err); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function initializeProductPlotters(callBack) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> Entering function."); }
/* Lets get all the cards that needs to be loaded. */
let initializationCounter = 0;
let loadingProductCards = productsPanel.getLoadingProductCards();
let okCounter = 0;
let failCounter = 0;
for (let i = 0; i < loadingProductCards.length; i++) {
/* For each one, we will initialize the associated plotter. */
initializeProductPlotter(loadingProductCards[i], onProductPlotterInitialized);
function onProductPlotterInitialized(err) {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> Entering function."); }
initializationCounter++;
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> Received OK Response."); }
okCounter++;
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> Received FAIL Response."); }
failCounter++;
break;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> Received Unexpected Response."); }
failCounter++;
break;
}
}
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> initializationCounter = " + initializationCounter); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> okCounter = " + okCounter); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> failCounter = " + failCounter); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> loadingProductCards.length = " + loadingProductCards.length); }
if (initializationCounter === loadingProductCards.length) { // This was the last one.
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> onProductPlotterInitialized -> Last Product Loaded."); }
/* If less than 50% of plotters are initialized then we return FAIL. */
if (okCounter >= 1) {
callBack(GLOBAL.DEFAULT_OK_RESPONSE);
} else {
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeProductPlotters -> err = " + err); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function initializeProductPlotter(pProductCard, callBack) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> Entering function."); }
/* Before Initializing a Plotter, we need the Storage it will use, loaded with the files it will initially need. */
let objName = pProductCard.devTeam.codeName + "-" + pProductCard.bot.codeName + "-" + pProductCard.product.codeName;
let storage = newProductStorage(objName);
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> objName = " + objName); }
/*
Before Initializing the Storage, we will put the Product Card to listen to the events the storage will raise every time a file is loaded,
so that the UI can somehow show this. There are different types of events.
*/
for (let i = 0; i < pProductCard.product.dataSets.length; i++) {
let thisSet = pProductCard.product.dataSets[i];
switch (thisSet.type) {
case 'Market Files': {
storage.eventHandler.listenToEvent('Market File Loaded', pProductCard.onMarketFileLoaded);
}
break;
case 'Daily Files': {
storage.eventHandler.listenToEvent('Daily File Loaded', pProductCard.onDailyFileLoaded);
}
break;
case 'Single File': {
storage.eventHandler.listenToEvent('Single File Loaded', pProductCard.onSingleFileLoaded);
}
break;
case 'File Sequence': {
storage.eventHandler.listenToEvent('File Sequence Loaded', pProductCard.onFileSequenceLoaded);
}
break;
}
}
storage.initialize(pProductCard.devTeam, pProductCard.bot, pProductCard.product, DEFAULT_EXCHANGE, DEFAULT_MARKET, datetime, timePeriod, onProductStorageInitialized);
function onProductStorageInitialized(err) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> key = " + pProductCard.devTeam.codeName + "-" + pProductCard.bot.codeName + "-" + pProductCard.product.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> Received OK Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> The plotter will be started."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> Received FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> The plotter will not be started."); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> Received Unexpected Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> The plotter will not be started."); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
}
/* Now we have all the initial data loaded and ready to be delivered to the new instance of the plotter. */
let plotter = getNewPlotter(pProductCard.product.plotter.devTeam, pProductCard.product.plotter.codeName, pProductCard.product.plotter.moduleName);
plotter.container.displacement.parentDisplacement = thisObject.container.displacement;
plotter.container.frame.parentFrame = thisObject.container.frame;
plotter.container.parentContainer = thisObject.container;
plotter.container.frame.width = thisObject.container.frame.width * 1;
plotter.container.frame.height = thisObject.container.frame.height * 1;
plotter.container.frame.position.x = thisObject.container.frame.width / 2 - plotter.container.frame.width / 2;
plotter.container.frame.position.y = thisObject.container.frame.height / 2 - plotter.container.frame.height / 2;
plotter.initialize(storage, DEFAULT_EXCHANGE, DEFAULT_MARKET, datetime, timePeriod, onPlotterInizialized);
function onPlotterInizialized() {
try {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> onPlotterInizialized -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotter -> onProductStorageInitialized -> onPlotterInizialized -> key = " + pProductCard.product.plotter.devTeam + "-" + pProductCard.product.plotter.codeName + "-" + pProductCard.product.plotter.moduleName); }
try {
//plotter.positionAtDatetime(INITIAL_DATE);
} catch (err) {
// If the plotter does not implement this function its ok.
}
let productPlotter = {
productCard: pProductCard,
plotter: plotter,
storage: storage,
profile: undefined,
notes: undefined
};
/* Let the Plotter listen to the event of Cursor Files loaded, so that it can reack recalculating if needed. */
storage.eventHandler.listenToEvent('Daily File Loaded', plotter.onDailyFileLoaded);
/* Lets load now this plotter panels. */
productPlotter.panels = [];
for (let i = 0; i < pProductCard.product.plotter.module.panels.length; i++) {
let panelConfig = pProductCard.product.plotter.module.panels[i];
let parameters = {
devTeam: pProductCard.product.plotter.devTeam,
plotterCodeName: pProductCard.product.plotter.codeName,
moduleCodeName: pProductCard.product.plotter.moduleName,
panelCodeName: panelConfig.codeName
}
let plotterPanelHandle = canvas.panelsSpace.createNewPanel("Plotter Panel", parameters);
let plotterPanel = canvas.panelsSpace.getPanel(plotterPanelHandle);
/* Connect Panel to the Plotter via an Event. */
if (panelConfig.event !== undefined) {
productPlotter.plotter.container.eventHandler.listenToEvent(panelConfig.event, plotterPanel.onEventRaised);
}
productPlotter.panels.push(plotterPanelHandle);
}
/* Create The Profie Picture FloatingObject */
if (productPlotter.plotter.payload !== undefined) {
let imageId = pProductCard.bot.devTeam + "." + pProductCard.bot.profilePicture;
productPlotter.plotter.payload.profile.upLabel = pProductCard.product.shortDisplayName;
productPlotter.plotter.payload.profile.downLabel = pProductCard.bot.displayName;
productPlotter.plotter.payload.profile.imageId = imageId;
productPlotter.plotter.payload.profile.botAvatar = pProductCard.bot.avatar;
canvas.floatingSpace.profileBalls.createNewProfileBall(productPlotter.plotter.payload, onProfileBallCreated)
function onProfileBallCreated(err, pProfileHandle) {
productPlotter.profile = pProfileHandle;
/* There is no policy yet of what to do if this fails. */
}
/* Create the Text Notes */
canvas.floatingSpace.noteSets.createNoteSet(productPlotter.plotter.payload, productPlotter.plotter.container.eventHandler, onNoteSetCreated);
function onNoteSetCreated(err, pNoteSetHandle) {
productPlotter.noteSet = pNoteSetHandle;
/* There is no policy yet of what to do if this fails. */
}
}
/* Add the new Active Protter to the Array */
productPlotters.push(productPlotter);
callBack(GLOBAL.DEFAULT_OK_RESPONSE);
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeProductPlotter -> onProductStorageInitialized -> onPlotterInizialized -> err = " + err); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeProductPlotter -> onProductStorageInitialized -> err = " + err); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initializeProductPlotter -> err = " + err); }
callBack(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function onProductCardStatusChanged(pProductCard) {
if (INFO_LOG === true) { logger.write("[INFO] onProductCardStatusChanged -> Entering function."); }
if (pProductCard.status === PRODUCT_CARD_STATUS.LOADING) {
/* Lets see if we can find the Plotter of this card on our Active Plotters list, other wise we will initialize it */
let found = false;
for (let i = 0; i < productPlotters.length; i++) {
if (productPlotters[i].productCard.code === pProductCard.code) {
found = true;
}
}
if (found === false) {
initializeProductPlotter(pProductCard, onProductPlotterInitialized);
function onProductPlotterInitialized(err) {
if (INFO_LOG === true) { logger.write("[INFO] initializeProductPlotters -> onProductPlotterInitialized -> Entering function."); }
/* There is no policy yet of what to do if this fails. */
}
}
}
if (pProductCard.status === PRODUCT_CARD_STATUS.OFF) {
/* If the plotter of this card is on our Active Plotters list, then we remove it. */
for (let i = 0; i < productPlotters.length; i++) {
if (productPlotters[i].productCard.code === pProductCard.code) {
if (productPlotters[i].profile !== undefined) {
canvas.floatingSpace.profileBalls.destroyProfileBall(productPlotters[i].profile);
}
/* Destroyd the Note Set */
canvas.floatingSpace.noteSets.destroyNoteSet(productPlotters[i].noteSet);
/* Then the panels. */
for (let j = 0; j < productPlotters[i].panels.length; j++) {
canvas.panelsSpace.destroyPanel(productPlotters[i].panels[j]);
}
/* Finally the Storage Objects */
productPlotters[i].storage.finalize();
if (productPlotters[i].plotter.finalize !== undefined) {
productPlotters[i].plotter.finalize();
}
productPlotters.splice(i, 1); // Delete item from array.
return; // We already found the product woth changes and processed it.
}
}
}
}
function setTimePeriod(pTimePeriod) {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> Entering function."); }
timePeriod = pTimePeriod;
if (initializationReady === true) {
for (let i = 0; i < productPlotters.length; i++) {
let productPlotter = productPlotters[i];
productPlotter.productCard.setTimePeriod(timePeriod);
productPlotter.storage.setTimePeriod(timePeriod);
productPlotter.plotter.setTimePeriod(timePeriod);
}
for (let i = 0; i < competitionPlotters.length; i++) {
let competitionPlotter = competitionPlotters[i];
competitionPlotter.plotter.setTimePeriod(timePeriod);
}
}
}
function setDatetime(pDatetime) {
if (INFO_LOG === true) { logger.write("[INFO] setDatetime -> Entering function."); }
datetime = pDatetime;
for (let i = 0; i < productPlotters.length; i++) {
let productPlotter = productPlotters[i];
productPlotter.productCard.setDatetime(pDatetime);
productPlotter.storage.setDatetime(pDatetime);
productPlotter.plotter.setDatetime(pDatetime);
}
for (let i = 0; i < competitionPlotters.length; i++) {
let competitionPlotter = competitionPlotters[i];
competitionPlotter.plotter.setDatetime(datetime);
}
}
function positionAtDatetime(pDatetime) {
if (INFO_LOG === true) { logger.write("[INFO] positionAtDatetime -> Entering function."); }
for (let i = 0; i < productPlotters.length; i++) {
let productPlotter = productPlotters[i];
if (productPlotter.plotter.positionAtDatetime !== undefined) {
productPlotter.plotter.positionAtDatetime(pDatetime);
}
}
}
function getContainer(point) {
if (INFO_LOG === true) { logger.write("[INFO] getContainer -> Entering function."); }
let container;
return container;
}
function draw() {
if (INTENSIVE_LOG === true) { logger.write("[INFO] draw -> Entering function."); }
if (productPlotters === undefined) { return; } // We need to wait
/* First the Product Plotters. */
for (let i = 0; i < productPlotters.length; i++) {
let productPlotter = productPlotters[i];
productPlotter.plotter.draw();
}
/* Then the competition plotters. */
for (let i = 0; i < competitionPlotters.length; i++) {
let competitionPlotter = competitionPlotters[i];
competitionPlotter.plotter.draw();
}
}
}
+976
View File
@@ -0,0 +1,976 @@
function newProductCard() {
const CONSOLE_LOG = false;
var thisObject = {
container: undefined,
draw: draw,
status: 'off',
devTeam: undefined,
bot: undefined,
product: undefined,
code: undefined,
setDatetime: setDatetime,
setTimePeriod: setTimePeriod,
onMarketFileLoaded: onMarketFileLoaded,
onDailyFileLoaded: onDailyFileLoaded,
onSingleFileLoaded: onSingleFileLoaded,
onFileSequenceLoaded: onFileSequenceLoaded,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
};
let LOADING_FILL_STYLE = 'rgba(234, 143, 23, @Opacity)';
let LOADED_FILL_STYLE = 'rgba(45, 232, 28, @Opacity)';
let UNLOADED_FILL_STYLE = 'rgba(226, 226, 226, @Opacity)';
let LOADING_STROKE_STYLE = 'rgba(234, 143, 23, @Opacity)';
let LOADED_STROKE_STYLE = 'rgba(150, 150, 150, @Opacity)';
let UNLOADED_STROKE_STYLE = 'rgba(226, 226, 226, @Opacity)';
let marketFileProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
};
let dailyFileProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
};
let singleFileProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
};
let fileSequenceProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
};
let timePeriod = INITIAL_TIME_PERIOD;
let datetime = INITIAL_DATE;
/* TODO We are in a transition period in which bots and teams images might be located at different places.
What we are going to do then is to try to load them from both places and use the variable that finally gets an
image. */
/* This is the legacy image storage. */
let legacyTeamAvatar;
let legacyTeamAvatarLoaded = false;
/* TODO Temporary code */
let legacyBotAvatar;
let legacyBotAvatarLoaded = false;
/* Now the plotters images */
let legacyPlotterBanner;
let legacyPlotterBannerLoaded = false;
/* We are transitioning towards this */
let teamAvatar; // stores the avatar image of the team the bot portrayed at this card belongs to.
let teamAvatarLoaded = false;
/* TODO Temporary code */
let botAvatar; // stores the avatar image of the team the bot portrayed at this card belongs to.
let botAvatarLoaded = false;
/* Add an Event Handler */
thisObject.eventHandler = newEventHandler();
let imagesLoaded = 0;
return thisObject;
function initialize() {
/* Create this objects continer */
var container = newContainer();
container.name = "Product Card " + thisObject.code;
container.initialize();
container.isDraggeable = false;
container.isClickeable = true;
thisObject.container = container;
/* Add information that will later be needed.*/
let team = ecosystem.getTeam(thisObject.product.plotter.devTeam);
let plotter = ecosystem.getPlotter(team, thisObject.product.plotter.codeName);
let plotterModule = ecosystem.getPlotterModule(plotter, thisObject.product.plotter.moduleName);
thisObject.product.plotter.profilePicture = plotterModule.profilePicture;
thisObject.product.plotter.module = plotterModule;
/* Lets set the basic dimensions of this thisObject. */
var position = {
x: 0,
y: 0
};
this.container.frame.position = position;
this.container.frame.width = 330;
this.container.frame.height = 100;
/* We retrieve the locally stored status of the Product */
let storedValue = window.localStorage.getItem(thisObject.code);
if (storedValue !== null) {
thisObject.status = storedValue;
if (thisObject.status === PRODUCT_CARD_STATUS.ON) {
changeStatusTo(PRODUCT_CARD_STATUS.LOADING);
}
} else {
/*
This happens the first time the app is run on a new browser.
We will start with all product off, except for the candles chart, since something needs to be shown and allow the user to position themselves
on the timeline.
For the time being, we will hard-code the name of the bot we will turn on by default, since we dont see that change in the near future.
*/
const DEFAULT_ON_PRODUCT = "AAMasters-AAOlivia-Candles";
if (thisObject.code === DEFAULT_ON_PRODUCT) {
changeStatusTo(PRODUCT_CARD_STATUS.LOADING);
} else {
changeStatusTo(PRODUCT_CARD_STATUS.OFF);
}
}
/* Lets listen to our own events to react when we have a Mouse Click */
thisObject.container.eventHandler.listenToEvent('onMouseClick', buttonPressed);
/* WARNING THIS IS TEMPORARY CODE */
const LEGACY_TEAM = thisObject.devTeam.codeName;
const REPO = thisObject.bot.repo;
const PROFILE_PIC = thisObject.bot.profilePicture;
/* The plotter banner, comes from the Legacy Location so far, no matter if the Team is at the Teams Modules or not. */
const PLOTTER_TEAM = thisObject.product.plotter.devTeam;
const PLOTTER_REPO = thisObject.product.plotter.codeName;
const PLOTTER_PROFILE_PIC = thisObject.product.plotter.profilePicture;
legacyPlotterBanner = new Image();
legacyPlotterBanner.onload = onLegacyPlotterBanner;
function onLegacyPlotterBanner() {
legacyPlotterBannerLoaded = true;
}
legacyPlotterBanner.src = window.canvasApp.urlPrefix + "Images/" + PLOTTER_TEAM + "/" + PLOTTER_REPO + "/" + PLOTTER_PROFILE_PIC;
const TEAM = thisObject.devTeam.codeName.toLowerCase();
const BOT = thisObject.bot.codeName.toLowerCase();
if (window.canvasApp.context.teamProfileImages.get(TEAM) === undefined) { // This means this Team is a Lecay Team, still not at any Module.
/*
Here we will download the images still at the legacy storage.
*/
legacyTeamAvatar = new Image();
legacyTeamAvatar.onload = onLegacyImageLoad;
function onLegacyImageLoad() {
legacyTeamAvatarLoaded = true;
}
legacyTeamAvatar.src = window.canvasApp.urlPrefix + "Images/" + LEGACY_TEAM + "/" + LEGACY_TEAM + ".png";
legacyBotAvatar = new Image();
legacyBotAvatar.onload = onLegacyImageLoadBot;
function onLegacyImageLoadBot() {
legacyBotAvatarLoaded = true;
thisObject.bot.avatar = legacyBotAvatar;
}
legacyBotAvatar.src = window.canvasApp.urlPrefix + "Images/" + LEGACY_TEAM + "/" + REPO + "/" + PROFILE_PIC;
}
else {
/*
Here we will download the images of teams uploaded at the Teams Module.
There might be Product Cards of bots beloging to teams not present currently at the Teams Module, in those cases
nothing should happen.
*/
teamAvatar = new Image();
teamAvatar.onload = onImageLoad;
function onImageLoad() {
teamAvatarLoaded = true;
}
teamAvatar.src = window.canvasApp.context.teamProfileImages.get(TEAM);
botAvatar = new Image();
botAvatar.onload = onImageLoadBot;
function onImageLoadBot() {
botAvatarLoaded = true;
thisObject.bot.avatar = botAvatar;
}
botAvatar.src = window.canvasApp.context.fbProfileImages.get(TEAM + "-" + BOT);
}
}
function getContainer(point) {
var container;
/* First we check if this point is inside this space. */
if (this.container.frame.isThisPointHere(point, true) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
}
function setDatetime(pDatetime) {
/*
When the datetime changes from one day to another, this forces cursors to potentially load more files, thus we reset this counter and
get ready to receive events on files loaded.
*/
let currentDate = Math.trunc(datetime.valueOf() / ONE_DAY_IN_MILISECONDS);
let newDate = Math.trunc(pDatetime.valueOf() / ONE_DAY_IN_MILISECONDS);
datetime = pDatetime;
if (currentDate !== newDate) {
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
dailyFileProgressBar.animatedValue = 0;
if (CONSOLE_LOG === true) {
console.log("ProductCard -> onDayChanged -> dailyFileProgressBar.animatedValue = " + dailyFileProgressBar.animatedValue);
}
}
}
}
function setTimePeriod(pTimePeriod) {
/*
When the time period below or equal to 1 hour changes, this forces cursors to potentially load more files, thus we reset this counter and
get ready to receive events on files loaded.
*/
if (timePeriod !== pTimePeriod) {
timePeriod = pTimePeriod;
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
dailyFileProgressBar.animatedValue = 0;
if (CONSOLE_LOG === true) {
console.log("ProductCard -> onTimePeriodChanged -> dailyFileProgressBar.animatedValue = " + dailyFileProgressBar.animatedValue);
}
}
}
}
function onMarketFileLoaded(event) {
marketFileProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue);
marketFileProgressBar.fillStyle = LOADING_FILL_STYLE;
marketFileProgressBar.strokeStyle = LOADING_STROKE_STYLE;
if (marketFileProgressBar.value > 100) { marketFileProgressBar.value = 100; }
if (CONSOLE_LOG === true) {
console.log("ProductCard onMarketFileLoaded Value = " + marketFileProgressBar.value + "% for " + thisObject.code + ". Event = " + JSON.stringify(event));
}
}
function onDailyFileLoaded(event) {
dailyFileProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue);
dailyFileProgressBar.fillStyle = LOADING_FILL_STYLE;
dailyFileProgressBar.strokeStyle = LOADING_STROKE_STYLE;
if (dailyFileProgressBar.value > 100) { dailyFileProgressBar.value = 100;}
if (CONSOLE_LOG === true) {
console.log("ProductCard onDailyFileLoaded Value = " + dailyFileProgressBar.value + "% for " + thisObject.code + ". Event = " + JSON.stringify(event));
}
}
function onSingleFileLoaded(event) {
singleFileProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue);
singleFileProgressBar.fillStyle = LOADING_FILL_STYLE;
singleFileProgressBar.strokeStyle = LOADING_STROKE_STYLE;
if (singleFileProgressBar.value > 100) { singleFileProgressBar.value = 100; }
if (CONSOLE_LOG === true) {
console.log("ProductCard onSingleFileLoaded Value = " + singleFileProgressBar.value + "% for " + thisObject.code + ". Event = " + JSON.stringify(event));
}
}
function onFileSequenceLoaded(event) {
fileSequenceProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue);
fileSequenceProgressBar.fillStyle = LOADING_FILL_STYLE;
fileSequenceProgressBar.strokeStyle = LOADING_STROKE_STYLE;
if (fileSequenceProgressBar.value > 100) { fileSequenceProgressBar.value = 100; }
if (CONSOLE_LOG === true) {
console.log("ProductCard onFileSequenceLoaded Value = " + fileSequenceProgressBar.value + "% for " + thisObject.code + ". Event = " + JSON.stringify(event));
}
}
function buttonPressed(event) {
switch (thisObject.status) {
case PRODUCT_CARD_STATUS.ON:
changeStatusTo(PRODUCT_CARD_STATUS.OFF);
marketFileProgressBar.animatedValue = 0;
marketFileProgressBar.value = 0;
marketFileProgressBar.fillStyle = UNLOADED_FILL_STYLE;
marketFileProgressBar.strokeStyle = UNLOADED_STROKE_STYLE;
dailyFileProgressBar.animatedValue = 0;
dailyFileProgressBar.value = 0;
dailyFileProgressBar.fillStyle = UNLOADED_FILL_STYLE;
dailyFileProgressBar.strokeStyle = UNLOADED_STROKE_STYLE;
singleFileProgressBar.animatedValue = 0;
singleFileProgressBar.value = 0;
singleFileProgressBar.fillStyle = UNLOADED_FILL_STYLE;
singleFileProgressBar.strokeStyle = UNLOADED_STROKE_STYLE;
fileSequenceProgressBar.animatedValue = 0;
fileSequenceProgressBar.value = 0;
fileSequenceProgressBar.fillStyle = UNLOADED_FILL_STYLE;
fileSequenceProgressBar.strokeStyle = UNLOADED_STROKE_STYLE;
break;
case PRODUCT_CARD_STATUS.OFF:
changeStatusTo(PRODUCT_CARD_STATUS.LOADING);
break;
}
}
function changeStatusTo(pNewStatus) {
if (thisObject.status !== pNewStatus) {
thisObject.status = pNewStatus;
let eventData = thisObject;
thisObject.container.eventHandler.raiseEvent('Status Changed', eventData);
window.localStorage.setItem(thisObject.code, thisObject.status);
}
}
function draw() {
drawProductCard();
}
function drawProductCard() {
/*
Put images on the card.
*/
const devTeamImageSize = 50;
const botImageSize = 50;
const plotterImageSize = {
width: 180,
height: 50
};
/* First the Dev Team Profile Picture. */
let teamImagePoint = {
x: 10,
y: thisObject.container.frame.height / 2 - devTeamImageSize / 2
};
teamImagePoint = thisObject.container.frame.frameThisPoint(teamImagePoint);
let teamImage;
if (legacyTeamAvatarLoaded === true) {
teamImage = legacyTeamAvatar;
}
if (teamAvatarLoaded === true) {
teamImage = teamAvatar;
}
if (teamImage !== undefined) {
if (teamImage.naturalHeight !== 0) {
/* The image is rounded before being displayed. */
browserCanvasContext.save();
browserCanvasContext.beginPath();
browserCanvasContext.arc(teamImagePoint.x + devTeamImageSize / 2, teamImagePoint.y + devTeamImageSize / 2, devTeamImageSize / 2, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.clip();
browserCanvasContext.drawImage(teamImage, teamImagePoint.x, teamImagePoint.y, devTeamImageSize, devTeamImageSize);
browserCanvasContext.beginPath();
browserCanvasContext.arc(teamImagePoint.x, teamImagePoint.y, devTeamImageSize / 2, 0, Math.PI * 2, true);
browserCanvasContext.clip();
browserCanvasContext.closePath();
browserCanvasContext.restore();
}
}
/* Second the Bot's Profile Picture. */
if (thisObject.bot.profilePicture !== undefined) {
let botImagePoint = {
x: thisObject.container.frame.width - botImageSize / 2 - 40,
y: thisObject.container.frame.height / 2 - botImageSize / 2
};
botImagePoint = thisObject.container.frame.frameThisPoint(botImagePoint);
let imageId = thisObject.bot.devTeam + "." + thisObject.bot.profilePicture;
/* TODO Temporary code */
let botImage;
botImage = thisObject.bot.avatar;
if (botImage !== undefined) {
if (botImage.naturalHeight !== 0) {
/* The image is rounded before being displayed. */
browserCanvasContext.save();
browserCanvasContext.beginPath();
browserCanvasContext.arc(botImagePoint.x + botImageSize / 2, botImagePoint.y + botImageSize / 2, botImageSize / 2, 0, Math.PI * 2, true);
browserCanvasContext.closePath();
browserCanvasContext.clip();
browserCanvasContext.drawImage(botImage, botImagePoint.x, botImagePoint.y, botImageSize, botImageSize);
browserCanvasContext.beginPath();
browserCanvasContext.arc(botImagePoint.x, botImagePoint.y, botImageSize / 2, 0, Math.PI * 2, true);
browserCanvasContext.clip();
browserCanvasContext.closePath();
browserCanvasContext.restore();
}
}
}
/* Third the Plotter's Profile Picture. */
if (thisObject.product.plotter.profilePicture !== undefined) {
let plotterImagePoint = {
x: thisObject.container.frame.width / 2 - plotterImageSize.width / 2,
y: thisObject.container.frame.height / 2 - plotterImageSize.height / 2
};
plotterImagePoint = thisObject.container.frame.frameThisPoint(plotterImagePoint);
let imageId = thisObject.product.plotter.devTeam + "." + thisObject.product.plotter.codeName + "." + thisObject.product.plotter.moduleName + "." + thisObject.product.plotter.profilePicture;
let plotterImage = legacyPlotterBanner;
if (plotterImage !== undefined) {
if (plotterImage.naturalHeight !== 0) {
browserCanvasContext.drawImage(plotterImage, plotterImagePoint.x, plotterImagePoint.y, plotterImageSize.width, plotterImageSize.height);
}
}
}
drawProductLoadStatus();
function drawProductLoadStatus() {
let offFillStyle = 'rgba(' + UI_COLOR.RED + ', 0.20)';
let onFillStyle = 'rgba(' + UI_COLOR.GREEN + ', 0.20)';
let loadingFillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 0.40)';
switch (thisObject.status) {
case PRODUCT_CARD_STATUS.ON:
browserCanvasContext.fillStyle = onFillStyle;
break;
case PRODUCT_CARD_STATUS.OFF:
browserCanvasContext.fillStyle = offFillStyle;
break;
case PRODUCT_CARD_STATUS.LOADING:
browserCanvasContext.fillStyle = loadingFillStyle;
break;
}
let centerPoint = {
x: thisObject.container.frame.width / 2,
y: thisObject.container.frame.height / 2 - 13
};
let point1 = {
x: centerPoint.x - plotterImageSize.width / 2,
y: centerPoint.y - plotterImageSize.height / 2 - 7
};
let point2 = {
x: centerPoint.x + plotterImageSize.width / 2,
y: centerPoint.y - plotterImageSize.height / 2 - 7
};
let point3 = {
x: centerPoint.x + plotterImageSize.width / 2,
y: centerPoint.y - plotterImageSize.height / 2 + 7
};
let point4 = {
x: centerPoint.x - plotterImageSize.width / 2,
y: centerPoint.y - plotterImageSize.height / 2 + 7
};
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point4 = thisObject.container.frame.frameThisPoint(point4);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
browserCanvasContext.closePath();
browserCanvasContext.fill();
browserCanvasContext.strokeStyle = 'rgba(150, 150, 150, 1)';
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.stroke();
}
/*
print the text
*/
let labelPoint;
let fontSize = 10;
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
let label;
/* devTeam */
label = thisObject.devTeam.displayName;
labelPoint = {
x: 10 + devTeamImageSize / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: thisObject.container.frame.height / 2 + devTeamImageSize / 2 + fontSize * FONT_ASPECT_RATIO + 5
};
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint);
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
/* bot */
label = thisObject.bot.displayName;
labelPoint = {
x: thisObject.container.frame.width - 40 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: thisObject.container.frame.height / 2 + devTeamImageSize / 2 + fontSize * FONT_ASPECT_RATIO + 5
};
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint);
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
/* product */
fontSize = 10;
label = thisObject.product.displayName;
labelPoint = {
x: 65,
y: thisObject.container.frame.height / 2 + 15
};
labelPoint = {
x: thisObject.container.frame.width / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: thisObject.container.frame.height / 2 - devTeamImageSize / 2 - fontSize * FONT_ASPECT_RATIO - 5
};
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint);
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
/* ------------------- Progress Bars -------------------------- */
const ANIMATED_INCREMENT = 5;
const OPACITY_INCREMENT = 0.05;
const OPACITY_MIN = 0.1;
let point1;
let point2;
let point3;
let point4;
/* We draw here the Market Progress Bar. */
/* Animate */
if (marketFileProgressBar.animatedValue < marketFileProgressBar.value) {
marketFileProgressBar.animatedValue = marketFileProgressBar.animatedValue + ANIMATED_INCREMENT;
marketFileProgressBar.opacity = marketFileProgressBar.opacity + OPACITY_INCREMENT;
}
if (marketFileProgressBar.animatedValue >= 100) {
marketFileProgressBar.animatedValue = 100;
marketFileProgressBar.opacity = marketFileProgressBar.opacity - OPACITY_INCREMENT;
if (marketFileProgressBar.opacity < OPACITY_MIN) { marketFileProgressBar.opacity = OPACITY_MIN;}
marketFileProgressBar.fillStyle = LOADED_FILL_STYLE.replace('@Opacity', marketFileProgressBar.opacity.toString());
marketFileProgressBar.strokeStyle = LOADED_STROKE_STYLE.replace('@Opacity', marketFileProgressBar.opacity.toString());
changeStatusTo(PRODUCT_CARD_STATUS.ON);
}
point1 = {
x: 0,
y: thisObject.container.frame.height - 1
};
point2 = {
x: thisObject.container.frame.width * marketFileProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 1
};
point3 = {
x: thisObject.container.frame.width * marketFileProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 3
};
point4 = {
x: 0,
y: thisObject.container.frame.height - 3
};
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point4 = thisObject.container.frame.frameThisPoint(point4);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = marketFileProgressBar.fillStyle.replace('@Opacity', marketFileProgressBar.opacity.toString());
browserCanvasContext.strokeStyle = marketFileProgressBar.strokeStyle.replace('@Opacity', marketFileProgressBar.opacity.toString());
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.stroke();
/* We draw here the Daily Progress Bar. */
/* Animate */
if (dailyFileProgressBar.animatedValue < dailyFileProgressBar.value) {
dailyFileProgressBar.animatedValue = dailyFileProgressBar.animatedValue + ANIMATED_INCREMENT;
dailyFileProgressBar.opacity = dailyFileProgressBar.opacity + OPACITY_INCREMENT;
}
if (dailyFileProgressBar.animatedValue >= 100) {
dailyFileProgressBar.animatedValue = 100;
dailyFileProgressBar.opacity = dailyFileProgressBar.opacity - OPACITY_INCREMENT;
if (dailyFileProgressBar.opacity < OPACITY_MIN) { dailyFileProgressBar.opacity = OPACITY_MIN; }
dailyFileProgressBar.fillStyle = LOADED_FILL_STYLE.replace('@Opacity', dailyFileProgressBar.opacity.toString());
dailyFileProgressBar.strokeStyle = LOADED_STROKE_STYLE.replace('@Opacity', dailyFileProgressBar.opacity.toString());
changeStatusTo(PRODUCT_CARD_STATUS.ON);
}
point1 = {
x: 0,
y: thisObject.container.frame.height - 4
};
point2 = {
x: thisObject.container.frame.width * dailyFileProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 4
};
point3 = {
x: thisObject.container.frame.width * dailyFileProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 6
};
point4 = {
x: 0,
y: thisObject.container.frame.height - 6
};
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point4 = thisObject.container.frame.frameThisPoint(point4);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = dailyFileProgressBar.fillStyle.replace('@Opacity', dailyFileProgressBar.opacity.toString());
browserCanvasContext.strokeStyle = dailyFileProgressBar.strokeStyle.replace('@Opacity', dailyFileProgressBar.opacity.toString());
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.stroke();
/* We draw here the Single File Progress Bar. */
/* Animate */
if (singleFileProgressBar.animatedValue < singleFileProgressBar.value) {
singleFileProgressBar.animatedValue = singleFileProgressBar.animatedValue + ANIMATED_INCREMENT;
singleFileProgressBar.opacity = singleFileProgressBar.opacity + OPACITY_INCREMENT;
}
if (singleFileProgressBar.animatedValue >= 100) {
singleFileProgressBar.animatedValue = 100;
singleFileProgressBar.opacity = singleFileProgressBar.opacity - OPACITY_INCREMENT;
if (singleFileProgressBar.opacity < OPACITY_MIN) { singleFileProgressBar.opacity = OPACITY_MIN; }
singleFileProgressBar.fillStyle = LOADED_FILL_STYLE.replace('@Opacity', singleFileProgressBar.opacity.toString());
singleFileProgressBar.strokeStyle = LOADED_STROKE_STYLE.replace('@Opacity', singleFileProgressBar.opacity.toString());
changeStatusTo(PRODUCT_CARD_STATUS.ON);
}
point1 = {
x: 0,
y: thisObject.container.frame.height - 7
};
point2 = {
x: thisObject.container.frame.width * singleFileProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 7
};
point3 = {
x: thisObject.container.frame.width * singleFileProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 9
};
point4 = {
x: 0,
y: thisObject.container.frame.height - 9
};
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point4 = thisObject.container.frame.frameThisPoint(point4);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = singleFileProgressBar.fillStyle.replace('@Opacity', singleFileProgressBar.opacity.toString());
browserCanvasContext.strokeStyle = singleFileProgressBar.strokeStyle.replace('@Opacity', singleFileProgressBar.opacity.toString());
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.stroke();
/* We draw here the File Sequence Progress Bar. */
/* Animate */
if (fileSequenceProgressBar.animatedValue < fileSequenceProgressBar.value) {
fileSequenceProgressBar.animatedValue = fileSequenceProgressBar.animatedValue + ANIMATED_INCREMENT;
fileSequenceProgressBar.opacity = fileSequenceProgressBar.opacity + OPACITY_INCREMENT;
}
if (fileSequenceProgressBar.animatedValue >= 100) {
fileSequenceProgressBar.animatedValue = 100;
fileSequenceProgressBar.opacity = fileSequenceProgressBar.opacity - OPACITY_INCREMENT;
if (fileSequenceProgressBar.opacity < OPACITY_MIN) { fileSequenceProgressBar.opacity = OPACITY_MIN; }
fileSequenceProgressBar.fillStyle = LOADED_FILL_STYLE.replace('@Opacity', fileSequenceProgressBar.opacity.toString());
fileSequenceProgressBar.strokeStyle = LOADED_STROKE_STYLE.replace('@Opacity', fileSequenceProgressBar.opacity.toString());
changeStatusTo(PRODUCT_CARD_STATUS.ON);
}
point1 = {
x: 0,
y: thisObject.container.frame.height - 10
};
point2 = {
x: thisObject.container.frame.width * fileSequenceProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 10
};
point3 = {
x: thisObject.container.frame.width * fileSequenceProgressBar.animatedValue / 100,
y: thisObject.container.frame.height - 11
};
point4 = {
x: 0,
y: thisObject.container.frame.height - 11
};
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1);
point2 = thisObject.container.frame.frameThisPoint(point2);
point3 = thisObject.container.frame.frameThisPoint(point3);
point4 = thisObject.container.frame.frameThisPoint(point4);
browserCanvasContext.beginPath();
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
browserCanvasContext.lineTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
browserCanvasContext.closePath();
browserCanvasContext.fillStyle = fileSequenceProgressBar.fillStyle.replace('@Opacity', fileSequenceProgressBar.opacity.toString());
browserCanvasContext.strokeStyle = fileSequenceProgressBar.strokeStyle.replace('@Opacity', fileSequenceProgressBar.opacity.toString());
browserCanvasContext.fill();
browserCanvasContext.lineWidth = 0.1;
browserCanvasContext.stroke();
}
}
+496
View File
@@ -0,0 +1,496 @@
function newProductStorage(pName) {
const MODULE_NAME = "Product Storage";
const INFO_LOG = false;
const ERROR_LOG = true;
const logger = newWebDebugLog();
logger.fileName = MODULE_NAME;
/*
This object will initialize children objects that will end up loading the data of each set defined at each product of the bot received at initialization.
Once all the underlaying objects are fully initialized it will callback.
At the same time it will raise an event for each underlaying file being loaded, so that the UI can reflect the progress to the end user.
Product Storage
|
|-----> SingleFile
|
|-----> FileSequence
|
|-----> DailyFiles -----> FileCursor
|
|-----> MarketFiles
*/
let thisObject = {
marketFiles: [],
dailyFiles: [],
singleFile: [],
fileSequences: [],
setDatetime: setDatetime,
setTimePeriod: setTimePeriod,
eventHandler: undefined,
initialize: initialize,
finalize: finalize
}
thisObject.eventHandler = newEventHandler();
/* We name the event Handler to easy debugging. */
thisObject.eventHandler.name = "Storage-" + pName;
let datetime;
let timePeriod;
return thisObject;
function finalize() {
try {
if (INFO_LOG === true) { logger.write("[INFO] finalize -> Entering function."); }
for (let i = 0; i < thisObject.marketFiles.length; i++) {
let marketFile = thisObject.marketFiles[i];
marketFile.finalize();
}
thisObject.marketFiles = undefined;
for (let i = 0; i < thisObject.dailyFiles.length; i++) {
let dailyFile = thisObject.dailyFiles[i];
dailyFile.finalize();
}
thisObject.dailyFile = undefined;
for (let i = 0; i < thisObject.fileSequences.length; i++) {
let fileSequence = thisObject.fileSequences[i];
fileSequence.finalize();
}
thisObject.dailyFile = undefined;
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] finalize -> err = " + err); }
}
}
function initialize(pDevTeam, pBot, pProduct, pExchange, pMarket, pDatetime, pTimePeriod, callBackFunction) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
datetime = pDatetime;
timePeriod = pTimePeriod;
let dataSetsToLoad = 0;
let dataSetsLoaded = 0;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> dataSetsToLoad = " + dataSetsToLoad); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> dataSetsLoaded = " + dataSetsLoaded); }
for (let i = 0; i < pProduct.dataSets.length; i++) {
let thisSet = pProduct.dataSets[i];
switch (thisSet.type) {
case 'Market Files': {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Market Files -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
dataSetsToLoad++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> dataSetsToLoad = " + dataSetsToLoad); }
let marketFiles = newMarketFiles();
marketFiles.initialize(pDevTeam, pBot, pProduct, thisSet, pExchange, pMarket, onMarketFileReady);
thisObject.marketFiles.push(marketFiles);
}
break;
case 'Daily Files': {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Daily Files -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
dataSetsToLoad++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> dataSetsToLoad = " + dataSetsToLoad); }
let dailyFiles = newDailyFiles();
dailyFiles.initialize(pDevTeam, pBot, pProduct, thisSet, pExchange, pMarket, pDatetime, pTimePeriod, onDailyFileReady);
thisObject.dailyFiles.push(dailyFiles);
}
break;
case 'Single File': {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> Single File -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
dataSetsToLoad++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> dataSetsToLoad = " + dataSetsToLoad); }
let singleFile = newSingleFile();
singleFile.initialize(pDevTeam, pBot, pProduct, thisSet, pExchange, pMarket, onSingleFileReady);
thisObject.singleFile.push(singleFile);
}
break;
case 'File Sequence': {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> File Sequence -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
dataSetsToLoad++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> dataSetsToLoad = " + dataSetsToLoad); }
let fileSequences = newFileSequence();
fileSequences.initialize(pDevTeam, pBot, pProduct, thisSet, pExchange, pMarket, onFileSequenceReady);
thisObject.fileSequences.push(fileSequences);
}
break;
}
function onMarketFileReady(err, pCaller) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> err.message = " + err.message); }
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
let event = {
totalValue: pCaller.getExpectedFiles(),
currentValue: pCaller.getFilesLoaded()
}
thisObject.eventHandler.raiseEvent('Market File Loaded', event);
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> event.currentValue = " + event.currentValue); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> event.totalValue = " + event.totalValue); }
if (event.currentValue === event.totalValue) {
dataSetsLoaded++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onMarketFileReady -> dataSetsLoaded = " + dataSetsLoaded); }
checkInitializeComplete();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onMarketFileReady -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function onDailyFileReady(err, pCaller) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> err.message = " + err.message); }
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
let event = {
totalValue: pCaller.getExpectedFiles(),
currentValue: pCaller.getFilesLoaded()
}
thisObject.eventHandler.raiseEvent('Daily File Loaded', event);
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> event.currentValue = " + event.currentValue); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> event.totalValue = " + event.totalValue); }
if (event.currentValue === event.totalValue) {
dataSetsLoaded++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onDailyFileReady -> dataSetsLoaded = " + dataSetsLoaded); }
checkInitializeComplete();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onDailyFileReady -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function onSingleFileReady(err, pCaller) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> err.message = " + err.message); }
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
let event = {
totalValue: 1,
currentValue: 1
}
thisObject.eventHandler.raiseEvent('Single File Loaded', event);
if (event.currentValue === event.totalValue) {
dataSetsLoaded++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onSingleFileReady -> dataSetsLoaded = " + dataSetsLoaded); }
checkInitializeComplete();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onSingleFileReady -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function onFileSequenceReady(err, pCaller) {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received OK Response."); }
break;
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received FAIL Response."); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
return;
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received CUSTOM FAIL Response."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> err.message = " + err.message); }
callBackFunction(err);
return;
}
default: {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady -> Received Unexpected Response."); }
callBackFunction(err);
return;
}
}
let event = {
totalValue: pCaller.getExpectedFiles(),
currentValue: pCaller.getFilesLoaded()
}
thisObject.eventHandler.raiseEvent('File Sequence Loaded', event);
if (event.currentValue === event.totalValue) {
dataSetsLoaded++;
if (INFO_LOG === true) { logger.write("[INFO] initialize -> onFileSequenceReady = " + dataSetsLoaded); }
checkInitializeComplete();
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> onFileSequenceReady -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function checkInitializeComplete() {
try {
if (INFO_LOG === true) { logger.write("[INFO] initialize -> checkInitializeComplete -> Entering function."); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> checkInitializeComplete -> key = " + pDevTeam.codeName + "-" + pBot.codeName + "-" + pProduct.codeName); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> checkInitializeComplete -> dataSetsToLoad = " + dataSetsToLoad); }
if (INFO_LOG === true) { logger.write("[INFO] initialize -> checkInitializeComplete -> dataSetsLoaded = " + dataSetsLoaded); }
if (dataSetsLoaded === dataSetsToLoad) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE);
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> checkInitializeComplete -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err = " + err); }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE);
}
}
function setDatetime(pDatetime) {
if (INFO_LOG === true) { logger.write("[INFO] setDatetime -> Entering function."); }
/* If there is a change in the day, then we take some actions, otherwise, we dont. */
let currentDate = Math.trunc(datetime.valueOf() / ONE_DAY_IN_MILISECONDS);
let newDate = Math.trunc(pDatetime.valueOf() / ONE_DAY_IN_MILISECONDS);
datetime = new Date(pDatetime);
if (currentDate !== newDate) {
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
for (let i = 0; i < thisObject.dailyFiles.length; i++) {
thisObject.dailyFiles[i].setDatetime(pDatetime);
}
}
}
}
function setTimePeriod(pTimePeriod) {
if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> Entering function."); }
/* We are going to filter out the cases in which the timePeriod received is the same that the one we already know. */
if (timePeriod !== pTimePeriod) {
timePeriod = pTimePeriod;
if (timePeriod <= _1_HOUR_IN_MILISECONDS) {
for (let i = 0; i < thisObject.dailyFiles.length; i++) {
thisObject.dailyFiles[i].setTimePeriod(pTimePeriod, datetime);
}
}
}
}
}
+290
View File
@@ -0,0 +1,290 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<Name>Project</Name>
<RootNamespace>browser</RootNamespace>
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>3ef11619-de26-4b8b-819d-a413df220b76</ProjectGuid>
<ProjectHome>
</ProjectHome>
<StartupFile>server.js</StartupFile>
<SearchPath>
</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
<NodejsPort>1337</NodejsPort>
<StartWebBrowser>true</StartWebBrowser>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="AABrowserAPI\BotCode.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="AABrowserAPI\TeamSetup.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="AABrowserAPI\UserAuthentication.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Animation.js" />
<Compile Include="Azure\azure-storage.blob.js" />
<Compile Include="BottomSpace\DeleteTradingHistory.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="BreakpointsBar.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="BottomSpace\ChartAspectRatio.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="CloudVM\CloudRequire.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="CloudVM\CloudVM.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="CloudVM\Exchange\ExchangeAPI.js" />
<Compile Include="Exchange\ExchangeAPI.js" />
<Compile Include="Server\Exchange\ExchangeAPI.js" />
<Compile Include="Server\Exchange\exchangeUtils.js" />
<Compile Include="Globals.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Server\Exchange\Wrappers\beautifier.js" />
<Compile Include="Server\Exchange\Wrappers\binance.js" />
<Compile Include="Server\Exchange\Wrappers\binanceClient.js" />
<Compile Include="Server\Exchange\Wrappers\poloniex.js" />
<Compile Include="Server\Exchange\Wrappers\poloniexClient.js" />
<Compile Include="TopSpace\Login.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="PlottersManager.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Scales\RightScale.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Scripts\AppLoader.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Scripts\AppPreLoader.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Server\BotsScripts.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Server\SessionManager.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="CloudVM\CloudSupport.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="CloudVM\WebFS.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="FloatingSpace\Note.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="FloatingSpace\NoteSets.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="FloatingSpace\FloatingObject.js" />
<Compile Include="CompetitionStorage.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Files\FileSequence.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="FloatingSpace\FloatingLayer.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="ImageButton.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Server\StorageAccessManager.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Spaces\BottomSpace.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Spaces\TopSpace.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TopSpace\CompanyLogo.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TopSpace\CurrentBot.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TopSpace\CurrentProcess.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TopSpace\CurrentStartMode.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TopSpace\DevTeam.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TopSpace\EndUser.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="BottomSpace\PlayStopButton.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="WebDebugLog.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="FloatingSpace\ProfileBalls.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="FloatingSpace\ProfileBall.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Scripts\require.js" />
<Compile Include="Server\CloudScripts.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Server\ConfigReader.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Server\Github.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Server\Storage.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Spaces\PanelsSpace.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="PlotterPanel.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="ProductCard.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Ecosystem.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Files\SingleFile.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Files\FileCloud.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Files\FileCursor.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Files\DailyFiles.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Candle.js" />
<Compile Include="Canvas.js" />
<Compile Include="Scales\ChartGrid.js" />
<Compile Include="Spaces\ChartSpace.js" />
<Compile Include="ChartUtilities.js" />
<Compile Include="Container.js" />
<Compile Include="Dashboard.js" />
<Compile Include="Files\MarketFiles.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Plotter.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="server.js" />
<Compile Include="Displace.js" />
<Compile Include="EventHandler.js" />
<Compile Include="Spaces\FloatingSpace.js" />
<Compile Include="Frame.js" />
<Compile Include="Panels\ProductsPanel.js" />
<Compile Include="Panels\TimeControlPanel.js" />
<Compile Include="TimeLineCoordinateSystem.js" />
<Compile Include="SplashScreen.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="ProductStorage.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TextButton.js" />
<Compile Include="TimelineChart.js" />
<Compile Include="TimeMachine.js" />
<Compile Include="Utilities.js" />
<Compile Include="ViewPort.js" />
<Compile Include="VolumeBar.js" />
<Content Include="index.html" />
<Content Include="Server\Exchange\Wrappers\binanceProperties.json" />
<Content Include="Server\Exchange\Wrappers\poloniexProperties.json" />
<Content Include="this.server.config.json" />
</ItemGroup>
<ItemGroup>
<Folder Include="Azure\" />
<Folder Include="CloudVM\" />
<Folder Include="CloudVM\Exchange\" />
<Folder Include="Exchange\" />
<Folder Include="Server\Exchange\" />
<Folder Include="Files\" />
<Folder Include="FloatingSpace\" />
<Folder Include="AABrowserAPI\" />
<Folder Include="BottomSpace\" />
<Folder Include="Scales\" />
<Folder Include="Server\Exchange\Wrappers\" />
<Folder Include="TopSpace\" />
<Folder Include="Scripts\" />
<Folder Include="Server\" />
<Folder Include="Spaces\" />
<Folder Include="Panels\" />
</ItemGroup>
<!-- Do not delete the following Import Project. While this appears to do nothing it is a marker for setting TypeScript properties before our import that depends on them. -->
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="False" />
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsTools.targets" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>0</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:48022/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>True</UseCustomServer>
<CustomServerUrl>http://localhost:1337</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}" User="">
<WebProjectProperties>
<StartPageUrl>
</StartPageUrl>
<StartAction>CurrentPage</StartAction>
<AspNetDebugging>True</AspNetDebugging>
<SilverlightDebugging>False</SilverlightDebugging>
<NativeDebugging>False</NativeDebugging>
<SQLDebugging>False</SQLDebugging>
<ExternalProgram>
</ExternalProgram>
<StartExternalURL>
</StartExternalURL>
<StartCmdLineArguments>
</StartCmdLineArguments>
<StartWorkingDirectory>
</StartWorkingDirectory>
<EnableENC>False</EnableENC>
<AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>
+1
View File
@@ -0,0 +1 @@
# CanvasApp
+769
View File
@@ -0,0 +1,769 @@
function newChartGrid() {
let thisObject = {
container: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize
};
let container = newContainer();
container.initialize();
thisObject.container = container;
thisObject.container.frame.width = 0;
thisObject.container.frame.height = 0;
container.frame.position.x = 0;
container.frame.position.y = 0;
container.isDraggeable = false;
container.isClickeable = true;
let rigthScale;
return thisObject;
function initialize() {
rigthScale = newRigthScale();
rigthScale.initialize();
}
function getContainer(point) {
let container;
container = rigthScale.getContainer(point);
if (container !== undefined) {
return container;
}
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return this.container;
} else {
/* This point does not belong to this space. */
return undefined;
}
}
function draw(container, timeLineCoordinateSystem) {
rightScaleBackground();
leftScaleBackground();
let periods = [];
let boxes = [];
let labels = [];
const basePeriod = {
x: 8 * 60 * 60 * 1000,
y: timeLineCoordinateSystem.max.y / 1000 / canvas.bottomSpace.chartAspectRatio.aspectRatio.y
};
let period = {
x: basePeriod.x,
y: basePeriod.y
};
calculateTimeLabels();
printLabels(1000, 10000);
function calculateTimeLabels() {
periods.push(period); // 0
period = {
x: basePeriod.x / 8,
y: basePeriod.y / 10
};
periods.push(period); // 1
period = {
x: basePeriod.x / 8 / 6,
y: basePeriod.y / 100
};
periods.push(period); // 2
period = {
x: basePeriod.x * 3,
y: basePeriod.y * 10
};
periods.push(period); // 3
period = {
x: basePeriod.x * 3 * 7,
y: basePeriod.y * 100
};
periods.push(period); // 4
/* Period #2 Plotting */
boxes = [];
plotGrid(periods[2]);
labels = [];
/* Label Calculation */
for (let i = 0; i < boxes.length; i++) {
const UPPER_PERIOD = 1;
let box = boxes[i];
let currentValue = box.topLeft;
currentValue = unTransformThisPoint(currentValue, container);
currentValue = timeLineCoordinateSystem.unInverseTransform(currentValue, container.frame.height);
/* We must compare the current value on the current period, against the next period, to know which cell we are in. */
let distanceToNextPeriod = Math.trunc((currentValue.x / periods[UPPER_PERIOD].x - Math.trunc(currentValue.x / periods[UPPER_PERIOD].x)) * 1000);
switch (distanceToNextPeriod) {
case 0: {
labels.push("0");
break;
}
case Math.trunc(1 / 6 * 1000): {
}
labels.push("10");
break;
case Math.trunc(2 / 6 * 1000): {
}
labels.push("20");
break;
case Math.trunc(3 / 6 * 1000): {
}
labels.push("30");
break;
case Math.trunc(4 / 6 * 1000): {
}
labels.push("40");
break;
case Math.trunc(5 / 6 * 1000): {
}
labels.push("50");
break;
}
}
printLabels(1, 150);
/* Period #1 Plotting */
boxes = [];
plotGrid(periods[1]);
labels = [];
/* Label Calculation */
for (let i = 0; i < boxes.length; i++) {
const UPPER_PERIOD = 3;
let box = boxes[i];
let currentValue = box.topLeft;
currentValue = unTransformThisPoint(currentValue, container);
currentValue = timeLineCoordinateSystem.unInverseTransform(currentValue, container.frame.height);
/* We must compare the current value on the current period, against the next period, to know which cell we are in. */
let distanceToNextPeriod = Math.trunc((currentValue.x / periods[UPPER_PERIOD].x - Math.trunc(currentValue.x / periods[UPPER_PERIOD].x)) * 1000);
switch (distanceToNextPeriod) {
case 0: {
labels.push("0 Hs");
break;
}
case Math.trunc(1 / 24 * 1000): {
}
labels.push("1 Hs");
break;
case Math.trunc(2 / 24 * 1000): {
}
labels.push("2 Hs");
break;
case Math.trunc(3 / 24 * 1000): {
}
labels.push("3 Hs");
break;
case Math.trunc(4 / 24 * 1000): {
}
labels.push("4 Hs");
break;
case Math.trunc(5 / 24 * 1000): {
}
labels.push("5 Hs");
break;
case Math.trunc(6 / 24 * 1000): {
}
labels.push("6 Hs");
break;
case Math.trunc(7 / 24 * 1000): {
}
labels.push("7 Hs");
break;
case Math.trunc(8 / 24 * 1000): {
}
labels.push("8 Hs");
break;
case Math.trunc(9 / 24 * 1000): {
}
labels.push("9 Hs");
break;
case Math.trunc(10 / 24 * 1000): {
}
labels.push("10 Hs");
break;
case Math.trunc(11 / 24 * 1000): {
}
labels.push("11 Hs");
break;
case Math.trunc(12 / 24 * 1000): {
}
labels.push("12 Hs");
break;
case Math.trunc(13 / 24 * 1000): {
}
labels.push("13 Hs");
break;
case Math.trunc(14 / 24 * 1000): {
}
labels.push("14 Hs");
break;
case Math.trunc(15 / 24 * 1000): {
}
labels.push("15 Hs");
break;
case Math.trunc(16 / 24 * 1000): {
}
labels.push("16 Hs");
break;
case Math.trunc(17 / 24 * 1000): {
}
labels.push("17 Hs");
break;
case Math.trunc(18 / 24 * 1000): {
}
labels.push("18 Hs");
break;
case Math.trunc(19 / 24 * 1000): {
}
labels.push("19 Hs");
break;
case Math.trunc(20 / 24 * 1000): {
}
labels.push("20 Hs");
break;
case Math.trunc(21 / 24 * 1000): {
}
labels.push("21 Hs");
break;
case Math.trunc(22 / 24 * 1000): {
}
labels.push("22 Hs");
break;
case Math.trunc(23 / 24 * 1000): {
}
labels.push("23 Hs");
break;
}
}
printLabels(5, 250);
/* Period #0 Plotting */
boxes = [];
plotGrid(periods[0]);
labels = [];
/* Label Calculation */
for (let i = 0; i < boxes.length; i++) {
const UPPER_PERIOD = 3;
let box = boxes[i];
let currentValue = box.topLeft;
currentValue = unTransformThisPoint(currentValue, container);
currentValue = timeLineCoordinateSystem.unInverseTransform(currentValue, container.frame.height);
/* We must compare the current value on the current period, against the next period, to know which cell we are in. */
let distanceToNextPeriod = Math.trunc((currentValue.x / periods[UPPER_PERIOD].x - Math.trunc(currentValue.x / periods[UPPER_PERIOD].x)) * 1000);
switch (distanceToNextPeriod) {
case 0: {
labels.push("Morning");
break;
}
case Math.trunc(1 / 3 * 1000): {
}
labels.push("Afternoon");
break;
case Math.trunc(2 / 3 * 1000): {
}
labels.push("Evening");
break;
}
}
printLabels(15, 50);
/* Period #3 Plotting */
boxes = [];
plotGrid(periods[3]);
labels = [];
/* Label Calculation */
for (let i = 0; i < boxes.length; i++) {
const UPPER_PERIOD = 1;
let box = boxes[i];
let currentValue = box.topLeft;
currentValue = unTransformThisPoint(currentValue, container);
currentValue = timeLineCoordinateSystem.unInverseTransform(currentValue, container.frame.height);
let date = new Date(currentValue.x);
labels.push(date.toDateString());
}
printLabels(100, 2250);
/* Period #4 Plotting */
boxes = [];
plotGrid(periods[4]);
labels = [];
/* Label Calculation */
for (let i = 0; i < boxes.length; i++) {
const UPPER_PERIOD = 1;
let box = boxes[i];
let currentValue = box.topLeft;
currentValue = unTransformThisPoint(currentValue, container);
currentValue = timeLineCoordinateSystem.unInverseTransform(currentValue, container.frame.height);
let date = new Date(currentValue.x);
var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
labels.push(monthNames[date.getMonth()] + ' ' + date.getFullYear());
}
}
function plotGrid(period) {
let periodWidth = period.x;
let periodHeight = period.y;
let visiblePoint1 = {
x: viewPort.visibleArea.topLeft.x,
y: viewPort.visibleArea.bottomLeft.y
};
visiblePoint1 = unTransformThisPoint(visiblePoint1, container);
visiblePoint1 = timeLineCoordinateSystem.unInverseTransform(visiblePoint1, container.frame.height);
let visiblePoint2 = {
x: viewPort.visibleArea.bottomRight.x,
y: viewPort.visibleArea.topRight.y
};
visiblePoint2 = unTransformThisPoint(visiblePoint2, container);
visiblePoint2 = timeLineCoordinateSystem.unInverseTransform(visiblePoint2, container.frame.height);
startingPoint = {
x: Math.trunc(visiblePoint1.x / periodWidth) * periodWidth,
y: Math.round(Math.trunc(visiblePoint1.y / periodHeight) * periodHeight * 100000) / 100000
};
endingPoint = {
x: Math.trunc(visiblePoint2.x / periodWidth) * periodWidth,
y: Math.trunc(visiblePoint2.y / periodHeight) * periodHeight
};
let lineWidth;
if (viewPort.zoomLevel > 0) {
lineWidth = period.x / basePeriod.x + period.x / basePeriod.x * viewPort.zoomLevel / 20;
} else {
lineWidth = period.x / basePeriod.x + period.x / basePeriod.x * viewPort.zoomLevel / 80;
}
if (lineWidth < 0.7) {
return;
}
if (lineWidth > 1.4) {
lineWidth = 1.4;
}
browserCanvasContext.beginPath();
let y1;
let y2;
let lastRightLabelPosition = {
x: 0,
y: 0
};
let lastLeftLabelPosition = {
x: 0,
y: 0
};
for (var j = startingPoint.y; j <= endingPoint.y + periodHeight; j = j + periodHeight) {
if (j >= 0 && j <= timeLineCoordinateSystem.max.y) {
let point1 = {
x: visiblePoint1.x,
y: j
};
let point2 = {
x: visiblePoint2.x,
y: j
};
point1 = timeLineCoordinateSystem.transformThisPoint(point1);
point2 = timeLineCoordinateSystem.transformThisPoint(point2);
point1 = transformThisPoint(point1, container);
point2 = transformThisPoint(point2, container);
if (point1.y >= viewPort.visibleArea.topLeft.y) {
/* Here we keep the last two positive valued of y */
y2 = y1;
y1 = point1.y;
}
point1 = viewPort.fitIntoVisibleArea(point1);
point2 = viewPort.fitIntoVisibleArea(point2);
browserCanvasContext.moveTo(point1.x, point1.y);
browserCanvasContext.lineTo(point2.x, point2.y);
/* Now we put the scale on the right side of the chart */
drawRigthScale();
drawLeftScale();
function drawRigthScale() {
/* And now the scale. */
let fontSize = 10;
let label = ' ' + Math.round(j * 1) / 1;
label = Number(label).toLocaleString();
let labelPoint = {
x: viewPort.visibleArea.bottomRight.x + 5,
y: point1.y + fontSize / 2 * FONT_ASPECT_RATIO
};
if (Math.abs(lastRightLabelPosition.y - labelPoint.y > fontSize || lastRightLabelPosition.y === 0)) {
if (labelPoint.y > viewPort.visibleArea.topLeft.y + fontSize && labelPoint.y < viewPort.visibleArea.bottomRight.y - fontSize) {
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
}
lastRightLabelPosition.x = labelPoint.x;
lastRightLabelPosition.y = labelPoint.y;
}
function drawLeftScale() {
let fontSize = 10;
/*
j is a value between 0 and the max y on the scale of the products.
If we want to convert j to the scale of profits we need to apply the following formula:
*/
let labelValue = (j - timeLineCoordinateSystem.max.y / 2) * 200 / timeLineCoordinateSystem.max.y;
labelValue = Math.round(labelValue * 100) / 100;
if (labelValue > 0) { labelValue = '+' + labelValue; }
if (parseInt(labelValue) > -10 && parseInt(labelValue) < 10) { labelValue = ' ' + labelValue; }
if (parseInt(labelValue) === 0) { labelValue = ' ' + labelValue; }
let label = ' ' + pad(labelValue, 3) + '%';
let labelPoint = {
x: 0,
y: point1.y + fontSize / 2 * FONT_ASPECT_RATIO
};
if (Math.abs(lastLeftLabelPosition.y - labelPoint.y > fontSize || lastLeftLabelPosition.y === 0)) {
if (labelPoint.y > viewPort.visibleArea.topLeft.y + fontSize && labelPoint.y < viewPort.visibleArea.bottomRight.y - fontSize) {
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
}
lastLeftLabelPosition.x = labelPoint.x;
lastLeftLabelPosition.y = labelPoint.y;
}
}
}
let x1;
let x2;
for (var i = startingPoint.x; i <= endingPoint.x + periodWidth; i = i + periodWidth) {
let point3 = {
x: i,
y: 0
};
let point4 = {
x: i,
y: timeLineCoordinateSystem.max.y
};
point3 = timeLineCoordinateSystem.transformThisPoint(point3);
point4 = timeLineCoordinateSystem.transformThisPoint(point4);
point3 = transformThisPoint(point3, container);
point4 = transformThisPoint(point4, container);
/* Here we keep the last two positive valued of y */
x2 = x1;
x1 = point3.x;
if (x2 !== undefined) {
let topLeft = {
x: x2,
y: y1
};
let bottomRight = {
x: x1,
y: y2
};
let box = {
topLeft: topLeft,
bottomRight: bottomRight
};
boxes.push(box);
}
/* Painting the lines */
point3 = viewPort.fitIntoVisibleArea(point3);
point4 = viewPort.fitIntoVisibleArea(point4);
browserCanvasContext.moveTo(point3.x, point3.y);
browserCanvasContext.lineTo(point4.x, point4.y);
}
browserCanvasContext.closePath();
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK + ', 0.' + Math.trunc(lineWidth + 1) + ')';
browserCanvasContext.lineWidth = lineWidth;
browserCanvasContext.stroke();
}
function printLabels(baseZoomFilter, maxZoom) {
let zoomFilter = viewPort.zoomFontSize(baseZoomFilter);
if (zoomFilter < 7 || zoomFilter > maxZoom) {
return;
}
for (let i = 0; i < boxes.length; i++) {
let label = labels[i];
if (label === undefined) {
label = "undefined";
}
let fontSize = 10;
let labelPoint = {
x: boxes[i].topLeft.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: viewPort.visibleArea.topLeft.y - fontSize / 2 + 1
};
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO;
browserCanvasContext.beginPath();
browserCanvasContext.rect(labelPoint.x, labelPoint.y - fontSize, xOffset * 2, fontSize );
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)';
browserCanvasContext.fill();
browserCanvasContext.closePath();
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY;
browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)';
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y);
}
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)';
browserCanvasContext.beginPath();
browserCanvasContext.rect(0, TOP_SPACE_HEIGHT, viewPort.visibleArea.topLeft.x, viewPort.visibleArea.topLeft.y - TOP_SPACE_HEIGHT);
browserCanvasContext.rect(viewPort.visibleArea.topRight.x, TOP_SPACE_HEIGHT, 500, viewPort.visibleArea.topLeft.y - TOP_SPACE_HEIGHT);
browserCanvasContext.closePath();
browserCanvasContext.fill();
}
function rightScaleBackground() {
const RIGHT_MARGIN = 50;
/* We will paint some transparent background here. */
let opacity = "0.95";
browserCanvasContext.beginPath();
browserCanvasContext.rect(viewPort.visibleArea.topRight.x, viewPort.visibleArea.topRight.y, RIGHT_MARGIN, viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topRight.y);
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')';
browserCanvasContext.closePath();
browserCanvasContext.fill();
}
function leftScaleBackground() {
const LEFT_MARGIN = 50;
/* We will paint some transparent background here. */
let opacity = "0.95";
browserCanvasContext.beginPath();
browserCanvasContext.rect(0, viewPort.visibleArea.topRight.y, LEFT_MARGIN, viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topRight.y);
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')';
browserCanvasContext.closePath();
browserCanvasContext.fill();
}
}
}
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff. Show more