No files matched your search
@@ -1,37 +0,0 @@
|
||||
|
||||
#PORT NUMBERS: If any of these ports are already in use by a different app, please pick a new number between 1 and 50000.
|
||||
WEB_SERVER_PORT=34247
|
||||
WEB_SOCKETS_SERVER_PORT=8080
|
||||
|
||||
|
||||
# TASK MANAGER VARIABLES:
|
||||
|
||||
TASK_SERVER_PATH=./TaskServer
|
||||
|
||||
# TASK SERVER VARIABLES:
|
||||
|
||||
INTER_PROCESS_FILES_PATH=./Inter-Process-Files
|
||||
STORAGE_PATH=./Data-Storage
|
||||
PLOTTERS_PATH=./Legacy-Code
|
||||
DATA_MINES_PATH=./Data-Mines
|
||||
TRADING_SYSTEMS_PATH=./Trading-Systems
|
||||
SUPER_SCRIPTS_PATH=./Super-Scripts
|
||||
|
||||
WRITE_LOGS_TO_FILES=true
|
||||
BOTS_PATH=./Legacy-Code
|
||||
LOG_PATH=./Log-Files
|
||||
WEB_SERVER_URL=localhost
|
||||
|
||||
# WEB SERVER VARIABLES:
|
||||
|
||||
#Log options
|
||||
CONSOLE_LOG=false
|
||||
CONSOLE_ERROR_LOG=true
|
||||
LOG_FILE_CONTENT=false
|
||||
|
||||
PATH_TO_CANVAS_APP=./CanvasApp
|
||||
PATH_TO_FILES_COMPONENT=./Files-Component/src
|
||||
PATH_TO_WEB_SERVER=./BackendServers/
|
||||
|
||||
APP_SCHEMA_PATH=./
|
||||
WORKSPACE_PATH=./
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Before you open an issue
|
||||
|
||||
There are two requirements to open an issue:
|
||||
|
||||
1. You must first follow the [Troubleshooting Guide](https://docs.superalgos.org/suite-how-to-troubleshoot-an-issue.html)
|
||||
|
||||
2. If your issue hasn't been resolved by following the Troubleshooting Guide, then follow the guide on [How to Report an Issue](https://docs.superalgos.org/suite-how-to-report-an-issue.html).
|
||||
|
||||
## Context
|
||||
|
||||
*Complete and adjust the contents leaving the information that fits your case and deleting the information that doesn't.*
|
||||
|
||||
**Operating System:** Windows | MacOs | Linux | Other (include the version on either case)
|
||||
|
||||
**Software version:** today's master branch | today's develop branch
|
||||
|
||||
**Workspace version:** default Workspace.json (Getting Started Guide) | Simple Workspace.json | Workspace - Binance - WHB - BBTB.json | My custom workspace
|
||||
|
||||
**Reproducible:** the issue may | may not be reproduced.
|
||||
|
||||
## Explain your issue
|
||||
|
||||
### 1. Explain what the problem seems to be.
|
||||
|
||||
Type your explanation here.
|
||||
|
||||
### 2. Clearly explain what you wish to accomplish.
|
||||
|
||||
Type your explanation here.
|
||||
|
||||
### 3. Explain, step by step, what you've done to achieve the goal. The Team will follow these steps to reproduce the issue, so be precise.
|
||||
|
||||
Type your explanation here.
|
||||
|
||||
### 4. Explain what is the result you expect from your actions.
|
||||
|
||||
Type your explanation here.
|
||||
|
||||
### 5. Explain what happens instead of the expected results.
|
||||
|
||||
Type your explanation here.
|
||||
|
||||
### 6. Explain what errors you have found on-screen, on the browser console application, or in the ```Log-Files``` folder.
|
||||
|
||||
Type your explanation here.
|
||||
|
||||
## Attach a video reproducing the issue
|
||||
|
||||
Attach video here.
|
||||
|
||||
## Attach relevant log files and error screenshots
|
||||
|
||||
Attach logs here.
|
||||
|
||||
## Attach you custom workspace if any
|
||||
|
||||
Attach custom workspace here.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -1,2 +1,6 @@
|
||||
Data-Storage
|
||||
Log-Files
|
||||
Log-Files
|
||||
My-Workspaces
|
||||
debug.log
|
||||
|
||||
*.db
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"**/Data-Storage": true,
|
||||
"**/Documentation": true,
|
||||
"**/Log-Files": true,
|
||||
"**/node_modules": true,
|
||||
"**/Deprecated-Code": true
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/Data-Storage": true,
|
||||
"**/Documentation": true,
|
||||
"**/Log-Files": true,
|
||||
"**/Deprecated-Code": true
|
||||
},
|
||||
"search.maintainFileSearchCache": true
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
INTER_PROCESS_FILES_PATH=../Inter-Process-Files
|
||||
STORAGE_PATH=../Data-Storage
|
||||
PLOTTERS_PATH=../Legacy-Code
|
||||
|
||||
USE_KEYVAULT=false
|
||||
WRITE_LOGS_TO_FILES=true
|
||||
BOTS_PATH=../Legacy-Code
|
||||
LOG_PATH=../Log-Files
|
||||
|
||||
WEB_SOCKETS_SERVER_PORT=8080
|
||||
WEB_SERVER_PORT=34247
|
||||
WEB_SERVER_URL=localhost
|
||||
@@ -1,252 +0,0 @@
|
||||
let dashboard
|
||||
|
||||
function newAppLoader() {
|
||||
const MODULE_NAME = 'App Loader'
|
||||
const INFO_LOG = false
|
||||
const ERROR_LOG = true
|
||||
const logger = newWebDebugLog()
|
||||
logger.fileName = MODULE_NAME
|
||||
|
||||
let thisObject = {
|
||||
loadModules: loadModules
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
async function loadModules() {
|
||||
try {
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> Entering function.') }
|
||||
|
||||
let plotters
|
||||
let modulesArray = []
|
||||
|
||||
plotters = defaultPlotters()
|
||||
|
||||
modulesArray = modulesArray.concat([
|
||||
'ChartingSpace/Viewport.js',
|
||||
|
||||
'Globals.js',
|
||||
|
||||
'AppSchema.js',
|
||||
'Workspace.js',
|
||||
|
||||
'ChartingSpace/EdgeEditor.js',
|
||||
'ChartingSpace/ChartUtilities.js',
|
||||
'ChartingSpace/PlottersManager.js',
|
||||
'ChartingSpace/TimelineChart.js',
|
||||
'ChartingSpace/TimeMachine.js',
|
||||
'ChartingSpace/CoordinateSystem.js',
|
||||
|
||||
'DesignSpace/Workspace/Workspace.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/UiObjectsFromNodes.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/ChainAttachDetach.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/ReferenceAttachDetach.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/NodeDeleter.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/ProtocolNode.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/NodeCloning.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/NodeChildren.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/TaskFunctions.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/SessionFunctions.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/ShortcutKeys.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/OnFocus.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/SuperScripts.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/CCXTFunctions.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/WebhookFunctions.js',
|
||||
'DesignSpace/Workspace/FunctionLibraries/DependenciesFilter.js',
|
||||
|
||||
'Utilities/RoundedCornersBackground.js',
|
||||
|
||||
'Panels/LayersPanel.js',
|
||||
'Panels/UpDownButton.js',
|
||||
'Panels/LeftRightButton.js',
|
||||
'Panels/Layer.js',
|
||||
'Panels/PlotterPanel.js',
|
||||
'Panels/PanelsVisibleButton.js',
|
||||
|
||||
'ControlsToolBox/SidePanel.js',
|
||||
'ControlsToolBox/SidePanelTab.js',
|
||||
|
||||
'Spaces/CockpitSpace.js',
|
||||
'Spaces/TopSpace.js',
|
||||
'Spaces/PanelsSpace.js',
|
||||
'Spaces/ChartingSpace.js',
|
||||
'Spaces/FloatingSpace.js',
|
||||
'Spaces/DesignSpace.js',
|
||||
|
||||
'Files/SingleFile.js',
|
||||
'Files/FileCloud.js',
|
||||
'Files/MarketFiles.js',
|
||||
'Files/DailyFiles.js',
|
||||
'Files/FileCursor.js',
|
||||
'Files/FileSequence.js',
|
||||
'Files/FileStorage.js',
|
||||
|
||||
'FloatingSpace/FloatingObject.js',
|
||||
'FloatingSpace/FloatingLayer.js',
|
||||
'FloatingSpace/UiObjectConstructor.js',
|
||||
'FloatingSpace/UiObject.js',
|
||||
'FloatingSpace/UiObjectTitle.js',
|
||||
'FloatingSpace/CircularMenu.js',
|
||||
'FloatingSpace/CircularMenuItem.js',
|
||||
'FloatingSpace/CircularProgressBar.js',
|
||||
'FloatingSpace/BusyProgressBar.js',
|
||||
'FloatingSpace/CodeEditor.js',
|
||||
'FloatingSpace/ConfigEditor.js',
|
||||
'FloatingSpace/ConditionEditor.js',
|
||||
'FloatingSpace/FormulaEditor.js',
|
||||
'FloatingSpace/Picker.js',
|
||||
|
||||
'Scales/RateScale.js',
|
||||
'Scales/TimeScale.js',
|
||||
'Scales/TimeFrameScale.js',
|
||||
'Scales/Commons.js',
|
||||
'Scales/AutoScaleButton.js',
|
||||
|
||||
'CockpitSpace/AssetBalances.js',
|
||||
'CockpitSpace/Speedometer.js',
|
||||
'CockpitSpace/FullScreen.js',
|
||||
|
||||
'EventsServerClient.js',
|
||||
|
||||
'VideoRecorder.js',
|
||||
'Plotter.js',
|
||||
'LegacyPlotter.js',
|
||||
'PlotterPanel.js',
|
||||
|
||||
'ProductStorage.js',
|
||||
|
||||
'SplashScreen.js',
|
||||
'Canvas.js',
|
||||
'EventHandler.js',
|
||||
'Frame.js',
|
||||
|
||||
'Animation.js',
|
||||
|
||||
'Container.js',
|
||||
|
||||
'Utilities.js',
|
||||
'PostLoader.js'
|
||||
])
|
||||
|
||||
modulesArray = modulesArray.concat(plotters)
|
||||
|
||||
let downloadedCounter = 0
|
||||
let versionParam = window.canvasApp.version
|
||||
if (versionParam === undefined) { versionParam = '' } else {
|
||||
versionParam = '?' + versionParam
|
||||
}
|
||||
|
||||
for (let i = 0; i < modulesArray.length; i++) {
|
||||
let path = window.canvasApp.urlPrefix + modulesArray[i] + versionParam
|
||||
|
||||
REQUIREJS([path], onRequired)
|
||||
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> Module Requested.') }
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> path = ' + path) }
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> total requested = ' + (i + 1)) }
|
||||
|
||||
function onRequired(pModule) {
|
||||
try {
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> Entering function.') }
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> Module Downloaded.') }
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> path = ' + path) }
|
||||
|
||||
downloadedCounter++
|
||||
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> downloadedCounter = ' + downloadedCounter) }
|
||||
|
||||
if (downloadedCounter === modulesArray.length) {
|
||||
if (INFO_LOG === true) { logger.write('[INFO] loadModules -> onRequired -> Starting Advanced Algos Platform.') }
|
||||
setTimeout(() => {
|
||||
dashboard = newDashboard()
|
||||
dashboard.start()
|
||||
}, 500)
|
||||
|
||||
}
|
||||
} catch (err) {
|
||||
if (ERROR_LOG === true) { logger.write('[ERROR] loadModules -> onRequired -> err = ' + err.stack) }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (ERROR_LOG === true) { logger.write('[ERROR] loadModules -> err = ' + err.stack) }
|
||||
}
|
||||
}
|
||||
|
||||
function defaultPlotters() {
|
||||
return [
|
||||
'Plotters/Masters/Plotters-Candles-Volumes/Candles.js',
|
||||
'Plotters/Masters/Plotters-Candles-Volumes/CandlePanel.js',
|
||||
'Plotters/Masters/Plotters-Candles-Volumes/Volumes.js',
|
||||
'Plotters/Masters/Plotters-Candles-Volumes/VolumePanel.js',
|
||||
'Plotters/Masters/Plotters-Bollinger-Bands/BollingerBands.js',
|
||||
'Plotters/Masters/Plotters-Bollinger-Bands/BollingerBandsPanel.js',
|
||||
'Plotters/Masters/Plotters-Bollinger-Bands/PercentageBandwidth.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulation.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulationAssetBalancesPanel.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulationCurrentPositionPanel.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/TradingSimulationPartialResultsPanel.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/Conditions.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/Strategies.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/Trades.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/SimulationExecution.js',
|
||||
'Plotters/TradingEngines/Plotters-Trading-Simulation/SimulationExecutionPanel.js'
|
||||
]
|
||||
}
|
||||
|
||||
function getPlotters(ecosystem) {
|
||||
if (INFO_LOG === true) { console.log('[INFO] server -> onBrowserRequest -> onFileRead -> addPlotters -> Entering function.') }
|
||||
|
||||
let plotters = []
|
||||
let dataMines = ecosystem.dataMines
|
||||
let hosts = ecosystem.hosts
|
||||
|
||||
plotters = plotters.concat(addScript(dataMines))
|
||||
plotters = plotters.concat(addScript(hosts))
|
||||
|
||||
return plotters
|
||||
}
|
||||
|
||||
function addScript(pDataMinesOrHosts) {
|
||||
if (INFO_LOG === true) { console.log('[INFO] server -> onBrowserRequest -> onFileRead -> addPlotters -> addScript -> Entering function.') }
|
||||
const htmlLinePlotter = 'Plotters/@dataMine@/@repo@/@module@.js'
|
||||
const htmlLinePlotterPanel = 'PlotterPanels/@dataMine@/@repo@/@module@.js'
|
||||
let plotters = []
|
||||
|
||||
for (let i = 0; i < pDataMinesOrHosts.length; i++) {
|
||||
let dataMine = pDataMinesOrHosts[i]
|
||||
for (let j = 0; j < dataMine.plotters.length; j++) {
|
||||
let plotter = dataMine.plotters[j]
|
||||
if (plotter.modules !== undefined) {
|
||||
for (let k = 0; k < plotter.modules.length; k++) {
|
||||
let module = plotter.modules[k]
|
||||
let htmlLineCopy = htmlLinePlotter
|
||||
|
||||
let stringToInsert
|
||||
stringToInsert = htmlLineCopy.replace('@dataMine@', dataMine.codeName)
|
||||
stringToInsert = stringToInsert.replace('@repo@', plotter.repo)
|
||||
stringToInsert = stringToInsert.replace('@module@', module.moduleName)
|
||||
|
||||
plotters.push(stringToInsert)
|
||||
|
||||
if (module.panels !== undefined) {
|
||||
for (let l = 0; l < module.panels.length; l++) {
|
||||
let panel = module.panels[l]
|
||||
let htmlLineCopy = htmlLinePlotterPanel
|
||||
|
||||
let stringToInsert
|
||||
stringToInsert = htmlLineCopy.replace('@dataMine@', dataMine.codeName)
|
||||
stringToInsert = stringToInsert.replace('@repo@', plotter.repo)
|
||||
stringToInsert = stringToInsert.replace('@module@', panel.moduleName)
|
||||
|
||||
plotters.push(stringToInsert)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return plotters
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
|
||||
/* Callbacks default responses. */
|
||||
|
||||
let GLOBAL = {};
|
||||
|
||||
GLOBAL.DEFAULT_OK_RESPONSE = {
|
||||
result: "Ok",
|
||||
message: "Operation Succeeded"
|
||||
};
|
||||
|
||||
GLOBAL.DEFAULT_FAIL_RESPONSE = {
|
||||
result: "Fail",
|
||||
message: "Operation Failed"
|
||||
};
|
||||
|
||||
GLOBAL.DEFAULT_RETRY_RESPONSE = {
|
||||
result: "Retry",
|
||||
message: "Retry Later"
|
||||
};
|
||||
|
||||
GLOBAL.CUSTOM_OK_RESPONSE = {
|
||||
result: "Ok, but check Message",
|
||||
message: "Custom Message"
|
||||
};
|
||||
|
||||
GLOBAL.CUSTOM_FAIL_RESPONSE = {
|
||||
result: "Fail Because",
|
||||
message: "Custom Message"
|
||||
};
|
||||
|
||||
let browserCanvas; // This is the canvas object of the browser.
|
||||
|
||||
function spacePad(str, max) {
|
||||
str = str.toString();
|
||||
return str.length < max ? spacePad(" " + str, max) : str;
|
||||
}
|
||||
|
||||
function loadSuperalgos() {
|
||||
|
||||
const MODULE_NAME = "App Pre-Loader";
|
||||
const INFO_LOG = false;
|
||||
const ERROR_LOG = true;
|
||||
|
||||
if (INFO_LOG === true) { console.log(spacePad(MODULE_NAME, 50) + " : " + "[INFO] loadSuperalgos -> Entering function."); }
|
||||
|
||||
/* The first thing to do here is to add the canvas where all the action is going to happen. */
|
||||
|
||||
|
||||
let textArea = document.createElement('textarea');
|
||||
textArea.id = "textArea";
|
||||
textArea.spellcheck = false;
|
||||
textArea.style = 'resize: none;' +
|
||||
' border: none;' +
|
||||
' outline: none;' +
|
||||
'box-shadow: none;' +
|
||||
'overflow:hidden;' +
|
||||
'font-family: ' + 'Saira' + ';' +
|
||||
'font-size: 12px;' +
|
||||
'background-color: rgb(255, 255, 255);' +
|
||||
'color:rgb(255, 255, 255);' +
|
||||
'width: ' + 800 + 'px;' +
|
||||
'height: ' + 600 + 'px'
|
||||
|
||||
let textAreaDiv = document.getElementById('textAreaDiv');
|
||||
textAreaDiv.appendChild(textArea);
|
||||
textAreaDiv.style = 'position:fixed; top:' + -1500 + 'px; left:' + 500 + 'px; z-index:10; '
|
||||
|
||||
let input = document.createElement('input');
|
||||
input.id = "input";
|
||||
input.spellcheck = false;
|
||||
input.style = "border: none; outline: none; box-shadow: none; overflow:hidden; width: 0px; height: 0px;";
|
||||
|
||||
let inputDiv = document.getElementById('inputDiv');
|
||||
inputDiv.appendChild(input);
|
||||
|
||||
|
||||
let canvas = document.createElement('canvas');
|
||||
|
||||
canvas.id = "canvas";
|
||||
canvas.width = 1400;
|
||||
canvas.height = 600;
|
||||
canvas.style.border = "0";
|
||||
canvas.style = "position:absolute; top:0px; left:0px; z-index:1";
|
||||
|
||||
let canvasApp = document.getElementById('canvasApp');
|
||||
canvasApp.appendChild(canvas);
|
||||
|
||||
browserCanvas = document.getElementById('canvas');
|
||||
|
||||
browserCanvas.width = window.innerWidth;
|
||||
browserCanvas.height = window.innerHeight - window.canvasApp.topMargin;
|
||||
browserCanvas.style.border = "none";
|
||||
|
||||
browserCanvas.style.top = window.canvasApp.topMargin + 'px';
|
||||
|
||||
|
||||
|
||||
loadDebugModule();
|
||||
|
||||
function loadDebugModule() {
|
||||
|
||||
try {
|
||||
if (INFO_LOG === true) { console.log(spacePad(MODULE_NAME, 50) + " : " + "[INFO] loadDebugModule -> Entering function."); }
|
||||
|
||||
let path = window.canvasApp.urlPrefix + "WebDebugLog.js";
|
||||
|
||||
REQUIREJS([path], onRequired);
|
||||
|
||||
function onRequired(pModule) {
|
||||
|
||||
if (INFO_LOG === true) { console.log(spacePad(MODULE_NAME, 50) + " : " + "[INFO] " + path + " downloaded."); }
|
||||
|
||||
loadModules();
|
||||
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(spacePad(MODULE_NAME, 50) + " : " + "[ERROR] loadDebugModule --> " + path + " --> err = " + err.stack);
|
||||
}
|
||||
}
|
||||
|
||||
/* And Finally, we start loading all the scripts we will inmediatelly need. */
|
||||
|
||||
function loadModules() {
|
||||
|
||||
try {
|
||||
|
||||
if (INFO_LOG === true) { console.log(spacePad(MODULE_NAME, 50) + " : " + "[INFO] loadModules -> Entering function."); }
|
||||
|
||||
let path = window.canvasApp.urlPrefix + "WebServer/AppLoader.js";
|
||||
|
||||
REQUIREJS([path], onRequired);
|
||||
|
||||
function onRequired(pModule) {
|
||||
|
||||
if (INFO_LOG === true) { console.log(spacePad(MODULE_NAME, 50) + " : " + "[INFO] " + path + " downloaded."); }
|
||||
|
||||
let APP_LOADER_MODULE = newAppLoader();
|
||||
APP_LOADER_MODULE.loadModules();
|
||||
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(spacePad(MODULE_NAME, 50) + " : " + "[ERROR] loadModules --> " + path + " --> err = " + err.stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function callServer(pContentToSend, pPath, callBackFunction) {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function () {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, xhttp.responseText);
|
||||
return;
|
||||
} else if (this.readyState === 4 && this.status === 404) {
|
||||
callBackFunction({ result: "Fail", message: xhttp.responseText.trim(), code: xhttp.responseText.trim() });
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if (pContentToSend === undefined) {
|
||||
xhttp.open("GET", pPath, true);
|
||||
xhttp.send();
|
||||
} else {
|
||||
try {
|
||||
let blob = new Blob([pContentToSend], { type: 'text/plain' });
|
||||
xhttp.open("POST", pPath, true);
|
||||
xhttp.send(blob);
|
||||
} catch (err) {
|
||||
if (ERROR_LOG === true) { console.log(spacePad(MODULE_NAME, 50) + " : " + "[ERROR] callServer -> err.message = " & err.message); }
|
||||
callBackFunction({ result: "Fail", message: err.message })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 255 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 809 KiB |
@@ -1,6 +0,0 @@
|
||||
function getNewPlotterPanel(pDataMineOrHost, pPlotter, pModule, pPanel) {
|
||||
let functionName = pDataMineOrHost + pPlotter + pModule + pPanel;
|
||||
functionName = functionName.replace(/-/g, "");
|
||||
functionName = 'new' + functionName
|
||||
return window[functionName]();
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Superalgos</title>
|
||||
<meta name="description"
|
||||
content="Crypto Trading on an Industrial Scale">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link href="https://fonts.googleapis.com/css?family=Saira+Condensed:300,600|Saira:300,600&subset=latin-ext,vietnamese"
|
||||
rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css"
|
||||
integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
|
||||
<link rel="shortcut icon" type="image/png/ico" href="Images/favicon.ico" />
|
||||
|
||||
<script type="text/javascript" src="WebServer/require.js"></script>
|
||||
<script type="text/javascript" src="WebServer/AppPreLoader.js"></script>
|
||||
<script src="externalScripts/CCapture.all.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function loadCanvas() {
|
||||
if (window.canvasApp.visible === undefined) {
|
||||
window.canvasApp = {
|
||||
version: '', // This is used to avoid catching problems at the browser level.
|
||||
sessionToken: '',
|
||||
visible: true,
|
||||
topMargin: 0,
|
||||
urlPrefix: 'http://localhost:WEB_SERVER_PORT/',
|
||||
graphQL: {
|
||||
masterAppApiUrl: 'https://demo-api-dev.superalgos.org/graphql',
|
||||
},
|
||||
context: {}
|
||||
};
|
||||
|
||||
try {
|
||||
loadSuperalgos();
|
||||
} catch (err) {
|
||||
console.log("[ERROR] CanvasApp can not be started. Please check that WebServer is running.", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
try {
|
||||
if (canvas === undefined) { return }
|
||||
if (canvas.eventHandler === undefined) { return }
|
||||
canvas.eventHandler.raiseEvent('Browser Resized')
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body id="body" onload="loadCanvas()"
|
||||
style="overflow:hidden; background: url(Images/superalgos-platform.jpg); background-size: cover;"
|
||||
onresize="onResize()">
|
||||
|
||||
<div id="masterApp"></div>
|
||||
<div id="canvasApp"></div>
|
||||
<div id="textAreaDiv"></div>
|
||||
<div id="inputDiv" style="font-family:saira condensed;"> </div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,237 +0,0 @@
|
||||
exports.newEventsServer = function newEventsServer() {
|
||||
|
||||
const MODULE = "Events Server"
|
||||
const LOG_INFO = false
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
run: run,
|
||||
onMessage: onMessage
|
||||
}
|
||||
|
||||
let eventHandlers = new Map()
|
||||
let counter = 0
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
}
|
||||
|
||||
function onMessage(data, callbackFunction) {
|
||||
try {
|
||||
let command = JSON.parse(data)
|
||||
|
||||
switch (command.action) {
|
||||
case "greetings": {
|
||||
sendResponse(global.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
case "createEventHandler": {
|
||||
let eventHandler = eventHandlers.get(command.eventHandlerName)
|
||||
if (eventHandler === undefined) {
|
||||
/*
|
||||
We will only create event handlers which were not created before. Remember that someone trying to listen events
|
||||
at an event handler that does not exist, will create that eventhandler, so it is possible that the emitter
|
||||
when trying to create the event handler in fact was late and the event handler is already there if the listener
|
||||
arrived here first. An event handler created with this method is not destroyed if there are no listeners or they
|
||||
all leave.
|
||||
*/
|
||||
eventHandler = newEventHandler()
|
||||
eventHandler.deleteWhenAllListenersAreGone = false
|
||||
eventHandlers.set(command.eventHandlerName, eventHandler)
|
||||
}
|
||||
sendResponse(global.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
case "deleteEventHandler": {
|
||||
let eventHandler = eventHandlers.get(command.eventHandlerName)
|
||||
if (eventHandler !== undefined) {
|
||||
/*
|
||||
We will only delete event handlers which have noone listening, allowing a listener to continue listening even
|
||||
when the event emitter is gone, asuming that it could come back at some point in time and resume emitting.
|
||||
*/
|
||||
if (eventHandler.listeners.length === 0) {
|
||||
eventHandlers.delete(command.eventHandlerName)
|
||||
} else {
|
||||
eventHandler.deleteWhenAllListenersAreGone = true
|
||||
}
|
||||
}
|
||||
|
||||
sendResponse(global.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
case "listenToEvent": {
|
||||
let eventHandler = eventHandlers.get(command.eventHandlerName)
|
||||
if (eventHandler === undefined) {
|
||||
/*
|
||||
We will create event handlers which were not created before if a listener tries to listen to a handler that does not
|
||||
exist before the emitter comes and create it. This is to aviod syncronization problems and also problems with emitters life
|
||||
cycles with higher frecuency that the ones of listeners. Created in this way, event handlers are marked for deletion if
|
||||
all listeners stop listening at one point in time.
|
||||
*/
|
||||
eventHandler = newEventHandler()
|
||||
eventHandler.deleteWhenAllListenersAreGone = true
|
||||
eventHandlers.set(command.eventHandlerName, eventHandler)
|
||||
}
|
||||
eventSubscriptionId = eventHandler.listenToEvent(command.eventHandlerName, command.eventType, command.callerId, handlerFunction, command.extraData)
|
||||
|
||||
function handlerFunction(event, extraData) {
|
||||
let outputData = {
|
||||
action: 'Event Raised',
|
||||
eventHandlerName: command.eventHandlerName,
|
||||
eventType: command.eventType,
|
||||
event: event,
|
||||
callerId: command.callerId,
|
||||
extraData: extraData
|
||||
}
|
||||
callbackFunction(JSON.stringify(outputData))
|
||||
}
|
||||
|
||||
let response = {
|
||||
result: global.DEFAULT_OK_RESPONSE.result,
|
||||
message: global.DEFAULT_OK_RESPONSE.message,
|
||||
eventSubscriptionId: eventSubscriptionId
|
||||
}
|
||||
|
||||
sendResponse(response)
|
||||
return
|
||||
}
|
||||
case "stopListening": {
|
||||
let eventHandler = eventHandlers.get(command.eventHandlerName)
|
||||
|
||||
if (eventHandler === undefined) {
|
||||
|
||||
/* If the event handler does not exist anymore, then there is no need to perform further actiions. */
|
||||
sendResponse(global.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
|
||||
eventHandler.stopListening(command.eventHandlerName, command.eventType, command.callerId, command.eventSubscriptionId)
|
||||
|
||||
/*
|
||||
We check here if there are no more listeners and the event handler original emmiter is also gone, then we need to delete
|
||||
this event handlers since chances are that is not needed anymore.
|
||||
*/
|
||||
if (eventHandler.listeners.length === 0 && eventHandler.deleteWhenAllListenersAreGone === true) {
|
||||
eventHandlers.delete(command.eventHandlerName)
|
||||
}
|
||||
|
||||
sendResponse(global.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
case "raiseEvent": {
|
||||
let eventHandler = eventHandlers.get(command.eventHandlerName)
|
||||
|
||||
if (eventHandler === undefined) {
|
||||
|
||||
eventHandler = newEventHandler()
|
||||
eventHandlers.set(command.eventHandlerName, eventHandler)
|
||||
|
||||
/* No matter if it is the listener or the emiter the one that acts first, if an event handler does not exist we just create it acan keep it there. */
|
||||
|
||||
}
|
||||
//console.log("[INFO] BackendServers -> Events Server -> Raising Event " + command.eventHandlerName + " " + command.eventType)
|
||||
eventHandler.raiseEvent(command.eventType, command.event)
|
||||
sendResponse(global.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[WARN] BackendServers -> Events Server -> onMessage -> Unknown Command Received:" + data)
|
||||
|
||||
function sendResponse(message) {
|
||||
if (command.callerId !== undefined) {
|
||||
message.callerId = command.callerId
|
||||
}
|
||||
message.action = 'Event Server Response'
|
||||
callbackFunction(JSON.stringify(message))
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log("[ERROR] BackendServers -> Events Server -> onMessage -> Bad Command Received:" + data)
|
||||
console.log("[ERROR] BackendServers -> Events Server -> onMessage -> An Error Happened:" + err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function run() {
|
||||
console.log('Events Server Started.')
|
||||
}
|
||||
|
||||
function newEventHandler() {
|
||||
let thisObject = {
|
||||
name: undefined, // This is for debugging purposes only.
|
||||
deleteWhenAllListenersAreGone: false,
|
||||
listeners: [], // Here we store all the functions we will call when an event is raiseed.
|
||||
listenToEvent: listenToEvent,
|
||||
stopListening: stopListening,
|
||||
raiseEvent: raiseEvent,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
thisObject.listeners = []
|
||||
}
|
||||
|
||||
function listenToEvent(eventHandlerName, eventType, callerId, handler, extraData) {
|
||||
let eventSubscriptionId = Math.trunc(Math.random() * 1000000)
|
||||
|
||||
/*
|
||||
We can not allow to have the exact same listener more than once. In case that we find a listener trying to listen again, the first record will
|
||||
be deleted and we are just going to consider the last one comming in.
|
||||
*/
|
||||
for (let i = 0; i < thisObject.listeners.length; i++) {
|
||||
if (eventHandlerName === thisObject.listeners[i][0] && eventType === thisObject.listeners[i][1] && callerId === thisObject.listeners[i][2]) {
|
||||
thisObject.listeners.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
thisObject.listeners.push([eventHandlerName, eventType, callerId, handler, extraData, eventSubscriptionId])
|
||||
|
||||
|
||||
return eventSubscriptionId
|
||||
}
|
||||
|
||||
function stopListening(eventHandlerName, eventType, callerId, eventSubscriptionId) {
|
||||
|
||||
if (eventSubscriptionId !== undefined) {
|
||||
for (let i = 0; i < thisObject.listeners.length; i++) {
|
||||
if (eventSubscriptionId === thisObject.listeners[i][5]) {
|
||||
thisObject.listeners.splice(i, 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (eventHandlerName !== undefined && eventType !== undefined && callerId !== undefined) {
|
||||
for (let i = 0; i < thisObject.listeners.length; i++) {
|
||||
if (eventHandlerName === thisObject.listeners[i][0] && eventType === thisObject.listeners[i][1] && callerId === thisObject.listeners[i][2]) {
|
||||
thisObject.listeners.splice(i, 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function raiseEvent(eventType, event) {
|
||||
for (let i = 0; i < thisObject.listeners.length; i++) {
|
||||
/* We will execute all the functions listening to this event type. */
|
||||
|
||||
if (thisObject.listeners[i][1] === eventType) {
|
||||
let handler = thisObject.listeners[i][3]
|
||||
let extraData = thisObject.listeners[i][4]
|
||||
|
||||
handler(event, extraData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
(function () {
|
||||
require('./lib/main').config(
|
||||
Object.assign(
|
||||
{},
|
||||
require('./lib/env-options'),
|
||||
require('./lib/cli-options')(process.argv)
|
||||
)
|
||||
)
|
||||
})()
|
||||
@@ -1,13 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
const re = /^dotenv_config_(encoding|path|debug)=(.+)$/
|
||||
|
||||
module.exports = function optionMatcher (args /*: Array<string> */) {
|
||||
return args.reduce(function (acc, cur) {
|
||||
const matches = cur.match(re)
|
||||
if (matches) {
|
||||
acc[matches[1]] = matches[2]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
// ../config.js accepts options via environment variables
|
||||
const options = {}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_ENCODING != null) {
|
||||
options.encoding = process.env.DOTENV_CONFIG_ENCODING
|
||||
}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_PATH != null) {
|
||||
options.path = process.env.DOTENV_CONFIG_PATH
|
||||
}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_DEBUG != null) {
|
||||
options.debug = process.env.DOTENV_CONFIG_DEBUG
|
||||
}
|
||||
|
||||
module.exports = options
|
||||
@@ -1,113 +0,0 @@
|
||||
/* @flow */
|
||||
/*::
|
||||
|
||||
type DotenvParseOptions = {
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
// keys and values from src
|
||||
type DotenvParseOutput = { [string]: string }
|
||||
|
||||
type DotenvConfigOptions = {
|
||||
path?: string, // path to .env file
|
||||
encoding?: string, // encoding of .env file
|
||||
debug?: string // turn on logging for debugging purposes
|
||||
}
|
||||
|
||||
type DotenvConfigOutput = {
|
||||
parsed?: DotenvParseOutput,
|
||||
error?: Error
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
function log (message /*: string */) {
|
||||
console.log(`[dotenv][DEBUG] ${message}`)
|
||||
}
|
||||
|
||||
const NEWLINE = '\n'
|
||||
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
|
||||
const RE_NEWLINES = /\\n/g
|
||||
const NEWLINES_MATCH = /\n|\r|\r\n/
|
||||
|
||||
// Parses src into an Object
|
||||
function parse (src /*: string | Buffer */, options /*: ?DotenvParseOptions */) /*: DotenvParseOutput */ {
|
||||
const debug = Boolean(options && options.debug)
|
||||
const obj = {}
|
||||
|
||||
// convert Buffers before splitting into lines and processing
|
||||
src.toString().split(NEWLINES_MATCH).forEach(function (line, idx) {
|
||||
// matching "KEY' and 'VAL' in 'KEY=VAL'
|
||||
const keyValueArr = line.match(RE_INI_KEY_VAL)
|
||||
// matched?
|
||||
if (keyValueArr != null) {
|
||||
const key = keyValueArr[1]
|
||||
// default undefined or missing values to empty string
|
||||
let val = (keyValueArr[2] || '')
|
||||
const end = val.length - 1
|
||||
const isDoubleQuoted = val[0] === '"' && val[end] === '"'
|
||||
const isSingleQuoted = val[0] === "'" && val[end] === "'"
|
||||
|
||||
// if single or double quoted, remove quotes
|
||||
if (isSingleQuoted || isDoubleQuoted) {
|
||||
val = val.substring(1, end)
|
||||
|
||||
// if double quoted, expand newlines
|
||||
if (isDoubleQuoted) {
|
||||
val = val.replace(RE_NEWLINES, NEWLINE)
|
||||
}
|
||||
} else {
|
||||
// remove surrounding whitespace
|
||||
val = val.trim()
|
||||
}
|
||||
|
||||
obj[key] = val
|
||||
} else if (debug) {
|
||||
log(`did not match key and value when parsing line ${idx + 1}: ${line}`)
|
||||
}
|
||||
})
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
// Populates process.env from .env file
|
||||
function config (options /*: ?DotenvConfigOptions */) /*: DotenvConfigOutput */ {
|
||||
let dotenvPath = path.resolve(process.cwd(), '.env')
|
||||
let encoding /*: string */ = 'utf8'
|
||||
let debug = false
|
||||
|
||||
if (options) {
|
||||
if (options.path != null) {
|
||||
dotenvPath = options.path
|
||||
}
|
||||
if (options.encoding != null) {
|
||||
encoding = options.encoding
|
||||
}
|
||||
if (options.debug != null) {
|
||||
debug = true
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// specifying an encoding returns a string instead of a buffer
|
||||
const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug })
|
||||
|
||||
Object.keys(parsed).forEach(function (key) {
|
||||
if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
|
||||
process.env[key] = parsed[key]
|
||||
} else if (debug) {
|
||||
log(`"${key}" is already defined in \`process.env\` and will not be overwritten`)
|
||||
}
|
||||
})
|
||||
|
||||
return { parsed }
|
||||
} catch (e) {
|
||||
return { error: e }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.config = config
|
||||
module.exports.parse = parse
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
"_from": "dotenv@^8.2.0",
|
||||
"_id": "dotenv@8.2.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||
"_location": "/dotenv",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "dotenv@^8.2.0",
|
||||
"name": "dotenv",
|
||||
"escapedName": "dotenv",
|
||||
"rawSpec": "^8.2.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "^8.2.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
|
||||
"_spec": "dotenv@^8.2.0",
|
||||
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\BackendServers",
|
||||
"bugs": {
|
||||
"url": "https://github.com/motdotla/dotenv/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {},
|
||||
"deprecated": false,
|
||||
"description": "Loads environment variables from .env file",
|
||||
"devDependencies": {
|
||||
"decache": "^4.5.1",
|
||||
"dtslint": "^0.9.8",
|
||||
"flow-bin": "^0.109.0",
|
||||
"sinon": "^7.5.0",
|
||||
"standard": "^13.1.0",
|
||||
"standard-markdown": "^5.1.0",
|
||||
"standard-version": "^7.0.0",
|
||||
"tap": "^14.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"homepage": "https://github.com/motdotla/dotenv#readme",
|
||||
"keywords": [
|
||||
"dotenv",
|
||||
"env",
|
||||
".env",
|
||||
"environment",
|
||||
"variables",
|
||||
"config",
|
||||
"settings"
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"main": "lib/main.js",
|
||||
"name": "dotenv",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/motdotla/dotenv.git"
|
||||
},
|
||||
"scripts": {
|
||||
"dtslint": "dtslint types",
|
||||
"flow": "flow",
|
||||
"lint": "standard",
|
||||
"postlint": "standard-markdown",
|
||||
"prerelease": "npm test",
|
||||
"pretest": "npm run lint && npm run dtslint",
|
||||
"release": "standard-version",
|
||||
"test": "tap tests/*.js --100"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"flow-typed/"
|
||||
]
|
||||
},
|
||||
"types": "types",
|
||||
"version": "8.2.0"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": ["es6"],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noEmit": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"dotenv": ["."]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "dtslint/dtslint.json",
|
||||
"rules": {
|
||||
"strict-export-declare-modifiers": false
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
{
|
||||
"name": "backend-servers",
|
||||
"version": "0.0.6",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"requires": {
|
||||
"balanced-match": "1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"ccxt": {
|
||||
"version": "1.26.45",
|
||||
"resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.26.45.tgz",
|
||||
"integrity": "sha512-/gmeUKUlNsroBR2/W7A3knZzCvPYzztb7VRwtWyqze7U/LZiXsXo1GBSC2goQIe2xL8FlAyk7ARjZrPdSWtExA=="
|
||||
},
|
||||
"child_process": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz",
|
||||
"integrity": "sha1-sffn/HPSXn/R1FWtyU4UODAYK1o="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
"inflight": "1.0.6",
|
||||
"inherits": "2.0.4",
|
||||
"minimatch": "3.0.4",
|
||||
"once": "1.4.0",
|
||||
"path-is-absolute": "1.0.1"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"requires": {
|
||||
"once": "1.4.0",
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"is-wsl": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
|
||||
"integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"requires": {
|
||||
"brace-expansion": "1.1.11"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"open": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz",
|
||||
"integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==",
|
||||
"requires": {
|
||||
"is-wsl": "1.1.0"
|
||||
}
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"requires": {
|
||||
"glob": "7.1.6"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
|
||||
"integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "backend-servers",
|
||||
"version": "0.0.6",
|
||||
"description": "BackendServer",
|
||||
"main": "server.js",
|
||||
"author": {
|
||||
"name": "Luis-Fernando-Molina"
|
||||
},
|
||||
"dependencies": {
|
||||
"child_process": "^1.0.2",
|
||||
"dotenv": "^8.2.0",
|
||||
"ws": "^7.1.2",
|
||||
"ccxt": "^1.23.67",
|
||||
"open": "^6.4.0",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
if (err.message.indexOf("EADDRINUSE") > 0) {
|
||||
console.log("A Superalgos Backend Server cannot be started. Reason: the port " + port + " is already in use by another application.")
|
||||
return
|
||||
}
|
||||
console.log('[ERROR] Backend Server -> server -> uncaughtException -> err.message = ' + err.message)
|
||||
console.log('[ERROR] Backend Server -> server -> uncaughtException -> err.stack = ' + err.stack)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('[ERROR] Backend Server -> server -> unhandledRejection -> reason = ' + JSON.stringify(reason))
|
||||
console.log('[ERROR] Backend Server -> server -> unhandledRejection -> p = ' + JSON.stringify(p))
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
/* Callbacks default responses. */
|
||||
|
||||
global.DEFAULT_OK_RESPONSE = {
|
||||
result: "Ok",
|
||||
message: "Operation Succeeded"
|
||||
};
|
||||
|
||||
global.DEFAULT_FAIL_RESPONSE = {
|
||||
result: "Fail",
|
||||
message: "Operation Failed"
|
||||
};
|
||||
|
||||
global.DEFAULT_RETRY_RESPONSE = {
|
||||
result: 'Retry',
|
||||
message: 'Retry Later'
|
||||
}
|
||||
|
||||
global.CUSTOM_OK_RESPONSE = {
|
||||
result: 'Ok, but check Message',
|
||||
message: 'Custom Message'
|
||||
}
|
||||
|
||||
global.CUSTOM_FAIL_RESPONSE = {
|
||||
result: 'Fail Because',
|
||||
message: 'Custom Message'
|
||||
}
|
||||
|
||||
|
||||
let EVENTS_SERVER = require('./eventsServer.js');
|
||||
let WEB_SOCKETS_SERVER = require('./webSocketsServer.js');
|
||||
let TASK_MANAGER_SERVER = require('./taskManagerServer.js');
|
||||
let WEB_SERVER = require('./webServer.js');
|
||||
|
||||
try {
|
||||
EVENTS_SERVER = EVENTS_SERVER.newEventsServer()
|
||||
EVENTS_SERVER.initialize()
|
||||
EVENTS_SERVER.run()
|
||||
|
||||
WEB_SOCKETS_SERVER = WEB_SOCKETS_SERVER.newWebSocketsServer(EVENTS_SERVER)
|
||||
WEB_SOCKETS_SERVER.initialize()
|
||||
WEB_SOCKETS_SERVER.run()
|
||||
|
||||
TASK_MANAGER_SERVER = TASK_MANAGER_SERVER.newTaskManagerServer(WEB_SOCKETS_SERVER, EVENTS_SERVER)
|
||||
TASK_MANAGER_SERVER.initialize()
|
||||
TASK_MANAGER_SERVER.run()
|
||||
|
||||
WEB_SERVER = WEB_SERVER.newWebServer(EVENTS_SERVER)
|
||||
WEB_SERVER.initialize()
|
||||
WEB_SERVER.run()
|
||||
|
||||
} catch (err) {
|
||||
console.log('[ERROR] BackendServers -> Task Manager -> server -> Error = ' + err.stack)
|
||||
}
|
||||
|
||||
@@ -1,296 +0,0 @@
|
||||
exports.newTaskManagerServer = function newTaskManagerServer(WEB_SOCKETS_SERVER, EVENTS_SERVER) {
|
||||
|
||||
const MODULE = "Task Manager Server"
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
run: run
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
This server creates and destroys Task Servers according to what is going on at the UI. Each of these created servers will do their own
|
||||
work. The responsibility of this server is to manage those children processes in order to be in sync with what the end user want and is defining
|
||||
at the user interface.
|
||||
|
||||
*/
|
||||
|
||||
const { fork } = require('child_process')
|
||||
require('dotenv').config()
|
||||
tasks = new Map()
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
}
|
||||
|
||||
function run() {
|
||||
|
||||
/*
|
||||
|
||||
Here we will create an Event Handler for this server. After that we will listen to events happening here. Elements of the UI will raise events here,
|
||||
as a way to communicate what is going on with the user interacting with UI components. That is the way this server will know for example when a new
|
||||
task needs to be created or destroyed.
|
||||
|
||||
*/
|
||||
|
||||
let eventsServerClient = newEventsServerClient()
|
||||
eventsServerClient.createEventHandler('Task Manager')
|
||||
eventsServerClient.listenToEvent('Task Manager', 'Run Task', undefined, undefined, undefined, runTask)
|
||||
eventsServerClient.listenToEvent('Task Manager', 'Stop Task', undefined, undefined, undefined, stopTask)
|
||||
|
||||
console.log('Task Manager Server Started.')
|
||||
|
||||
function runTask(message) {
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Entering function.')
|
||||
|
||||
if (message.event === undefined) {
|
||||
console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Message Received Without Event -> message = ' + JSON.stringify(message).substring(0, 1000))
|
||||
return
|
||||
}
|
||||
|
||||
if (message.event.taskId === undefined) {
|
||||
console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Message Received Without taskId -> message = ' + JSON.stringify(message).substring(0, 1000))
|
||||
return
|
||||
}
|
||||
|
||||
if (message.event.taskDefinition === undefined) {
|
||||
console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Message Received Without taskDefinition -> message = ' + JSON.stringify(message).substring(0, 1000))
|
||||
return
|
||||
}
|
||||
|
||||
if (tasks.get(message.event.taskId) !== undefined) {
|
||||
let key = message.event.taskName + '-' + 'Task' + '-' + message.event.taskId
|
||||
eventsServerClient.raiseEvent(key, 'Running') // Meaning Task Running
|
||||
return
|
||||
}
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Name = ' + message.event.taskName)
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Id = ' + message.event.taskId)
|
||||
|
||||
let path = process.env.TASK_SERVER_PATH + '/server.js'
|
||||
|
||||
/* Workarround to avoid having the same debug port at the forked process which makes it crash. */
|
||||
for (let i = 0; i < process.execArgv.length; i++) {
|
||||
let argument = process.execArgv[i]
|
||||
if (argument.indexOf('--inspect') > -1) {
|
||||
process.execArgv[i] = ''
|
||||
}
|
||||
}
|
||||
|
||||
/* Forking this process. */
|
||||
let task = {
|
||||
childProcess: fork(path, [message.event.taskId], { stdio: 'inherit' }),
|
||||
id: message.event.taskId,
|
||||
name: message.event.taskName
|
||||
}
|
||||
|
||||
tasks.set(message.event.taskId, task)
|
||||
|
||||
task.childProcess.on('error', (err) => {
|
||||
console.log('[ERROR] BackendServers -> Task Manager Server -> runTask -> Problem with Task Name = ' + task.name)
|
||||
console.log('[ERROR] BackendServers -> Task Manager Server -> runTask -> Problem with Task Id = ' + task.id)
|
||||
console.log(`[ERROR] BackendServers -> Task Manager Server -> runTask -> Task Manager exited with error ${err}`)
|
||||
})
|
||||
task.childProcess.on('close', (code, signal) => {
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Terminated. -> Task Name = ' + task.name)
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Terminated. -> Task Id = ' + task.id)
|
||||
tasks.delete(task.id)
|
||||
})
|
||||
|
||||
eventsServerClient.listenToEvent('Task Manager - ' + message.event.taskId, 'Nodejs Process Ready for Task', undefined, undefined, undefined, sendStartingEvent)
|
||||
|
||||
function sendStartingEvent() {
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Emitting Event -> key = ' + 'Task Server - ' + task.id)
|
||||
eventsServerClient.raiseEvent('Task Server - ' + task.id, 'Run Task', message.event)
|
||||
}
|
||||
}
|
||||
|
||||
function stopTask(message) {
|
||||
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Entering function.')
|
||||
|
||||
if (message.event === undefined) {
|
||||
console.log('[WARN] BackendServers -> Task Manager Server -> stopTask -> Message Received Without Event -> message = ' + JSON.stringify(message).substring(0, 1000))
|
||||
return
|
||||
}
|
||||
|
||||
if (message.event.taskId === undefined) {
|
||||
console.log('[WARN] BackendServers -> Task Manager Server -> stopTask -> Message Received Without taskId -> message = ' + JSON.stringify(message).substring(0, 1000))
|
||||
return
|
||||
}
|
||||
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Task Name = ' + message.event.taskName)
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Task Id = ' + message.event.taskId)
|
||||
|
||||
let task = tasks.get(message.event.taskId)
|
||||
|
||||
if (task) {
|
||||
task.childProcess.send('Stop this Task');
|
||||
//console.log('[INFO] BackendServers -> Task Manager Server -> stopTask -> Child Process instructed to finish.')
|
||||
} else {
|
||||
console.log('[WARN] BackendServers -> Task Manager Server -> stopTask -> Cannot delete Task that does not exist.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function newEventsServerClient() {
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
createEventHandler: createEventHandler,
|
||||
deleteEventHandler: deleteEventHandler,
|
||||
listenToEvent: listenToEvent,
|
||||
stopListening: stopListening,
|
||||
raiseEvent: raiseEvent,
|
||||
onMessage: onMessage
|
||||
}
|
||||
|
||||
let eventListeners = new Map()
|
||||
let responseWaiters = new Map()
|
||||
|
||||
return thisObject
|
||||
|
||||
|
||||
function finalize() {
|
||||
/* Before disconnecting we will forze all eventListeners to stop listening. */
|
||||
const eventListenersArray = [...eventListeners.values()]
|
||||
for (let i = 0; i < eventListenersArray.length; i++) {
|
||||
let handler = eventListenersArray[i]
|
||||
let eventCommand = {
|
||||
action: 'stopListening',
|
||||
eventHandlerName: handler.eventHandlerName,
|
||||
eventType: handler.eventType,
|
||||
callerId: handler.callerId
|
||||
}
|
||||
sendCommand(eventCommand)
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
}
|
||||
|
||||
function onMessage(data) {
|
||||
try {
|
||||
let message = JSON.parse(data)
|
||||
|
||||
if (message.action === 'Event Raised') {
|
||||
let key
|
||||
if (message.callerId) {
|
||||
key = message.eventHandlerName + '-' + message.eventType + '-' + message.callerId
|
||||
} else {
|
||||
key = message.eventHandlerName + '-' + message.eventType
|
||||
}
|
||||
let handler = eventListeners.get(key)
|
||||
if (handler) {
|
||||
handler.callBack(message)
|
||||
} else {
|
||||
console.log(key + ' not found so could not deliver event raised.')
|
||||
console.log(' Message = ' + data)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (message.action === 'Event Server Response') {
|
||||
let handler = responseWaiters.get(message.callerId)
|
||||
if (handler) {
|
||||
handler(message)
|
||||
}
|
||||
return
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[ERROR] BackendServers -> Task Manager Server -> onMessage -> Error Receiving Message from Events Server -> data = ' + JSON.stringify(data))
|
||||
console.log('[ERROR] BackendServers -> Task Manager Server -> onMessage -> Error Receiving Message from Events Server -> error = ' + err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function sendCommand(command, responseCallBack, eventsCallBack) {
|
||||
try {
|
||||
if (command.action === 'listenToEvent') {
|
||||
let key
|
||||
if (command.callerId) {
|
||||
key = command.eventHandlerName + '-' + command.eventType + '-' + command.callerId
|
||||
} else {
|
||||
key = command.eventHandlerName + '-' + command.eventType
|
||||
}
|
||||
let handler = {
|
||||
eventHandlerName: command.eventHandlerName,
|
||||
eventType: command.eventType,
|
||||
callerId: command.callerId,
|
||||
callBack: eventsCallBack
|
||||
}
|
||||
eventListeners.set(key, handler)
|
||||
}
|
||||
if (command.callerId && responseCallBack) {
|
||||
responseWaiters.set(command.callerId, responseCallBack)
|
||||
}
|
||||
|
||||
EVENTS_SERVER.onMessage(JSON.stringify(command), thisObject.onMessage)
|
||||
} catch (err) {
|
||||
console.log('[ERROR] BackendServers -> Task Manager Server -> sendCommand -> Error Sending Command to Events Server -> command = ' + JSON.stringify(command))
|
||||
console.log('[ERROR] BackendServers -> Task Manager Server -> sendCommand -> Error Sending Command to Events Server -> error = ' + err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function createEventHandler(eventHandlerName, callerId, responseCallBack) {
|
||||
let eventCommand = {
|
||||
action: 'createEventHandler',
|
||||
eventHandlerName: eventHandlerName,
|
||||
callerId: callerId
|
||||
}
|
||||
sendCommand(eventCommand, responseCallBack)
|
||||
}
|
||||
|
||||
function deleteEventHandler(eventHandlerName, callerId, responseCallBack) {
|
||||
let eventCommand = {
|
||||
action: 'deleteEventHandler',
|
||||
eventHandlerName: eventHandlerName,
|
||||
callerId: callerId
|
||||
}
|
||||
sendCommand(eventCommand, responseCallBack)
|
||||
}
|
||||
|
||||
function listenToEvent(eventHandlerName, eventType, extraData, callerId, responseCallBack, eventsCallBack) {
|
||||
let eventCommand = {
|
||||
action: 'listenToEvent',
|
||||
eventHandlerName: eventHandlerName,
|
||||
eventType: eventType,
|
||||
extraData: extraData,
|
||||
callerId: callerId
|
||||
}
|
||||
sendCommand(eventCommand, responseCallBack, eventsCallBack)
|
||||
}
|
||||
|
||||
function stopListening(eventHandlerName, eventType, eventSubscriptionId, callerId, responseCallBack) {
|
||||
/* User either needs to specify a valid eventSubscriptionId OR the 3 params: eventHandlerName, eventType, callerId which were used when start listening to events. */
|
||||
let eventCommand = {
|
||||
action: 'stopListening',
|
||||
eventHandlerName: eventHandlerName,
|
||||
eventType: eventType,
|
||||
eventSubscriptionId: eventSubscriptionId,
|
||||
callerId: callerId
|
||||
}
|
||||
sendCommand(eventCommand, responseCallBack)
|
||||
}
|
||||
|
||||
function raiseEvent(eventHandlerName, eventType, event, callerId, responseCallBack) {
|
||||
let eventCommand = {
|
||||
action: 'raiseEvent',
|
||||
eventHandlerName: eventHandlerName,
|
||||
eventType: eventType,
|
||||
event: event,
|
||||
callerId: callerId
|
||||
}
|
||||
sendCommand(eventCommand, responseCallBack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,654 +0,0 @@
|
||||
exports.newWebServer = function newWebServer(EVENTS_SERVER) {
|
||||
|
||||
const MODULE = "Web Server"
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
run: run
|
||||
}
|
||||
|
||||
require('dotenv').config()
|
||||
const open = require('open')
|
||||
|
||||
CONSOLE_LOG = process.env.CONSOLE_LOG === 'true'
|
||||
CONSOLE_ERROR_LOG = process.env.CONSOLE_ERROR_LOG === 'true'
|
||||
LOG_FILE_CONTENT = process.env.LOG_FILE_CONTENT === 'true'
|
||||
|
||||
let port = process.env.WEB_SERVER_PORT
|
||||
|
||||
let http = require('http')
|
||||
let isHttpServerStarted = false
|
||||
let cloneExecutorChildProcess
|
||||
let webhook = new Map()
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
}
|
||||
|
||||
function run() {
|
||||
startHtttpServer()
|
||||
}
|
||||
|
||||
function startHtttpServer() {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> startHtttpServer -> Entering function.') }
|
||||
|
||||
try {
|
||||
if (isHttpServerStarted === false) {
|
||||
gWebServer = http.createServer(onBrowserRequest).listen(port)
|
||||
isHttpServerStarted = true
|
||||
open('http://localhost:' + port)
|
||||
console.log('Web Server Started.')
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[ERROR] webServer -> startHtttpServer -> Error = ' + err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function onBrowserRequest(request, response) {
|
||||
if (CONSOLE_LOG === true && request.url.indexOf('NO-LOG') === -1) { console.log('[INFO] webServer -> onBrowserRequest -> request.url = ' + request.url) }
|
||||
|
||||
function getBody(callback) { // Gets the de body from a POST request to the web server
|
||||
let body = ''
|
||||
|
||||
request.on('data', function (data) {
|
||||
body += data
|
||||
// Too much POST data
|
||||
if (body.length > 1e6) {
|
||||
request.connection.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
request.on('end', function () {
|
||||
callback(body)
|
||||
})
|
||||
}
|
||||
|
||||
let requestParameters = request.url.split('/')
|
||||
|
||||
if (requestParameters[1].indexOf('index.html') >= 0) {
|
||||
/*
|
||||
We use this to solve the problem when someone is arriving to the site with a sessionToken in the queryString. We extract here that
|
||||
token, that will be sent later embedded into the HTML code, so that it can enter into the stardard circuit where any site can put
|
||||
the sessionToken into their HTML code and from there the Browser app will log the user in.
|
||||
*/
|
||||
|
||||
let queryString = requestParameters[1].split('?')
|
||||
|
||||
requestParameters[1] = ''
|
||||
requestParameters[2] = queryString[1]
|
||||
homePage()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
requestParameters = request.url.split('?') // Remove version information
|
||||
requestParameters = requestParameters[0].split('/')
|
||||
|
||||
switch (requestParameters[1]) {
|
||||
|
||||
case 'CCXT':
|
||||
{
|
||||
getBody(processRequest)
|
||||
|
||||
async function processRequest(body) {
|
||||
try {
|
||||
let params = JSON.parse(body)
|
||||
|
||||
const ccxt = require('ccxt')
|
||||
|
||||
switch (params.method) {
|
||||
case 'fetchMarkets': {
|
||||
|
||||
const exchangeClass = ccxt[params.exchangeId]
|
||||
const exchangeConstructorParams = {
|
||||
'timeout': 30000,
|
||||
'enableRateLimit': true,
|
||||
verbose: false
|
||||
}
|
||||
|
||||
let ccxtExchange = new exchangeClass(exchangeConstructorParams)
|
||||
let ccxtMarkets = []
|
||||
|
||||
if (ccxtExchange.has.fetchMarkets === true) {
|
||||
ccxtMarkets = await ccxtExchange.fetchMarkets()
|
||||
}
|
||||
respondWithContent(JSON.stringify(ccxtMarkets), response)
|
||||
return
|
||||
}
|
||||
case 'listExchanges': {
|
||||
let exchanges = []
|
||||
for (let i = 0; i < ccxt.exchanges.length; i++) {
|
||||
let exchangeId = ccxt.exchanges[i]
|
||||
|
||||
const exchangeClass = ccxt[exchangeId]
|
||||
const exchangeConstructorParams = {
|
||||
'timeout': 30000,
|
||||
'enableRateLimit': true,
|
||||
verbose: false
|
||||
}
|
||||
let ccxtExchange
|
||||
try { ccxtExchange = new exchangeClass(exchangeConstructorParams) }
|
||||
catch (err) { }
|
||||
if (ccxtExchange === undefined) { continue }
|
||||
|
||||
|
||||
if (ccxtExchange.has.fetchOHLCV === params.has.fetchOHLCV) {
|
||||
if (ccxtExchange.has.fetchMarkets === params.has.fetchMarkets) {
|
||||
if (ccxtExchange.timeframes['1m'] !== undefined) {
|
||||
let exchange = {
|
||||
name: ccxtExchange.name,
|
||||
id: ccxtExchange.id
|
||||
}
|
||||
exchanges.push(exchange)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
respondWithContent(JSON.stringify(exchanges), response)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let content = {
|
||||
err: global.DEFAULT_FAIL_RESPONSE // method not supported
|
||||
}
|
||||
} catch (err) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> CCXT FetchMarkets -> Could not fetch markets.') }
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message
|
||||
}
|
||||
respondWithContent(JSON.stringify(error), response)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'Webhook': {
|
||||
switch (requestParameters[2]) { // switch by command
|
||||
case 'Fetch-Messages': {
|
||||
let exchange = requestParameters[3]
|
||||
let market = requestParameters[4]
|
||||
|
||||
/* Some validations */
|
||||
if (exchange === undefined) {
|
||||
console.log('[WARN] webServer -> Webhook -> Fetch-Messages -> Message with no Exchange received -> messageReceived = ' + messageReceived)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response)
|
||||
return
|
||||
}
|
||||
if (market === undefined) {
|
||||
console.log('[WARN] webServer -> Webhook -> Fetch-Messages -> Message with no market received -> messageReceived = ' + messageReceived)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response)
|
||||
return
|
||||
}
|
||||
|
||||
let key = exchange + '-' + market
|
||||
|
||||
let webhookMessages = webhook.get(key)
|
||||
if (webhookMessages === undefined) {
|
||||
webhookMessages = []
|
||||
}
|
||||
|
||||
respondWithContent(JSON.stringify(webhookMessages), response)
|
||||
webhookMessages = []
|
||||
|
||||
webhook.set(key, webhookMessages)
|
||||
break
|
||||
}
|
||||
case 'New-Message': {
|
||||
getBody(processRequest)
|
||||
|
||||
function processRequest(messageReceived) {
|
||||
let timestamp = (new Date()).valueOf()
|
||||
let source = requestParameters[3]
|
||||
let exchange = requestParameters[4]
|
||||
let market = requestParameters[5]
|
||||
|
||||
/* Some validations */
|
||||
if (source === undefined) {
|
||||
console.log('[WARN] webServer -> Webhook -> New-Message -> Message with no Source received -> messageReceived = ' + messageReceived)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response)
|
||||
return
|
||||
}
|
||||
if (exchange === undefined) {
|
||||
console.log('[WARN] webServer -> Webhook -> New-Message -> Message with no Exchange received -> messageReceived = ' + messageReceived)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response)
|
||||
return
|
||||
}
|
||||
if (market === undefined) {
|
||||
console.log('[WARN] webServer -> Webhook -> New-Message -> Message with no market received -> messageReceived = ' + messageReceived)
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_FAIL_RESPONSE), response)
|
||||
return
|
||||
}
|
||||
|
||||
let key = exchange + '-' + market
|
||||
|
||||
let webhookMessages = webhook.get(key)
|
||||
if (webhookMessages === undefined) {
|
||||
webhookMessages = []
|
||||
}
|
||||
|
||||
webhookMessages.push([timestamp, source, messageReceived])
|
||||
webhook.set(key, webhookMessages)
|
||||
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_OK_RESPONSE), response)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
case 'ResetLogsAndData':
|
||||
{
|
||||
try {
|
||||
let rimraf = require('rimraf')
|
||||
rimraf.sync(process.env.STORAGE_PATH + '/Masters/Masters/AAJason.1.0')
|
||||
rimraf.sync(process.env.LOG_PATH)
|
||||
|
||||
respondWithContent(JSON.stringify(global.DEFAULT_OK_RESPONSE), response)
|
||||
} catch (err) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> ResetLogsAndData -> Could not delete Logs and Data.') }
|
||||
let error = {
|
||||
result: 'Fail Because',
|
||||
message: err.message
|
||||
}
|
||||
respondWithContent(JSON.stringify(error), response)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'LegacyPlotter.js':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_WEB_SERVER + 'WebServer/LegacyPlotter.js', response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'PlotterPanel.js':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_WEB_SERVER + 'WebServer/PlotterPanel.js', response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Images': // This means the Images folder.
|
||||
{
|
||||
let path = process.env.PATH_TO_WEB_SERVER + 'WebServer/Images/' + requestParameters[2]
|
||||
|
||||
if (requestParameters[3] !== undefined) {
|
||||
path = path + '/' + requestParameters[3]
|
||||
}
|
||||
|
||||
if (requestParameters[4] !== undefined) {
|
||||
path = path + '/' + requestParameters[4]
|
||||
}
|
||||
|
||||
if (requestParameters[5] !== undefined) {
|
||||
path = path + '/' + requestParameters[5]
|
||||
}
|
||||
|
||||
path = unescape(path)
|
||||
|
||||
respondWithImage(path, response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'favicon.ico': // This means the Scripts folder.
|
||||
{
|
||||
respondWithImage(process.env.PATH_TO_WEB_SERVER + 'WebServer/Images/' + 'favicon.ico', response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'CockpitSpace': // This means the CockpitSpace folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/CockpitSpace/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'TopSpace': // This means the TopSpace folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/TopSpace/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'DesignSpace': // This means the DesignSpace folder.
|
||||
|
||||
{
|
||||
if (requestParameters[3] === undefined) {
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/DesignSpace/' + requestParameters[2], response)
|
||||
return
|
||||
}
|
||||
if (requestParameters[4] === undefined) {
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/DesignSpace/' + requestParameters[2] + '/' + requestParameters[3], response)
|
||||
return
|
||||
}
|
||||
if (requestParameters[5] === undefined) {
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/DesignSpace/' + requestParameters[2] + '/' + requestParameters[3] + '/' + requestParameters[4], response)
|
||||
return
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case 'ControlsToolBox': // This means the DesignSpace folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/ControlsToolBox/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Utilities': // This means the DesignSpace folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/Utilities/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'WebServer': // This means the WebServer folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_WEB_SERVER + 'WebServer/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'externalScripts': // This means the WebServer folder.
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_WEB_SERVER + 'WebServer/externalScripts/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Plotters': // This means the plotter folder, not to be confused with the Plotters script!
|
||||
{
|
||||
let dataMine = requestParameters[2]
|
||||
let codeName = requestParameters[3]
|
||||
let moduleName = requestParameters[4]
|
||||
let filePath = process.env.PLOTTERS_PATH + '/' + dataMine + '/plotters/' + codeName + '/' + moduleName
|
||||
respondWithFile(filePath, response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'PlotterPanels': // This means the PlotterPanels folder, not to be confused with the Plotter Panels scripts!
|
||||
{
|
||||
let dataMine = requestParameters[2]
|
||||
let codeName = requestParameters[3]
|
||||
let moduleName = requestParameters[4]
|
||||
let filePath = process.env.PLOTTERS_PATH + '/' + dataMine + '/plotters/' + codeName + '/' + moduleName
|
||||
respondWithFile(filePath, response)
|
||||
}
|
||||
break
|
||||
case 'Panels':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/' + requestParameters[1] + '/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'ChartLayers':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/' + requestParameters[1] + '/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Spaces':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/' + requestParameters[1] + '/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Scales':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/' + requestParameters[1] + '/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Files':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_FILES_COMPONENT + '/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'FloatingSpace':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/' + requestParameters[1] + '/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'ChartingSpace':
|
||||
{
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/' + requestParameters[1] + '/' + requestParameters[2], response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'AppSchema.js':
|
||||
{
|
||||
let fs = require('fs')
|
||||
|
||||
try {
|
||||
let filePath = process.env.APP_SCHEMA_PATH + 'AppSchema.json'
|
||||
fs.readFile(filePath, onFileRead)
|
||||
} catch (e) {
|
||||
console.log('[ERROR] Error reading the App Schema.', e)
|
||||
}
|
||||
|
||||
function onFileRead(err, appSchema) {
|
||||
if (err) {
|
||||
respondWithContent(undefined, response)
|
||||
} else {
|
||||
let responseContent = 'function getAppSchema(){ return ' + appSchema + '}'
|
||||
respondWithContent(responseContent, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case 'Workspace.js':
|
||||
{
|
||||
let fs = require('fs')
|
||||
|
||||
try {
|
||||
let filePath = process.env.WORKSPACE_PATH + 'Workspace.json'
|
||||
fs.readFile(filePath, onFileRead)
|
||||
} catch (e) {
|
||||
console.log('[ERROR] Error reading the Workspace.', e)
|
||||
}
|
||||
|
||||
function onFileRead(err, workspace) {
|
||||
if (err) {
|
||||
respondWithContent(undefined, response)
|
||||
} else {
|
||||
let responseContent = 'function getWorkspace(){ return ' + workspace + '}'
|
||||
respondWithContent(responseContent, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case 'DataMines':
|
||||
{
|
||||
respondWithFile(process.env.DATA_MINES_PATH + '/' + requestParameters[2] + '.json', response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'TradingSystems':
|
||||
{
|
||||
respondWithFile(process.env.TRADING_SYSTEMS_PATH + '/' + requestParameters[2] + '.json', response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'SuperScripts':
|
||||
{
|
||||
respondWithFile(process.env.SUPER_SCRIPTS_PATH + '/' + requestParameters[2] + '.json', response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Storage':
|
||||
{
|
||||
respondWithFile(process.env.STORAGE_PATH + '/' + request.url.substring(9), response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'GetDefinition':
|
||||
{
|
||||
respondWithFile(process.env.INTER_PROCESS_FILES_PATH + '/definition.json', response)
|
||||
}
|
||||
break
|
||||
|
||||
case 'SaveDefinition':
|
||||
{
|
||||
let fs = require('fs')
|
||||
let body = ''
|
||||
|
||||
request.on('data', function (data) {
|
||||
body += data
|
||||
// Too much POST data
|
||||
if (body.length > 1e6) {
|
||||
request.connection.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
request.on('end', function () {
|
||||
try {
|
||||
let filePath = process.env.INTER_PROCESS_FILES_PATH + '/definition.json'
|
||||
fs.writeFile(filePath, body, onFileWrite)
|
||||
} catch (e) {
|
||||
console.log('[ERROR] Error writing user config.', e)
|
||||
respondWithContent(undefined, response)
|
||||
}
|
||||
|
||||
function onFileWrite(err) {
|
||||
if (err) {
|
||||
respondWithContent(undefined, response)
|
||||
} else {
|
||||
let responseContent = 'User config updated.'
|
||||
respondWithContent(responseContent, response)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
{
|
||||
homePage()
|
||||
}
|
||||
}
|
||||
|
||||
function homePage() {
|
||||
if (requestParameters[1] === '') {
|
||||
let fs = require('fs')
|
||||
try {
|
||||
let fileName = process.env.PATH_TO_WEB_SERVER + 'WebServer/index.html'
|
||||
fs.readFile(fileName, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> onBrowserRequest -> onFileRead -> Entering function.') }
|
||||
|
||||
try {
|
||||
let fileContent = file.toString()
|
||||
|
||||
fileContent = fileContent.replace('WEB_SERVER_PORT', process.env.WEB_SERVER_PORT)
|
||||
respondWithContent(fileContent, response)
|
||||
} catch (err) {
|
||||
console.log('[ERROR] webServer -> onBrowserRequest -> File Not Found: ' + fileName + ' or Error = ' + err.stack)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
} else {
|
||||
respondWithFile(process.env.PATH_TO_CANVAS_APP + '/' + requestParameters[1], response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function respondWithFile(fileName, response) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> respondWithFile -> Entering function.') }
|
||||
|
||||
let fs = require('fs')
|
||||
if (fileName.indexOf('undefined') > 0) {
|
||||
console.log('[WRN] webServer -> respondWithFile -> Received request for undefined file. ')
|
||||
respondWithContent(undefined, response)
|
||||
} else {
|
||||
try {
|
||||
fs.readFile(fileName, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> respondWithFile -> onFileRead -> Entering function.') }
|
||||
if (!err) {
|
||||
respondWithContent(file.toString(), response)
|
||||
} else {
|
||||
respondWithContent(undefined, response)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
returnEmptyArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function respondWithContent(content, response) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> respondWithContent -> Entering function.') }
|
||||
|
||||
try {
|
||||
response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate') // HTTP 1.1.
|
||||
response.setHeader('Pragma', 'no-cache') // HTTP 1.0.
|
||||
response.setHeader('Expires', '0') // Proxies.
|
||||
response.setHeader('Access-Control-Allow-Origin', '*') // Allows to access data from other domains.
|
||||
|
||||
if (content !== undefined) {
|
||||
response.writeHead(200, { 'Content-Type': 'text/html' })
|
||||
response.write(content)
|
||||
} else {
|
||||
response.writeHead(404, { 'Content-Type': 'text/html' })
|
||||
response.write('The specified key does not exist.')
|
||||
}
|
||||
response.end('\n')
|
||||
} catch (err) {
|
||||
returnEmptyArray(response)
|
||||
}
|
||||
}
|
||||
|
||||
function respondWithImage(fileName, response) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> respondWithImage -> Entering function.') }
|
||||
|
||||
let fs = require('fs')
|
||||
try {
|
||||
fs.readFile(fileName, onFileRead)
|
||||
|
||||
function onFileRead(err, file) {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> respondWithImage -> onFileRead -> Entering function.') }
|
||||
|
||||
try {
|
||||
response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate') // HTTP 1.1.
|
||||
response.setHeader('Pragma', 'no-cache') // HTTP 1.0.
|
||||
response.setHeader('Expires', '0') // Proxies.
|
||||
response.setHeader('Access-Control-Allow-Origin', '*') // Allows to access data from other domains.
|
||||
|
||||
response.writeHead(200, { 'Content-Type': 'image/png' })
|
||||
response.end(file, 'binary')
|
||||
} catch (err) {
|
||||
console.log('[ERROR] webServer -> respondWithImage -> onFileRead -> File Not Found: ' + fileName + ' or Error = ' + err.stack)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[ERROR] webServer -> respondWithImage -> err = ' + err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function returnEmptyArray(response) {
|
||||
try {
|
||||
if (CONSOLE_LOG === true) { console.log('[INFO] webServer -> respondWithFile -> returnEmptyArray -> Entering function.') }
|
||||
|
||||
response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate') // HTTP 1.1.
|
||||
response.setHeader('Pragma', 'no-cache') // HTTP 1.0.
|
||||
response.setHeader('Expires', '0') // Proxies.
|
||||
|
||||
response.writeHead(200, { 'Content-Type': 'text/html' })
|
||||
response.write('[]')
|
||||
response.end('\n')
|
||||
} catch (err) {
|
||||
console.log('[ERROR] webServer -> returnEmptyArray -> err.message ' + err.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
exports.newWebSocketsServer = function newWebSocketsServer(EVENTS_SERVER) {
|
||||
|
||||
const MODULE = "Web Sockets Server"
|
||||
const LOG_INFO = false
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
run: run
|
||||
}
|
||||
|
||||
require('dotenv').config()
|
||||
const WEB_SOCKET = require('ws')
|
||||
let socketServer
|
||||
let port = process.env.WEB_SOCKETS_SERVER_PORT
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize() {
|
||||
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
}
|
||||
|
||||
function run() {
|
||||
setUpWebSocketServer()
|
||||
}
|
||||
|
||||
function setUpWebSocketServer() {
|
||||
try {
|
||||
socketServer = new WEB_SOCKET.Server({ port: port })
|
||||
|
||||
socketServer.on('connection', onConnection)
|
||||
|
||||
function onConnection(socket) {
|
||||
|
||||
let lastNonce = -1
|
||||
if (LOG_INFO === true) {
|
||||
console.log('New Websocket Connection.')
|
||||
}
|
||||
|
||||
socket.on('message', onMenssage)
|
||||
|
||||
function onMenssage(message){
|
||||
|
||||
try {
|
||||
if (LOG_INFO === true) {
|
||||
console.log('Message Received: ' + message.substring(0, 1000))
|
||||
}
|
||||
|
||||
let messageArray = message.split('|*|')
|
||||
|
||||
let origin = messageArray[0]
|
||||
let nonce = messageArray[1]
|
||||
let messageToEventServer = messageArray[2]
|
||||
|
||||
if (origin === 'Web Browser') {
|
||||
if (isNaN(nonce) || nonce === "") {
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce is not a Number. message = ' + message.substring(0, 1000))
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce is not a Number. nonce = ' + nonce)
|
||||
return
|
||||
}
|
||||
|
||||
if (nonce === "1") { // this happens once the browser is restarted, and the server is running since a previous session.
|
||||
lastNonce = 0
|
||||
}
|
||||
|
||||
if (Number(nonce) < Number(lastNonce)) {
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. message = ' + message.substring(0, 1000))
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. nonce = ' + nonce)
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. lastNonce = ' + lastNonce)
|
||||
return
|
||||
}
|
||||
|
||||
lastNonce = nonce
|
||||
|
||||
try {
|
||||
let jsonCheck = JSON.parse(messageToEventServer)
|
||||
} catch (err) {
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Message received from the browser is not a valid JSON. message = ' + message.substring(0, 1000))
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Message received from the browser is not a valid JSON. messageToEventServer = ' + messageToEventServer)
|
||||
return
|
||||
}
|
||||
|
||||
let acknowledgeMessage = {
|
||||
action: 'Acknowledge',
|
||||
nonce: nonce
|
||||
}
|
||||
|
||||
socket.send(JSON.stringify(acknowledgeMessage))
|
||||
}
|
||||
|
||||
|
||||
EVENTS_SERVER.onMessage(messageToEventServer, onResponse)
|
||||
|
||||
function onResponse(message) {
|
||||
socket.send(message)
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> Nonce received is less than Last Nonce. err = ' + err.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Web Sockets Server Started.')
|
||||
} catch (err) {
|
||||
console.log('[ERROR] BackendServers -> Web Sockets Server -> run -> setUpWebSocketServer -> err.message = ' + err.message.substring(0, 1000))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,7 @@
|
||||
# Contributing
|
||||
|
||||
We are thrilled you are interested in contributing to this project. Your help may be essential to the project's success and we want you in!
|
||||
We are thrilled you are interested in contributing to Superalgos. Your help may be essential to the project's success and we want you in!
|
||||
|
||||
Superalgos is a collective project, currently at a very early stage. We not only welcome contributions but may even choose to incentivize relevant contributions via the project's native crypto token, to be deployed in the near future.
|
||||
[There is something you may do](https://docs.superalgos.org/contributing-to-superalgos.html) to help the project grow regardless of what your skill set may be.
|
||||
|
||||
|
||||
|
||||
Contributions are deemed _voluntary work_, irrespective of the incentives that may be in place, and are subject to the conditions described in the software [LICENSE](LICENSE).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First step is to fork this repository and start using the app. The repository includes all source code which constitutes your development environment. The app runs uncompilled on the actual code.
|
||||
|
||||
* The priority at this moment is the stabilization of existing functionality. Your first contribution will be using, learning, and testing the app, and reporting any bugs you may find.
|
||||
|
||||
* You may debug and remove bugs yourself, and submit pull requests.
|
||||
|
||||
* Another top priority is building a robust base of indicators and technical studies. This is done from the UI, using the functionality managed by data mines.
|
||||
|
||||
As you engage with other developers and the Core Team, we will get to know you and develop a relationship, so that you may later participate in core development tasks.
|
||||
|
||||
Please join the [Superalgos Develop](https://t.me/superalgosdevelop) Telegram group, let us know about your progress and ask any questions you may have. Feel free to let us know about yourself and your personal interests.
|
||||
Thank you!
|
||||
@@ -1,174 +0,0 @@
|
||||
|
||||
function newAnimation () {
|
||||
const MODULE_NAME = 'Animation'
|
||||
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,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
let totalConsumption = 0
|
||||
let totalCounter = 0
|
||||
let pointerIcon
|
||||
let videoRecorder
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
thisObject.stop()
|
||||
pointerIcon = undefined
|
||||
videoRecorder = undefined
|
||||
}
|
||||
|
||||
function initialize () {
|
||||
videoRecorder = newVideoRecorder()
|
||||
}
|
||||
|
||||
function start () {
|
||||
animationLoop() // Inside this function the animation process is started, and at the same time it creates a loop.
|
||||
}
|
||||
|
||||
function stop () {
|
||||
window.cancelAnimationFrame(animationLoopHandle)
|
||||
}
|
||||
|
||||
function addCallBackFunction (key, callBack) {
|
||||
callBackFunctions.set(key, callBack)
|
||||
}
|
||||
|
||||
function removeCallBackFunction (key) {
|
||||
callBackFunctions.delete(key)
|
||||
}
|
||||
|
||||
function animationLoop () {
|
||||
try {
|
||||
if (window.canvasApp.visible === true) {
|
||||
/* We set the canvas to its normal width and height */
|
||||
// browserCanvas.width = window.innerWidth
|
||||
// browserCanvas.height = window.innerHeight - CURRENT_TOP_MARGIN
|
||||
|
||||
/* First thing is to clear the actual canvas */
|
||||
clearBrowserCanvas()
|
||||
|
||||
/* We loop through the callback functions collections and execute them all. */
|
||||
let performanceMap = new Map()
|
||||
let totalTimeConsumed = 0
|
||||
let totalElements = 0
|
||||
let chanceToExecute
|
||||
let randomNumber
|
||||
let mustExecute
|
||||
|
||||
// console.clear()
|
||||
let row = 0
|
||||
for (const [key, callBackFunction] of callBackFunctions.entries()) {
|
||||
row++
|
||||
switch (key) {
|
||||
case 'Floating Space Physics':
|
||||
chanceToExecute = 50
|
||||
randomNumber = Math.random() * 100 * chanceToExecute
|
||||
if (randomNumber > 100 - chanceToExecute) { mustExecute = true } else { mustExecute = false }
|
||||
break
|
||||
default: {
|
||||
mustExecute = true
|
||||
}
|
||||
|
||||
}
|
||||
let timeConsumed = 0
|
||||
if (mustExecute === true) {
|
||||
let t0 = performance.now()
|
||||
callBackFunction()
|
||||
let t1 = performance.now()
|
||||
timeConsumed = t1 - t0
|
||||
if (key === 'Charting Space Draw') {
|
||||
if (Math.random() * 100 > 99) {
|
||||
totalConsumption = 0
|
||||
totalCounter = 0
|
||||
}
|
||||
|
||||
totalConsumption = totalConsumption + timeConsumed
|
||||
totalCounter = totalCounter + 1
|
||||
}
|
||||
performanceMap.set(key, timeConsumed)
|
||||
totalTimeConsumed = totalTimeConsumed + timeConsumed
|
||||
totalElements++
|
||||
}
|
||||
}
|
||||
|
||||
/* Frame per Seconds */
|
||||
|
||||
ANIMATION_FRAME_PER_SECONDS = Math.trunc(1000 / totalTimeConsumed)
|
||||
|
||||
/* Performance Check */
|
||||
if (SHOW_ANIMATION_PERFORMACE === true) {
|
||||
row = 0
|
||||
for (const [key, timeConsumed] of performanceMap.entries()) {
|
||||
row++
|
||||
labelToPrint = key + ' ' + timeConsumed.toFixed(4)
|
||||
printLabel(labelToPrint, 10, 100 + row * 30, 1, 20, UI_COLOR.RED)
|
||||
let percentage = timeConsumed * 100 / totalTimeConsumed
|
||||
labelToPrint = key + ' ' + percentage.toFixed(1) + '%'
|
||||
printLabel(labelToPrint, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
|
||||
}
|
||||
|
||||
/* Other Variables */
|
||||
row++
|
||||
printLabel(DEBUG.variable1, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
|
||||
row++
|
||||
printLabel(DEBUG.variable2, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
|
||||
row++
|
||||
printLabel(DEBUG.variable3, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
|
||||
row++
|
||||
printLabel(DEBUG.variable4, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
|
||||
row++
|
||||
printLabel('Animation Frame Per Seconds: ' + ANIMATION_FRAME_PER_SECONDS, 300, 100 + row * 30, 1, 20, UI_COLOR.TITANIUM_YELLOW)
|
||||
}
|
||||
} else {
|
||||
browserCanvas.width = 1
|
||||
browserCanvas.height = 1
|
||||
}
|
||||
|
||||
/* Media Recording */
|
||||
videoRecorder.physics()
|
||||
if (areWeRecording === true) {
|
||||
videoRecorder.recordCanvas()
|
||||
}
|
||||
|
||||
/* We request the next frame to be drawn, and stablishing a loop */
|
||||
|
||||
/* Use this code for full animation speed. */
|
||||
animationLoopHandle = window.requestAnimationFrame(animationLoop)
|
||||
|
||||
/* Use this code for max 10 frames per second animation speed, if the app is consumming too much of your CPU. */
|
||||
/*
|
||||
setTimeout(nextLoop, 100)
|
||||
function nextLoop () {
|
||||
animationLoopHandle = window.requestAnimationFrame(animationLoop)
|
||||
}
|
||||
*/
|
||||
} catch (err) {
|
||||
if (ERROR_LOG === true) { logger.write('[ERROR] animationLoop -> err = ' + err.stack) }
|
||||
}
|
||||
}
|
||||
|
||||
function clearBrowserCanvas () {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
|
||||
browserCanvasContext.clearRect(0, 0, browserCanvas.width, browserCanvas.height)
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
|
||||
function getSideDays (timeFrame) {
|
||||
let daysOnSides
|
||||
|
||||
if (timeFrame < _1_HOUR_IN_MILISECONDS) {
|
||||
daysOnSides = 1
|
||||
}
|
||||
|
||||
if (timeFrame === _1_HOUR_IN_MILISECONDS) {
|
||||
daysOnSides = 9
|
||||
}
|
||||
|
||||
if (timeFrame === _2_HOURS_IN_MILISECONDS) {
|
||||
daysOnSides = 10
|
||||
}
|
||||
|
||||
if (timeFrame === _3_HOURS_IN_MILISECONDS) {
|
||||
daysOnSides = 12
|
||||
}
|
||||
|
||||
if (timeFrame === _4_HOURS_IN_MILISECONDS) {
|
||||
daysOnSides = 20
|
||||
}
|
||||
|
||||
if (timeFrame === _6_HOURS_IN_MILISECONDS) {
|
||||
daysOnSides = 35
|
||||
}
|
||||
|
||||
if (timeFrame === _8_HOURS_IN_MILISECONDS) {
|
||||
daysOnSides = 44
|
||||
}
|
||||
|
||||
if (timeFrame === _12_HOURS_IN_MILISECONDS) {
|
||||
daysOnSides = 56
|
||||
}
|
||||
|
||||
if (timeFrame === ONE_DAY_IN_MILISECONDS) {
|
||||
daysOnSides = 154
|
||||
}
|
||||
|
||||
return daysOnSides
|
||||
}
|
||||
|
||||
function getCondenseFactor (timeFrame) {
|
||||
switch (timeFrame) {
|
||||
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 (timeFrame) {
|
||||
switch (timeFrame) {
|
||||
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('NEW ZOOM LEVEL', zoomLevel)
|
||||
if (zoomLevel > 400) {
|
||||
return _1_MINUTE_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 360) {
|
||||
return _2_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 330) {
|
||||
return _3_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 300) {
|
||||
return _4_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 270) {
|
||||
return _5_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 250) {
|
||||
return _10_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 230) {
|
||||
return _15_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 210) {
|
||||
return _20_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 190) {
|
||||
return _30_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 170) {
|
||||
return _40_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 150) {
|
||||
return _45_MINUTES_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 130) {
|
||||
return _1_HOUR_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 110) {
|
||||
return _2_HOURS_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 80) {
|
||||
return _3_HOURS_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 50) {
|
||||
return _4_HOURS_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 35) {
|
||||
return _6_HOURS_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 20) {
|
||||
return _8_HOURS_IN_MILISECONDS
|
||||
}
|
||||
|
||||
if (zoomLevel > 10) {
|
||||
return _12_HOURS_IN_MILISECONDS
|
||||
}
|
||||
|
||||
return ONE_DAY_IN_MILISECONDS
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
|
||||
This Object object is responsible for defining the coordinate system in a TimeLine.
|
||||
|
||||
The scale on the X axis depends on the time.
|
||||
The scale on the Y axis depends on the data that wants to be plotted. Usually we need the Max amount on that data to generate a proper scale.
|
||||
|
||||
*/
|
||||
|
||||
function newCoordinateSystem () {
|
||||
let thisObject = {
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
parentMin: undefined,
|
||||
parentMax: undefined,
|
||||
childrenMin: undefined,
|
||||
childrenMax: undefined,
|
||||
maxHeight: undefined,
|
||||
maxWidth: undefined,
|
||||
scale: undefined,
|
||||
eventHandler: undefined,
|
||||
autoMinXScale: true,
|
||||
autoMaxXScale: true,
|
||||
autoMinYScale: true,
|
||||
autoMaxYScale: true,
|
||||
HORIZONTAL_MARGIN_FACTOR: 0.80,
|
||||
VERTICAL_MARGIN_FACTOR: 0.90,
|
||||
HORIZONTAL_MARGIN_INVERSE_FACTOR: 0.20,
|
||||
VERTICAL_MARGIN_INVERSE_FACTOR: 0.10,
|
||||
physics: physics,
|
||||
reportParentXValue: reportParentXValue,
|
||||
reportParentYValue: reportParentYValue,
|
||||
reportXValue: reportXValue,
|
||||
reportYValue: reportYValue,
|
||||
zoomX: zoomX,
|
||||
zoomY: zoomY,
|
||||
recalculateScale: recalculateScale,
|
||||
transformThisPoint: transformThisPoint,
|
||||
transformThisPoint2: transformThisPoint2,
|
||||
unInverseTransform: unInverseTransform,
|
||||
inverseTransformUncappedY: inverseTransformUncappedY,
|
||||
initializeX: initializeX,
|
||||
initializeY: initializeY,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
thisObject.min = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
thisObject.max = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
thisObject.parentMin = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
thisObject.parentMax = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
thisObject.childrenMin = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
thisObject.childrenMax = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
thisObject.scale = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
thisObject.eventHandler = newEventHandler()
|
||||
thisObject.eventHandler.name = 'Coordinate System'
|
||||
|
||||
let newXMax = -VERY_LARGE_NUMBER
|
||||
let newXMin = VERY_LARGE_NUMBER
|
||||
|
||||
let newYMax = -VERY_LARGE_NUMBER
|
||||
let newYMin = VERY_LARGE_NUMBER
|
||||
|
||||
let parentMinChanged = false
|
||||
let parentMaxChanged = false
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
thisObject.eventHandler.finalize()
|
||||
thisObject.eventHandler = undefined
|
||||
}
|
||||
|
||||
function initialize (minValue, maxValue, pMaxWidth, pMaxHeight) {
|
||||
/* Defines the min and max value of rate that we are going to transport to the available screen at the center position. */
|
||||
thisObject.min.x = minValue.x
|
||||
thisObject.max.x = maxValue.x
|
||||
|
||||
thisObject.min.y = minValue.y
|
||||
thisObject.max.y = maxValue.y
|
||||
|
||||
thisObject.maxWidth = pMaxWidth
|
||||
thisObject.maxHeight = pMaxHeight
|
||||
|
||||
recalculateScale()
|
||||
}
|
||||
|
||||
function reportXValue (value) {
|
||||
if (thisObject.autoMinXScale === true) {
|
||||
if (value < newXMin && value !== 0) {
|
||||
newXMin = value
|
||||
}
|
||||
}
|
||||
if (thisObject.autoMaxXScale === true) {
|
||||
if (value > newXMax && value !== 0) {
|
||||
newXMax = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reportYValue (value) {
|
||||
if (thisObject.autoMinYScale === true) {
|
||||
if (value < newYMin) {
|
||||
newYMin = value
|
||||
}
|
||||
}
|
||||
if (thisObject.autoMaxYScale === true) {
|
||||
if (value > newYMax) {
|
||||
newYMax = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reportParentXValue (min, max) {
|
||||
if (thisObject.autoMinXScale === true) {
|
||||
if (thisObject.parentMin.x !== min) {
|
||||
thisObject.parentMin.x = min
|
||||
}
|
||||
}
|
||||
if (thisObject.autoMaxXScale === true) {
|
||||
if (thisObject.parentMax.x !== max) {
|
||||
thisObject.parentMax.x = max
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reportParentYValue (min, max) {
|
||||
if (thisObject.autoMinYScale === true) {
|
||||
if (thisObject.parentMin.y !== min) {
|
||||
thisObject.parentMin.y = min
|
||||
}
|
||||
}
|
||||
if (thisObject.autoMaxYScale === true) {
|
||||
if (thisObject.parentMax.y !== max) {
|
||||
thisObject.parentMax.y = max
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function physics () {
|
||||
let mustRecalculate = false
|
||||
|
||||
if ((thisObject.autoMinXScale === true || thisObject.autoMaxXScale === true)) {
|
||||
if (thisObject.autoMaxXScale === true && thisObject.childrenMax.x !== newXMax && newXMax !== -VERY_LARGE_NUMBER) {
|
||||
thisObject.childrenMax.x = newXMax
|
||||
}
|
||||
|
||||
if (thisObject.autoMaxXScale === true) {
|
||||
newXMax = -VERY_LARGE_NUMBER
|
||||
}
|
||||
|
||||
if (thisObject.autoMinXScale === true && thisObject.childrenMin.x !== newXMin && newXMin !== VERY_LARGE_NUMBER) {
|
||||
thisObject.childrenMin.x = newXMin
|
||||
newXMin = VERY_LARGE_NUMBER
|
||||
}
|
||||
|
||||
if (thisObject.autoMinXScale === true) {
|
||||
newXMin = VERY_LARGE_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
if ((thisObject.autoMinYScale === true || thisObject.autoMaxYScale === true)) {
|
||||
if (thisObject.autoMaxYScale === true && thisObject.childrenMax.y !== newYMax && newYMax !== -VERY_LARGE_NUMBER) {
|
||||
thisObject.childrenMax.y = newYMax
|
||||
}
|
||||
|
||||
if (thisObject.autoMaxYScale === true) {
|
||||
newYMax = -VERY_LARGE_NUMBER
|
||||
}
|
||||
|
||||
if (thisObject.autoMinYScale === true && thisObject.childrenMin.y !== newYMin && newYMin !== VERY_LARGE_NUMBER) {
|
||||
thisObject.childrenMin.y = newYMin
|
||||
newYMin = VERY_LARGE_NUMBER
|
||||
}
|
||||
|
||||
if (thisObject.autoMinYScale === true) {
|
||||
newYMin = VERY_LARGE_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
/* Here we will see if any of the children or parent values modify the current status quo */
|
||||
/* Min */
|
||||
let minX = Math.min(thisObject.childrenMin.x, thisObject.parentMin.x)
|
||||
let minY = Math.min(thisObject.childrenMin.y, thisObject.parentMin.y)
|
||||
let maxX = Math.max(thisObject.childrenMax.x, thisObject.parentMax.x)
|
||||
let maxY = Math.max(thisObject.childrenMax.y, thisObject.parentMax.y)
|
||||
|
||||
if (thisObject.parentMin.x === 0) {
|
||||
minX = thisObject.childrenMin.x
|
||||
}
|
||||
|
||||
if (thisObject.parentMin.y === 0) {
|
||||
minY = thisObject.childrenMin.y
|
||||
}
|
||||
|
||||
if (thisObject.parentMax.x === 0) {
|
||||
maxX = thisObject.childrenMax.x
|
||||
}
|
||||
|
||||
if (thisObject.parentMax.y === 0) {
|
||||
maxY = thisObject.childrenMax.y
|
||||
}
|
||||
|
||||
if (minX !== 0 && thisObject.min.x !== minX && thisObject.autoMinXScale === true) {
|
||||
thisObject.min.x = minX
|
||||
mustRecalculate = true
|
||||
}
|
||||
|
||||
if (minY !== 0 && thisObject.min.y !== minY && thisObject.autoMinYScale === true) {
|
||||
thisObject.min.y = minY
|
||||
mustRecalculate = true
|
||||
}
|
||||
|
||||
if (maxX !== 0 && thisObject.max.x !== maxX && thisObject.autoMaxXScale === true) {
|
||||
thisObject.max.x = maxX
|
||||
mustRecalculate = true
|
||||
}
|
||||
|
||||
if (maxY !== 0 && thisObject.max.y !== maxY && thisObject.autoMaxYScale === true) {
|
||||
thisObject.max.y = maxY
|
||||
mustRecalculate = true
|
||||
}
|
||||
|
||||
if (mustRecalculate === true) {
|
||||
recalculateScale()
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateScale (event) {
|
||||
thisObject.scale.x = thisObject.maxWidth * thisObject.HORIZONTAL_MARGIN_FACTOR / (thisObject.max.x - thisObject.min.x)
|
||||
thisObject.scale.y = thisObject.maxHeight * thisObject.VERTICAL_MARGIN_FACTOR / (thisObject.max.y - thisObject.min.y)
|
||||
|
||||
thisObject.eventHandler.raiseEvent('Scale Changed', event)
|
||||
}
|
||||
|
||||
function zoomX (factor, mousePosition, container) {
|
||||
let mouseAtCointainer = unTransformThisPoint(mousePosition, container)
|
||||
let leftDistance = mouseAtCointainer.x
|
||||
let rightDistance = container.frame.width - mouseAtCointainer.x
|
||||
let diff = thisObject.max.x - thisObject.min.x
|
||||
let min = thisObject.min.x + diff * factor * leftDistance / (container.frame.width / 2)
|
||||
let max = thisObject.max.x - diff * factor * rightDistance / (container.frame.width / 2)
|
||||
|
||||
if (min < max) {
|
||||
let mustRecalculate = false
|
||||
if (thisObject.autoMinXScale === false) {
|
||||
thisObject.min.x = min
|
||||
mustRecalculate = true
|
||||
}
|
||||
if (thisObject.autoMaxXScale === false) {
|
||||
thisObject.max.x = max
|
||||
mustRecalculate = true
|
||||
}
|
||||
if (mustRecalculate === true) {
|
||||
thisObject.recalculateScale()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function zoomY (factor, mousePosition, container) {
|
||||
let mouseAtCointainer = unTransformThisPoint(mousePosition, container)
|
||||
let topDistance = mouseAtCointainer.y
|
||||
let bottomDistance = container.frame.height - mouseAtCointainer.y
|
||||
let diff = thisObject.max.y - thisObject.min.y
|
||||
let min = thisObject.min.y + diff * factor * bottomDistance / (container.frame.height / 2)
|
||||
let max = thisObject.max.y - diff * factor * topDistance / (container.frame.height / 2)
|
||||
|
||||
if (min < max) {
|
||||
let mustRecalculate = false
|
||||
if (thisObject.autoMinYScale === false) {
|
||||
thisObject.min.y = min
|
||||
mustRecalculate = true
|
||||
}
|
||||
if (thisObject.autoMaxYScale === false) {
|
||||
thisObject.max.y = max
|
||||
mustRecalculate = true
|
||||
}
|
||||
if (mustRecalculate === true) {
|
||||
thisObject.recalculateScale()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeX (minValue, maxValue, maxWidth) {
|
||||
thisObject.min.x = minValue.x // * 0.999; // 0.1% less
|
||||
thisObject.max.x = maxValue.x // * 1.001; // 0.1% more
|
||||
|
||||
thisObject.scale.x = thisObject.maxWidth / (thisObject.max.x - thisObject.min.x)
|
||||
}
|
||||
|
||||
function initializeY (minValue, maxValue, pMaxHeight) {
|
||||
thisObject.min.y = minValue.y // * 0.999; // 0.1% less
|
||||
thisObject.max.y = maxValue.y // * 1.001; // 0.1% more
|
||||
|
||||
thisObject.scale.y = pMaxHeight / (thisObject.max.y - thisObject.min.y)
|
||||
|
||||
thisObject.maxHeight = pMaxHeight
|
||||
}
|
||||
|
||||
function transformThisPoint (point) {
|
||||
/*
|
||||
|
||||
This is the straigh fordward transformation this object provides. The input is a point on the data set that wants to be plotted in a timeline.
|
||||
The x value of the point must be a datetime.valueOf() and is going to be transformed into an x value on the coordinate system of the timeline.
|
||||
The y value should be a value in the dataset at that moment in time. Depending on how this coordinate system was initialized then are the
|
||||
possible values y can have. For sure it must be in the range between the min and max y declared at initialization. The y value has a special
|
||||
treatment since the browser canvas object used, has a zero y value at the top, while the timeline we use has a zero y value at the botton,
|
||||
for that reason y is flipped.
|
||||
|
||||
Besides this, what we do is to multiply by the scale, which in turn is calculated at initialization time depending on the values provided.
|
||||
|
||||
*/
|
||||
|
||||
point = {
|
||||
x: (point.x - thisObject.min.x) * thisObject.scale.x + thisObject.maxWidth * thisObject.HORIZONTAL_MARGIN_INVERSE_FACTOR / 2,
|
||||
y: thisObject.maxHeight - (point.y - thisObject.min.y) * thisObject.scale.y - thisObject.maxHeight * thisObject.VERTICAL_MARGIN_INVERSE_FACTOR / 2
|
||||
}
|
||||
|
||||
return point
|
||||
}
|
||||
|
||||
function transformThisPoint2 (point) {
|
||||
point = {
|
||||
x: (point.x - thisObject.min.x) * thisObject.scale.x + thisObject.maxWidth * thisObject.HORIZONTAL_MARGIN_INVERSE_FACTOR / 2,
|
||||
y: (thisObject.maxHeight - point.y - thisObject.min.y) * thisObject.scale.y - thisObject.maxHeight * thisObject.VERTICAL_MARGIN_INVERSE_FACTOR / 2
|
||||
}
|
||||
|
||||
return point
|
||||
}
|
||||
|
||||
function unInverseTransform (point, inverseY) {
|
||||
point = {
|
||||
x: ((point.x - thisObject.maxWidth * thisObject.HORIZONTAL_MARGIN_INVERSE_FACTOR / 2) / thisObject.scale.x) + thisObject.min.x,
|
||||
y: (inverseY * thisObject.VERTICAL_MARGIN_FACTOR - point.y + thisObject.maxHeight * thisObject.VERTICAL_MARGIN_INVERSE_FACTOR / 2) / thisObject.scale.y + thisObject.min.y
|
||||
}
|
||||
|
||||
return point
|
||||
}
|
||||
|
||||
function inverseTransformUncappedY (point, inverseY) {
|
||||
point = {
|
||||
x: (point.x - thisObject.min.x) * thisObject.scale.x + thisObject.maxWidth * thisObject.HORIZONTAL_MARGIN_INVERSE_FACTOR / 2,
|
||||
y: (inverseY * thisObject.VERTICAL_MARGIN_FACTOR - point.y) * thisObject.scale.y - thisObject.maxHeight * thisObject.VERTICAL_MARGIN_INVERSE_FACTOR / 2
|
||||
}
|
||||
|
||||
return point
|
||||
}
|
||||
}
|
||||
@@ -1,716 +0,0 @@
|
||||
function newEdgeEditor () {
|
||||
const MODULE_NAME = 'Edge Editor'
|
||||
|
||||
let thisObject = {
|
||||
container: undefined,
|
||||
fitFunction: undefined,
|
||||
isVisible: true,
|
||||
isMouseOver: undefined,
|
||||
resetAspectRatio: resetAspectRatio,
|
||||
onKeyPressed: onKeyPressed,
|
||||
physics: physics,
|
||||
drawForeground: drawForeground,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
const EDGE_SIZE = 6
|
||||
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
|
||||
thisObject.container.isDraggeable = true
|
||||
thisObject.container.isClickeable = false
|
||||
thisObject.container.isWheelable = false
|
||||
thisObject.container.detectMouseOver = true
|
||||
|
||||
let whatHappened
|
||||
let whereIsMouseOver = 'outside'
|
||||
|
||||
let coordinateSystem
|
||||
let coordinateSystemWhenDragStarted
|
||||
|
||||
let onMouseOverEventSubscriptionId
|
||||
let onMouseNotOverEventSubscriptionId
|
||||
let onDragStartedEventSubscriptionId
|
||||
|
||||
let mouse = {
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
|
||||
mouseWhenDragStarted = {
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
|
||||
parentFrameWhenDragStarted = {
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
|
||||
let doubleClickCounter = 0
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
thisObject.container.eventHandler.stopListening(onMouseOverEventSubscriptionId)
|
||||
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
|
||||
thisObject.container.eventHandler.stopListening(onDragStartedEventSubscriptionId)
|
||||
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.fitFunction = undefined
|
||||
mouse = undefined
|
||||
mouseWhenDragStarted = undefined
|
||||
parentFrameWhenDragStarted = undefined
|
||||
|
||||
coordinateSystem = undefined
|
||||
|
||||
if (coordinateSystemWhenDragStarted !== undefined) {
|
||||
coordinateSystemWhenDragStarted.finalize()
|
||||
}
|
||||
|
||||
coordinateSystemWhenDragStarted = undefined
|
||||
}
|
||||
|
||||
function initialize (pCoordinateSystem) {
|
||||
coordinateSystem = pCoordinateSystem
|
||||
|
||||
onMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
|
||||
onMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
|
||||
onDragStartedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onDragStarted', onDragStarted)
|
||||
}
|
||||
|
||||
function onMouseOver (event) {
|
||||
thisObject.isMouseOver = true
|
||||
mouse = {
|
||||
position: {
|
||||
x: event.x,
|
||||
y: event.y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseNotOver () {
|
||||
thisObject.isMouseOver = false
|
||||
}
|
||||
|
||||
function resetAspectRatio () {
|
||||
/* Resize the Time Machine to match the current screen aspect ration */
|
||||
|
||||
thisObject.container.parentContainer.frame.width = browserCanvas.width / TIME_MACHINE_WIDTH
|
||||
thisObject.container.parentContainer.frame.height = (COCKPIT_SPACE_POSITION - TOP_SPACE_HEIGHT) / TIME_MACHINE_HEIGHT
|
||||
coordinateSystem.maxHeight = thisObject.container.parentContainer.frame.height
|
||||
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
|
||||
coordinateSystem.recalculateScale()
|
||||
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
|
||||
}
|
||||
|
||||
function onDoubleClick (event) {
|
||||
doubleClickCounter = 0
|
||||
if (canvas.chartingSpace.viewport.zoomLevel === DOUBLE_CLICK_ZOOM_OUT_LEVEL) {
|
||||
canvas.chartingSpace.viewport.displaceToContainer(thisObject.container.parentContainer)
|
||||
canvas.chartingSpace.viewport.zoomAtCenter(DOUBLE_CLICK_ZOOM_IN_LEVEL)
|
||||
return
|
||||
}
|
||||
if (canvas.chartingSpace.viewport.zoomLevel === DOUBLE_CLICK_ZOOM_IN_LEVEL) {
|
||||
canvas.chartingSpace.viewport.zoomAtCenter(DOUBLE_CLICK_ZOOM_IN_IN_LEVEL)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function onDragStarted (event) {
|
||||
if (event.buttons === 1) {
|
||||
if (doubleClickCounter > 0) {
|
||||
onDoubleClick(event)
|
||||
return
|
||||
} else {
|
||||
doubleClickCounter = 50
|
||||
}
|
||||
}
|
||||
|
||||
mouseWhenDragStarted = {
|
||||
position: {
|
||||
x: event.x,
|
||||
y: event.y
|
||||
}
|
||||
}
|
||||
|
||||
parentFrameWhenDragStarted = {
|
||||
position: {
|
||||
x: thisObject.container.parentContainer.frame.position.x,
|
||||
y: thisObject.container.parentContainer.frame.position.y
|
||||
},
|
||||
width: thisObject.container.parentContainer.frame.width,
|
||||
height: thisObject.container.parentContainer.frame.height
|
||||
}
|
||||
|
||||
coordinateSystemWhenDragStarted = newCoordinateSystem()
|
||||
|
||||
let minValue = {
|
||||
x: coordinateSystem.min.x,
|
||||
y: coordinateSystem.min.y
|
||||
}
|
||||
|
||||
let maxValue = {
|
||||
x: coordinateSystem.max.x,
|
||||
y: coordinateSystem.max.y
|
||||
}
|
||||
|
||||
coordinateSystemWhenDragStarted.initialize(minValue, maxValue, coordinateSystem.maxWidth, coordinateSystem.maxHeight)
|
||||
|
||||
switch (event.buttons) {
|
||||
case 1: {
|
||||
whatHappened = 'left mouse button'
|
||||
if (event.shiftKey === true) {
|
||||
whatHappened = 'left mouse button + SHIFT'
|
||||
}
|
||||
break
|
||||
}
|
||||
case 2: {
|
||||
whatHappened = 'right mouse button' // this will never happen as of today
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyPressed (event) {
|
||||
const STEP = 10
|
||||
|
||||
if (event.shiftKey === false && event.ctrlKey === false && event.code === 'ArrowLeft') {
|
||||
onDragStarted(event)
|
||||
thisObject.container.frame.position.x = thisObject.container.frame.position.x + STEP
|
||||
whatHappened = 'left or right arrow key pressed'
|
||||
return
|
||||
}
|
||||
|
||||
if (event.shiftKey === false && event.ctrlKey === false && event.code === 'ArrowRight') {
|
||||
onDragStarted(event)
|
||||
thisObject.container.frame.position.x = thisObject.container.frame.position.x - STEP
|
||||
whatHappened = 'left or right arrow key pressed'
|
||||
return
|
||||
}
|
||||
|
||||
if (event.shiftKey === false && event.ctrlKey === false && event.code === 'ArrowUp') {
|
||||
onDragStarted(event)
|
||||
thisObject.container.frame.position.y = thisObject.container.frame.position.y + STEP
|
||||
whatHappened = 'up or down arrow key pressed'
|
||||
return
|
||||
}
|
||||
|
||||
if (event.shiftKey === false && event.ctrlKey === false && event.code === 'ArrowDown') {
|
||||
onDragStarted(event)
|
||||
thisObject.container.frame.position.y = thisObject.container.frame.position.y - STEP
|
||||
whatHappened = 'up or down arrow key pressed'
|
||||
return
|
||||
}
|
||||
|
||||
if (event.shiftKey === true && (event.ctrlKey === true || event.metaKey === true) && (event.key === 'A' || event.key === 'a')) {
|
||||
resetAspectRatio()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function getContainer (event, purpose) {
|
||||
if (thisObject.container.frame.isThisPointHere(event, undefined, undefined, -EDGE_SIZE) === true && event.buttons !== 2) {
|
||||
let point = {
|
||||
x: event.x,
|
||||
y: event.y
|
||||
}
|
||||
point = unTransformThisPoint(point, thisObject.container)
|
||||
|
||||
if (point.x <= 0) {
|
||||
whereIsMouseOver = 'left'
|
||||
return thisObject.container
|
||||
}
|
||||
|
||||
if (point.x >= thisObject.container.frame.width) {
|
||||
whereIsMouseOver = 'right'
|
||||
return thisObject.container
|
||||
}
|
||||
|
||||
if (point.y <= 0) {
|
||||
whereIsMouseOver = 'top'
|
||||
return thisObject.container
|
||||
}
|
||||
|
||||
if (point.y >= thisObject.container.frame.height) {
|
||||
whereIsMouseOver = 'bottom'
|
||||
return thisObject.container
|
||||
}
|
||||
|
||||
whereIsMouseOver = 'center'
|
||||
switch (purpose) {
|
||||
case GET_CONTAINER_PURPOSE.MOUSE_OVER:
|
||||
return // We will let the Time Machine to handle this situation.
|
||||
break
|
||||
case GET_CONTAINER_PURPOSE.DRAGGING:
|
||||
return thisObject.container
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function physics () {
|
||||
draggingPhysics()
|
||||
doubleClickPhysics()
|
||||
}
|
||||
|
||||
function doubleClickPhysics () {
|
||||
doubleClickCounter--
|
||||
if (doubleClickCounter < 0) {
|
||||
doubleClickCounter = 0
|
||||
}
|
||||
}
|
||||
|
||||
function draggingPhysics () {
|
||||
if (coordinateSystemWhenDragStarted === undefined) { return }
|
||||
if (thisObject.container.frame.position.x === 0 && thisObject.container.frame.position.y === 0) { return }
|
||||
|
||||
let mouseNoZoom = canvas.chartingSpace.viewport.unTransformThisPoint(mouse.position)
|
||||
let mouseWhenDragStartedNoZoom = canvas.chartingSpace.viewport.unTransformThisPoint(mouseWhenDragStarted.position)
|
||||
|
||||
let dragVectorWhenDragStarted = {
|
||||
x: mouseNoZoom.x - mouseWhenDragStartedNoZoom.x,
|
||||
y: mouseNoZoom.y - mouseWhenDragStartedNoZoom.y
|
||||
}
|
||||
|
||||
let dragVector = {
|
||||
x: thisObject.container.frame.position.x,
|
||||
y: thisObject.container.frame.position.y
|
||||
}
|
||||
|
||||
thisObject.container.frame.position.x = 0
|
||||
thisObject.container.frame.position.y = 0
|
||||
|
||||
const MIN_WIDTH = 200
|
||||
const MIN_HEIGHT = 100
|
||||
|
||||
switch (whereIsMouseOver) {
|
||||
case 'center': {
|
||||
switch (whatHappened) {
|
||||
case 'left mouse button + SHIFT': {
|
||||
/* This is equivalent to drag the whole Time Machine, so we will apply the translation received onto the Time Machine container. */
|
||||
thisObject.container.parentContainer.frame.position.x = parentFrameWhenDragStarted.position.x + dragVectorWhenDragStarted.x
|
||||
thisObject.container.parentContainer.frame.position.y = parentFrameWhenDragStarted.position.y + dragVectorWhenDragStarted.y
|
||||
snapPointToGrid(thisObject.container.parentContainer.frame.position)
|
||||
thisObject.container.parentContainer.eventHandler.raiseEvent('onDisplace')
|
||||
break
|
||||
}
|
||||
case 'left mouse button': {
|
||||
let point = {
|
||||
x: (-dragVectorWhenDragStarted.x),
|
||||
y: (-dragVectorWhenDragStarted.y)
|
||||
}
|
||||
|
||||
let newMinDate = getDateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystemWhenDragStarted)
|
||||
let newMaxRate = getRateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystemWhenDragStarted)
|
||||
|
||||
let xDifferenceMaxMin = coordinateSystemWhenDragStarted.max.x - coordinateSystemWhenDragStarted.min.x
|
||||
let yDifferenceMaxMin = coordinateSystemWhenDragStarted.max.y - coordinateSystemWhenDragStarted.min.y
|
||||
coordinateSystem.min.x = newMinDate.valueOf()
|
||||
coordinateSystem.max.x = newMinDate.valueOf() + xDifferenceMaxMin
|
||||
coordinateSystem.min.y = newMaxRate - yDifferenceMaxMin
|
||||
coordinateSystem.max.y = newMaxRate
|
||||
let event = {
|
||||
type: 'center dragged',
|
||||
dragVector: dragVector
|
||||
}
|
||||
coordinateSystem.recalculateScale(event)
|
||||
}
|
||||
break
|
||||
case 'left or right arrow key pressed': {
|
||||
let point = {
|
||||
x: -dragVector.x + thisObject.container.frame.width * coordinateSystem.HORIZONTAL_MARGIN_INVERSE_FACTOR / 2,
|
||||
y: 0
|
||||
}
|
||||
|
||||
let newMinDate = getDateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
|
||||
let xDifferenceMaxMin = coordinateSystem.max.x - coordinateSystem.min.x
|
||||
coordinateSystem.min.x = newMinDate.valueOf()
|
||||
coordinateSystem.max.x = newMinDate.valueOf() + xDifferenceMaxMin
|
||||
let event = {
|
||||
type: 'center dragged',
|
||||
dragVector: dragVector
|
||||
}
|
||||
coordinateSystem.recalculateScale(event)
|
||||
}
|
||||
break
|
||||
case 'up or down arrow key pressed': {
|
||||
let point = {
|
||||
x: 0,
|
||||
y: -dragVector.y + thisObject.container.frame.height * coordinateSystem.VERTICAL_MARGIN_INVERSE_FACTOR / 2
|
||||
}
|
||||
|
||||
let newMaxRate = getRateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
|
||||
let yDifferenceMaxMin = coordinateSystem.max.y - coordinateSystem.min.y
|
||||
coordinateSystem.min.y = newMaxRate - yDifferenceMaxMin
|
||||
coordinateSystem.max.y = newMaxRate
|
||||
let event = {
|
||||
type: 'center dragged',
|
||||
dragVector: dragVector
|
||||
}
|
||||
coordinateSystem.recalculateScale(event)
|
||||
}
|
||||
break
|
||||
}
|
||||
thisObject.container.parentContainer.eventHandler.raiseEvent('onMouseOver', mouse.position)
|
||||
break
|
||||
}
|
||||
case 'top' : {
|
||||
dragVectorWhenDragStarted.x = 0
|
||||
|
||||
let newHight = parentFrameWhenDragStarted.height - dragVectorWhenDragStarted.y
|
||||
if (newHight < MIN_HEIGHT && dragVectorWhenDragStarted.y > 0) {
|
||||
dragVectorWhenDragStarted.y = parentFrameWhenDragStarted.height - MIN_HEIGHT
|
||||
}
|
||||
|
||||
thisObject.container.parentContainer.frame.position.y = parentFrameWhenDragStarted.position.y + dragVectorWhenDragStarted.y
|
||||
snapPointToGrid(thisObject.container.parentContainer.frame.position)
|
||||
thisObject.container.parentContainer.frame.height = parentFrameWhenDragStarted.height + (parentFrameWhenDragStarted.position.y - thisObject.container.parentContainer.frame.position.y)
|
||||
|
||||
let point = {
|
||||
x: 0,
|
||||
y: (thisObject.container.parentContainer.frame.position.y - parentFrameWhenDragStarted.position.y)
|
||||
}
|
||||
|
||||
/* This is equivalent to getRateFromPointAtContainer, but as we do not have a container anymore because we already change it, we do it like this. */
|
||||
point = coordinateSystemWhenDragStarted.unInverseTransform(point, parentFrameWhenDragStarted.height)
|
||||
let newMaxRate = point.y
|
||||
|
||||
switch (whatHappened) {
|
||||
case 'left mouse button': {
|
||||
coordinateSystem.max.y = newMaxRate
|
||||
coordinateSystem.maxHeight = thisObject.container.parentContainer.frame.height
|
||||
let event = {
|
||||
type: 'top dragged',
|
||||
dragVector: dragVector
|
||||
}
|
||||
coordinateSystem.recalculateScale(event)
|
||||
break
|
||||
}
|
||||
case 'left mouse button + SHIFT': {
|
||||
coordinateSystem.maxHeight = thisObject.container.parentContainer.frame.height
|
||||
coordinateSystem.recalculateScale()
|
||||
break
|
||||
}
|
||||
}
|
||||
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
|
||||
break
|
||||
}
|
||||
case 'bottom' : {
|
||||
dragVectorWhenDragStarted.x = 0
|
||||
|
||||
let newHight = dragVectorWhenDragStarted.y + parentFrameWhenDragStarted.height
|
||||
if (newHight < MIN_HEIGHT && dragVectorWhenDragStarted.y < 0) {
|
||||
dragVectorWhenDragStarted.y = MIN_HEIGHT - parentFrameWhenDragStarted.height
|
||||
}
|
||||
|
||||
let point = {
|
||||
x: 0,
|
||||
y: dragVectorWhenDragStarted.y + parentFrameWhenDragStarted.height + parentFrameWhenDragStarted.position.y
|
||||
}
|
||||
snapPointToGrid(point)
|
||||
point.y = point.y - parentFrameWhenDragStarted.position.y
|
||||
|
||||
thisObject.container.parentContainer.frame.height = point.y
|
||||
|
||||
/* This is equivalent to getRateFromPointAtContainer, but as we do not have a container anymore because we already change it, we do it like this. */
|
||||
point = coordinateSystemWhenDragStarted.unInverseTransform(point, parentFrameWhenDragStarted.height)
|
||||
let newMinRate = point.y
|
||||
|
||||
switch (whatHappened) {
|
||||
case 'left mouse button': {
|
||||
coordinateSystem.min.y = newMinRate
|
||||
coordinateSystem.maxHeight = thisObject.container.parentContainer.frame.height
|
||||
let event = {
|
||||
type: 'bottom dragged',
|
||||
dragVector: dragVector
|
||||
}
|
||||
coordinateSystem.recalculateScale(event)
|
||||
break
|
||||
}
|
||||
case 'left mouse button + SHIFT': {
|
||||
coordinateSystem.maxHeight = thisObject.container.parentContainer.frame.height
|
||||
coordinateSystem.recalculateScale()
|
||||
break
|
||||
}
|
||||
}
|
||||
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
|
||||
break
|
||||
}
|
||||
case 'left' : {
|
||||
dragVectorWhenDragStarted.y = 0
|
||||
|
||||
let newWidth = parentFrameWhenDragStarted.width - dragVectorWhenDragStarted.x
|
||||
if (newWidth < MIN_WIDTH && dragVectorWhenDragStarted.x > 0) {
|
||||
dragVectorWhenDragStarted.x = parentFrameWhenDragStarted.width - MIN_WIDTH
|
||||
}
|
||||
|
||||
thisObject.container.parentContainer.frame.position.x = parentFrameWhenDragStarted.position.x + dragVectorWhenDragStarted.x
|
||||
snapPointToGrid(thisObject.container.parentContainer.frame.position)
|
||||
thisObject.container.parentContainer.frame.width = parentFrameWhenDragStarted.width + (parentFrameWhenDragStarted.position.x - thisObject.container.parentContainer.frame.position.x)
|
||||
|
||||
let point = {
|
||||
x: (thisObject.container.parentContainer.frame.position.x - parentFrameWhenDragStarted.position.x),
|
||||
y: 0
|
||||
}
|
||||
|
||||
/* This is equivalent to getDateFromPointAtContainer, but as we do not have a container anymore because we already change it, we do it like this. */
|
||||
point = coordinateSystemWhenDragStarted.unInverseTransform(point, parentFrameWhenDragStarted.width)
|
||||
let newMinDate = point.x
|
||||
|
||||
switch (whatHappened) {
|
||||
case 'left mouse button': {
|
||||
coordinateSystem.min.x = newMinDate.valueOf()
|
||||
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
|
||||
coordinateSystem.recalculateScale()
|
||||
break
|
||||
}
|
||||
case 'left mouse button + SHIFT': {
|
||||
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
|
||||
coordinateSystem.recalculateScale()
|
||||
break
|
||||
}
|
||||
}
|
||||
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
|
||||
break
|
||||
}
|
||||
case 'right' : {
|
||||
dragVectorWhenDragStarted.y = 0
|
||||
|
||||
let newWidth = dragVectorWhenDragStarted.x + parentFrameWhenDragStarted.width
|
||||
if (newWidth < MIN_WIDTH && dragVectorWhenDragStarted.x < 0) {
|
||||
dragVectorWhenDragStarted.x = MIN_WIDTH - parentFrameWhenDragStarted.width
|
||||
}
|
||||
|
||||
let point = {
|
||||
x: dragVectorWhenDragStarted.x + parentFrameWhenDragStarted.width + parentFrameWhenDragStarted.position.x,
|
||||
y: 0
|
||||
}
|
||||
snapPointToGrid(point)
|
||||
point.x = point.x - parentFrameWhenDragStarted.position.x
|
||||
|
||||
thisObject.container.parentContainer.frame.width = point.x
|
||||
|
||||
/* This is equivalent to getRateFromPointAtContainer, but as we do not have a container anymore because we already change it, we do it like this. */
|
||||
point = coordinateSystemWhenDragStarted.unInverseTransform(point, parentFrameWhenDragStarted.width)
|
||||
let newMaxDate = point.x
|
||||
|
||||
switch (whatHappened) {
|
||||
case 'left mouse button': {
|
||||
coordinateSystem.max.x = newMaxDate.valueOf()
|
||||
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
|
||||
coordinateSystem.recalculateScale()
|
||||
break
|
||||
}
|
||||
case 'left mouse button + SHIFT': {
|
||||
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
|
||||
coordinateSystem.recalculateScale()
|
||||
break
|
||||
}
|
||||
}
|
||||
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function snapPointToGrid (point) {
|
||||
point.x = snapScalarToGrid(point.x)
|
||||
point.y = snapScalarToGrid(point.y)
|
||||
}
|
||||
|
||||
function snapScalarToGrid (scalar) {
|
||||
let sign
|
||||
if (scalar < 0) {
|
||||
sign = -1
|
||||
} else {
|
||||
sign = 1
|
||||
}
|
||||
const GRID_SIZE = 10
|
||||
return Math.trunc(scalar / GRID_SIZE) * GRID_SIZE + GRID_SIZE / 2 * sign
|
||||
}
|
||||
}
|
||||
|
||||
function drawForeground () {
|
||||
let MARGIN = 1
|
||||
let edgeSize
|
||||
let lineWidth
|
||||
|
||||
if (whereIsMouseOver === 'outside' || thisObject.isMouseOver === false) {
|
||||
edgeSize = 2
|
||||
lineWidth = 0.1
|
||||
} else {
|
||||
edgeSize = EDGE_SIZE
|
||||
lineWidth = 0.5
|
||||
}
|
||||
|
||||
const OPACITY = 1
|
||||
|
||||
pointA1 = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
pointA2 = {
|
||||
x: thisObject.container.frame.width,
|
||||
y: 0
|
||||
}
|
||||
|
||||
pointA3 = {
|
||||
x: thisObject.container.frame.width,
|
||||
y: thisObject.container.frame.height
|
||||
}
|
||||
|
||||
pointA4 = {
|
||||
x: 0,
|
||||
y: thisObject.container.frame.height
|
||||
}
|
||||
|
||||
pointB1 = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
pointB2 = {
|
||||
x: thisObject.container.frame.width,
|
||||
y: 0
|
||||
}
|
||||
|
||||
pointB3 = {
|
||||
x: thisObject.container.frame.width,
|
||||
y: thisObject.container.frame.height
|
||||
}
|
||||
|
||||
pointB4 = {
|
||||
x: 0,
|
||||
y: thisObject.container.frame.height
|
||||
}
|
||||
|
||||
pointA1 = transformThisPoint(pointA1, thisObject.container)
|
||||
pointA2 = transformThisPoint(pointA2, thisObject.container)
|
||||
pointA3 = transformThisPoint(pointA3, thisObject.container)
|
||||
pointA4 = transformThisPoint(pointA4, thisObject.container)
|
||||
|
||||
pointB1 = transformThisPoint(pointB1, thisObject.container)
|
||||
pointB2 = transformThisPoint(pointB2, thisObject.container)
|
||||
pointB3 = transformThisPoint(pointB3, thisObject.container)
|
||||
pointB4 = transformThisPoint(pointB4, thisObject.container)
|
||||
|
||||
pointA1 = {
|
||||
x: pointA1.x - MARGIN,
|
||||
y: pointA1.y - MARGIN
|
||||
}
|
||||
|
||||
pointA2 = {
|
||||
x: pointA2.x + MARGIN,
|
||||
y: pointA2.y - MARGIN
|
||||
}
|
||||
|
||||
pointA3 = {
|
||||
x: pointA3.x + MARGIN,
|
||||
y: pointA3.y + MARGIN
|
||||
}
|
||||
|
||||
pointA4 = {
|
||||
x: pointA4.x - MARGIN,
|
||||
y: pointA4.y + MARGIN
|
||||
}
|
||||
|
||||
pointB1 = {
|
||||
x: pointB1.x - edgeSize,
|
||||
y: pointB1.y - edgeSize
|
||||
}
|
||||
|
||||
pointB2 = {
|
||||
x: pointB2.x + edgeSize,
|
||||
y: pointB2.y - edgeSize
|
||||
}
|
||||
|
||||
pointB3 = {
|
||||
x: pointB3.x + edgeSize,
|
||||
y: pointB3.y + edgeSize
|
||||
}
|
||||
|
||||
pointB4 = {
|
||||
x: pointB4.x - edgeSize,
|
||||
y: pointB4.y + edgeSize
|
||||
}
|
||||
|
||||
pointA1 = canvas.chartingSpace.viewport.fitIntoViewport(pointA1)
|
||||
pointA2 = canvas.chartingSpace.viewport.fitIntoViewport(pointA2)
|
||||
pointA3 = canvas.chartingSpace.viewport.fitIntoViewport(pointA3)
|
||||
pointA4 = canvas.chartingSpace.viewport.fitIntoViewport(pointA4)
|
||||
|
||||
pointB1 = canvas.chartingSpace.viewport.fitIntoViewport(pointB1)
|
||||
pointB2 = canvas.chartingSpace.viewport.fitIntoViewport(pointB2)
|
||||
pointB3 = canvas.chartingSpace.viewport.fitIntoViewport(pointB3)
|
||||
pointB4 = canvas.chartingSpace.viewport.fitIntoViewport(pointB4)
|
||||
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.moveTo(pointA1.x, pointA1.y)
|
||||
browserCanvasContext.lineTo(pointA2.x, pointA2.y)
|
||||
browserCanvasContext.lineTo(pointB2.x, pointB2.y)
|
||||
browserCanvasContext.lineTo(pointB1.x, pointB1.y)
|
||||
browserCanvasContext.lineTo(pointA1.x, pointA1.y)
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
drawEdge('top')
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.moveTo(pointA2.x, pointA2.y)
|
||||
browserCanvasContext.lineTo(pointA3.x, pointA3.y)
|
||||
browserCanvasContext.lineTo(pointB3.x, pointB3.y)
|
||||
browserCanvasContext.lineTo(pointB2.x, pointB2.y)
|
||||
browserCanvasContext.lineTo(pointA2.x, pointA2.y)
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
drawEdge('right')
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.moveTo(pointA3.x, pointA3.y)
|
||||
browserCanvasContext.lineTo(pointA4.x, pointA4.y)
|
||||
browserCanvasContext.lineTo(pointB4.x, pointB4.y)
|
||||
browserCanvasContext.lineTo(pointB3.x, pointB3.y)
|
||||
browserCanvasContext.lineTo(pointA3.x, pointA3.y)
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
drawEdge('bottom')
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.moveTo(pointA4.x, pointA4.y)
|
||||
browserCanvasContext.lineTo(pointA1.x, pointA1.y)
|
||||
browserCanvasContext.lineTo(pointB1.x, pointB1.y)
|
||||
browserCanvasContext.lineTo(pointB4.x, pointB4.y)
|
||||
browserCanvasContext.lineTo(pointA4.x, pointA4.y)
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
drawEdge('left')
|
||||
|
||||
function drawEdge (edgeType) {
|
||||
if (whereIsMouseOver === edgeType && thisObject.isMouseOver === true) {
|
||||
browserCanvasContext.lineWidth = lineWidth
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + OPACITY + ')'
|
||||
} else {
|
||||
browserCanvasContext.lineWidth = lineWidth
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + OPACITY + ')'
|
||||
}
|
||||
browserCanvasContext.fill()
|
||||
browserCanvasContext.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
function newPlottersManager () {
|
||||
const MODULE_NAME = 'Plotters Manager'
|
||||
const ERROR_LOG = true
|
||||
const logger = newWebDebugLog()
|
||||
logger.fileName = MODULE_NAME
|
||||
|
||||
let timeFrame = INITIAL_TIME_PERIOD
|
||||
let datetime = NEW_SESSION_INITIAL_DATE
|
||||
|
||||
let thisObject = {
|
||||
fitFunction: undefined,
|
||||
container: undefined,
|
||||
payload: undefined,
|
||||
connectors: [],
|
||||
setDatetime: setDatetime,
|
||||
setTimeFrame: setTimeFrame,
|
||||
setCoordinateSystem: setCoordinateSystem,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
thisObject.connectors = []
|
||||
|
||||
let initializationReady = false
|
||||
let layersPanel
|
||||
let onLayerStatusChangedEventSuscriptionId
|
||||
let coordinateSystem
|
||||
|
||||
setupContainer()
|
||||
return thisObject
|
||||
|
||||
function setupContainer () {
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
}
|
||||
|
||||
function finalize () {
|
||||
layersPanel.container.eventHandler.stopListening(onLayerStatusChangedEventSuscriptionId)
|
||||
layersPanel = undefined
|
||||
|
||||
for (let i = 0; i < thisObject.connectors.length; i++) {
|
||||
let connector = thisObject.connectors[i]
|
||||
/* Then the panels. */
|
||||
for (let j = 0; j < connector.panels.length; j++) {
|
||||
canvas.panelsSpace.destroyPanel(connector.panels[j])
|
||||
connector.panels[j] = undefined
|
||||
}
|
||||
connector.panels = undefined
|
||||
|
||||
/* Finalize the plotters */
|
||||
if (connector.plotter.finalize !== undefined) {
|
||||
connector.plotter.container.eventHandler.stopListening(connector.plotter.onRecordChangeEventsSubscriptionId)
|
||||
connector.plotter.finalize()
|
||||
}
|
||||
connector.plotter = undefined
|
||||
|
||||
/* Finally the Storage Objects */
|
||||
finalizeStorage(connector.storage)
|
||||
connector.storage = undefined
|
||||
|
||||
connector = undefined
|
||||
}
|
||||
thisObject.connectors = []
|
||||
coordinateSystem = undefined
|
||||
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.payload = undefined
|
||||
}
|
||||
|
||||
function finalizeStorage (storage) {
|
||||
storage.eventHandler.stopListening(storage.onMarketFileLoadedLayerEventsSubscriptionId)
|
||||
storage.eventHandler.stopListening(storage.onDailyFileLoadedLayerEventsSubscriptionId)
|
||||
storage.eventHandler.stopListening(storage.onSingleFileLoadedLayerEventsSubscriptionId)
|
||||
storage.eventHandler.stopListening(storage.onFileSequenceLoadedLayerEventsSubscriptionId)
|
||||
storage.eventHandler.stopListening(storage.onDailyFileLoadedPlotterEventsSubscriptionId)
|
||||
storage.finalize()
|
||||
}
|
||||
|
||||
function initialize (pLayersPanel) {
|
||||
/* Remember this */
|
||||
layersPanel = pLayersPanel
|
||||
|
||||
/* Listen to the event of change of status */
|
||||
onLayerStatusChangedEventSuscriptionId = layersPanel.container.eventHandler.listenToEvent('Layer Status Changed', onLayerStatusChanged)
|
||||
}
|
||||
|
||||
function initializePlotter (layer) {
|
||||
try {
|
||||
/* Before Initializing a Plotter, we need the Storage it will use, loaded with the files it will initially need. */
|
||||
let storage = newProductStorage(layer.payload.node.id)
|
||||
|
||||
/*
|
||||
Before Initializing the Storage, we will put the Layer 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 < layer.definition.referenceParent.referenceParent.datasets.length; i++) {
|
||||
let dataset = layer.definition.referenceParent.referenceParent.datasets[i]
|
||||
|
||||
switch (dataset.code.type) {
|
||||
case 'Market Files': {
|
||||
storage.onMarketFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Market File Loaded', layer.onMarketFileLoaded)
|
||||
}
|
||||
break
|
||||
case 'Daily Files': {
|
||||
storage.onDailyFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', layer.onDailyFileLoaded)
|
||||
}
|
||||
break
|
||||
case 'Single File': {
|
||||
storage.onSingleFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Single File Loaded', layer.onSingleFileLoaded)
|
||||
}
|
||||
break
|
||||
case 'File Sequence': {
|
||||
storage.onFileSequenceLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('File Sequence Loaded', layer.onFileSequenceLoaded)
|
||||
}
|
||||
break
|
||||
default: {
|
||||
if (ERROR_LOG === true) {
|
||||
logger.write('[ERROR] initializePlotter -> Dataset Type Incorrect or Undefined -> dataset.type = ' + dataset.type)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let baseAsset = layer.definition.referenceParent.parentNode.referenceParent.baseAsset.referenceParent.code.codeName
|
||||
let quotedAsset = layer.definition.referenceParent.parentNode.referenceParent.quotedAsset.referenceParent.code.codeName
|
||||
let market = {
|
||||
baseAsset: baseAsset,
|
||||
quotedAsset: quotedAsset
|
||||
}
|
||||
let product = layer.definition.referenceParent.referenceParent
|
||||
let bot = layer.definition.referenceParent.referenceParent.parentNode
|
||||
let dataMine = layer.definition.referenceParent.referenceParent.parentNode.parentNode
|
||||
let exchange = layer.definition.referenceParent.parentNode.referenceParent.parentNode.parentNode
|
||||
let plotterModule = layer.definition.referenceParent.referenceParent.referenceParent
|
||||
let session
|
||||
|
||||
if (layer.definition.referenceParent.parentNode.parentNode !== undefined) {
|
||||
if (layer.definition.referenceParent.parentNode.parentNode.type === 'Session Reference') {
|
||||
if (layer.definition.referenceParent.parentNode.parentNode.referenceParent !== undefined) {
|
||||
session = layer.definition.referenceParent.parentNode.parentNode.referenceParent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let host = layer.networkNode.code.host
|
||||
let webPort = layer.networkNode.code.webPort
|
||||
if (host === undefined) { host = 'localhost' }
|
||||
if (webPort === undefined) { webPort = window.location.port }
|
||||
|
||||
let eventsServerClient = canvas.designSpace.workspace.eventsServerClients.get(layer.networkNode.id)
|
||||
|
||||
storage.initialize(
|
||||
dataMine,
|
||||
bot,
|
||||
session,
|
||||
product,
|
||||
exchange,
|
||||
market,
|
||||
datetime,
|
||||
timeFrame,
|
||||
host,
|
||||
webPort,
|
||||
eventsServerClient,
|
||||
onProductStorageInitialized
|
||||
)
|
||||
|
||||
function onProductStorageInitialized (err) {
|
||||
try {
|
||||
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
|
||||
/* Now we have all the initial data loaded and ready to be delivered to the new instance of the plotter. */
|
||||
let plotter
|
||||
|
||||
if (plotterModule.code.isLegacy !== true) {
|
||||
plotter = newPlotter()
|
||||
} else {
|
||||
plotter = getNewPlotter(dataMine.code.codeName, plotterModule.parentNode.code.codeName, plotterModule.code.codeName)
|
||||
}
|
||||
|
||||
plotter.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
|
||||
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.fitFunction = thisObject.fitFunction
|
||||
plotter.initialize(storage, datetime, timeFrame, coordinateSystem, onPlotterInizialized, product)
|
||||
|
||||
function onPlotterInizialized () {
|
||||
try {
|
||||
let connector = {
|
||||
layer: layer,
|
||||
plotter: plotter,
|
||||
storage: storage
|
||||
}
|
||||
/* Let the Plotter listen to the event of Cursor Files loaded, so that it can react recalculating if needed. */
|
||||
plotter.onDailyFileLoadedPlotterEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', plotter.onDailyFileLoaded)
|
||||
/* Lets load now this plotter panels. */
|
||||
connector.panels = []
|
||||
|
||||
if (product !== undefined) {
|
||||
for (let i = 0; i < plotterModule.panels.length; i++) {
|
||||
let panel = plotterModule.panels[i]
|
||||
|
||||
let parameters = {
|
||||
dataMine: dataMine.code.codeName,
|
||||
plotterCodeName: plotterModule.parentNode.code.codeName,
|
||||
moduleCodeName: plotterModule.code.codeName,
|
||||
panelNode: panel
|
||||
}
|
||||
|
||||
let owner = thisObject.payload.node.payload.parentNode.id // Panels are owned by the time machine.
|
||||
let plotterPanelHandle = canvas.panelsSpace.createNewPanel('Plotter Panel', parameters, owner, layer.session)
|
||||
let plotterPanel = canvas.panelsSpace.getPanel(plotterPanelHandle)
|
||||
|
||||
/* Connect Panel to the Plotter via an Event. */
|
||||
connector.plotter.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', plotterPanel.onRecordChange)
|
||||
connector.panels.push(plotterPanelHandle)
|
||||
}
|
||||
|
||||
connector.layer.panels = connector.panels
|
||||
}
|
||||
|
||||
thisObject.connectors.push(connector)
|
||||
} catch (err) {
|
||||
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> onProductStorageInitialized -> onPlotterInizialized -> err = ' + err.stack) }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> onProductStorageInitialized -> err = ' + err.stack) }
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> err = ' + err.stack) }
|
||||
}
|
||||
}
|
||||
|
||||
function onLayerStatusChanged (layer) {
|
||||
if (layer.status === LAYER_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 < thisObject.connectors.length; i++) {
|
||||
let connector = thisObject.connectors[i]
|
||||
if (connector.layer.payload.node.id === layer.payload.node.id) {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if (found === false) {
|
||||
initializePlotter(layer, onProductPlotterInitialized)
|
||||
function onProductPlotterInitialized (err) {
|
||||
/* There is no policy yet of what to do if this fails. */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layer.status === LAYER_STATUS.OFF) {
|
||||
/* If the plotter of this card is not on our Active Plotters list, then we remove it. */
|
||||
for (let i = 0; i < thisObject.connectors.length; i++) {
|
||||
let connector = thisObject.connectors[i]
|
||||
if (connector.layer.payload.node.id === layer.payload.node.id) {
|
||||
/* Then the panels. */
|
||||
for (let j = 0; j < connector.panels.length; j++) {
|
||||
canvas.panelsSpace.destroyPanel(connector.panels[j])
|
||||
}
|
||||
/* Finally the Storage Objects */
|
||||
|
||||
if (connector.plotter.finalize !== undefined) {
|
||||
connector.plotter.container.eventHandler.stopListening(connector.plotter.onRecordChangeEventsSubscriptionId)
|
||||
connector.plotter.container.finalize()
|
||||
connector.plotter.finalize()
|
||||
}
|
||||
finalizeStorage(connector.storage)
|
||||
thisObject.connectors.splice(i, 1) // Delete item from array.
|
||||
return // We already found the product woth changes and processed it.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setTimeFrame (pTimeFrame) {
|
||||
timeFrame = pTimeFrame
|
||||
for (let i = 0; i < thisObject.connectors.length; i++) {
|
||||
let connector = thisObject.connectors[i]
|
||||
connector.layer.setTimeFrame(timeFrame)
|
||||
connector.storage.setTimeFrame(timeFrame)
|
||||
connector.plotter.setTimeFrame(timeFrame)
|
||||
}
|
||||
}
|
||||
|
||||
function setDatetime (pDatetime) {
|
||||
datetime = pDatetime
|
||||
for (let i = 0; i < thisObject.connectors.length; i++) {
|
||||
let connector = thisObject.connectors[i]
|
||||
connector.layer.setDatetime(pDatetime)
|
||||
connector.storage.setDatetime(pDatetime)
|
||||
connector.plotter.setDatetime(pDatetime)
|
||||
}
|
||||
}
|
||||
|
||||
function setCoordinateSystem (pCoordinateSystem) {
|
||||
coordinateSystem = pCoordinateSystem
|
||||
for (let i = 0; i < thisObject.connectors.length; i++) {
|
||||
let connector = thisObject.connectors[i]
|
||||
connector.plotter.setCoordinateSystem(coordinateSystem)
|
||||
}
|
||||
}
|
||||
|
||||
function getContainer (point) {
|
||||
}
|
||||
|
||||
function draw () {
|
||||
if (thisObject.connectors === undefined) { return } // We need to wait
|
||||
/* First the Product Plotters. */
|
||||
let maxElementsPlotted = 0
|
||||
for (let i = 0; i < thisObject.connectors.length; i++) {
|
||||
let connector = thisObject.connectors[thisObject.connectors.length - i - 1]
|
||||
let elementsPlotted = connector.plotter.draw()
|
||||
if (elementsPlotted !== undefined) {
|
||||
if (elementsPlotted > maxElementsPlotted) {
|
||||
maxElementsPlotted = elementsPlotted
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxElementsPlotted
|
||||
}
|
||||
}
|
||||
@@ -1,822 +0,0 @@
|
||||
/*
|
||||
|
||||
Markets are a function of time. When watching them, end users must be positioned at one particular point in time. The system currently allows users
|
||||
to position themselves at any time they like.
|
||||
|
||||
In the future, it will be usefull to explore markets and compare them at different times simultaneously. Anticipating that future this module exists.
|
||||
All the timelineCharts that depand on a datetime are children of this object Time Machine. In the future we will allow users to have more than one Time Machine,
|
||||
each one with it own timelineCharts, and each one positioned at an especific point in titme.
|
||||
|
||||
*/
|
||||
|
||||
function newTimeMachine () {
|
||||
const MODULE_NAME = 'Time Machine'
|
||||
const logger = newWebDebugLog()
|
||||
logger.fileName = MODULE_NAME
|
||||
|
||||
let timeFrame = INITIAL_TIME_PERIOD
|
||||
|
||||
let thisObject = {
|
||||
container: undefined,
|
||||
timeScale: undefined,
|
||||
rateScale: undefined,
|
||||
payload: undefined,
|
||||
edgeEditor: undefined,
|
||||
onFocus: undefined,
|
||||
onKeyPressed: onKeyPressed,
|
||||
timelineCharts: [],
|
||||
fitFunction: fitFunction,
|
||||
physics: physics,
|
||||
draw: draw,
|
||||
drawBackground: drawBackground,
|
||||
drawForeground: drawForeground,
|
||||
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
let timeMachineCoordinateSystem = newCoordinateSystem()
|
||||
timeMachineCoordinateSystem.name = 'TIME MACHINE'
|
||||
|
||||
let mouse = {
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
|
||||
let tabAnimation = 0
|
||||
let tabAnimationStatus = 'Close'
|
||||
let tabAnimationCounter = 0
|
||||
let wasOnFocus = false
|
||||
let drawScales = false
|
||||
let syncWithDesignerLoop = 0
|
||||
let timelineChartsMap = new Map()
|
||||
|
||||
let onMouseOverEventSuscriptionId
|
||||
let onMouseNotOverEventSuscriptionId
|
||||
let timeScaleMouseOverEventSuscriptionId
|
||||
let rateScaleMouseOverEventSuscriptionId
|
||||
let timeFrameScaleEventSuscriptionId
|
||||
let timeFrameScaleMouseOverEventSuscriptionId
|
||||
let onScaleChangedEventSubscriptionId
|
||||
|
||||
setupContainer()
|
||||
return thisObject
|
||||
|
||||
function setupContainer () {
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
thisObject.container.fitFunction = thisObject.fitFunction
|
||||
thisObject.container.isDraggeable = false
|
||||
thisObject.container.insideViewport = true
|
||||
thisObject.container.detectMouseOver = true
|
||||
|
||||
thisObject.container.frame.width = browserCanvas.width / TIME_MACHINE_WIDTH
|
||||
thisObject.container.frame.height = (browserCanvas.height - TOP_SPACE_HEIGHT - COCKPIT_SPACE_HEIGHT) / TIME_MACHINE_HEIGHT
|
||||
}
|
||||
|
||||
function finalize () {
|
||||
timeMachineCoordinateSystem.eventHandler.stopListening(onScaleChangedEventSubscriptionId)
|
||||
|
||||
if (thisObject.timeScale !== undefined) {
|
||||
finalizeTimeScale()
|
||||
}
|
||||
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
finalizeRateScale()
|
||||
}
|
||||
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
finalizeTimeFrameScale()
|
||||
}
|
||||
|
||||
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
|
||||
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSuscriptionId)
|
||||
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[i]
|
||||
timelineChart.container.eventHandler.stopListening(timelineChart.onChildrenMouseOverEventSuscriptionId)
|
||||
timelineChart.finalize()
|
||||
}
|
||||
|
||||
thisObject.timelineCharts = undefined
|
||||
thisObject.fitFunction = undefined
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.payload = undefined
|
||||
thisObject.edgeEditor = undefined
|
||||
|
||||
mouse = undefined
|
||||
timelineChartsMap = undefined
|
||||
|
||||
timeMachineCoordinateSystem.finalize()
|
||||
timeMachineCoordinateSystem = undefined
|
||||
}
|
||||
|
||||
function finalizeTimeScale () {
|
||||
if (thisObject.timeScale === undefined) { return }
|
||||
|
||||
thisObject.timeScale.container.eventHandler.stopListening(timeScaleMouseOverEventSuscriptionId)
|
||||
thisObject.timeScale.finalize()
|
||||
thisObject.timeScale = undefined
|
||||
}
|
||||
|
||||
function finalizeRateScale () {
|
||||
if (thisObject.rateScale === undefined) { return }
|
||||
|
||||
thisObject.rateScale.container.eventHandler.stopListening(rateScaleMouseOverEventSuscriptionId)
|
||||
thisObject.rateScale.finalize()
|
||||
thisObject.rateScale = undefined
|
||||
}
|
||||
|
||||
function finalizeTimeFrameScale () {
|
||||
if (thisObject.timeFrameScale === undefined) { return }
|
||||
|
||||
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleEventSuscriptionId)
|
||||
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleMouseOverEventSuscriptionId)
|
||||
thisObject.timeFrameScale.finalize()
|
||||
thisObject.timeFrameScale = undefined
|
||||
}
|
||||
|
||||
function initialize (callBackFunction) {
|
||||
timeFrame = INITIAL_TIME_PERIOD
|
||||
loadFrame(thisObject.payload, thisObject.container.frame)
|
||||
saveFrame(thisObject.payload, thisObject.container.frame)
|
||||
|
||||
recalculateCoordinateSystem()
|
||||
recalculateCurrentDatetime()
|
||||
|
||||
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
|
||||
onMouseNotOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
|
||||
onScaleChangedEventSubscriptionId = timeMachineCoordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
|
||||
|
||||
thisObject.edgeEditor = newEdgeEditor()
|
||||
thisObject.edgeEditor.initialize(timeMachineCoordinateSystem)
|
||||
thisObject.edgeEditor.container.connectToParent(thisObject.container, true, true, false, true, true, true)
|
||||
|
||||
callBackFunction()
|
||||
}
|
||||
|
||||
function onKeyPressed (event) {
|
||||
thisObject.edgeEditor.onKeyPressed(event)
|
||||
}
|
||||
|
||||
function onMouseOver (event) {
|
||||
drawScales = true
|
||||
|
||||
mouse.position.x = event.x
|
||||
mouse.position.y = event.y
|
||||
|
||||
if (thisObject.timeScale !== undefined) {
|
||||
thisObject.timeScale.onMouseOverSomeTimeMachineContainer(event)
|
||||
}
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
thisObject.rateScale.onMouseOverSomeTimeMachineContainer(event)
|
||||
}
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.onMouseOverSomeTimeMachineContainer(event)
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseNotOver (event) {
|
||||
drawScales = false
|
||||
|
||||
if (thisObject.timeScale !== undefined) {
|
||||
thisObject.timeScale.visible = false
|
||||
}
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
thisObject.rateScale.visible = false
|
||||
}
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTimeScale () {
|
||||
thisObject.timeScale = newTimeScale()
|
||||
thisObject.timeScale.fitFunction = thisObject.fitFunction
|
||||
thisObject.timeScale.payload = thisObject.payload.node.timeScale.payload
|
||||
|
||||
timeScaleMouseOverEventSuscriptionId = thisObject.timeScale.container.eventHandler.listenToEvent('onMouseOverScale', timeScaleMouseOver)
|
||||
thisObject.timeScale.initialize(timeMachineCoordinateSystem, thisObject.container)
|
||||
|
||||
function timeScaleMouseOver (event) {
|
||||
thisObject.container.eventHandler.raiseEvent('onMouseOver', event)
|
||||
}
|
||||
}
|
||||
|
||||
function initializeRateScale () {
|
||||
thisObject.rateScale = newRateScale()
|
||||
thisObject.rateScale.fitFunction = thisObject.fitFunction
|
||||
thisObject.rateScale.payload = thisObject.payload.node.rateScale.payload
|
||||
|
||||
rateScaleMouseOverEventSuscriptionId = thisObject.rateScale.container.eventHandler.listenToEvent('onMouseOverScale', rateScaleMouseOver)
|
||||
thisObject.rateScale.initialize(timeMachineCoordinateSystem, thisObject.container, thisObject.container)
|
||||
|
||||
function rateScaleMouseOver (event) {
|
||||
thisObject.container.eventHandler.raiseEvent('onMouseOver', event)
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTimeFrameScale () {
|
||||
thisObject.timeFrameScale = newTimeFrameScale()
|
||||
thisObject.timeFrameScale.fitFunction = thisObject.fitFunction
|
||||
thisObject.timeFrameScale.payload = thisObject.payload.node.timeFrameScale.payload
|
||||
|
||||
timeFrameScaleEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('Time Frame Value Changed', timeFrameScaleValueChanged)
|
||||
timeFrameScaleMouseOverEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('onMouseOverScale', timeFrameScaleMouseOver)
|
||||
thisObject.timeFrameScale.initialize(thisObject.container)
|
||||
|
||||
function timeFrameScaleValueChanged (event) {
|
||||
let currentTimeFrame = timeFrame
|
||||
timeFrame = event.timeFrame
|
||||
if (timeFrame !== currentTimeFrame) {
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[i]
|
||||
timelineChart.upstreamTimeFrame = timeFrame
|
||||
if (timelineChart.timeFrameScale === undefined) {
|
||||
timelineChart.setTimeFrame(timeFrame)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function timeFrameScaleMouseOver (event) {
|
||||
thisObject.container.eventHandler.raiseEvent('onMouseOver', event)
|
||||
}
|
||||
}
|
||||
|
||||
function getContainer (point, purpose) {
|
||||
let container
|
||||
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) {
|
||||
container = thisObject.rateScale.getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
if (container.isForThisPurpose(purpose)) {
|
||||
return container
|
||||
} else {
|
||||
if (purpose === GET_CONTAINER_PURPOSE.DRAGGING && container.isClickeable === true) {
|
||||
return container
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thisObject.timeScale !== undefined && thisObject.timeScale.isVisible === true) {
|
||||
container = thisObject.timeScale.getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
if (container.isForThisPurpose(purpose)) {
|
||||
return container
|
||||
} else {
|
||||
if (purpose === GET_CONTAINER_PURPOSE.DRAGGING && container.isClickeable === true) {
|
||||
return container
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) {
|
||||
container = thisObject.timeFrameScale.getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
if (container.isForThisPurpose(purpose)) {
|
||||
return container
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
container = thisObject.timelineCharts[i].getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
if (container.isForThisPurpose(purpose)) {
|
||||
if (thisObject.container.frame.isThisPointHere(point) === true) {
|
||||
return container
|
||||
}
|
||||
} else {
|
||||
if (purpose === GET_CONTAINER_PURPOSE.DRAGGING && container.isClickeable === true) {
|
||||
if (thisObject.container.frame.isThisPointHere(point) === true) {
|
||||
return container
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container = thisObject.edgeEditor.getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
return container
|
||||
} else {
|
||||
if (thisObject.container.isForThisPurpose(purpose)) {
|
||||
if (thisObject.container.frame.isThisPointHere(point) === true) {
|
||||
return thisObject.container
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onScaleChanged () {
|
||||
recalculateCurrentDatetime()
|
||||
}
|
||||
|
||||
function recalculateCurrentDatetime () {
|
||||
let center = {
|
||||
x: thisObject.container.frame.width / 2,
|
||||
y: thisObject.container.frame.height / 2
|
||||
}
|
||||
|
||||
datetime = new Date(getDateFromPointAtContainer(center, thisObject.container, timeMachineCoordinateSystem))
|
||||
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[i]
|
||||
timelineChart.setDatetime(datetime)
|
||||
}
|
||||
}
|
||||
|
||||
function fitFunction (point, fullVisible, margin, topMargin, bottomMargin) {
|
||||
/* We prevent a point to be out of the container AND out of the Charting Space in general */
|
||||
|
||||
let returnPoint = {
|
||||
x: point.x,
|
||||
y: point.y
|
||||
}
|
||||
|
||||
let upCorner = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
let bottonCorner = {
|
||||
x: thisObject.container.frame.width,
|
||||
y: thisObject.container.frame.height
|
||||
}
|
||||
|
||||
upCorner = transformThisPoint(upCorner, thisObject.container)
|
||||
bottonCorner = transformThisPoint(bottonCorner, thisObject.container)
|
||||
|
||||
/* Checking against the container limits. */
|
||||
if (margin === undefined) { margin = 0 }
|
||||
if (topMargin === undefined) { topMargin = 0 }
|
||||
if (bottomMargin === undefined) { bottomMargin = 0 }
|
||||
|
||||
if (returnPoint.x - margin < upCorner.x) { returnPoint.x = upCorner.x + margin }
|
||||
if (returnPoint.x + margin > bottonCorner.x) { returnPoint.x = bottonCorner.x - margin }
|
||||
if (returnPoint.y - margin - topMargin < upCorner.y) { returnPoint.y = upCorner.y + margin + topMargin }
|
||||
if (returnPoint.y + margin + bottomMargin > bottonCorner.y) { returnPoint.y = bottonCorner.y - margin - bottomMargin }
|
||||
|
||||
returnPoint = canvas.chartingSpace.fitFunction(returnPoint, fullVisible)
|
||||
|
||||
return returnPoint
|
||||
}
|
||||
|
||||
function physics () {
|
||||
thisObject.edgeEditor.physics()
|
||||
timeMachineCoordinateSystem.physics()
|
||||
|
||||
saveFrame(thisObject.payload, thisObject.container.frame)
|
||||
if (thisObject.container.frame.isInViewPort()) {
|
||||
childrenPhysics()
|
||||
syncWithDesigner()
|
||||
}
|
||||
panelPhysics()
|
||||
onFocusPhysics()
|
||||
tabAnimationPhysics()
|
||||
}
|
||||
|
||||
function tabAnimationPhysics () {
|
||||
const MAX_COUNTER_VALUE = 40
|
||||
const STEP = 10
|
||||
|
||||
if (wasOnFocus === true && thisObject.onFocus === false) {
|
||||
tabAnimationStatus = 'Closing'
|
||||
}
|
||||
if (wasOnFocus === false && thisObject.onFocus === true) {
|
||||
tabAnimationStatus = 'Opening'
|
||||
}
|
||||
|
||||
if (tabAnimationStatus === 'Closing') {
|
||||
tabAnimationCounter = tabAnimationCounter - STEP
|
||||
if (tabAnimationCounter <= 0) {
|
||||
tabAnimationCounter = 0
|
||||
tabAnimationStatus = 'Closed'
|
||||
}
|
||||
}
|
||||
if (tabAnimationStatus === 'Opening') {
|
||||
tabAnimationCounter = tabAnimationCounter + STEP
|
||||
if (tabAnimationCounter >= MAX_COUNTER_VALUE) {
|
||||
tabAnimationCounter = MAX_COUNTER_VALUE
|
||||
tabAnimationStatus = 'Open'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onFocusPhysics () {
|
||||
wasOnFocus = thisObject.onFocus
|
||||
if (thisObject.edgeEditor.isMouseOver === true) {
|
||||
thisObject.onFocus = true
|
||||
} else {
|
||||
thisObject.onFocus = false
|
||||
}
|
||||
}
|
||||
|
||||
function panelPhysics () {
|
||||
if (
|
||||
thisObject.container.frame.isInViewPort() &&
|
||||
canvas.chartingSpace.viewport.zoomLevel >= ZOOM_OUT_THRESHOLD_FOR_NOT_HIDDING_PANELS) {
|
||||
canvas.panelsSpace.unHide(thisObject.payload.node.id, 'Layers Panel')
|
||||
canvas.panelsSpace.unHide(thisObject.payload.node.id, 'Plotter Panel')
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
thisObject.container.frame.isCenterInViewPort() &&
|
||||
canvas.chartingSpace.viewport.zoomLevel >= ZOOM_OUT_THRESHOLD_FOR_HIDDING_PANELS
|
||||
) {
|
||||
canvas.panelsSpace.unHide(thisObject.payload.node.id, 'Layers Panel')
|
||||
canvas.panelsSpace.unHide(thisObject.payload.node.id, 'Plotter Panel')
|
||||
} else {
|
||||
canvas.panelsSpace.hide(thisObject.payload.node.id, 'Layers Panel')
|
||||
canvas.panelsSpace.hide(thisObject.payload.node.id, 'Plotter Panel')
|
||||
}
|
||||
}
|
||||
|
||||
function syncWithDesigner () {
|
||||
syncWithDesignerTimelineCharts()
|
||||
syncWithDesignerScales()
|
||||
}
|
||||
|
||||
function syncWithDesignerScales () {
|
||||
if (thisObject.payload.node === undefined) {
|
||||
finalizeTimeScale()
|
||||
finalizeRateScale()
|
||||
finalizeTimeFrameScale()
|
||||
return
|
||||
}
|
||||
if (thisObject.payload.node.timeScale === undefined && thisObject.timeScale !== undefined) {
|
||||
finalizeTimeScale()
|
||||
}
|
||||
if (thisObject.payload.node.timeScale !== undefined && thisObject.timeScale === undefined) {
|
||||
initializeTimeScale()
|
||||
}
|
||||
if (thisObject.payload.node.rateScale === undefined && thisObject.rateScale !== undefined) {
|
||||
finalizeRateScale()
|
||||
}
|
||||
if (thisObject.payload.node.rateScale !== undefined && thisObject.rateScale === undefined) {
|
||||
initializeRateScale()
|
||||
}
|
||||
if (thisObject.payload.node.timeFrameScale === undefined && thisObject.timeFrameScale !== undefined) {
|
||||
finalizeTimeFrameScale()
|
||||
}
|
||||
if (thisObject.payload.node.timeFrameScale !== undefined && thisObject.timeFrameScale === undefined) {
|
||||
initializeTimeFrameScale()
|
||||
}
|
||||
}
|
||||
|
||||
function syncWithDesignerTimelineCharts () {
|
||||
syncWithDesignerLoop = syncWithDesignerLoop + 0.00000000001
|
||||
|
||||
for (let j = 0; j < thisObject.payload.node.timelineCharts.length; j++) {
|
||||
let node = thisObject.payload.node.timelineCharts[j]
|
||||
let timelineChart = timelineChartsMap.get(node.id)
|
||||
if (timelineChart === undefined) {
|
||||
/* The timeline timelineChart node is new, thus we need to initialize a new timelineChart */
|
||||
initializeTimelineChart(node, syncWithDesignerLoop)
|
||||
} else {
|
||||
/* The time machine already exists, we tag it as existing at the current loop. */
|
||||
timelineChart.syncWithDesignerLoop = syncWithDesignerLoop
|
||||
}
|
||||
}
|
||||
|
||||
/* We check all the timeMachines we have to see if we need to remove any of them */
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[i]
|
||||
if (timelineChart.syncWithDesignerLoop < syncWithDesignerLoop) {
|
||||
/* Must be removed */
|
||||
timelineChart.container.eventHandler.stopListening(timelineChart.onChildrenMouseOverEventSuscriptionId)
|
||||
timelineChart.finalize()
|
||||
timelineChartsMap.delete(timelineChart.nodeId)
|
||||
thisObject.timelineCharts.splice(i, 1)
|
||||
/* We remove one at the time */
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTimelineChart (node, syncWithDesignerLoop) {
|
||||
let timelineChart = newTimelineChart()
|
||||
timelineChart.syncWithDesignerLoop = syncWithDesignerLoop
|
||||
timelineChart.payload = node.payload
|
||||
timelineChart.nodeId = node.id
|
||||
timelineChartsMap.set(node.id, timelineChart)
|
||||
timelineChart.payload.uiObject.setValue('Loading...')
|
||||
|
||||
/* Setting up the new timeline timelineChart. */
|
||||
timelineChart.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
|
||||
timelineChart.container.fitFunction = thisObject.container.fitFunction
|
||||
timelineChart.fitFunction = thisObject.fitFunction
|
||||
timelineChart.container.frame.width = thisObject.container.frame.width
|
||||
timelineChart.container.frame.height = thisObject.container.frame.height
|
||||
timelineChart.container.frame.position.x = 0
|
||||
timelineChart.container.frame.position.y = 0
|
||||
timelineChart.initialize(timeMachineCoordinateSystem, timeFrame)
|
||||
|
||||
/* we will store the event suscription id as a property of the timelineChart, to avoid keeping it an a separate array */
|
||||
timelineChart.onChildrenMouseOverEventSuscriptionId = timelineChart.container.eventHandler.listenToEvent('onChildrenMouseOver', onChildrenMouseOver)
|
||||
|
||||
thisObject.timelineCharts.push(timelineChart)
|
||||
timelineChart.payload.uiObject.setValue('')
|
||||
|
||||
function onChildrenMouseOver (event) {
|
||||
thisObject.container.eventHandler.raiseEvent('onMouseOver', event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function childrenPhysics () {
|
||||
if (thisObject.timeScale !== undefined) {
|
||||
thisObject.timeScale.physics()
|
||||
}
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
thisObject.rateScale.physics()
|
||||
}
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.physics()
|
||||
}
|
||||
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[i]
|
||||
timelineChart.physics()
|
||||
}
|
||||
}
|
||||
|
||||
function drawBackground () {
|
||||
drawChartsBackground()
|
||||
if (thisObject.container.frame.isInViewPort()) {
|
||||
if (drawScales === true) {
|
||||
if (thisObject.timeScale !== undefined && thisObject.timeScale.isVisible === true) { thisObject.timeScale.drawBackground() }
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.drawBackground() }
|
||||
}
|
||||
|
||||
let maxElementsPlotted = 0
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[thisObject.timelineCharts.length - i - 1]
|
||||
let elementsPlotted = timelineChart.drawBackground()
|
||||
if (elementsPlotted !== undefined) {
|
||||
if (elementsPlotted > maxElementsPlotted) {
|
||||
maxElementsPlotted = elementsPlotted
|
||||
}
|
||||
}
|
||||
}
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.adjustTimeFrame(maxElementsPlotted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawChartsBackground () {
|
||||
drawContainerBackground(thisObject.container, UI_COLOR.WHITE, 0.5, thisObject.fitFunction)
|
||||
}
|
||||
|
||||
function draw () {
|
||||
if (thisObject.payload === undefined) { return }
|
||||
if (thisObject.payload.node === undefined) { return }
|
||||
if (thisObject.container.frame.isInViewPort()) {
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[thisObject.timelineCharts.length - i - 1]
|
||||
timelineChart.draw()
|
||||
}
|
||||
|
||||
if (drawScales === true) {
|
||||
if (thisObject.timeScale !== undefined && thisObject.timeScale.isVisible === true) { thisObject.timeScale.draw() }
|
||||
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.draw() }
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.draw() }
|
||||
}
|
||||
} else {
|
||||
if (canvas.chartingSpace.viewport.zoomTargetLevel < ZOOM_OUT_THRESHOLD_FOR_DISPLAYING_TIME_MACHINES_ICONIZED) {
|
||||
let icon = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
|
||||
if (icon !== undefined) {
|
||||
if (icon.canDrawIcon === true) {
|
||||
let imageSize = 40
|
||||
let imagePosition = {
|
||||
x: thisObject.container.frame.width / 2,
|
||||
y: thisObject.container.frame.height / 2
|
||||
}
|
||||
|
||||
imagePosition = transformThisPoint(imagePosition, thisObject.container)
|
||||
imagePosition = thisObject.fitFunction(imagePosition, true)
|
||||
|
||||
browserCanvasContext.drawImage(
|
||||
icon,
|
||||
imagePosition.x - imageSize / 2,
|
||||
imagePosition.y - imageSize / 2,
|
||||
imageSize,
|
||||
imageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawForeground () {
|
||||
if (thisObject.container.frame.isInViewPort()) {
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelineChart = thisObject.timelineCharts[thisObject.timelineCharts.length - i - 1]
|
||||
timelineChart.drawForeground()
|
||||
}
|
||||
|
||||
if (drawScales === true) {
|
||||
if (thisObject.timeScale !== undefined && thisObject.timeScale.isVisible === true) { thisObject.timeScale.drawForeground() }
|
||||
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.drawForeground() }
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.drawForeground() }
|
||||
}
|
||||
|
||||
drawLabel()
|
||||
thisObject.edgeEditor.drawForeground()
|
||||
}
|
||||
}
|
||||
|
||||
function drawLabel () {
|
||||
if (thisObject.payload.node === undefined) { return }
|
||||
if (thisObject.payload === undefined) { return }
|
||||
/* Draw Title Above the Container */
|
||||
let position = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
let imageSize = 13
|
||||
let fontSize = 15
|
||||
let opacity = 1
|
||||
let icon = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
|
||||
|
||||
position = transformThisPoint(position, thisObject.container)
|
||||
|
||||
let label = thisObject.payload.node.name
|
||||
let description = loadPropertyFromNodeConfig(thisObject.payload, 'description')
|
||||
|
||||
if (description !== undefined) {
|
||||
label = description
|
||||
}
|
||||
printLabel(label, position.x + 20, position.y - 10, opacity, fontSize)
|
||||
|
||||
if (icon !== undefined) {
|
||||
if (icon.canDrawIcon === true) {
|
||||
browserCanvasContext.drawImage(
|
||||
icon, position.x + 5,
|
||||
position.y - 22,
|
||||
imageSize,
|
||||
imageSize)
|
||||
}
|
||||
}
|
||||
|
||||
imageSize = 13
|
||||
fontSize = 15
|
||||
let exchangeMarkets = new Map()
|
||||
|
||||
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
|
||||
let timelinechart = thisObject.timelineCharts[i]
|
||||
if (timelinechart.layersManager !== undefined) {
|
||||
for (let j = 0; j < timelinechart.layersManager.layers.length; j++) {
|
||||
let layer = timelinechart.layersManager.layers[j]
|
||||
|
||||
exchangeMarket = {
|
||||
exchangeName: layer.exchange.name,
|
||||
marketName: layer.market,
|
||||
exchangeIcon: layer.exchangeIcon,
|
||||
baseAssetIcon: layer.baseAssetIcon,
|
||||
quotedAssetIcon: layer.quotedAssetIcon
|
||||
}
|
||||
exchangeMarkets.set(exchangeMarket.exchangeName + '-' + exchangeMarket.marketName, exchangeMarket)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawTab(0, 0, exchangeMarkets.size * tabAnimationCounter, 90, thisObject.container)
|
||||
|
||||
const INTER_EXCHANGE_SPACE = 60
|
||||
const INTER_MARKET_SPACE = -100
|
||||
|
||||
if (tabAnimationStatus === 'Open') {
|
||||
drawMarketNames()
|
||||
}
|
||||
|
||||
function drawMarketNames () {
|
||||
exchangeMarkets.forEach((exchangeMarket, i) => {
|
||||
browserCanvasContext.save()
|
||||
browserCanvasContext.translate(position.x, position.y)
|
||||
browserCanvasContext.rotate(-Math.PI / 2)
|
||||
|
||||
let xOffSet = -80
|
||||
|
||||
icon = exchangeMarket.exchangeIcon
|
||||
|
||||
if (icon !== undefined) {
|
||||
if (icon.canDrawIcon === true) {
|
||||
browserCanvasContext.drawImage(
|
||||
icon,
|
||||
-20 + xOffSet,
|
||||
-43,
|
||||
imageSize,
|
||||
imageSize)
|
||||
}
|
||||
}
|
||||
|
||||
printLabel(exchangeMarket.exchangeName, -5 + xOffSet, -30, opacity, fontSize, UI_COLOR.GREY)
|
||||
|
||||
position.x = position.x + INTER_EXCHANGE_SPACE
|
||||
|
||||
icon = exchangeMarket.baseAssetIcon
|
||||
if (icon !== undefined) {
|
||||
if (icon.canDrawIcon === true) {
|
||||
browserCanvasContext.drawImage(
|
||||
icon,
|
||||
-20 + xOffSet,
|
||||
-22,
|
||||
imageSize,
|
||||
imageSize)
|
||||
}
|
||||
}
|
||||
|
||||
printLabel(exchangeMarket.marketName, -5 + xOffSet, -10, opacity, fontSize, UI_COLOR.GREY)
|
||||
|
||||
icon = exchangeMarket.quotedAssetIcon
|
||||
if (icon !== undefined) {
|
||||
if (icon.canDrawIcon === true) {
|
||||
browserCanvasContext.drawImage(
|
||||
icon,
|
||||
+50 + xOffSet,
|
||||
-22,
|
||||
imageSize,
|
||||
imageSize)
|
||||
}
|
||||
}
|
||||
|
||||
position.x = position.x + INTER_MARKET_SPACE
|
||||
|
||||
browserCanvasContext.restore()
|
||||
})
|
||||
}
|
||||
|
||||
function drawTab (x, y, width, height, container) {
|
||||
const GRADIENT = 0
|
||||
const X_OFFSET = -3
|
||||
const Y_OFFSET = 13
|
||||
const TAB_CORNERS_RADIUS = 5
|
||||
|
||||
let point = {
|
||||
x: x,
|
||||
y: y
|
||||
}
|
||||
point = transformThisPoint(point, container)
|
||||
|
||||
let point1 = {
|
||||
x: point.x + X_OFFSET,
|
||||
y: point.y + Y_OFFSET
|
||||
}
|
||||
|
||||
let point2 = {
|
||||
x: point.x + X_OFFSET,
|
||||
y: point.y + height + Y_OFFSET
|
||||
}
|
||||
|
||||
let point3 = {
|
||||
x: point.x - width + X_OFFSET,
|
||||
y: point.y + height - GRADIENT + Y_OFFSET
|
||||
}
|
||||
|
||||
let point4 = {
|
||||
x: point.x - width + X_OFFSET,
|
||||
y: point.y + GRADIENT + Y_OFFSET
|
||||
}
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.moveTo(point1.x, point1.y)
|
||||
browserCanvasContext.lineTo(point2.x, point2.y)
|
||||
browserCanvasContext.lineTo(point3.x, point3.y)
|
||||
browserCanvasContext.arc(point3.x, point3.y - TAB_CORNERS_RADIUS, TAB_CORNERS_RADIUS, 0.5 * Math.PI, 1.0 * Math.PI)
|
||||
// browserCanvasContext.lineTo(point4.x, point4.y)
|
||||
browserCanvasContext.arc(point4.x, point4.y + TAB_CORNERS_RADIUS, TAB_CORNERS_RADIUS, 1.0 * Math.PI, 1.5 * Math.PI)
|
||||
browserCanvasContext.closePath()
|
||||
browserCanvasContext.lineWidth = 1
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ''
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ''
|
||||
browserCanvasContext.fill()
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateCoordinateSystem () {
|
||||
let minValue = {
|
||||
x: MIN_PLOTABLE_DATE.valueOf(),
|
||||
y: 0
|
||||
}
|
||||
|
||||
let maxValue = {
|
||||
x: MAX_PLOTABLE_DATE.valueOf(),
|
||||
y: nextPorwerOf10(MAX_DEFAULT_RATE_SCALE_VALUE) / 4
|
||||
}
|
||||
|
||||
timeMachineCoordinateSystem.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
thisObject.container.frame.width,
|
||||
thisObject.container.frame.height
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,424 +0,0 @@
|
||||
function newTimelineChart () {
|
||||
const MODULE_NAME = 'Timeline Chart'
|
||||
const INFO_LOG = false
|
||||
const INTENSIVE_LOG = false
|
||||
const ERROR_LOG = true
|
||||
let logger = newWebDebugLog()
|
||||
logger.fileName = MODULE_NAME
|
||||
|
||||
let timeFrame = INITIAL_TIME_PERIOD
|
||||
let datetime = NEW_SESSION_INITIAL_DATE
|
||||
|
||||
let thisObject = {
|
||||
container: undefined,
|
||||
fitFunction: undefined,
|
||||
rateScale: undefined,
|
||||
timeFrameScale: undefined,
|
||||
payload: undefined,
|
||||
layersManager: undefined,
|
||||
plotterManager: undefined,
|
||||
upstreamTimeFrame: undefined,
|
||||
setDatetime: setDatetime,
|
||||
setTimeFrame: setTimeFrame,
|
||||
physics: physics,
|
||||
draw: draw,
|
||||
drawBackground: drawBackground,
|
||||
drawForeground: drawForeground,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
let timeMachineCoordinateSystem
|
||||
let timelineChartCoordinateSystem = newCoordinateSystem()
|
||||
timelineChartCoordinateSystem.name = 'TIMELINE CHART'
|
||||
|
||||
let coordinateSystem
|
||||
|
||||
let layersPanel
|
||||
let layersPanelHandle
|
||||
|
||||
let onMouseOverEventSuscriptionId
|
||||
let onMouseNotOverEventSuscriptionId
|
||||
let rateScaleUpstreamEventSuscriptionId
|
||||
let rateScaleMouseOverEventSuscriptionId
|
||||
let timeFrameScaleEventSuscriptionId
|
||||
let timeFrameScaleMouseOverEventSuscriptionId
|
||||
let scaleChangedEventSubscriptionId
|
||||
|
||||
let drawScales = false
|
||||
let mouse = {
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
|
||||
setupContainer()
|
||||
return thisObject
|
||||
|
||||
function setupContainer () {
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
thisObject.container.detectMouseOver = true
|
||||
}
|
||||
|
||||
function finalize () {
|
||||
timeMachineCoordinateSystem.eventHandler.stopListening(scaleChangedEventSubscriptionId)
|
||||
|
||||
if (thisObject.layersManager !== undefined) {
|
||||
finalizeLayersManager()
|
||||
}
|
||||
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
finalizeRateScale()
|
||||
}
|
||||
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
finalizeTimeFrameScale()
|
||||
}
|
||||
|
||||
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
|
||||
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSuscriptionId)
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.payload = undefined
|
||||
|
||||
mouse = undefined
|
||||
logger = undefined
|
||||
|
||||
timeMachineCoordinateSystem = undefined
|
||||
timelineChartCoordinateSystem.finalize()
|
||||
timelineChartCoordinateSystem = undefined
|
||||
coordinateSystem = undefined
|
||||
layersPanel = undefined
|
||||
layersPanelHandle = undefined
|
||||
}
|
||||
|
||||
function finalizeLayersManager () {
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
thisObject.plotterManager.finalize()
|
||||
}
|
||||
thisObject.plotterManager = undefined
|
||||
thisObject.layersManager = undefined
|
||||
|
||||
canvas.panelsSpace.destroyPanel(layersPanelHandle)
|
||||
}
|
||||
|
||||
function finalizeTimeFrameScale () {
|
||||
if (thisObject.timeFrameScale === undefined) { return }
|
||||
|
||||
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleEventSuscriptionId)
|
||||
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleMouseOverEventSuscriptionId)
|
||||
thisObject.timeFrameScale.finalize()
|
||||
thisObject.timeFrameScale = undefined
|
||||
if (thisObject.upstreamTimeFrame !== undefined) {
|
||||
timeFrame = thisObject.upstreamTimeFrame
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
thisObject.plotterManager.setTimeFrame(timeFrame)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function finalizeRateScale () {
|
||||
if (thisObject.rateScale === undefined) { return }
|
||||
|
||||
thisObject.rateScale.container.eventHandler.stopListening(rateScaleMouseOverEventSuscriptionId)
|
||||
thisObject.container.parentContainer.eventHandler.stopListening(rateScaleUpstreamEventSuscriptionId)
|
||||
thisObject.rateScale.finalize()
|
||||
thisObject.rateScale = undefined
|
||||
|
||||
/* Resets the local container with the dimessions of its parent, the Time Machine */
|
||||
thisObject.container.frame.position.x = 0
|
||||
thisObject.container.frame.position.y = 0
|
||||
thisObject.container.frame.height = thisObject.container.parentContainer.frame.height
|
||||
thisObject.container.frame.width = thisObject.container.parentContainer.frame.width
|
||||
}
|
||||
|
||||
function initialize (pTimeMachineCoordinateSystem, pTimeFrame) {
|
||||
/* We load the logow we will need for the background. */
|
||||
|
||||
timeMachineCoordinateSystem = pTimeMachineCoordinateSystem
|
||||
coordinateSystem = timeMachineCoordinateSystem
|
||||
initializeCoordinateSystem()
|
||||
|
||||
timeFrame = pTimeFrame
|
||||
|
||||
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
|
||||
onMouseNotOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
|
||||
scaleChangedEventSubscriptionId = timeMachineCoordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
|
||||
}
|
||||
|
||||
function initializeCoordinateSystem () {
|
||||
let minValue = {
|
||||
x: timeMachineCoordinateSystem.min.x,
|
||||
y: 0
|
||||
}
|
||||
|
||||
let maxValue = {
|
||||
x: timeMachineCoordinateSystem.max.x,
|
||||
y: nextPorwerOf10(MAX_DEFAULT_RATE_SCALE_VALUE) / 4
|
||||
}
|
||||
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
minValue.y = thisObject.rateScale.minValue
|
||||
maxValue.y = thisObject.rateScale.maxValue
|
||||
}
|
||||
|
||||
timelineChartCoordinateSystem.initialize(
|
||||
minValue,
|
||||
maxValue,
|
||||
thisObject.container.frame.width,
|
||||
thisObject.container.frame.height
|
||||
)
|
||||
}
|
||||
|
||||
function initializeLayersManager () {
|
||||
let owner = thisObject.payload.node.payload.parentNode.id // The real owner is the Time Machine
|
||||
layersPanelHandle = canvas.panelsSpace.createNewPanel('Layers Panel', undefined, owner)
|
||||
thisObject.layersManager = canvas.panelsSpace.getPanel(layersPanelHandle)
|
||||
thisObject.layersManager.payload = thisObject.payload.node.layersManager.payload
|
||||
thisObject.layersManager.initialize()
|
||||
|
||||
/* Initialize the Plotter Manager */
|
||||
thisObject.plotterManager = newPlottersManager()
|
||||
|
||||
thisObject.plotterManager.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
|
||||
|
||||
thisObject.plotterManager.container.frame.position.x = 0
|
||||
thisObject.plotterManager.container.frame.position.y = 0
|
||||
|
||||
thisObject.plotterManager.fitFunction = thisObject.fitFunction
|
||||
thisObject.plotterManager.payload = thisObject.payload
|
||||
thisObject.plotterManager.initialize(thisObject.layersManager)
|
||||
thisObject.plotterManager.setTimeFrame(timeFrame)
|
||||
thisObject.plotterManager.setDatetime(datetime)
|
||||
thisObject.plotterManager.setCoordinateSystem(coordinateSystem)
|
||||
}
|
||||
|
||||
function initializeRateScale () {
|
||||
thisObject.rateScale = newRateScale()
|
||||
thisObject.rateScale.fitFunction = thisObject.fitFunction
|
||||
thisObject.rateScale.payload = thisObject.payload.node.rateScale.payload
|
||||
|
||||
rateScaleMouseOverEventSuscriptionId = thisObject.rateScale.container.eventHandler.listenToEvent('onMouseOverScale', rateScaleMouseOver)
|
||||
thisObject.rateScale.initialize(timelineChartCoordinateSystem, thisObject.container.parentContainer, thisObject.container)
|
||||
|
||||
function rateScaleMouseOver (event) {
|
||||
thisObject.container.eventHandler.raiseEvent('onChildrenMouseOver', event)
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTimeFrameScale () {
|
||||
thisObject.timeFrameScale = newTimeFrameScale()
|
||||
thisObject.timeFrameScale.fitFunction = thisObject.fitFunction
|
||||
thisObject.timeFrameScale.payload = thisObject.payload.node.timeFrameScale.payload
|
||||
|
||||
timeFrameScaleEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('Time Frame Value Changed', timeFrameScaleValueChanged)
|
||||
timeFrameScaleMouseOverEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('onMouseOverScale', timeFrameScaleMouseOver)
|
||||
thisObject.timeFrameScale.initialize(thisObject.container.parentContainer)
|
||||
|
||||
function timeFrameScaleValueChanged (event) {
|
||||
let currentTimeFrame = timeFrame
|
||||
timeFrame = event.timeFrame
|
||||
if (timeFrame !== currentTimeFrame) {
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
thisObject.plotterManager.setTimeFrame(timeFrame)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function timeFrameScaleMouseOver (event) {
|
||||
thisObject.container.eventHandler.raiseEvent('onChildrenMouseOver', event)
|
||||
}
|
||||
}
|
||||
|
||||
function onScaleChanged (event) {
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
thisObject.rateScale.onUpstreamScaleChanged(event)
|
||||
}
|
||||
timelineChartCoordinateSystem.min.x = timeMachineCoordinateSystem.min.x
|
||||
timelineChartCoordinateSystem.max.x = timeMachineCoordinateSystem.max.x
|
||||
timelineChartCoordinateSystem.maxHeight = timeMachineCoordinateSystem.maxHeight
|
||||
timelineChartCoordinateSystem.maxWidth = timeMachineCoordinateSystem.maxWidth
|
||||
timelineChartCoordinateSystem.autoMinXScale = timeMachineCoordinateSystem.autoMinXScale
|
||||
timelineChartCoordinateSystem.autoMaxXScale = timeMachineCoordinateSystem.autoMaxXScale
|
||||
timelineChartCoordinateSystem.recalculateScale()
|
||||
}
|
||||
|
||||
function setTimeFrame (pTimeFrame) {
|
||||
timeFrame = pTimeFrame
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
thisObject.plotterManager.setTimeFrame(timeFrame)
|
||||
}
|
||||
}
|
||||
|
||||
function setDatetime (pDatetime) {
|
||||
datetime = pDatetime
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
thisObject.plotterManager.setDatetime(datetime)
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseOver (event) {
|
||||
/* This event gets to the timelinechart container because it inherits it from the time machine container, which is the one raising Mouse Over and Mouse not Over Events to its children. */
|
||||
drawScales = true
|
||||
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
thisObject.rateScale.onMouseOverSomeTimeMachineContainer(event)
|
||||
}
|
||||
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.onMouseOverSomeTimeMachineContainer(event)
|
||||
}
|
||||
|
||||
mouse.position.x = event.x
|
||||
mouse.position.y = event.y
|
||||
}
|
||||
|
||||
function onMouseNotOver (event) {
|
||||
/* This event is inherited from the Time Machine */
|
||||
drawScales = false
|
||||
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
thisObject.rateScale.visible = false
|
||||
}
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
function getContainer (point, purpose) {
|
||||
let container
|
||||
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) {
|
||||
container = thisObject.rateScale.getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
if (container.isForThisPurpose(purpose)) {
|
||||
return container
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) {
|
||||
container = thisObject.timeFrameScale.getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
if (container.isForThisPurpose(purpose)) {
|
||||
return container
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
function physics () {
|
||||
thisObjectPhysics()
|
||||
childrenPhysics()
|
||||
syncWithDesignerScales()
|
||||
syncWithDesignerLayersManager()
|
||||
}
|
||||
|
||||
function thisObjectPhysics () {
|
||||
/* Only if the plotter manager has some layer turned on, we will pass the min and max upstream. */
|
||||
if (thisObject.plotterManager !== undefined && thisObject.plotterManager.connectors.length > 0) {
|
||||
timelineChartCoordinateSystem.reportParentXValue(timeMachineCoordinateSystem.min.x, timeMachineCoordinateSystem.max.x)
|
||||
timelineChartCoordinateSystem.physics()
|
||||
|
||||
timeMachineCoordinateSystem.reportXValue(timelineChartCoordinateSystem.childrenMin.x)
|
||||
timeMachineCoordinateSystem.reportXValue(timelineChartCoordinateSystem.childrenMax.x)
|
||||
}
|
||||
}
|
||||
|
||||
function syncWithDesignerLayersManager () {
|
||||
if (thisObject.payload.node === undefined) {
|
||||
finalizeLayersManager()
|
||||
return
|
||||
}
|
||||
|
||||
if (thisObject.payload.node.layersManager === undefined && thisObject.layersManager !== undefined) {
|
||||
finalizeLayersManager()
|
||||
}
|
||||
if (thisObject.payload.node.layersManager !== undefined && thisObject.layersManager === undefined) {
|
||||
initializeLayersManager()
|
||||
}
|
||||
}
|
||||
|
||||
function syncWithDesignerScales () {
|
||||
if (thisObject.payload.node === undefined) {
|
||||
finalizeRateScale()
|
||||
finalizeTimeFrameScale()
|
||||
return
|
||||
}
|
||||
if (thisObject.payload.node.rateScale === undefined && thisObject.rateScale !== undefined) {
|
||||
finalizeRateScale()
|
||||
coordinateSystem = timeMachineCoordinateSystem
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
thisObject.plotterManager.setCoordinateSystem(coordinateSystem)
|
||||
}
|
||||
}
|
||||
if (thisObject.payload.node.rateScale !== undefined && thisObject.rateScale === undefined) {
|
||||
initializeRateScale()
|
||||
coordinateSystem = timelineChartCoordinateSystem
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
thisObject.plotterManager.setCoordinateSystem(coordinateSystem)
|
||||
}
|
||||
}
|
||||
if (thisObject.payload.node.timeFrameScale === undefined && thisObject.timeFrameScale !== undefined) {
|
||||
finalizeTimeFrameScale()
|
||||
}
|
||||
if (thisObject.payload.node.timeFrameScale !== undefined && thisObject.timeFrameScale === undefined) {
|
||||
initializeTimeFrameScale()
|
||||
}
|
||||
}
|
||||
|
||||
function childrenPhysics () {
|
||||
if (thisObject.rateScale !== undefined) {
|
||||
thisObject.rateScale.layersOn = thisObject.plotterManager.connectors.length
|
||||
thisObject.rateScale.physics()
|
||||
}
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.layersOn = thisObject.plotterManager.connectors.length
|
||||
thisObject.timeFrameScale.physics()
|
||||
}
|
||||
}
|
||||
|
||||
function drawBackground () {
|
||||
if (thisObject.container.frame.isInViewPort()) {
|
||||
if (drawScales === true) {
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.drawBackground() }
|
||||
}
|
||||
drawChartsBackground()
|
||||
if (thisObject.plotterManager !== undefined) {
|
||||
let elementsPlotted = thisObject.plotterManager.draw()
|
||||
if (thisObject.timeFrameScale !== undefined) {
|
||||
thisObject.timeFrameScale.adjustTimeFrame(elementsPlotted)
|
||||
} else {
|
||||
return elementsPlotted
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function draw () {
|
||||
if (thisObject.container.frame.isInViewPort()) {
|
||||
if (drawScales === true) {
|
||||
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.draw() }
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.draw() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawForeground () {
|
||||
if (thisObject.container.frame.isInViewPort()) {
|
||||
if (drawScales === true) {
|
||||
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.drawForeground() }
|
||||
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.drawForeground() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawChartsBackground () {
|
||||
drawContainerBackground(thisObject.container, UI_COLOR.WHITE, 0, thisObject.fitFunction)
|
||||
}
|
||||
}
|
||||
@@ -1,421 +0,0 @@
|
||||
|
||||
function newViewport () {
|
||||
const MODULE_NAME = 'Viewport'
|
||||
|
||||
const MIN_ZOOM_LEVEL = 0
|
||||
const MAX_ZOOM_LEVEL = 500
|
||||
|
||||
let ANIMATION_INCREMENT = 0.25
|
||||
let ANIMATION_STEPS = 5
|
||||
|
||||
let TOP_MARGIN = 40 + TOP_SPACE_HEIGHT
|
||||
let BOTTOM_MARGIN = 42 + COCKPIT_SPACE_HEIGHT
|
||||
let LEFT_MARGIN = 0
|
||||
let RIGHT_MARGIN = 0
|
||||
let MARGINS = {
|
||||
TOP: TOP_MARGIN,
|
||||
BOTTOM: BOTTOM_MARGIN,
|
||||
LEFT: LEFT_MARGIN,
|
||||
RIGHT: RIGHT_MARGIN
|
||||
}
|
||||
|
||||
let thisObject = {
|
||||
visible: false,
|
||||
visibleArea: undefined,
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
eventHandler: undefined,
|
||||
zoomTargetLevel: undefined,
|
||||
zoomLevel: undefined,
|
||||
mousePosition: undefined,
|
||||
margins: MARGINS,
|
||||
payload: undefined,
|
||||
zoomAtCenter: zoomAtCenter,
|
||||
changeZoom: changeZoom,
|
||||
onMouseWheel: onMouseWheel,
|
||||
transformThisPoint: transformThisPoint,
|
||||
unTransformThisPoint: unTransformThisPoint,
|
||||
isThisPointVisible: isThisPointVisible,
|
||||
isThisPointInViewport: isThisPointInViewport,
|
||||
fitIntoVisibleArea: fitIntoVisibleArea,
|
||||
fitIntoViewport: fitIntoViewport,
|
||||
displace: displace,
|
||||
displaceToContainer: displaceToContainer,
|
||||
physics: physics,
|
||||
raiseEvents: raiseEvents,
|
||||
resize: resize,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
let increment = 0.035
|
||||
let position = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
thisObject.mousePosition = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
thisObject.eventHandler = newEventHandler()
|
||||
|
||||
/* Initial default value */
|
||||
thisObject.zoomLevel = MIN_ZOOM_LEVEL
|
||||
thisObject.zoomTargetLevel = Math.round(MIN_ZOOM_LEVEL)
|
||||
INITIAL_TIME_PERIOD = recalculatePeriod(thisObject.zoomLevel)
|
||||
|
||||
let overrideMousePositionCounter = 0
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
thisObject.eventHandler.finalize()
|
||||
thisObject.payload = undefined
|
||||
thisObject = undefined
|
||||
}
|
||||
|
||||
function initialize () {
|
||||
if (thisObject.payload !== undefined) {
|
||||
/* Read the position from the frame structure */
|
||||
|
||||
let frame = {
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
loadFrame(thisObject.payload, frame)
|
||||
if (!isNaN(frame.position.x)) {
|
||||
position.x = frame.position.x
|
||||
}
|
||||
if (!isNaN(frame.position.y)) {
|
||||
position.y = frame.position.y
|
||||
}
|
||||
}
|
||||
|
||||
resize()
|
||||
readObjectState()
|
||||
}
|
||||
|
||||
function resize () {
|
||||
TOP_MARGIN = 40 + TOP_SPACE_HEIGHT
|
||||
BOTTOM_MARGIN = 42 + browserCanvas.height - COCKPIT_SPACE_POSITION
|
||||
LEFT_MARGIN = 0
|
||||
RIGHT_MARGIN = 0
|
||||
MARGINS = {
|
||||
TOP: TOP_MARGIN,
|
||||
BOTTOM: BOTTOM_MARGIN,
|
||||
LEFT: LEFT_MARGIN,
|
||||
RIGHT: RIGHT_MARGIN
|
||||
}
|
||||
|
||||
thisObject.visibleArea = {
|
||||
topLeft: { x: LEFT_MARGIN, y: TOP_MARGIN },
|
||||
topRight: { x: browserCanvas.width - RIGHT_MARGIN, y: TOP_MARGIN },
|
||||
bottomRight: { x: browserCanvas.width - RIGHT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN},
|
||||
bottomLeft: { x: LEFT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN}
|
||||
}
|
||||
|
||||
thisObject.width = thisObject.visibleArea.topRight.x - thisObject.visibleArea.topLeft.x
|
||||
thisObject.height = thisObject.visibleArea.bottomRight.y - thisObject.visibleArea.topLeft.y
|
||||
|
||||
thisObject.center = {
|
||||
x: LEFT_MARGIN + thisObject.width / 2,
|
||||
y: TOP_MARGIN + thisObject.height / 2
|
||||
}
|
||||
}
|
||||
|
||||
function raiseEvents () {
|
||||
if (thisObject.visible === false) { return }
|
||||
let event = {
|
||||
newPosition: position
|
||||
}
|
||||
|
||||
thisObject.eventHandler.raiseEvent('Position Changed', event)
|
||||
}
|
||||
|
||||
function displaceToContainer (container) {
|
||||
let targetPoint = {
|
||||
x: -container.frame.position.x - container.frame.width / 2,
|
||||
y: -container.frame.position.y - container.frame.height / 2
|
||||
}
|
||||
position.x = targetPoint.x + browserCanvas.width / 2
|
||||
position.y = targetPoint.y + (COCKPIT_SPACE_POSITION - TOP_SPACE_HEIGHT) / 2 + TOP_SPACE_HEIGHT
|
||||
}
|
||||
|
||||
function zoomAtCenter (level) {
|
||||
thisObject.zoomTargetLevel = Math.round(level)
|
||||
overrideMousePositionCounter = 50
|
||||
ANIMATION_INCREMENT = 0.5
|
||||
}
|
||||
|
||||
function mousePositionPhysics () {
|
||||
if (overrideMousePositionCounter > 0) {
|
||||
thisObject.mousePosition.x = browserCanvas.width / 2
|
||||
thisObject.mousePosition.y = (COCKPIT_SPACE_POSITION - TOP_SPACE_HEIGHT) / 2 + TOP_SPACE_HEIGHT
|
||||
|
||||
overrideMousePositionCounter--
|
||||
if (overrideMousePositionCounter < 0) {
|
||||
overrideMousePositionCounter = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function physics () {
|
||||
if (thisObject.visible === false) { return }
|
||||
mousePositionPhysics()
|
||||
animationPhysics()
|
||||
positioningPhysics()
|
||||
readObjectState()
|
||||
}
|
||||
|
||||
function positioningPhysics () {
|
||||
if (thisObject.visible === false) { return }
|
||||
if (thisObject.payload === undefined) { return }
|
||||
/* Save the position at the frame lavel */
|
||||
let frame = {}
|
||||
frame.position = position
|
||||
saveFrame(thisObject.payload, frame)
|
||||
}
|
||||
|
||||
function animationPhysics () {
|
||||
if (thisObject.zoomLevel < thisObject.zoomTargetLevel) {
|
||||
if (thisObject.zoomTargetLevel - thisObject.zoomLevel < ANIMATION_INCREMENT) {
|
||||
ANIMATION_INCREMENT = Math.round(Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel) * 100) / 100
|
||||
}
|
||||
thisObject.zoomLevel = Math.round((thisObject.zoomLevel + ANIMATION_INCREMENT) * 100) / 100
|
||||
changeZoom(thisObject.zoomLevel - ANIMATION_INCREMENT, thisObject.zoomLevel)
|
||||
}
|
||||
|
||||
if (thisObject.zoomLevel > thisObject.zoomTargetLevel) {
|
||||
if (thisObject.zoomLevel - thisObject.zoomTargetLevel < ANIMATION_INCREMENT) {
|
||||
ANIMATION_INCREMENT = Math.round(Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel) * 100) / 100
|
||||
}
|
||||
thisObject.zoomLevel = Math.round((thisObject.zoomLevel - ANIMATION_INCREMENT) * 100) / 100
|
||||
changeZoom(thisObject.zoomLevel + ANIMATION_INCREMENT, thisObject.zoomLevel)
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseWheel (event) {
|
||||
if (thisObject.visible === false) { return }
|
||||
if ((event.ctrlKey === true || event.metaKey === true)) { return }
|
||||
let morePower = 1
|
||||
|
||||
if (IS_MAC) {
|
||||
event.delta = event.delta * MAC_AMOUNT_FACTOR
|
||||
}
|
||||
|
||||
let amount = event.delta
|
||||
|
||||
if (event.buttons === 4) { morePower = 2 } // Mouse wheel pressed.
|
||||
/* We adjust the sensitivity for Mac Users */
|
||||
|
||||
if (thisObject.zoomTargetLevel > 10) {
|
||||
amount = amount * 2
|
||||
}
|
||||
if (thisObject.zoomTargetLevel > 25) {
|
||||
amount = amount * 3
|
||||
}
|
||||
if (thisObject.zoomTargetLevel > 50) {
|
||||
amount = amount * 3.5
|
||||
}
|
||||
|
||||
if (thisObject.zoomTargetLevel + amount * morePower > MAX_ZOOM_LEVEL) {
|
||||
return false
|
||||
}
|
||||
if (thisObject.zoomTargetLevel + amount * morePower < MIN_ZOOM_LEVEL) {
|
||||
return false
|
||||
}
|
||||
thisObject.zoomTargetLevel = Math.round(thisObject.zoomTargetLevel + amount * morePower)
|
||||
|
||||
ANIMATION_INCREMENT = Math.round(Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel) / ANIMATION_STEPS * 100) / 100
|
||||
|
||||
let newEvent = {
|
||||
newLevel: thisObject.zoomTargetLevel,
|
||||
newPosition: position,
|
||||
type: undefined,
|
||||
shiftKey: event.shiftKey
|
||||
}
|
||||
|
||||
if (amount > 0) {
|
||||
newEvent.type = 'Zoom In'
|
||||
} else {
|
||||
newEvent.type = 'Zoom Out'
|
||||
}
|
||||
|
||||
thisObject.eventHandler.raiseEvent('Zoom Changed', newEvent)
|
||||
return true
|
||||
}
|
||||
|
||||
function fitIntoVisibleArea (point) {
|
||||
let pointCopy = {
|
||||
x: point.x,
|
||||
y: point.y
|
||||
}
|
||||
|
||||
/* Here we check the boundaries of the resulting points, so they dont go out of the visible area. */
|
||||
if (pointCopy.x > thisObject.visibleArea.bottomRight.x + 1) {
|
||||
pointCopy.x = thisObject.visibleArea.bottomRight.x + 1
|
||||
}
|
||||
|
||||
if (pointCopy.x < thisObject.visibleArea.topLeft.x - 1) {
|
||||
pointCopy.x = thisObject.visibleArea.topLeft.x - 1
|
||||
}
|
||||
|
||||
if (pointCopy.y > thisObject.visibleArea.bottomRight.y + 1) {
|
||||
pointCopy.y = thisObject.visibleArea.bottomRight.y + 1
|
||||
}
|
||||
|
||||
if (pointCopy.y < thisObject.visibleArea.topLeft.y - 1) {
|
||||
pointCopy.y = thisObject.visibleArea.topLeft.y - 1
|
||||
}
|
||||
|
||||
return pointCopy
|
||||
}
|
||||
|
||||
function fitIntoViewport (point) {
|
||||
let pointCopy = {
|
||||
x: point.x,
|
||||
y: point.y
|
||||
}
|
||||
if (pointCopy.y > COCKPIT_SPACE_POSITION) {
|
||||
pointCopy.y = COCKPIT_SPACE_POSITION
|
||||
}
|
||||
return pointCopy
|
||||
}
|
||||
|
||||
function displace (displaceVector, recalculate) {
|
||||
if (thisObject.visible === false) { return }
|
||||
position.x = position.x + displaceVector.x
|
||||
position.y = position.y + displaceVector.y
|
||||
|
||||
saveObjectState()
|
||||
|
||||
let event = {
|
||||
newPosition: position,
|
||||
recalculate: recalculate
|
||||
}
|
||||
|
||||
thisObject.eventHandler.raiseEvent('Position Changed', event)
|
||||
}
|
||||
|
||||
function changeZoom (oldLevel, newLevel) {
|
||||
if (thisObject.visible === false) { return }
|
||||
let oldMouse = unTransformThisPoint(thisObject.mousePosition, oldLevel)
|
||||
let newMouse = transformThisPoint(oldMouse, newLevel)
|
||||
|
||||
position.x = position.x - newMouse.x + thisObject.mousePosition.x
|
||||
position.y = position.y - newMouse.y + thisObject.mousePosition.y
|
||||
|
||||
saveObjectState()
|
||||
|
||||
thisObject.eventHandler.raiseEvent('Zoom Changed')
|
||||
}
|
||||
|
||||
function transformThisPoint (point, level) {
|
||||
if (thisObject.visible === false) { return }
|
||||
let transformedPoint = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
if (level === undefined) {
|
||||
transformedPoint.x = point.x * (1 + thisObject.zoomLevel) + position.x
|
||||
transformedPoint.y = point.y * (1 + thisObject.zoomLevel) + position.y
|
||||
} else {
|
||||
transformedPoint.x = point.x * (1 + level) + position.x
|
||||
transformedPoint.y = point.y * (1 + level) + position.y
|
||||
}
|
||||
|
||||
return transformedPoint
|
||||
}
|
||||
|
||||
function unTransformThisPoint (point, level) {
|
||||
let pointWithoutZoom = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
if (level === undefined) {
|
||||
pointWithoutZoom.x = (point.x - position.x) / (1 + thisObject.zoomLevel)
|
||||
pointWithoutZoom.y = (point.y - position.y) / (1 + thisObject.zoomLevel)
|
||||
} else {
|
||||
pointWithoutZoom.x = (point.x - position.x) / (1 + level)
|
||||
pointWithoutZoom.y = (point.y - position.y) / (1 + level)
|
||||
}
|
||||
|
||||
return pointWithoutZoom
|
||||
}
|
||||
|
||||
function isThisPointVisible (point) {
|
||||
if (thisObject.visible === false) { return }
|
||||
if (point.x < thisObject.visibleArea.topLeft.x || point.x > thisObject.visibleArea.bottomRight.x || point.y < thisObject.visibleArea.topLeft.y || point.y > thisObject.visibleArea.bottomRight.y) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function isThisPointInViewport (point) {
|
||||
if (thisObject.visible === false) { return }
|
||||
if (point.y > COCKPIT_SPACE_POSITION) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function saveObjectState () {
|
||||
if (thisObject.payload === undefined) { return }
|
||||
|
||||
/* Save the zoom at the node config, so that the user can change it if he wishes to. */
|
||||
try {
|
||||
let code = JSON.parse(thisObject.payload.node.code)
|
||||
code.zoom = (thisObject.zoomTargetLevel - MIN_ZOOM_LEVEL) / (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) * 100
|
||||
code.zoom = code.zoom.toFixed(2)
|
||||
thisObject.payload.node.code = JSON.stringify(code)
|
||||
} catch (err) {
|
||||
// we ignore errors here since most likely they will be parsing errors.
|
||||
}
|
||||
}
|
||||
|
||||
function readObjectState () {
|
||||
if (thisObject.payload === undefined) { return }
|
||||
|
||||
/* Read the zoom level from the node config */
|
||||
try {
|
||||
let code = JSON.parse(thisObject.payload.node.code)
|
||||
|
||||
if (isNaN(code.zoom) || code.zoom === null || code.zoom === undefined) {
|
||||
saveObjectState()
|
||||
return
|
||||
}
|
||||
code.zoom = code.zoom / 100 * (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) + MIN_ZOOM_LEVEL
|
||||
if (code.zoom < MIN_ZOOM_LEVEL) { code.zoom = MIN_ZOOM_LEVEL }
|
||||
if (code.zoom > MAX_ZOOM_LEVEL) { code.zoom = MAX_ZOOM_LEVEL }
|
||||
|
||||
if (code.zoom.toFixed(2) !== thisObject.zoomTargetLevel.toFixed(2)) {
|
||||
newZoomLevel(code.zoom)
|
||||
} else {
|
||||
saveObjectState()
|
||||
}
|
||||
} catch (err) {
|
||||
// we ignore errors here since most likely they will be parsing errors.
|
||||
}
|
||||
|
||||
function newZoomLevel (level) {
|
||||
thisObject.zoomLevel = Math.round(level)
|
||||
thisObject.zoomTargetLevel = Math.round(level)
|
||||
INITIAL_TIME_PERIOD = recalculatePeriod(level)
|
||||
saveObjectState()
|
||||
ANIMATION_INCREMENT = 0
|
||||
|
||||
let event = {
|
||||
newLevel: thisObject.zoomTargetLevel,
|
||||
newPosition: position,
|
||||
type: undefined
|
||||
}
|
||||
thisObject.eventHandler.raiseEvent('Zoom Changed', event)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
|
||||
function newAssetalances () {
|
||||
const MODULE_NAME = 'Asset Balances'
|
||||
|
||||
let thisObject = {
|
||||
visible: true,
|
||||
container: undefined,
|
||||
paramsArray: undefined,
|
||||
setParamsArray: setParamsArray,
|
||||
physics: physics,
|
||||
draw: draw,
|
||||
speedometers: [],
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
|
||||
thisObject.container.isDraggeable = false
|
||||
thisObject.container.isWheelable = false
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
for (let i = 0; i < thisObject.speedometers.length; i++) {
|
||||
let speedometer = thisObject.speedometers[i]
|
||||
speedometer.finalize()
|
||||
}
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.paramsArray = undefined
|
||||
}
|
||||
|
||||
function initialize () {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
let speedometer = newSpeedometer()
|
||||
|
||||
speedometer.initialize()
|
||||
speedometer.container.connectToParent(thisObject.container)
|
||||
speedometer.container.frame.position.x = thisObject.container.frame.width / 2
|
||||
speedometer.container.frame.position.y = thisObject.container.frame.height * (2 + i * 2) / 5
|
||||
thisObject.speedometers.push(speedometer)
|
||||
}
|
||||
}
|
||||
|
||||
function getContainer (point, purpose) {
|
||||
if (thisObject.visible !== true) { return }
|
||||
|
||||
let container
|
||||
for (let i = 0; i < thisObject.speedometers.length; i++) {
|
||||
container = thisObject.speedometers[i].getContainer(point, purpose)
|
||||
if (container !== undefined) {
|
||||
if (container.isForThisPurpose(purpose)) {
|
||||
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
|
||||
return container
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
|
||||
return thisObject.container
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function setParamsArray (paramsArray) {
|
||||
thisObject.paramsArray = paramsArray
|
||||
for (let i = 0; i < thisObject.speedometers.length; i++) {
|
||||
let speedometer = thisObject.speedometers[i]
|
||||
speedometer.params = paramsArray[i]
|
||||
}
|
||||
}
|
||||
|
||||
function physics () {
|
||||
|
||||
}
|
||||
|
||||
function draw () {
|
||||
if (thisObject.visible !== true) { return }
|
||||
|
||||
for (let i = 0; i < thisObject.speedometers.length; i++) {
|
||||
let speedometer = thisObject.speedometers[i]
|
||||
speedometer.draw()
|
||||
}
|
||||
|
||||
drawQuotedAssetalances()
|
||||
}
|
||||
|
||||
function drawQuotedAssetalances () {
|
||||
if (thisObject.paramsArray === undefined) { return }
|
||||
|
||||
let fontSize
|
||||
let label
|
||||
let xOffset
|
||||
let yOffset
|
||||
|
||||
const OPACITY = 1
|
||||
|
||||
/* We put the params.VALUE in the middle */
|
||||
|
||||
fontSize = 15
|
||||
|
||||
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
|
||||
|
||||
label = 'ASSET BALANCES'
|
||||
|
||||
xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
|
||||
yOffset = -45 + 9
|
||||
|
||||
labelPoint = {
|
||||
x: 0 - xOffset + (thisObject.paramsArray[1].LEFT_OFFSET - thisObject.paramsArray[0].LEFT_OFFSET) / 2 + thisObject.paramsArray[0].LEFT_OFFSET - 20,
|
||||
y: COCKPIT_SPACE_POSITION - COCKPIT_SPACE_HEIGHT / 2 - yOffset
|
||||
}
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
|
||||
function newFullScreen () {
|
||||
const MODULE_NAME = 'Fullscreen'
|
||||
|
||||
let thisObject = {
|
||||
visible: true,
|
||||
container: undefined,
|
||||
status: undefined,
|
||||
physics: physics,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
|
||||
thisObject.container.isDraggeable = false
|
||||
thisObject.container.isWheelable = false
|
||||
thisObject.container.isClickeable = true
|
||||
thisObject.container.detectMouseOver = true
|
||||
|
||||
let selfMouseOverEventSubscriptionId
|
||||
let selfMouseClickEventSubscriptionId
|
||||
let selfMouseNotOverEventSubscriptionId
|
||||
|
||||
let isMouseOver = false
|
||||
let counterTillNextState = 0
|
||||
|
||||
let layersToTurnOn = []
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
thisObject.container.eventHandler.stopListening(selfMouseOverEventSubscriptionId)
|
||||
thisObject.container.eventHandler.stopListening(selfMouseClickEventSubscriptionId)
|
||||
thisObject.container.eventHandler.stopListening(selfMouseNotOverEventSubscriptionId)
|
||||
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
}
|
||||
|
||||
function initialize () {
|
||||
thisObject.container.frame.width = 50
|
||||
thisObject.container.frame.height = COCKPIT_SPACE_HEIGHT - 12
|
||||
|
||||
selfMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
|
||||
selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
|
||||
selfMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
|
||||
|
||||
thisObject.status = 'Ready'
|
||||
}
|
||||
|
||||
function getContainer (point, purpose) {
|
||||
if (thisObject.visible !== true) { return }
|
||||
|
||||
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
|
||||
return thisObject.container
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseOver (point) {
|
||||
if (thisObject.container.frame.isThisPointHere(point, true, false) === true) {
|
||||
isMouseOver = true
|
||||
} else {
|
||||
isMouseOver = false
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseNotOver (point) {
|
||||
isMouseOver = false
|
||||
}
|
||||
|
||||
function onMouseClick (event) {
|
||||
if (thisObject.status !== 'On') {
|
||||
thisObject.status = 'On'
|
||||
goFullscreen()
|
||||
CURRENT_TOP_MARGIN = 0
|
||||
AT_FULL_SCREEN_MODE = true
|
||||
} else {
|
||||
thisObject.status = 'Off'
|
||||
goOutFullscreen()
|
||||
CURRENT_TOP_MARGIN = window.canvasApp.topMargin
|
||||
AT_FULL_SCREEN_MODE = false
|
||||
}
|
||||
}
|
||||
|
||||
function goFullscreen () {
|
||||
if (browserCanvas.requestFullscreen) {
|
||||
browserCanvas.requestFullscreen()
|
||||
} else if (browserCanvas.mozRequestFullScreen) {
|
||||
browserCanvas.mozRequestFullScreen()
|
||||
} else if (browserCanvas.webkitRequestFullscreen) {
|
||||
browserCanvas.webkitRequestFullscreen()
|
||||
} else if (browserCanvas.msRequestFullscreen) { browserCanvas.msRequestFullscreen() }
|
||||
}
|
||||
|
||||
function goOutFullscreen () {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen()
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen()
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen()
|
||||
} else if (document.msExitFullscreen) { document.msExitFullscreen() }
|
||||
}
|
||||
|
||||
function physics () {
|
||||
positionPhysics()
|
||||
}
|
||||
|
||||
function positionPhysics () {
|
||||
thisObject.container.frame.position.x = thisObject.container.parentContainer.frame.width - thisObject.container.frame.width
|
||||
thisObject.container.frame.position.y = 6
|
||||
}
|
||||
|
||||
function draw () {
|
||||
if (thisObject.visible !== true) { return }
|
||||
drawBackground()
|
||||
drawText()
|
||||
}
|
||||
|
||||
function drawBackground () {
|
||||
let params = {
|
||||
cornerRadius: 3,
|
||||
lineWidth: 0.01,
|
||||
container: thisObject.container,
|
||||
borderColor: UI_COLOR.DARK,
|
||||
castShadow: false,
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
if (isMouseOver === true) {
|
||||
params.backgroundColor = UI_COLOR.TURQUOISE
|
||||
} else {
|
||||
params.backgroundColor = UI_COLOR.DARK_TURQUOISE
|
||||
}
|
||||
|
||||
roundedCornersBackground(params)
|
||||
}
|
||||
|
||||
function drawText () {
|
||||
let fontSize
|
||||
let label
|
||||
let xOffset
|
||||
let yOffset
|
||||
|
||||
const OPACITY = 1
|
||||
|
||||
/* We put the params.VALUE in the middle */
|
||||
|
||||
fontSize = 15
|
||||
|
||||
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
|
||||
label = 'FS'
|
||||
|
||||
let labelPoint = {
|
||||
x: thisObject.container.frame.width / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
|
||||
y: thisObject.container.frame.height - 9
|
||||
}
|
||||
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint)
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
|
||||
function newSpeedometer () {
|
||||
const MODULE_NAME = 'Speedometer'
|
||||
|
||||
let thisObject = {
|
||||
visible: true,
|
||||
container: undefined,
|
||||
params: undefined,
|
||||
physics: physics,
|
||||
draw: draw,
|
||||
getContainer: getContainer,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
}
|
||||
|
||||
thisObject.container = newContainer()
|
||||
thisObject.container.initialize(MODULE_NAME)
|
||||
|
||||
thisObject.container.isDraggeable = false
|
||||
thisObject.container.isWheelable = false
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
thisObject.container.finalize()
|
||||
thisObject.container = undefined
|
||||
thisObject.params = undefined
|
||||
}
|
||||
|
||||
function initialize () {
|
||||
|
||||
}
|
||||
|
||||
function getContainer (point, purpose) {
|
||||
if (thisObject.visible !== true) { return }
|
||||
|
||||
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
|
||||
return thisObject.container
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function physics () {
|
||||
|
||||
}
|
||||
|
||||
function draw () {
|
||||
if (thisObject.params === undefined) { return }
|
||||
drawAssetCircle()
|
||||
}
|
||||
|
||||
function drawAssetCircle () {
|
||||
const RED_LINE_HIGHT = 2
|
||||
const RADIUS = 50
|
||||
const OPACITY = 1
|
||||
|
||||
let centerPoint = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
centerPoint = thisObject.container.frame.frameThisPoint(centerPoint)
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, RADIUS + RED_LINE_HIGHT, 0 * Math.PI, 2.0 * Math.PI)
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fill()
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, RADIUS, 0.0 * Math.PI, 2.0 * Math.PI)
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fill()
|
||||
|
||||
/* We draw the circle bar */
|
||||
|
||||
const DEFAULT_THICKNESS = 2
|
||||
const VALUE_THICKNESS = 8
|
||||
const VALUE_BG_THICKNESS = 1
|
||||
const BAR_RADIUS = RADIUS * 0.85
|
||||
|
||||
let BAR_START_ANGLE = 0.85 * Math.PI
|
||||
let BAR_END_ANGLE = 2.15 * Math.PI
|
||||
let CURRENT_VALUE_ANGLE = thisObject.params.VALUE * (BAR_END_ANGLE - BAR_START_ANGLE) / thisObject.params.MAX_VALUE + BAR_START_ANGLE
|
||||
let MIN_VALUE_ANGLE = thisObject.params.MIN_VALUE * (BAR_END_ANGLE - BAR_START_ANGLE) / thisObject.params.MAX_VALUE + BAR_START_ANGLE
|
||||
let INIT_VALUE_ANGLE = thisObject.params.INIT_VALUE * (BAR_END_ANGLE - BAR_START_ANGLE) / thisObject.params.MAX_VALUE + BAR_START_ANGLE
|
||||
let PROFIT_VALUE_ANGLE = CURRENT_VALUE_ANGLE
|
||||
|
||||
if (CURRENT_VALUE_ANGLE > INIT_VALUE_ANGLE) { CURRENT_VALUE_ANGLE = INIT_VALUE_ANGLE }
|
||||
if (CURRENT_VALUE_ANGLE < MIN_VALUE_ANGLE) { CURRENT_VALUE_ANGLE = MIN_VALUE_ANGLE }
|
||||
if (PROFIT_VALUE_ANGLE > BAR_END_ANGLE) { PROFIT_VALUE_ANGLE = BAR_END_ANGLE }
|
||||
|
||||
if (
|
||||
thisObject.params.VALUE > 0 &&
|
||||
thisObject.params.ASSET_NAME === thisObject.params.BASE_ASSET &&
|
||||
thisObject.params.POSITION_TAKEN === false
|
||||
) {
|
||||
browserCanvasContext.setLineDash([0, 0])
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, BAR_START_ANGLE, MIN_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, MIN_VALUE_ANGLE, CURRENT_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, CURRENT_VALUE_ANGLE, INIT_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
if (PROFIT_VALUE_ANGLE > INIT_VALUE_ANGLE) {
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, INIT_VALUE_ANGLE, PROFIT_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
}
|
||||
|
||||
browserCanvasContext.setLineDash([2, 3])
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, BAR_START_ANGLE, MIN_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, MIN_VALUE_ANGLE, CURRENT_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, CURRENT_VALUE_ANGLE, INIT_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
|
||||
if (PROFIT_VALUE_ANGLE > INIT_VALUE_ANGLE) {
|
||||
browserCanvasContext.beginPath()
|
||||
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, INIT_VALUE_ANGLE, PROFIT_VALUE_ANGLE)
|
||||
|
||||
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.lineWidth = VALUE_THICKNESS
|
||||
browserCanvasContext.stroke()
|
||||
browserCanvasContext.closePath()
|
||||
}
|
||||
}
|
||||
|
||||
/* Common Variables */
|
||||
|
||||
let fontSize
|
||||
let label
|
||||
let xOffset
|
||||
let yOffset
|
||||
|
||||
/* We put the thisObject.params.VALUE in the middle */
|
||||
|
||||
fontSize = 22
|
||||
if (thisObject.params.VALUE > 999) {
|
||||
fontSize = 18
|
||||
}
|
||||
if (thisObject.params.VALUE > 9999) {
|
||||
fontSize = 14
|
||||
}
|
||||
if (thisObject.params.VALUE > 99999) {
|
||||
fontSize = 10
|
||||
}
|
||||
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
|
||||
|
||||
label = thisObject.params.VALUE
|
||||
|
||||
if (isNaN(label) === false) {
|
||||
label = Number(label)
|
||||
|
||||
label = dynamicDecimals(label, 2)
|
||||
if (label === 0) { label = label.toFixed(2) }
|
||||
}
|
||||
|
||||
// label = label.substring(0, 6)
|
||||
|
||||
xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO + 7
|
||||
|
||||
labelPoint = {
|
||||
x: centerPoint.x - xOffset,
|
||||
y: centerPoint.y
|
||||
}
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
|
||||
|
||||
/* We put the top label */
|
||||
|
||||
fontSize = 12
|
||||
|
||||
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
|
||||
|
||||
label = thisObject.params.ASSET_LABEL
|
||||
|
||||
xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO + 3
|
||||
yOffset = 22
|
||||
|
||||
labelPoint = {
|
||||
x: centerPoint.x - xOffset,
|
||||
y: centerPoint.y - yOffset
|
||||
}
|
||||
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
|
||||
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
|
||||
|
||||
/* We put the bottom label */
|
||||
|
||||
fontSize = 12
|
||||
|
||||
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
|
||||
|
||||
label = thisObject.params.ASSET_NAME + ' '
|
||||
|
||||
xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO + 3
|
||||
yOffset = -15
|
||||
|
||||
labelPoint = {
|
||||
x: centerPoint.x - xOffset,
|
||||
y: centerPoint.y - yOffset
|
||||
}
|
||||
|
||||
if (thisObject.params.ASSET_NAME === thisObject.params.BASE_ASSET) {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + OPACITY + ')'
|
||||
} else {
|
||||
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
|
||||
}
|
||||
|
||||
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
|
||||
function newContainer () {
|
||||
let thisObject = {
|
||||
id: newUniqueId(),
|
||||
type: 'Rectangle',
|
||||
frame: undefined,
|
||||
eventHandler: undefined,
|
||||
parentContainer: undefined,
|
||||
isDraggeable: true,
|
||||
notDraggingOnX: false,
|
||||
notDraggingOnY: false,
|
||||
isClickeable: false,
|
||||
isWheelable: false,
|
||||
detectMouseOver: false,
|
||||
name: undefined,
|
||||
fitFunction: undefined,
|
||||
isVisibleFunction: undefined,
|
||||
displace: displace,
|
||||
initialize: initialize,
|
||||
finalize: finalize,
|
||||
connectToParent: connectToParent,
|
||||
isForThisPurpose: isForThisPurpose
|
||||
}
|
||||
|
||||
let connectedToParentWidth = false
|
||||
let connectedToParentHeight = false
|
||||
let connectedToParentRadius = false
|
||||
|
||||
let onDimmensionsChangedParentEvent = false
|
||||
let onMouseOverParentEvent = false
|
||||
let onMouseNotOverParentEvent = false
|
||||
let onFocusParentEvent = false
|
||||
let onNotFocusParentEvent = false
|
||||
let onDisplaceParentEvent = false
|
||||
let onDragStartedParentEvent = false
|
||||
let onDragFinishedParentEvent = false
|
||||
|
||||
let isConnectedToParent = false
|
||||
|
||||
let dimensionsChangedEventSubscriptionId
|
||||
let onMouseOverEventSubscriptionId
|
||||
let onMouseNotOverEventSubscriptionId
|
||||
let onFocusEventSubscriptionId
|
||||
let onNotFocusEventSubscriptionId
|
||||
let onDisplaceEventSubscriptionId
|
||||
let onDragStartedEventSubscriptionId
|
||||
let onDragFinishedEventSubscriptionId
|
||||
|
||||
return thisObject
|
||||
|
||||
function finalize () {
|
||||
if (isConnectedToParent === true) {
|
||||
thisObject.parentContainer.eventHandler.stopListening(dimensionsChangedEventSubscriptionId)
|
||||
thisObject.parentContainer.eventHandler.stopListening(onMouseOverEventSubscriptionId)
|
||||
thisObject.parentContainer.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
|
||||
thisObject.parentContainer.eventHandler.stopListening(onFocusEventSubscriptionId)
|
||||
thisObject.parentContainer.eventHandler.stopListening(onNotFocusEventSubscriptionId)
|
||||
thisObject.parentContainer.eventHandler.stopListening(onDisplaceEventSubscriptionId)
|
||||
thisObject.parentContainer.eventHandler.stopListening(onDragStartedEventSubscriptionId)
|
||||
thisObject.parentContainer.eventHandler.stopListening(onDragFinishedEventSubscriptionId)
|
||||
|
||||
thisObject.parentContainer = undefined
|
||||
thisObject.eventHandler.finalize()
|
||||
|
||||
thisObject.frame.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
function initialize (pName, pType) {
|
||||
thisObject.name = pName
|
||||
thisObject.type = pType
|
||||
|
||||
thisObject.frame = newFrame()
|
||||
thisObject.frame.initialize(pType)
|
||||
if (pName !== undefined) {
|
||||
thisObject.frame.containerName = pName
|
||||
}
|
||||
thisObject.frame.container = thisObject
|
||||
|
||||
thisObject.eventHandler = newEventHandler()
|
||||
thisObject.eventHandler.name = pName
|
||||
}
|
||||
|
||||
function connectToParent (
|
||||
parentContainer,
|
||||
onWidth,
|
||||
onHeight,
|
||||
onRadius,
|
||||
onDimmensionsChangedEvent,
|
||||
onMouseOverEvent,
|
||||
onMouseNotOverEvent,
|
||||
onFocusEvent,
|
||||
onNotFocusEvent,
|
||||
onDisplaceEvent,
|
||||
onDragStartedEvent,
|
||||
onDragFinishedEvent
|
||||
) {
|
||||
connectedToParentWidth = onWidth
|
||||
connectedToParentHeight = onHeight
|
||||
connectedToParentRadius = onRadius
|
||||
|
||||
onDimmensionsChangedParentEvent = onDimmensionsChangedEvent
|
||||
onMouseOverParentEvent = onMouseOverEvent
|
||||
onMouseNotOverParentEvent = onMouseNotOverEvent
|
||||
onFocusParentEvent = onFocusEvent
|
||||
onNotFocusParentEvent = onNotFocusEvent
|
||||
onDisplaceParentEvent = onDisplaceEvent
|
||||
onDragStartedParentEvent = onDragStartedEvent
|
||||
onDragFinishedParentEvent = onDragFinishedEvent
|
||||
|
||||
isConnectedToParent = true
|
||||
|
||||
thisObject.frame.parentFrame = parentContainer.frame
|
||||
thisObject.parentContainer = parentContainer
|
||||
|
||||
if (onDimmensionsChangedParentEvent === true) {
|
||||
dimensionsChangedEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('Dimmensions Changed', onParentDimmensionsChanged)
|
||||
}
|
||||
if (onMouseOverParentEvent === true) {
|
||||
onMouseOverEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onMouseOver', onMouseOver)
|
||||
}
|
||||
if (onMouseNotOverParentEvent === true) {
|
||||
onMouseNotOverEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
|
||||
}
|
||||
if (onFocusParentEvent === true) {
|
||||
onFocusEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onFocus', onFocus)
|
||||
}
|
||||
if (onNotFocusParentEvent === true) {
|
||||
onNotFocusEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onNotFocus', onNotFocus)
|
||||
}
|
||||
if (onDisplaceParentEvent === true) {
|
||||
onDisplaceEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onDisplace', onDisplace)
|
||||
}
|
||||
if (onDragStartedParentEvent === true) {
|
||||
onDragStartedEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onDragStarted', onDragStarted)
|
||||
}
|
||||
if (onDragFinishedParentEvent === true) {
|
||||
onDragFinishedEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onDragFinished', onDragFinished)
|
||||
}
|
||||
|
||||
if (connectedToParentWidth) {
|
||||
thisObject.frame.width = thisObject.parentContainer.frame.width
|
||||
}
|
||||
if (connectedToParentHeight) {
|
||||
thisObject.frame.height = thisObject.parentContainer.frame.height
|
||||
}
|
||||
if (connectedToParentRadius) {
|
||||
thisObject.frame.radius = thisObject.parentContainer.frame.radius
|
||||
}
|
||||
}
|
||||
|
||||
function onParentDimmensionsChanged (event) {
|
||||
let dimmensionsChanged = false
|
||||
if (connectedToParentWidth) {
|
||||
thisObject.frame.width = thisObject.parentContainer.frame.width
|
||||
dimmensionsChanged = true
|
||||
}
|
||||
if (connectedToParentHeight) {
|
||||
thisObject.frame.height = thisObject.parentContainer.frame.height
|
||||
dimmensionsChanged = true
|
||||
}
|
||||
if (connectedToParentRadius) {
|
||||
thisObject.frame.radius = thisObject.parentContainer.frame.radius
|
||||
dimmensionsChanged = true
|
||||
}
|
||||
|
||||
if (dimmensionsChanged) {
|
||||
thisObject.eventHandler.raiseEvent('Dimmensions Changed', event)
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseOver (event) {
|
||||
thisObject.eventHandler.raiseEvent('onMouseOver', event)
|
||||
}
|
||||
|
||||
function onMouseNotOver (event) {
|
||||
thisObject.eventHandler.raiseEvent('onMouseNotOver', event)
|
||||
}
|
||||
|
||||
function onFocus (event) {
|
||||
thisObject.eventHandler.raiseEvent('onFocus', event)
|
||||
}
|
||||
|
||||
function onNotFocus (event) {
|
||||
thisObject.eventHandler.raiseEvent('onNotFocus', event)
|
||||
}
|
||||
|
||||
function onDisplace (event) {
|
||||
thisObject.eventHandler.raiseEvent('onDisplace', event)
|
||||
}
|
||||
|
||||
function onDragStarted (event) {
|
||||
thisObject.eventHandler.raiseEvent('onDragStarted', event)
|
||||
}
|
||||
|
||||
function onDragFinished (event) {
|
||||
thisObject.eventHandler.raiseEvent('onDragFinished', event)
|
||||
}
|
||||
|
||||
function isForThisPurpose (purpose) {
|
||||
if (purpose !== undefined) {
|
||||
switch (purpose) {
|
||||
case GET_CONTAINER_PURPOSE.MOUSE_OVER:
|
||||
if (thisObject.detectMouseOver === true) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
case GET_CONTAINER_PURPOSE.MOUSE_WHEEL:
|
||||
if (thisObject.isWheelable === true) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
case GET_CONTAINER_PURPOSE.MOUSE_CLICK:
|
||||
if (thisObject.isClickeable === true) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
case GET_CONTAINER_PURPOSE.DRAGGING:
|
||||
if (thisObject.isDraggeable === true) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
default: { return false }
|
||||
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function displace (point) {
|
||||
/* This function will move the container according to the vector received. If it has a visible function will use it
|
||||
to see if the container can be moved there or not. It wont if the center will not be visible.
|
||||
|
||||
Returns true if move was possible, false if not. */
|
||||
|
||||
let checkPoint = {}
|
||||
|
||||
if (thisObject.isVisibleFunction === undefined) {
|
||||
drag()
|
||||
return true
|
||||
} else {
|
||||
checkPoint.x = thisObject.frame.position.x + point.x + thisObject.frame.width / 2
|
||||
checkPoint.y = thisObject.frame.position.y + point.y + thisObject.frame.height / 2
|
||||
let isVisible = thisObject.isVisibleFunction(checkPoint)
|
||||
if (isVisible === true) {
|
||||
drag()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
function drag () {
|
||||
if (thisObject.notDraggingOnX === false) {
|
||||
thisObject.frame.position.x = thisObject.frame.position.x + point.x
|
||||
}
|
||||
if (thisObject.notDraggingOnY === false) {
|
||||
thisObject.frame.position.y = thisObject.frame.position.y + point.y
|
||||
}
|
||||
thisObject.eventHandler.raiseEvent('onDisplace', event)
|
||||
}
|
||||
}
|
||||
}
|
||||