Missing Files

This commit is contained in:
Luis Fernando Molina committed 2020-10-21 19:00:09 +02:00
1 parent f68ebb63ca
commit 6bcce5b25f
100 files changed
+27338

No files matched your search

@@ -0,0 +1,37 @@
function newEthereumActionSwitch() {
let thisObject = {
executeAction: executeAction,
initialize: initialize,
finalize: finalize
}
let functionLibraryGeth = newGeth()
return thisObject
function finalize() {
functionLibraryGeth = undefined
}
function initialize() {
/* Nothing to initialize since a Function Library does not hold any state. */
}
async function executeAction(action) {
switch (action.name) {
case 'Install Geth': {
functionLibraryGeth.install(action.node)
break
}
case 'Run Geth': {
functionLibraryGeth.run(action.node)
break
}
case 'Stop Geth': {
functionLibraryGeth.stop(action.node)
break
}
}
}
}
@@ -0,0 +1,21 @@
function newGeth() {
thisObject = {
install: install,
run: run,
stop: stop
}
return thisObject
function install(node) {
callWebServer('ExecuteTerminalCommand/dir')
}
function run(node) {
}
function stop(node) {
}
}
@@ -0,0 +1,546 @@
function newSuperalgosActionSwitch() {
let thisObject = {
executeAction: executeAction,
initialize: initialize,
finalize: finalize
}
let functionLibraryReferenceAttachDetach = newReferenceAttachDetach()
let functionLibraryChainAttachDetach = newChainAttachDetach()
let functionLibraryNodeDeleter = newNodeDeleter()
let functionLibraryUiObjectsFromNodes = newUiObjectsFromNodes()
let functionLibraryProtocolNode = newProtocolNode()
let functionLibraryNodeCloning = newNodeCloning()
let functionLibraryShortcutKeys = newShortcutKeys()
let functionLibraryOnFocus = newOnFocus()
let functionLibrarySuperScripts = newSuperScriptsFunctions()
let functionLibraryWebhookFunctions = newWebhookFunctions()
let functionLibraryDependenciesFilter = newDependenciesFilter()
let functionLibraryNodePath = newNodePath()
let functionLibraryTaskFunctions = newTaskFunctions()
let functionLibrarySessionFunctions = newSessionFunctions()
let functionLibraryCryptoEcosystemFunctions = newCryptoEcosystemFunctions()
let functionLibraryDataMineFunctions = newDataMineFunctions()
let functionLibraryDataStorageFunctions = newDataStorageFunctions()
let functionLibraryChartingSpaceFunctions = newChartingSpaceFunctions()
let functionLibraryPluginsFunctions = newPluginsFunctions()
return thisObject
function finalize() {
functionLibraryReferenceAttachDetach = undefined
functionLibraryChainAttachDetach = undefined
functionLibraryNodeDeleter = undefined
functionLibraryUiObjectsFromNodes = undefined
functionLibraryProtocolNode = undefined
functionLibraryNodeCloning = undefined
functionLibraryShortcutKeys = undefined
functionLibraryOnFocus = undefined
functionLibrarySuperScripts = undefined
functionLibraryWebhookFunctions = undefined
functionLibraryDependenciesFilter = undefined
functionLibraryNodePath = undefined
functionLibraryTaskFunctions = undefined
functionLibrarySessionFunctions = undefined
functionLibraryCryptoEcosystemFunctions = undefined
functionLibraryDataMineFunctions = undefined
functionLibraryDataStorageFunctions = undefined
functionLibraryChartingSpaceFunctions = undefined
functionLibraryPluginsFunctions = undefined
}
function initialize() {
/* Nothing to initialize since a Function Library does not hold any state. */
}
async function executeAction(action) {
switch (action.name) {
case 'Get Node On Focus': {
return functionLibraryOnFocus.getNodeThatIsOnFocus(action.node)
}
case 'Get Node By Shortcut Key': {
return functionLibraryShortcutKeys.getNodeByShortcutKey(action.node, action.extraParameter)
}
case 'Get Node Data Structure': {
return functionLibraryProtocolNode.getProtocolNode(action.node, action.extraParameter, false, true, true, true)
}
case 'Create UI Object': {
functionLibraryUiObjectsFromNodes.createUiObjectFromNode(action.node, undefined, undefined, action.extraParameter)
}
break
case 'Connect Children to Reference Parents': {
functionLibraryUiObjectsFromNodes.tryToConnectChildrenWithReferenceParents()
}
break
case 'Get Node By Id': {
return functionLibraryUiObjectsFromNodes.getNodeById(action.relatedNodeId)
}
case 'Syncronize Tasks': {
functionLibraryUiObjectsFromNodes.syncronizeTasksFoundAtWorkspaceWithBackEnd(functionLibraryTaskFunctions)
}
break
case 'Syncronize Sessions': {
functionLibraryUiObjectsFromNodes.syncronizeSessionsFoundAtWorkspaceWithBackEnd(functionLibrarySessionFunctions)
}
break
case 'Play Tutorials': {
functionLibraryUiObjectsFromNodes.playTutorials()
}
break
case 'Recreate Workspace': {
functionLibraryUiObjectsFromNodes.recreateWorkspace(action.node, action.callBackFunction)
}
break
case 'Delete Workspace': {
functionLibraryNodeDeleter.deleteWorkspace(action.node, action.rootNodes)
}
break
case 'Copy Node Path':
{
let nodePath = functionLibraryNodePath.getNodePath(action.node)
UI.projects.superalgos.utilities.clipboard.copyTextToClipboard(nodePath)
UI.projects.superalgos.spaces.cockpitSpace.setStatus(
nodePath + ' copied to the Clipboard.'
, 50, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.ALL_GOOD)
}
break
case 'Add UI Object':
{
functionLibraryUiObjectsFromNodes.addUIObject(action.node, action.relatedNodeType, action.rootNodes)
}
break
case 'Add Missing Children':
{
functionLibraryUiObjectsFromNodes.addMissingChildren(action.node)
}
break
case 'Delete UI Object':
{
functionLibraryNodeDeleter.deleteUIObject(action.node, action.rootNodes)
}
break
case 'Edit Code':
break
case 'Share':
{
let text = JSON.stringify(functionLibraryProtocolNode.getProtocolNode(action.node, true, false, true, true, true))
let nodeName = action.node.name
if (nodeName === undefined) {
nodeName = ''
} else {
nodeName = '.' + nodeName
}
let fileName = 'Share - ' + action.node.type + ' - ' + nodeName + '.json'
UI.projects.superalgos.utilities.download.downloadText(fileName, text)
}
break
case 'Backup':
{
let text = JSON.stringify(functionLibraryProtocolNode.getProtocolNode(action.node, false, false, true, true, true))
let nodeName = action.node.name
if (nodeName === undefined) {
nodeName = ''
} else {
nodeName = ' ' + nodeName
}
let fileName = 'Backup - ' + action.node.type + ' - ' + nodeName + '.json'
UI.projects.superalgos.utilities.download.downloadText(fileName, text)
}
break
case 'Clone':
{
let text = JSON.stringify(functionLibraryNodeCloning.getNodeClone(action.node))
let nodeName = action.node.name
if (nodeName === undefined) {
nodeName = ''
} else {
nodeName = ' ' + nodeName
}
let fileName = 'Clone - ' + action.node.type + ' - ' + nodeName + '.json'
UI.projects.superalgos.utilities.download.downloadText(fileName, text)
}
break
case 'Debug Task':
{
functionLibraryTaskFunctions.runTask(action.node, functionLibraryProtocolNode, true, action.callBackFunction)
}
break
case 'Run Task':
{
functionLibraryTaskFunctions.runTask(action.node, functionLibraryProtocolNode, false, action.callBackFunction)
}
break
case 'Stop Task':
{
functionLibraryTaskFunctions.stopTask(action.node, functionLibraryProtocolNode, action.callBackFunction)
}
break
case 'Run All Tasks':
{
functionLibraryTaskFunctions.runAllTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Tasks':
{
functionLibraryTaskFunctions.stopAllTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Run All Task Managers':
{
functionLibraryTaskFunctions.runAllTaskManagers(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Task Managers':
{
functionLibraryTaskFunctions.stopAllTaskManagers(action.node, functionLibraryProtocolNode)
}
break
case 'Run All Exchange Data Tasks':
{
functionLibraryTaskFunctions.runAllExchangeDataTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Exchange Data Tasks':
{
functionLibraryTaskFunctions.stopAllExchangeDataTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Run All Exchange Trading Tasks':
{
functionLibraryTaskFunctions.runAllExchangeTradingTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Exchange Trading Tasks':
{
functionLibraryTaskFunctions.stopAllExchangeTradingTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Run All Market Data Tasks':
{
functionLibraryTaskFunctions.runAllMarketDataTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Market Data Tasks':
{
functionLibraryTaskFunctions.stopAllMarketDataTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Run All Market Trading Tasks':
{
functionLibraryTaskFunctions.runAllMarketTradingTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Market Trading Tasks':
{
functionLibraryTaskFunctions.stopAllMarketTradingTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Run All Data Mine Tasks':
{
functionLibraryTaskFunctions.runAllDataMineTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Data Mine Tasks':
{
functionLibraryTaskFunctions.stopAllDataMineTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Run All Trading Mine Tasks':
{
functionLibraryTaskFunctions.runAllTradingMineTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Stop All Trading Mine Tasks':
{
functionLibraryTaskFunctions.stopAllTradingMineTasks(action.node, functionLibraryProtocolNode)
}
break
case 'Add Missing Exchange Data Tasks':
{
functionLibraryTaskFunctions.addMissingExchangeDataTasks(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Market Data Tasks':
{
functionLibraryTaskFunctions.addMissingMarketDataTasks(action.node, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Data Mine Tasks':
{
functionLibraryTaskFunctions.addMissingDataMineTasks(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Exchange Trading Tasks':
{
functionLibraryTaskFunctions.addMissingExchangeTradingTasks(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Market Trading Tasks':
{
functionLibraryTaskFunctions.addMissingMarketTradingTasks(action.node, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Trading Mine Tasks':
{
functionLibraryTaskFunctions.addMissingTradingMineTasks(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add All Tasks':
{
functionLibraryTaskFunctions.addAllTasks(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Crypto Exchanges':
{
functionLibraryCryptoEcosystemFunctions.addMissingExchanges(action.node, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Assets':
{
functionLibraryCryptoEcosystemFunctions.addMissingAssets(action.node, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Markets':
{
functionLibraryCryptoEcosystemFunctions.addMissingMarkets(action.node, functionLibraryUiObjectsFromNodes, functionLibraryNodeCloning)
}
break
case 'Install Market':
{
functionLibraryCryptoEcosystemFunctions.installMarket(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter, functionLibraryChartingSpaceFunctions, functionLibraryDataStorageFunctions)
}
break
case 'Uninstall Market':
{
functionLibraryCryptoEcosystemFunctions.uninstallMarket(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter, functionLibraryChartingSpaceFunctions, functionLibraryDataStorageFunctions)
}
break
case 'Add All Output Datasets':
{
functionLibraryDataMineFunctions.addAllOutputDatasets(action.node, functionLibraryUiObjectsFromNodes)
}
break
case 'Add All Data Products':
{
functionLibraryDataStorageFunctions.addAllDataProducts(action.node, functionLibraryUiObjectsFromNodes)
}
break
case 'Add All Data Mine Products':
{
functionLibraryDataStorageFunctions.addAllDataMineProducts(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add All Trading Mine Products':
{
functionLibraryDataStorageFunctions.addAllTradingMineProducts(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Session References':
{
functionLibraryDataStorageFunctions.addMissingSessionReferences(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Market Data Products':
{
functionLibraryDataStorageFunctions.addMissingMarketDataProducts(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Market Trading Products':
{
functionLibraryDataStorageFunctions.addMissingMarketTradingProducts(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Exchange Trading Products':
{
functionLibraryDataStorageFunctions.addMissingExchangeTradingProducts(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Exchange Data Products':
{
functionLibraryDataStorageFunctions.addMissingExchangeDataProducts(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add All Data Dependencies':
{
functionLibraryDataMineFunctions.addAllDataDependencies(action.node, functionLibraryUiObjectsFromNodes)
}
break
case 'Add All Data Mine Dependencies':
{
functionLibraryDataMineFunctions.addAllDataMineDataDependencies(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add All Mine Layers':
{
functionLibraryChartingSpaceFunctions.addAllMineLayers(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
}
break
case 'Add Missing Time Machines':
{
functionLibraryChartingSpaceFunctions.addMissingTimeMachines(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
}
break
case 'Add Missing Dashboards':
{
functionLibraryChartingSpaceFunctions.addMissingDashboards(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
}
break
case 'Play Tutorial':
{
UI.projects.superalgos.spaces.tutorialSpace.playTutorial(action.node)
}
break
case 'Play Tutorial Topic':
{
UI.projects.superalgos.spaces.tutorialSpace.playTutorialTopic(action.node)
}
break
case 'Play Tutorial Step':
{
UI.projects.superalgos.spaces.tutorialSpace.playTutorialStep(action.node)
}
break
case 'Resume Tutorial':
{
UI.projects.superalgos.spaces.tutorialSpace.resumeTutorial(action.node)
}
break
case 'Resume Tutorial Topic':
{
UI.projects.superalgos.spaces.tutorialSpace.resumeTutorialTopic(action.node)
}
break
case 'Resume Tutorial Step':
{
UI.projects.superalgos.spaces.tutorialSpace.resumeTutorialStep(action.node)
}
break
case 'Reset Tutorial Progress':
{
UI.projects.superalgos.spaces.tutorialSpace.resetTutorialProgress(action.node)
}
break
case 'Send Webhook Test Message':
{
functionLibraryWebhookFunctions.sendTestMessage(action.node, action.callBackFunction)
}
break
case 'Run Session':
{
functionLibrarySessionFunctions.runSession(action.node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, false, action.callBackFunction)
}
break
case 'Resume Session':
{
functionLibrarySessionFunctions.runSession(action.node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, true, action.callBackFunction)
}
break
case 'Stop Session':
{
functionLibrarySessionFunctions.stopSession(action.node, functionLibraryProtocolNode, action.callBackFunction)
}
break
case 'Run Super Action':
{
functionLibrarySuperScripts.runSuperScript(action.node, action.rootNodes, functionLibraryNodeCloning, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
}
break
case 'Parent Attach': {
functionLibraryChainAttachDetach.chainAttachNode(action.node, action.relatedNode, action.rootNodes)
}
break
case 'Reference Attach': {
functionLibraryReferenceAttachDetach.referenceAttachNode(action.node, action.relatedNode, action.rootNodes)
}
break
case 'Parent Detach':
{
functionLibraryChainAttachDetach.chainDetachNode(action.node, action.rootNodes)
}
break
case 'Reference Detach':
{
functionLibraryReferenceAttachDetach.referenceDetachNode(action.node)
}
break
case 'Push Code to Javascript Code':
{
action.node.javascriptCode.code = action.node.code
}
break
case 'Fetch Code to Javascript Code':
{
action.node.code = action.node.javascriptCode.code
}
break
case 'Open Documentation':
{
let definition = getNodeDefinition(action.node)
if (definition !== undefined) {
if (definition.docURL !== undefined) {
UI.projects.superalgos.spaces.docSpace.navigateTo(definition.docURL)
} else {
let headName = UI.projects.superalgos.utilities.hierarchy.getHiriarchyHead(action.node).type
headName = headName.toLowerCase()
headName = headName.split(" ").join("-")
let nodeName = action.node.type
nodeName = nodeName.toLowerCase()
nodeName = nodeName.split(" ").join("-")
url = UI.projects.superalgos.globals.docs.DOCUMENTATION_URL_PREFIX + "suite-hierarchy-" + headName + ".html#" + nodeName
UI.projects.superalgos.spaces.docSpace.navigateTo(url)
}
}
}
break
case 'Add Missing Plugin Projects':
{
functionLibraryPluginsFunctions.pluginMissingProjects(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Plugin Data Mines':
{
functionLibraryPluginsFunctions.pluginMissingDataMines(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Plugin Trading Mines':
{
functionLibraryPluginsFunctions.pluginMissingTradingMines(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Plugin Trading Systems':
{
functionLibraryPluginsFunctions.pluginMissingTradingSystems(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Plugin Trading Engines':
{
functionLibraryPluginsFunctions.pluginMissingTradingEngines(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Plugin Super Scripts':
{
functionLibraryPluginsFunctions.pluginMissingSuperScripts(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
case 'Add Missing Plugin Tutorials':
{
functionLibraryPluginsFunctions.pluginMissingTutorials(action.node, action.rootNodes, functionLibraryUiObjectsFromNodes)
}
break
}
}
}
@@ -0,0 +1,221 @@
function newChainAttachDetach() {
thisObject = {
chainDetachNode: chainDetachNode,
chainAttachNode: chainAttachNode
}
return thisObject
function chainDetachNode(node, rootNodes) {
if (node.payload.parentNode === undefined) { return }
switch (node.type) {
case 'Phase': {
let payload = node.payload
for (let i = 0; i < payload.parentNode.phases.length; i++) {
let phase = payload.parentNode.phases[i]
if (phase.id === node.id) {
if (i < payload.parentNode.phases.length - 1) {
let nextPhase = payload.parentNode.phases[i + 1]
if (i > 0) {
let previousPhase = payload.parentNode.phases[i - 1]
nextPhase.payload.chainParent = previousPhase
} else {
nextPhase.payload.chainParent = payload.parentNode
}
}
payload.parentNode.phases.splice(i, 1)
completeDetachment(node, rootNodes)
return
}
}
return
}
default: {
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
/* Detach from parent */
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = getNodeDefinition(node.payload.parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (nodeDefinition.propertyNameAtParent === property.name) {
switch (property.type) {
case 'node': {
node.payload.parentNode[property.name] = undefined
}
break
case 'array': {
let nodePropertyArray = node.payload.parentNode[property.name]
if (nodePropertyArray !== undefined) {
for (let j = 0; j < nodePropertyArray.length; j++) {
let arrayItem = nodePropertyArray[j]
if (arrayItem.id === node.id) {
nodePropertyArray.splice(j, 1)
}
}
}
}
break
}
}
}
}
}
}
completeDetachment(node, rootNodes)
}
}
}
}
function chainAttachNode(node, attachToNode, rootNodes) {
switch (node.type) {
case 'Exchange Account Key': {
node.payload.parentNode = attachToNode
node.payload.chainParent = attachToNode
if (node.payload.parentNode.keys !== undefined) {
node.payload.parentNode.keys.push(node)
} else {
node.payload.parentNode.key = node
}
completeAttachment(node, rootNodes)
}
break
case 'Phase': {
switch (attachToNode.type) {
case 'Stop': {
node.payload.parentNode = attachToNode
if (attachToNode.phases.length > 0) {
let phase = attachToNode.phases[attachToNode.phases.length - 1]
node.payload.chainParent = phase
} else {
node.payload.chainParent = attachToNode
}
attachToNode.phases.push(node)
completeAttachment(node, rootNodes)
}
break
case 'Take Profit': {
node.payload.parentNode = attachToNode
if (attachToNode.phases.length > 0) {
let phase = attachToNode.phases[attachToNode.phases.length - 1]
node.payload.chainParent = phase
} else {
node.payload.chainParent = attachToNode
}
attachToNode.phases.push(node)
completeAttachment(node, rootNodes)
}
break
case 'Initial Stop': {
if (attachToNode.phases.length >= 1) {
return
}
node.payload.parentNode = attachToNode
if (attachToNode.phases.length > 0) {
let phase = attachToNode.phases[attachToNode.phases.length - 1]
node.payload.chainParent = phase
} else {
node.payload.chainParent = attachToNode
}
attachToNode.phases.push(node)
completeAttachment(node, rootNodes)
}
break
case 'Initial Take Profit': {
if (attachToNode.phases.length >= 1) {
return
}
node.payload.parentNode = attachToNode
if (attachToNode.phases.length > 0) {
let phase = attachToNode.phases[attachToNode.phases.length - 1]
node.payload.chainParent = phase
} else {
node.payload.chainParent = attachToNode
}
attachToNode.phases.push(node)
completeAttachment(node, rootNodes)
}
break
case 'Phase': {
node.payload.parentNode = attachToNode.payload.parentNode
for (let i = 0; i < node.payload.parentNode.phases.length; i++) {
let phase = node.payload.parentNode.phases[i]
if (attachToNode.id === phase.id) {
if (i === node.payload.parentNode.phases.length - 1) {
node.payload.chainParent = attachToNode
node.payload.parentNode.phases.push(node)
completeAttachment(node, rootNodes)
} else {
node.payload.chainParent = attachToNode
let nextPhase = node.payload.parentNode.phases[i + 1]
nextPhase.payload.chainParent = node
node.payload.parentNode.phases.splice(i + 1, 0, node)
completeAttachment(node, rootNodes)
return
}
}
}
}
}
}
break
default: {
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
node.payload.parentNode = attachToNode
node.payload.chainParent = attachToNode
/* Attach to new parent */
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = getNodeDefinition(node.payload.parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (nodeDefinition.propertyNameAtParent === property.name) {
switch (property.type) {
case 'node': {
node.payload.parentNode[property.name] = node
}
break
case 'array': {
if (node.payload.parentNode[property.name] === undefined) {
node.payload.parentNode[property.name] = []
}
let nodePropertyArray = node.payload.parentNode[property.name]
nodePropertyArray.push(node)
}
break
}
}
}
}
}
}
completeAttachment(node, rootNodes)
}
}
}
}
function completeDetachment(node, rootNodes) {
node.payload.parentNode = undefined
node.payload.chainParent = undefined
rootNodes.push(node)
}
function completeAttachment(node, rootNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.id === node.id) {
rootNodes.splice(i, 1)
return
}
}
}
}
@@ -0,0 +1,247 @@
function newChartingSpaceFunctions() {
thisObject = {
addAllMineLayers: addAllMineLayers,
addMissingDashboards: addMissingDashboards,
addMissingTimeMachines: addMissingTimeMachines,
createTimeMachine: createTimeMachine
}
return thisObject
function addAllMineLayers(node, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter) {
/* Validations to see if we can do this or not. */
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a reference parent node to execute this action.')
return
}
if (node.payload.referenceParent.payload === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a reference parent node to execute this action.')
return
}
/*
We are going to go through the referenced branch and recreate the structure
we find there inside the layers manager. We will end up having at the end
all layers referencing the data products inside the referenced branch.
*/
let dataMine = node.payload.referenceParent
scanBotArray(dataMine.botProducts)
function scanBotArray(botArray) {
for (let i = 0; i < botArray.length; i++) {
let bot = botArray[i]
let botLayers = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Bot Layers')
botLayers.name = bot.name
UI.projects.superalgos.utilities.folders.asymetricalFolderStructureCloning(
bot,
botLayers,
'dataProducts',
'dataProductFolders',
'layerFolders',
'Layer',
'Layer Folder',
undefined,
functionLibraryUiObjectsFromNodes
)
/*
There are some layers that should not exist, for example the ones related to Data Products
that do not have a plotter module. Since our previous action created all layers no matter
what, we need now to delete all the ones that do not have a plotter module.
*/
let allLayers = UI.projects.superalgos.utilities.branches.nodeBranchToArray(botLayers, 'Layer')
for (let j = 0; j < allLayers.length; j++) {
let layer = allLayers[j]
layer.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_45
let plotterModule = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(layer, 'Plotter Module', undefined, true, false, false, true)
if (plotterModule === undefined) {
functionLibraryNodeDeleter.deleteUIObject(layer, rootNodes)
}
}
}
}
}
function addMissingTimeMachines(node, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter) {
if (node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('This node needs to have a Reference Parent for this command tu run.')
return
}
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Network') {
let networkNode = rootNode
scanNetworkNode(networkNode)
}
}
function scanNetworkNode(networkNode) {
if (networkNode === undefined) { return }
let backtestingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Backtesting Session')
let fordwardTestingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Forward Testing Session')
let paperTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Paper Trading Session')
let liveTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Live Trading Session')
scanSessionArray(backtestingSessionsArray)
scanSessionArray(fordwardTestingSessionsArray)
scanSessionArray(paperTradingSessionsArray)
scanSessionArray(liveTradingSessionsArray)
function scanSessionArray(sessionsArray) {
for (let i = 0; i < sessionsArray.length; i++) {
let session = sessionsArray[i]
let environment = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(session, node.payload.referenceParent.type, undefined, true, false, true, false)
if (environment === undefined) { continue }
if (environment.id !== node.payload.referenceParent.id) { continue }
let market = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(session, 'Market Trading Tasks', undefined, true, false, true, false)
if (market.payload.referenceParent === undefined) { continue }
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, session, true) === true) {
createTimeMachine(node, session, market.payload.referenceParent, networkNode, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
}
}
}
}
}
function createTimeMachine(dashboard, session, market, networkNode, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter) {
let mineProducts
let timeMachine = functionLibraryUiObjectsFromNodes.addUIObject(dashboard, 'Time Machine')
timeMachine.payload.referenceParent = session
timeMachine.name = session.name + ' ' + session.type + ' ' + networkNode.name
timeMachine.payload.floatingObject.collapseToggle()
timeMachine.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
timeMachine.timeFrameScale.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
timeMachine.timeScale.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
timeMachine.rateScale.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
/*
We need to create a Timeline Chart for each Data Mine Indicators.
*/
mineProducts = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Data Mine Products')
for (let j = 0; j < mineProducts.length; j++) {
let mineProduct = mineProducts[j]
/*
We need to filter out the ones that do not belong to the market where
the session is running at.
*/
if (mineProduct.payload.parentNode.payload.referenceParent === undefined) { continue }
if (mineProduct.payload.parentNode.payload.referenceParent.id !== market.id) { continue }
let timelineChart = functionLibraryUiObjectsFromNodes.addUIObject(timeMachine, 'Timeline Chart')
/*
The Mine Product Node might be collapesd and since its creation it never
received the physics call, so we will do the call so that it properly
sets its own name, which we are going to reuse here.
*/
mineProduct.payload.uiObject.invisiblePhysics()
timelineChart.name = mineProduct.name
timelineChart.layerManager.payload.referenceParent = mineProduct
timelineChart.payload.floatingObject.collapseToggle()
timelineChart.layerManager.payload.floatingObject.collapseToggle()
timelineChart.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
timelineChart.layerManager.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
let menu = timelineChart.layerManager.payload.uiObject.menu
menu.internalClick('Add All Mine Layers')
menu.internalClick('Add All Mine Layers')
}
mineProducts = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Trading Mine Products')
for (let j = 0; j < mineProducts.length; j++) {
let mineProduct = mineProducts[j]
/*
The mine products found so far, belongs to any session. To filer all the sessions
that are not the one we are interested in, we do the following:
*/
if (mineProduct.payload.parentNode === undefined) { continue }
if (mineProduct.payload.parentNode.payload.referenceParent.id !== session.id) { continue }
/*
At the current version of Superalgos, beta 6, there is only one Trading Mine,
with only one bot, and it has so many data products that we want to put them
in 3 different timeline charts. So we will create 3 charts, connect them,
and delete from each one 1/3 of the layers. We do all that next:
*/
for (let k = 0; k < 3; k++) {
let timelineChart = functionLibraryUiObjectsFromNodes.addUIObject(timeMachine, 'Timeline Chart')
timelineChart.layerManager.payload.referenceParent = mineProduct
timelineChart.payload.floatingObject.collapseToggle()
timelineChart.layerManager.payload.floatingObject.collapseToggle()
timelineChart.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
timelineChart.layerManager.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
let menu = timelineChart.layerManager.payload.uiObject.menu
menu.internalClick('Add All Mine Layers')
menu.internalClick('Add All Mine Layers')
switch (k) {
case 0: {
timelineChart.name = 'Trading Engine'
deleteNodeByName('Trading System')
deleteNodeByName('Simulation Objects')
break
}
case 1: {
timelineChart.name = 'Trading System'
deleteNodeByName('Trading Engine')
deleteNodeByName('Simulation Objects')
break
}
case 2: {
timelineChart.name = 'Simulation Objects'
deleteNodeByName('Trading Engine')
deleteNodeByName('Trading System')
break
}
}
function deleteNodeByName(nodeName) {
let nodeToDelete = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(timelineChart.layerManager, undefined, nodeName, true, true, false, false)
if (nodeToDelete === undefined) { return }
functionLibraryNodeDeleter.deleteUIObject(nodeToDelete, rootNodes)
}
}
}
}
function addMissingDashboards(node, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Network') {
let network = rootNode
scanNetwork(network)
}
}
function scanNetwork(network) {
if (network === undefined) { return }
for (let j = 0; j < network.networkNodes.length; j++) {
let networkNode = network.networkNodes[j]
scanNetworkNode(networkNode)
}
function scanNetworkNode(networkNode) {
let testingEnvironment = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Testing Environment', node, true)
let productionEnvironment = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Production Environment', node, true)
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, testingEnvironment, true) === true) {
let dashboard = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Dashboard')
dashboard.payload.referenceParent = testingEnvironment
dashboard.name = testingEnvironment.type + ' ' + networkNode.name
}
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, productionEnvironment, true) === true) {
let dashboard = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Dashboard')
dashboard.payload.referenceParent = productionEnvironment
dashboard.name = productionEnvironment.type + ' ' + networkNode.name
}
}
}
}
}
@@ -0,0 +1,460 @@
function newCryptoEcosystemFunctions() {
thisObject = {
addMissingExchanges: addMissingExchanges,
addMissingAssets: addMissingAssets,
addMissingMarkets: addMissingMarkets,
installMarket: installMarket,
uninstallMarket: uninstallMarket
}
return thisObject
function addMissingExchanges(node, functionLibraryUiObjectsFromNodes) {
currentExchanges = new Map()
let parent = node.payload.parentNode
if (parent !== undefined) {
for (let i = 0; i < parent.cryptoExchanges.length; i++) {
let cryptoExchanges = parent.cryptoExchanges[i]
for (let j = 0; j < cryptoExchanges.exchanges.length; j++) {
let exchange = cryptoExchanges.exchanges[j]
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(exchange.payload, 'codeName')
currentExchanges.set(codeName, exchange)
}
}
}
let params = {
method: 'listExchanges',
has: {
fetchOHLCV: true,
fetchMarkets: true
}
}
callWebServer(JSON.stringify(params), 'CCXT', onResponse)
function onResponse(err, data) {
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
return
}
let exchanges = JSON.parse(data)
for (let i = 0; i < exchanges.length; i++) {
let exchange = exchanges[i]
let existingExchange = currentExchanges.get(exchange.id)
if (existingExchange === undefined) {
let newExchange = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Crypto Exchange')
newExchange.name = exchange.name
newExchange.config = '{ \n\"codeName\": \"' + exchange.id + '\"\n}'
newExchange.payload.floatingObject.collapseToggle()
newExchange.exchangeAssets.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
newExchange.exchangeMarkets.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
newExchange.exchangeAccounts.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
newExchange.exchangeAssets.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_050X
newExchange.exchangeMarkets.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
newExchange.exchangeAccounts.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_025X
newExchange.exchangeAssets.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
newExchange.exchangeMarkets.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
newExchange.exchangeAccounts.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
}
}
}
}
function addMissingAssets(node, functionLibraryUiObjectsFromNodes) {
if (node.payload.parentNode === undefined) { return }
let currentAssets = new Map()
for (let j = 0; j < node.assets.length; j++) {
let asset = node.assets[j]
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(asset.payload, 'codeName')
currentAssets.set(codeName, asset)
}
let exchangeId = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload.parentNode.payload, 'codeName')
try {
let params = {
exchangeId: exchangeId,
method: 'fetchMarkets'
}
callWebServer(JSON.stringify(params), 'CCXT', onResponse)
function onResponse(err, data) {
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
return
}
let queryParams = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload, 'addMissingAssetsFilter')
let markets = JSON.parse(data)
for (let i = 0; i < markets.length; i++) {
let market = markets[i]
if (queryParams !== undefined) {
if (queryParams.baseAsset !== undefined) {
if (market.base.indexOf(queryParams.baseAsset) < 0) {
continue
}
}
if (queryParams.quotedAsset !== undefined) {
if (market.quote.indexOf(queryParams.quotedAsset) < 0) {
continue
}
}
}
if (currentAssets.get(market.base) === undefined) {
addAsset(market.base)
currentAssets.set(market.base, market.base)
}
if (currentAssets.get(market.quote) === undefined) {
addAsset(market.quote)
currentAssets.set(market.quote, market.quote)
}
function addAsset(name) {
let newAsseet = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Asset')
newAsseet.name = name
newAsseet.config = '{ \n\"codeName\": \"' + name + '\"\n}'
}
}
}
} catch (err) {
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
console.log(err.stack)
}
}
function addMissingMarkets(node, functionLibraryUiObjectsFromNodes, functionLibraryNodeCloning) {
if (node.payload.parentNode === undefined) { return }
if (node.payload.parentNode.exchangeAssets === undefined) { return }
if (node.payload.parentNode.payload.parentNode === undefined) { return }
if (node.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { return }
let currentAssets = new Map()
let exchangeAssets = node.payload.parentNode.exchangeAssets
for (let j = 0; j < exchangeAssets.assets.length; j++) {
let asset = exchangeAssets.assets[j]
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(asset.payload, 'codeName')
currentAssets.set(codeName, asset)
}
let currentMarkets = new Map()
let exchangeMarkets = node
for (let j = 0; j < exchangeMarkets.markets.length; j++) {
let asset = exchangeMarkets.markets[j]
let codeName = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(asset.payload, 'codeName')
currentMarkets.set(codeName, asset)
}
let exchangeId = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload.parentNode.payload, 'codeName')
try {
let params = {
exchangeId: exchangeId,
method: 'fetchMarkets'
}
callWebServer(JSON.stringify(params), 'CCXT', onResponse)
function onResponse(err, data) {
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
return
}
let markets = JSON.parse(data)
for (let i = 0; i < markets.length; i++) {
let market = markets[i]
let baseAsset = currentAssets.get(market.base)
let quotedAsset = currentAssets.get(market.quote)
if (baseAsset === undefined) {
continue
}
if (quotedAsset === undefined) {
continue
}
if (currentMarkets.get(market.symbol) === undefined) {
addMarket(market.symbol, baseAsset, quotedAsset)
}
function addMarket(name, baseAsset, quotedAsset) {
let newMarket = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Market')
newMarket.name = name
newMarket.config = '{ \n\"codeName\": \"' + name + '\"\n}'
newMarket.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
newMarket.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
newMarket.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
newMarket.baseAsset.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_45
newMarket.quotedAsset.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_45
newMarket.baseAsset.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
newMarket.quotedAsset.payload.floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
newMarket.baseAsset.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
newMarket.quotedAsset.payload.floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
newMarket.baseAsset.payload.referenceParent = baseAsset
newMarket.quotedAsset.payload.referenceParent = quotedAsset
currentMarkets.set(name, newMarket)
}
}
}
} catch (err) {
node.payload.uiObject.setErrorMessage('Failed to Fetch Assets from the Exchange')
console.log(err.stack)
}
}
function installMarket(node, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter, functionLibraryChartingSpaceFunctions, functionLibraryDataStorageFunctions) {
let market = node
let cryptoExchange = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(node, 'Crypto Exchange', undefined, true, false, true, false)
if (cryptoExchange === undefined) {
node.payload.uiObject.setErrorMessage('Market must be a descendant of a Crypto Exchange')
return
}
let dashboardsArray = []
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Network') {
installInNetwork(rootNode)
}
}
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Charting Space') {
installInChartingSpace(rootNode)
}
}
function installInNetwork(network) {
for (let j = 0; j < network.networkNodes.length; j++) {
let networkNode = network.networkNodes[j]
installInNetworkNode(networkNode)
}
function installInNetworkNode(networkNode) {
/*
Here we complete the missing stuff at Data Mining
*/
let dataMining = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Data Mining', node, true)
if (dataMining === undefined) {
node.payload.uiObject.setErrorMessage('Data Mining node not found at Network Node ' + networkNode.name)
return
}
let exchangeDataTasks = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(dataMining, 'Exchange Data Tasks', cryptoExchange, functionLibraryUiObjectsFromNodes)
exchangeDataTasks.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
let marketDataTask = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeDataTasks, 'Market Data Tasks', market, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
UI.projects.superalgos.utilities.menu.menuClick(marketDataTask, 'Add Missing Data Mine Tasks', true)
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketDataTask.dataMineTasks, 'Add All Tasks', true)
let sessionsCreatedArray = []
/*
Next we complete the missing stuff at Testing Environment
*/
installEnvironment('Testing Environment')
/*
Next we complete the missing stuff at Production Environment
*/
installEnvironment('Production Environment')
function installEnvironment(environment) {
/*
Now we install the environmnet at the current Network Node
*/
let environmentFound = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, environment, node, true)
if (environmentFound === undefined) {
node.payload.uiObject.setErrorMessage(environment + ' node not found at Network Node ' + networkNode.name)
return
}
let exchangeTradingTasks = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(environmentFound, 'Exchange Trading Tasks', cryptoExchange, functionLibraryUiObjectsFromNodes)
exchangeTradingTasks.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
let marketTradingTask = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeTradingTasks, 'Market Trading Tasks', market, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
UI.projects.superalgos.utilities.menu.menuClick(marketTradingTask, 'Add Missing Trading Mine Tasks', true)
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketTradingTask.tradingMineTasks, 'Add All Tasks', true)
/* This will be needed at the charging space, for creating Dashboards */
let backtestingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketTradingTask, 'Backtesting Session')
let liveTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(marketTradingTask, 'Live Trading Session')
let allSessionsArray = backtestingSessionsArray.concat(liveTradingSessionsArray)
sessionsCreatedArray = sessionsCreatedArray.concat(allSessionsArray)
dashboardsArray.push({ environmentNode: environmentFound, networkNode: networkNode, sessionsArray: allSessionsArray })
}
/*
Here we complete the missing stuff at Data Mines Data
*/
let dataMinesData = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Data Mines Data', node, true)
if (dataMinesData === undefined) {
node.payload.uiObject.setErrorMessage('Data Mines Data node not found at Network Node ' + networkNode.name)
return
}
let exchangeDataProducts = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(dataMinesData, 'Exchange Data Products', cryptoExchange, functionLibraryUiObjectsFromNodes)
exchangeDataProducts.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
let marketDataProducts = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeDataProducts, 'Market Data Products', market, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
marketDataProducts.payload.floatingObject.collapseToggle()
UI.projects.superalgos.utilities.menu.menuClick(marketDataProducts, 'Add All Data Mine Products', true)
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(marketDataProducts.dataMineProducts, 'Add All Data Products', true)
/*
Finally we complete the missing stuff at Trading Mines Data
*/
let tradingMinesData = UI.projects.superalgos.utilities.branches.findInBranch(networkNode, 'Trading Mines Data', node, true)
if (tradingMinesData === undefined) {
node.payload.uiObject.setErrorMessage('Trading Mines Data node not found at Network Node ' + networkNode.name)
return
}
let exchangeTradingProducts = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(tradingMinesData, 'Exchange Trading Products', cryptoExchange, functionLibraryUiObjectsFromNodes)
exchangeTradingProducts.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
let marketTradingProducts = UI.projects.superalgos.utilities.children.findAndRecreateChildWithReference(exchangeTradingProducts, 'Market Trading Products', market, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
marketTradingProducts.payload.floatingObject.collapseToggle()
/*
Create the new session references.
*/
for (let i = 0; i < sessionsCreatedArray.length; i++) {
let session = sessionsCreatedArray[i]
if (UI.projects.superalgos.utilities.children.isMissingChildren(marketTradingProducts, session, true) === true) {
functionLibraryDataStorageFunctions.createSessionReference(marketTradingProducts, session, functionLibraryUiObjectsFromNodes)
}
}
/*
Create everything inside the session references.
*/
for (let j = 0; j < marketTradingProducts.sessionReferences.length; j++) {
let sessionReference = marketTradingProducts.sessionReferences[j]
UI.projects.superalgos.utilities.menu.menuClick(sessionReference, 'Add All Trading Mine Products', true)
UI.projects.superalgos.utilities.menu.menuClickOfNodeArray(sessionReference.tradingMineProducts, 'Add All Data Products', true)
sessionReference.payload.floatingObject.collapseToggle()
}
}
}
function installInChartingSpace(chartingSpace) {
for (let i = 0; i < dashboardsArray.length; i++) {
/*
If the Dashboard we need is not already there we create a new one.
*/
let arrayItem = dashboardsArray[i]
let dashboard = UI.projects.superalgos.utilities.children.findOrCreateChildWithReference(chartingSpace, 'Dashboard', arrayItem.environmentNode, functionLibraryUiObjectsFromNodes)
dashboard.name = arrayItem.environmentNode.type + ' ' + arrayItem.networkNode.name
/*
We delete all the existing Time Machines related to the market we are currently installing.
For that, we make a new array with the existing Time Machines so that the deleting
of each node does not affect the proccessing of the whole set.
*/
let timeMachines = []
for (let i = 0; i < dashboard.timeMachines.length; i++) {
let timeMachine = dashboard.timeMachines[i]
timeMachines.push(timeMachine)
}
for (let i = 0; i < timeMachines.length; i++) {
let timeMachine = timeMachines[i]
let session = timeMachine.payload.referenceParent
if (session === undefined || session.cleaned === true) {
/*
This is what usually happens, that the intall process make these
time machines to lose their reference parent since the install
process deletes them.
*/
functionLibraryNodeDeleter.deleteUIObject(timeMachine, rootNodes)
continue
}
let marketTradingTasks = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(session, 'Market Trading Tasks', undefined, true, false, true, false)
if (marketTradingTasks === undefined) { continue }
if (marketTradingTasks.payload === undefined) { continue }
if (marketTradingTasks.payload.referenceParent === undefined) { continue }
if (marketTradingTasks.payload.referenceParent.id === market.id) {
functionLibraryNodeDeleter.deleteUIObject(timeMachine, rootNodes)
}
}
/*
We create a time machine for each session added during the previous processing.
*/
for (let j = 0; j < arrayItem.sessionsArray.length; j++) {
let session = arrayItem.sessionsArray[j]
functionLibraryChartingSpaceFunctions.createTimeMachine(dashboard, session, node, arrayItem.networkNode, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter)
}
}
}
}
function uninstallMarket(node, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter, functionLibraryChartingSpaceFunctions, functionLibraryDataStorageFunctions) {
let market = node
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Charting Space') {
uninstallInChartingSpace(rootNode)
}
}
function uninstallInChartingSpace(chartingSpace) {
/* Delete all time machines which are referencing sessions inside the market being unistalled. */
let timeMachines = UI.projects.superalgos.utilities.branches.nodeBranchToArray(chartingSpace, 'Time Machine')
for (let i = 0; i < timeMachines.length; i++) {
let timeMachine = timeMachines[i]
let session = timeMachine.payload.referenceParent
if (session === undefined) { continue }
let marketTradingTasks = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(session, 'Market Trading Tasks', undefined, true, false, true, false)
if (marketTradingTasks === undefined) { continue }
if (marketTradingTasks.payload === undefined) { continue }
if (marketTradingTasks.payload.referenceParent === undefined) { continue }
if (marketTradingTasks.payload.referenceParent.id === market.id) {
functionLibraryNodeDeleter.deleteUIObject(timeMachine, rootNodes)
}
}
/* Delete all Dashboards that does not have time machines inside. */
let dashboardArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(chartingSpace, 'Dashboard')
for (let i = 0; i < dashboardArray.length; i++) {
let dashboard = dashboardArray[i]
if (dashboard.timeMachines.length === 0) {
functionLibraryNodeDeleter.deleteUIObject(dashboard, rootNodes)
}
}
/* Scan Networks for the market being unistalled to delete it. */
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Network') {
uninstallInNetwork(rootNode)
}
}
}
function uninstallInNetwork(network) {
let marketDataTasksArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Data Tasks')
let marketTradingTasksArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Trading Tasks')
let marketDataProductsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Data Products')
let marketTradingProductsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(network, 'Market Trading Products')
uninstalMarketArray(marketDataTasksArray)
uninstalMarketArray(marketTradingTasksArray)
uninstalMarketArray(marketDataProductsArray)
uninstalMarketArray(marketTradingProductsArray)
function uninstalMarketArray(marketArray) {
for (let i = 0; i < marketArray.length; i++) {
let marketReference = marketArray[i]
if (marketReference.payload === undefined) { continue }
if (marketReference.payload.referenceParent === undefined) { continue }
if (marketReference.payload.referenceParent.id === market.id) {
functionLibraryNodeDeleter.deleteUIObject(marketReference, rootNodes)
}
}
}
}
}
}
@@ -0,0 +1,103 @@
function newDataMineFunctions() {
thisObject = {
addAllOutputDatasets: addAllOutputDatasets,
addAllDataDependencies: addAllDataDependencies,
addAllDataMineDataDependencies: addAllDataMineDataDependencies
}
return thisObject
function addAllOutputDatasets(node, functionLibraryUiObjectsFromNodes) {
/* Validations to see if we can do this or not. */
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (node.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a parent node to execute this action.')
return
}
if (node.payload.parentNode.payload === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a parent node to execute this action.')
return
}
if (node.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a grand parent node to execute this action.')
return
}
/*
Next, we are going to scan recursively through all nodes of type Product Definition Folder
and Product Definition. For each Product Definition Folder we will create a counterpart
Output Dataset Folder, and for each Product Definition found we will create a Output Definition
for each Dataset defined inside the Product Definition.
*/
UI.projects.superalgos.utilities.folders.asymetricalFolderStructureCloning(
node.payload.parentNode.payload.parentNode,
node,
'products',
'productDefinitionFolders',
'outputDatasetFolders',
'Output Dataset',
'Output Dataset Folder',
'datasets',
functionLibraryUiObjectsFromNodes
)
}
function addAllDataDependencies(node, functionLibraryUiObjectsFromNodes) {
/* Validations to see if we can do this or not. */
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a reference parent node to execute this action.')
return
}
if (node.payload.referenceParent.payload === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a reference parent node to execute this action.')
return
}
/*
Next, we are going to scan through all the bots of the Data Mine referenced, and for each bot we will
create a Bots Data Dependency node. Later we will scan all the Products Definitions of each bot, and for each
Dataset of each Product we will create a Data Dependency. In case we find Product Definition Folders, we will
recreate that structure too, using in this case Data Dependency Folders.
*/
let dataMine = node.payload.referenceParent
scanBotArray(dataMine.sensorBots)
scanBotArray(dataMine.indicatorBots)
scanBotArray(dataMine.tradingBots)
function scanBotArray(botArray) {
for (let i = 0; i < botArray.length; i++) {
let bot = botArray[i]
let botProducts = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Bot Data Dependencies')
botProducts.name = bot.name
UI.projects.superalgos.utilities.folders.asymetricalFolderStructureCloning(
bot,
botProducts,
'products',
'productDefinitionFolders',
'dataDependencyFolders',
'Data Dependency',
'Data Dependency Folder',
'datasets',
functionLibraryUiObjectsFromNodes
)
}
}
}
function addAllDataMineDataDependencies(node, rootNodes, functionLibraryUiObjectsFromNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Data Mine') {
let dataMineDataDependencies = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Data Mine Data Dependencies')
dataMineDataDependencies.payload.referenceParent = rootNode
}
}
}
}
@@ -0,0 +1,167 @@
function newDataStorageFunctions() {
thisObject = {
addAllDataProducts: addAllDataProducts,
addAllDataMineProducts: addAllDataMineProducts,
addAllTradingMineProducts: addAllTradingMineProducts,
addMissingSessionReferences: addMissingSessionReferences,
addMissingMarketDataProducts: addMissingMarketDataProducts,
addMissingMarketTradingProducts: addMissingMarketTradingProducts,
addMissingExchangeTradingProducts: addMissingExchangeTradingProducts,
addMissingExchangeDataProducts: addMissingExchangeDataProducts,
createSessionReference: createSessionReference
}
return thisObject
function addAllDataProducts(node, functionLibraryUiObjectsFromNodes) {
/* Validations to see if we can do this or not. */
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a reference parent node to execute this action.')
return
}
if (node.payload.referenceParent.payload === undefined) {
node.payload.uiObject.setErrorMessage('You need to have a reference parent node to execute this action.')
return
}
/*
Next, we are going to scan through all the bots of the Data Mine referenced, and for each bot we will
create a Bots Products node. Later we will scan all the Products Definitions of each bot, and for each one
we will create a Data Product. In case we find Product Definition Folders, we will recreate that structure
too, using in this case Data Product Folders.
*/
let mine = node.payload.referenceParent
scanBotArray(mine.sensorBots)
scanBotArray(mine.indicatorBots)
scanBotArray(mine.tradingBots)
function scanBotArray(botArray) {
if (botArray === undefined) { return }
for (let i = 0; i < botArray.length; i++) {
let bot = botArray[i]
let botProducts = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Bot Products')
botProducts.name = bot.name
botProducts.payload.floatingObject.collapseToggle()
UI.projects.superalgos.utilities.folders.asymetricalFolderStructureCloning(
bot,
botProducts,
'products',
'productDefinitionFolders',
'dataProductFolders',
'Data Product',
'Data Product Folder',
undefined,
functionLibraryUiObjectsFromNodes
)
}
}
}
function addAllDataMineProducts(node, rootNodes, functionLibraryUiObjectsFromNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Data Mine') {
let dataMineProducts = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Data Mine Products')
dataMineProducts.payload.referenceParent = rootNode
}
}
}
function addAllTradingMineProducts(node, rootNodes, functionLibraryUiObjectsFromNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Trading Mine') {
let tradingMineProducts = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Trading Mine Products')
tradingMineProducts.payload.referenceParent = rootNode
}
}
}
function addMissingSessionReferences(node, rootNodes, functionLibraryUiObjectsFromNodes) {
let networkNode = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(node, 'Network Node', undefined, true, false, true, false)
if (networkNode === undefined) { return }
let backtestingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Backtesting Session')
let fordwardTestingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Forward Testing Session')
let paperTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Paper Trading Session')
let liveTradingSessionsArray = UI.projects.superalgos.utilities.branches.nodeBranchToArray(networkNode, 'Live Trading Session')
addMissingSession(backtestingSessionsArray)
addMissingSession(fordwardTestingSessionsArray)
addMissingSession(paperTradingSessionsArray)
addMissingSession(liveTradingSessionsArray)
function addMissingSession(sessionsArray) {
for (let i = 0; i < sessionsArray.length; i++) {
let session = sessionsArray[i]
/* We will filter out all the sessions that does not belong to the market we are in */
let marketTradingTasks = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(session, 'Market Trading Tasks', undefined, true, false, true, false)
if (node.payload.referenceParent.id !== marketTradingTasks.payload.referenceParent.id) { continue }
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, session, true) === true) {
createSessionReference(node, session, functionLibraryUiObjectsFromNodes)
}
}
}
}
function createSessionReference(node, session, functionLibraryUiObjectsFromNodes) {
let sessionReference = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Session Reference')
sessionReference.payload.referenceParent = session
}
function addMissingMarketDataProducts(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingMarketProducts(node, rootNodes, 'Market Data Products', functionLibraryUiObjectsFromNodes)
}
function addMissingMarketTradingProducts(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingMarketProducts(node, rootNodes, 'Market Trading Products', functionLibraryUiObjectsFromNodes)
}
function addMissingMarketProducts(node, rootNodes, newNodeType, functionLibraryUiObjectsFromNodes) {
if (node.payload.referenceParent === undefined) { return }
if (node.payload.referenceParent.exchangeMarkets === undefined) { return }
let marketsArray = node.payload.referenceParent.exchangeMarkets.markets
for (let i = 0; i < marketsArray.length; i++) {
let market = marketsArray[i]
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, market, true) === true) {
let marketDataProducts = functionLibraryUiObjectsFromNodes.addUIObject(node, newNodeType)
marketDataProducts.payload.referenceParent = market
}
}
}
function addMissingExchangeTradingProducts(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingExchange(node, rootNodes, 'Exchange Trading Products', functionLibraryUiObjectsFromNodes)
}
function addMissingExchangeDataProducts(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingExchange(node, rootNodes, 'Exchange Data Products', functionLibraryUiObjectsFromNodes)
}
function addMissingExchange(node, rootNodes, newNodeType, functionLibraryUiObjectsFromNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Crypto Ecosystem') {
let cryptoEcosystem = rootNode
for (let j = 0; j < cryptoEcosystem.cryptoExchanges.length; j++) {
let cryptoExchanges = cryptoEcosystem.cryptoExchanges[j]
for (let k = 0; k < cryptoExchanges.exchanges.length; k++) {
let cryptoExchange = cryptoExchanges.exchanges[k]
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, cryptoExchange, true) === true) {
let exchange = functionLibraryUiObjectsFromNodes.addUIObject(node, newNodeType)
exchange.payload.referenceParent = cryptoExchange
}
}
}
}
}
}
}
@@ -0,0 +1,74 @@
function newDependenciesFilter() {
thisObject = {
createFilter: createFilter
}
return thisObject
function createFilter(node) {
let filters = new Map()
recursiveFilter(node)
return Array.from(filters.keys())
function recursiveFilter(node) {
filter(node.code)
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
recursiveFilter(node[property.name])
}
previousPropertyName = property.name
}
}
break
case 'array': {
let nodePropertyArray = node[property.name]
if (nodePropertyArray !== undefined) {
for (let j = 0; j < nodePropertyArray.length; j++) {
let nodeProperty = nodePropertyArray[j]
recursiveFilter(nodeProperty)
}
}
}
break
}
}
}
}
}
function filter(code) {
if (code === undefined) { return }
let instructionsArray = code.split(' ')
for (let i = 0; i < instructionsArray.length; i++) {
let instruction = instructionsArray[i]
if (instruction.indexOf('chart') >= 0) {
let parts = instruction.split('.')
let timeFrame = parts[1]
let product = parts[2]
let productParts = product.split(',')
product = productParts[0]
productParts = product.split(')')
product = productParts[0]
// Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10
if (timeFrame !== 'atAnyTimeFrame') {
timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7)
}
filters.set(timeFrame + '-' + product, true)
}
}
}
}
}
@@ -0,0 +1,67 @@
function newNodeChildren() {
thisObject = {
childrenCount: childrenCount
}
return thisObject
function childrenCount(parentNode, childNode) {
return countChildrenUiObject(parentNode, childNode)
}
function countChildrenUiObject(parentNode, childNode) {
let response = {
childrenCount: 0,
childIndex: undefined
}
let parentNodeDefinition = getNodeDefinition(parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (parentNode[property.name] !== undefined) {
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
response.childrenCount++
if (parentNode[property.name].id === childNode.id) {
response.childIndex = response.childrenCount
}
previousPropertyName = property.name
}
}
break
case 'array': {
let nodeDefinition = getNodeDefinition(childNode)
if (nodeDefinition !== undefined) {
let nodePropertyArray = parentNode[property.name]
for (let j = 0; j < nodePropertyArray.length; j++) {
let child = nodePropertyArray[j]
if (nodeDefinition.chainedToSameType === true) {
if (j < 1) {
response.childrenCount++
if (child.id === childNode.id) {
response.childIndex = response.childrenCount
}
}
} else {
response.childrenCount++
if (child.id === childNode.id) {
response.childIndex = response.childrenCount
}
}
}
}
}
break
}
}
}
}
}
return response
}
}
@@ -0,0 +1,179 @@
function newNodeCloning() {
const MODULE_NAME = 'Node Cloning'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
thisObject = {
getNodeClone: getNodeClone
}
return thisObject
function getNodeClone(node) {
let idConversionMap = new Map()
let inmatureClone = cloneNode(node)
let matureClone = redirectReferenceParents(inmatureClone)
return matureClone
function cloneNode(node) {
if (node === undefined) { return }
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
let object = {
type: node.type,
name: node.name,
code: node.code,
config: node.config,
project: node.project
}
/* Children Nodes */
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
object[property.name] = cloneNode(node[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (node[property.name] !== undefined) {
let nodePropertyArray = node[property.name]
object[property.name] = []
for (let m = 0; m < nodePropertyArray.length; m++) {
let protocolNode = cloneNode(nodePropertyArray[m])
if (protocolNode !== undefined) {
object[property.name].push(protocolNode)
}
}
}
break
}
}
}
}
object.id = newUniqueId()
idConversionMap.set(node.id, object.id)
object.savedPayload = getSavedPayload(node)
return object
}
}
function redirectReferenceParents(node) {
if (node === undefined) { return }
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
let object = {
type: node.type,
name: node.name,
code: node.code,
config: node.config,
project: node.project
}
/* Children Nodes */
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
object[property.name] = redirectReferenceParents(node[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (node[property.name] !== undefined) {
let nodePropertyArray = node[property.name]
object[property.name] = []
for (let m = 0; m < nodePropertyArray.length; m++) {
let protocolNode = redirectReferenceParents(nodePropertyArray[m])
if (protocolNode !== undefined) {
object[property.name].push(protocolNode)
}
}
}
break
}
}
}
}
object.id = node.id
object.savedPayload = node.savedPayload
if (object.savedPayload !== undefined) {
if (object.savedPayload.referenceParent !== undefined) {
let newId = idConversionMap.get(object.savedPayload.referenceParent.id)
if (newId !== undefined) {
object.savedPayload.referenceParent.id = newId
}
}
}
return object
}
}
}
function getSavedPayload(node) {
if (node.payload === undefined) { return }
let savedPayload = {
position: {
x: node.payload.position.x,
y: node.payload.position.y
},
targetPosition: {
x: node.payload.targetPosition.x,
y: node.payload.targetPosition.y
},
floatingObject: {
isPinned: node.payload.floatingObject.isPinned,
isFrozen: (node.payload.floatingObject.isFrozen && node.payload.floatingObject.frozenManually),
isCollapsed: (node.payload.floatingObject.isCollapsed && node.payload.floatingObject.collapsedManually),
angleToParent: (node.payload.floatingObject.angleToParent),
distanceToParent: (node.payload.floatingObject.distanceToParent),
arrangementStyle: (node.payload.floatingObject.arrangementStyle)
},
uiObject: {
isPlaying: node.payload.uiObject.isPlaying,
isRunning: node.payload.uiObject.isRunning,
shortcutKey: node.payload.uiObject.shortcutKey
}
}
/* Next for the ones that have a reference parent, we include it */
if (node.payload.referenceParent !== undefined) {
savedPayload.referenceParent = {
type: node.payload.referenceParent.type,
name: node.payload.referenceParent.name,
id: node.payload.referenceParent.id
}
} else {
/* The referenceParent property can be inherited from the previous saved payload. */
if (node.savedPayload !== undefined) {
savedPayload.referenceParent = node.savedPayload.referenceParent
}
}
return savedPayload
}
}
@@ -0,0 +1,138 @@
function newNodeDeleter() {
thisObject = {
deleteWorkspace: deleteWorkspace,
deleteUIObject: deleteUIObject
}
return thisObject
function destroyUiObject(node) {
UI.projects.superalgos.spaces.floatingSpace.uiObjectConstructor.destroyUiObject(node.payload)
}
function deleteWorkspace(node, rootNodes) {
if (node.rootNodes !== undefined) {
while (node.rootNodes.length > 0) {
let rootNode = node.rootNodes[0]
deleteUIObject(rootNode, rootNodes)
}
}
completeDeletion(node, rootNodes)
destroyUiObject(node)
cleanNode(node)
}
function deleteUIObject(node, rootNodes) {
/* First we restore the reference parent to its default state */
if (node.payload !== undefined && node.payload.referenceParent !== undefined && node.payload.referenceParent.payload !== undefined && node.payload.referenceParent.payload.uiObject !== undefined) {
node.payload.referenceParent.payload.uiObject.isShowing = false
}
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
/* Remove all of its own children nodes. */
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
deleteUIObject(node[property.name], rootNodes)
}
previousPropertyName = property.name
}
}
break
case 'array': {
let nodePropertyArray = node[property.name]
if (nodePropertyArray !== undefined) {
while (nodePropertyArray.length > 0) {
deleteUIObject(nodePropertyArray[0], rootNodes)
}
}
}
break
}
}
}
/* Remove node from parent */
if (node.payload !== undefined) {
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = getNodeDefinition(node.payload.parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (nodeDefinition.propertyNameAtParent === property.name) {
switch (property.type) {
case 'node': {
node.payload.parentNode[property.name] = undefined
}
break
case 'array': {
let nodePropertyArray = node.payload.parentNode[property.name]
if (nodePropertyArray !== undefined) {
for (let j = 0; j < nodePropertyArray.length; j++) {
let arrayItem = nodePropertyArray[j]
if (arrayItem.id === node.id) {
/* If this object is chained to the ones of the same type we need to give the next in the chain the reference to the current chain parent */
if (nodeDefinition.chainedToSameType === true) {
if (j < nodePropertyArray.length - 1) {
let nextArrayItem = nodePropertyArray[j + 1]
nextArrayItem.payload.chainParent = node.payload.chainParent
}
}
nodePropertyArray.splice(j, 1)
}
}
}
}
break
}
}
}
}
}
}
}
completeDeletion(node, rootNodes)
destroyUiObject(node)
cleanNode(node)
}
}
function completeDeletion(node, rootNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.id === node.id) {
rootNodes.splice(i, 1)
return
}
}
}
function cleanNode(node) {
if (node === undefined) { return }
if (node.payload === undefined) { return }
node.payload.targetPosition.x = undefined
node.payload.targetPosition.y = undefined
node.payload.visible = undefined
node.payload.subTitle = undefined
node.payload.title = undefined
node.payload.node = undefined
node.payload.parentNode = undefined
node.payload.chainParent = undefined
node.payload.executeAction = undefined
node.handle = undefined
node.payload = undefined
node.cleaned = true
}
}
@@ -0,0 +1,56 @@
function newNodePath() {
thisObject = {
getNodePath: getNodePath
}
return thisObject
function getNodePath(node) {
let nodePath = 'value'
recursiveGet(node)
return 'tradingEngine.' + nodePath
function recursiveGet(node) {
if (node.payload === undefined) { return }
if (node.payload.parentNode === undefined) { return }
let nodeDefinition = getNodeDefinition(node.payload.parentNode)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties === undefined) { return }
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
let parentProperty = node.payload.parentNode[property.name]
if (parentProperty === undefined) { continue }
switch (property.type) {
case 'node': {
if (parentProperty.id === node.id) {
/* We found it */
nodePath = property.name + '.' + nodePath
recursiveGet(node.payload.parentNode)
}
}
break
case 'array': {
for (let j = 0; j < parentProperty.length; j++) {
let arrayProperty = parentProperty[j]
if (arrayProperty === undefined) {continue}
if (arrayProperty.id === node.id) {
/* We found it */
nodePath = property.name + '[' + j + ']' + '.' + nodePath
recursiveGet(node.payload.parentNode)
}
}
}
break
}
}
}
}
}
@@ -0,0 +1,55 @@
function newOnFocus() {
thisObject = {
getNodeThatIsOnFocus: getNodeThatIsOnFocus
}
return thisObject
function getNodeThatIsOnFocus(node) {
if (node === undefined || node === null) { return }
if (node.payload === undefined) { return }
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
/* First we ask the question to ourself */
if (node.payload.uiObject.isOnFocus === true) {
return node
}
/* Then we check all of its own children nodes. */
if (node.payload.floatingObject.isCollapsed !== true) {
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
let child = getNodeThatIsOnFocus(node[property.name])
if (child !== undefined) {
return child
}
}
previousPropertyName = property.name
}
}
break
case 'array': {
let nodePropertyArray = node[property.name]
if (nodePropertyArray !== undefined) {
for (let m = 0; m < nodePropertyArray.length; m++) {
let child = getNodeThatIsOnFocus(nodePropertyArray[m])
if (child !== undefined) {
return child
}
}
}
}
break
}
}
}
}
}
}
}
@@ -0,0 +1,101 @@
function newPluginsFunctions() {
thisObject = {
pluginMissingProjects: pluginMissingProjects,
pluginMissingDataMines: pluginMissingDataMines,
pluginMissingTradingMines: pluginMissingTradingMines,
pluginMissingTradingSystems: pluginMissingTradingSystems,
pluginMissingTradingEngines: pluginMissingTradingEngines,
pluginMissingSuperScripts: pluginMissingSuperScripts,
pluginMissingTutorials: pluginMissingTutorials
}
return thisObject
function getPluginFileNames(pluginType, callBack) {
callWebServer(undefined, 'PluginFileNames/' + 'Superalgos' + '/' + pluginType, onResponse)
function onResponse(err, data) {
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
console.log('Failed to Fetch Plugin ' + pluginType + ' from the Backend')
return
}
let pluginFileNames = JSON.parse(data)
callBack(pluginFileNames)
}
}
function addPluginFileIfNeeded(node, fileNames, functionLibraryUiObjectsFromNodes) {
for (let i = 0; i < fileNames.length; i++) {
let fileName = fileNames[i]
fileName = fileName.replace('.json', '')
if (UI.projects.superalgos.utilities.children.isMissingChildrenByName(node, fileName) === true) {
let child = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Plugin File')
child.name = fileName
}
}
}
function pluginMissingProjects(node, rootNodes, functionLibraryUiObjectsFromNodes) {
let url = 'ProjectNames'
callWebServer(undefined, url, onResponse)
function onResponse(err, pProjects) {
let projects = JSON.parse(pProjects)
for (let i = 0; i < projects.length; i++) {
let project = projects[i]
if (UI.projects.superalgos.utilities.children.isMissingChildrenByName(node, project) === true) {
let child = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Plugin Project')
child.name = project
}
}
}
}
function pluginMissingDataMines(node, rootNodes, functionLibraryUiObjectsFromNodes) {
getPluginFileNames('Data-Mines', onNamesArrived)
function onNamesArrived(fileNames) {
addPluginFileIfNeeded(node, fileNames, functionLibraryUiObjectsFromNodes)
}
}
function pluginMissingTradingMines(node, rootNodes, functionLibraryUiObjectsFromNodes) {
getPluginFileNames('Trading-Mines', onNamesArrived)
function onNamesArrived(fileNames) {
addPluginFileIfNeeded(node, fileNames, functionLibraryUiObjectsFromNodes)
}
}
function pluginMissingTradingSystems(node, rootNodes, functionLibraryUiObjectsFromNodes) {
getPluginFileNames('Trading-Systems', onNamesArrived)
function onNamesArrived(fileNames) {
addPluginFileIfNeeded(node, fileNames, functionLibraryUiObjectsFromNodes)
}
}
function pluginMissingTradingEngines(node, rootNodes, functionLibraryUiObjectsFromNodes) {
getPluginFileNames('Trading-Engines', onNamesArrived)
function onNamesArrived(fileNames) {
addPluginFileIfNeeded(node, fileNames, functionLibraryUiObjectsFromNodes)
}
}
function pluginMissingSuperScripts(node, rootNodes, functionLibraryUiObjectsFromNodes) {
getPluginFileNames('Super-Scripts', onNamesArrived)
function onNamesArrived(fileNames) {
addPluginFileIfNeeded(node, fileNames, functionLibraryUiObjectsFromNodes)
}
}
function pluginMissingTutorials(node, rootNodes, functionLibraryUiObjectsFromNodes) {
getPluginFileNames('Tutorials', onNamesArrived)
function onNamesArrived(fileNames) {
addPluginFileIfNeeded(node, fileNames, functionLibraryUiObjectsFromNodes)
}
}
}
@@ -0,0 +1,207 @@
function newProtocolNode() {
const MODULE_NAME = 'Protocol Node'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
thisObject = {
getProtocolNode: getProtocolNode
}
return thisObject
function getProtocolNode(node, removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, lightingPath) {
if (node === undefined) { return }
if (node.payload === undefined) { return }
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
if (removePersonalData === true && nodeDefinition.isPersonalData === true) { return }
let object = {
type: node.type,
name: node.name,
code: node.code,
config: node.config,
project: node.project
}
/* Children Nodes */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (node[property.name] !== undefined) {
if (lightingPath === undefined) {
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseConfig, includeIds, includeReferencesInSavedPayload, includePayload)
} else {
let newLightingPath = getNewLightingPath(lightingPath, node.type, property.childType)
if (newLightingPath !== undefined) {
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
}
break
}
case 'array': {
if (node[property.name] !== undefined) {
if (lightingPath === undefined) {
let nodePropertyArray = node[property.name]
object[property.name] = []
for (let m = 0; m < nodePropertyArray.length; m++) {
let protocolNode = getProtocolNode(nodePropertyArray[m], removePersonalData, parseConfig, includeIds, includeReferencesInSavedPayload, includePayload)
if (protocolNode !== undefined) {
object[property.name].push(protocolNode)
}
}
} else {
let newLightingPath = getNewLightingPath(lightingPath, node.type, property.childType)
if (newLightingPath !== undefined) {
let nodePropertyArray = node[property.name]
object[property.name] = []
for (let m = 0; m < nodePropertyArray.length; m++) {
let protocolNode = getProtocolNode(nodePropertyArray[m], removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
if (protocolNode !== undefined) {
object[property.name].push(protocolNode)
}
}
}
}
}
break
}
}
}
}
/* Parent Nodes */
if (node.payload.parentNode !== undefined) {
let newLightingPath = getNewLightingPath(lightingPath, node.type, node.payload.parentNode.type)
if (newLightingPath !== undefined) {
object.parentNode = getProtocolNode(node.payload.parentNode, removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
} else {
let newLightingPath = getNewLightingPath(lightingPath, node.type, node.payload.parentNode.type)
}
}
if (node.payload.referenceParent !== undefined) {
let newLightingPath = getNewLightingPath(lightingPath, node.type, node.payload.referenceParent.type)
if (newLightingPath !== undefined) {
object.referenceParent = getProtocolNode(node.payload.referenceParent, removePersonalData, parseConfig, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
if (parseConfig && object.config !== undefined && nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
try {
object.config = JSON.parse(node.config)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> err = ' + err.stack) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.type = ' + node.type) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.name = ' + node.name) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.config = ' + node.config) }
if (ERROR_LOG === true) { logger.write('[ERROR] getProtocolNode -> default -> node.id = ' + node.id) }
}
}
}
if (includeIds) {
object.id = node.id
}
if (includePayload) {
object.savedPayload = getSavedPayload(node, includeReferencesInSavedPayload)
}
return object
}
}
function getNewLightingPath(lightingPath, currentNodeType, nextNodeType) {
if (lightingPath === undefined) { return }
if (currentNodeType === undefined) { return }
if (nextNodeType === undefined) { return }
let currentNodePosition = lightingPath.indexOf('->' + currentNodeType + '->')
let nextNodePosition = lightingPath.indexOf('->' + nextNodeType + '->')
/*
In some situations, the current and next node are of the same type.
When that happens, we need to search for the second instance of that type
at the lighting path.
*/
if (currentNodeType === nextNodeType) {
let tempLightingPath = lightingPath.substring(currentNodePosition + currentNodeType.length, lightingPath.length + 1)
nextNodePosition = tempLightingPath.indexOf('->' + nextNodeType + '->')
}
let newLightingPath = lightingPath.substring(nextNodePosition, lightingPath.length + 1)
if (nextNodePosition > currentNodePosition) {
return newLightingPath
} else {
return
}
}
function getSavedPayload(node, includeReferencesInSavedPayload) {
if (node.payload === undefined) { return }
let savedPayload = {
position: {
x: node.payload.position.x,
y: node.payload.position.y
},
targetPosition: {
x: node.payload.targetPosition.x,
y: node.payload.targetPosition.y
},
floatingObject: {
isPinned: node.payload.floatingObject.isPinned,
isFrozen: (node.payload.floatingObject.isFrozen && node.payload.floatingObject.frozenManually),
isCollapsed: (node.payload.floatingObject.isCollapsed && node.payload.floatingObject.collapsedManually),
angleToParent: (node.payload.floatingObject.angleToParent),
distanceToParent: (node.payload.floatingObject.distanceToParent),
arrangementStyle: (node.payload.floatingObject.arrangementStyle)
},
uiObject: {
isPlaying: node.payload.uiObject.isPlaying,
isRunning: node.payload.uiObject.isRunning,
shortcutKey: node.payload.uiObject.shortcutKey
}
}
if (node.payload.frame !== undefined) {
savedPayload.frame = {
position: {
x: node.payload.frame.position.x,
y: node.payload.frame.position.y
},
width: node.payload.frame.width,
height: node.payload.frame.height,
radius: node.payload.frame.radius
}
}
if (node.payload.tutorial !== undefined) {
savedPayload.tutorial = {
status: node.payload.tutorial.status
}
}
if (includeReferencesInSavedPayload) {
/* Next for the ones that have a reference parent, we include it */
if (node.payload.referenceParent !== undefined) {
savedPayload.referenceParent = {
type: node.payload.referenceParent.type,
name: node.payload.referenceParent.name,
id: node.payload.referenceParent.id
}
} else {
/* The referenceParent property can be inherited from the previous saved payload. */
if (node.savedPayload !== undefined) {
savedPayload.referenceParent = node.savedPayload.referenceParent
}
}
}
return savedPayload
}
}
@@ -0,0 +1,36 @@
function newReferenceAttachDetach() {
thisObject = {
referenceDetachNode: referenceDetachNode,
referenceAttachNode: referenceAttachNode
}
return thisObject
function referenceDetachNode(node) {
completeDetachment(node)
}
function referenceAttachNode(node, attachToNode) {
completeAttachment(node, attachToNode)
}
function completeAttachment(node, attachToNode) {
node.payload.referenceParent = attachToNode
}
function completeDetachment(node) {
if (node.payload !== undefined) {
if (node.payload.referenceParent !== undefined) {
if (node.payload.referenceParent.payload !== undefined) {
if (node.payload.referenceParent.payload.uiObject !== undefined) {
node.payload.referenceParent.payload.uiObject.isShowing = false
}
}
}
node.payload.referenceParent = undefined
if (node.savedPayload !== undefined) {
node.savedPayload.referenceParent = undefined
}
}
}
}
@@ -0,0 +1,235 @@
function newSessionFunctions() {
thisObject = {
syncronizeSessionWithBackEnd: syncronizeSessionWithBackEnd,
runSession: runSession,
stopSession: stopSession
}
return thisObject
function syncronizeSessionWithBackEnd(node) {
let networkNode = validations(node)
if (networkNode === undefined) {
/* Nodes that do not belong to a network can not get ready. */
return
}
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id)
/* First we setup everything so as to listen to the response from the Task Server */
let eventSubscriptionIdOnStatus
let key = node.name + '-' + node.type + '-' + node.id
eventsServerClient.listenToEvent(key, 'Status Response', undefined, node.id, onResponse, onStatus)
function onResponse(message) {
eventSubscriptionIdOnStatus = message.eventSubscriptionId
}
function onStatus(message) {
eventsServerClient.stopListening(key, eventSubscriptionIdOnStatus, node.id)
if (message.event.status === 'Session Runnning' ) {
node.payload.uiObject.menu.internalClick('Run Session')
}
}
/* Second we ask the Task Server if this Session is Running. */
eventsServerClient.raiseEvent(key, 'Session Status')
}
function runSession(node, functionLibraryProtocolNode, functionLibraryDependenciesFilter, resume, callBackFunction) {
let networkNode = validations(node)
if (networkNode === undefined) {
/* This means that the validations failed. */
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id)
node.payload.uiObject.run(eventsServerClient, callBackFunction)
let key = node.name + '-' + node.type + '-' + node.id
let lightingPath = '' +
'Trading System->' +
'Dynamic Indicators->Indicator Function->Formula->' +
'Trading Strategy->' +
'Trigger Stage->Trigger On Event->Trigger Off Event->Take Position Event->' +
'Announcement->Announcement Formula->' +
'Open Stage->' +
'Manage Stage->' +
'Managed Stop Loss->Managed Take Profit->' +
'Phase->Formula->Next Phase Event->Move To Phase Event->Phase->' +
'Situation->Condition->Javascript Code->' +
'Close Stage->' +
'Initial Targets->Target Size In Base Asset->Target Size In Quoted Asset->Target Rate->Formula->' +
'Announcement->Announcement Formula->' +
'Open Execution->Close Execution->' +
'Execution Algorithm->Market Buy Order->Market Sell Order->Limit Buy Order->Limit Sell Order->' +
'Order Rate->Formula->' +
'Create Order Event->Cancel Order Event->' +
'Size In Base Asset->Size In Quoted Asset->Position Rate->Formula->' +
'Situation->Condition->Javascript Code->' +
'Market Order->Limit Order->' +
'Simulated Exchange Events->Simulated Partial Fill->Simulated Actual Rate->Simulated Fees Paid->Formula->'
let tradingSystem = functionLibraryProtocolNode.getProtocolNode(node.tradingSystemReference.payload.referenceParent, false, true, true, false, false, lightingPath)
lightingPath = '' +
'Trading Engine->' +
'Dynamic Indicators->Indicator Function->' +
'Current->Last->Previous->' +
'Episode->' +
'Episode Base Asset->Episode Quoted Asset->Episode Counters->Episode Statistics->' +
'Strategies->Positions->Orders->Hits->Fails->' +
'Profit Loss->Hit Ratio->Hit Fail->Days->ROI->Annualized Rate Of Return->User Defined Statistic->' +
'Candle->Cycle->' +
'Begin->End->Last Begin->Last End->Open->Close->Min->Max->Index->' +
'Distance To Event->' +
'Head Of The Market->Process Date->' +
'Trigger On->Trigger Off->Take Position->Close Position->Next Phase->Move To Phase->Create Order->Cancel Order->Close Order->' +
'Strategy->' +
'Strategy Counters->' +
'Position->' +
'Entry Target Rate->Exit Target Rate->' +
'Stop Loss->Stop Loss Phase->Stop Loss Position->' +
'Take Profit->Take Profit Phase->Take Profit Position->' +
'Position Counters->' +
'Position Statistics->Days->User Defined Statistic->' +
'Position Base Asset->Position Quoted Asset->Entry Target Size->Exit Target Size->' +
'Profit Loss->ROI->Hit Fail->' +
'Exchange Orders->Market Buy Orders->Market Sell Orders->Limit Buy Orders->Limit Sell Orders->' +
'Market Order->Limit Order->' +
'Exchange Id->Rate->Order Name->Algorithm Name->Lock->' +
'Order Counters->' +
'Order Base Asset->Order Quoted Asset->' +
'Size->Size Filled->Fees Paid->' +
'Order Statistics->Percentage Filled->Actual Rate->Days->User Defined Statistic->' +
'Strategy Trigger Stage->Strategy Open Stage->Strategy Manage Stage->Strategy Close Stage->' +
'Begin->End->Exit Type->Status->Begin Rate->End Rate->Stage Base Asset->Stage Quoted Asset->Size Placed->Target Size->Size Filled->Fees Paid->Stage Defined In->' +
'Serial Number->Identifier->Begin->End->Begin Rate->End Rate->Strategy Name->Status->Exit Type->' +
'Balance->Begin Balance->End Balance->' +
'Index->Situation Name->Formula->Periods->'
let tradingEngine = functionLibraryProtocolNode.getProtocolNode(node.tradingEngineReference.payload.referenceParent, false, true, true, false, false, lightingPath)
lightingPath = '' +
'Backtesting Session->Paper Trading Session->Forward Testing Session->Live Trading Session->' +
'Parameters->' +
'Session Base Asset->Session Quoted Asset->Time Range->Time Frame->Slippage->Fee Structure->Snapshots->Heartbeats->User Defined Parameters->' +
'Exchange Account Asset->Asset->' +
'Social Bots->Telegram Bot->'
let session = functionLibraryProtocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath)
let dependencyFilter = functionLibraryDependenciesFilter.createFilter(node.tradingSystemReference.payload.referenceParent)
/* Raise event to run the session */
let event = {
session: JSON.stringify(session),
tradingSystem: JSON.stringify(tradingSystem),
tradingEngine: JSON.stringify(tradingEngine),
dependencyFilter: JSON.stringify(dependencyFilter),
resume: resume
}
if (resume !== true) {
eventsServerClient.raiseEvent(key, 'Run Session', event)
} else {
eventsServerClient.raiseEvent(key, 'Resume Session', event)
}
if (node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
}
function stopSession(node, functionLibraryProtocolNode, callBackFunction) {
let networkNode = validations(node)
if (networkNode === undefined) {
/* This means that the validations failed. */
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id)
let key = node.name + '-' + node.type + '-' + node.id
eventsServerClient.raiseEvent(key, 'Stop Session')
node.payload.uiObject.stop(callBackFunction)
}
function validations(node) {
if (node.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs a Process Instance parent to be able to run.')
return
}
if (node.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside a Trading Process Instance.')
return
}
if (node.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside a Task.')
return
}
if (node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside a Task Manager.')
return
}
let taskManager = node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode
if (taskManager.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside Mine Tasks.')
return
}
if (taskManager.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside Market Tasks.')
return
}
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside Exchange Tasks.')
return
}
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside a Testing or Production Environment.')
return
}
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs to be inside a Network Node.')
return
}
let networkNode = taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode
if (node.tradingSystemReference === undefined) {
node.payload.uiObject.setErrorMessage('Session needs a child Trading System Reference.')
return
}
if (node.tradingEngineReference === undefined) {
node.payload.uiObject.setErrorMessage('Session needs a child Trading Engine Reference.')
return
}
if (node.tradingSystemReference.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Trading System Reference needs to reference a Trading System.')
return
}
if (node.tradingEngineReference.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Trading Engine Reference needs to reference a Trading Engine.')
return
}
return networkNode
}
}
@@ -0,0 +1,54 @@
function newShortcutKeys() {
thisObject = {
getNodeByShortcutKey: getNodeByShortcutKey
}
return thisObject
function getNodeByShortcutKey(node, searchingKey) {
if (node === undefined) { return }
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
/* Check Self first */
if (node.payload.uiObject.shortcutKey === searchingKey) {
return node
}
/* Check all of its own children nodes. */
if (node.payload.floatingObject.isCollapsed !== true) {
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
let child = getNodeByShortcutKey(node[property.name], searchingKey)
if (child !== undefined) {
return child
}
}
previousPropertyName = property.name
}
}
break
case 'array': {
let nodePropertyArray = node[property.name]
if (nodePropertyArray !== undefined) {
for (let m = 0; m < nodePropertyArray.length; m++) {
let child = getNodeByShortcutKey(nodePropertyArray[m], searchingKey)
if (child !== undefined) {
return child
}
}
}
}
break
}
}
}
}
}
}
}
@@ -0,0 +1,90 @@
function newSuperScriptsFunctions() {
thisObject = {
runSuperScript: runSuperScript
}
return thisObject
function runSuperScript(node, rootNodes, functionLibraryNodeCloning, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter) {
try {
let clone = functionLibraryNodeCloning.getNodeClone
let executionResult = true
let superAction = node
function setup(templateClone, target, exchange, exchangeNodeType, arrayPropertyName) {
spawnPosition.x = target.payload.position.x
spawnPosition.y = target.payload.position.y
if (exchange === undefined) {
functionLibraryUiObjectsFromNodes.createUiObjectFromNode(templateClone, target, target)
} else {
let definition = getNodeDefinition(target)
for (let i = 0; i < definition.properties.length; i++) {
let property = definition.properties[i]
if (property.childType === exchangeNodeType) {
let exchanges = target[property.name]
if (exchanges === undefined) {
exchanges = []
}
let targetExchange
for (let j = 0; j < exchanges.length; j++) {
let thisExchange = exchanges[j]
if (thisExchange.payload.referenceParent !== undefined) {
if (thisExchange.payload.referenceParent.id === exchange.id) {
targetExchange = thisExchange
}
}
}
if (targetExchange === undefined) {
targetExchange = functionLibraryUiObjectsFromNodes.addUIObject(target, exchangeNodeType)
targetExchange.payload.referenceParent = exchange
}
let nodesArray = targetExchange[arrayPropertyName]
nodesArray.push(templateClone)
functionLibraryUiObjectsFromNodes.createUiObjectFromNode(templateClone, targetExchange, targetExchange)
}
}
}
}
function deleteNode(node) {
functionLibraryNodeDeleter.deleteUIObject(node, rootNodes)
}
/* Validations */
if (executionResult === true && node.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Super Action node needs a Parent Node.')
executionResult = false
}
if (executionResult === true && node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Super Action node needs to reference a Master Script Node.')
executionResult = false
}
if (executionResult === true && node.payload.referenceParent.javascriptCode === undefined) {
node.payload.uiObject.setErrorMessage('Master Script Node needs to have a child Javascript Code Node.')
executionResult = false
}
let masterScript = node.payload.referenceParent
eval(masterScript.javascriptCode.code)
let masterScriptInstance = newNewMasterScriptInstance()
if (executionResult === true) {
executionResult = masterScriptInstance.runValidations(superAction, masterScript)
}
if (executionResult === true) {
executionResult = masterScriptInstance.runScript(superAction, masterScript)
}
if (executionResult === true) {
superAction.payload.uiObject.setValue('Execution Completed Successfully')
} else {
superAction.payload.uiObject.setValue('Execution Failed')
}
} catch (err) {
superAction.payload.uiObject.setErrorMessage(err.message)
superAction.payload.uiObject.setValue('Execution Failed')
}
}
}
@@ -0,0 +1,619 @@
function newTaskFunctions() {
thisObject = {
syncronizeTaskWithBackEnd: syncronizeTaskWithBackEnd,
runTask: runTask,
stopTask: stopTask,
runAllTasks: runAllTasks,
stopAllTasks: stopAllTasks,
runAllTaskManagers: runAllTaskManagers,
stopAllTaskManagers: stopAllTaskManagers,
runAllExchangeDataTasks: runAllExchangeDataTasks,
stopAllExchangeDataTasks: stopAllExchangeDataTasks,
runAllExchangeTradingTasks: runAllExchangeTradingTasks,
stopAllExchangeTradingTasks: stopAllExchangeTradingTasks,
runAllMarketDataTasks: runAllMarketDataTasks,
stopAllMarketDataTasks: stopAllMarketDataTasks,
runAllMarketTradingTasks: runAllMarketTradingTasks,
stopAllMarketTradingTasks: stopAllMarketTradingTasks,
runAllDataMineTasks: runAllDataMineTasks,
stopAllDataMineTasks: stopAllDataMineTasks,
runAllTradingMineTasks: runAllTradingMineTasks,
stopAllTradingMineTasks: stopAllTradingMineTasks,
addMissingExchangeDataTasks: addMissingExchangeDataTasks,
addMissingMarketDataTasks: addMissingMarketDataTasks,
addMissingDataMineTasks: addMissingDataMineTasks,
addMissingExchangeTradingTasks: addMissingExchangeTradingTasks,
addMissingMarketTradingTasks: addMissingMarketTradingTasks,
addMissingTradingMineTasks: addMissingTradingMineTasks,
addAllTasks: addAllTasks
}
return thisObject
function syncronizeTaskWithBackEnd(node) {
let networkNode = validations(node)
if (networkNode === undefined) {
/* Nodes that do not belong to a network can not get ready. */
return
}
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id)
/* First we setup everything so as to listen to the response from the Task Manger */
let eventSubscriptionIdOnStatus
let key = 'Task Client - ' + node.id
eventsServerClient.listenToEvent(key, 'Task Status', undefined, node.id, onResponse, onStatus)
function onResponse(message) {
eventSubscriptionIdOnStatus = message.eventSubscriptionId
}
function onStatus(message) {
eventsServerClient.stopListening(key, eventSubscriptionIdOnStatus, node.id)
if (message.event.status === 'Task Process Running' ) {
node.payload.uiObject.menu.internalClick('Run Task')
}
}
/* Second we ask the Task Manager if this Task has a process Running. */
let event = {
taskId: node.id
}
eventsServerClient.raiseEvent('Task Manager', 'Task Status', event)
}
function runTask(node, functionLibraryProtocolNode, isDebugging, callBackFunction) {
let networkNode = validations(node)
if (networkNode === undefined) {
/* This means that the validations failed. */
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id)
for (let i = 0; i < node.bot.processes.length; i++) {
let process = node.bot.processes[i]
process.payload.uiObject.run(eventsServerClient)
}
let taskLightingPath = '->Task->' +
'Sensor Bot Instance->' +
'Indicator Bot Instance->Time Frames Filter->' +
'Trading Bot Instance->' +
'Sensor Process Instance->Indicator Process Instance->Trading Process Instance->' +
'Execution Started Event->' +
'Key Reference->Exchange Account Key->' +
'Task Manager->' +
'Data Mine Tasks->Trading Mine Tasks->' +
'Market Data Tasks->Market Trading Tasks->' +
'Exchange Data Tasks->Exchange Trading Tasks->' +
'Market->Exchange Markets->Crypto Exchange->' +
'Market Base Asset->Market Quoted Asset->Asset->' +
'Backtesting Session->Live Trading Session->Paper Trading Session->Forward Testing Session->' +
'Process Definition->' +
'Process Output->' +
'Output Dataset Folder->Output Dataset Folder->Output Dataset Folder->Output Dataset Folder->Output Dataset Folder->' +
'Output Dataset->Dataset Definition->Product Definition->' +
'Process Dependencies->' +
'Status Dependency->Status Report->Process Definition->' +
'Data Mine Data Dependencies->Bot Data Dependencies->' +
'Data Dependency Folder->Data Dependency Folder->Data Dependency Folder->Data Dependency Folder->Data Dependency Folder->' +
'Data Dependency->Dataset Definition->Product Definition->' +
'Record Definition->Record Property->Formula->' +
'Data Building Procedure->' +
'Procedure Initialization->Javascript Code->' +
'Procedure Loop->Javascript Code->' +
'Calculations Procedure->' +
'Procedure Initialization->Javascript Code->' +
'Procedure Loop->Javascript Code->' +
'Status Report->' +
'Execution Finished Event->' +
'Execution Started Event->Execution Finished Event->Process Definition->' +
'Sensor Bot->' +
'Product Definition Folder->Product Definition Folder->Product Definition Folder->Product Definition Folder->Product Definition Folder->' +
'Indicator Bot->' +
'Trading Bot->' +
'Data Mine->Trading Mine->'
let taskDefinition = functionLibraryProtocolNode.getProtocolNode(node, false, true, true, false, false, taskLightingPath)
let networkLightingPath = '->Network->Network Node->' +
'Data Storage->Data Mines Data->Exchange Data Products->' +
'Market Data Products->' +
'Data Mine Products->Bot Products->' +
'Data Product Folder->Data Product Folder->Data Product Folder->Data Product Folder->Data Product Folder->' +
'Data Product->Product Definition->' +
'Data Mining->Testing Environment->Production Environment->' +
'Exchange Data Tasks->Exchange Trading Tasks->Crypto Exchange->' +
'Market Data Tasks->Market Trading Tasks->Market->' +
'Data Mine Tasks->Trading Mine Tasks->' +
'Task Manager->Task->' +
'Indicator Bot Instance->Sensor Bot Instance->Trading Bot Instance->' +
'Indicator Process Instance->Sensor Process Instance->Trading Process Instance->' +
'Paper Trading Session->Forward Testing Session->Backtesting Session->Live Trading Session->' +
'Market->' +
'Process Definition->'
let networkDefinition = functionLibraryProtocolNode.getProtocolNode(networkNode.payload.parentNode, false, true, true, false, false, networkLightingPath)
let event = {
appSchema: JSON.stringify(SCHEMAS_BY_PROJECT.get('Superalgos').array.appSchema),
taskId: node.id,
taskName: node.name,
taskDefinition: JSON.stringify(taskDefinition),
networkDefinition: JSON.stringify(networkDefinition)
}
if (isDebugging === true) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE)
eventsServerClient.raiseEvent('Task Server', 'Debug Task Started', event)
return
}
node.payload.uiObject.run(eventsServerClient, callBackFunction)
eventsServerClient.raiseEvent('Task Manager', 'Run Task', event)
}
function stopTask(node, functionLibraryProtocolNode, callBackFunction) {
let networkNode = validations(node)
if (networkNode === undefined) {
/* This means that the validations failed. */
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id)
let event = {
taskId: node.id,
taskName: node.name
}
node.payload.uiObject.stop(callBackFunction)
eventsServerClient.raiseEvent('Task Manager', 'Stop Task', event)
if (node.bot === undefined) { return }
if (node.bot.processes.length === 0) { return }
for (let i = 0; i < node.bot.processes.length; i++) {
let process = node.bot.processes[i]
process.payload.uiObject.stop()
}
}
function validations(node) {
if (node.bot === undefined) {
node.payload.uiObject.setErrorMessage('Task needs to have a Bot Instance.')
return
}
if (node.bot.processes.length === 0) {
node.payload.uiObject.setErrorMessage('Task Bot Instance needs to have al least once Process Instance.')
return
}
if (node.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Task needs to be inside a Task Manager.')
return
}
let taskManager = node.payload.parentNode
if (taskManager.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Task needs to be inside Mine Tasks.')
return
}
if (taskManager.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Task needs to be inside Market Tasks.')
return
}
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Task needs to be inside Exchange Tasks.')
return
}
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Task needs to be inside a Data Mining, Testing or Production Environment.')
return
}
if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Task needs to be inside a Network Node.')
return
}
let networkNode = taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode
if (UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(networkNode.payload, 'host') === undefined) {
node.payload.uiObject.setErrorMessage('Network Node needs to have a valid Host property at its config.')
return
}
if (UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(networkNode.payload, 'webPort') === undefined) {
node.payload.uiObject.setErrorMessage('Network Node needs to have a valid webPort property at its config.')
return
}
if (UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(networkNode.payload, 'webSocketsPort') === undefined) {
node.payload.uiObject.setErrorMessage('Network Node needs to have a valid webSocketsPort property at its config.')
return
}
return networkNode
}
function runAllTasks(taskManager, functionLibraryProtocolNode) {
for (let i = 0; i < taskManager.tasks.length; i++) {
let node = taskManager.tasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run Task')
}
}
function stopAllTasks(taskManager, functionLibraryProtocolNode) {
for (let i = 0; i < taskManager.tasks.length; i++) {
let node = taskManager.tasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop Task')
}
}
function runAllTaskManagers(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.taskManagers.length; i++) {
let node = parent.taskManagers[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run All Tasks')
menu.internalClick('Run All Tasks')
}
}
function stopAllTaskManagers(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.taskManagers.length; i++) {
let node = parent.taskManagers[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop All Tasks')
menu.internalClick('Stop All Tasks')
}
}
function runAllExchangeDataTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.exchangeDataTasks.length; i++) {
let node = parent.exchangeDataTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run All Market Data Tasks')
menu.internalClick('Run All Market Data Tasks')
}
}
function stopAllExchangeDataTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.exchangeDataTasks.length; i++) {
let node = parent.exchangeDataTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop All Market Data Tasks')
menu.internalClick('Stop All Market Data Tasks')
}
}
function runAllExchangeTradingTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.exchangeTradingTasks.length; i++) {
let node = parent.exchangeTradingTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run All Market Trading Tasks')
menu.internalClick('Run All Market Trading Tasks')
}
}
function stopAllExchangeTradingTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.exchangeTradingTasks.length; i++) {
let node = parent.exchangeTradingTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop All Market Trading Tasks')
menu.internalClick('Stop All Market Trading Tasks')
}
}
function runAllMarketDataTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.marketDataTasks.length; i++) {
let node = parent.marketDataTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run All Data Mine Tasks')
menu.internalClick('Run All Data Mine Tasks')
}
}
function stopAllMarketDataTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.marketDataTasks.length; i++) {
let node = parent.marketDataTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop All Data Mine Tasks')
menu.internalClick('Stop All Data Mine Tasks')
}
}
function runAllMarketTradingTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.marketTradingTasks.length; i++) {
let node = parent.marketTradingTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run All Trading Mine Tasks')
menu.internalClick('Run All Trading Mine Tasks')
}
}
function stopAllMarketTradingTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.marketTradingTasks.length; i++) {
let node = parent.marketTradingTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop All Trading Mine Tasks')
menu.internalClick('Stop All Trading Mine Tasks')
}
}
function runAllDataMineTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.dataMineTasks.length; i++) {
let node = parent.dataMineTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run All Task Managers')
menu.internalClick('Run All Task Managers')
}
}
function stopAllDataMineTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.dataMineTasks.length; i++) {
let node = parent.dataMineTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop All Task Managers')
menu.internalClick('Stop All Task Managers')
}
}
function runAllTradingMineTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.tradingMineTasks.length; i++) {
let node = parent.tradingMineTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Run All Task Managers')
menu.internalClick('Run All Task Managers')
}
}
function stopAllTradingMineTasks(parent, functionLibraryProtocolNode) {
for (let i = 0; i < parent.tradingMineTasks.length; i++) {
let node = parent.tradingMineTasks[i]
let menu = node.payload.uiObject.menu
menu.internalClick('Stop All Task Managers')
menu.internalClick('Stop All Task Managers')
}
}
function addMissingExchangeDataTasks(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingExchangeTasks(node, rootNodes, 'Exchange Data Tasks', functionLibraryUiObjectsFromNodes)
}
function addMissingExchangeTradingTasks(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingExchangeTasks(node, rootNodes, 'Exchange Trading Tasks', functionLibraryUiObjectsFromNodes)
}
function addMissingExchangeTasks(node, rootNodes, newNodeType, functionLibraryUiObjectsFromNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Crypto Ecosystem') {
let cryptoEcosystem = rootNode
for (let j = 0; j < cryptoEcosystem.cryptoExchanges.length; j++) {
let cryptoExchanges = cryptoEcosystem.cryptoExchanges[j]
for (let k = 0; k < cryptoExchanges.exchanges.length; k++) {
let cryptoExchange = cryptoExchanges.exchanges[k]
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, cryptoExchange, true) === true) {
let exchangeTasks = functionLibraryUiObjectsFromNodes.addUIObject(node, newNodeType)
exchangeTasks.payload.referenceParent = cryptoExchange
}
}
}
}
}
}
function addMissingMarketDataTasks(node, functionLibraryUiObjectsFromNodes) {
addMissingMarketTasks(node, 'Market Data Tasks', functionLibraryUiObjectsFromNodes)
}
function addMissingMarketTradingTasks(node, functionLibraryUiObjectsFromNodes) {
addMissingMarketTasks(node, 'Market Trading Tasks', functionLibraryUiObjectsFromNodes)
}
function addMissingMarketTasks(node, newNodeType, functionLibraryUiObjectsFromNodes) {
if (node.payload === undefined) { return }
if (node.payload.referenceParent === undefined) { return }
if (node.payload.referenceParent.exchangeMarkets === undefined) { return }
let markets = node.payload.referenceParent.exchangeMarkets.markets
for (let i = 0; i < markets.length; i++) {
let market = markets[i]
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, market, true) === true) {
let marketDataTasks = functionLibraryUiObjectsFromNodes.addUIObject(node, newNodeType)
marketDataTasks.payload.referenceParent = market
}
}
}
function addMissingDataMineTasks(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingMineTasks(node, rootNodes, 'Data Mine', 'Data Mine Tasks', functionLibraryUiObjectsFromNodes)
}
function addMissingTradingMineTasks(node, rootNodes, functionLibraryUiObjectsFromNodes) {
addMissingMineTasks(node, rootNodes, 'Trading Mine', 'Trading Mine Tasks', functionLibraryUiObjectsFromNodes)
}
function addMissingMineTasks(node, rootNodes, rootNodeType, newNodeType, functionLibraryUiObjectsFromNodes) {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === rootNodeType) {
let dataMine = rootNode
if (UI.projects.superalgos.utilities.children.isMissingChildren(node, dataMine, true) === true) {
let dataMineTasks = functionLibraryUiObjectsFromNodes.addUIObject(node, newNodeType)
dataMineTasks.payload.referenceParent = dataMine
}
}
}
}
function addAllTasks(node, rootNodes, functionLibraryUiObjectsFromNodes) {
if (node.payload === undefined) { return }
if (node.payload.referenceParent === undefined) { return }
let taskManager = functionLibraryUiObjectsFromNodes.addUIObject(node, 'Task Manager')
taskManager.name = node.payload.referenceParent.name
taskManager.payload.floatingObject.collapseToggle()
switch (node.type) {
case 'Data Mine Tasks': {
addDataTasks()
break
}
case 'Trading Mine Tasks': {
addTradingTasks()
break
}
}
function addDataTasks() {
addTaskForTradinSystem()
}
function addTradingTasks() {
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode.type === 'Trading System') {
addTaskForTradinSystem(rootNode)
}
}
}
function addTaskForTradinSystem(tradingSystem) {
let mine = node.payload.referenceParent
addTasksForBotArray(mine.sensorBots)
addTasksForBotArray(mine.indicatorBots)
addTasksForBotArray(mine.tradingBots)
function addTasksForBotArray(botsArray) {
if (botsArray === undefined) { return }
for (let i = 0; i < botsArray.length; i++) {
let bot = botsArray[i]
let task = functionLibraryUiObjectsFromNodes.addUIObject(taskManager, 'Task')
if (tradingSystem !== undefined) {
task.name = tradingSystem.name
} else {
task.name = bot.name
}
let botInstance
switch (bot.type) {
case 'Sensor Bot': {
botInstance = functionLibraryUiObjectsFromNodes.addUIObject(task, 'Sensor Bot Instance')
botInstance.name = bot.name
break
}
case 'Indicator Bot': {
botInstance = functionLibraryUiObjectsFromNodes.addUIObject(task, 'Indicator Bot Instance')
botInstance.name = bot.name
break
}
case 'Trading Bot': {
botInstance = functionLibraryUiObjectsFromNodes.addUIObject(task, 'Trading Bot Instance')
botInstance.name = bot.name
break
}
}
for (let j = 0; j < bot.processes.length; j++) {
let process = bot.processes[j]
let processInstance
switch (bot.type) {
case 'Sensor Bot': {
processInstance = functionLibraryUiObjectsFromNodes.addUIObject(botInstance, 'Sensor Process Instance')
processInstance.payload.referenceParent = process
break
}
case 'Indicator Bot': {
processInstance = functionLibraryUiObjectsFromNodes.addUIObject(botInstance, 'Indicator Process Instance')
processInstance.payload.referenceParent = process
break
}
case 'Trading Bot': {
processInstance = functionLibraryUiObjectsFromNodes.addUIObject(botInstance, 'Trading Process Instance')
processInstance.payload.referenceParent = process
if (node.payload.parentNode === undefined) { return }
if (node.payload.parentNode.payload === undefined) { return }
if (node.payload.parentNode.payload.parentNode === undefined) { return }
if (node.payload.parentNode.payload.parentNode.payload === undefined) { return }
if (node.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { return }
let environment = node.payload.parentNode.payload.parentNode.payload.parentNode
let session
switch (environment.type) {
case 'Testing Environment': {
addSession('Backtesting Session')
break
}
case 'Production Environment': {
addSession('Live Trading Session')
break
}
}
break
function addSession(sessionType) {
session = functionLibraryUiObjectsFromNodes.addUIObject(processInstance, sessionType)
session.name = task.name
let config = JSON.parse(session.config)
config.folderName = session.name.split(" ").join("-")
session.config = JSON.stringify(config)
for (let m = 0; m < rootNodes.length; m++) {
let rootNode = rootNodes[m]
if (rootNode.type === 'Trading Engine' && rootNode.isPlugin === true) {
let tradingEngine = rootNode
session.tradingEngineReference.payload.referenceParent = tradingEngine
session.tradingSystemReference.payload.referenceParent = tradingSystem
}
}
}
}
}
processInstance.payload.floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_90
}
}
}
}
}
}
@@ -0,0 +1,656 @@
function newUiObjectsFromNodes() {
thisObject = {
syncronizeTasksFoundAtWorkspaceWithBackEnd: syncronizeTasksFoundAtWorkspaceWithBackEnd,
syncronizeSessionsFoundAtWorkspaceWithBackEnd: syncronizeSessionsFoundAtWorkspaceWithBackEnd,
playTutorials: playTutorials,
recreateWorkspace: recreateWorkspace,
getNodeById: getNodeById,
tryToConnectChildrenWithReferenceParents: tryToConnectChildrenWithReferenceParents,
createUiObjectFromNode: createUiObjectFromNode,
addUIObject: addUIObject,
addMissingChildren: addMissingChildren
}
let mapOfReferenceChildren = new Map()
let mapOfNodes
let tasksFoundAtWorkspace
let sessionsFoundAtWorkspace
let tutorialsToPlay
return thisObject
function getNodeById(nodeId) {
return mapOfNodes.get(nodeId)
}
function recreateWorkspace(node, callBackFunction) {
mapOfNodes = new Map()
tasksFoundAtWorkspace = []
sessionsFoundAtWorkspace = []
tutorialsToPlay = []
removeNullRootNodes()
function removeNullRootNodes() {
for (let i = 0; i < node.rootNodes.length; i++) {
let rootNode = node.rootNodes[i]
if (rootNode === null) {
node.rootNodes.splice(i, 1)
removeNullRootNodes()
return
}
}
}
addPluginNodes()
function addPluginNodes(pluginNames) {
let blobService = newFileStorage()
let totalPlugin = 0
let totalRead = 0
for (let i = 0; i < node.rootNodes.length; i++) {
let rootNode = node.rootNodes[i]
if (rootNode.type === 'Plugins') {
let plugins = rootNode
if (plugins.pluginProjects === undefined) { continue }
for (let j = 0; j < plugins.pluginProjects.length; j++) {
let project = plugins.pluginProjects[j]
if (project.pluginDataMines !== undefined) {
totalPlugin = totalPlugin + project.pluginDataMines.pluginFiles.length
pluginAllTheseFiles(project.pluginDataMines.pluginFiles, 'Data-Mines')
}
if (project.pluginTradingMines !== undefined) {
totalPlugin = totalPlugin + project.pluginTradingMines.pluginFiles.length
pluginAllTheseFiles(project.pluginTradingMines.pluginFiles, 'Trading-Mines')
}
if (project.pluginTradingSystems !== undefined) {
totalPlugin = totalPlugin + project.pluginTradingSystems.pluginFiles.length
pluginAllTheseFiles(project.pluginTradingSystems.pluginFiles, 'Trading-Systems')
}
if (project.pluginTradingEngines !== undefined) {
totalPlugin = totalPlugin + project.pluginTradingEngines.pluginFiles.length
pluginAllTheseFiles(project.pluginTradingEngines.pluginFiles, 'Trading-Engines')
}
if (project.pluginSuperScripts !== undefined) {
totalPlugin = totalPlugin + project.pluginSuperScripts.pluginFiles.length
pluginAllTheseFiles(project.pluginSuperScripts.pluginFiles, 'Super-Scripts')
}
if (project.pluginTutorials !== undefined) {
totalPlugin = totalPlugin + project.pluginTutorials.pluginFiles.length
pluginAllTheseFiles(project.pluginTutorials.pluginFiles, 'Tutorials')
}
}
}
}
/*
If there is no Plugins node at the workspace, we load it anyways here.
*/
if (totalPlugin === 0) {
addUserDefinedNodes()
}
function pluginAllTheseFiles(pluginFiles, pluginType) {
for (let i = 0; i < pluginFiles.length; i++) {
let pluginFile = pluginFiles[i]
let name = pluginFile.name
callWebServer(undefined, 'LoadPlugin' + '/' + 'Superalgos' + '/' + pluginType + '/' + name + '.json', onFileReceived)
function onFileReceived(err, text, response) {
if (err && err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
console.log('[WARN] Cannot load plugin ' + pluginType + ' ' + name + '. The Workspace will be loaded with this plugin file missing.')
} else {
let receivedNode = JSON.parse(text)
/*
If the workspace already contains a root node with the id of the head of the hirierchy
we are loading, we remove it because the plugin file has precedende.
*/
for (let i = 0; i < node.rootNodes.length; i++) {
let rootNode = node.rootNodes[i]
if (rootNode.id === receivedNode.id) {
node.rootNodes.splice(i, 1)
break
}
}
receivedNode.isPlugin = true
if (pluginFile.pluginFilePosition !== undefined) {
let positionOffset = {
x: pluginFile.pluginFilePosition.savedPayload.position.x - receivedNode.savedPayload.position.x,
y: pluginFile.pluginFilePosition.savedPayload.position.y - receivedNode.savedPayload.position.y
}
receivedNode.positionOffset = positionOffset
}
node.rootNodes.unshift(receivedNode)
}
totalRead++
if (totalPlugin === totalRead) {
addUserDefinedNodes()
}
}
}
}
}
function addUserDefinedNodes() {
/* Create the workspace UI OBject and then continue with the root nodes. */
createUiObject(false, 'Workspace', node.name, node, undefined, undefined, 'Workspace')
if (node.rootNodes !== undefined) {
for (let i = 0; i < node.rootNodes.length; i++) {
let rootNode = node.rootNodes[i]
createUiObjectFromNode(rootNode, undefined, undefined)
}
}
tryToConnectChildrenWithReferenceParents()
if (callBackFunction !== undefined) {
callBackFunction() // The recreation of the workspace is complete
}
}
}
function syncronizeTasksFoundAtWorkspaceWithBackEnd(functionLibraryTaskFunctions) {
for (let i = 0; i < tasksFoundAtWorkspace.length; i++) {
let node = tasksFoundAtWorkspace[i]
functionLibraryTaskFunctions.syncronizeTaskWithBackEnd(node)
}
tasksFoundAtWorkspace = undefined
}
function syncronizeSessionsFoundAtWorkspaceWithBackEnd(functionLibrarySessionFunctions) {
for (let i = 0; i < sessionsFoundAtWorkspace.length; i++) {
let node = sessionsFoundAtWorkspace[i]
functionLibrarySessionFunctions.syncronizeSessionWithBackEnd(node)
}
sessionsFoundAtWorkspace = undefined
}
function playTutorials() {
for (let i = 0; i < tutorialsToPlay.length; i++) {
let node = tutorialsToPlay[i]
node.payload.uiObject.menu.internalClick('Play Tutorial')
}
tutorialsToPlay = undefined
}
function tryToConnectChildrenWithReferenceParents() {
/* We reconstruct here the reference relationships. */
for (const [key, node] of mapOfNodes) {
if (node.id === "54854f90-d121-4365-8f40-9a26e7af1097") {
console.log('ACA')
}
if (node.payload === undefined) { continue }
if (node.payload.referenceParent !== undefined) {
if (node.payload.referenceParent.cleaned === true) {
node.payload.referenceParent = mapOfNodes.get(node.payload.referenceParent.id)
if (node.payload.referenceParent === undefined) {
//console.log('[WARN]' + node.type + ' ' + node.name + ' reference parent lost during re-binding phase.')
}
continue // We were referencing a deleted node, so we replace it potentially with a newly created one.
} else {
continue // In this case the reference is already good.
}
}
if (node.savedPayload !== undefined) {
if (node.savedPayload.referenceParent !== undefined) { // these are children recreated
node.payload.referenceParent = mapOfNodes.get(node.savedPayload.referenceParent.id)
if (node.payload.referenceParent === undefined) {
//console.log('[WARN]' + node.type + ' ' + node.name + ' reference parent lost during re-binding phase.')
}
}
}
}
}
function migrateCodeToConfig(node, nodeDefinition) {
/* Code needed to Migrante from Beta 5 to Beta a Workspace */
if (nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
if (node.code !== undefined) {
node.config = node.code
node.code = undefined
}
}
}
}
function createUiObjectFromNode(node, parentNode, chainParent, positionOffset) {
/* Migration code from beta 6 to beta 7 */
if (node.project === undefined) {
node.project = 'Superalgos'
}
/*
This function can be called with a positionOffset to change the node
saved position and all of its descendants positions as well with an
offset. It can also happen that the positionOffset is defined as a property
of the node, in which case it will produce exactly the same effect.
*/
if (node.positionOffset !== undefined) {
positionOffset = node.positionOffset
}
/* Get node definition */
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition !== undefined) {
migrateCodeToConfig(node, nodeDefinition)
/* Resolve Initial Values */
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
if (node.code === undefined) {
node.code = nodeDefinition.initialValues.code
}
}
if (nodeDefinition.initialValues.config !== undefined) {
if (node.config === undefined) {
node.config = nodeDefinition.initialValues.config
}
}
}
/* For the cases where an node is not chained to its parent but to the one at the parent before it at its collection */
if (nodeDefinition.chainedToSameType === true) {
if (parentNode !== undefined) {
let parentNodeDefinition = getNodeDefinition(parentNode)
if (parentNodeDefinition !== undefined) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (property.childType === node.type) {
if (property.type === 'array') {
if (parentNode[property.name] !== undefined) {
if (parentNode[property.name].length > 1) {
let nodeChildren = parentNode[property.name]
for (let j = 0; j < nodeChildren.length; j++) {
if (node.id === nodeChildren[j].id) {
if (j > 0) {
chainParent = nodeChildren[j - 1]
}
}
}
}
}
}
}
}
}
}
}
}
/* Create Self */
createUiObject(false, node.type, node.name, node, parentNode, chainParent, node.type, positionOffset)
/* Create Children */
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
if (node[property.name] !== undefined) {
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
createUiObjectFromNode(node[property.name], node, node, positionOffset)
previousPropertyName = property.name
}
}
break
case 'array': {
let nodePropertyArray = node[property.name]
for (let m = 0; m < nodePropertyArray.length; m++) {
let arrayItem = nodePropertyArray[m]
createUiObjectFromNode(arrayItem, node, node, positionOffset)
}
}
break
}
} else {
if (property.type === 'array') {
node[property.name] = []
}
}
}
}
}
}
function addUIObject(parentNode, type, rootNodes) {
let object = {
name: 'New ' + type,
type: type,
project: parentNode.project
}
let parentNodeDefinition = getNodeDefinition(parentNode)
if (parentNodeDefinition === undefined) {
console.log('Cannot addUIOBject from parent of ' + type + ' because that type it is not defined at the APP_SCHEMA.')
}
/* Resolve Initial Values */
let nodeDefinition = getNodeDefinition(object)
if (nodeDefinition === undefined) {
console.log('Cannot addUIOBject of ' + type + ' because that type it is not defined at the APP_SCHEMA.')
return
}
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
object.code = nodeDefinition.initialValues.code
}
}
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.config !== undefined) {
object.config = nodeDefinition.initialValues.config
}
}
if (nodeDefinition.isHierarchyHead === true) {
rootNodes.push(object)
createUiObject(true, object.type, object.name, object, parentNode, undefined)
return object
}
/* For the cases where an node is not chained to its parent but to the one at the parent before it at its collection */
let chainParent = parentNode
if (nodeDefinition.chainedToSameType === true) {
if (parentNodeDefinition.properties !== undefined) {
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (property.childType === type) {
if (property.type === 'array') {
if (parentNode[property.name] !== undefined) {
if (parentNode[property.name].length > 0) {
let nodeChildren = parentNode[property.name]
chainParent = nodeChildren[nodeChildren.length - 1]
}
}
}
}
}
}
}
/* Create Empty Arrays for properties of type Array */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
if (property.type === 'array') {
object[property.name] = []
}
}
}
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
object.code = nodeDefinition.initialValues.code
}
if (nodeDefinition.initialValues.config !== undefined) {
object.config = nodeDefinition.initialValues.config
}
}
/* Connect to Parent */
if (parentNodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < parentNodeDefinition.properties.length; i++) {
let property = parentNodeDefinition.properties[i]
if (property.childType === type) {
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
parentNode[property.name] = object
previousPropertyName = property.name
}
}
break
case 'array': {
if (parentNode[property.name] === undefined) {
parentNode[property.name] = []
}
if (property.maxItems !== undefined) {
if (parentNode[property.name].length < property.maxItems) {
parentNode[property.name].push(object)
} else {
return // Object can not be created.
}
} else {
parentNode[property.name].push(object)
}
}
break
}
}
}
}
createUiObject(true, object.type, object.name, object, parentNode, chainParent)
/* Auto Add more Children */
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (property.autoAdd === true) {
addUIObject(object, property.childType)
previousPropertyName = property.name
}
}
}
break
case 'array': {
if (property.autoAdd === true) {
if (object[property.name] === undefined) {
object[property.name] = []
}
addUIObject(object, property.childType)
}
}
break
}
}
}
return object
}
function addMissingChildren(node) {
let nodeDefinition = getNodeDefinition(node)
/* Connect to Parent */
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
if (property.type === 'node') {
if (property.name !== previousPropertyName) {
if (node[property.name] === undefined) {
addUIObject(node, property.childType)
previousPropertyName = property.name
}
}
}
}
}
}
function createUiObject(userAddingNew, uiObjectType, name, node, parentNode, chainParent, title, positionOffset) {
let payload = {}
/* Mechanism related to keeping references when cloning */
if (node.id === undefined) {
node.id = newUniqueId()
} else {
/*
We need to avoid nodes having the same id. If we add nodes to a workspace that already exist with the same Id,
the nodes being added will get a new id at this moment.
*/
let testNode = mapOfNodes.get(node.id)
if (testNode !== undefined && testNode.cleaned !== true) {
console.log(testNode.name + ' already have the id of the node ' + node.name + ' being added.')
node.id = newUniqueId()
}
}
/* Default Naming */
if (name === '' || name === undefined) { name = 'My ' + uiObjectType }
/* If we are creating this object as the result of restoring a backup, share or clone, we will bring some of the saved properties to the new running instance. */
if (userAddingNew === false && uiObjectType !== 'Workspace') {
/* This following info can not be missing. */
if (node.savedPayload === undefined) {
console.log('Node ' + node.type + ' without savedPayload.', node)
return
}
if (node.savedPayload.position === undefined) {
console.log('Node ' + node.type + ' without savedPayload.position.', node)
return
}
if (node.savedPayload.targetPosition === undefined) {
console.log('Node ' + node.type + ' without savedPayload.targetPosition.', node)
return
}
/* If there is not a position offset, which happens when we are dropping a node into the designer, we create a cero vector then. */
if (positionOffset === undefined) {
positionOffset = {
x: 0,
y: 0
}
}
/* Adding the offset to the saved positions. */
node.savedPayload.targetPosition.x = node.savedPayload.targetPosition.x + positionOffset.x
node.savedPayload.targetPosition.y = node.savedPayload.targetPosition.y + positionOffset.y
node.savedPayload.position.x = node.savedPayload.position.x + positionOffset.x
node.savedPayload.position.y = node.savedPayload.position.y + positionOffset.y
/* Transferring the saved payload properties into the running instance being created. */
payload.targetPosition = {
x: node.savedPayload.targetPosition.x,
y: node.savedPayload.targetPosition.y
}
node.savedPayload.targetPosition = undefined
/* Reference children connection to parents */
if (node.savedPayload.referenceParent !== undefined) {
payload.referenceParent = mapOfNodes.get(node.savedPayload.referenceParent.id)
if (payload.referenceParent !== undefined) {
mapOfReferenceChildren.set(node.id, node)
}
}
}
/* If we are adding a new object, then we set the initial values for position and targetPosition */
if (userAddingNew === true || uiObjectType === 'Workspace') {
/* Workspace allways to the spawn position */
if (uiObjectType === 'Workspace') {
payload.position = {
x: spawnPosition.x,
y: spawnPosition.y
}
}
/* Chain parent pointing to the position of the chain parent if defined. */
if (chainParent === undefined) {
payload.targetPosition = {
x: spawnPosition.x,
y: spawnPosition.y
}
} else {
payload.targetPosition = {
x: chainParent.payload.position.x,
y: chainParent.payload.position.y
}
}
}
/* Setting the title */
if (title !== undefined) {
payload.subTitle = title
} else {
payload.subTitle = uiObjectType
}
payload.visible = true
payload.title = name
payload.node = node
payload.parentNode = parentNode
payload.chainParent = chainParent
payload.executeAction = UI.projects.superalgos.spaces.designSpace.workspace.executeAction
node.payload = payload
node.type = uiObjectType
/*
Now we copy the possible frame saved to the payload where it can be used. A saved frame stores the position of a a chartingSpace object related to a node.
This will prevent that if those charting space objects never get activated, that the frame information is lost when the workspace is saved.
*/
if (node.savedPayload !== undefined) {
if (node.savedPayload.frame !== undefined) {
let frame = {
position: {
x: 0,
y: 0
}
}
frame.position.x = node.savedPayload.frame.position.x
frame.position.y = node.savedPayload.frame.position.y
frame.width = node.savedPayload.frame.width
frame.height = node.savedPayload.frame.height
frame.radius = node.savedPayload.frame.radius
UI.projects.superalgos.utilities.loadSaveFrame.saveFrame(payload, frame)
}
if (node.savedPayload.tutorial !== undefined) {
let tutorial = {
status: node.savedPayload.tutorial.status
}
UI.projects.superalgos.utilities.tutorial.saveTutorial(payload, tutorial)
}
}
/* Now we mount the floating object where the UIOBject will be laying on top of */
UI.projects.superalgos.spaces.floatingSpace.uiObjectConstructor.createUiObject(userAddingNew, payload)
/* This is the point where we build a map with all nodes present at the workspace */
mapOfNodes.set(node.id, node)
/* We will collect all tasks at the workspace in order to later syncronize them with the backend */
if (userAddingNew === false && uiObjectType === 'Task' && node.savedPayload !== undefined) {
if (tasksFoundAtWorkspace !== undefined) { // it might be undefined when you are spawning a task that was backed up
tasksFoundAtWorkspace.push(node)
}
}
/* Check if there are sessions to run */
if (userAddingNew === false && node.savedPayload !== undefined) {
if (uiObjectType === 'Live Trading Session' || uiObjectType === 'Forward Testing Session' || uiObjectType === 'Backtesting Session' || uiObjectType === 'Paper Trading Session') {
if (sessionsFoundAtWorkspace !== undefined) { // it might be undefined when you are spawning a session that was running while backed up
sessionsFoundAtWorkspace.push(node)
}
}
}
/* Check if there are tutorials to play */
if (userAddingNew === false && node.savedPayload !== undefined) {
if (uiObjectType === 'Tutorial') {
if (node.savedPayload.uiObject.isPlaying === true) {
if (tutorialsToPlay !== undefined) { // it might be undefined when you are spawning a tutorial that was playing while backed up
tutorialsToPlay.push(node)
}
}
}
}
}
}
@@ -0,0 +1,22 @@
function newWebhookFunctions() {
thisObject = {
sendTestMessage: sendTestMessage
}
return thisObject
function sendTestMessage(node, callBackFunction) {
let testMessage = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload, 'testMessage')
let letURL = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(node.payload, 'webhookURL')
callWebServer(testMessage, letURL, onResponse)
function onResponse(err) {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE)
} else {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
}
}
@@ -0,0 +1,7 @@
function newSuperalgosGlobalsDocs() {
thisObject = {
DOCUMENTATION_URL_PREFIX: 'https://docs.superalgos.org/',
DOCUMENTATION_URL_DEFAULT: 'https://docs.superalgos.org/suite-about-this-documentation.html'
}
return thisObject
}
@@ -0,0 +1,15 @@
function newSuperalgosGlobalsZoom() {
thisObject = {
DOUBLE_CLICK_ZOOM_OUT_LEVEL: 0,
DOUBLE_CLICK_ZOOM_IN_LEVEL: 6,
DOUBLE_CLICK_ZOOM_IN_IN_LEVEL: 7,
ZOOM_OUT_THRESHOLD_FOR_NOT_HIDDING_PANELS: 12,
ZOOM_OUT_THRESHOLD_FOR_HIDDING_PANELS: 7,
ZOOM_OUT_THRESHOLD_FOR_CHANGING_TIME_FRAME: 3,
ZOOM_OUT_THRESHOLD_FOR_PACKING_OBJECTS_AT_THE_BOTTOM_OR_TOP_OF_VIEWPORT: 2,
ZOOM_OUT_THRESHOLD_FOR_PLOTTING_IN_LOW_RESOLUTION: 3,
ZOOM_OUT_THRESHOLD_FOR_DISPLAYING_TIME_MACHINES_ICONIZED: 5,
ZOOM_OUT_THRESHOLD_FOR_DISPLAYING_SCALES: 3
}
return thisObject
}
@@ -0,0 +1,139 @@
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
}
@@ -0,0 +1,462 @@
/*
The chart space is where all the charts live. What this space contains is a type of object we call Time Machine. A Time Machine is a cointainer of
charts objects. The idea is simple, all the chart objects are ploted according to the time of the Time Machine object. When the time of the Time Machine
changes, then all charts in it are replotted with the corresponging data.
*/
function newSuperalgosChartingSpace() {
const MODULE_NAME = 'Charting Space'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
visible: false,
container: undefined,
inViewport: undefined,
timeMachines: undefined,
viewport: undefined,
payload: undefined,
findTimeMachine: findTimeMachine,
onKeyPressed: onKeyPressed,
reset: reset,
oneScreenUp: oneScreenUp,
oneScreenDown: oneScreenDown,
oneScreenLeft: oneScreenLeft,
oneScreenRight: oneScreenRight,
fitFunction: fitFunction,
isThisPointVisible: isThisPointVisible,
physics: physics,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize,
finalize: finalize
}
let canvasBrowserResizedEventSubscriptionId
let timeMachinesMap
let syncWithDesignerLoop
const PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT = 25
initialSetup()
let isInitialized = false
return thisObject
function reset() {
finalize()
initialSetup()
isInitialized = false
initialize()
}
function initialSetup() {
thisObject.timeMachines = []
thisObject.visible = true
timeMachinesMap = new Map()
syncWithDesignerLoop = 0
thisObject.inViewport = new Map()
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isDraggeable = false
thisObject.container.isWheelable = false
}
function finalize() {
for (let i = 0; i < thisObject.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[i]
timeMachine.finalize()
}
thisObject.inViewport = undefined
thisObject.timeMachines = undefined
timeMachinesMap = undefined
thisObject.container.eventHandler.stopListening(canvasBrowserResizedEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
if (thisObject.viewport !== undefined) {
thisObject.viewport.finalize()
thisObject.viewport = undefined
}
thisObject.payload = undefined
}
function initialize() {
if (isInitialized === true) { return }
if (UI.projects.superalgos.spaces.designSpace === undefined) { return }
if (UI.projects.superalgos.spaces.designSpace.workspace === undefined) { return }
let rootNodes = UI.projects.superalgos.spaces.designSpace.workspace.workspaceNode.rootNodes
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
if (rootNode !== null) {
if (rootNode.type === 'Charting Space') {
thisObject.payload = rootNode.payload
}
}
}
if (thisObject.payload === undefined) {
// if (ERROR_LOG === true) { logger.write('[WARN] initialize -> There must exist a Charting Space at the Design Space in order to enable Charts. PLease create one and refreash your browser. ') }
return
}
thisObject.viewport = newViewport()
if (thisObject.payload.node.viewport === undefined) {
if (ERROR_LOG === true) { logger.write('[WARN] initialize -> There must exist a Viewport node attached to the Charting Space node in order for the Viewport save its properties. ') }
return
} else {
thisObject.viewport.payload = thisObject.payload.node.viewport.payload
}
thisObject.viewport.initialize()
canvasBrowserResizedEventSubscriptionId = canvas.eventHandler.listenToEvent('Browser Resized', resize)
isInitialized = true
}
function getContainer(point, purpose) {
if (thisObject.visible !== true) { return }
if (thisObject.viewport === undefined) { return }
if (thisObject.viewport.isThisPointInViewport(point) === false) { return }
let container
/* This first step is not actually to get the container but to allow things to be turned off in case there is a switch of focus from one time machine to another */
for (let i = 0; i < thisObject.timeMachines.length; i++) {
container = thisObject.timeMachines[i].container
if (purpose === GET_CONTAINER_PURPOSE.MOUSE_OVER) {
container.eventHandler.raiseEvent('onMouseNotOver')
}
}
/*
Now we see which is the inner most container that has it.
In this case we will ask all the time machines even if one of them already returned a matching container.
This will help the others know they are not on ofcus
*/
let containerFound
for (let i = 0; i < thisObject.timeMachines.length; i++) {
container = thisObject.timeMachines[i].getContainer(point, purpose)
if (container !== undefined) {
if (purpose !== undefined) {
if (containerFound === undefined) {
containerFound = container
}
} else {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
if (containerFound === undefined) {
containerFound = container
}
}
}
}
}
if (containerFound !== undefined) {
containerFound.space = 'Charting Space'
if (purpose === GET_CONTAINER_PURPOSE.MOUSE_WHEEL && containerFound.isWheelable !== true) {
UI.projects.superalgos.spaces.chartingSpace.viewport.onMouseWheel(event)
return
}
return containerFound
}
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
thisObject.container.space = 'Charting Space'
if (purpose === GET_CONTAINER_PURPOSE.MOUSE_WHEEL && thisObject.container.isWheelable !== true) {
UI.projects.superalgos.spaces.chartingSpace.viewport.onMouseWheel(event)
return
}
return thisObject.container
} else {
return undefined
}
}
function resize() {
thisObject.viewport.resize()
thisObject.container.frame.width = browserCanvas.width
thisObject.container.frame.height = COCKPIT_SPACE_POSITION
}
function oneScreenUp() {
if (thisObject.visible === false) { return }
let displaceVector = {
x: 0,
y: browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
UI.projects.superalgos.spaces.chartingSpace.viewport.displace(displaceVector)
}
function oneScreenDown() {
if (thisObject.visible === false) { return }
let displaceVector = {
x: 0,
y: -browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
UI.projects.superalgos.spaces.chartingSpace.viewport.displace(displaceVector)
}
function oneScreenLeft() {
if (thisObject.visible === false) { return }
let displaceVector = {
x: browserCanvas.width * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100,
y: 0
}
UI.projects.superalgos.spaces.chartingSpace.viewport.displace(displaceVector, true)
}
function oneScreenRight() {
if (thisObject.visible === false) { return }
let displaceVector = {
x: -browserCanvas.width * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100,
y: 0
}
UI.projects.superalgos.spaces.chartingSpace.viewport.displace(displaceVector, true)
}
function fitFunction(point, fullVisible) {
/* Here we check the boundaries of the resulting points, so they dont go out of the visible area. */
let returnPoint = {
x: point.x,
y: point.y
}
if (point.x > browserCanvas.width) {
returnPoint.x = browserCanvas.width
}
if (point.x < 0) {
returnPoint.x = 0
}
if (fullVisible === true) {
if (point.y > COCKPIT_SPACE_POSITION) {
returnPoint.y = COCKPIT_SPACE_POSITION
}
} else {
if (point.y > COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT / 2) {
returnPoint.y = COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT / 2
}
}
if (point.y < TOP_SPACE_HEIGHT) {
returnPoint.y = TOP_SPACE_HEIGHT
}
return returnPoint
}
function isThisPointVisible(point) {
if (point.x > browserCanvas.width) {
return false
}
if (point.x < 0) {
return false
}
if (point.y > COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT / 2) {
return false
}
if (point.y < 0) {
return false
}
return true
}
function physics() {
initialize()
thisObjectPhysics()
if (thisObject.visible !== true) { return }
if (thisObject.viewport !== undefined) {
thisObject.viewport.physics()
}
childrenPhysics()
syncWithDesigner()
}
function onKeyPressed(event) {
if (thisObject.visible !== true) { return }
for (let j = 0; j < thisObject.timeMachines.length; j++) {
let timeMachine = thisObject.timeMachines[j]
if (timeMachine.onFocus === true) {
timeMachine.onKeyPressed(event)
}
}
}
function findTimeMachine(node) {
for (let i = 0; i < thisObject.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[i]
if (timeMachine.payload.node.id === node.id) {
return timeMachine
}
}
}
function syncWithDesigner() {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.node === undefined) { return }
syncWithDesignerLoop = syncWithDesignerLoop + 0.00000000001
if (thisObject.payload.node.dashboards !== undefined) {
for (let i = 0; i < thisObject.payload.node.dashboards.length; i++) {
let dashboard = thisObject.payload.node.dashboards[i]
if (dashboard.timeMachines !== undefined) {
for (let j = 0; j < dashboard.timeMachines.length; j++) {
let node = dashboard.timeMachines[j]
let timeMachine = timeMachinesMap.get(node.id)
if (timeMachine === undefined) {
/* The time machine node is new, thus we need to initialize a new timeMachine */
initializeTimeMachine(node, syncWithDesignerLoop)
} else {
/* The time machine already exists, we tag it as existing at the current loop. */
timeMachine.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.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[i]
if (timeMachine.syncWithDesignerLoop < syncWithDesignerLoop) {
/* Must be removed */
timeMachine.finalize()
timeMachinesMap.delete(timeMachine.nodeId)
thisObject.timeMachines.splice(i, 1)
/* We remove one at the time */
return
}
}
function initializeTimeMachine(node, syncWithDesignerLoop) {
if (node.payload === undefined) { return } // not ready to consider this Time Machine
if (node.payload.uiObject === undefined) { return }
let timeMachine = newTimeMachine()
timeMachine.syncWithDesignerLoop = syncWithDesignerLoop
timeMachine.payload = node.payload
timeMachine.nodeId = node.id
timeMachinesMap.set(node.id, timeMachine)
timeMachine.payload.uiObject.setValue('Loading...')
/* Setting up the new time machine. */
timeMachine.initialize(onTimeMachineInitialized)
function onTimeMachineInitialized() {
thisObject.timeMachines.push(timeMachine)
timeMachine.payload.uiObject.setValue('')
if (UI.projects.superalgos.spaces.chartingSpace.viewport !== undefined) {
UI.projects.superalgos.spaces.chartingSpace.viewport.raiseEvents() // These events will impacts on objects just initialized.
}
}
}
}
function thisObjectPhysics() {
thisObject.container.frame.height = COCKPIT_SPACE_POSITION
if (thisObject.container.frame.height <= TOP_SPACE_HEIGHT) {
thisObject.visible = false
if (thisObject.viewport !== undefined) {
thisObject.viewport.visible = false
}
} else {
thisObject.visible = true
if (thisObject.viewport !== undefined) {
thisObject.viewport.visible = true
}
}
if (UI.projects.superalgos.spaces.chartingSpace.viewport !== undefined) {
UI.projects.superalgos.spaces.chartingSpace.viewport.resize()
}
}
function childrenPhysics() {
for (let i = 0; i < thisObject.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[i]
if (timeMachine.payload.node === undefined) {
continue
}
if (timeMachine.container.frame.isInViewPort()) {
thisObject.inViewport.set(timeMachine.payload.node.id, timeMachine)
} else {
thisObject.inViewport.delete(timeMachine.payload.node.id)
}
timeMachine.physics()
}
}
function drawBackground() {
if (thisObject.visible === false) { return }
drawSpaceBackground()
for (let i = 0; i < thisObject.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[thisObject.timeMachines.length - i - 1]
timeMachine.drawBackground()
}
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
if (thisObject.visible === false) { return }
drawBackground()
for (let i = 0; i < thisObject.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[thisObject.timeMachines.length - i - 1]
timeMachine.draw()
}
drawForeground()
}
function drawForeground() {
for (let i = 0; i < thisObject.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[thisObject.timeMachines.length - i - 1]
timeMachine.drawForeground()
}
}
function drawSpaceBackground() {
let opacity = '1'
let fromPoint = {
x: 0,
y: 0
}
let toPoint = {
x: browserCanvas.width,
y: COCKPIT_SPACE_POSITION
}
browserCanvasContext.beginPath()
browserCanvasContext.rect(fromPoint.x, fromPoint.y, toPoint.x - fromPoint.x, toPoint.y - fromPoint.y)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
}
}
@@ -0,0 +1,375 @@
/*
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: 1,
VERTICAL_MARGIN_FACTOR: 1,
HORIZONTAL_MARGIN_INVERSE_FACTOR: 0,
VERTICAL_MARGIN_INVERSE_FACTOR: 0,
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, maxWidth, maxHeight) {
/* 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 = maxWidth
thisObject.maxHeight = maxHeight
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) {
/* We will try to create a margin on the y axis so that in auto mode the charts dont get into the scales */
const TOP_MARGIN_FACTOR = 1.01
const BOTTOM_MARGIN_FACTOR = 0.99
if (thisObject.autoMinYScale === true) {
if (value * BOTTOM_MARGIN_FACTOR < newYMin) {
newYMin = value * BOTTOM_MARGIN_FACTOR
}
}
if (thisObject.autoMaxYScale === true) {
if (value * TOP_MARGIN_FACTOR> newYMax) {
newYMax = value * TOP_MARGIN_FACTOR
}
}
}
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 = UI.projects.superalgos.utilities.coordinateTransformations.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 = UI.projects.superalgos.utilities.coordinateTransformations.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
}
}
@@ -0,0 +1,729 @@
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 (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomLevel === UI.projects.superalgos.globals.zoom.DOUBLE_CLICK_ZOOM_OUT_LEVEL) {
UI.projects.superalgos.spaces.chartingSpace.viewport.displaceToContainer(thisObject.container.parentContainer)
UI.projects.superalgos.spaces.chartingSpace.viewport.zoomAtCenter(UI.projects.superalgos.globals.zoom.DOUBLE_CLICK_ZOOM_IN_LEVEL)
return
}
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomLevel === UI.projects.superalgos.globals.zoom.DOUBLE_CLICK_ZOOM_IN_LEVEL) {
UI.projects.superalgos.spaces.chartingSpace.viewport.zoomAtCenter(UI.projects.superalgos.globals.zoom.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, forceExecution) {
if (forceExecution !== true) {
if (whereIsMouseOver !== 'center' ) {return}
}
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') {
if (ARE_WE_RECORDING_A_MARKET_PANORAMA === true) {
if (PANORAMA_WAS_PANNED === false) {
PANORAMA_WAS_PANNED = true
onDragStarted(event)
thisObject.container.frame.position.x = thisObject.container.frame.position.x - STEP * 2
whatHappened = 'left or right arrow key pressed'
}
} else {
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 = UI.projects.superalgos.utilities.coordinateTransformations.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 = UI.projects.superalgos.spaces.chartingSpace.viewport.unTransformThisPoint(mouse.position)
let mouseWhenDragStartedNoZoom = UI.projects.superalgos.spaces.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 = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystemWhenDragStarted)
let newMaxRate = UI.projects.superalgos.utilities.dateRateTransformations.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 = UI.projects.superalgos.utilities.dateRateTransformations.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 = UI.projects.superalgos.utilities.dateRateTransformations.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 UI.projects.superalgos.utilities.dateRateTransformations.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 UI.projects.superalgos.utilities.dateRateTransformations.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 UI.projects.superalgos.utilities.dateRateTransformations.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 UI.projects.superalgos.utilities.dateRateTransformations.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 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pointA1, thisObject.container)
pointA2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pointA2, thisObject.container)
pointA3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pointA3, thisObject.container)
pointA4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pointA4, thisObject.container)
pointB1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pointB1, thisObject.container)
pointB2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pointB2, thisObject.container)
pointB3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(pointB3, thisObject.container)
pointB4 = UI.projects.superalgos.utilities.coordinateTransformations.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 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoViewport(pointA1)
pointA2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoViewport(pointA2)
pointA3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoViewport(pointA3)
pointA4 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoViewport(pointA4)
pointB1 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoViewport(pointB1)
pointB2 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoViewport(pointB2)
pointB3 = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoViewport(pointB3)
pointB4 = UI.projects.superalgos.spaces.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()
}
}
}
@@ -0,0 +1,489 @@
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++) {
UI.projects.superalgos.spaces.panelSpace.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.config.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.baseAsset.config.codeName
let quotedAsset = layer.quotedAsset.config.codeName
let market = {
baseAsset: baseAsset,
quotedAsset: quotedAsset
}
let productDefinition = layer.productDefinition
let bot = layer.bot
let dataMine = layer.dataMine
let exchange = layer.exchange
let plotterModule = layer.plotterModule
let session
let tradingSystem
let tradingEngine
/*
A layer can be referencing a Data Product in two different branches of the Network hiriatchy.
In one of those braches we can get the Session node, at the other we Cannot.
*/
let sessionReference = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(layer.definition, 'Session Reference', undefined, false, true, true, true)
if (sessionReference !== undefined) {
session = sessionReference.referenceParent
if (session === undefined) {
logger.write('[ERROR] initializePlotter -> Sessioin is Undefined at Session Reference -> Plotter will not be loaded. ')
return
}
/* From the session we might be able to reach the Trading System or the Trading Engine */
if (session.tradingSystemReference !== undefined) {
tradingSystem = session.tradingSystemReference.referenceParent
}
if (session.tradingEngineReference !== undefined) {
tradingEngine = session.tradingEngineReference.referenceParent
}
}
let host = layer.networkNode.config.host
let webPort = layer.networkNode.config.webPort
if (host === undefined) { host = window.location.hostname }
if (webPort === undefined) { webPort = window.location.port }
let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(layer.networkNode.id)
storage.initialize(
dataMine,
bot,
session,
productDefinition,
exchange,
market,
datetime,
timeFrame,
host,
webPort,
eventsServerClient,
onProductStorageInitialized
)
function onProductStorageInitialized(err) {
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.config.isLegacy !== true) {
plotter = newPlotter()
} else {
plotter = getNewPlotter(dataMine.config.codeName, plotterModule.parentNode.config.codeName, plotterModule.config.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, productDefinition)
function onPlotterInizialized() {
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 (productDefinition !== undefined) {
/* Here we setup the panels associated with this plotter */
for (let i = 0; i < plotterModule.panels.length; i++) {
let panel = plotterModule.panels[i]
let parameters = {
dataMine: dataMine.config.codeName,
plotterCodeName: plotterModule.parentNode.config.codeName,
moduleCodeName: plotterModule.config.codeName,
panelNode: panel
}
let owner = thisObject.payload.node.payload.parentNode.id // Panels are owned by the time machine.
let plotterPanelHandle = UI.projects.superalgos.spaces.panelSpace.createNewPanel('Plotter Panel', parameters, owner, layer.session)
let plotterPanel = UI.projects.superalgos.spaces.panelSpace.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
/*
Next we will check the different types of Plotting related to connecting to an existing node branch.
*/
if (plotterModule.nodesHighlights !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesHighlights = newNodesHighlights()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesHighlights.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesHighlights.initialize(tradingEngine)
break
}
connector.nodesHighlights.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesHighlights.onRecordChange)
}
if (plotterModule.nodesValues !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesValues = newNodesValues()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesValues.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesValues.initialize(tradingEngine)
break
}
connector.nodesValues.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesValues.onRecordChange)
}
if (plotterModule.nodesErrors !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesErrors = newNodesErrors()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesErrors.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesErrors.initialize(tradingEngine)
break
}
connector.nodesErrors.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesErrors.onRecordChange)
}
if (plotterModule.nodesWarnings !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesWarnings = newNodesWarnings()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesWarnings.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesWarnings.initialize(tradingEngine)
break
}
connector.nodesWarnings.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesWarnings.onRecordChange)
}
if (plotterModule.nodesInfos !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesInfos = newNodesInfos()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesInfos.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesInfos.initialize(tradingEngine)
break
}
connector.nodesInfos.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesInfos.onRecordChange)
}
if (plotterModule.nodesRunning !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesRunning = newNodesRunning()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesRunning.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesRunning.initialize(tradingEngine)
break
}
connector.nodesRunning.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesRunning.onRecordChange)
}
if (plotterModule.nodesStatus !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesStatus = newNodesStatus()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesStatus.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesStatus.initialize(tradingEngine)
break
}
connector.nodesStatus.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesStatus.onRecordChange)
}
if (plotterModule.nodesProgress !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesProgress = newNodesProgress()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesProgress.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesProgress.initialize(tradingEngine)
break
}
connector.nodesProgress.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesProgress.onRecordChange)
}
if (plotterModule.nodesAnnouncements !== undefined && plotterModule.config.connectTo !== undefined) {
connector.nodesAnnounements = newNodesAnnouncements()
switch (plotterModule.config.connectTo) {
case 'Trading System':
connector.nodesAnnounements.initialize(tradingSystem)
break
case 'Trading Engine':
connector.nodesAnnounements.initialize(tradingEngine)
break
}
connector.nodesAnnounements.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.nodesAnnounements.onRecordChange)
}
/*
Another type of plotting is with Record Values. This method uses the record definition to find the target node
and from there is looks into its children all based on the Record Definition configuration.
*/
if (plotterModule.recordValues !== undefined) {
connector.recordValues = newRecordValues()
connector.recordValues.initialize(tradingSystem, tradingEngine, productDefinition)
connector.recordValues.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', connector.recordValues.onRecordChange)
}
}
thisObject.connectors.push(connector)
}
}
}
} 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)
}
}
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++) {
UI.projects.superalgos.spaces.panelSpace.destroyPanel(connector.panels[j])
}
/* Finally the Storage Objects */
finalizeNodesPlotting(connector)
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 finalizeNodesPlotting(connector) {
if (connector.nodesHighlights !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesHighlights.onRecordChangeEventsSubscriptionId)
connector.nodesHighlights.finalize()
}
if (connector.nodesValues !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesValues.onRecordChangeEventsSubscriptionId)
connector.nodesValues.finalize()
}
if (connector.nodesErrors !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesErrors.onRecordChangeEventsSubscriptionId)
connector.nodesErrors.finalize()
}
if (connector.nodesWarnings !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesWarnings.onRecordChangeEventsSubscriptionId)
connector.nodesWarnings.finalize()
}
if (connector.nodesInfos !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesInfos.onRecordChangeEventsSubscriptionId)
connector.nodesInfos.finalize()
}
if (connector.nodesStatus !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesStatus.onRecordChangeEventsSubscriptionId)
connector.nodesStatus.finalize()
}
if (connector.nodesProgress !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.Progress.onRecordChangeEventsSubscriptionId)
connector.Progress.finalize()
}
if (connector.nodesRunning !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.nodesRunning.onRecordChangeEventsSubscriptionId)
connector.nodesRunning.finalize()
}
if (connector.recordValues !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.recordValues.onRecordChangeEventsSubscriptionId)
connector.recordValues.finalize()
}
}
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
}
}
@@ -0,0 +1,46 @@
function newNodesAnnouncements() {
const MODULE_NAME = 'Nodes Announcements'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.announcements
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setValue(value, 20)
}
}
@@ -0,0 +1,47 @@
function newNodesErrors() {
const MODULE_NAME = 'Nodes Errors'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.errors
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === '') {
node.payload.uiObject.resetErrorMessage()
} else {
node.payload.uiObject.setErrorMessage(value)
}
}
}
@@ -0,0 +1,42 @@
function newNodesHighlights() {
const MODULE_NAME = 'Nodes Highlights'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.highlights
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let nodeId = array[i]
highlight(nodeId)
}
}
function highlight(nodeId) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
node.payload.uiObject.highlight(10)
}
}
@@ -0,0 +1,47 @@
function newNodesInfos() {
const MODULE_NAME = 'Nodes Infos'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.infos
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === '') {
node.payload.uiObject.resetInfoMessage()
} else {
node.payload.uiObject.setInfoMessage(value)
}
}
}
@@ -0,0 +1,47 @@
function newNodesProgress() {
const MODULE_NAME = 'Nodes Progress'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.progress
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setPercentage(value, 30)
}
}
@@ -0,0 +1,47 @@
function newNodesRunning() {
const MODULE_NAME = 'Nodes Running'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.running
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.runningAtBackend()
}
}
@@ -0,0 +1,47 @@
function newNodesStatus() {
const MODULE_NAME = 'Nodes Status'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.status
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setStatus(value, 30)
}
}
@@ -0,0 +1,48 @@
function newNodesValues() {
const MODULE_NAME = 'Nodes Values'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.values
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.valueAtAngle = false
node.payload.uiObject.setValue(value, 1)
}
}
@@ -0,0 +1,47 @@
function newNodesWarnings() {
const MODULE_NAME = 'Nodes Warnings'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let hiriarchyMap
return thisObject
function finalize() {
hiriarchyMap = undefined
}
function initialize(pRootNode) {
let rootNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pRootNode.id)
hiriarchyMap = UI.projects.superalgos.utilities.hierarchy.getHiriarchyMap(rootNode)
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
let array = currentRecord.warnings
if (array === undefined) { return }
for (let i = 0; i < array.length; i++) {
let arrayItem = array[i]
let nodeId = arrayItem[0]
let value = arrayItem[1]
applyValue(nodeId, value)
}
}
function applyValue(nodeId, value) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
let node = hiriarchyMap.get(nodeId)
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === '') {
node.payload.uiObject.resetWarningMessage()
} else {
node.payload.uiObject.setWarningMessage(value)
}
}
}
@@ -0,0 +1,918 @@
function newPlotter() {
const MODULE_NAME = 'Plotter'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
currentRecord: undefined,
container: undefined,
fitFunction: undefined,
onDailyFileLoaded: onDailyFileLoaded,
initialize: initialize,
finalize: finalize,
getContainer: getContainer,
setTimeFrame: setTimeFrame,
setDatetime: setDatetime,
setCoordinateSystem: setCoordinateSystem,
draw: draw
}
let container = newContainer()
container.initialize()
thisObject.container = container
let coordinateSystem
let slotHeight = (UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y) / 10 // This is the amount of slots available
let mustRecalculateDataPoints = false
let atMousePositionFillStyles = new Map()
let atMousePositionStrokeStyles = new Map()
let timeFrame // This will hold the current Time Frame the user is at.
let datetime // This will hold the current Datetime the user is at.
let marketFile // This is the current Market File being plotted.
let fileCursor // This is the current File Cursor being used to retrieve Daily Files.
let marketFiles // This object will provide the different Market Files at different Time Periods.
let dailyFiles // This object will provide the different File Cursors at different Time Periods.
let productDefinition // Here we store a snapshot of the product definition which references this plotter.
let records = [] // We will have the information to be plotted here.
let userPositionDate
let minUserPositionRate
let maxUserPositionRate
let onMouseOverEventSuscriptionId
let zoomChangedEventSubscriptionId
let offsetChangedEventSubscriptionId
let dragFinishedEventSubscriptionId
let dimmensionsChangedEventSubscriptionId
let marketFilesUpdatedEventSubscriptionId
let dailyFilesUpdatedEventSubscriptionId
let onDisplaceEventSubscriptionId
let scaleChangedEventSubscriptionId
let logged = false
return thisObject
function finalize() {
try {
/* Stop listening to the necesary events. */
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId)
UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.stopListening(offsetChangedEventSubscriptionId)
canvas.eventHandler.stopListening(dragFinishedEventSubscriptionId)
thisObject.container.eventHandler.stopListening(dimmensionsChangedEventSubscriptionId)
marketFiles.eventHandler.stopListening(marketFilesUpdatedEventSubscriptionId)
dailyFiles.eventHandler.stopListening(dailyFilesUpdatedEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onDisplaceEventSubscriptionId)
thisObject.fitFunction = undefined
/* Clear References */
marketFiles = undefined
dailyFiles = undefined
datetime = undefined
timeFrame = undefined
marketFile = undefined
fileCursor = undefined
finalizeCoordinateSystem()
coordinateSystem = undefined
slotHeight = undefined
mustRecalculateDataPoints = undefined
atMousePositionFillStyles = undefined
atMousePositionStrokeStyles = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack.stack) }
}
}
function initialize(pStorage, pDatetime, pTimeFrame, pCoordinateSystem, callBackFunction, pProductDefinition) {
try {
/* Store the information received. */
marketFiles = pStorage.marketFiles[0]
dailyFiles = pStorage.dailyFiles[0]
datetime = pDatetime
timeFrame = pTimeFrame
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
productDefinition = pProductDefinition
/* We need a Market File in order to calculate the Y scale, since this scale depends on actual data. */
marketFile = marketFiles.getFile(ONE_DAY_IN_MILISECONDS) // This file is the one processed faster.
/* Now we set the right files according to current Period. */
marketFile = marketFiles.getFile(pTimeFrame)
fileCursor = dailyFiles.getFileCursor(pTimeFrame)
/* Listen to the necesary events. */
zoomChangedEventSubscriptionId = UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.listenToEvent('Zoom Changed', onViewportZoomChanged)
offsetChangedEventSubscriptionId = UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.listenToEvent('Position Changed', onViewportPositionChanged)
dragFinishedEventSubscriptionId = canvas.eventHandler.listenToEvent('Drag Finished', onDragFinished)
marketFilesUpdatedEventSubscriptionId = marketFiles.eventHandler.listenToEvent('Files Updated', onMarketFilesUpdated)
dailyFilesUpdatedEventSubscriptionId = dailyFiles.eventHandler.listenToEvent('Files Updated', onDailyFilesUpdated)
onDisplaceEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onDisplace', onDisplace)
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
/* Get ready for plotting. */
recalculate()
dimmensionsChangedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('Dimmensions Changed', function () {
recalculate()
})
callBackFunction()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
function initializeCoordinateSystem() {
scaleChangedEventSubscriptionId = coordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
}
function finalizeCoordinateSystem() {
coordinateSystem.eventHandler.stopListening(scaleChangedEventSubscriptionId)
}
function onScaleChanged() {
mustRecalculateDataPoints = true
recalculate()
}
function onMouseOver(event) {
let userPosition = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(event, thisObject.container, coordinateSystem)
userPositionDate = userPosition.valueOf()
let minPositionPoint = {
x: event.x,
y: event.y + 4
}
minUserPositionRate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtBrowserCanvas(minPositionPoint, thisObject.container, coordinateSystem)
let maxPositionPoint = {
x: event.x,
y: event.y - 4
}
maxUserPositionRate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtBrowserCanvas(maxPositionPoint, thisObject.container, coordinateSystem)
}
function onMarketFilesUpdated() {
try {
let newMarketFile = marketFiles.getFile(timeFrame)
if (newMarketFile !== undefined) {
marketFile = newMarketFile
mustRecalculateDataPoints = true
recalculate()
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onMarketFilesUpdated -> err = ' + err.stack.stack) }
}
}
function onDailyFilesUpdated() {
try {
let newFileCursor = dailyFiles.getFileCursor(timeFrame)
if (newFileCursor !== undefined) {
fileCursor = newFileCursor
mustRecalculateDataPoints = true
recalculate()
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDailyFilesUpdated -> err = ' + err.stack.stack) }
}
}
function getContainer(point) {
try {
let container
/* First we check if this point is inside this space. */
if (thisObject.container.frame.isThisPointHere(point) === true) {
return thisObject.container
} else {
/* This point does not belong to this space. */
return undefined
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] getContainer -> err = ' + err.stack) }
}
}
function setTimeFrame(pTimeFrame) {
try {
if (timeFrame !== pTimeFrame) {
timeFrame = pTimeFrame
mustRecalculateDataPoints = true
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
marketFile = marketFiles.getFile(pTimeFrame)
} else {
fileCursor = dailyFiles.getFileCursor(pTimeFrame)
}
recalculate()
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] setTimeFrame -> err = ' + err.stack) }
}
}
function setDatetime(pDatetime) {
datetime = pDatetime
}
function setCoordinateSystem(pCoordinateSystem) {
finalizeCoordinateSystem()
coordinateSystem = pCoordinateSystem
initializeCoordinateSystem()
}
function onDailyFileLoaded(event) {
try {
if (event.currentValue === event.totalValue) {
/* This happens only when all of the files in the cursor have been loaded. */
recalculate()
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDailyFileLoaded -> err = ' + err.stack) }
}
}
function draw() {
try {
thisObject.container.frame.draw()
plot()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] draw -> err = ' + err.stack) }
}
}
function recalculate() {
try {
if (timeFrame >= _1_HOUR_IN_MILISECONDS) {
recalculateUsingMarketFiles()
} else {
recalculateUsingDailyFiles()
}
thisObject.container.eventHandler.raiseEvent('CandleStairs Changed', records) // --> Check This
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] recalculate -> err = ' + err.stack) }
}
}
function jsonifyDataFile(dataFile, recordDefinition, farLeftDate, farRightDate) {
/*
This function has as an input the raw data on files and creates with it an array of JSON objects
with not calculated properties for later being consumed by Formulas
*/
let jsonifiedArray = []
let previous
for (let i = 0; i < dataFile.length; i++) {
let record = {}
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.config.isCalculated !== true) {
record[property.config.codeName] = dataFile[i][j]
}
}
if (productDefinition.config.nodePathType === 'array') {
/*
When we have an array configuration, we know that the last field of the record
contains the array index, which is needed to correctly plot this data. Since
this index is not part of the product definition, we will restore its value in
this way:
*/
record.index = dataFile[i][recordDefinition.properties.length]
}
if (record.begin === undefined || record.end === undefined) {
console.log('Could not find the property begin or end which are needed for the plotter to work. productDefinition.config.codeName = ' + productDefinition.config.codeName)
continue
}
if (record.end <= farLeftDate.valueOf()) { continue }
if (record.begin >= farRightDate.valueOf()) { continue }
if (record.end < coordinateSystem.min.x) { continue }
if (record.begin > coordinateSystem.max.x) { continue }
record.previous = previous
jsonifiedArray.push(record)
previous = record
}
return jsonifiedArray
}
function calculationsProcedure(jsonArray, recordDefinition, calculationsProcedure, timeFrame) {
/*
This function has as an input an array of JSON objects, and it adds calculated properties to
complete the set of properties that will be available.
*/
let system = { // These are the available system variables to be used in User Code and Formulas
timeFrame: timeFrame,
ONE_DAY_IN_MILISECONDS: ONE_DAY_IN_MILISECONDS
}
let variable = {} // This is the structure where the user will define its own variables that will be shared across different config blocks and formulas.
let results = []
/* This is Initialization Code */
if (calculationsProcedure.initialization !== undefined) {
if (calculationsProcedure.initialization.javascriptCode !== undefined) {
try {
eval(calculationsProcedure.initialization.javascriptCode.code)
} catch (err) {
logger.write('[ERROR] calculationsProcedure -> initialization -> Error executing User Code. Error = ' + err.stack.stack)
logger.write('[ERROR] calculationsProcedure -> initialization -> Error executing User Code. Code = ' + calculationsProcedure.initialization.javascriptCode.code)
throw ('Error Executing User Code.')
}
}
}
/* This is Initialization Code */
if (calculationsProcedure.loop !== undefined) {
if (calculationsProcedure.loop.javascriptCode !== undefined) {
for (let index = 0; index < jsonArray.length; index++) {
let product = jsonArray[index]
/* This is Loop Code */
try {
eval(calculationsProcedure.loop.javascriptCode.code)
} catch (err) {
logger.write('[ERROR] calculationsProcedure -> loop -> Error executing User Code. Error = ' + err.stack.stack)
logger.write('[ERROR] calculationsProcedure -> loop -> Error executing User Code. product = ' + JSON.stringify(product))
logger.write('[ERROR] calculationsProcedure -> loop -> Error executing User Code. Code = ' + calculationsProcedure.loop.javascriptCode.code)
throw ('Error Executing User Code.')
}
/* For each calculated property we apply its formula */
for (let j = 0; j < recordDefinition.properties.length; j++) {
let property = recordDefinition.properties[j]
if (property.config.isCalculated === true) {
if (property.formula !== undefined) {
if (property.formula.code !== undefined) {
try {
let newValue = eval(property.formula.code)
let currentRecord = product
currentRecord[property.config.codeName] = newValue
} catch (err) {
logger.write('[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Error = ' + err.stack.stack)
logger.write('[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. product = ' + JSON.stringify(product))
logger.write('[ERROR] calculationsProcedure -> loop -> formula -> Error executing User Code. Code = ' + property.formula.code)
throw ('Error Executing User Code.')
}
}
}
}
}
/* Adding the new element to the resulting array */
results.push(product)
}
}
}
return results
}
function recalculateUsingDailyFiles() {
try {
if (fileCursor === undefined) {
records = []
return
} // We need to wait until there is a fileCursor available or maybe this indicator does not produce data for the current Time Frame
if (fileCursor.files.size === 0) { return } // We need to wait until there are files in the cursor
let daysOnSides = getSideDays(timeFrame)
let leftDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem)
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem)
let dateDiff = rightDate.valueOf() - leftDate.valueOf()
let farLeftDate = new Date(leftDate.valueOf() - dateDiff * 1.5)
let farRightDate = new Date(rightDate.valueOf() + dateDiff * 1.5)
let currentDate = new Date(farLeftDate.valueOf())
records = []
while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) {
let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2)
let dailyFile = fileCursor.files.get(stringDate)
if (dailyFile !== undefined) {
/* Transform the current file content into an array of JSON objects */
let jsonData = jsonifyDataFile(dailyFile, productDefinition.record, farLeftDate, farRightDate)
/* Add the calculated properties */
if (productDefinition.calculations !== undefined) {
let calculationsResult = calculationsProcedure(jsonData, productDefinition.record, productDefinition.calculations, timeFrame)
records.push(...calculationsResult) // This adds records to the current array.
} else {
records.push(...jsonData)// This adds records to the current array.
}
}
currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS)
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] recalculateUsingDailyFiles -> err = ' + err.stack) }
}
}
function recalculateUsingMarketFiles() {
try {
if (marketFile === undefined) {
records = []
return
} // Initialization not complete yet or this indicator does not produce data for the current time frame
let daysOnSides = getSideDays(timeFrame)
let leftDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem)
let rightDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight, thisObject.container, coordinateSystem)
let dateDiff = rightDate.valueOf() - leftDate.valueOf()
leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5)
rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5)
for (let i = 0; i < records.length; i++) {
let record = records[i]
record.fillStyle = undefined
record.strokeStyle = undefined
record.dataPoints = undefined
record.previous = undefined
records[i] = {}
}
records = []
/* Transform the current file content into an array of JSON objects */
let jsonData = jsonifyDataFile(marketFile, productDefinition.record, leftDate, rightDate)
/* Add the calculated properties */
if (productDefinition.calculations !== undefined) {
let calculationsResult = calculationsProcedure(jsonData, productDefinition.record, productDefinition.calculations, timeFrame)
records.push(...calculationsResult) // This adds records to the current array.
} else {
records.push(...jsonData)// This adds records to the current array.
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] recalculateUsingMarketFiles -> err = ' + err.stack) }
}
}
function plot() {
try {
/* Clean the pannel at places where there is no record. */
thisObject.container.eventHandler.raiseEvent('Current Record Changed', undefined)
for (let i = 0; i < records.length; i++) {
let record = records[i]
/*
In the formulas to create plotters, we allos users to reference the previous record.
To enable that we need to link all records to the previous one in this way.
*/
if (i == 0) {
record.previous = {} // this way it wont be undefined
} else {
record.previous = records[i - 1]
}
let beginPoint = {
x: record.begin,
y: 0
}
let endPoint = {
x: record.end,
y: 0
}
beginPoint = coordinateSystem.transformThisPoint(beginPoint)
endPoint = coordinateSystem.transformThisPoint(endPoint)
beginPoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(beginPoint, thisObject.container)
endPoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(endPoint, thisObject.container)
beginPoint = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(beginPoint)
endPoint = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(endPoint)
beginPoint = thisObject.fitFunction(beginPoint)
endPoint = thisObject.fitFunction(endPoint)
if (endPoint.x < UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.x || beginPoint.x > UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.x) {
continue
}
let atMousePosition = false
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
if (record.rate !== undefined && productDefinition.referenceParent.config.useRateAtMousePosition === true) {
/* Current Record depends also on rate */
if (record.rate >= minUserPositionRate && record.rate <= maxUserPositionRate) {
atMousePosition = true
thisObject.container.eventHandler.raiseEvent('Current Record Changed', record)
}
} else {
/* Current Record depends only on begin and end. */
atMousePosition = true
thisObject.container.eventHandler.raiseEvent('Current Record Changed', record)
}
}
/* If there is code we execute it now. */
if (productDefinition.referenceParent.javascriptCode !== undefined) {
eval(productDefinition.referenceParent.javascriptCode.code)
}
if (productDefinition.referenceParent.shapes === undefined) { continue }
if (productDefinition.referenceParent.shapes.chartPoints === undefined) { continue }
let dataPoints = new Map()
if (record.dataPoints !== undefined && mustRecalculateDataPoints === false) {
/* We use the datapoints already calculated. */
dataPoints = record.dataPoints
} else {
if (logged === false) {
logged = true
}
/* It seems we need to calculate the data points this time. */
for (let k = 0; k < productDefinition.referenceParent.shapes.chartPoints.length; k++) {
let chartPoints = productDefinition.referenceParent.shapes.chartPoints[k]
for (let j = 0; j < chartPoints.points.length; j++) {
let point = chartPoints.points[j]
if (point.pointFormula !== undefined) {
let x = 0
let y = 0
eval(point.pointFormula.code)
let rawPoint = {
x: x,
y: y
}
/*
The information we store in files is independent from the charing system and its coordinate systems.
That means that the first thing we allways need to do is to trasform these points to the coordinate system of the timeline.
*/
let dataPoint
dataPoint = coordinateSystem.transformThisPoint(rawPoint)
dataPoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(dataPoint, thisObject.container)
let testPoint = {
x: dataPoint.x,
y: dataPoint.y
}
dataPoint = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
if (testPoint.x === dataPoint.x) {
dataPoint.isInViewPort = true
} else {
dataPoint.isInViewPort = false
}
/* Store the data point at the local map */
dataPoint.rawPoint = rawPoint
dataPoints.set(point.id, dataPoint)
}
}
}
/* Remember this datapoints, so that we do not need to calculate them again. */
record.dataPoints = dataPoints
}
/* Here we are going to plot all the polygons. */
for (let j = 0; j < productDefinition.referenceParent.shapes.polygons.length; j++) {
let polygon = productDefinition.referenceParent.shapes.polygons[j]
/* We will check if we need to plot this Polygon or not. */
if (polygon.polygonCondition !== undefined) {
let mustPlot = eval(polygon.polygonCondition.code)
if (mustPlot !== true) { continue }
}
let calculatedStyle
/* Finding out the fill style */
let fillStyle = { // default values
opacity: 1,
paletteColor: UI_COLOR.BLACK
}
if (polygon.polygonBody !== undefined) {
if (record.fillStyle === undefined) {
record.fillStyle = new Map()
}
calculatedStyle = record.fillStyle.get(polygon.id)
if (calculatedStyle !== undefined) {
/* We use the already calculated style */
fillStyle = calculatedStyle
} else {
/* Get the default style if exists */
if (polygon.polygonBody.style !== undefined) {
if (polygon.polygonBody.style.config !== undefined) {
if (polygon.polygonBody.style.config.default !== undefined) {
let bodyStyle = polygon.polygonBody.style.config.default
if (bodyStyle.opacity !== undefined) { fillStyle.opacity = bodyStyle.opacity }
if (bodyStyle.paletteColor !== undefined) { fillStyle.paletteColor = eval(bodyStyle.paletteColor) }
}
}
}
/* Apply conditional styles */
if (polygon.polygonBody.styleConditions !== undefined) {
for (let k = 0; k < polygon.polygonBody.styleConditions.length; k++) {
let condition = polygon.polygonBody.styleConditions[k]
let value = eval(condition.code)
if (value === true) {
if (condition.style !== undefined) {
let bodyStyle = condition.style.config
if (bodyStyle.opacity !== undefined) { fillStyle.opacity = bodyStyle.opacity }
if (bodyStyle.paletteColor !== undefined) { fillStyle.paletteColor = eval(bodyStyle.paletteColor) }
}
}
}
}
/* Get the atMousePosition style if exists */
if (polygon.polygonBody.style !== undefined) {
if (polygon.polygonBody.style.config.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBody.style.config.atMousePosition
let atMousePositionStyle = {}
if (atMousePositionStyleDefinition.opacity !== undefined) { atMousePositionStyle.opacity = atMousePositionStyleDefinition.opacity }
if (atMousePositionStyleDefinition.paletteColor !== undefined) { atMousePositionStyle.paletteColor = eval(atMousePositionStyleDefinition.paletteColor) }
atMousePositionFillStyles.set(polygon.id, atMousePositionStyle)
}
}
record.fillStyle.set(polygon.id, fillStyle)
}
}
/* Finding out the stroke style */
let strokeStyle = { // default values
opacity: 1,
paletteColor: UI_COLOR.BLACK,
lineWidth: 1,
lineDash: [0, 0]
}
if (polygon.polygonBorder !== undefined) {
if (record.strokeStyle === undefined) {
record.strokeStyle = new Map()
}
calculatedStyle = record.strokeStyle.get(polygon.id)
if (calculatedStyle !== undefined) {
/* We use the already calculated style */
strokeStyle = calculatedStyle
} else {
/* Get the default style if exists */
if (polygon.polygonBorder.style !== undefined) {
if (polygon.polygonBorder.style.config !== undefined) {
if (polygon.polygonBorder.style.config.default !== undefined) {
let borderStyle = polygon.polygonBorder.style.config.default
if (borderStyle.opacity !== undefined) { strokeStyle.opacity = borderStyle.opacity }
if (borderStyle.paletteColor !== undefined) { strokeStyle.paletteColor = eval(borderStyle.paletteColor) }
if (borderStyle.lineWidth !== undefined) { strokeStyle.lineWidth = borderStyle.lineWidth }
if (borderStyle.lineDash !== undefined) { strokeStyle.lineDash = borderStyle.lineDash }
}
}
}
/* Apply conditional styles */
if (polygon.polygonBorder.styleConditions !== undefined) {
for (let k = 0; k < polygon.polygonBorder.styleConditions.length; k++) {
let condition = polygon.polygonBorder.styleConditions[k]
let value = eval(condition.code)
if (value === true) {
if (condition.style !== undefined) {
let borderStyle = condition.style.config
if (borderStyle.opacity !== undefined) { strokeStyle.opacity = borderStyle.opacity }
if (borderStyle.paletteColor !== undefined) { strokeStyle.paletteColor = eval(borderStyle.paletteColor) }
if (borderStyle.lineWidth !== undefined) { strokeStyle.lineWidth = borderStyle.lineWidth }
if (borderStyle.lineDash !== undefined) { strokeStyle.lineDash = borderStyle.lineDash }
}
}
}
}
/* Get the atMousePosition style if exists */
if (polygon.polygonBorder.style !== undefined) {
if (polygon.polygonBorder.style.config.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBorder.style.config.atMousePosition
let atMousePositionStyle = {}
if (atMousePositionStyleDefinition.opacity !== undefined) { atMousePositionStyle.opacity = atMousePositionStyleDefinition.opacity }
if (atMousePositionStyleDefinition.paletteColor !== undefined) { atMousePositionStyle.paletteColor = eval(atMousePositionStyleDefinition.paletteColor) }
if (atMousePositionStyleDefinition.lineWidth !== undefined) { atMousePositionStyle.lineWidth = atMousePositionStyleDefinition.lineWidth }
if (atMousePositionStyleDefinition.lineDash !== undefined) { atMousePositionStyle.lineDash = atMousePositionStyleDefinition.lineDash }
atMousePositionStrokeStyles.set(polygon.id, atMousePositionStyle)
}
}
record.strokeStyle.set(polygon.id, strokeStyle)
}
}
/* Draw the Polygon */
browserCanvasContext.beginPath()
for (let k = 0; k < polygon.polygonVertexes.length; k++) {
let polygonVertex = polygon.polygonVertexes[k]
if (polygonVertex.referenceParent !== undefined) {
let dataPointObject = dataPoints.get(polygonVertex.referenceParent.id)
if (dataPointObject === undefined) {
polygonVertex.payload.uiObject.setErrorMessage('Vertex not referencing any Point')
console.log('[WARN] You have a Polygon Vertex not referencing any Point.')
continue
}
let dataPoint = {
x: dataPointObject.x,
y: dataPointObject.y
}
/* We make sure the points do not fall outside the viewport visible area. This step allways need to be done. */
dataPoint = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
/*
Contributing to Auto-Scale: A point will contribute to the y coordinate only if the x coordinate is plotted in the screen.
It can happen that objects that span through a long period of time could have its begin point inside the visible
viewport but not its end point. In those cases, the end point should not be reported.
*/
if (dataPointObject.rawPoint.y > 1 && dataPointObject.rawPoint.y !== undefined && isNaN(dataPointObject.rawPoint.y) === false) {
let rawPoint = coordinateSystem.transformThisPoint(dataPointObject.rawPoint)
if (dataPointObject.isInViewPort === true) {
coordinateSystem.reportYValue(dataPointObject.rawPoint.y)
}
}
if (k === 0) {
browserCanvasContext.moveTo(dataPoint.x, dataPoint.y)
} else {
browserCanvasContext.lineTo(dataPoint.x, dataPoint.y)
}
}
}
browserCanvasContext.closePath()
/* Apply the fill style to the canvas object */
if (polygon.polygonBody !== undefined) {
/* Replace the fill style if we are at mouse position */
if (atMousePosition === true) {
let atMousePositionFillStyle = atMousePositionFillStyles.get(polygon.id)
if (atMousePositionFillStyle !== undefined) {
fillStyle = atMousePositionFillStyle
}
}
browserCanvasContext.fillStyle = 'rgba(' + fillStyle.paletteColor + ', ' + fillStyle.opacity + ')'
browserCanvasContext.fill()
}
/* Apply the stroke style to the canvas object */
if (polygon.polygonBorder !== undefined) {
/* Replace the stroke style if we are at mouse position */
if (atMousePosition === true) {
let atMousePositionStrokeStyle = atMousePositionStrokeStyles.get(polygon.id)
if (atMousePositionStrokeStyle !== undefined) {
strokeStyle = atMousePositionStrokeStyle
}
}
browserCanvasContext.lineWidth = strokeStyle.lineWidth
browserCanvasContext.setLineDash(strokeStyle.lineDash)
browserCanvasContext.strokeStyle = 'rgba(' + strokeStyle.paletteColor + ', ' + strokeStyle.opacity + ')'
browserCanvasContext.stroke()
}
}
/* Here we are going to plot images. */
for (let j = 0; j < productDefinition.referenceParent.shapes.images.length; j++) {
let image = productDefinition.referenceParent.shapes.images[j]
if (image.imagePosition === undefined) { continue }
if (image.imagePosition.referenceParent === undefined) { continue }
if (image.imageCondition !== undefined) {
let mustPlot = eval(image.imageCondition.code)
if (mustPlot !== true) { continue }
}
let imageName = ''
let imageSize = 0
let offsetX = 0
let offsetY = 0
let imagePosition = { x: 0, y: 0 }
if (image.config.codeName !== undefined) { imageName = image.config.codeName }
if (image.config.size !== undefined) { imageSize = image.config.size }
if (image.imagePosition.config.offsetX !== undefined) { offsetX = image.imagePosition.config.offsetX }
if (image.imagePosition.config.offsetY !== undefined) { offsetY = image.imagePosition.config.offsetY }
let dataPointObject = dataPoints.get(image.imagePosition.referenceParent.id)
if (dataPointObject === undefined) { continue }
let dataPoint = {
x: dataPointObject.x,
y: dataPointObject.y
}
dataPoint = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
imagePosition.x = dataPoint.x
imagePosition.y = dataPoint.y
let imageToDraw = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', imageName)
if (imageToDraw !== undefined) {
if (imageToDraw.canDrawIcon === true) {
browserCanvasContext.drawImage(imageToDraw, imagePosition.x - imageSize / 2 + offsetX, imagePosition.y - imageSize / 2 - offsetY, imageSize, imageSize)
}
} else {
console.log('Can not plot image named ' + imageName + ' of product ' + productDefinition.name + ' because it does not exist.')
}
}
/* Here we are going to plot texts. */
for (let j = 0; j < productDefinition.referenceParent.shapes.texts.length; j++) {
let text = productDefinition.referenceParent.shapes.texts[j]
if (text.textPosition === undefined) { continue }
if (text.textPosition.referenceParent === undefined) { continue }
if (text.textCondition !== undefined) {
let mustPlot = eval(text.textCondition.code)
if (mustPlot !== true) { continue }
}
if (text.textFormula === undefined) { continue }
if (text.textStyle === undefined) { continue }
let value = eval(text.textFormula.code)
let fontSize = 0
let opacity = 0
let paletteColor = UI_COLOR.GREY
let offsetX = 0
let offsetY = 0
let textPosition = { x: 0, y: 0 }
if (text.textStyle.config.fontSize !== undefined) { fontSize = text.textStyle.config.fontSize }
if (text.textStyle.config.opacity !== undefined) { opacity = text.textStyle.config.opacity }
if (text.textStyle.config.paletteColor !== undefined) { paletteColor = eval(text.textStyle.config.paletteColor) }
if (text.textPosition.config.offsetX !== undefined) { offsetX = text.textPosition.config.offsetX }
if (text.textPosition.config.offsetY !== undefined) { offsetY = text.textPosition.config.offsetY }
let dataPointObject = dataPoints.get(text.textPosition.referenceParent.id)
if (dataPointObject === undefined) { continue }
let dataPoint = {
x: dataPointObject.x,
y: dataPointObject.y
}
dataPoint = UI.projects.superalgos.spaces.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
textPosition.x = dataPoint.x
textPosition.y = dataPoint.y
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + paletteColor + ', ' + opacity + ')'
browserCanvasContext.fillText(value, textPosition.x + offsetX, textPosition.y - offsetY)
}
}
if (coordinateSystem.autoMinYScale === true || coordinateSystem.autoMaxYScale === true) {
mustRecalculateDataPoints = true
} else {
mustRecalculateDataPoints = false
}
logged = false
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] plot -> err = ' + err.stack) }
}
}
function onViewportZoomChanged(event) {
try {
mustRecalculateDataPoints = true
recalculate()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onViewportZoomChanged -> err = ' + err.stack) }
}
}
function onDragFinished() {
if (UI.projects.superalgos.spaces.chartingSpace.visible === true) {
recalculate()
}
}
function onDisplace(event) {
recalculateAll(event)
}
function onViewportPositionChanged(event) {
recalculateAll(event)
}
function recalculateAll(event) {
mustRecalculateDataPoints = true
if (event !== undefined) {
if (event.recalculate === true) {
recalculate()
return
}
}
if (Math.random() * 100 > 95) {
recalculate()
}
}
}
@@ -0,0 +1,124 @@
function newRecordValues() {
const MODULE_NAME = 'Record Values'
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
onRecordChange: onRecordChange,
initialize: initialize,
finalize: finalize
}
let tradingSystem
let tradingEngine
let productDefinition
let propertyTargetNodeMap = new Map()
return thisObject
function finalize() {
tradingSystem = undefined
tradingEngine = undefined
productDefinition = undefined
propertyTargetNodeMap = undefined
}
function initialize(pTradingSystem, pTradingEngine, pProductDefinition) {
tradingSystem = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pTradingSystem.id)
tradingEngine = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsById(pTradingEngine.id)
productDefinition = pProductDefinition
/*
The product root can be a node or a node property of type array.
*/
let productRoot = eval(productDefinition.config.nodePath)
if (productDefinition.config.nodePathType === 'array') {
/*
This means that the configured nodePath is not pointing to a node, but to a node property that is an array.
For that reason we will assume that each element of the array is a record to be outputed
*/
for (let index = 0; index < productRoot.length; index++) {
/*
The Product Root Node is the root of the node hiriarchy from where we are going to extract the record values.
*/
let productRootNode = productRoot[index]
scanProperties(productDefinition, productRootNode, index)
}
} else {
/*
This means that the configured nodePath points to a single node, which is the one whose children constitutes
the record to be saved at the output file.
*/
/*
The Product Root Node is the root of the node hiriarchy from where we are going to extract the record values.
*/
let productRootNode = productRoot
scanProperties(productDefinition, productRootNode)
}
function scanProperties(productDefinition, productRootNode, index) {
for (let i = 0; i < productDefinition.record.properties.length; i++) {
let property = productDefinition.record.properties[i]
let key = property.id
if (index !== undefined) {
key = property.id + '-' + index
}
if (property.config.nodePath !== undefined) {
let propertyRoot
try {
propertyRoot = eval(property.config.nodePath)
} catch(err) {
console.log('Definition Error at Product ' + productDefinition.name)
console.log('productDefinition.config = ' + JSON.stringify(productDefinition.config))
console.log('Definition Error at Property ' + property.name)
console.log('property.config = ' + JSON.stringify(property.config))
console.log('property.config.nodePath = ' + property.config.nodePath)
return
}
propertyTargetNodeMap.set(key, propertyRoot)
} else {
propertyTargetNodeMap.set(key, productRootNode)
}
}
}
}
function onRecordChange(currentRecord) {
if (currentRecord === undefined) { return }
for (let i = 0; i < productDefinition.record.properties.length; i++) {
let property = productDefinition.record.properties[i]
let value = currentRecord[property.config.codeName]
let key = property.id
if (productDefinition.config.nodePathType === 'array') {
/*
When we have an array configuration, in this case we will use the index
property that was injected into the record in order to build the key to
get the node where we have to send the value.
*/
key = property.id + '-' + currentRecord.index
}
let targetNode = propertyTargetNodeMap.get(key)
/*
If the codeName of the Record Property can not match the name of the property at
the target node, the user can explicitly specify the property name at the configuration,
and in those cases we need to use that. This happens when there are many Record Properties
pointing to the same property at the Target Node.
*/
if (property.config.childProperty !== undefined) {
applyValue(targetNode[property.config.childProperty], value, property.config.decimals)
} else {
applyValue(targetNode[property.config.codeName], value, property.config.decimals)
}
}
}
function applyValue(node, value, minDecimals) {
if (UI.projects.superalgos.spaces.chartingSpace.visible !== true) { return }
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.uiObject === undefined) { return }
if (value === true) { value = 'true' }
if (value === false) { value = 'false' }
node.payload.uiObject.setValue(value, 1, minDecimals)
}
}
@@ -0,0 +1,205 @@
function newAutoScaleButton() {
let thisObject = {
container: undefined,
fitFunction: undefined,
parentContainer: undefined,
autoMinScale: undefined,
autoMaxScale: undefined,
setStatus: setStatus,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize,
finalize: finalize
}
/* Cointainer stuff */
thisObject.container = newContainer()
thisObject.container.name = 'Auto Scale Button'
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.frame.containerName = 'Auto Scale Button'
const ICON_SIZE = 36
let onMouseWheelEventSubscriptionId
let coordinateSystem
let axis
let currentStatus
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.parentContainer = undefined
thisObject.panels = undefined
coordinateSystem = undefined
axis = undefined
}
function initialize(pAxis, pCoordinateSystem) {
axis = pAxis
coordinateSystem = pCoordinateSystem
thisObject.autoMinScale = coordinateSystem.autoMinYScale
thisObject.autoMaxScale = coordinateSystem.autoMaxYScale
switch (axis) {
case 'X': {
thisObject.container.frame.width = ICON_SIZE
thisObject.container.frame.height = ICON_SIZE
let position = {
x: thisObject.container.parentContainer.frame.width * 7 / 8,
y: thisObject.container.parentContainer.frame.height / 2
}
thisObject.container.frame.position = position
break
}
case 'Y': {
thisObject.container.frame.width = ICON_SIZE
thisObject.container.frame.height = ICON_SIZE
let position = {
x: thisObject.container.parentContainer.frame.width * 7 / 8,
y: thisObject.container.parentContainer.frame.height / 2
}
thisObject.container.frame.position = position
break
}
}
onMouseWheelEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
}
function setStatus(autoMinScale, autoMaxScale) {
thisObject.autoMinScale = autoMinScale
thisObject.autoMaxScale = autoMaxScale
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === false) {
currentStatus = 1
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === false) {
currentStatus = 2
}
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === true) {
currentStatus = 4
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === true) {
currentStatus = 6
}
}
function onMouseWheel(event) {
let delta = event.wheelDelta
if (delta < 0) {
delta = -1
} else {
delta = 1
}
currentStatus = currentStatus + delta
if (currentStatus === 7) { currentStatus = 1 }
if (currentStatus === 0) { currentStatus = 6 }
switch (currentStatus) {
case 1: {
thisObject.autoMinScale = false
thisObject.autoMaxScale = false
update()
return
}
case 2: {
thisObject.autoMinScale = true
thisObject.autoMaxScale = false
update()
return
}
case 3: {
thisObject.autoMinScale = false
thisObject.autoMaxScale = false
update()
return
}
case 4: {
thisObject.autoMinScale = false
thisObject.autoMaxScale = true
update()
return
}
case 5: {
thisObject.autoMinScale = false
thisObject.autoMaxScale = false
update()
return
}
case 6: {
thisObject.autoMinScale = true
thisObject.autoMaxScale = true
update()
return
}
}
function update() {
switch (axis) {
case 'X': {
coordinateSystem.autoMinXScale = thisObject.autoMinScale
coordinateSystem.autoMaxXScale = thisObject.autoMaxScale
break
}
case 'Y': {
coordinateSystem.autoMinYScale = thisObject.autoMinScale
coordinateSystem.autoMaxYScale = thisObject.autoMaxScale
break
}
}
coordinateSystem.recalculateScale()
}
}
function getContainer(point, purpose) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function draw() {
let icon
switch (axis) {
case 'X': {
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === false) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-time-scale-manual')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === false) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-time-scale-auto-min')
}
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === true) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-time-scale-auto-max')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === true) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-time-scale-auto-min-max')
}
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon, 0, 0, 0, 0, ICON_SIZE, thisObject.container)
break
}
case 'Y': {
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === false) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-scale-manual')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === false) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-scale-auto-min')
}
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === true) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-scale-auto-max')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === true) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-auto-scale-auto-min-max')
}
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon, 0, 0, 0, 0, ICON_SIZE, thisObject.container)
break
}
}
}
}
@@ -0,0 +1,45 @@
function drawScaleDisplay(label1, label2, label3, xExtraOffSet1, xExtraOffSet2, xExtraOffSet3, icon1, icon2, container, backgroundColor) {
const RED_LINE_HIGHT = 4
const OPACITY = 1
let params = {
cornerRadius: 5,
lineWidth: 1,
container: container,
borderColor: UI_COLOR.RUSTED_RED,
castShadow: false,
backgroundColor: backgroundColor,
opacity: OPACITY
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
/* Place the Text */
label1 = label1.substring(0, 18)
label2 = label2.substring(0, 20)
label3 = label3.substring(0, 20)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label1, 1 / 2, 92 / 100, 0, 0, 9, container)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label2, 1 / 2, 42 / 100, 0, 0, 17, container)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label3, 1 / 2, 67 / 100, 0, 0, 9, container)
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon1, 1 / 8, 1 / 2, 0, 0, 28, container)
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon2, 7 / 8, 1 / 2, 0, 0, 28, container)
}
function drawScaleDisplayCover(container) {
let params = {
cornerRadius: 5,
lineWidth: 1,
container: container,
borderColor: UI_COLOR.WHITE,
castShadow: false,
backgroundColor: UI_COLOR.WHITE,
opacity: '0.25'
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
}
@@ -0,0 +1,571 @@
function newRateScale() {
const MODULE_NAME = 'Right Scale'
let thisObject = {
container: undefined,
rate: undefined,
fitFunction: undefined,
payload: undefined,
minValue: undefined,
maxValue: undefined,
isVisible: true,
layersOn: undefined,
onUpstreamScaleChanged: onUpstreamScaleChanged,
onMouseOverSomeTimeMachineContainer: onMouseOverSomeTimeMachineContainer,
physics: physics,
draw: draw,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isDraggeable = false
thisObject.container.isClickeable = false
thisObject.container.isWheelable = true
thisObject.container.detectMouseOver = true
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL
thisObject.container.frame.height = 40
let draggeableContainer = newContainer()
draggeableContainer.initialize(MODULE_NAME + ' Draggeable')
draggeableContainer.isDraggeable = true
let visible = true
let isMouseOver
let onMouseWheelEventSubscriptionId
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
let onScaleChangedEventSubscriptionId
let onDragStartedEventSubscriptionId
let coordinateSystem
let coordinateSystemWhenDragStarted
let limitingContainer
let rateCalculationsContainer
mouseWhenDragStarted = {
position: {
x: 0,
y: 0
}
}
parentFrameWhenDragStarted = {
position: {
x: 0,
y: 0
},
width: 0,
height: 0
}
let scaleDisplayTimer = 0
let autoScaleButton
let wheelDeltaDirection
let wheelDeltaCounter = 0
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
coordinateSystem.eventHandler.stopListening(onScaleChangedEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onDragStartedEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.payload = undefined
if (coordinateSystemWhenDragStarted !== undefined) {
coordinateSystemWhenDragStarted.finalize()
}
coordinateSystemWhenDragStarted = undefined
coordinateSystem = undefined
limitingContainer = undefined
rateCalculationsContainer = undefined
mouseWhenDragStarted = undefined
parentFrameWhenDragStarted = undefined
autoScaleButton.finalize()
autoScaleButton = undefined
}
function initialize(pCoordinateSystem, pLimitingContainer, pRateCalculationsContainer) {
coordinateSystem = pCoordinateSystem
limitingContainer = pLimitingContainer
rateCalculationsContainer = pRateCalculationsContainer
thisObject.minValue = coordinateSystem.min.y
thisObject.maxValue = coordinateSystem.max.y
onMouseWheelEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
onMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
onScaleChangedEventSubscriptionId = coordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
onDragStartedEventSubscriptionId = draggeableContainer.eventHandler.listenToEvent('onDragStarted', onDragStarted)
autoScaleButton = newAutoScaleButton()
autoScaleButton.container.connectToParent(thisObject.container)
autoScaleButton.initialize('Y', coordinateSystem)
readObjectState()
}
function onMouseOverSomeTimeMachineContainer(event) {
if (event.containerId === undefined) {
/* This happens when the mouse over was not at the instance of a certain scale, but anywhere else. */
visible = true
} else {
if (event.containerId === thisObject.container.id) {
visible = true
} else {
visible = false
turnOnCounter = 0
}
}
}
function onScaleChanged() {
saveObjectState()
}
function onMouseOver(event) {
isMouseOver = true
event.containerId = thisObject.container.id
thisObject.container.eventHandler.raiseEvent('onMouseOverScale', event)
}
function onMouseNotOver() {
isMouseOver = false
scaleDisplayTimer = 0
}
function onMouseWheel(event) {
if (IS_MAC) {
let sensitivity
if (event.wheelDelta < 0) {
if (event.shiftKey === true) {
sensitivity = 20
} else {
sensitivity = 5
}
if (wheelDeltaDirection === -1) {
wheelDeltaCounter++
if (wheelDeltaCounter < sensitivity) {
return
} else {
wheelDeltaCounter = 0
}
} else {
wheelDeltaCounter = 0
wheelDeltaDirection = -1
return
}
} else {
if (event.shiftKey === true) {
sensitivity = 20
} else {
sensitivity = 5
}
if (wheelDeltaDirection === 1) {
wheelDeltaCounter++
if (wheelDeltaCounter < sensitivity) {
return
} else {
wheelDeltaCounter = 0
}
} else {
wheelDeltaCounter = 0
wheelDeltaDirection = 1
return
}
}
}
if (event.shiftKey === true) {
autoScaleButton.container.eventHandler.raiseEvent('onMouseWheel', event)
return
}
let factor
let morePower = 10
if (event.buttons === 4) { morePower = 1 } // Mouse wheel pressed.
let delta = event.wheelDelta
if (delta < 0) {
factor = -0.01 * morePower
} else {
factor = 0.01 * morePower
}
coordinateSystem.zoomY(factor, event, limitingContainer)
scaleDisplayTimer = 100
}
function onDragStarted(event) {
mouseWhenDragStarted = {
position: {
x: event.x,
y: event.y
}
}
parentFrameWhenDragStarted = {
position: {
x: limitingContainer.frame.position.x,
y: limitingContainer.frame.position.y
},
width: limitingContainer.frame.width,
height: limitingContainer.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)
}
function getContainer(point, purpose) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
if (purpose === GET_CONTAINER_PURPOSE.DRAGGING) {
return draggeableContainer
}
return thisObject.container
}
}
function saveObjectState() {
try {
let config = JSON.parse(thisObject.payload.node.config)
config.minValue = coordinateSystem.min.y
config.maxValue = coordinateSystem.max.y
config.autoMinScale = coordinateSystem.autoMinYScale
config.autoMaxScale = coordinateSystem.autoMaxYScale
thisObject.payload.node.config = JSON.stringify(config, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function readObjectState() {
try {
let config = JSON.parse(thisObject.payload.node.config)
if (
(isNaN(config.minValue) || config.minValue === null || config.minValue === undefined) ||
(isNaN(config.maxValue) || config.maxValue === null || config.maxValue === undefined)
) {
// not using this value
} else {
if (
thisObject.minValue !== config.minValue ||
thisObject.maxValue !== config.maxValue ||
coordinateSystem.autoMinYScale !== config.autoMinScale ||
coordinateSystem.autoMaxYScale !== config.autoMaxScale
) {
thisObject.minValue = config.minValue
thisObject.maxValue = config.maxValue
coordinateSystem.min.y = thisObject.minValue
coordinateSystem.max.y = thisObject.maxValue
if (config.autoMinScale !== undefined && (config.autoMinScale === true || config.autoMinScale === false) && config.autoMaxScale !== undefined && (config.autoMaxScale === true || config.autoMaxScale === false)) {
coordinateSystem.autoMinYScale = config.autoMinScale
coordinateSystem.autoMaxYScale = config.autoMaxScale
autoScaleButton.setStatus(config.autoMinScale, config.autoMaxScale)
}
coordinateSystem.recalculateScale()
}
}
saveObjectState() // this overrides any invalid value at the config.
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function physics() {
scaleDisplayTimer--
readObjectState()
positioningPhysics()
draggingPhysics()
}
function draggingPhysics() {
if (coordinateSystemWhenDragStarted === undefined) { return }
if (draggeableContainer.frame.position.y === 0) { return }
let mouseNoZoom = UI.projects.superalgos.spaces.chartingSpace.viewport.unTransformThisPoint(canvas.mouse.position)
let mouseWhenDragStartedNoZoom = UI.projects.superalgos.spaces.chartingSpace.viewport.unTransformThisPoint(mouseWhenDragStarted.position)
let dragVectorWhenDragStarted = {
x: 0,
y: mouseNoZoom.y - mouseWhenDragStartedNoZoom.y
}
let dragVector = {
x: 0,
y: draggeableContainer.frame.position.y
}
draggeableContainer.frame.position.y = 0
let point = {
x: 0,
y: (-dragVectorWhenDragStarted.y)
}
let newMaxRate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtContainer(point, limitingContainer, coordinateSystemWhenDragStarted)
let yDifferenceMaxMin = coordinateSystemWhenDragStarted.max.y - coordinateSystemWhenDragStarted.min.y
coordinateSystem.min.y = newMaxRate - yDifferenceMaxMin
coordinateSystem.max.y = newMaxRate
let event = {
type: 'center dragged',
dragVector: dragVector
}
coordinateSystem.recalculateScale()
}
function onUpstreamScaleChanged(event) {
if (event === undefined) { return }
if (event.dragVector.y === 0) { return }
if (event.type === 'center dragged') {
let point = {
x: event.dragVector.x,
y: -event.dragVector.y
}
let newMaxRate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtContainer(point, rateCalculationsContainer, coordinateSystem)
let yDifferenceMaxMin = coordinateSystem.max.y - coordinateSystem.min.y
coordinateSystem.min.y = newMaxRate - yDifferenceMaxMin
coordinateSystem.max.y = newMaxRate
coordinateSystem.recalculateScale()
}
if (event.type === 'top dragged') {
let point = {
x: event.dragVector.x,
y: event.dragVector.y
}
let newMaxRate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtContainer(point, rateCalculationsContainer, coordinateSystem)
coordinateSystem.max.y = newMaxRate
coordinateSystem.maxHeight = rateCalculationsContainer.frame.height
coordinateSystem.recalculateScale()
}
if (event.type === 'bottom dragged') {
let point = {
x: event.dragVector.x,
y: event.dragVector.y + rateCalculationsContainer.frame.height
}
let newMinRate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtContainer(point, rateCalculationsContainer, coordinateSystem)
coordinateSystem.min.y = newMinRate
coordinateSystem.maxHeight = rateCalculationsContainer.frame.height
coordinateSystem.recalculateScale()
}
}
function positioningPhysics() {
/* Container Limits */
let upCorner = {
x: 0,
y: 0
}
let bottonCorner = {
x: limitingContainer.frame.width,
y: limitingContainer.frame.height
}
upCorner = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(upCorner, limitingContainer)
bottonCorner = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bottonCorner, limitingContainer)
upCorner = limitingContainer.fitFunction(upCorner, true)
bottonCorner = limitingContainer.fitFunction(bottonCorner, true)
/* We will check if we need to change the bottom because of being one of many scales of the same type */
let displaceFactor = 0
if (thisObject.payload.parentNode === undefined) { return } // This happens when in the process of deleting the scale, timeline chart or time machine.
if (thisObject.payload.parentNode.type === 'Timeline Chart') {
if (thisObject.payload.parentNode.payload.parentNode !== undefined) {
if (thisObject.payload.parentNode.payload.parentNode.rateScale !== undefined) {
if (thisObject.payload.parentNode.payload.parentNode.rateScale.payload.isVisible === true) {
displaceFactor++
}
}
for (let i = 0; i < thisObject.payload.parentNode.payload.parentNode.timelineCharts.length; i++) {
let timelineChart = thisObject.payload.parentNode.payload.parentNode.timelineCharts[i]
if (timelineChart.rateScale !== undefined) {
if (thisObject.payload.node.id !== timelineChart.rateScale.id) {
if (timelineChart.rateScale.payload.isVisible === true) {
displaceFactor++
}
} else {
break
}
}
}
}
}
bottonCorner.x = bottonCorner.x - thisObject.container.frame.width * displaceFactor
/* Mouse Position Rate Calculation */
let ratePoint = {
x: 0,
y: canvas.mouse.position.y
}
thisObject.rate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtBrowserCanvas(ratePoint, rateCalculationsContainer, coordinateSystem)
/* rateScale Positioning */
ratePoint = {
x: limitingContainer.frame.width,
y: 0
}
ratePoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(ratePoint, limitingContainer.frame.container)
ratePoint.y = canvas.mouse.position.y - thisObject.container.frame.height / 2 + thisObject.container.frame.height
/* Checking against the container limits. */
if (ratePoint.x < upCorner.x) { ratePoint.x = upCorner.x }
if (ratePoint.x + thisObject.container.frame.width > bottonCorner.x) { ratePoint.x = bottonCorner.x }
if (ratePoint.y < upCorner.y + thisObject.container.frame.height) { ratePoint.y = upCorner.y + thisObject.container.frame.height }
if (ratePoint.y > bottonCorner.y) { ratePoint.y = bottonCorner.y }
thisObject.container.frame.position.y = ratePoint.y - thisObject.container.frame.height
thisObject.container.frame.position.x = ratePoint.x - thisObject.container.frame.width
thisObject.isVisible = true
thisObject.payload.isVisible = true
if (thisObject.container.frame.position.y + thisObject.container.frame.height * 2 > bottonCorner.y ||
thisObject.container.frame.position.y - thisObject.container.frame.height * 1 < upCorner.y ||
thisObject.container.frame.position.x < upCorner.x
) {
thisObject.isVisible = false
thisObject.payload.isVisible = false
}
if (thisObject.layersOn === 0) {
thisObject.isVisible = false
thisObject.payload.isVisible = false
}
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_DISPLAYING_SCALES) {
thisObject.isVisible = false
}
}
function draw() {
drawScaleBox()
autoScaleButton.draw()
if (visible === false) {
drawScaleDisplayCover(thisObject.container)
}
}
function drawForeground() {
if (isMouseOver === true) {
drawScaleBox()
autoScaleButton.draw()
}
}
function drawBackground() {
drawScale()
}
function drawScale() {
const SEPARATION = 50
const NUMBER_OF_LABELS = Math.trunc(UI.projects.superalgos.spaces.chartingSpace.viewport.height / SEPARATION)
const FONT_SIZE = 15
for (let i = 0; i <= NUMBER_OF_LABELS; i++) {
let ratePoint1 = {
x: 0,
y: TOP_SPACE_HEIGHT + SEPARATION * (i + 1)
}
let ratePoint2 = {
x: 0,
y: TOP_SPACE_HEIGHT + SEPARATION * (i + 0)
}
let rate = UI.projects.superalgos.utilities.dateRateTransformations.getRateFromPointAtBrowserCanvas(ratePoint1, rateCalculationsContainer, coordinateSystem)
let labels = scaleLabels(rate)
let decimalsDisplace = labels[1].length * FONT_SIZE * FONT_ASPECT_RATIO
let fitPoint1 = thisObject.fitFunction(ratePoint1)
let fitPoint2 = thisObject.fitFunction(ratePoint2)
if (fitPoint1.y === ratePoint1.y && fitPoint2.y === ratePoint2.y) {
UI.projects.superalgos.utilities.drawPrint.drawLabel(labels[1], 1 / 2, 0, 0, 0, FONT_SIZE, thisObject.container, UI_COLOR.GREY, undefined, ratePoint1.y)
UI.projects.superalgos.utilities.drawPrint.drawLabel(labels[2], 1 / 2, 0, decimalsDisplace, -5, 9, thisObject.container, UI_COLOR.GREY, undefined, ratePoint1.y)
}
}
}
function drawScaleBox() {
if (thisObject.rate === undefined) { return }
if (thisObject.payload === undefined) { return }
if (thisObject.payload.node === undefined) { return }
let icon1 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.payload.parentNode.project, thisObject.payload.node.payload.parentNode.type)
let icon2 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.payload.node.type)
let backgroundColor = UI_COLOR.BLACK
let labels = scaleLabels(thisObject.rate)
drawScaleDisplay(labels[0], labels[1], labels[2], 0, 0, 0, icon1, icon2, thisObject.container, backgroundColor)
}
function scaleLabels(rate) {
if (rate < coordinateSystem.min.y) {
rate = coordinateSystem.min.y
}
if (rate > coordinateSystem.max.y) {
rate = coordinateSystem.max.y
}
let label = dynamicDecimals(rate)
let labelArray = label.split('.')
let label1 = thisObject.payload.node.payload.parentNode.name
let label2 = (Math.trunc(rate)).toLocaleString()
let label3 = labelArray[1]
if (label3 === undefined) { label3 = '00' }
if (rate < 1) {
label2 = label
label3 = ''
}
if (scaleDisplayTimer > 0) {
label2 = (coordinateSystem.scale.y * 10000).toFixed(2)
label3 = 'SCALE'
}
return [label1, label2, label3]
}
}
@@ -0,0 +1,393 @@
function newTimeFrameScale() {
const MODULE_NAME = 'Time Frame Scale'
let thisObject = {
timeFrame: undefined,
container: undefined,
fitFunction: undefined,
payload: undefined,
isVisible: true,
layersOn: undefined,
adjustTimeFrame: adjustTimeFrame,
onMouseOverSomeTimeMachineContainer: onMouseOverSomeTimeMachineContainer,
draw: draw,
drawForeground: drawForeground,
physics: physics,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
const FILES_PERIOD_DEFAULT_VALUE = 0
const TIME_PERIOD_DEFAULT_VALUE = 0
let displayingRealTimeFrame = true
let greyOutCoverLayer = false
let isMouseOver
let filePeriodIndex = FILES_PERIOD_DEFAULT_VALUE
let timeFrameIndex = TIME_PERIOD_DEFAULT_VALUE
let timeFramesMasterArray = [marketFilesPeriods, dailyFilePeriods]
let timeFrameLabel = '24-hs'
let onMouseWheelEventSubscriptionId
let onViewportZoomChangedEventSubscriptionId
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
let limitingContainer
setupContainer()
let wheelDeltaDirection
let wheelDeltaCounter = 0
return thisObject
function setupContainer() {
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isDraggeable = false
thisObject.container.isClickeable = false
thisObject.container.isWheelable = true
thisObject.container.detectMouseOver = true
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL
thisObject.container.frame.height = 40
}
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSubscriptionId)
UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.stopListening(onViewportZoomChangedEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.payload = undefined
limitingContainer = undefined
}
function initialize(pLimitingContainer) {
limitingContainer = pLimitingContainer
readObjectState()
newTimeFrame()
onMouseWheelEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
onViewportZoomChangedEventSubscriptionId = UI.projects.superalgos.spaces.chartingSpace.viewport.eventHandler.listenToEvent('Zoom Changed', onViewportZoomChanged)
onMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
}
function onMouseOverSomeTimeMachineContainer(event) {
if (event.containerId === undefined) {
/* This happens when the mouse over was not at the instance of a certain scale, but anywhere else. */
greyOutCoverLayer = false
} else {
if (event.containerId === thisObject.container.id) {
greyOutCoverLayer = false
} else {
greyOutCoverLayer = true
turnOnCounter = 0
}
}
}
function onMouseOver(event) {
isMouseOver = true
event.containerId = thisObject.container.id
thisObject.container.eventHandler.raiseEvent('onMouseOverScale', event)
}
function onMouseNotOver() {
isMouseOver = false
}
function physics() {
readObjectState()
positioningPhysics()
}
function adjustTimeFrame(elementsPlotted) {
const ELEMENTS_PLOTTED_THREASHOLD = 500
if (
UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel >= UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_CHANGING_TIME_FRAME &&
displayingRealTimeFrame === false
) {
let event = {}
event.timeFrame = thisObject.timeFrame
thisObject.container.eventHandler.raiseEvent('Time Frame Value Changed', event)
displayingRealTimeFrame = true
}
if (
elementsPlotted > ELEMENTS_PLOTTED_THREASHOLD &&
UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_CHANGING_TIME_FRAME &&
displayingRealTimeFrame === true
) {
let event = {}
event.timeFrame = ONE_DAY_IN_MILISECONDS
thisObject.container.eventHandler.raiseEvent('Time Frame Value Changed', event)
displayingRealTimeFrame = false
}
}
function positioningPhysics() {
/* Container Limits */
let upCorner = {
x: 0,
y: 0
}
let bottonCorner = {
x: limitingContainer.frame.width,
y: limitingContainer.frame.height
}
upCorner = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(upCorner, limitingContainer)
bottonCorner = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bottonCorner, limitingContainer)
upCorner = limitingContainer.fitFunction(upCorner, true)
bottonCorner = limitingContainer.fitFunction(bottonCorner, true)
/* We will check if we need to change the bottom because of being one of many scales of the same type */
let displaceFactor = 0
if (thisObject.payload.parentNode === undefined) { return } // This happens when in the process of deleting the scale, timeline chart or time machine.
if (thisObject.payload.parentNode.type === 'Timeline Chart') {
if (thisObject.payload.parentNode.payload.parentNode !== undefined) {
if (thisObject.payload.parentNode.payload.parentNode.timeFrameScale !== undefined) {
if (thisObject.payload.parentNode.payload.parentNode.timeFrameScale.payload.isVisible === true) {
displaceFactor++
}
}
for (let i = 0; i < thisObject.payload.parentNode.payload.parentNode.timelineCharts.length; i++) {
let timelineChart = thisObject.payload.parentNode.payload.parentNode.timelineCharts[i]
if (timelineChart.timeFrameScale !== undefined) {
if (thisObject.payload.node.id !== timelineChart.timeFrameScale.id) {
if (timelineChart.timeFrameScale.payload.isVisible === true) {
displaceFactor++
}
} else {
break
}
}
}
}
}
bottonCorner.y = bottonCorner.y - thisObject.container.frame.height * displaceFactor
/* Positioning */
timePoint = {
x: 0,
y: limitingContainer.frame.height
}
timePoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(timePoint, limitingContainer.frame.container)
timePoint.x = canvas.mouse.position.x - thisObject.container.frame.width / 2
/* Checking against the container limits. */
if (timePoint.x < upCorner.x) { timePoint.x = upCorner.x }
if (timePoint.x + thisObject.container.frame.width > bottonCorner.x) { timePoint.x = bottonCorner.x - thisObject.container.frame.width }
if (timePoint.y < upCorner.y + thisObject.container.frame.height) { timePoint.y = upCorner.y + thisObject.container.frame.height }
if (timePoint.y > bottonCorner.y) { timePoint.y = bottonCorner.y }
thisObject.container.frame.position.x = timePoint.x
thisObject.container.frame.position.y = timePoint.y - thisObject.container.frame.height
thisObject.isVisible = true
thisObject.payload.isVisible = true
if (thisObject.container.frame.position.y + thisObject.container.frame.height > bottonCorner.y ||
thisObject.container.frame.position.y - thisObject.container.frame.height * 3 < upCorner.y ||
thisObject.container.frame.position.x < upCorner.x) {
thisObject.isVisible = false
thisObject.payload.isVisible = false
}
if (thisObject.layersOn === 0) {
thisObject.isVisible = false
thisObject.payload.isVisible = false
}
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_DISPLAYING_SCALES) {
thisObject.isVisible = false
}
}
function onViewportZoomChanged(event) {
if (event !== undefined) { // it is undefined when the level is just being animated.
if (event.shiftKey === false || event.shiftKey === undefined) { return } // with no shft key pressed, no automatic change in scale
let currentTimeFrame = thisObject.timeFrame
let timeFrame = recalculatePeriod(event.newLevel)
if (timeFrame !== currentTimeFrame) {
for (let i = 0; i < timeFramesMasterArray.length; i++) {
let timeFrameArray = timeFramesMasterArray[i]
for (let j = 0; j < timeFrameArray.length; j++) {
let record = timeFrameArray[j]
if (timeFrame === record[0]) {
filePeriodIndex = i
timeFrameIndex = j
}
}
}
newTimeFrame()
saveObjectState()
}
}
}
function onMouseWheel(event) {
if (IS_MAC) {
let sensitivity
if (event.wheelDelta < 0) {
if (event.shiftKey === true) {
sensitivity = 20
} else {
sensitivity = 5
}
if (wheelDeltaDirection === -1) {
wheelDeltaCounter++
if (wheelDeltaCounter < sensitivity) {
return
} else {
wheelDeltaCounter = 0
}
} else {
wheelDeltaCounter = 0
wheelDeltaDirection = -1
return
}
} else {
if (event.shiftKey === true) {
sensitivity = 20
} else {
sensitivity = 5
}
if (wheelDeltaDirection === 1) {
wheelDeltaCounter++
if (wheelDeltaCounter < sensitivity) {
return
} else {
wheelDeltaCounter = 0
}
} else {
wheelDeltaCounter = 0
wheelDeltaDirection = 1
return
}
}
}
let delta = event.wheelDelta
if (delta < 0) {
timeFrameIndex--
if (timeFrameIndex < 0) {
filePeriodIndex--
if (filePeriodIndex < 0) {
filePeriodIndex = 0
timeFrameIndex = 0
} else {
timeFrameIndex = timeFramesMasterArray[filePeriodIndex].length - 1
}
}
} else {
timeFrameIndex++
if (timeFrameIndex > timeFramesMasterArray[filePeriodIndex].length - 1) {
filePeriodIndex++
if (filePeriodIndex > timeFramesMasterArray.length - 1) {
filePeriodIndex = timeFramesMasterArray.length - 1
timeFrameIndex = timeFramesMasterArray[filePeriodIndex].length - 1
} else {
timeFrameIndex = 0
}
}
}
newTimeFrame()
saveObjectState()
}
function getContainer(point) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function saveObjectState() {
try {
let config = JSON.parse(thisObject.payload.node.config)
config.value = timeFrameLabel
thisObject.payload.node.config = JSON.stringify(config)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function readObjectState() {
try {
let config = JSON.parse(thisObject.payload.node.config)
if (config.value !== timeFrameLabel) {
let found = false
for (let i = 0; i < timeFramesMasterArray.length; i++) {
let timeFrameArray = timeFramesMasterArray[i]
for (let j = 0; j < timeFrameArray.length; j++) {
let record = timeFrameArray[j]
if (config.value === record[1]) {
filePeriodIndex = i
timeFrameIndex = j
found = true
}
}
}
if (found === true) {
newTimeFrame()
} else {
saveObjectState()
}
}
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function newTimeFrame() {
let timeFrameArray = timeFramesMasterArray[filePeriodIndex]
thisObject.timeFrame = timeFrameArray[timeFrameIndex][0]
timeFrameLabel = timeFrameArray[timeFrameIndex][1]
// console.log('NEW TIME FRAME LABEL', timeFrameLabel)
let event = {}
event.timeFrame = thisObject.timeFrame
thisObject.container.eventHandler.raiseEvent('Time Frame Value Changed', event)
}
function draw() {
drawScaleBox()
if (greyOutCoverLayer === true) {
drawScaleDisplayCover(thisObject.container)
}
}
function drawForeground() {
if (isMouseOver === true) {
drawScaleBox()
}
}
function drawScaleBox() {
if (timeFrameLabel === undefined) { return }
let label = timeFrameLabel.split('-')
let label1 = thisObject.payload.node.payload.parentNode.name
let label2 = label[0]
let label3 = label[1].toUpperCase()
let icon1 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.payload.parentNode.project, thisObject.payload.node.payload.parentNode.type)
let icon2 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.payload.node.type)
let backgroundColor = UI_COLOR.BLACK
drawScaleDisplay(label1, label2, label3, 0, 0, 0, icon1, icon2, thisObject.container, backgroundColor)
}
}
@@ -0,0 +1,364 @@
function newTimeScale() {
const MODULE_NAME = 'Time Scale'
let thisObject = {
container: undefined,
date: undefined,
fitFunction: undefined,
payload: undefined,
isVisible: true,
fromDate: undefined,
toDate: undefined,
onMouseOverSomeTimeMachineContainer: onMouseOverSomeTimeMachineContainer,
physics: physics,
draw: draw,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isDraggeable = false
thisObject.container.isClickeable = false
thisObject.container.isWheelable = true
thisObject.container.detectMouseOver = true
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL
thisObject.container.frame.height = 40
let visible = true
let autoScaleButton
let isMouseOver
let onMouseWheelEventSubscriptionId
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
let onScaleChangedEventSubscriptionId
let coordinateSystem
let limitingContainer
let wheelDeltaDirection
let wheelDeltaCounter = 0
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
coordinateSystem.eventHandler.stopListening(onScaleChangedEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.payload = undefined
coordinateSystem = undefined
limitingContainer = undefined
autoScaleButton.finalize()
autoScaleButton = undefined
}
function initialize(pCoordinateSystem, pLimitingContainer) {
coordinateSystem = pCoordinateSystem
limitingContainer = pLimitingContainer
onMouseWheelEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
onMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
onScaleChangedEventSubscriptionId = coordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
autoScaleButton = newAutoScaleButton()
autoScaleButton.container.connectToParent(thisObject.container)
autoScaleButton.initialize('X', coordinateSystem)
readObjectState()
}
function onMouseOverSomeTimeMachineContainer(event) {
if (event.containerId === undefined) {
/* This happens when the mouse over was not at the instance of a certain scale, but anywhere else. */
visible = true
} else {
if (event.containerId === thisObject.container.id) {
visible = true
} else {
visible = false
turnOnCounter = 0
}
}
}
function onMouseOver(event) {
isMouseOver = true
event.containerId = thisObject.container.id
thisObject.container.eventHandler.raiseEvent('onMouseOverScale', event)
}
function onMouseNotOver() {
isMouseOver = false
}
function onMouseWheel(event) {
if (IS_MAC) {
let sensitivity
if (event.wheelDelta < 0) {
if (event.shiftKey === true) {
sensitivity = 20
} else {
sensitivity = 5
}
if (wheelDeltaDirection === -1) {
wheelDeltaCounter++
if (wheelDeltaCounter < sensitivity) {
return
} else {
wheelDeltaCounter = 0
}
} else {
wheelDeltaCounter = 0
wheelDeltaDirection = -1
return
}
} else {
if (event.shiftKey === true) {
sensitivity = 20
} else {
sensitivity = 5
}
if (wheelDeltaDirection === 1) {
wheelDeltaCounter++
if (wheelDeltaCounter < sensitivity) {
return
} else {
wheelDeltaCounter = 0
}
} else {
wheelDeltaCounter = 0
wheelDeltaDirection = 1
return
}
}
}
if (event.shiftKey === true) {
autoScaleButton.container.eventHandler.raiseEvent('onMouseWheel', event)
return
}
let factor
let morePower = 10
if (event.buttons === 4) { morePower = 1 } // Mouse wheel pressed.
let delta = event.wheelDelta
if (delta < 0) {
factor = -0.01 * morePower
} else {
factor = 0.01 * morePower
}
coordinateSystem.zoomX(factor, event, limitingContainer, MODULE_NAME)
}
function onScaleChanged() {
saveObjectState()
}
function getContainer(point, purpose) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function saveObjectState() {
try {
let config = JSON.parse(thisObject.payload.node.config)
config.fromDate = (new Date(coordinateSystem.min.x)).toISOString()
config.toDate = (new Date(coordinateSystem.max.x)).toISOString()
config.autoMinScale = coordinateSystem.autoMinXScale
config.autoMaxScale = coordinateSystem.autoMaxXScale
thisObject.payload.node.config = JSON.stringify(config, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function readObjectState() {
try {
let config = JSON.parse(thisObject.payload.node.config)
if (
(isNaN(Date.parse(config.fromDate)) || config.fromDate === null || config.fromDate === undefined) ||
(isNaN(Date.parse(config.toDate)) || config.toDate === null || config.toDate === undefined)
) {
// not using this value
} else {
if (thisObject.fromDate !== Date.parse(config.fromDate) || thisObject.toDate !== Date.parse(config.toDate)) {
thisObject.fromDate = Date.parse(config.fromDate)
thisObject.toDate = Date.parse(config.toDate)
coordinateSystem.min.x = thisObject.fromDate
coordinateSystem.max.x = thisObject.toDate
if (config.autoMinScale !== undefined && (config.autoMinScale === true || config.autoMinScale === false) && config.autoMaxScale !== undefined && (config.autoMaxScale === true || config.autoMaxScale === false)) {
coordinateSystem.autoMinXScale = config.autoMinScale
coordinateSystem.autoMaxXScale = config.autoMaxScale
autoScaleButton.setStatus(config.autoMinScale, config.autoMaxScale)
}
coordinateSystem.recalculateScale()
}
}
saveObjectState() // this overrides any invalid value at the config.
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function physics() {
readObjectState()
positioningPhysics()
}
function positioningPhysics() {
/* Container Limits */
let upCorner = {
x: 0,
y: 0
}
let bottonCorner = {
x: limitingContainer.frame.width,
y: limitingContainer.frame.height
}
upCorner = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(upCorner, limitingContainer)
bottonCorner = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(bottonCorner, limitingContainer)
upCorner = limitingContainer.fitFunction(upCorner, true)
bottonCorner = limitingContainer.fitFunction(bottonCorner, true)
/* Mouse Position Date Calculation */
let timePoint = {
x: canvas.mouse.position.x,
y: 0
}
let mouseDate = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(timePoint, limitingContainer, coordinateSystem)
thisObject.date = new Date(mouseDate)
/* timeScale Positioning */
timePoint = {
x: 0,
y: 0
}
timePoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(timePoint, limitingContainer.frame.container)
timePoint.x = canvas.mouse.position.x - thisObject.container.frame.width / 2
/* Checking against the container limits. */
if (timePoint.x < upCorner.x) { timePoint.x = upCorner.x }
if (timePoint.x + thisObject.container.frame.width > bottonCorner.x) { timePoint.x = bottonCorner.x - thisObject.container.frame.width }
if (timePoint.y < upCorner.y) { timePoint.y = upCorner.y }
if (timePoint.y + thisObject.container.frame.height > bottonCorner.y) { timePoint.y = bottonCorner.y - thisObject.container.frame.height }
thisObject.container.frame.position.x = timePoint.x
thisObject.container.frame.position.y = timePoint.y
thisObject.isVisible = true
if (thisObject.container.frame.position.y + thisObject.container.frame.height * 4 > bottonCorner.y ||
thisObject.container.frame.position.y < upCorner.y ||
thisObject.container.frame.position.x < upCorner.x) {
thisObject.isVisible = false
}
if (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_DISPLAYING_SCALES) {
thisObject.isVisible = false
}
}
function drawBackground() {
drawScale()
}
function drawScale() {
const SEPARATION = 150
const NUMBER_OF_LABELS = Math.trunc(UI.projects.superalgos.spaces.chartingSpace.viewport.width / SEPARATION)
const FONT_SIZE = 15
for (let i = 0; i <= NUMBER_OF_LABELS; i++) {
let timePoint = {
x: SEPARATION * (i + 1),
y: 0
}
let time = UI.projects.superalgos.utilities.dateRateTransformations.getDateFromPointAtBrowserCanvas(timePoint, limitingContainer, coordinateSystem)
let labels = scaleLabels(time, true)
let labelDisplace = labels[1].length * FONT_SIZE * FONT_ASPECT_RATIO
let timePoint1 = {
x: SEPARATION * (i + 1) - labelDisplace,
y: 0
}
let timePoint2 = {
x: SEPARATION * (i + 1) + labelDisplace,
y: 0
}
let fitPoint1 = thisObject.fitFunction(timePoint1)
let fitPoint2 = thisObject.fitFunction(timePoint2)
if (fitPoint1.x === timePoint1.x && fitPoint2.x === timePoint2.x) {
UI.projects.superalgos.utilities.drawPrint.drawLabel(labels[1], 1 / 2, 0, 18, 17, FONT_SIZE, thisObject.container, UI_COLOR.GREY, timePoint1.x, undefined)
UI.projects.superalgos.utilities.drawPrint.drawLabel(labels[2], 1 / 2, 0, 18, 30, 12, thisObject.container, UI_COLOR.GREY, timePoint1.x, undefined)
}
}
}
function draw() {
drawScaleBox()
autoScaleButton.draw()
if (visible === false) {
drawScaleDisplayCover(thisObject.container)
}
}
function drawForeground() {
if (isMouseOver === true) {
drawScaleBox()
autoScaleButton.draw()
}
}
function drawScaleBox() {
if (thisObject.date === undefined) { return }
let icon1 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.payload.parentNode.project, thisObject.payload.node.payload.parentNode.type)
let icon2 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.payload.node.type)
let backgroundColor = UI_COLOR.BLACK
let labels = scaleLabels(thisObject.date)
drawScaleDisplay(labels[0], labels[1], labels[2], 0, 0, 0, icon1, icon2, thisObject.container, backgroundColor)
}
function scaleLabels(date, excludeYear) {
let label = date.toUTCString()
let labelArray = label.split(' ')
let label1 = thisObject.payload.node.payload.parentNode.name
let label2 = labelArray[1] + ' ' + labelArray[2] + ' ' + labelArray[3]
let label3 = labelArray[4]
if (excludeYear === true) {
label2 = labelArray[1] + ' ' + labelArray[2]
}
return [label1, label2, label3]
}
}
@@ -0,0 +1,835 @@
/*
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
UI.projects.superalgos.utilities.loadSaveFrame.loadFrame(thisObject.payload, thisObject.container.frame)
setInitialPosition()
UI.projects.superalgos.utilities.loadSaveFrame.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 setInitialPosition() {
if (thisObject.container.frame.position.x === 0 && thisObject.container.frame.position.y === 0) {
let timeMachineIndex = UI.projects.superalgos.utilities.children.findChildIndexAtParentNode(thisObject.payload.node)
let dashboardIndex = UI.projects.superalgos.utilities.children.findChildIndexAtParentNode(thisObject.payload.parentNode)
thisObject.container.frame.position.x = thisObject.container.frame.width * timeMachineIndex * 2
thisObject.container.frame.position.y = thisObject.container.frame.height * dashboardIndex * 2
}
}
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(UI.projects.superalgos.utilities.dateRateTransformations.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 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(upCorner, thisObject.container)
bottonCorner = UI.projects.superalgos.utilities.coordinateTransformations.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 = UI.projects.superalgos.spaces.chartingSpace.fitFunction(returnPoint, fullVisible)
return returnPoint
}
function physics() {
thisObject.edgeEditor.physics()
timeMachineCoordinateSystem.physics()
UI.projects.superalgos.utilities.loadSaveFrame.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() &&
UI.projects.superalgos.spaces.chartingSpace.viewport.zoomLevel >= UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_NOT_HIDDING_PANELS) {
UI.projects.superalgos.spaces.panelSpace.unHide(thisObject.payload.node.id, 'Layers Panel')
UI.projects.superalgos.spaces.panelSpace.unHide(thisObject.payload.node.id, 'Plotter Panel')
return
}
if (
thisObject.container.frame.isCenterInViewPort() &&
UI.projects.superalgos.spaces.chartingSpace.viewport.zoomLevel >= UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_HIDDING_PANELS
) {
UI.projects.superalgos.spaces.panelSpace.unHide(thisObject.payload.node.id, 'Layers Panel')
UI.projects.superalgos.spaces.panelSpace.unHide(thisObject.payload.node.id, 'Plotter Panel')
} else {
UI.projects.superalgos.spaces.panelSpace.hide(thisObject.payload.node.id, 'Layers Panel')
UI.projects.superalgos.spaces.panelSpace.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() {
UI.projects.superalgos.utilities.drawPrint.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 (UI.projects.superalgos.spaces.chartingSpace.viewport.zoomTargetLevel < UI.projects.superalgos.globals.zoom.ZOOM_OUT_THRESHOLD_FOR_DISPLAYING_TIME_MACHINES_ICONIZED) {
let icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, 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 = UI.projects.superalgos.utilities.coordinateTransformations.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 === undefined) { return }
if (thisObject.payload.node === undefined) { return }
/* Draw Title Above the Container */
let position = {
x: 0,
y: 0
}
let imageSize = 12
let fontSize = 12
let opacity = 1
let icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.payload.node.type)
position = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(position, thisObject.container)
let label = thisObject.payload.node.name
let description = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'description')
if (description !== undefined) {
label = description
}
UI.projects.superalgos.utilities.drawPrint.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 - 18,
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.layerManager !== undefined) {
let layers = timelinechart.layerManager.layers
for (let j = 0; j < layers.length; j++) {
let layer = layers[j]
let 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)
}
}
UI.projects.superalgos.utilities.drawPrint.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)
}
}
UI.projects.superalgos.utilities.drawPrint.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 = UI.projects.superalgos.utilities.coordinateTransformations.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
)
}
}
@@ -0,0 +1,422 @@
function newTimelineChart() {
const MODULE_NAME = 'Timeline Chart'
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,
layerManager: 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.layerManager !== undefined) {
finalizeLayerManager()
}
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 finalizeLayerManager() {
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.finalize()
}
thisObject.plotterManager = undefined
thisObject.layerManager = undefined
UI.projects.superalgos.spaces.panelSpace.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.heigh
)
}
function initializeLayerManager() {
let owner = thisObject.payload.node.payload.parentNode.id // The real owner is the Time Machine
layersPanelHandle = UI.projects.superalgos.spaces.panelSpace.createNewPanel('Layers Panel', undefined, owner)
thisObject.layerManager = UI.projects.superalgos.spaces.panelSpace.getPanel(layersPanelHandle)
thisObject.layerManager.payload = thisObject.payload.node.layerManager.payload
thisObject.layerManager.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.layerManager)
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()
syncWithDesignerLayerManager()
}
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 syncWithDesignerLayerManager() {
if (thisObject.payload.node === undefined) {
finalizeLayerManager()
return
}
if (thisObject.payload.node.layerManager === undefined && thisObject.layerManager !== undefined) {
finalizeLayerManager()
}
if (thisObject.payload.node.layerManager !== undefined && thisObject.layerManager === undefined) {
initializeLayerManager()
}
}
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() {
UI.projects.superalgos.utilities.drawPrint.drawContainerBackground(thisObject.container, UI_COLOR.WHITE, 0, thisObject.fitFunction)
}
}
@@ -0,0 +1,423 @@
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 MARGIN_AMOUNT = 40
let TOP_MARGIN = TOP_SPACE_HEIGHT
let BOTTOM_MARGIN = COCKPIT_SPACE_HEIGHT + MARGIN_AMOUNT
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,
marginAmount: MARGIN_AMOUNT,
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 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
}
}
UI.projects.superalgos.utilities.loadSaveFrame.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 = TOP_SPACE_HEIGHT + MARGIN_AMOUNT
BOTTOM_MARGIN = browserCanvas.height - COCKPIT_SPACE_POSITION + MARGIN_AMOUNT
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
UI.projects.superalgos.utilities.loadSaveFrame.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 config = JSON.parse(thisObject.payload.node.config)
config.zoom = (thisObject.zoomTargetLevel - MIN_ZOOM_LEVEL) / (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) * 100
config.zoom = config.zoom.toFixed(2)
thisObject.payload.node.config = JSON.stringify(config)
} 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 config = JSON.parse(thisObject.payload.node.config)
if (isNaN(config.zoom) || config.zoom === null || config.zoom === undefined) {
saveObjectState()
return
}
config.zoom = config.zoom / 100 * (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) + MIN_ZOOM_LEVEL
if (config.zoom < MIN_ZOOM_LEVEL) { config.zoom = MIN_ZOOM_LEVEL }
if (config.zoom > MAX_ZOOM_LEVEL) { config.zoom = MAX_ZOOM_LEVEL }
if (config.zoom.toFixed(2) !== thisObject.zoomTargetLevel.toFixed(2)) {
newZoomLevel(config.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
}
}
}
@@ -0,0 +1,199 @@
function newSuperalgosChatSpace() {
const MODULE_NAME = 'Chat Space'
let thisObject = {
sidePanelTab: undefined,
container: undefined,
navigateTo: navigateTo,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
let isInitialized = false
thisObject.container = newContainer()
thisObject.container.name = MODULE_NAME
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = true
thisObject.container.status = 'hidden'
resize()
let browserResizedEventSubscriptionId
let openingEventSubscriptionId
let closingEventSubscriptionId
const DEFAULT_URL = 'https://web.telegram.org/#/im?p=@superalgoscommunity'
return thisObject
function initialize() {
thisObject.sidePanelTab = newSidePanelTab()
thisObject.sidePanelTab.container.connectToParent(thisObject.container, false, false)
thisObject.sidePanelTab.initialize('right', 1)
openingEventSubscriptionId = thisObject.sidePanelTab.container.eventHandler.listenToEvent('opening', onOpening)
closingEventSubscriptionId = thisObject.sidePanelTab.container.eventHandler.listenToEvent('closing', onClosing)
browserResizedEventSubscriptionId = canvas.eventHandler.listenToEvent('Browser Resized', resize)
isInitialized = true
}
function finalize() {
canvas.eventHandler.stopListening(browserResizedEventSubscriptionId)
thisObject.sidePanelTab.container.eventHandler.stopListening(openingEventSubscriptionId)
thisObject.sidePanelTab.container.eventHandler.stopListening(closingEventSubscriptionId)
}
function onOpening() {
let docIFrame = document.getElementById('docIFrame')
if (docIFrame.src === "") {
docIFrame.src = DEFAULT_URL
}
}
function onClosing() {
}
function navigateTo(url) {
let docIFrame = document.getElementById('docIFrame')
docIFrame.src = url
thisObject.sidePanelTab.open()
}
function resize() {
thisObject.container.frame.width = 1200
thisObject.container.frame.height = browserCanvas.height // - TOP_SPACE_HEIGHT
thisObject.container.frame.position.x = browserCanvas.width
thisObject.container.frame.position.y = 0 // TOP_SPACE_HEIGHT
if (thisObject.sidePanelTab !== undefined) {
thisObject.sidePanelTab.resize()
}
}
function getContainer(point, purpose) {
let container
container = thisObject.sidePanelTab.getContainer(point, purpose)
if (container !== undefined) { return container }
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
if (container.isWheelable === true) {
return thisObject.container
} else {
UI.projects.superalgos.spaces.chartingSpace.viewport.onMouseWheel(event)
return
}
} else {
return
}
}
function physics() {
thisObject.sidePanelTab.physics()
chatAppDivPhysics()
iFramePhysics()
function chatAppDivPhysics() {
let chatAppDiv = document.getElementById('chatApp')
chatAppDivPosition = {
x: 0,
y: 0
}
chatAppDivPosition = thisObject.container.frame.frameThisPoint(chatAppDivPosition)
chatAppDiv.style = ' ' +
'position:fixed; top:' + chatAppDivPosition.y + 'px; ' +
'left:' + chatAppDivPosition.x + 'px; z-index:1; ' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
}
function iFramePhysics() {
let docIFrame = document.getElementById('chatIFrame')
docIFrame.style = ' ' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
}
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
if (isInitialized === false) { return }
borders()
thisObject.sidePanelTab.draw()
}
function borders() {
let point1
let point2
let point3
let point4
point1 = {
x: 0,
y: 0
}
point2 = {
x: thisObject.container.frame.width,
y: 0
}
point3 = {
x: thisObject.container.frame.width,
y: thisObject.container.frame.height
}
point4 = {
x: 0,
y: thisObject.container.frame.height
}
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
point4 = thisObject.container.frame.frameThisPoint(point4)
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
browserCanvasContext.lineTo(point1.x, point1.y)
browserCanvasContext.closePath()
let opacity = 1
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.LIGHT_GREY + ', ' + opacity + ''
browserCanvasContext.fill()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREY + ', ' + opacity + ''
browserCanvasContext.lineWidth = 0.3
browserCanvasContext.stroke()
/* Shadow */
if (thisObject.container.status !== 'hidden') {
for (let i = 0; i <= 30; i++) {
opacity = 1 - (i / 300) - 0.95
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point2.x + i, point2.y)
browserCanvasContext.lineTo(point3.x + i, point3.y)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', ' + opacity + ''
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
}
}
}
}
@@ -0,0 +1,123 @@
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)
}
}
@@ -0,0 +1,366 @@
function newSuperalgosCockpitSpace() {
const MODULE_NAME = 'CockpitSpace'
const STATUS_TYPES = {
ALL_GOOD: 1,
WARNING: 2
}
let thisObject = {
container: undefined,
status: 'BOTTOM',
fullscreen: undefined,
statusTypes: STATUS_TYPES,
setStatus: setStatus,
toTop: toTop,
toBottom: toBottom,
toMiddle: toMiddle,
moveUp: moveUp,
moveDown: moveDown,
draw: draw,
physics: physics,
getContainer: getContainer,
finalize: finalize,
initialize: initialize,
initializePosition: initializePosition
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = false
thisObject.container.detectMouseOver = true
thisObject.container.isDraggeable = true
thisObject.container.notDraggingOnX = true
controlsMap = new Map()
resize()
let selfMouseClickEventSubscriptionId
let canvasBrowserResizedEventSubscriptionId
let statusCounter = 0
let statusText
let statusType
let isInitilized = false
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(selfMouseClickEventSubscriptionId)
thisObject.container.eventHandler.stopListening(canvasBrowserResizedEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fullscreen = undefined
}
function initialize() {
canvasBrowserResizedEventSubscriptionId = canvas.eventHandler.listenToEvent('Browser Resized', resize)
selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
thisObject.fullscreen = newFullScreen()
thisObject.fullscreen.container.connectToParent(thisObject.container)
thisObject.fullscreen.initialize()
}
function initializePosition() {
thisObject.container.frame.position.x = 0
let INITIAL_POSITION
if (UI.projects.superalgos.spaces.designSpace.workspace.enabled === true) {
let localStorage = window.localStorage.getItem(MODULE_NAME)
if (localStorage !== null) {
storage = JSON.parse(localStorage)
thisObject.container.frame.position.y = storage.spacePosition
} else {
INITIAL_POSITION = browserCanvas.height - 55
thisObject.container.frame.position.y = browserCanvas.height * INITIAL_POSITION / 100 - COCKPIT_SPACE_HEIGHT
}
} else {
INITIAL_POSITION = 100
thisObject.container.frame.position.y = browserCanvas.height * INITIAL_POSITION / 100 - COCKPIT_SPACE_HEIGHT
}
isInitilized = true
}
function onMouseClick(event) {
}
function setStatus(text, counter, type) {
statusCounter = counter
statusText = text
statusType = type
}
function resize() {
thisObject.container.frame.width = browserCanvas.width
thisObject.container.frame.height = COCKPIT_SPACE_HEIGHT
switch (thisObject.status) {
case 'BOTTOM': {
thisObject.container.frame.position.y = browserCanvas.height - COCKPIT_SPACE_HEIGHT
break
}
case 'TOP': {
thisObject.container.frame.position.y = TOP_SPACE_HEIGHT
break
}
}
}
function toTop() {
thisObject.container.frame.position.y = TOP_SPACE_HEIGHT
}
function toBottom() {
thisObject.container.frame.position.y = browserCanvas.height - COCKPIT_SPACE_HEIGHT
}
function toMiddle() {
thisObject.container.frame.position.y = browserCanvas.height / 2 - COCKPIT_SPACE_HEIGHT
}
function moveUp() {
thisObject.container.frame.position.y = thisObject.container.frame.position.y - COCKPIT_SPACE_HEIGHT * 2
if (thisObject.container.frame.position.y < 0) {
thisObject.container.frame.position.y = 0
}
}
function moveDown() {
thisObject.container.frame.position.y = thisObject.container.frame.position.y + COCKPIT_SPACE_HEIGHT * 2
if (thisObject.container.frame.position.y > browserCanvas.height - COCKPIT_SPACE_HEIGHT) {
thisObject.container.frame.position.y = browserCanvas.height - COCKPIT_SPACE_HEIGHT
}
}
function statusPhysics() {
statusCounter--
if (statusCounter < 0) {
statusCounter = 0
statusText = undefined,
statusType = undefined
}
}
function physics() {
thisObjectPhysics()
childrenPhysics()
statusPhysics()
}
function childrenPhysics() {
thisObject.fullscreen.physics()
}
function thisObjectPhysics() {
if (isInitilized === false) { return }
/* Check the limits */
thisObject.status = 'MIDDLE'
if (UI.projects.superalgos.spaces.designSpace.workspace.enabled === true) {
thisObject.container.isDraggeable = true
} else {
thisObject.container.isDraggeable = false
}
if (thisObject.container.frame.position.y > browserCanvas.height * 99.5 / 100 - COCKPIT_SPACE_HEIGHT) {
thisObject.container.frame.position.y = browserCanvas.height - COCKPIT_SPACE_HEIGHT
thisObject.status = 'BOTTOM'
UI.projects.superalgos.spaces.designSpace.makeInvisible()
UI.projects.superalgos.spaces.floatingSpace.makeInvisible()
} else {
UI.projects.superalgos.spaces.designSpace.makeVisible()
UI.projects.superalgos.spaces.floatingSpace.makeVisible()
}
if (thisObject.container.frame.position.y < browserCanvas.height * 0.5 / 100 + TOP_SPACE_HEIGHT) {
thisObject.container.frame.position.y = TOP_SPACE_HEIGHT
thisObject.status = 'TOP'
UI.projects.superalgos.spaces.panelSpace.visible = false
} else {
UI.projects.superalgos.spaces.panelSpace.visible = true
}
COCKPIT_SPACE_POSITION = thisObject.container.frame.position.y
let storage = {
spacePosition: COCKPIT_SPACE_POSITION
}
window.localStorage.setItem(MODULE_NAME, JSON.stringify(storage))
if (UI.projects.superalgos.spaces.chartingSpace.viewport !== undefined) {
UI.projects.superalgos.spaces.chartingSpace.viewport.resize()
}
}
function getContainer(point) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
thisObject.container.space = 'Cockpit Space'
return thisObject.container
} else {
return undefined
}
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
thisObject.container.frame.draw(false, false)
drawBackground()
// thisObject.fullscreen.draw()
}
function drawBackground() {
let opacity = 1
let zeroPoint = {
x: 0,
y: 0
}
const RED_LINE_HIGHT = 2
zeroPoint = thisObject.container.frame.frameThisPoint(zeroPoint)
let barColor = UI_COLOR.DARK_TURQUOISE // default
let textColor
if (statusType !== undefined) {
switch (statusType) {
case STATUS_TYPES.ALL_GOOD:
{
barColor = UI_COLOR.PATINATED_TURQUOISE
textColor = UI_COLOR.WHITE
break
}
case STATUS_TYPES.WARNING:
{
barColor = UI_COLOR.RED
textColor = UI_COLOR.TITANIUM_YELLOW
break
}
}
}
browserCanvasContext.beginPath()
browserCanvasContext.rect(zeroPoint.x, zeroPoint.y, thisObject.container.frame.width, thisObject.container.frame.height)
browserCanvasContext.fillStyle = 'rgba(' + barColor + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
browserCanvasContext.beginPath()
browserCanvasContext.rect(zeroPoint.x, zeroPoint.y, thisObject.container.frame.width, RED_LINE_HIGHT)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
browserCanvasContext.beginPath()
browserCanvasContext.rect(zeroPoint.x, zeroPoint.y - RED_LINE_HIGHT + thisObject.container.frame.height, thisObject.container.frame.width, RED_LINE_HIGHT)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
if (statusText !== undefined) {
let position = {
x: thisObject.container.frame.width / 2,
y: thisObject.container.frame.height / 2 + 5
}
UI.projects.superalgos.utilities.drawPrint.printLabel(statusText, position.x, position.y, 1, 15, textColor, true, thisObject.container)
}
if (UI.projects.superalgos.spaces.designSpace !== undefined) {
if (UI.projects.superalgos.spaces.designSpace.workspace.enabled === true && statusText === undefined) {
arrow()
}
}
}
function arrow() {
const X_OFFSET = thisObject.container.frame.width / 2
const Y_OFFSET = thisObject.container.frame.height / 2
const HEIGHT = 6
const WIDTH = 18
const LINE_WIDTH = 3
const OPACITY = 1
let DISTANCE_BETWEEN_ARROWS = 0
let ARROW_1_DIRECTION = 0
let ARROW_2_DIRECTION = 0
switch (thisObject.status) {
case ('TOP'): {
ARROW_1_DIRECTION = -1
ARROW_2_DIRECTION = -1
DISTANCE_BETWEEN_ARROWS = 6
break
}
case ('MIDDLE'): {
ARROW_1_DIRECTION = 1
ARROW_2_DIRECTION = -1
DISTANCE_BETWEEN_ARROWS = 9
break
}
case ('BOTTOM'): {
ARROW_1_DIRECTION = 1
ARROW_2_DIRECTION = 1
DISTANCE_BETWEEN_ARROWS = 6
break
}
}
point1 = {
x: X_OFFSET - WIDTH / 2,
y: Y_OFFSET + HEIGHT / 2 * ARROW_1_DIRECTION - DISTANCE_BETWEEN_ARROWS / 2
}
point2 = {
x: X_OFFSET,
y: Y_OFFSET - HEIGHT / 2 * ARROW_1_DIRECTION - DISTANCE_BETWEEN_ARROWS / 2
}
point3 = {
x: X_OFFSET + WIDTH / 2,
y: Y_OFFSET + HEIGHT / 2 * ARROW_1_DIRECTION - DISTANCE_BETWEEN_ARROWS / 2
}
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
point4 = {
x: X_OFFSET - WIDTH / 2,
y: Y_OFFSET + HEIGHT / 2 * ARROW_2_DIRECTION + DISTANCE_BETWEEN_ARROWS / 2
}
point5 = {
x: X_OFFSET,
y: Y_OFFSET - HEIGHT / 2 * ARROW_2_DIRECTION + DISTANCE_BETWEEN_ARROWS / 2
}
point6 = {
x: X_OFFSET + WIDTH / 2,
y: Y_OFFSET + HEIGHT / 2 * ARROW_2_DIRECTION + DISTANCE_BETWEEN_ARROWS / 2
}
point4 = thisObject.container.frame.frameThisPoint(point4)
point5 = thisObject.container.frame.frameThisPoint(point5)
point6 = thisObject.container.frame.frameThisPoint(point6)
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.moveTo(point4.x, point4.y)
browserCanvasContext.lineTo(point5.x, point5.y)
browserCanvasContext.lineTo(point6.x, point6.y)
browserCanvasContext.lineWidth = LINE_WIDTH
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
browserCanvasContext.stroke()
}
}
@@ -0,0 +1,169 @@
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 = TOP_MARGIN
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
}
UI.projects.superalgos.utilities.drawPrint.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)
}
}
@@ -0,0 +1,265 @@
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 */
label = thisObject.params.VALUE
if (isNaN(label) === false) {
label = Number(label)
label = dynamicDecimals(label, 2)
if (label === 0) { label = label.toFixed(2) }
}
fontSize = 22
if (label.length > 8) {
fontSize = 18
}
if (label.length > 10) {
fontSize = 14
}
if (label.length > 12) {
fontSize = 10
}
if (label.length > 14) {
fontSize = 8
}
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
// 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)
}
}
@@ -0,0 +1,131 @@
function newSuperalgosDesignSpace() {
const MODULE_NAME = 'Designe Space'
let thisObject = {
container: undefined,
iconsByProjectAndName: undefined,
iconsByProjectAndType: undefined,
workspace: undefined,
getIconByProjectAndName: getIconByProjectAndName,
getIconByProjectAndType: getIconByProjectAndType,
physics: physics,
draw: draw,
getContainer: getContainer,
makeVisible: makeVisible,
makeInvisible: makeInvisible,
initialize: initialize
}
let container = newContainer()
container.initialize()
thisObject.container = container
container.isDraggeable = false
thisObject.iconsByProjectAndName = new Map()
thisObject.iconsByProjectAndType = new Map()
return thisObject
function initialize() {
loadIconCollection(onIconsReady)
function onIconsReady() {
buildIconByProjectAndTypeMap()
thisObject.workspace = newWorkspace()
thisObject.workspace.initialize()
}
function buildIconByProjectAndTypeMap() {
/* Take types-icons relationships defined at the schema */
for (let i = 0; i < PROJECTS_ARRAY.length; i++) {
let project = PROJECTS_ARRAY[i]
let appSchema = SCHEMAS_BY_PROJECT.get(project).array.appSchema
for (let j = 0; j < appSchema.length; j++) {
let nodeDefinition = appSchema[j]
let iconName = nodeDefinition.icon
if (iconName === undefined) {
iconName = nodeDefinition.type.toLowerCase()
iconName = iconName.split(" ").join("-")
}
let icon = thisObject.getIconByProjectAndName(project, iconName)
if (icon !== undefined) {
let key = project + '-' + nodeDefinition.type
thisObject.iconsByProjectAndType.set(key, icon)
}
}
}
}
}
function loadIconCollection(callBack) {
callWebServer(undefined, 'IconNames', onResponse)
function onResponse(err, data) {
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
console.log('Failed to Fetch Image Names from the Backend')
return
}
let iconsArray = JSON.parse(data)
let imageLoadedCounter = 0
for (let i = 0; i < iconsArray.length; i++) {
let project = iconsArray[i][0]
let name = iconsArray[i][1]
loadImage(project, name)
}
function loadImage(project, name) {
imageLoadedCounter++
const PATH = 'Icons/' + project + '/'
let image = new Image()
image.onload = onImageLoad
image.fileName = name
function onImageLoad() {
image.canDrawIcon = true
}
image.src = PATH + name
let key = project + '-' + name.substring(0, name.length - 4)
thisObject.iconsByProjectAndName.set(key, image)
if (imageLoadedCounter === iconsArray.length) {
callBack()
}
}
}
}
function getIconByProjectAndName(project, name) {
return thisObject.iconsByProjectAndName.get(project + '-' + name)
}
function getIconByProjectAndType(project, type) {
return thisObject.iconsByProjectAndType.get(project + '-' + type)
}
function physics() {
if (thisObject.workspace === undefined) { return }
thisObject.workspace.physics()
}
function makeVisible() {
visible = true
}
function makeInvisible() {
visible = false
}
function getContainer(point) {
}
function draw() {
if (thisObject.workspace === undefined) { return }
if (CAN_SPACES_DRAW === false) { return }
thisObject.workspace.draw()
}
}
@@ -0,0 +1,493 @@
function newWorkspace() {
const MODULE_NAME = 'Workspace'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
workspaceNode: undefined,
container: undefined,
enabled: false,
nodeChildren: undefined,
eventsServerClients: new Map(),
replaceWorkspaceByLoadingOne: replaceWorkspaceByLoadingOne,
save: saveWorkspace,
backup: backupWorkspace,
share: shareWorkspace,
getProjectsHeads: getProjectsHeads,
getHierarchyHeads: getHierarchyHeads,
getHierarchyHeadsById: getHierarchyHeadsById,
getHierarchyHeadsByType: getHierarchyHeadsByType,
getNodeThatIsOnFocus: getNodeThatIsOnFocus,
getNodeByShortcutKey: getNodeByShortcutKey,
getNodeById: getNodeById,
stopAllRunningTasks: stopAllRunningTasks,
executeAction: executeAction,
physics: physics,
draw: draw,
spawn: spawn,
initialize: initialize,
finalize: finalize
}
spawnPosition = {
x: UI.projects.superalgos.spaces.floatingSpace.container.frame.width / 2,
y: UI.projects.superalgos.spaces.floatingSpace.container.frame.height / 2
}
thisObject.workspaceNode = {}
thisObject.workspaceNode.rootNodes = []
thisObject.nodeChildren = newNodeChildren()
let savingWorkspaceIntervalId
let isInitialized = false
let workingAtTask = 0
let circularProgressBar = newBusyProgressBar()
circularProgressBar.fitFunction = UI.projects.superalgos.spaces.floatingSpace.fitIntoVisibleArea
let loadedWorkspaceNode
let sessionTimestamp = (new Date()).valueOf()
window.localStorage.setItem('Session Timestamp', sessionTimestamp)
let actionSwitchesByProject = new Map()
return thisObject
function finalize() {
thisObject.definition = undefined
thisObject.workspaceNode = undefined
circularProgressBar.finalize()
circularProgressBar = undefined
actionSwitchesByProject = undefined
}
function initialize() {
try {
/* Set up the action switches map */
for (let i = 0; i < PROJECTS_ARRAY.length; i++) {
let project = PROJECTS_ARRAY[i]
let actionSwitch = eval('new' + project + 'ActionSwitch()')
actionSwitchesByProject.set(project, actionSwitch)
}
/* Check which was the last workspace. */
let lastUsedWorkspace = window.localStorage.getItem('Last Used Workspace')
if (lastUsedWorkspace !== 'undefined' && lastUsedWorkspace !== null && lastUsedWorkspace !== undefined) {
callWebServer(undefined, 'LoadMyWorkspace' + '/' + lastUsedWorkspace, onFileReceived)
function onFileReceived(err, text, response) {
if (err && err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
UI.projects.superalgos.spaces.cockpitSpace.setStatus('Could not load the last Workspace used, called "' + lastUsedWorkspace + '". Will switch to the default Workspace instead.', 500, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.WARNING)
thisObject.workspaceNode = getWorkspace() // This is the default workspace that comes with the system.
thisObject.workspaceNode.project = 'Superalgos'
recreateWorkspace()
return
}
thisObject.workspaceNode = JSON.parse(text)
thisObject.workspaceNode.project = 'Superalgos'
recreateWorkspace()
}
} else {
thisObject.workspaceNode = getWorkspace() // This is the default workspace that comes with the system.
thisObject.workspaceNode.project = 'Superalgos'
recreateWorkspace()
}
function recreateWorkspace() {
executeAction({ node: thisObject.workspaceNode, name: 'Recreate Workspace', project: 'Superalgos', callBackFunction: finishInitialization })
}
function finishInitialization() {
setupEventsServerClients()
runTasksAndSessions()
thisObject.enabled = true
UI.projects.superalgos.spaces.cockpitSpace.initializePosition()
CAN_SPACES_DRAW = true
savingWorkspaceIntervalId = setInterval(saveWorkspace, 60000)
isInitialized = true
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) }
}
}
function runTasksAndSessions() {
executeAction({ name: 'Syncronize Tasks', project: 'Superalgos' })
executeAction({ name: 'Syncronize Sessions', project: 'Superalgos' })
executeAction({ name: 'Play Tutorials', project: 'Superalgos' })
}
function setupEventsServerClients() {
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
if (rootNode.type === 'Network') {
if (rootNode.networkNodes === undefined) { continue }
for (let j = 0; j < rootNode.networkNodes.length; j++) {
let networkNode = rootNode.networkNodes[j]
let eventsServerClient = newEventsServerClient(networkNode)
eventsServerClient.initialize()
thisObject.eventsServerClients.set(networkNode.id, eventsServerClient)
}
}
}
}
async function saveWorkspace() {
let workspace = UI.projects.superalgos.spaces.designSpace.workspace.workspaceNode
/* Validation if it is too early to save. */
if (isInitialized === false) { return }
/* Validation of 2 sessions opened at the same time. */
let savedSessionTimestamp = window.localStorage.getItem('Session Timestamp')
if (Number(savedSessionTimestamp) !== sessionTimestamp) {
UI.projects.superalgos.spaces.cockpitSpace.setStatus(
'Could not save the Workspace. You have more that one instance of the Superlagos User Interface open at the same time. Plese close this instance as it is older than the others.'
, 150, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.WARNING)
return
}
/* Validation that there is something to save */
let textToSave = await stringifyWorkspace()
if (textToSave === undefined) {
UI.projects.superalgos.spaces.cockpitSpace.setStatus(
'Could not save the Workspace. Something is preventing the System to do it at this time.'
, 150, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.WARNING)
return
}
window.localStorage.setItem('Session Timestamp', sessionTimestamp)
/* Validation Workspace has a name */
if (workspace.name === undefined) {
UI.projects.superalgos.spaces.cockpitSpace.setStatus(
'Could not save the Workspace. You need to specify a name for it.'
, 150, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.WARNING)
return
}
let url = 'SaveWorkspace/' + workspace.name
callWebServer(textToSave, url, onResponse)
return true
function onResponse(err) {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
window.localStorage.setItem('Last Used Workspace', workspace.name)
window.localStorage.setItem('Session Timestamp', sessionTimestamp)
if (ARE_WE_RECORDING_A_MARKET_PANORAMA === false) {
UI.projects.superalgos.spaces.cockpitSpace.setStatus(workspace.name + ' Saved.', 50, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.ALL_GOOD)
}
} else {
UI.projects.superalgos.spaces.cockpitSpace.setStatus('Could not save the Workspace at the Backend. Please check the Backend Console for more information.', 150, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.WARNING)
}
}
}
function backupWorkspace(action) {
let text = stringifyWorkspace(false)
let fileName = 'Backup - ' + action.node.type + ' - ' + action.node.name + '.json'
if (text !== undefined) {
UI.projects.superalgos.utilities.download.downloadText(fileName, text)
}
}
function shareWorkspace(action) {
let text = stringifyWorkspace(true)
let fileName = 'Share - ' + action.node.type + ' - ' + action.node.name + '.json'
if (text !== undefined) {
UI.projects.superalgos.utilities.download.downloadText(fileName, text)
}
}
async function getNodeById(nodeId) {
return await executeAction({ name: 'Get Node By Id', project: 'Superalgos', relatedNodeId: nodeId })
}
function physics() {
eventsServerClientsPhysics()
replacingWorkspacePhysics()
}
function eventsServerClientsPhysics() {
thisObject.eventsServerClients.forEach(applyPhysics)
function applyPhysics(eventServerClient) {
eventServerClient.physics()
}
}
function finalizeEventsServerClients() {
thisObject.eventsServerClients.forEach(finalize)
function finalize(eventServerClient) {
eventServerClient.finalize()
}
}
function replacingWorkspacePhysics() {
if (thisObject.enabled !== true) { return }
if (workingAtTask > 0) {
circularProgressBar.physics()
switch (workingAtTask) {
case 1:
UI.projects.superalgos.spaces.tutorialSpace.stop()
executeAction({ node: thisObject.workspaceNode, name: 'Delete Workspace', project: 'Superalgos' })
workingAtTask++
break
case 2:
finalizeEventsServerClients()
thisObject.eventsServerClients = new Map()
workingAtTask++
break
case 3:
clearInterval(savingWorkspaceIntervalId)
workingAtTask++
break
case 4:
thisObject.workspaceNode = loadedWorkspaceNode
thisObject.workspaceNode.project = 'Superalgos'
loadedWorkspaceNode = undefined
workingAtTask++
break
case 5:
executeAction({ node: thisObject.workspaceNode, name: 'Recreate Workspace', project: 'Superalgos', callBackFunction: finishInitialization })
function finishInitialization() {
setupEventsServerClients()
runTasksAndSessions()
}
workingAtTask++
break
case 6:
UI.projects.superalgos.spaces.chartingSpace.reset()
workingAtTask++
break
case 7:
workingAtTask = 0
circularProgressBar.visible = false
break
}
}
}
function draw() {
if (circularProgressBar !== undefined) {
circularProgressBar.draw()
}
}
async function stringifyWorkspace(removePersonalData) {
let stringifyReadyNodes = []
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
if (rootNode.isPlugin !== true) {
let node = await executeAction({ node: rootNode, name: 'Get Node Data Structure', project: 'Superalgos', extraParameter: removePersonalData })
stringifyReadyNodes.push(node)
}
}
let workspace = {
type: 'Workspace',
name: thisObject.workspaceNode.name,
rootNodes: stringifyReadyNodes
}
/*
Sometimes it happens that there are no rootNodes.
In those situations the workspace can not be stringified,
to prevent later saving it corrupting the original file.
*/
if (stringifyReadyNodes.length > 0) {
return JSON.stringify(workspace)
} else {
return
}
}
function stopAllRunningTasks() {
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
if (rootNode.type === 'Network') {
if (rootNode.networkNodes !== undefined) {
for (let j = 0; j < rootNode.networkNodes.length; j++) {
let networkNode = rootNode.networkNodes[j]
if (networkNode.dataMining !== undefined && networkNode.dataMining.payload !== undefined) {
networkNode.dataMining.payload.uiObject.menu.internalClick('Stop All Exchange Data Tasks')
networkNode.dataMining.payload.uiObject.menu.internalClick('Stop All Exchange Data Tasks')
}
if (networkNode.testingEnvironment !== undefined && networkNode.testingEnvironment.payload !== undefined) {
networkNode.testingEnvironment.payload.uiObject.menu.internalClick('Stop All Exchange Trading Tasks')
networkNode.testingEnvironment.payload.uiObject.menu.internalClick('Stop All Exchange Trading Tasks')
}
if (networkNode.productionEnvironment !== undefined && networkNode.productionEnvironment.payload !== undefined) {
networkNode.productionEnvironment.payload.uiObject.menu.internalClick('Stop All Exchange Trading Tasks')
networkNode.productionEnvironment.payload.uiObject.menu.internalClick('Stop All Exchange Trading Tasks')
}
}
}
}
}
}
async function getNodeByShortcutKey(searchingKey) {
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let node = await executeAction({ node: rootNode, name: 'Get Node By Shortcut Key', project: 'Superalgos', extraParameter: searchingKey })
if (node !== undefined) { return node }
}
}
async function getNodeThatIsOnFocus() {
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let node = await executeAction({ node: rootNode, name: 'Get Node On Focus', project: 'Superalgos' })
if (node !== undefined) { return node }
}
}
function getHierarchyHeads() {
let nodes = []
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let nodeDefinition = getNodeDefinition(rootNode)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isHierarchyHead === true) {
nodes.push(rootNode)
}
}
}
return nodes
}
function getProjectsHeads() {
let nodes = []
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let nodeDefinition = getNodeDefinition(rootNode)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isProjectHead === true) {
nodes.push(rootNode)
}
}
}
return nodes
}
function getHierarchyHeadsById(nodeId) {
let hiriatchyHeads = getHierarchyHeads()
for (let i = 0; i < hiriatchyHeads.length; i++) {
let hiriatchyHead = hiriatchyHeads[i]
if (hiriatchyHead.id === nodeId) {
return hiriatchyHead
}
}
}
function getHierarchyHeadsByType(nodeType) {
let hiriatchyHeads = getHierarchyHeads()
for (let i = 0; i < hiriatchyHeads.length; i++) {
let hiriatchyHead = hiriatchyHeads[i]
if (hiriatchyHead.type === nodeType) {
return hiriatchyHead
}
}
}
function replaceWorkspaceByLoadingOne(name) {
let webCommand
if (name.indexOf('Plugin \u2192 ') >= 0) {
name = name.replace('Plugin \u2192 ', '')
webCommand = 'LoadPlugin' + '/' + 'Superalgos' + '/' + 'Workspaces' + '/' + name + '.json'
} else {
webCommand = 'LoadMyWorkspace' + '/' + name
}
callWebServer(undefined, webCommand, onFileReceived)
function onFileReceived(err, text, response) {
if (err && err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
UI.projects.superalgos.spaces.cockpitSpace.setStatus('Could not load the Workspace called "' + name + '". ', 500, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.WARNING)
return
}
loadedWorkspaceNode = JSON.parse(text)
saveWorkspace()
UI.projects.superalgos.spaces.cockpitSpace.toTop()
let position = {
x: browserCanvas.width / 2,
y: browserCanvas.height / 2
}
circularProgressBar.initialize(position)
circularProgressBar.visible = true
workingAtTask = 1
}
}
function spawn(nodeText, mousePointer) {
try {
let point = {
x: mousePointer.x,
y: mousePointer.y
}
point = UI.projects.superalgos.spaces.floatingSpace.container.frame.unframeThisPoint(point)
spawnPosition.x = point.x
spawnPosition.y = point.y
let droppedNode = JSON.parse(nodeText)
if (droppedNode.type === 'Workspace') {
loadedWorkspaceNode = droppedNode
circularProgressBar.initialize(mousePointer)
circularProgressBar.visible = true
workingAtTask = 1
return
}
/* It does not exist, so we recreeate it respecting the inner state of each object. */
let positionOffset = {
x: spawnPosition.x,
y: spawnPosition.y
}
if (droppedNode.savedPayload !== undefined) {
positionOffset.x = positionOffset.x - droppedNode.savedPayload.position.x
positionOffset.y = positionOffset.y - droppedNode.savedPayload.position.y
}
thisObject.workspaceNode.rootNodes.push(droppedNode)
executeAction({ node: droppedNode, name: 'Create UI Object', project: 'Superalgos', extraParameter: positionOffset })
executeAction({ name: 'Connect Children to Reference Parents', project: 'Superalgos' })
droppedNode = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] spawn -> err = ' + err.stack) }
}
}
async function executeAction(action) {
/*
Supported parameters as part of the action object:
action.node : It is the node at which the action was taken. If not specific node is involved then it should be the workspace node.
action.relatedNode : It is a secondary node involved with the action. For example the node to which the main node is being attached to.
action.relatedNodeId : It is the id of a node related to the action.
action.relatedNodeType : It is the type of the node related to the action.
action.callBackFunction : A callback function to call when the action is complete.
action.extraParameter : A parameter to send unusual info to the fnction processing the action.
We add rootNodes property here.
*/
action.rootNodes = thisObject.workspaceNode.rootNodes
let actionSwitch = actionSwitchesByProject.get(action.project)
return actionSwitch.executeAction(action)
}
}
@@ -0,0 +1,192 @@
function newSuperalgosDocSpace() {
const MODULE_NAME = 'Doc Space'
let thisObject = {
sidePanelTab: undefined,
container: undefined,
navigateTo: navigateTo,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
let isInitialized = false
thisObject.container = newContainer()
thisObject.container.name = MODULE_NAME
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = true
thisObject.container.status = 'hidden'
resize()
let browserResizedEventSubscriptionId
let openingEventSubscriptionId
let closingEventSubscriptionId
return thisObject
function initialize() {
thisObject.sidePanelTab = newSidePanelTab()
thisObject.sidePanelTab.container.connectToParent(thisObject.container, false, false)
thisObject.sidePanelTab.initialize('right')
openingEventSubscriptionId = thisObject.sidePanelTab.container.eventHandler.listenToEvent('opening', onOpening)
closingEventSubscriptionId = thisObject.sidePanelTab.container.eventHandler.listenToEvent('closing', onClosing)
browserResizedEventSubscriptionId = canvas.eventHandler.listenToEvent('Browser Resized', resize)
isInitialized = true
}
function finalize() {
canvas.eventHandler.stopListening(browserResizedEventSubscriptionId)
thisObject.sidePanelTab.container.eventHandler.stopListening(openingEventSubscriptionId)
thisObject.sidePanelTab.container.eventHandler.stopListening(closingEventSubscriptionId)
}
function onOpening() {
let docIFrame = document.getElementById('docIFrame')
if (docIFrame.src === "") {
docIFrame.src = UI.projects.superalgos.globals.docs.DOCUMENTATION_URL_DEFAULT
}
}
function onClosing() {
}
function navigateTo(url) {
let docIFrame = document.getElementById('docIFrame')
docIFrame.src = url
thisObject.sidePanelTab.open()
}
function resize() {
thisObject.container.frame.width = 1200
thisObject.container.frame.height = browserCanvas.height // - TOP_SPACE_HEIGHT
thisObject.container.frame.position.x = browserCanvas.width
thisObject.container.frame.position.y = 0 // TOP_SPACE_HEIGHT
if (thisObject.sidePanelTab !== undefined) {
thisObject.sidePanelTab.resize()
}
}
function getContainer(point, purpose) {
let container
container = thisObject.sidePanelTab.getContainer(point, purpose)
if (container !== undefined) { return container }
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
} else {
return undefined
}
}
function physics() {
thisObject.sidePanelTab.physics()
docAppDivPhysics()
iFramePhysics()
function docAppDivPhysics() {
let docAppDiv = document.getElementById('docApp')
docAppDivPosition = {
x: 0,
y: 0
}
docAppDivPosition = thisObject.container.frame.frameThisPoint(docAppDivPosition)
docAppDiv.style = ' ' +
'position:fixed; top:' + docAppDivPosition.y + 'px; ' +
'left:' + docAppDivPosition.x + 'px; z-index:1; ' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
}
function iFramePhysics() {
let docIFrame = document.getElementById('docIFrame')
docIFrame.style = ' ' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
}
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
if (isInitialized === false) { return }
borders()
thisObject.sidePanelTab.draw()
}
function borders() {
let point1
let point2
let point3
let point4
point1 = {
x: 0,
y: 0
}
point2 = {
x: thisObject.container.frame.width,
y: 0
}
point3 = {
x: thisObject.container.frame.width,
y: thisObject.container.frame.height
}
point4 = {
x: 0,
y: thisObject.container.frame.height
}
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
point4 = thisObject.container.frame.frameThisPoint(point4)
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
browserCanvasContext.lineTo(point1.x, point1.y)
browserCanvasContext.closePath()
let opacity = 1
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.LIGHT_GREY + ', ' + opacity + ''
browserCanvasContext.fill()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREY + ', ' + opacity + ''
browserCanvasContext.lineWidth = 0.3
browserCanvasContext.stroke()
/* Shadow */
if (thisObject.container.status !== 'hidden') {
for (let i = 0; i <= 30; i++) {
opacity = 1 - (i / 300) - 0.95
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point2.x + i, point2.y)
browserCanvasContext.lineTo(point3.x + i, point3.y)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', ' + opacity + ''
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
}
}
}
}
@@ -0,0 +1,72 @@
function newBusyProgressBar() {
const MODULE_NAME = 'Circular Progress Bar'
let thisObject = {
container: undefined,
isDeployed: undefined,
visible: undefined,
physics: physics,
draw: draw,
finalize: finalize,
initialize: initialize
}
let position
let addRadius
let eventSubscriptionHeartbeat
return thisObject
function finalize() {
thisObject.payload = undefined
thisObject.fitFunction = undefined
}
function initialize(pPosition) {
position = pPosition
addRadius = 0
}
function physics() {
addRadius = addRadius + 20
}
function draw() {
if (thisObject.visible !== true) { return }
let visiblePosition = {
x: position.x,
y: position.y
}
visiblePosition = thisObject.fitFunction(visiblePosition)
const RADIUS = 10 + addRadius
let OPACITY = 1
let initialAngle = 0
let finalAngle = Math.PI * 2
browserCanvasContext.beginPath()
browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, RADIUS, initialAngle, finalAngle, false)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)'
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + OPACITY * 2 + ')'
browserCanvasContext.lineWidth = 15
browserCanvasContext.setLineDash([3, 4])
browserCanvasContext.stroke()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = 10
browserCanvasContext.setLineDash([3, 4])
browserCanvasContext.stroke()
}
}
@@ -0,0 +1,225 @@
function newCircularMenu() {
const MODULE_NAME = 'Circular Menu'
let thisObject = {
container: undefined,
isDeployed: undefined,
internalClick: internalClick,
physics: physics,
invisiblePhysics: invisiblePhysics,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME, 'Circle')
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = false
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
let menuItems = []
let selfFocusEventSubscriptionId
let selfNotFocuskEventSubscriptionId
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(selfFocusEventSubscriptionId)
thisObject.container.eventHandler.stopListening(selfNotFocuskEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
menuItem.finalize()
}
menuItems = undefined
}
function initialize(menuItemsInitialValues, payload) {
/* Create the array of Menu Items */
let iconAndTextArray = []
let iconOnlyArray
let ringsArray = [[], [], [], []]
for (let i = 0; i < menuItemsInitialValues.length; i++) {
let menuItem = newCircularMenuItem()
let menuItemInitialValue = menuItemsInitialValues[i]
menuItem.action = menuItemInitialValue.action
menuItem.actionProject = menuItemInitialValue.actionProject
menuItem.actionFunction = menuItemInitialValue.actionFunction
menuItem.actionStatus = menuItemInitialValue.actionStatus
menuItem.label = menuItemInitialValue.label
menuItem.workingLabel = menuItemInitialValue.workingLabel
menuItem.workDoneLabel = menuItemInitialValue.workDoneLabel
menuItem.workFailedLabel = menuItemInitialValue.workFailedLabel
menuItem.secondaryAction = menuItemInitialValue.secondaryAction
menuItem.secondaryLabel = menuItemInitialValue.secondaryLabel
menuItem.secondaryWorkingLabel = menuItemInitialValue.secondaryWorkingLabel
menuItem.secondaryWorkDoneLabel = menuItemInitialValue.secondaryWorkDoneLabel
menuItem.secondaryWorkFailedLabel = menuItemInitialValue.secondaryWorkFailedLabel
menuItem.secondaryIcon = menuItemInitialValue.secondaryIcon
menuItem.visible = menuItemInitialValue.visible
menuItem.iconPathOn = menuItemInitialValue.iconPathOn
menuItem.iconPathOff = menuItemInitialValue.iconPathOff
menuItem.rawRadius = menuItemInitialValue.rawRadius
menuItem.targetRadius = menuItemInitialValue.label
menuItem.currentRadius = menuItemInitialValue.currentRadius
menuItem.angle = menuItemInitialValue.angle
menuItem.currentStatus = menuItemInitialValue.currentStatus
menuItem.relatedUiObject = menuItemInitialValue.relatedUiObject
menuItem.dontShowAtFullscreen = menuItemInitialValue.dontShowAtFullscreen
menuItem.askConfirmation = menuItemInitialValue.askConfirmation
menuItem.confirmationLabel = menuItemInitialValue.confirmationLabel
menuItem.disableIfPropertyIsDefined = menuItemInitialValue.disableIfPropertyIsDefined
menuItem.propertyToCheckFor = menuItemInitialValue.propertyToCheckFor
menuItem.ring = menuItemInitialValue.ring
menuItem.icons = menuItemInitialValue.icons
if (menuItem.label === undefined) {
menuItem.type = 'Icon Only'
if (menuItem.ring === undefined) {
menutItem.ring = 1
}
iconOnlyArray = ringsArray[menuItem.ring - 1]
iconOnlyArray.push(menuItem)
} else {
menuItem.type = 'Icon & Text'
iconAndTextArray.push(menuItem)
}
menuItem.initialize(payload)
menuItem.container.connectToParent(thisObject.container, false, false, true, true, false, false, true, true)
menuItems.push(menuItem)
}
/* There are 4 possible rings of icons, we will go through each of them here. */
let amplitudeArray = [80, 50, 40, 80]
let initialAngleArray = [220, 205, 200, 180]
for (let j = 1; j < ringsArray.length + 1; j++) {
let iconOnlyArray = ringsArray[j - 1]
/* Here we calculate the angles for each menu item, and then apply it if it was not previously defined. */
let amplitude = amplitudeArray[j - 1]
let initialAngle = initialAngleArray[j - 1]
let step = amplitude / (iconOnlyArray.length - 1)
if (iconOnlyArray.length === 1) {
step = 0
}
for (let i = 0; i < iconOnlyArray.length; i++) {
let menuItem = iconOnlyArray[i]
let angle = initialAngle - step * i
if (menuItem.angle === undefined) {
menuItem.angle = angle
}
}
}
/* Text and Icon */
let amplitude = 140
let initialAngle = -70
step = amplitude / 7
let currentItem = (7 - iconAndTextArray.length) / 2 + 1
for (let i = 0; i < iconAndTextArray.length; i++) {
let menuItem = iconAndTextArray[i]
let angle = initialAngle + step * (currentItem - 0.5)
currentItem++
if (menuItem.angle === undefined) {
menuItem.angle = angle
}
}
iconOnlyArray = undefined
iconAndTextArray = undefined
/* Listen to events */
selfFocusEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onFocus', onFocus)
selfNotFocuskEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onNotFocus', onNotFocus)
}
function getContainer(point) {
let container
if (thisObject.isDeployed === true) {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
if (menuItem.visible === true) {
container = menuItem.getContainer(point)
}
if (container !== undefined) { return container }
}
}
}
function internalClick(action) {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
if (menuItem.visible === true) {
if (menuItem.nextAction === action) {
menuItem.internalClick()
}
}
}
}
function invisiblePhysics() {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
menuItem.invisiblePhysics()
}
}
function physics() {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
menuItem.physics()
}
}
function onFocus() {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
menuItem.targetRadius = Math.trunc(menuItem.rawRadius * 1.5)
menuItem.isDeployed = true
}
thisObject.isDeployed = true
}
function onNotFocus() {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
menuItem.targetRadius = menuItem.rawRadius * 0 - i * 1.5
menuItem.isDeployed = false
}
thisObject.isDeployed = false
}
function drawBackground(pFloatingObject) {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
if (menuItem.visible === true) {
menuItem.drawBackground()
}
}
}
function drawForeground(pFloatingObject) {
for (let i = 0; i < menuItems.length; i++) {
let menuItem = menuItems[i]
if (menuItem.visible === true) {
menuItem.drawForeground()
}
}
}
}
@@ -0,0 +1,492 @@
function newCircularMenuItem() {
const MODULE_NAME = 'Circular Menu Iem'
let thisObject = {
type: undefined,
isDeployed: undefined,
askConfirmation: undefined,
confirmationLabel: undefined,
iconOn: undefined,
iconOff: undefined,
icons: undefined,
currentIcon: undefined,
disableIfPropertyIsDefined: undefined,
propertyToCheckFor: undefined,
action: undefined,
actionProject: undefined,
actionFunction: undefined,
actionStatus: undefined,
label: undefined,
workingLabel: undefined,
workDoneLabel: undefined,
workFailedLabel: undefined,
secondaryAction: undefined,
secondaryLabel: undefined,
secondaryWorkingLabel: undefined,
secondaryWorkDoneLabel: undefined,
secondaryWorkFailedLabel: undefined,
secondaryIcon: undefined,
nextAction: undefined,
visible: false,
iconPathOn: undefined,
iconPathOff: undefined,
rawRadius: undefined,
targetRadius: undefined,
currentRadius: undefined,
angle: undefined,
container: undefined,
payload: undefined,
relatedUiObject: undefined,
dontShowAtFullscreen: undefined,
isEnabled: true,
shorcutNumber: undefined,
internalClick: internalClick,
physics: physics,
invisiblePhysics: invisiblePhysics,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = true
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.container.frame.width = 0
thisObject.container.frame.height = 0
let isMouseOver = false
let selfMouseOverEventSubscriptionId
let selfMouseClickEventSubscriptionId
let selfMouseNotOverEventSubscriptionId
let labelToPrint = ''
let defaultBackgroudColor = UI_COLOR.BLACK
let backgroundColorToUse = UI_COLOR.RED
let temporaryStatus = 0
let temporaryStatusCounter = 0
const STATUS_NO_ACTION_TAKEN_YET = 0
const STATUS_PRIMARY_ACTION_WORKING = -1
const STATUS_SECONDARY_ACTION_WORKING = -2
const STATUS_PRIMARY_WORK_DONE = -3
const STATUS_PRIMARY_WORK_FAILED = -4
const STATUS_WAITING_CONFIRMATION = -5
const STATUS_SECONDARY_WORK_DONE = -6
const STATUS_SECONDARY_WORK_FAILED = -7
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
thisObject.iconOn = undefined
thisObject.iconOff = undefined
thisObject.icons = undefined
thisObject.currentIcon = undefined
thisObject.payload = undefined
thisObject.actionFunction = undefined
thisObject.actionStatus = undefined
thisObject.disableIfPropertyIsDefined = undefined
thisObject.propertyToCheckFor = undefined
}
function initialize(pPayload) {
thisObject.payload = pPayload
iconPhysics()
selfMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
selfMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
containerPhysics()
thisObject.nextAction = thisObject.action
}
function getContainer(point) {
if (thisObject.dontShowAtFullscreen === true && AT_FULL_SCREEN_MODE === true) { return }
let container
if (thisObject.isDeployed === true) {
if (thisObject.container.frame.isThisPointHere(point, true, false) === true) {
return thisObject.container
} else {
return undefined
}
}
}
function invisiblePhysics() {
temporaryStatusPhysics()
}
function temporaryStatusPhysics() {
/* Temporary Status impacts on the label to use and the background of that label */
if (temporaryStatusCounter > 0) {
temporaryStatusCounter--
}
if (temporaryStatusCounter === 0) {
temporaryStatus = STATUS_NO_ACTION_TAKEN_YET
labelToPrint = thisObject.label
backgroundColorToUse = defaultBackgroudColor
thisObject.nextAction = thisObject.action
}
}
function physics() {
if (thisObject.dontShowAtFullscreen === true && AT_FULL_SCREEN_MODE === true) { return }
positionPhysics()
temporaryStatusPhysics()
disablePhysics()
iconPhysics()
backgroundColorPhysics()
containerPhysics()
}
function positionPhysics() {
let INCREASE_STEP = 2
if (Math.abs(thisObject.currentRadius - thisObject.targetRadius) >= INCREASE_STEP) {
if (thisObject.currentRadius < thisObject.targetRadius) {
thisObject.currentRadius = thisObject.currentRadius + INCREASE_STEP
} else {
thisObject.currentRadius = thisObject.currentRadius - INCREASE_STEP
}
}
let radiusGrowthFactor
if (thisObject.type === 'Icon Only') {
switch (thisObject.ring) {
case 1: {
radiusGrowthFactor = 5.5
break
}
case 2: {
radiusGrowthFactor = 4.0
break
}
case 3: {
radiusGrowthFactor = 3.0
break
}
case 4: {
radiusGrowthFactor = 2.0
break
}
}
} else {
radiusGrowthFactor = 3.2
}
radiusGrowthFactor = radiusGrowthFactor * UI.projects.superalgos.spaces.floatingSpace.settings.node.menuItem.radiusPercentage / 100
thisObject.container.frame.position.x =
thisObject.payload.floatingObject.targetRadius *
radiusGrowthFactor / 7
* Math.cos(toRadians(thisObject.angle)) -
thisObject.currentRadius * 1.5
thisObject.container.frame.position.y =
thisObject.payload.floatingObject.targetRadius *
radiusGrowthFactor / 7
* Math.sin(toRadians(thisObject.angle))
- thisObject.container.frame.height / 2
}
function disablePhysics() {
/* Here we will check if we need to monitor a property that influences the status of the Menu Item. */
if (thisObject.disableIfPropertyIsDefined === true) {
if (thisObject.payload.node[thisObject.propertyToCheckFor] === undefined) {
/* This menu item is enabled. */
thisObject.isEnabled = true
} else {
/* This menu item is disabled. */
thisObject.isEnabled = false
}
}
}
function containerPhysics() {
if (thisObject.type === 'Icon & Text') {
thisObject.container.frame.width = 220 * UI.projects.superalgos.spaces.floatingSpace.settings.node.menuItem.widthPercentage / 100
} else {
thisObject.container.frame.width = 50 * UI.projects.superalgos.spaces.floatingSpace.settings.node.menuItem.widthPercentage / 100
}
thisObject.container.frame.height = 40 * UI.projects.superalgos.spaces.floatingSpace.settings.node.menuItem.heightPercentage / 100
}
function backgroundColorPhysics() {
defaultBackgroudColor = UI.projects.superalgos.spaces.floatingSpace.style.node.menuItem.backgroundColor
}
function iconPhysics() {
if (
(
temporaryStatus === STATUS_PRIMARY_WORK_DONE ||
temporaryStatus === STATUS_SECONDARY_ACTION_WORKING ||
temporaryStatus === STATUS_SECONDARY_WORK_DONE ||
temporaryStatus === STATUS_SECONDARY_WORK_FAILED
) && thisObject.secondaryAction !== undefined
) {
thisObject.iconOn = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName('Superalgos', thisObject.secondaryIcon)
thisObject.iconOff = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName('Superalgos', thisObject.secondaryIcon)
} else {
if (thisObject.relatedUiObject !== undefined) {
thisObject.iconOn = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.relatedUiObject)
thisObject.iconOff = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.project, thisObject.relatedUiObject)
} else {
if (thisObject.iconPathOn !== undefined && thisObject.iconPathOff !== undefined) {
thisObject.iconOn = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName('Superalgos', thisObject.iconPathOn)
thisObject.iconOff = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName('Superalgos', thisObject.iconPathOff)
} else {
thisObject.iconOn = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName('Superalgos', thisObject.icons[thisObject.actionStatus()])
thisObject.iconOff = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName('Superalgos', thisObject.icons[thisObject.actionStatus()])
}
}
}
/* Current Status might be linked to some other object status */
if (thisObject.actionStatus !== undefined) {
thisObject.currentStatus = thisObject.actionStatus()
}
/* Current Status sets the icon to be used */
if (thisObject.currentStatus === true) {
thisObject.icon = thisObject.iconOn
} else {
thisObject.icon = thisObject.iconOff
}
}
function onMouseOver(point) {
if (thisObject.container.frame.isThisPointHere(point, true, false) === true) {
isMouseOver = true
} else {
isMouseOver = false
}
MENU_ITEM_ON_FOCUS = thisObject
}
function onMouseNotOver(point) {
isMouseOver = false
MENU_ITEM_ON_FOCUS = undefined
}
function internalClick() {
if (thisObject.shorcutNumber !== undefined) {
let label = thisObject.payload.node.name + ' ' + labelToPrint
UI.projects.superalgos.spaces.cockpitSpace.setStatus(label, 4, UI.projects.superalgos.spaces.cockpitSpace.statusTypes.ALL_GOOD)
}
onMouseClick()
}
function onMouseClick() {
if (thisObject.isEnabled === false) { return }
if (thisObject.label === undefined) {
/* This is what we have in the case of menu items that are only Icons. In this situation there is no complex logic, just execute the specified action. */
thisObject.actionFunction({ node: thisObject.payload.node, name: thisObject.action, project: thisObject.actionProject, relatedNodeType: thisObject.relatedUiObject })
return
}
if (thisObject.askConfirmation !== true) { /* No confirmation is needed */
if (temporaryStatus === STATUS_NO_ACTION_TAKEN_YET || temporaryStatus === STATUS_PRIMARY_WORK_DONE) {
executeAction()
} // Any click out of those states is ignored
} else {
/* Confirmation is needed */
/* The first click ask for confirmation. */
if (temporaryStatus === STATUS_NO_ACTION_TAKEN_YET) {
setStatus(thisObject.confirmationLabel, UI_COLOR.GOLDEN_ORANGE, 100, STATUS_WAITING_CONFIRMATION)
return
}
/* A Click during confirmation executes the pre-defined action. */
if (temporaryStatus === STATUS_WAITING_CONFIRMATION || temporaryStatus === STATUS_PRIMARY_WORK_DONE) {
executeAction()
if (thisObject.workDoneLabel !== undefined) {
setStatus(thisObject.workDoneLabel, UI_COLOR.PATINATED_TURQUOISE, 5, STATUS_SECONDARY_WORK_DONE)
} else {
setStatus('Done', UI_COLOR.PATINATED_TURQUOISE, 5, STATUS_SECONDARY_WORK_DONE)
}
return
}
}
function executeAction() {
if (temporaryStatus === STATUS_NO_ACTION_TAKEN_YET || temporaryStatus === STATUS_WAITING_CONFIRMATION) {
/* We need to execute the main Action */
/* If there is a working label defined, we use it here. */
if (thisObject.workingLabel !== undefined) {
setStatus(thisObject.workingLabel, UI_COLOR.GREY, undefined, STATUS_PRIMARY_ACTION_WORKING) // Status will not expire, will only change with a callback. Mouse Clicks will be ignored.
}
/* Execute the action and wait for callbacks to update our statuus. */
thisObject.actionFunction({ node: thisObject.payload.node, name: thisObject.action, project: thisObject.actionProject, relatedNodeType: thisObject.relatedUiObject, callBackFunction: onPrimaryCallBack })
return
}
if (temporaryStatus === STATUS_PRIMARY_WORK_DONE && thisObject.secondaryAction !== undefined) {
/* We need to execute the secondary action. */
if (thisObject.secondaryWorkingLabel !== undefined) {
setStatus(thisObject.secondaryWorkingLabel, UI_COLOR.GREY, undefined, STATUS_SECONDARY_ACTION_WORKING) // Status will not expire, will only change with a callback. Mouse Clicks will be ignored.
}
/* Execute the action and wait for callbacks to update our statuus. */
thisObject.actionFunction({ node: thisObject.payload.node, name: thisObject.secondaryAction, project: thisObject.actionProject, relatedNodeType: thisObject.relatedUiObject, callBackFunction: onSecondaryCallBack })
return
}
function onPrimaryCallBack(err, event) {
/* While the primary action is being executed some event might have happen. Following we process the ones we can */
if (event !== undefined) {
if (event.type === 'Secondary Action Already Executed') {
setStatus(thisObject.secondaryWorkDoneLabel, UI_COLOR.PATINATED_TURQUOISE, 5, STATUS_SECONDARY_WORK_DONE)
return
}
}
/* If there is a secondary action we will act different that if there is not */
if (thisObject.secondaryAction === undefined) { // This means there are no more possible actions.
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
if (thisObject.workDoneLabel !== undefined) {
setStatus(thisObject.workDoneLabel, UI_COLOR.PATINATED_TURQUOISE, 5, STATUS_PRIMARY_WORK_DONE)
}
} else {
if (thisObject.workFailedLabel != undefined) {
setStatus(thisObject.workFailedLabel, UI_COLOR.TITANIUM_YELLOW, 5, STATUS_PRIMARY_WORK_FAILED)
}
}
} else {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
if (thisObject.workDoneLabel !== undefined) {
thisObject.nextAction = thisObject.secondaryAction
setStatus(thisObject.secondaryLabel, defaultBackgroudColor, undefined, STATUS_PRIMARY_WORK_DONE)
}
} else {
if (thisObject.workFailedLabel != undefined) {
setStatus(thisObject.workFailedLabel, UI_COLOR.TITANIUM_YELLOW, 5, STATUS_PRIMARY_WORK_FAILED)
}
}
}
}
function onSecondaryCallBack(err) {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
if (thisObject.secondaryWorkDoneLabel !== undefined) {
setStatus(thisObject.secondaryWorkDoneLabel, UI_COLOR.PATINATED_TURQUOISE, 5, STATUS_SECONDARY_WORK_DONE)
}
} else {
if (thisObject.secondaryWorkFailedLabel != undefined) {
setStatus(thisObject.secondaryWorkFailedLabel, UI_COLOR.TITANIUM_YELLOW, 5, STATUS_SECONDARY_WORK_FAILED)
}
}
}
}
}
function setStatus(text, backgroundColor, waitingCycles, newStatus) {
labelToPrint = text
backgroundColorToUse = backgroundColor
temporaryStatus = newStatus
temporaryStatusCounter = newStatus // This will often put this into negatives numbers, which will disable the counting back and automatic reseting.
if (waitingCycles !== undefined) { // This will override the often negative value with a positive one that will tend to zero onto the default state.
temporaryStatusCounter = waitingCycles
}
}
function drawBackground() {
if (thisObject.dontShowAtFullscreen === true && AT_FULL_SCREEN_MODE === true) { return }
if (thisObject.container.frame.position.x > 0 && thisObject.isDeployed === true && thisObject.currentRadius >= thisObject.targetRadius) {
if (thisObject.type === 'Icon & Text') {
let backgroundColor = backgroundColorToUse
if (thisObject.isEnabled === false) {
backgroundColor = UI_COLOR.GREY
}
let params = {
cornerRadius: 5,
lineWidth: 0.1,
container: thisObject.container,
borderColor: backgroundColor,
backgroundColor: backgroundColor,
castShadow: false,
xOffset: 60
}
if (isMouseOver === true) {
params.opacity = 1
} else {
params.opacity = 0.8
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
}
}
}
function drawForeground() {
if (thisObject.dontShowAtFullscreen === true && AT_FULL_SCREEN_MODE === true) { return }
let menuPosition = {
x: thisObject.currentRadius * 1.5,
y: thisObject.container.frame.height / 2
}
menuPosition = thisObject.container.frame.frameThisPoint(menuPosition)
/* Menu Item */
let iconSize
if (isMouseOver === true) {
iconSize = UI.projects.superalgos.spaces.floatingSpace.style.node.menuItem.imageSize * 150 / 100
} else {
iconSize = UI.projects.superalgos.spaces.floatingSpace.style.node.menuItem.imageSize
}
if (thisObject.icon === undefined) { return }
if (thisObject.icon.canDrawIcon === true && thisObject.currentRadius > 1 && thisObject.isDeployed === true) {
browserCanvasContext.drawImage(thisObject.icon, menuPosition.x - iconSize, menuPosition.y - iconSize, iconSize * 2, iconSize * 2)
/* Menu Label */
if (thisObject.type === 'Icon & Text') {
label = labelToPrint
if (thisObject.shorcutNumber !== undefined) {
label = '' + thisObject.shorcutNumber + '- ' + labelToPrint
}
let labelPoint
let fontSize = UI.projects.superalgos.spaces.floatingSpace.style.node.menuItem.fontSize
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
if (thisObject.currentRadius >= thisObject.targetRadius) {
labelPoint = {
x: menuPosition.x + thisObject.currentRadius + 25,
y: menuPosition.y + fontSize * FONT_ASPECT_RATIO
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + UI.projects.superalgos.spaces.floatingSpace.style.node.menuItem.fontColor + ', 1)'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
}
}
}
}
@@ -0,0 +1,147 @@
function newCircularProgressBar() {
const MODULE_NAME = 'Circular Progress Bar'
let thisObject = {
container: undefined,
isDeployed: undefined,
physics: physics,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME, 'Circle')
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = false
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
let opacityCounters = []
let eventSubscriptionIdHeartbeat
let needToDrawRing = true
let eventsServerClient
return thisObject
function finalize() {
finalizeEventsServerClient()
thisObject.container = undefined
thisObject.payload = undefined
thisObject.fitFunction = undefined
}
function finalizeEventsServerClient() {
if (eventsServerClient !== undefined) {
let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id
if (eventSubscriptionIdHeartbeat !== undefined) {
eventsServerClient.stopListening(key, eventSubscriptionIdHeartbeat)
}
}
}
function initialize(payload, pEventsServerClient) {
thisObject.payload = payload
finalizeEventsServerClient()
eventsServerClient = pEventsServerClient
for (let i = 0; i < 60; i++) {
opacityCounters.push(0)
}
let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id
eventsServerClient.listenToEvent(key, 'Heartbeat', undefined, key, onResponse, onHeartBeat)
function onResponse(message) {
eventSubscriptionIdHeartbeat = message.eventSubscriptionId
}
}
function onHeartBeat(message) {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.uiObject === undefined) { return }
opacityCounters[message.event.seconds] = 2000
if (message.event.processingDate !== undefined) {
thisObject.payload.uiObject.valueAtAngle = false
thisObject.payload.uiObject.setValue(message.event.processingDate, 2000)
}
if (message.event.percentage !== undefined) {
thisObject.payload.uiObject.setPercentage(message.event.percentage, 2000)
}
if (message.event.status !== undefined) {
needToDrawRing = false
thisObject.payload.uiObject.setStatus(message.event.status, 200000)
}
thisObject.payload.uiObject.heartBeat()
}
function getContainer(point) {
if (UI.projects.superalgos.spaces.floatingSpace.inMapMode === true) { return }
let container
for (let i = 0; i < menuItems.length; i++) {
let menutItem = menuItems[i]
container = menutItem.getContainer(point)
if (container !== undefined) { return container }
}
}
function physics() {
for (let i = 0; i < 60; i++) {
opacityCounters[i] = opacityCounters[i] - 2
if (opacityCounters[i] < 0) {
opacityCounters[i] = 0
}
}
}
function drawForeground(pFloatingObject) {
}
function drawBackground(pFloatingObject) {
if (UI.projects.superalgos.spaces.floatingSpace.inMapMode === true) { return }
if (needToDrawRing !== true) { return }
const VISIBLE_RADIUS = thisObject.container.frame.radius
let visiblePosition = {
x: thisObject.container.frame.position.x,
y: thisObject.container.frame.position.y
}
visiblePosition = thisObject.container.frame.frameThisPoint(visiblePosition)
visiblePosition = thisObject.fitFunction(visiblePosition)
for (let i = 0; i < 60; i++) {
let OPACITY = opacityCounters[i] / 4000
if (OPACITY === 0) { continue }
let initialAngle = Math.PI * 2 / 60 * i - Math.PI / 2
let finalAngle = Math.PI * 2 / 60 * (i + 1) - Math.PI / 2
browserCanvasContext.beginPath()
browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS, initialAngle, finalAngle, false)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GOLDEN_ORANGE + ', ' + OPACITY * 2 + ')'
browserCanvasContext.lineWidth = 6 + opacityCounters[i] / 100 / 4
browserCanvasContext.setLineDash([1, 10])
browserCanvasContext.stroke()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = 0 + opacityCounters[i] / 100 / 4
browserCanvasContext.setLineDash([2, 10])
browserCanvasContext.stroke()
}
}
}
@@ -0,0 +1,200 @@
function newCodeEditor() {
const MODULE_NAME = 'Code Editor'
let thisObject = {
isVisibleFunction: undefined,
visible: false,
imagePathOK: undefined,
imagePathNOT_OK: undefined,
rawRadius: undefined,
targetRadius: undefined,
currentRadius: undefined,
container: undefined,
payload: undefined,
deactivate: deactivate,
activate: activate,
physics: physics,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = false
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
let isMouseOver = false
let SIZE_FACTOR = 1.0
return thisObject
function finalize() {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
}
function initialize() {
}
function deactivate() {
if (thisObject.visible === true) {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.code = textArea.value
}
EDITOR_ON_FOCUS = false
}
function activate(action) {
thisObject.visible = true
thisObject.payload = action.node.payload
thisObject.rawRadius = 8
thisObject.targetRadius = thisObject.container.frame.radius
thisObject.currentRadius = 0
thisObject.payload.uiObject.resetErrorMessage()
let textArea = document.getElementById('textArea')
textArea.value = thisObject.payload.node.code
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + UI_FONT.PRIMARY + ';' +
'font-size: 14px;' +
'background-color: rgb(' + UI_COLOR.RUSTED_RED + ');' +
'color:rgb(255, 255, 255);' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
textArea.style.display = 'block'
textArea.focus()
EDITOR_ON_FOCUS = true
}
function getContainer(point) {
let container
if (thisObject.visible === true) {
if (point.x === VERY_LARGE_NUMBER) {
/* The the mouse leaves the canvas, and event of mouse over with a ridiculous coordinate is triggered so that
anyone can react. In our case, the code editor has a text area that is not part of the canvas, so the event is
triggered. We compensate recognizing this coordinate and returning our container. */
return thisObject.container
}
if (thisObject.container.frame.isThisPointHere(point, true, false) === true) {
return thisObject.container
} else {
return undefined
}
}
}
function physics() {
if (Math.abs(thisObject.currentRadius - thisObject.targetRadius) >= 0.5) {
if (thisObject.currentRadius < thisObject.targetRadius) {
thisObject.currentRadius = thisObject.currentRadius + 0.5
} else {
thisObject.currentRadius = thisObject.currentRadius - 0.5
}
}
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.container.frame.width = thisObject.container.frame.radius * 1 * SIZE_FACTOR
thisObject.container.frame.height = thisObject.container.frame.radius * 1 * SIZE_FACTOR
let textAreaPosition = {
x: 0 - thisObject.container.frame.width / 2,
y: 0 - thisObject.container.frame.height * 3 / 7 + CURRENT_TOP_MARGIN
}
textAreaPosition = thisObject.container.frame.frameThisPoint(textAreaPosition)
if (thisObject.visible === true) {
let checkPosition = {
x: textAreaPosition.x,
y: textAreaPosition.y - CURRENT_TOP_MARGIN
}
if (thisObject.isVisibleFunction(checkPosition) === false) {
deactivate()
}
}
if (thisObject.visible === true) {
let textAreaDiv = document.getElementById('textAreaDiv')
textAreaDiv.style = 'position:fixed; top:' + textAreaPosition.y + 'px; left:' + textAreaPosition.x + 'px; z-index:1; '
}
}
function drawBackground() {
if (thisObject.visible === true) {
let position = {
x: 0,
y: 0
}
position = thisObject.container.frame.frameThisPoint(position)
let radius = thisObject.container.frame.radius * SIZE_FACTOR
if (radius > 0.5) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius + 3, 0, Math.PI * 2, true)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + 1 + ')'
browserCanvasContext.fill()
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius , 0, Math.PI * 2, true)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + 1 + ')'
browserCanvasContext.fill()
}
}
}
function drawForeground() {
let iconPosition = {
x: 0,
y: thisObject.currentRadius * 1.5
}
iconPosition = thisObject.container.frame.frameThisPoint(iconPosition)
/* Menu Item */
if (thisObject.canDrawIcon === true && thisObject.currentRadius > 1) {
browserCanvasContext.drawImage(thisObject.icon, iconPosition.x - thisObject.currentRadius, iconPosition.y - thisObject.currentRadius, thisObject.currentRadius * 2, thisObject.currentRadius * 2)
/* Menu Label */
let label = 'Code looks good!'
let labelPoint
let fontSize = 10
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
if (thisObject.currentRadius >= thisObject.targetRadius) {
labelPoint = {
x: iconPosition.x + thisObject.currentRadius + 10,
y: iconPosition.y + fontSize * FONT_ASPECT_RATIO
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,205 @@
function newConfigEditor() {
const MODULE_NAME = 'Config Editor'
let thisObject = {
isVisibleFunction: undefined,
visible: false,
imagePathOK: undefined,
imagePathNOT_OK: undefined,
rawRadius: undefined,
targetRadius: undefined,
currentRadius: undefined,
container: undefined,
payload: undefined,
deactivate: deactivate,
activate: activate,
physics: physics,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = false
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
let isMouseOver = false
let SIZE_FACTOR = 1
return thisObject
function finalize() {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
}
function initialize() {
}
function deactivate() {
if (thisObject.visible === true) {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.config = textArea.value
try {
let config = JSON.parse(thisObject.payload.node.config)
} catch (err) {
thisObject.payload.uiObject.setErrorMessage(err.message, 10)
}
}
EDITOR_ON_FOCUS = false
}
function activate(action) {
thisObject.visible = true
thisObject.payload = action.node.payload
thisObject.rawRadius = 8
thisObject.targetRadius = thisObject.container.frame.radius
thisObject.currentRadius = 0
thisObject.payload.uiObject.resetErrorMessage()
let textArea = document.getElementById('textArea')
textArea.value = thisObject.payload.node.config
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + UI_FONT.PRIMARY + ';' +
'font-size: 14px;' +
'background-color: rgb(' + UI_COLOR.DARK_TURQUOISE + ');' +
'color:rgb(255, 255, 255);' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
textArea.style.display = 'block'
textArea.focus()
EDITOR_ON_FOCUS = true
}
function getContainer(point) {
let container
if (thisObject.visible === true) {
if (point.x === VERY_LARGE_NUMBER) {
/* The the mouse leaves the canvas, and event of mouse over with a ridiculous coordinate is triggered so that
anyone can react. In our case, the config editor has a text area that is not part of the canvas, so the event is
triggered. We compensate recognizing this coordinate and returning our container. */
return thisObject.container
}
if (thisObject.container.frame.isThisPointHere(point, true, false) === true) {
return thisObject.container
} else {
return undefined
}
}
}
function physics() {
if (Math.abs(thisObject.currentRadius - thisObject.targetRadius) >= 0.5) {
if (thisObject.currentRadius < thisObject.targetRadius) {
thisObject.currentRadius = thisObject.currentRadius + 0.5
} else {
thisObject.currentRadius = thisObject.currentRadius - 0.5
}
}
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.container.frame.width = thisObject.container.frame.radius * 1 * SIZE_FACTOR
thisObject.container.frame.height = thisObject.container.frame.radius * 1 * SIZE_FACTOR
let textAreaPosition = {
x: 0 - thisObject.container.frame.width / 2,
y: 0 - thisObject.container.frame.height * 3 / 7 + CURRENT_TOP_MARGIN
}
textAreaPosition = thisObject.container.frame.frameThisPoint(textAreaPosition)
if (thisObject.visible === true) {
let checkPosition = {
x: textAreaPosition.x,
y: textAreaPosition.y - CURRENT_TOP_MARGIN
}
if (thisObject.isVisibleFunction(checkPosition) === false) {
deactivate()
}
}
if (thisObject.visible === true) {
let textAreaDiv = document.getElementById('textAreaDiv')
textAreaDiv.style = 'position:fixed; top:' + textAreaPosition.y + 'px; left:' + textAreaPosition.x + 'px; z-index:1; '
}
}
function drawBackground() {
if (thisObject.visible === true) {
let position = {
x: 0,
y: 0
}
position = thisObject.container.frame.frameThisPoint(position)
let radius = thisObject.container.frame.radius * SIZE_FACTOR
if (radius > 0.5) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius + 3, 0, Math.PI * 2, true)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + 1 + ')'
browserCanvasContext.fill()
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius , 0, Math.PI * 2, true)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + 1 + ')'
browserCanvasContext.fill()
}
}
}
function drawForeground() {
let iconPosition = {
x: 0,
y: thisObject.currentRadius * 1.5
}
iconPosition = thisObject.container.frame.frameThisPoint(iconPosition)
/* Menu Item */
if (thisObject.canDrawIcon === true && thisObject.currentRadius > 1) {
browserCanvasContext.drawImage(thisObject.icon, iconPosition.x - thisObject.currentRadius, iconPosition.y - thisObject.currentRadius, thisObject.currentRadius * 2, thisObject.currentRadius * 2)
/* Menu Label */
let label = 'Code looks good!'
let labelPoint
let fontSize = 10
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
if (thisObject.currentRadius >= thisObject.targetRadius) {
labelPoint = {
x: iconPosition.x + thisObject.currentRadius + 10,
y: iconPosition.y + fontSize * FONT_ASPECT_RATIO
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
}
}
}
@@ -0,0 +1,752 @@
/*
This module represent one layer of many possible layers that could be at the Floating Space. Objects in the same layer are subject to
the same physics, and by being at the same level, they interact with each other. For example, they can bounce when one hit the other.
This module posesses its own physics engine. There are different types of floating objects, but this layer takes care of each of them.
Floating Objects Types:
1. Profile Balls: These are small balls with a profile picture, and two levels, one above and one below the ball. They are usually used
to specify the location of a bot instance.
2. Notes: Notes are a rectangular area where some text is posted. It has a subject and a body.
3. UI Objects: These are small balls that represent parts of an strategy.
*/
function newFloatingLayer() {
const MODULE_NAME = 'Floating Layer'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
addFloatingObject: addFloatingObject,
removeFloatingObject: removeFloatingObject,
getFloatingObject: getFloatingObject,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
/*
When objects are added to this layer they are added to the invisibleFloatingObjects array and they stay there because they are invisible.
Visibility of objects is not decided at this layer, but outside. The ones who decides which object is visible or not are plotters, because
they know the position of objects and the coordinate system which these positions belong to.
To save resources, the physics engine only apply its calculations to visible floating objects.
*/
let invisibleFloatingObjects = []
/*
Floating objects are accesible to plotters because they carry a "payload" object that was creted by them. This object includes the position
and visible property. When visible turns to true, this layer module will move the reference of the floating object from the invisible array
to the visibleFloatingObjects array. If the plotter decides that the object is to far from the what the user is seeing, it can eventually
turn the visible property off again, forcing the layer to remove the object from the visibleFloatingObjects and place it again at the invisible
array.
*/
let visibleFloatingObjects = []
let maxTargetRepulsionForce = 0.001
let currentHandle = 0
let invisiblePhysicsIntervalId
return thisObject
function finalize() {
clearInterval(invisiblePhysicsIntervalId)
invisibleFloatingObjects = []
visibleFloatingObjects = []
}
function initialize() {
invisiblePhysicsIntervalId = setInterval(invisiblePhysics, 10000)
}
function getContainer(point) {
let container
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
container = floatingObject.getContainer(point)
if (container !== undefined) { return container }
}
return container
}
function addFloatingObject(pFloatingObject) {
currentHandle++
pFloatingObject.handle = currentHandle // Math.floor((Math.random() * 10000000) + 1);
visibleFloatingObjects.push(pFloatingObject)
}
function removeFloatingObject(pFloatingObjectHandle) {
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
if (floatingObject.handle === pFloatingObjectHandle) {
invisibleFloatingObjects.splice(i, 1) // Delete item from array.
return
}
}
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
if (floatingObject.handle === pFloatingObjectHandle) {
visibleFloatingObjects.splice(i, 1) // Delete item from array.
return
}
}
}
function getFloatingObject(pFloatingObjectHandle, pFloatingObjectIndex) {
/*
There are two ways to look for a floating object: by handle or by index. The search by handle is done on the visible and invisible array.
The search by index is done only on the visible ones. The search by index is usually needed when mouse events occurs. In those cases
only objects visible to the end usser matters.
*/
try {
if (pFloatingObjectHandle !== undefined) {
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
if (floatingObject.handle === pFloatingObjectHandle) {
return floatingObject
}
}
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
if (floatingObject.handle === pFloatingObjectHandle) {
return floatingObject
}
}
}
if (pFloatingObjectIndex !== undefined) {
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
if (i === pFloatingObjectIndex) {
return floatingObject
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] getFloatingObject -> err= ' + err.stack) }
}
}
function draw() {
drawInvisibleObjects()
drawVisibleObjects()
}
function drawInvisibleObjects() {
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
floatingObject.drawBackground()
}
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
floatingObject.drawMiddleground()
}
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[invisibleFloatingObjects.length - i - 1]
floatingObject.drawForeground()
}
}
function drawVisibleObjects() {
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
floatingObject.drawBackground()
}
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
floatingObject.drawMiddleground()
}
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[visibleFloatingObjects.length - i - 1]
floatingObject.drawForeground()
}
/* Invisible objects on focus (freezed) should still have some priority */
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
floatingObject.drawOnFocus()
}
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
floatingObject.drawOnFocus()
}
}
function collapsePhysics(thisObject) {
let parent = thisObject.payload.chainParent
if (parent === undefined) { return }
if (parent.payload === undefined) { return }
if (parent.payload.floatingObject === undefined) { return }
thisObject.isParentCollapsed = parent.payload.floatingObject.isCollapsed
if (thisObject.collapsedManually === false) {
thisObject.isCollapsed = parent.payload.floatingObject.isCollapsed
}
}
function makeVisible() {
let newInvisibleArray = []
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
collapsePhysics(floatingObject)
if (floatingObject.isParentCollapsed === false) {
visibleFloatingObjects.push(floatingObject)
} else {
newInvisibleArray.push(floatingObject)
}
}
invisibleFloatingObjects = newInvisibleArray
}
function makeInvisible() {
let newVisibleArray = []
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
collapsePhysics(floatingObject)
if (floatingObject.isParentCollapsed === true) {
invisibleFloatingObjects.push(floatingObject)
} else {
newVisibleArray.push(floatingObject)
}
}
visibleFloatingObjects = newVisibleArray
}
/******************************************/
/* */
/* Physics Engine Follows */
/* */
/******************************************/
function invisiblePhysics() {
/*
Note that the Physics for invisible objects is called with a fixed time interval,
since it does not need the high intensity physics called during the animation.
*/
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
floatingObject.invisiblePhysics()
}
}
function physics() {
/*
The Physics engine is hooked at the animation loop, so it executes very very often. According to this Physics engine, each
floating object has a position and a speed. In fact, each floating object has two positions at the same time:
1. The current position: is the position of the ball, floating around.
2. The anchor position: is the position of where the ball is achored on the plot. This one is inside the payload object controlled by the
plotter.
The anchor position influences the current position, since the Physics engine will apply a gravity force to the ball's position in order
to make it gravitate towards the anchor position. At the same time there will be a repulsion force that will prevent the ball reaching
the anchor position, so that the anchor point keeps visible to the user.
*/
try {
makeVisible()
makeInvisible()
visiblePhysics()
enginePhysics()
proximityPhysics()
function visiblePhysics() {
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
floatingObject.physics()
}
}
function proximityPhysics(){
for (let i = 0; i < visibleFloatingObjects.length; i++) {
proximityBetweenFloatingObjects(i)
}
}
function enginePhysics() {
/* This function makes all the calculations to apply phisycs on all visible floatingObjects in this layer. */
try {
DEBUG.variable1 = 'Invisible Floating Objets: ' + invisibleFloatingObjects.length
DEBUG.variable2 = 'Visible Floating Objets: ' + visibleFloatingObjects.length
if (UI.projects.superalgos.spaces.floatingSpace.settings.physics !== true) {return}
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
if (floatingObject.isFrozen === true) { continue }
/* From here on, only if they are not too far. */
if (UI.projects.superalgos.spaces.floatingSpace.isItFar(floatingObject.payload)) { continue }
if (floatingObject.positionLocked === false) {
floatingObject.container.frame.position.x = floatingObject.container.frame.position.x + floatingObject.currentSpeed.x
floatingObject.container.frame.position.y = floatingObject.container.frame.position.y + floatingObject.currentSpeed.y
}
if (floatingObject.friction < floatingObject.targetFriction) {
floatingObject.friction = floatingObject.friction + 0.00001
} else {
floatingObject.friction = floatingObject.friction - 0.00001
}
floatingObject.currentSpeed.x = floatingObject.currentSpeed.x * floatingObject.friction // Desaceleration factor.
floatingObject.currentSpeed.y = floatingObject.currentSpeed.y * floatingObject.friction // Desaceleration factor.
let payload = {
position: undefined,
visible: false
}
switch (floatingObject.type) {
case 'UI Object': {
payload.targetPosition = floatingObject.payload.targetPosition
payload.visible = floatingObject.payload.visible
break
}
default: {
break
}
}
if (floatingObject.container.frame.position.x < payload.targetPosition.x) {
floatingObject.currentSpeed.x = floatingObject.currentSpeed.x + 0.005
} else {
floatingObject.currentSpeed.x = floatingObject.currentSpeed.x - 0.005
}
if (floatingObject.container.frame.position.y < payload.targetPosition.y) {
floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + 0.005
} else {
floatingObject.currentSpeed.y = floatingObject.currentSpeed.y - 0.005
}
const MAX_SPEED = 10
if (floatingObject.currentSpeed.x > MAX_SPEED) {
floatingObject.currentSpeed.x = MAX_SPEED
}
if (floatingObject.currentSpeed.y > MAX_SPEED) {
floatingObject.currentSpeed.y = MAX_SPEED
}
if (floatingObject.currentSpeed.x < -MAX_SPEED) {
floatingObject.currentSpeed.x = -MAX_SPEED
}
if (floatingObject.currentSpeed.y < -MAX_SPEED) {
floatingObject.currentSpeed.y = -MAX_SPEED
}
// We let the Floating Object animate the physics loops by itself.
checkBoundaries(floatingObject)
/* Collision Control */
for (let k = i + 1; k < visibleFloatingObjects.length; k++) {
if (colliding(visibleFloatingObjects[i], visibleFloatingObjects[k])) {
resolveCollision(visibleFloatingObjects[k], visibleFloatingObjects[i])
}
}
/* Calculate repulsion force produced by all other floatingObjects */
repulsionForceBetweenFloatingObjects(i)
targetRepulsionForce(i)
gravityForce(floatingObject, payload)
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] physics -> applyPhysics -> err= ' + err.stack) }
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] physics -> err= ' + err.stack) }
}
}
function checkBoundaries(floatingObject) {
if (floatingObject.container.frame.position.x - floatingObject.container.frame.radius < 0) {
floatingObject.container.frame.position.x = floatingObject.container.frame.radius
floatingObject.currentSpeed.x = -floatingObject.currentSpeed.x
}
if (floatingObject.container.frame.position.x + floatingObject.container.frame.radius > UI.projects.superalgos.spaces.floatingSpace.container.frame.width) {
floatingObject.container.frame.position.x = UI.projects.superalgos.spaces.floatingSpace.container.frame.width - floatingObject.container.frame.radius
floatingObject.currentSpeed.x = -floatingObject.currentSpeed.x
}
if (floatingObject.container.frame.position.y - floatingObject.container.frame.radius < 0) {
floatingObject.container.frame.position.y = floatingObject.container.frame.radius
floatingObject.currentSpeed.y = -floatingObject.currentSpeed.y
}
if (floatingObject.container.frame.position.y + floatingObject.container.frame.radius > UI.projects.superalgos.spaces.floatingSpace.container.frame.height) {
floatingObject.container.frame.position.y = UI.projects.superalgos.spaces.floatingSpace.container.frame.height - floatingObject.container.frame.radius
floatingObject.currentSpeed.y = -floatingObject.currentSpeed.y
}
}
function gravityForce(floatingObject, payload) {
try {
/* We simulate a kind of gravity towards the target point of each floatingObject. This force will make the floatingObject to keep pushing to reach that point. */
const coulomb = 0.00001
const minForce = 0.01
let d = Math.sqrt(Math.pow(payload.targetPosition.x - floatingObject.container.frame.position.x, 2) + Math.pow(payload.targetPosition.y - floatingObject.container.frame.position.y, 2)) // ... we calculate the distance ...
let force = coulomb * d * d / floatingObject.currentMass // In this case the mass of the floatingObject affects the gravity force that it receives, that gives priority to target position to bigger floatingObjects.
if (force < minForce) { // We need this attraction force to overcome the friction we imposed to the system.
force = minForce
}
let pos1 = {
x: floatingObject.container.frame.position.x,
y: floatingObject.container.frame.position.y
}
let pos2 = {
x: payload.targetPosition.x,
y: payload.targetPosition.y
}
let posDiff = { // Next we need the vector resulting from the 2 positions.
x: pos2.x - pos1.x,
y: pos2.y - pos1.y
}
if (d !== 0) {
let unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector.
x: posDiff.x / d,
y: posDiff.y / d
}
let forceVector = {
x: unitVector.x * force,
y: unitVector.y * force
}
/* We add the force vector to the speed vector */
if (isNaN(forceVector.x) === false && isNaN(forceVector.y) === false) {
floatingObject.currentSpeed.x = floatingObject.currentSpeed.x + forceVector.x
floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + forceVector.y
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] gravityForce -> err= ' + err.stack) }
}
}
function repulsionForceBetweenFloatingObjects(currentFloatingObject) {
try {
/* We generate a repulsion force between floatingObjects, that prevents them to be collisioning so often. */
const coulomb = 2
let floatingObject1 = visibleFloatingObjects[currentFloatingObject]
for (let i = 0; i < visibleFloatingObjects.length; i++) {
// The force to be applied is considering all other floatingObjects...
if (i !== currentFloatingObject) {
// ... except for the current one.
let floatingObject2 = visibleFloatingObjects[i] // So, for each floatingObject...
let d = Math.sqrt(Math.pow(floatingObject2.container.frame.position.x - floatingObject1.container.frame.position.x, 2) + Math.pow(floatingObject2.container.frame.position.y - floatingObject1.container.frame.position.y, 2)) // ... we calculate the distance ...
let force = coulomb * floatingObject2.currentMass / (d * d) // ... and with it the repulsion force.
/* We need to put a hard limit to this force, in order to to eject very little floatingObjects to the infinite and beyond. */
if (force > 1) {
force = 1
}
let pos1 = {
x: floatingObject1.container.frame.position.x,
y: floatingObject1.container.frame.position.y
}
let pos2 = {
x: floatingObject2.container.frame.position.x,
y: floatingObject2.container.frame.position.y
}
let posDiff = { // Next we need the vector resulting from the 2 positions.
x: pos2.x - pos1.x,
y: pos2.y - pos1.y
}
let unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector.
x: posDiff.x / d,
y: posDiff.y / d
}
let forceVector = {
x: unitVector.x * force,
y: unitVector.y * force
}
/* We substract the force vector to the speed vector of the current floatingObject */
if (isNaN(forceVector.x) === false && isNaN(forceVector.y) === false) {
floatingObject1.currentSpeed.x = floatingObject1.currentSpeed.x - forceVector.x
floatingObject1.currentSpeed.y = floatingObject1.currentSpeed.y - forceVector.y
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] repulsionForceBetweenFloatingObjects -> err= ' + err.stack) }
}
}
function proximityBetweenFloatingObjects(currentFloatingObject) {
try {
let floatingObject1 = visibleFloatingObjects[currentFloatingObject]
floatingObject1.nearbyFloatingObjects = []
for (let i = 0; i < visibleFloatingObjects.length; i++) {
if (i !== currentFloatingObject) {
let floatingObject2 = visibleFloatingObjects[i] // So, for each floatingObject...
let d = Math.sqrt(Math.pow(floatingObject2.container.frame.position.x - floatingObject1.container.frame.position.x, 2) + Math.pow(floatingObject2.container.frame.position.y - floatingObject1.container.frame.position.y, 2)) // ... we calculate the distance ...
if (floatingObject1.nearbyFloatingObjects.length === 0) {
floatingObject1.nearbyFloatingObjects.push([d, floatingObject2])
} else {
let recordAdded = false
for (let j = 0; j < floatingObject1.nearbyFloatingObjects.length; j++) {
let recordedDistance = floatingObject1.nearbyFloatingObjects[j][0]
if (d < recordedDistance) {
floatingObject1.nearbyFloatingObjects.splice(j, 0, [d, floatingObject2])
recordAdded = true
break
}
}
if (recordAdded === false) {
floatingObject1.nearbyFloatingObjects.push([d, floatingObject2])
}
}
floatingObject1.nearbyFloatingObjects.splice(10, floatingObject1.nearbyFloatingObjects.length)
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] proximityBetweenFloatingObjects -> err= ' + err.stack) }
}
}
function targetRepulsionForce(currentFloatingObject) {
try {
/* We generate a repulsion force between floatingObjects, that prevents them to be collisioning so often. */
const coulomb = 2
let floatingObject1 = visibleFloatingObjects[currentFloatingObject]
for (let i = 0; i < visibleFloatingObjects.length; i++) {
// The force to be applied is considering all other floatingObjects...
let floatingObject2 = visibleFloatingObjects[i] // So, for each floatingObject...
let payload = {
position: undefined
}
switch (floatingObject2.type) {
case 'UI Object': {
payload.targetPosition = floatingObject2.payload.targetPosition
break
}
default: {
break
}
}
let d = Math.sqrt(Math.pow(payload.targetPosition.x - floatingObject1.container.frame.position.x, 2) + Math.pow(payload.targetPosition.y - floatingObject1.container.frame.position.y, 2)) // ... we calculate the distance ...
let force = coulomb * floatingObject2.currentMass / (d * d) // ... and with it the repulsion force.
/* We need to put a hard limit to this force, in order to to eject very little floatingObjects to the infinite and beyond. */
if (force > maxTargetRepulsionForce) {
force = maxTargetRepulsionForce
}
let pos1 = {
x: floatingObject1.container.frame.position.x,
y: floatingObject1.container.frame.position.y
}
let pos2 = {
x: payload.targetPosition.x,
y: payload.targetPosition.y
}
let posDiff = { // Next we need the vector resulting from the 2 positions.
x: pos2.x - pos1.x,
y: pos2.y - pos1.y
}
if (d !== 0) {
let unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector.
x: posDiff.x / d,
y: posDiff.y / d
}
let forceVector = {
x: unitVector.x * force,
y: unitVector.y * force
}
/* We substract the force vector to the speed vector of the current floatingObject */
if (isNaN(forceVector.x) === false && isNaN(forceVector.y) === false) {
floatingObject1.currentSpeed.x = floatingObject1.currentSpeed.x - forceVector.x
floatingObject1.currentSpeed.y = floatingObject1.currentSpeed.y - forceVector.y
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] targetRepulsionForce -> err= ' + err.stack) }
}
}
function colliding(floatingObject1, floatingObject2) {
try {
/* This function detects weather 2 floatingObjects collide with each other. */
let r1 = floatingObject1.container.frame.radius
let r2 = floatingObject2.container.frame.radius
let distance = Math.sqrt(Math.pow(floatingObject2.container.frame.position.x - floatingObject1.container.frame.position.x, 2) + Math.pow(floatingObject2.container.frame.position.y - floatingObject1.container.frame.position.y, 2))
if (distance > (r1 + r2)) {
// No solutions, the circles are too far apart.
return false
} else if (distance <= r1 + r2) {
// One circle contains the other.
return true
} else if ((distance === 0) && (r1 === r2)) {
// the circles coincide.
return true
} else return true
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] colliding -> err= ' + err.stack) }
}
}
function distance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
}
function resolveCollision(floatingObject1, floatingObject2) {
try {
/* This function changes speed and position of floatingObjects that are in collision */
let collisionision_angle = Math.atan2((floatingObject2.container.frame.position.y - floatingObject1.container.frame.position.y), (floatingObject2.container.frame.position.x - floatingObject1.container.frame.position.x))
let speed1 = Math.sqrt(floatingObject1.currentSpeed.x * floatingObject1.currentSpeed.x + floatingObject1.currentSpeed.y * floatingObject1.currentSpeed.y) // Magnitude of Speed Vector for floatingObject 1
let speed2 = Math.sqrt(floatingObject2.currentSpeed.x * floatingObject2.currentSpeed.x + floatingObject2.currentSpeed.y * floatingObject2.currentSpeed.y) // Magnitude of Speed Vector for floatingObject 2
let direction_1 = Math.atan2(floatingObject1.currentSpeed.y, floatingObject1.currentSpeed.x)
let direction_2 = Math.atan2(floatingObject2.currentSpeed.y, floatingObject2.currentSpeed.x)
let new_xspeed_1 = speed1 * Math.cos(direction_1 - collisionision_angle)
let new_yspeed_1 = speed1 * Math.sin(direction_1 - collisionision_angle)
let new_xspeed_2 = speed2 * Math.cos(direction_2 - collisionision_angle)
let new_yspeed_2 = speed2 * Math.sin(direction_2 - collisionision_angle)
let final_xspeed_1 = ((floatingObject1.currentMass - floatingObject2.currentMass) * new_xspeed_1 + (floatingObject2.currentMass + floatingObject2.currentMass) * new_xspeed_2) / (floatingObject1.currentMass + floatingObject2.currentMass)
let final_xspeed_2 = ((floatingObject1.currentMass + floatingObject1.currentMass) * new_xspeed_1 + (floatingObject2.currentMass - floatingObject1.currentMass) * new_xspeed_2) / (floatingObject1.currentMass + floatingObject2.currentMass)
let final_yspeed_1 = new_yspeed_1
let final_yspeed_2 = new_yspeed_2
let cosAngle = Math.cos(collisionision_angle)
let sinAngle = Math.sin(collisionision_angle)
floatingObject1.currentSpeed.x = cosAngle * final_xspeed_1 - sinAngle * final_yspeed_1
floatingObject1.currentSpeed.y = sinAngle * final_xspeed_1 + cosAngle * final_yspeed_1
floatingObject2.currentSpeed.x = cosAngle * final_xspeed_2 - sinAngle * final_yspeed_2
floatingObject2.currentSpeed.y = sinAngle * final_xspeed_2 + cosAngle * final_yspeed_2
let pos1 = {
x: floatingObject1.container.frame.position.x,
y: floatingObject1.container.frame.position.y
}
let pos2 = {
x: floatingObject2.container.frame.position.x,
y: floatingObject2.container.frame.position.y
}
// get the mtd
let posDiff = {
x: pos1.x - pos2.x,
y: pos1.y - pos2.y
}
let d = Math.sqrt(Math.pow(floatingObject2.container.frame.position.x - floatingObject1.container.frame.position.x, 2) + Math.pow(floatingObject2.container.frame.position.y - floatingObject1.container.frame.position.y, 2))
// minimum translation distance to push floatingObjects apart after intersecting
let scalar = (((floatingObject1.container.frame.radius + floatingObject2.container.frame.radius) - d) / d)
let minTD = {
x: posDiff.x * scalar,
y: posDiff.y * scalar
}
// resolve intersection --
// computing inverse mass quantities
let im1 = 1 / floatingObject1.currentMass
let im2 = 1 / floatingObject2.currentMass
// push-pull them apart based off their mass
pos1.x = pos1.x + minTD.x * (im1 / (im1 + im2))
pos1.y = pos1.y + minTD.y * (im1 / (im1 + im2))
pos2.x = pos2.x - minTD.x * (im2 / (im1 + im2))
pos2.y = pos2.y - minTD.y * (im2 / (im1 + im2))
if (floatingObject1.positionLocked === false && isNaN(pos1.x) === false && isNaN(pos1.y) === false) {
floatingObject1.container.frame.position = pos1
}
if (floatingObject2.positionLocked === false && isNaN(pos2.x) === false && isNaN(pos2.y) === false) {
floatingObject2.container.frame.position = pos2
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] resolveCollision -> err= ' + err.stack) }
}
}
}
@@ -0,0 +1,829 @@
function newFloatingObject() {
const MODULE_NAME = 'Floating Object'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
fitFunction: undefined,
container: undefined,
positionLocked: false,
isOnFocus: false,
payload: undefined, // This is a reference to an object controlled by a Plotter. The plotter can change its internal value and we will see them from here.
type: undefined, // Currently there are two types of Floating Objects: Profile Balls, and Notes.
currentSpeed: 0, // This is the current speed of the floating object.
currentMass: 0, // This is the current mass of the floating object, including its zoom applied.
friction: 0, // This is a factor that will ultimatelly desacelerate the floating object.
targetFriction: 0,
rawMass: 0, // This is the mass value without zoom.
rawRadius: 0, // This is the radius of this floating object without zoom.
targetRadius: 0, // This is the target radius of the floating object with zoom applied. It should be animated until reaching this value.
isPinned: false,
isFrozen: false,
angleToParent: undefined,
distanceToParent: undefined,
arrangementStyle: ARRANGEMENT_STYLE.CONCAVE,
isCollapsed: false,
isParentCollapsed: false,
frozenManually: false,
collapsedManually: false,
typeStrokeStyle: undefined,
nameStrokeStyle: undefined,
forceFocus: forceFocus,
removeForceFocus: removeForceFocus,
setFocus: setFocus,
removeFocus: removeFocus,
unCollapseParent: unCollapseParent,
getPinStatus: getPinStatus,
getFreezeStatus: getFreezeStatus,
getCollapseStatus: getCollapseStatus,
getAngleToParent: getAngleToParent,
getDistanceToParent: getDistanceToParent,
getArrangementStyle: getArrangementStyle,
nearbyFloatingObjects: [],
setPosition: setPosition,
pinToggle: pinToggle,
freezeToggle: freezeToggle,
collapseToggle: collapseToggle,
angleToParentToggle: angleToParentToggle,
distanceToParentToggle: distanceToParentToggle,
arrangementStyleToggle: arrangementStyleToggle,
physics: physics,
invisiblePhysics: invisiblePhysics,
initializeMass: initializeMass,
initializeRadius: initializeRadius,
initializeImageSize: initializeImageSize,
initializeFontSize: initializeFontSize,
initializeCurrentPosition: initializeCurrentPosition,
radomizeCurrentSpeed: radomizeCurrentSpeed,
drawBackground: drawBackground,
drawMiddleground: drawMiddleground,
drawForeground: drawForeground,
drawOnFocus: drawOnFocus,
updateMass: updateMass, // Function to update the mass when the zoom level changed.
updateRadius: updateRadius, // Function to update the radius when the zoom level changed.
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME, 'Circle')
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = true
thisObject.container.detectMouseOver = true
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.typeStrokeStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
thisObject.nameStrokeStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
let selfMouseOverEventSubscriptionId
let selfMouseClickEventSubscriptionId
let spaceMouseOverEventSubscriptionId
let spaceFocusAquiredEventSubscriptionId
let lastParentAngle
let forcedFocusCounter = 0
const ON_FOCUS_RADIUS_FACTOR = 6
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(selfMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(selfMouseClickEventSubscriptionId)
UI.projects.superalgos.spaces.floatingSpace.container.eventHandler.stopListening(spaceMouseOverEventSubscriptionId)
UI.projects.superalgos.spaces.floatingSpace.container.eventHandler.stopListening(spaceFocusAquiredEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject.fitFunction = undefined
thisObject.nearbyFloatingObjects = undefined
}
function initialize(type, payload) {
thisObject.payload = payload
thisObject.type = type
selfMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
/* To consider that this object lost the focus, we monitor the space for 2 key events */
spaceMouseOverEventSubscriptionId = UI.projects.superalgos.spaces.floatingSpace.container.eventHandler.listenToEvent('onMouseOver', mouseOverFlotingSpace)
spaceFocusAquiredEventSubscriptionId = UI.projects.superalgos.spaces.floatingSpace.container.eventHandler.listenToEvent('onFocusAquired', someoneAquiredFocus)
/* Assign a position and speed */
thisObject.initializeCurrentPosition(thisObject.payload.targetPosition)
thisObject.radomizeCurrentSpeed()
}
function getContainer(point) {
if (thisObject.payload === undefined) { return }
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === true) { return }
if (UI.projects.superalgos.spaces.floatingSpace.inMapMode === true) { return }
let container
container = thisObject.payload.uiObject.getContainer(point)
if (container !== undefined) { return container }
if (thisObject.container.frame.isThisScreenPointHere(point) === true) {
return thisObject.container
} else {
return undefined
}
}
function getPinStatus() {
return thisObject.isPinned
}
function pinToggle() {
if (thisObject.isPinned !== true) {
thisObject.isPinned = true
thisObject.positionLocked = true
} else {
thisObject.isPinned = false
}
return thisObject.isPinned
}
function getFreezeStatus() {
return thisObject.isFrozen
}
function getCollapseStatus() {
return thisObject.isCollapsed
}
function unCollapseParent() {
if (thisObject.payload !== undefined) {
if (thisObject.payload.parentNode !== undefined) {
if (thisObject.payload.parentNode.payload !== undefined) {
if (thisObject.payload.parentNode.payload.floatingObject !== undefined) {
if (thisObject.payload.parentNode.payload.floatingObject.isCollapsed === true) {
thisObject.payload.parentNode.payload.floatingObject.isCollapsed = false
thisObject.payload.parentNode.payload.floatingObject.collapsedManually = false
thisObject.payload.parentNode.payload.floatingObject.unCollapseParent()
}
}
}
}
}
}
function getAngleToParent() {
return thisObject.angleToParent
}
function getDistanceToParent() {
return thisObject.distanceToParent
}
function getArrangementStyle() {
return thisObject.arrangementStyle
}
function freezeToggle() {
if (thisObject.isFrozen !== true) {
thisObject.isFrozen = true
thisObject.frozenManually = true
} else {
thisObject.isFrozen = false
thisObject.frozenManually = false
}
return thisObject.isFrozen
}
function collapseToggle() {
if (thisObject.isCollapsed !== true) {
thisObject.isCollapsed = true
thisObject.collapsedManually = true
} else {
thisObject.isCollapsed = false
thisObject.collapsedManually = false
}
return thisObject.isCollapsed
}
function angleToParentToggle() {
switch (thisObject.angleToParent) {
case ANGLE_TO_PARENT.NOT_FIXED:
thisObject.angleToParent = ANGLE_TO_PARENT.RANGE_360
break
case ANGLE_TO_PARENT.RANGE_360:
thisObject.angleToParent = ANGLE_TO_PARENT.RANGE_180
break
case ANGLE_TO_PARENT.RANGE_180:
thisObject.angleToParent = ANGLE_TO_PARENT.RANGE_90
break
case ANGLE_TO_PARENT.RANGE_90:
thisObject.angleToParent = ANGLE_TO_PARENT.RANGE_45
break
case ANGLE_TO_PARENT.RANGE_45:
thisObject.angleToParent = ANGLE_TO_PARENT.NOT_FIXED
break
}
return thisObject.angleToParent
}
function distanceToParentToggle() {
switch (thisObject.distanceToParent) {
case DISTANCE_TO_PARENT.NOT_FIXED:
thisObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_025X
break
case DISTANCE_TO_PARENT.PARENT_025X:
thisObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_050X
break
case DISTANCE_TO_PARENT.PARENT_050X:
thisObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
break
case DISTANCE_TO_PARENT.PARENT_100X:
thisObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_150X
break
case DISTANCE_TO_PARENT.PARENT_150X:
thisObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_200X
break
case DISTANCE_TO_PARENT.PARENT_200X:
thisObject.distanceToParent = DISTANCE_TO_PARENT.NOT_FIXED
break
}
return thisObject.distanceToParent
}
function arrangementStyleToggle() {
switch (thisObject.arrangementStyle) {
case ARRANGEMENT_STYLE.CONCAVE:
thisObject.arrangementStyle = ARRANGEMENT_STYLE.CONVEX
break
case ARRANGEMENT_STYLE.CONVEX:
thisObject.arrangementStyle = ARRANGEMENT_STYLE.VERTICAL_RIGHT
break
case ARRANGEMENT_STYLE.VERTICAL_RIGHT:
thisObject.arrangementStyle = ARRANGEMENT_STYLE.VERTICAL_LEFT
break
case ARRANGEMENT_STYLE.VERTICAL_LEFT:
thisObject.arrangementStyle = ARRANGEMENT_STYLE.HORIZONTAL_BOTTOM
break
case ARRANGEMENT_STYLE.HORIZONTAL_BOTTOM:
thisObject.arrangementStyle = ARRANGEMENT_STYLE.HORIZONTAL_TOP
break
case ARRANGEMENT_STYLE.HORIZONTAL_TOP:
thisObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
break
}
return thisObject.arrangementStyle
}
function invisiblePhysics() {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.uiObject === undefined) { return }
if (thisObject.payload.uiObject !== undefined) {
thisObject.payload.uiObject.invisiblePhysics()
}
}
function physics() {
frozenPhysics()
/* From here on, only if they are not too far. */
if (UI.projects.superalgos.spaces.floatingSpace.isItFar(thisObject.payload)) { return }
thisObjectPhysics()
if (thisObject.payload.uiObject !== undefined) {
thisObject.payload.uiObject.physics()
}
positionContraintsPhysics()
focusPhysics()
syncStylePhysics()
}
function syncStylePhysics() {
if (thisObject.rawFontSize !== UI.projects.superalgos.spaces.floatingSpace.style.node.fontSize) {
thisObject.rawFontSize = UI.projects.superalgos.spaces.floatingSpace.style.node.fontSize
thisObject.targetFontSize = thisObject.rawFontSize * 1
}
if (thisObject.rawImageSize !== UI.projects.superalgos.spaces.floatingSpace.style.node.imageSize) {
thisObject.rawImageSize = UI.projects.superalgos.spaces.floatingSpace.style.node.imageSize
thisObject.targetImageSize = thisObject.rawImageSize * 1
}
thisObject.typeStrokeStyle = 'rgba(' + UI.projects.superalgos.spaces.floatingSpace.style.node.type.fontColor + ', 1)'
thisObject.nameStrokeStyle = 'rgba(' + UI.projects.superalgos.spaces.floatingSpace.style.node.name.fontColor + ', 1)'
}
function focusPhysics() {
forcedFocusCounter--
if (forcedFocusCounter < 0) {
forcedFocusCounter = 0
}
}
function frozenPhysics() {
if (thisObject.frozenManually !== false) { return }
if (thisObject.payload === undefined) { return }
let parent = thisObject.payload.chainParent
if (parent !== undefined) {
if (parent.payload !== undefined) {
if (parent.payload.floatingObject !== undefined) {
thisObject.isFrozen = parent.payload.floatingObject.isFrozen
}
}
}
}
function positionContraintsPhysics() {
const MAX_DISTANCE_TO_PARENT = 5000
const MIN_DISTANCE_TO_PARENT = 100
const DEFAULT_NODE_TO_NODE_DISTANCE = 500 * UI.projects.superalgos.spaces.floatingSpace.settings.node.distancePercentage / 100
if (thisObject.angleToParent !== ANGLE_TO_PARENT.NOT_FIXED && thisObject.isOnFocus !== true) {
let parent = thisObject.payload.chainParent
let distanceToParent
let parentChildren
let parentDistanceToGarndParent
if (parent === undefined) {
parentDistanceToGarndParent = DEFAULT_NODE_TO_NODE_DISTANCE
distanceToParent = DEFAULT_NODE_TO_NODE_DISTANCE
parentChildren = 1
} else {
if (parent.payload === undefined) { return }
if (parent.payload.position === undefined) { return }
distanceToParent = Math.sqrt(Math.pow(parent.payload.position.x - thisObject.container.frame.position.x, 2) + Math.pow(parent.payload.position.y - thisObject.container.frame.position.y, 2)) // ... we calculate the distance ...
parentChildren = UI.projects.superalgos.spaces.designSpace.workspace.nodeChildren.childrenCount(parent, thisObject.payload.node)
parentDistanceToGarndParent = parent.payload.distance
}
let axisCount = parentChildren.childrenCount
let axisIndex = parentChildren.childIndex
let baseAngle = 0
let angleToParentAngle
if (parentDistanceToGarndParent !== undefined) {
switch (thisObject.distanceToParent) {
case DISTANCE_TO_PARENT.PARENT_025X:
distanceToParent = parentDistanceToGarndParent / 4
break
case DISTANCE_TO_PARENT.PARENT_050X:
distanceToParent = parentDistanceToGarndParent / 2
break
case DISTANCE_TO_PARENT.PARENT_100X:
distanceToParent = parentDistanceToGarndParent
break
case DISTANCE_TO_PARENT.PARENT_150X:
distanceToParent = parentDistanceToGarndParent * 1.5
break
case DISTANCE_TO_PARENT.PARENT_200X:
distanceToParent = parentDistanceToGarndParent * 2
break
}
}
if (distanceToParent > MAX_DISTANCE_TO_PARENT) {
distanceToParent = MAX_DISTANCE_TO_PARENT
}
if (distanceToParent < MIN_DISTANCE_TO_PARENT) {
distanceToParent = MIN_DISTANCE_TO_PARENT
}
switch (thisObject.angleToParent) {
case ANGLE_TO_PARENT.RANGE_360:
angleToParentAngle = 360
break
case ANGLE_TO_PARENT.RANGE_180:
angleToParentAngle = 180
break
case ANGLE_TO_PARENT.RANGE_90:
angleToParentAngle = 90
break
case ANGLE_TO_PARENT.RANGE_45:
angleToParentAngle = 45
break
}
if (axisIndex === undefined) {
axisCount = 1
axisIndex = axisCount
}
if (parent !== undefined) {
if (parent.payload.chainParent !== undefined && parent.payload.angle !== undefined) {
axisCount++
axisIndex++
baseAngle = parent.payload.angle + 180
lastParentAngle = parent.payload.angle
} else {
if (lastParentAngle !== undefined) {
axisCount++
axisIndex++
baseAngle = lastParentAngle + 180
}
}
}
let separatorAngle = (360 - angleToParentAngle) / 2
let angleStep = angleToParentAngle / axisCount
thisObject.payload.angle = baseAngle + separatorAngle + (axisIndex - 1) * angleStep
if (thisObject.payload.angle >= 360) {
thisObject.payload.angle = thisObject.payload.angle - 360
}
thisObject.payload.distance = distanceToParent
if (thisObject.isPinned === true) {
/* When an object is pinned, its angle to its parent needs to be calculated since it depends on where the user places the node. */
/*
if (thisObject.payload.chainParent !== undefined) {
let x = thisObject.container.frame.position.x - thisObject.payload.chainParent.payload.floatingObject.container.frame.position.x
let y = thisObject.container.frame.position.y - thisObject.payload.chainParent.payload.floatingObject.container.frame.position.y
thisObject.payload.angle = Math.atan(y / x)
}
*/
return
}
let newPosition
if (parent !== undefined) {
newPosition = {
x: parent.payload.position.x,
y: parent.payload.position.y
}
} else {
return
}
let displacement
switch (thisObject.arrangementStyle) {
case ARRANGEMENT_STYLE.CONCAVE: {
displacement = {
x: distanceToParent * Math.cos(toRadians(thisObject.payload.angle)),
y: distanceToParent * Math.sin(toRadians(thisObject.payload.angle))
}
break
}
case ARRANGEMENT_STYLE.CONVEX: {
displacement = {
x: 2 * distanceToParent * Math.cos(toRadians(lastParentAngle)) + distanceToParent * Math.cos(toRadians(thisObject.payload.angle + 180)),
y: 2 * distanceToParent * Math.sin(toRadians(lastParentAngle)) + distanceToParent * Math.sin(toRadians(thisObject.payload.angle + 180))
}
break
}
case ARRANGEMENT_STYLE.HORIZONTAL_BOTTOM: {
displacement = {
x: distanceToParent * Math.tan(toRadians(thisObject.payload.angle)),
y: distanceToParent
}
break
}
case ARRANGEMENT_STYLE.HORIZONTAL_TOP: {
displacement = {
x: -distanceToParent * Math.tan(toRadians(thisObject.payload.angle)),
y: -distanceToParent
}
break
}
case ARRANGEMENT_STYLE.VERTICAL_RIGHT: {
displacement = {
x: distanceToParent,
y: distanceToParent * Math.tan(toRadians(thisObject.payload.angle))
}
break
}
case ARRANGEMENT_STYLE.VERTICAL_LEFT: {
displacement = {
x: -distanceToParent,
y: -distanceToParent * Math.tan(toRadians(thisObject.payload.angle))
}
break
}
}
if (displacement.x > MAX_DISTANCE_TO_PARENT) {
displacement.x = MAX_DISTANCE_TO_PARENT
}
if (displacement.y > MAX_DISTANCE_TO_PARENT) {
displacement.y = MAX_DISTANCE_TO_PARENT
}
newPosition.x = newPosition.x + displacement.x
newPosition.y = newPosition.y + displacement.y
if (isNaN(newPosition.x) === false) {
thisObject.container.frame.position.x = newPosition.x
}
if (isNaN(newPosition.y) === false) {
thisObject.container.frame.position.y = newPosition.y
}
}
}
function thisObjectPhysics() {
const ANIMATION_STEPS = UI.projects.superalgos.spaces.floatingSpace.settings.node.animationSteps
imageSizePhysics()
fontSizePhysics()
radiusPhysics()
/* Floating object position in screen coordinates */
thisObject.payload.position.x = thisObject.container.frame.position.x
thisObject.payload.position.y = thisObject.container.frame.position.y
function imageSizePhysics() {
// The imageSize also have a target.
let imageSizeStep = (thisObject.targetImageSize - thisObject.currentImageSize) / ANIMATION_STEPS
thisObject.currentImageSize = thisObject.currentImageSize + imageSizeStep
if (thisObject.isOnFocus === true) {
if (thisObject.currentImageSize > thisObject.targetImageSize) {
thisObject.currentImageSize = thisObject.targetImageSize
}
} else {
if (thisObject.currentImageSize < thisObject.targetImageSize) {
thisObject.currentImageSize = thisObject.targetImageSize
}
}
}
function fontSizePhysics() {
// The fontSize also have a target.
let fontSizeStep = (thisObject.targetFontSize - thisObject.currentFontSize) / ANIMATION_STEPS
thisObject.currentFontSize = thisObject.currentFontSize + fontSizeStep
if (thisObject.isOnFocus === true) {
if (thisObject.currentFontSize > thisObject.targetFontSize) {
thisObject.currentFontSize = thisObject.targetFontSize
}
} else {
if (thisObject.currentFontSize < thisObject.targetFontSize) {
thisObject.currentFontSize = thisObject.targetFontSize
}
}
}
function radiusPhysics() {
let animationStepSize
if (thisObject.isOnFocus === true) {
animationStepSize = (targetRadiusWithFocus() - targetRadiusWithoutFocus()) / ANIMATION_STEPS
if (thisObject.container.frame.radius >= targetRadiusWithFocus()) { return }
thisObject.container.frame.radius = thisObject.container.frame.radius + animationStepSize
if (thisObject.container.frame.radius >= targetRadiusWithFocus()) {
thisObject.container.frame.radius = targetRadiusWithFocus()
}
thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event)
} else {
animationStepSize = (targetRadiusWithoutFocus() - targetRadiusWithFocus()) / ANIMATION_STEPS
if (thisObject.container.frame.radius <= targetRadiusWithoutFocus()) { return }
thisObject.container.frame.radius = thisObject.container.frame.radius + animationStepSize
if (thisObject.container.frame.radius <= targetRadiusWithoutFocus()) {
thisObject.container.frame.radius = targetRadiusWithoutFocus()
}
thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event)
}
}
}
function onMouseOver(point) {
if (thisObject.isOnFocus === false) {
setFocus(point)
}
}
function mouseOverFlotingSpace(point) {
removeFocus()
}
function someoneAquiredFocus(floatingObject) {
if (floatingObject === undefined || floatingObject.container === undefined) {
return
}
if (thisObject.container === undefined) {
return
}
if (floatingObject.container.id !== thisObject.container.id) {
removeFocus()
}
}
function forceFocus() {
forcedFocusCounter = 10
setFocus()
}
function removeForceFocus() {
forcedFocusCounter = 0
removeFocus()
}
function targetRadiusWithFocus() {
return thisObject.rawRadius * ON_FOCUS_RADIUS_FACTOR * UI.projects.superalgos.spaces.floatingSpace.settings.node.radiusPercentage / 100
}
function targetRadiusWithoutFocus() {
return thisObject.rawRadius * 1 * UI.projects.superalgos.spaces.floatingSpace.settings.node.radiusPercentage / 100
}
function setFocus(point) {
thisObject.targetRadius = targetRadiusWithFocus()
thisObject.currentMass = thisObject.rawMass * UI.projects.superalgos.spaces.floatingSpace.settings.node.massPercentage / 100
thisObject.targetImageSize = thisObject.rawImageSize * 2.0
thisObject.targetFontSize = thisObject.rawFontSize * 2.0
thisObject.payload.uiObject.container.eventHandler.raiseEvent('onFocus', point)
thisObject.positionLocked = true
UI.projects.superalgos.spaces.floatingSpace.container.eventHandler.raiseEvent('onFocusAquired', thisObject)
thisObject.isOnFocus = true
}
function removeFocus() {
if (forcedFocusCounter > 0) {
return
}
if (thisObject.payload === undefined) { return }
if (thisObject.isOnFocus === true) {
thisObject.targetRadius = targetRadiusWithoutFocus()
thisObject.currentMass = thisObject.rawMass * UI.projects.superalgos.spaces.floatingSpace.settings.node.massPercentage / 100
thisObject.targetImageSize = thisObject.rawImageSize * 1
thisObject.targetFontSize = thisObject.rawFontSize * 1
thisObject.payload.uiObject.container.eventHandler.raiseEvent('onNotFocus', thisObject.container)
if (thisObject.isPinned !== true) {
thisObject.positionLocked = false
}
thisObject.isOnFocus = false
}
}
function onMouseClick(pPoint) {
let event = {
point: pPoint,
parent: thisObject
}
thisObject.payload.uiObject.container.eventHandler.raiseEvent('onMouseClick', event)
}
function drawBackground() {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.uiObject === undefined) { return }
if (UI.projects.superalgos.spaces.floatingSpace.isItFar(thisObject.payload) && thisObject.payload.uiObject.isShowing === false) { return }
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === true) {
if (thisObject.payload.uiObject.isShowing !== true) {
return
}
}
thisObject.payload.uiObject.drawBackground()
}
function drawMiddleground() {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.uiObject === undefined) { return }
if (UI.projects.superalgos.spaces.floatingSpace.isItFar(thisObject.payload) && thisObject.payload.uiObject.isShowing === false) { return }
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === true) {
if (thisObject.payload.uiObject.isShowing !== true) {
return
}
}
thisObject.payload.uiObject.drawMiddleground()
}
function drawForeground() {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.uiObject === undefined) { return }
if (UI.projects.superalgos.spaces.floatingSpace.isItFar(thisObject.payload) && thisObject.payload.uiObject.isShowing === false) { return }
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === true) {
if (thisObject.payload.uiObject.isShowing !== true) {
return
}
}
thisObject.payload.uiObject.drawForeground()
}
function drawOnFocus() {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.uiObject === undefined) { return }
thisObject.payload.uiObject.drawOnFocus()
}
function initializeMass(suggestedValue) {
let mass = suggestedValue
if (mass < 0.1) {
mass = 0.1
}
thisObject.rawMass = mass
thisObject.currentMass = mass
}
function initializeRadius(suggestedValue) {
let radius = suggestedValue
if (radius < 2) {
radius = 2
}
thisObject.rawRadius = radius
thisObject.targetRadius = radius * UI.projects.superalgos.spaces.floatingSpace.settings.node.radiusPercentage / 100
thisObject.container.frame.radius = radius
thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event)
}
function initializeImageSize(suggestedValue) {
let size = suggestedValue
if (size < 2) {
size = 2
}
thisObject.rawImageSize = size
thisObject.targetImageSize = size
thisObject.currentImageSize = size / 3
}
function initializeFontSize(suggestedValue) {
let size = suggestedValue
if (size < 3) {
size = 3
}
thisObject.rawFontSize = size
thisObject.targetFontSize = size
thisObject.currentFontSize = size / 3
}
function initializeCurrentPosition(arroundPoint) {
let position = {}
if (thisObject.payload.position === undefined) {
position = {
x: Math.floor((Math.random() * (200) - 100)) + arroundPoint.x,
y: Math.floor((Math.random() * (200) - 100)) + arroundPoint.y
}
} else {
position = {
x: thisObject.payload.position.x,
y: thisObject.payload.position.y
}
}
setPosition(position)
}
function setPosition(position) {
thisObject.container.frame.position.x = position.x
thisObject.container.frame.position.y = position.y
thisObject.payload.position = {}
thisObject.payload.position.x = position.x
thisObject.payload.position.y = position.y
}
function radomizeCurrentSpeed() {
var initialXDirection
var randomX = Math.floor((Math.random() * 10) + 1)
if (randomX > 5) {
initialXDirection = 1
} else {
initialXDirection = -1
}
var initialYDirection
var randomY = Math.floor((Math.random() * 10) + 1)
if (randomY > 5) {
initialYDirection = 1
} else {
initialYDirection = -1
}
var velocity = {
x: initialXDirection * Math.floor((Math.random() * 300) + 1) / 100,
y: initialYDirection * Math.floor((Math.random() * 300) + 1) / 100
}
thisObject.currentSpeed = velocity
}
function updateMass() {
}
function updateRadius() {
}
}
@@ -0,0 +1,574 @@
function newSuperalgosFloatingSpace() {
const MODULE_NAME = 'Floating Space'
const ERROR_LOG = true
/*
The Floating Space is the place where floating elements like floatingObjects, live and are rendered.
This space has its own physics which helps with the animation of these objects and also preventing them to overlap.
*/
let thisObject = {
floatingLayer: undefined, // This is the array of floatingObjects being displayed
uiObjectConstructor: undefined,
container: undefined,
inMapMode: false,
drawReferenceLines: false,
drawChainLines: true,
style: undefined,
settings: undefined,
toggleDrawChainLines: toggleDrawChainLines,
toggleDrawReferenceLines: toggleDrawReferenceLines,
toggleMapMode: toggleMapMode,
enterMapMode: enterMapMode,
exitMapMode: exitMapMode,
transformPointToMap: transformPointToMap,
transformRadiusToMap: transformRadiusToMap,
transformImagesizeToMap: transformImagesizeToMap,
oneScreenUp: oneScreenUp,
oneScreenDown: oneScreenDown,
oneScreenLeft: oneScreenLeft,
oneScreenRight: oneScreenRight,
positionAtNode: positionAtNode,
fitIntoVisibleArea: fitIntoVisibleArea,
isThisPointVisible: isThisPointVisible,
isItFar: isItFar,
makeVisible: makeVisible,
makeInvisible: makeInvisible,
draw: draw,
physics: physics,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = true
thisObject.container.isWheelable = true
thisObject.container.detectMouseOver = true
thisObject.container.isClickeable = false
thisObject.container.frame.radius = 0
let devicePixelRatio = window.devicePixelRatio
const SPACE_SIZE = 50000
thisObject.container.frame.width = SPACE_SIZE
thisObject.container.frame.height = SPACE_SIZE
thisObject.container.frame.position.x = browserCanvas.width / 2 - thisObject.container.frame.width / 2
thisObject.container.frame.position.y = browserCanvas.height / 2 - thisObject.container.frame.height / 2
let visible = false
let floatingObjetOnFocus
const PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT = 25
let onDragStartedEventSubscriptionId
let spaceFocusAquiredEventSubscriptionId
/* Default Style */
thisObject.style = {
backgroundColor: UI_COLOR.BLACK,
node: {
imageSize: 96,
fontSize: 18,
type: {
fontColor: UI_COLOR.WHITE
},
name: {
fontColor: UI_COLOR.WHITE
},
menuItem: {
backgroundColor: UI_COLOR.BLACK,
fontColor: UI_COLOR.WHITE,
fontSize: 15,
imageSize: 50
}
}
}
/* Default Settings */
thisObject.settings = {
node: {
distancePercentage: 100,
radiusPercentage: 100,
massPercentage: 100,
animationSteps: 2,
menuItem: {
widthPercentage: 100,
heightPercentage: 100,
radiusPercentage: 100
}
},
physics: true,
}
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onDragStartedEventSubscriptionId)
UI.projects.superalgos.spaces.floatingSpace.container.eventHandler.stopListening(spaceFocusAquiredEventSubscriptionId)
thisObject.floatingLayer.finalize()
thisObject.uiObjectConstructor.finalize()
thisObject.container.finalize()
thisObject.floatingLayer = undefined
thisObject.uiObjectConstructor = undefined
thisObject.container = undefined
floatingObjetOnFocus = undefined
}
function initialize(callBackFunction) {
thisObject.floatingLayer = newFloatingLayer()
thisObject.floatingLayer.initialize()
thisObject.uiObjectConstructor = newUiObjectConstructor()
thisObject.uiObjectConstructor.initialize(thisObject.floatingLayer)
onDragStartedEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onDragStarted', onDragStarted)
spaceFocusAquiredEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onFocusAquired', someoneAquiredFocus)
}
function someoneAquiredFocus(floatingObject) {
if (floatingObject === undefined || floatingObject.container === undefined) {
return
}
floatingObjetOnFocus = floatingObject
}
function toggleDrawReferenceLines() {
if (thisObject.drawReferenceLines === true) {
thisObject.drawReferenceLines = false
} else {
thisObject.drawReferenceLines = true
}
}
function toggleDrawChainLines() {
if (thisObject.drawChainLines === true) {
thisObject.drawChainLines = false
} else {
thisObject.drawChainLines = true
}
}
function transformPointToMap(point) {
let returnPoint = {
x: point.x - thisObject.container.frame.position.x,
y: point.y - thisObject.container.frame.position.y
}
returnPoint.x = returnPoint.x / SPACE_SIZE * browserCanvas.width
returnPoint.y = returnPoint.y / SPACE_SIZE * browserCanvas.height
return returnPoint
}
function transformRadiusToMap(radius) {
const RADIUS_REDUCTION_FACTOR = 2
return radius / RADIUS_REDUCTION_FACTOR
}
function transformImagesizeToMap(imageSize) {
const IMAGE_REDUCTION_FACTOR = 3
return imageSize / IMAGE_REDUCTION_FACTOR
}
function enterMapMode() {
thisObject.inMapMode = true
}
function exitMapMode() {
thisObject.inMapMode = false
}
function toggleMapMode() {
if (thisObject.inMapMode === false) {
enterMapMode()
} else {
exitMapMode()
}
}
function onDragStarted(event) {
if (thisObject.inMapMode === false) {
if (event.buttons !== 2) { return }
event.candelDragging = true
enterMapMode()
} else {
if (event.buttons !== 1) {
event.candelDragging = true
return
}
let mousePosition = {
x: event.x,
y: event.y
}
let mouseAtSpace = {
x: mousePosition.x / browserCanvas.width * SPACE_SIZE,
y: mousePosition.y / browserCanvas.height * SPACE_SIZE
}
/* Let's see if we can snap to some of the root nodes that are Hierarchy Head and Project Heads */
let snapCandidateNodes = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeads()
snapCandidateNodes = snapCandidateNodes.concat(UI.projects.superalgos.spaces.designSpace.workspace.getProjectsHeads())
for (let i = 0; i < snapCandidateNodes.length; i++) {
let node = snapCandidateNodes[i]
let nodePosition = {
x: node.payload.floatingObject.container.frame.position.x,
y: node.payload.floatingObject.container.frame.position.y
}
// nodePosition = node.payload.floatingObject.container.frame.frameThisPoint(nodePosition)
let distance = Math.sqrt(Math.pow(mouseAtSpace.x - nodePosition.x, 2) + Math.pow(mouseAtSpace.y - nodePosition.y, 2))
const SNAP_THREASHOLD = 1000
if (distance < SNAP_THREASHOLD) {
mousePosition.x = nodePosition.x / SPACE_SIZE * browserCanvas.width
mousePosition.y = nodePosition.y / SPACE_SIZE * browserCanvas.height
}
}
/* Movign the Floating Space to where the mouse is. */
thisObject.container.frame.position.x = -mousePosition.x / browserCanvas.width * SPACE_SIZE + browserCanvas.width / 2
thisObject.container.frame.position.y = -mousePosition.y / browserCanvas.height * SPACE_SIZE + browserCanvas.height / 2
exitMapMode()
}
}
function isItFar(payload, dontCheckParent) {
/* If for any reason the paylaod is undefined we return false */
if (payload === undefined) { return false }
if (thisObject.inMapMode === true) { return false }
let radarFactor = 2 // How big is the margin
/* If the chain parent is not far, they we dont consither this far. */
if (dontCheckParent !== true) {
if (payload.chainParent !== undefined) {
if (isItFar(payload.chainParent.payload, true) === false) { return false }
}
}
/* Exceptions that are never considered far. */
if (
payload.node.type === 'Trading System' ||
payload.node.type === 'Network' ||
payload.node.type === 'Crypto Ecosystem' ||
payload.node.type === 'Charting Space' ||
payload.node.type === 'Data Mine' ||
payload.node.type === 'Super Scripts'
) {
return false
}
/* Another exception are the ones who have reference parents */
if (payload.referenceParent !== undefined) { return false }
/* Here we will check the position of a floatingobject to see if it is outside the screen, with a margin of one screen around. */
let point = thisObject.container.frame.frameThisPoint(payload.position)
if (point.x > browserCanvas.width + browserCanvas.width * radarFactor) {
return true
}
if (point.x < 0 - browserCanvas.width * radarFactor) {
return true
}
let bottom = COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT
let heightDiff = browserCanvas.height - bottom
if (point.y < bottom - heightDiff * radarFactor) {
return true
}
if (point.y > browserCanvas.height + heightDiff * radarFactor) {
return true
}
return false
}
function fitIntoVisibleArea(point) {
/* Here we check the boundaries of the resulting points, so they dont go out of the visible area. */
let returnPoint = {
x: point.x,
y: point.y
}
if (point.x > browserCanvas.width) {
returnPoint.x = browserCanvas.width
}
if (point.x < 0) {
returnPoint.x = 0
}
if (point.y < COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT) {
returnPoint.y = COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT
}
if (point.y > browserCanvas.height) {
returnPoint.y = browserCanvas.height
}
return returnPoint
}
function oneScreenUp() {
if (visible === false) { return }
let displaceVector = {
x: 0,
y: browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
thisObject.container.displace(displaceVector)
return displaceVector
}
function oneScreenDown() {
if (visible === false) { return }
let displaceVector = {
x: 0,
y: -browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
thisObject.container.displace(displaceVector)
return displaceVector
}
function oneScreenLeft() {
if (visible === false) { return }
let displaceVector = {
x: browserCanvas.width * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100,
y: 0
}
thisObject.container.displace(displaceVector)
return displaceVector
}
function oneScreenRight() {
if (visible === false) { return }
let displaceVector = {
x: -browserCanvas.width * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100,
y: 0
}
thisObject.container.displace(displaceVector)
return displaceVector
}
function positionAtNode(node) {
let position = thisObject.container.frame.frameThisPoint(node.payload.position)
let displaceVector = {
x: browserCanvas.width / 2 - position.x,
y: (COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT) + (browserCanvas.height - (COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT)) / 2 - position.y
}
thisObject.container.displace(displaceVector)
}
function isThisPointVisible(point) {
if (point.x > browserCanvas.width) {
return false
}
if (point.x < 0) {
return false
}
if (point.y < COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT) {
return false
}
if (point.y > browserCanvas.height) {
return false
}
return true
}
function makeVisible() {
visible = true
}
function makeInvisible() {
visible = false
}
function getContainer(point) {
if (visible === false) { return }
let container
if (floatingObjetOnFocus !== undefined) {
container = floatingObjetOnFocus.getContainer(point)
if (container !== undefined) {
container.space = 'Floating Space'
return container
}
}
container = thisObject.floatingLayer.getContainer(point)
if (container !== undefined) {
container.space = 'Floating Space'
return container
}
if (visible === true) {
thisObject.container.space = 'Floating Space'
return thisObject.container
}
}
function physics() {
if (visible === false) { return }
syncStylePhysics()
syncSettingsPhysics()
browserZoomPhysics()
positionContraintsPhysics()
thisObject.floatingLayer.physics()
}
function syncStylePhysics() {
if (UI.projects.superalgos.spaces.designSpace === undefined) { return }
if (UI.projects.superalgos.spaces.designSpace.workspace === undefined) { return }
let designSpaceNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsByType('Design Space')
if (designSpaceNode === undefined) { return }
if (designSpaceNode.spaceStyle === undefined) { return }
let configStyle
try {
configStyle = JSON.parse(designSpaceNode.spaceStyle.config)
} catch (err) {
if (thisObject.payload !== undefined) {
thisObject.payload.uiObject.setErrorMessage(err.message)
}
return
}
if (configStyle.backgroundColor !== undefined) {
thisObject.style.backgroundColor = eval(configStyle.backgroundColor)
}
if (configStyle.node !== undefined) {
if (configStyle.node.fontSize !== undefined) {
thisObject.style.node.fontSize = configStyle.node.fontSize
}
if (configStyle.node.imageSize !== undefined) {
thisObject.style.node.imageSize = configStyle.node.imageSize
}
if (configStyle.node.name !== undefined) {
if (configStyle.node.name.fontColor !== undefined) {
thisObject.style.node.name.fontColor = eval(configStyle.node.name.fontColor)
}
}
if (configStyle.node.type !== undefined) {
if (configStyle.node.type.fontColor !== undefined) {
thisObject.style.node.type.fontColor = eval(configStyle.node.type.fontColor)
}
}
if (configStyle.node.menuItem !== undefined) {
if (configStyle.node.menuItem.fontColor !== undefined) {
thisObject.style.node.menuItem.fontColor = eval(configStyle.node.menuItem.fontColor)
}
if (configStyle.node.menuItem.backgroundColor !== undefined) {
thisObject.style.node.menuItem.backgroundColor = eval(configStyle.node.menuItem.backgroundColor)
}
if (configStyle.node.menuItem.fontSize !== undefined) {
thisObject.style.node.menuItem.fontSize = configStyle.node.menuItem.fontSize
}
if (configStyle.node.menuItem.imageSize !== undefined) {
thisObject.style.node.menuItem.imageSize = configStyle.node.menuItem.imageSize
}
}
}
}
function syncSettingsPhysics() {
if (UI.projects.superalgos.spaces.designSpace === undefined) { return }
if (UI.projects.superalgos.spaces.designSpace.workspace === undefined) { return }
let designSpaceNode = UI.projects.superalgos.spaces.designSpace.workspace.getHierarchyHeadsByType('Design Space')
if (designSpaceNode === undefined) { return }
if (designSpaceNode.spaceSettings === undefined) { return }
let configSettings
try {
configSettings = JSON.parse(designSpaceNode.spaceSettings.config)
} catch (err) {
if (thisObject.payload !== undefined) {
thisObject.payload.uiObject.setErrorMessage(err.message)
}
return
}
if (configSettings.node !== undefined) {
if (configSettings.node.distancePercentage !== undefined) {
thisObject.settings.node.distancePercentage = configSettings.node.distancePercentage
}
if (configSettings.node.radiusPercentage !== undefined) {
thisObject.settings.node.radiusPercentage = configSettings.node.radiusPercentage
}
if (configSettings.node.massPercentage !== undefined) {
thisObject.settings.node.massPercentage = configSettings.node.massPercentage
}
if (configSettings.node.animationSteps !== undefined) {
thisObject.settings.node.animationSteps = configSettings.node.animationSteps
}
if (configSettings.node.menuItem !== undefined) {
if (configSettings.node.menuItem.widthPercentage !== undefined) {
thisObject.settings.node.menuItem.widthPercentage = configSettings.node.menuItem.widthPercentage
}
if (configSettings.node.menuItem.heightPercentage !== undefined) {
thisObject.settings.node.menuItem.heightPercentage = configSettings.node.menuItem.heightPercentage
}
if (configSettings.node.menuItem.radiusPercentage !== undefined) {
thisObject.settings.node.menuItem.radiusPercentage = configSettings.node.menuItem.radiusPercentage
}
}
}
if (configSettings.physics !== undefined) {
thisObject.settings.physics = configSettings.physics
}
}
function positionContraintsPhysics() {
if (thisObject.container.frame.position.x > 0) {
thisObject.container.frame.position.x = 0
}
if (thisObject.container.frame.position.y > 0) {
thisObject.container.frame.position.y = 0
}
if (thisObject.container.frame.position.x + thisObject.container.frame.width < browserCanvas.width) {
thisObject.container.frame.position.x = browserCanvas.width - thisObject.container.frame.width
}
if (thisObject.container.frame.position.y + thisObject.container.frame.height < browserCanvas.height) {
thisObject.container.frame.position.y = browserCanvas.height - thisObject.container.frame.height
}
}
function browserZoomPhysics() {
if (devicePixelRatio !== window.devicePixelRatio) {
devicePixelRatio = window.devicePixelRatio
thisObject.container.frame.position.x = browserCanvas.width / 2 - thisObject.container.frame.width / 2
thisObject.container.frame.position.y = browserCanvas.height / 2 - thisObject.container.frame.height / 2
}
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
if (visible === false) { return }
drawBackground()
thisObject.floatingLayer.draw()
}
function drawBackground() {
browserCanvasContext.beginPath()
browserCanvasContext.rect(thisObject.container.frame.position.x, thisObject.container.frame.position.y, thisObject.container.frame.width, thisObject.container.frame.height)
browserCanvasContext.fillStyle = 'rgba(' + thisObject.style.backgroundColor + ', 1)'
browserCanvasContext.closePath()
browserCanvasContext.fill()
}
}
@@ -0,0 +1,199 @@
function newFormulaEditor() {
const MODULE_NAME = 'Formula Editor'
let thisObject = {
isVisibleFunction: undefined,
visible: false,
imagePathOK: undefined,
imagePathNOT_OK: undefined,
rawRadius: undefined,
targetRadius: undefined,
currentRadius: undefined,
container: undefined,
payload: undefined,
deactivate: deactivate,
activate: activate,
physics: physics,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = false
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
let isMouseOver = false
let SIZE_FACTOR = 1.0
return thisObject
function finalize() {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
}
function initialize() {
}
function deactivate() {
if (thisObject.visible === true) {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.code = textArea.value
}
EDITOR_ON_FOCUS = false
}
function activate(action) {
thisObject.visible = true
thisObject.payload = action.node.payload
thisObject.rawRadius = 8
thisObject.targetRadius = thisObject.container.frame.radius
thisObject.currentRadius = 0
thisObject.payload.uiObject.resetErrorMessage()
let textArea = document.getElementById('textArea')
textArea.value = thisObject.payload.node.code
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + UI_FONT.PRIMARY + ';' +
'font-size: 14px;' +
'background-color: rgb(' + UI_COLOR.MANGANESE_PURPLE + ');' +
'color:rgb(255, 255, 255);' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
textArea.style.display = 'block'
textArea.focus()
EDITOR_ON_FOCUS = true
}
function getContainer(point) {
let container
if (thisObject.visible === true) {
if (point.x === VERY_LARGE_NUMBER) {
/* The the mouse leaves the canvas, and event of mouse over with a ridiculous coordinate is triggered so that
anyone can react. In our case, the code editor has a text area that is not part of the canvas, so the event is
triggered. We compensate recognizing this coordinate and returning our container. */
return thisObject.container
}
if (thisObject.container.frame.isThisPointHere(point, true, false) === true) {
return thisObject.container
} else {
return undefined
}
}
}
function physics() {
if (Math.abs(thisObject.currentRadius - thisObject.targetRadius) >= 0.5) {
if (thisObject.currentRadius < thisObject.targetRadius) {
thisObject.currentRadius = thisObject.currentRadius + 0.5
} else {
thisObject.currentRadius = thisObject.currentRadius - 0.5
}
}
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.container.frame.width = thisObject.container.frame.radius * 1 * SIZE_FACTOR
thisObject.container.frame.height = thisObject.container.frame.radius * 1 * SIZE_FACTOR
let textAreaPosition = {
x: 0 - thisObject.container.frame.width / 2,
y: 0 - thisObject.container.frame.height * 3 / 7 + CURRENT_TOP_MARGIN
}
textAreaPosition = thisObject.container.frame.frameThisPoint(textAreaPosition)
if (thisObject.visible === true) {
let checkPosition = {
x: textAreaPosition.x,
y: textAreaPosition.y - CURRENT_TOP_MARGIN
}
if (thisObject.isVisibleFunction(checkPosition) === false) {
deactivate()
}
}
if (thisObject.visible === true) {
let textAreaDiv = document.getElementById('textAreaDiv')
textAreaDiv.style = 'position:fixed; top:' + textAreaPosition.y + 'px; left:' + textAreaPosition.x + 'px; z-index:1; '
}
}
function drawBackground() {
if (thisObject.visible === true) {
let position = {
x: 0,
y: 0
}
position = thisObject.container.frame.frameThisPoint(position)
let radius = thisObject.container.frame.radius * SIZE_FACTOR
if (radius > 0.5) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius + 3, 0, Math.PI * 2, true)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + 1 + ')'
browserCanvasContext.fill()
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius , 0, Math.PI * 2, true)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', ' + 1 + ')'
browserCanvasContext.fill()
}
}
}
function drawForeground() {
let iconPosition = {
x: 0,
y: thisObject.currentRadius * 1.5
}
iconPosition = thisObject.container.frame.frameThisPoint(iconPosition)
/* Menu Item */
if (thisObject.canDrawIcon === true && thisObject.currentRadius > 1) {
browserCanvasContext.drawImage(thisObject.icon, iconPosition.x - thisObject.currentRadius, iconPosition.y - thisObject.currentRadius, thisObject.currentRadius * 2, thisObject.currentRadius * 2)
/* Menu Label */
let label = 'Code looks good!'
let labelPoint
let fontSize = 10
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
if (thisObject.currentRadius >= thisObject.targetRadius) {
labelPoint = {
x: iconPosition.x + thisObject.currentRadius + 10,
y: iconPosition.y + fontSize * FONT_ASPECT_RATIO
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
}
}
}
@@ -0,0 +1,216 @@
function newPicker() {
const MODULE_NAME = 'Picker'
let thisObject = {
container: undefined,
selectedItem: 0,
onParentChanged: onParentChanged,
getSelected: getSelected,
setSelected: setSelected,
physics: physics,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = false
thisObject.container.isWheelable = true
thisObject.container.detectMouseOver = true
thisObject.container.frame.radius = 0
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.container.frame.width = 150
thisObject.container.frame.height = 60
let isMouseOver
let optionsList
let parent
let current
let parentSelected = 0
let propertyName
let selected = 0
let lastSelected = 0
let onMouseWheelEventSubscriptionId
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
optionsList = undefined
parent = undefined
current = undefined
}
function initialize(pOptionsList, pCurrent, pParent, pPropertyName) {
optionsList = pOptionsList
current = pCurrent
parent = pParent
propertyName = pPropertyName
onMouseWheelEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
onMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
}
function onMouseOver(event) {
isMouseOver = true
}
function onMouseNotOver() {
isMouseOver = false
}
function setSelected(pOptionsList, pCurrent, pParent, pSelected) {
if (pOptionsList !== undefined) {
optionsList = pOptionsList
}
if (pCurrent !== undefined) {
current = pCurrent
}
if (pParent !== undefined) {
parent = pParent
}
if (pSelected !== undefined) {
selected = pSelected
}
raiseEventParentChanged()
}
function onParentChanged(event) {
if (event.parent !== undefined) {
parent = event.parent
}
parentSelected = event.selected
selected = 0
let parentKeys
parentKeys = Object.keys(parent)
checkPropertyName()
function checkPropertyName() {
if (propertyName === undefined) {
current = parent[parentKeys[parentSelected]]
checkArray()
} else {
current = parent[parentKeys[parentSelected]]
current = current[propertyName]
checkArray()
}
}
function checkArray() {
if (Array.isArray(current) === false) {
optionsList = Object.keys(current)
} else {
optionsList = current
}
}
raiseEventParentChanged()
}
function getContainer(point) {
let container
if (thisObject.container.frame.isThisPointHere(point, true, false) === true) {
return thisObject.container
}
}
function getSelected() {
return optionsList[selected]
}
function onMouseWheel() {
delta = event.wheelDelta
if (delta > 0) {
delta = -1
} else {
delta = 1
}
selected = selected + delta
if (selected < 0) { selected = 0 }
if (selected > optionsList.length - 1) {
selected = optionsList.length - 1
}
if (selected !== lastSelected) {
lastSelected = selected
raiseEventParentChanged()
}
}
function raiseEventParentChanged() {
let event = {
selected: selected,
parent: current,
propertyName: propertyName
}
thisObject.container.eventHandler.raiseEvent('onParentChanged', event)
}
function physics() {
}
function drawBackground() {
}
function drawForeground() {
const FONT_SIZE = 15
const VISIBLE_LABELS = 5
let fontSize
let fontColor
let opacity
for (let i = 0; i < VISIBLE_LABELS; i++) {
let index = i - 2 + selected
let label = ''
if (index >= 0 && index < optionsList.length) {
label = optionsList[index]
}
fontColor = UI_COLOR.LIGHT_GREY
switch (i) {
case 0:
fontSize = FONT_SIZE - 5
opacity = 0.4
break
case 1:
fontSize = FONT_SIZE - 3
opacity = 0.5
break
case 2:
fontSize = FONT_SIZE - 0
fontColor = UI_COLOR.BLACK
opacity = 1
break
case 3:
fontSize = FONT_SIZE - 3
opacity = 0.5
break
case 4:
fontSize = FONT_SIZE - 5
opacity = 0.4
break
}
if (i === 2 || isMouseOver === true) {
UI.projects.superalgos.utilities.drawPrint.drawLabel(label, 1 / 2, i / VISIBLE_LABELS, 0, 0, fontSize, thisObject.container, fontColor, undefined, undefined, opacity)
}
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,642 @@
function newUiObjectConstructor() {
const MODULE_NAME = 'UI Object Constructor'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
createUiObject: createUiObject,
destroyUiObject: destroyUiObject,
initialize: initialize,
finalize: finalize
}
let floatingLayer
return thisObject
function finalize() {
floatingLayer = undefined
}
function initialize(pFloatingLayer) {
floatingLayer = pFloatingLayer
}
function createUiObject(userAddingNew, payload) {
let floatingObject = newFloatingObject()
floatingObject.fitFunction = UI.projects.superalgos.spaces.floatingSpace.fitIntoVisibleArea
floatingObject.container.connectToParent(UI.projects.superalgos.spaces.floatingSpace.container, false, false, false, false, false, false, false, false)
floatingObject.initialize('UI Object', payload)
payload.floatingObject = floatingObject
/*
When this object is created based on a backup, share or clone, we will have a savedPayload that we will use to set the initial properties.
If it is a new object being created out of the user interface, we jusst continue with the construction process.
*/
if (userAddingNew === false && payload.node.type !== 'Workspace') {
let position = {
x: 0,
y: 0
}
position = {
x: payload.node.savedPayload.position.x,
y: payload.node.savedPayload.position.y
}
floatingObject.setPosition(position)
payload.node.savedPayload.position = undefined
if (payload.node.savedPayload.floatingObject.isPinned === true) {
floatingObject.pinToggle()
}
if (payload.node.savedPayload.floatingObject.isFrozen === true) {
floatingObject.freezeToggle()
}
if (payload.node.savedPayload.floatingObject.isCollapsed === true) {
floatingObject.collapseToggle()
}
if (payload.node.savedPayload.floatingObject.angleToParent !== undefined) {
floatingObject.angleToParent = payload.node.savedPayload.floatingObject.angleToParent
}
if (payload.node.savedPayload.floatingObject.distanceToParent !== undefined) {
floatingObject.distanceToParent = payload.node.savedPayload.floatingObject.distanceToParent
}
if (payload.node.savedPayload.floatingObject.arrangementStyle !== undefined) {
floatingObject.arrangementStyle = payload.node.savedPayload.floatingObject.arrangementStyle
}
}
/*
For brand new objects being created directly by the user, we will make them inherit some properties
from their closest siblings, and if they don't have, from their parents.
*/
if (userAddingNew === true) {
let definition = getNodeDefinition(payload.parentNode)
if (definition.properties !== undefined) {
for (let i = 0; i < definition.properties.length; i++) {
let property = definition.properties[i]
if (property.childType === payload.node.type) {
if (property.type === 'array') {
let parentNode = payload.parentNode
let parentNodeArray = parentNode[property.name]
if (parentNodeArray.length > 1) { // the new node was already added
let closestSibling = parentNodeArray[parentNodeArray.length - 2]
if (closestSibling !== undefined) {
floatingObject.angleToParent = closestSibling.payload.floatingObject.angleToParent
floatingObject.distanceToParent = closestSibling.payload.floatingObject.distanceToParent
floatingObject.arrangementStyle = closestSibling.payload.floatingObject.arrangementStyle
break
}
}
}
if (floatingObject.angleToParent === undefined) {
for (let j = i - 1; j >= 0; j--) {
let siblingProperty = definition.properties[j]
let parentNode = payload.parentNode
let parentNodeProperty = parentNode[siblingProperty.name]
if (parentNodeProperty !== undefined) {
if (siblingProperty.type === 'array') {
if (parentNodeProperty.length > 0) {
let closestSibling = parentNodeProperty[parentNodeProperty.length - 1]
if (closestSibling !== undefined) {
floatingObject.angleToParent = closestSibling.payload.floatingObject.angleToParent
floatingObject.distanceToParent = closestSibling.payload.floatingObject.distanceToParent
floatingObject.arrangementStyle = closestSibling.payload.floatingObject.arrangementStyle
break
}
}
} else {
let closestSibling = parentNodeProperty
if (closestSibling !== undefined) {
floatingObject.angleToParent = closestSibling.payload.floatingObject.angleToParent
floatingObject.distanceToParent = closestSibling.payload.floatingObject.distanceToParent
floatingObject.arrangementStyle = closestSibling.payload.floatingObject.arrangementStyle
break
}
}
}
}
for (let j = i + 1; j < definition.properties.length; j++) {
let siblingProperty = definition.properties[j]
let parentNode = payload.parentNode
let parentNodeProperty = parentNode[siblingProperty.name]
if (parentNodeProperty !== undefined) {
if (siblingProperty.type === 'array') {
if (parentNodeProperty.length > 0) {
let closestSibling = parentNodeProperty[parentNodeProperty.length - 1]
if (closestSibling !== undefined) {
floatingObject.angleToParent = closestSibling.payload.floatingObject.angleToParent
floatingObject.distanceToParent = closestSibling.payload.floatingObject.distanceToParent
floatingObject.arrangementStyle = closestSibling.payload.floatingObject.arrangementStyle
break
}
}
} else {
let closestSibling = parentNodeProperty
if (closestSibling !== undefined) {
floatingObject.angleToParent = closestSibling.payload.floatingObject.angleToParent
floatingObject.distanceToParent = closestSibling.payload.floatingObject.distanceToParent
floatingObject.arrangementStyle = closestSibling.payload.floatingObject.arrangementStyle
break
}
}
}
}
}
}
}
}
if (floatingObject.angleToParent === undefined) {
floatingObject.angleToParent = payload.parentNode.payload.floatingObject.angleToParent
floatingObject.distanceToParent = payload.parentNode.payload.floatingObject.distanceToParent
floatingObject.arrangementStyle = payload.parentNode.payload.floatingObject.arrangementStyle
}
}
/* Default Values in case there was no way to set a value previous to this. */
if (floatingObject.angleToParent === undefined) {
floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_360
}
if (floatingObject.distanceToParent === undefined) {
floatingObject.distanceToParent = DISTANCE_TO_PARENT.PARENT_100X
}
if (floatingObject.arrangementStyle === undefined) {
floatingObject.arrangementStyle = ARRANGEMENT_STYLE.CONCAVE
}
let uiObject = newUiObject()
payload.uiObject = uiObject
uiObject.fitFunction = UI.projects.superalgos.spaces.floatingSpace.fitIntoVisibleArea
uiObject.isVisibleFunction = UI.projects.superalgos.spaces.floatingSpace.isThisPointVisible
let menuItemsInitialValues = getMenuItemsInitialValues(uiObject, floatingObject, payload)
let schemaNode = getNodeDefinition(payload.node)
if (schemaNode === undefined) {
console.log(payload.node.type + ' node found at App Schema. This node will not be created. ')
return
}
let menuItems = schemaNode.menuItems
for (let j = 0; j < menuItems.length; j++) {
let item = menuItems[j]
item.angle = undefined
if (item.action !== undefined) {
if (item.action.indexOf('Add Missing Children') >= 0) {
item.action = 'Add Missing Children'
}
}
if (item.actionFunction === undefined) {
// item.actionFunction = 'payload.executeAction'
}
}
uiObject.initialize(payload, menuItemsInitialValues)
uiObject.container.connectToParent(floatingObject.container, false, false, true, true, false, false, true, true, true, true, true)
setFloatingObjectBasicProperties(floatingObject, payload)
if (payload.node.savedPayload !== undefined) {
if (payload.node.savedPayload.uiObject !== undefined) {
payload.uiObject.shortcutKey = payload.node.savedPayload.uiObject.shortcutKey
}
}
floatingLayer.addFloatingObject(floatingObject)
return
}
function addLeftIcons(menuItemsInitialValues, floatingObject, isPersonalData) {
menuItemsInitialValues.push(
{
action: 'Pin / Unpin',
actionFunction: floatingObject.pinToggle,
actionStatus: floatingObject.getPinStatus,
currentStatus: false,
label: undefined,
visible: true,
iconPathOn: 'pinned',
iconPathOff: 'unpinned',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Change Tension Level',
actionFunction: floatingObject.angleToParentToggle,
actionStatus: floatingObject.getAngleToParent,
currentStatus: true,
label: undefined,
visible: true,
icons: ['angle-to-parent-000', 'angle-to-parent-360', 'angle-to-parent-180', 'angle-to-parent-090', 'angle-to-parent-045'],
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Change Distance to Paarent',
actionFunction: floatingObject.distanceToParentToggle,
actionStatus: floatingObject.getDistanceToParent,
currentStatus: true,
label: undefined,
visible: true,
icons: ['distance-to-parent-000', 'distance-to-parent-025', 'distance-to-parent-050', 'distance-to-parent-100', 'distance-to-parent-150', 'distance-to-parent-200'],
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Change Arrangement Style',
actionFunction: floatingObject.arrangementStyleToggle,
actionStatus: floatingObject.getArrangementStyle,
currentStatus: true,
label: undefined,
visible: true,
icons: ['arrangement-concave', 'arrangement-convex', 'arrangement-vertical-right', 'arrangement-vertical-left', 'arrangement-horizontal-bottom', 'arrangement-horizontal-top'],
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Freeze / Unfreeze',
actionFunction: floatingObject.freezeToggle,
actionStatus: floatingObject.getFreezeStatus,
currentStatus: true,
label: undefined,
visible: true,
iconPathOn: 'unfreeze',
iconPathOff: 'freeze',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Collapse / Uncollapse',
actionFunction: floatingObject.collapseToggle,
actionStatus: floatingObject.getCollapseStatus,
currentStatus: false,
label: undefined,
visible: true,
iconPathOn: 'expand',
iconPathOff: 'collapse',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Backup',
actionFunction: floatingObject.payload.executeAction,
actionProject: 'Superalgos',
label: undefined,
visible: true,
iconPathOn: 'backup',
iconPathOff: 'backup',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 2
}
)
menuItemsInitialValues.push(
{
action: 'Clone',
actionFunction: floatingObject.payload.executeAction,
actionProject: 'Superalgos',
label: undefined,
visible: true,
iconPathOn: 'clone',
iconPathOff: 'clone',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 2
}
)
if (isPersonalData !== true) {
menuItemsInitialValues.push(
{
action: 'Share',
actionFunction: floatingObject.payload.executeAction,
actionProject: 'Superalgos',
label: undefined,
visible: true,
iconPathOn: 'share',
iconPathOff: 'share',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 2
}
)
}
menuItemsInitialValues.push(
{
action: 'Parent Detach',
actionFunction: floatingObject.payload.executeAction,
actionProject: 'Superalgos',
label: undefined,
visible: true,
iconPathOn: 'detach',
iconPathOff: 'detach',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 3
}
)
menuItemsInitialValues.push(
{
action: 'Reference Detach',
actionFunction: floatingObject.payload.executeAction,
actionProject: 'Superalgos',
label: undefined,
visible: true,
iconPathOn: 'delink',
iconPathOff: 'delink',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 3
}
)
menuItemsInitialValues.push(
{
action: 'Open Documentation',
actionFunction: floatingObject.payload.executeAction,
actionProject: 'Superalgos',
label: undefined,
visible: true,
iconPathOn: 'help',
iconPathOff: 'help',
rawRadius: 12,
targetRadius: 0,
currentRadius: 0,
ring: 4
}
)
}
function getMenuItemsInitialValues(uiObject, floatingObject, payload) {
let menuItemsInitialValues = []
let nodeDefinition = getNodeDefinition(payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
uiObject.configEditor = newConfigEditor()
uiObject.configEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.configEditor.container.connectToParent(uiObject.container, false, false, true, true, false, false, false, false)
uiObject.configEditor.initialize()
}
if (nodeDefinition.editors.code === true) {
uiObject.codeEditor = newCodeEditor()
uiObject.codeEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.codeEditor.container.connectToParent(uiObject.container, false, false, true, true, false, false, false, false)
uiObject.codeEditor.initialize()
}
if (nodeDefinition.editors.formula === true) {
uiObject.formulaEditor = newFormulaEditor()
uiObject.formulaEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.formulaEditor.container.connectToParent(uiObject.container, false, false, true, true, false, false, false, false)
uiObject.formulaEditor.initialize()
}
if (nodeDefinition.editors.condition === true) {
uiObject.conditionEditor = newConditionEditor()
uiObject.conditionEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.conditionEditor.container.connectToParent(uiObject.container, false, false, false, true, false, false, false, false)
uiObject.conditionEditor.initialize()
}
}
if (nodeDefinition.addLeftIcons === true) {
addLeftIcons(menuItemsInitialValues, floatingObject, nodeDefinition.isPersonalData)
}
if (nodeDefinition.isPinned === true) {
floatingObject.isPinned = true
}
if (nodeDefinition.positionLocked === true) {
floatingObject.positionLocked = true
}
for (let i = 0; i < nodeDefinition.menuItems.length; i++) {
let menutItemDefinition = nodeDefinition.menuItems[i]
let newMenuItem = JSON.parse(JSON.stringify(menutItemDefinition))
/* We need to reference the real function based on its name */
if (menutItemDefinition.actionFunction !== undefined) {
try {
newMenuItem.actionFunction = eval(menutItemDefinition.actionFunction)
} catch (err) {
console.log('Error at Menu Item Action Function: ' + menutItemDefinition.actionFunction + ' ' + err.stack)
continue
}
}
/* Adding default values */
if (newMenuItem.visible === undefined) {
newMenuItem.visible = true
}
if (newMenuItem.rawRadius === undefined) {
newMenuItem.rawRadius = 12
}
if (newMenuItem.targetRadius === undefined) {
newMenuItem.targetRadius = 0
}
if (newMenuItem.currentRadius === undefined) {
newMenuItem.currentRadius = 0
}
if (newMenuItem.actionProject === undefined) {
newMenuItem.actionProject = 'Superalgos'
}
menuItemsInitialValues.push(newMenuItem)
}
} else {
if (ERROR_LOG === true) { logger.write('[ERROR] getMenuItemsInitialValues -> UI Object Type not Recognized -> type = ' + payload.node.type) }
}
return menuItemsInitialValues
}
function setFloatingObjectBasicProperties(floatingObject, payload) {
const FRICTION = 0.95
const INITIAL_FRICTION = 0.97
const INITIAL_FONT_SIZE = 12 * 1.5
const INITIAL_RADIOUS = 70
const INITIAL_IMAGE_SIZE = 80 * 1.2
let nodeDefinition = getNodeDefinition(payload.node)
if (nodeDefinition === undefined) {
console.log('[WARN] Set up of the object ' + payload.node.name + ' of type ' + payload.node.type + ' can not be completed becasue its definition can not be found at the APP SCHEMA.')
return
}
if (nodeDefinition.isProjectHead === true) {
level_0()
floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_360
return
}
switch (nodeDefinition.level) {
case 0: {
level_0()
break
}
case 1: {
level_1()
break
}
case 2: {
level_2()
break
}
case 3: {
level_3()
break
}
case 4: {
level_4()
break
}
case 5: {
level_5()
break
}
}
function level_0() {
floatingObject.targetFriction = 0.93
floatingObject.friction = INITIAL_FRICTION
floatingObject.initializeMass(500)
floatingObject.initializeRadius(INITIAL_RADIOUS)
floatingObject.initializeImageSize(INITIAL_IMAGE_SIZE)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
}
function level_1() {
floatingObject.targetFriction = 0.94
floatingObject.friction = INITIAL_FRICTION
floatingObject.initializeMass(600)
floatingObject.initializeRadius(INITIAL_RADIOUS)
floatingObject.initializeImageSize(INITIAL_IMAGE_SIZE)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
if (payload.node.savedPayload === undefined) {
// floatingObject.angleToParentToggle()
}
}
function level_2() {
floatingObject.targetFriction = FRICTION
floatingObject.friction = INITIAL_FRICTION
floatingObject.initializeMass(300)
floatingObject.initializeRadius(INITIAL_RADIOUS - 1)
floatingObject.initializeImageSize(INITIAL_IMAGE_SIZE - 10)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', 1)'
if (payload.node.savedPayload === undefined) {
// floatingObject.angleToParentToggle()
}
}
function level_3() {
floatingObject.targetFriction = FRICTION
floatingObject.friction = INITIAL_FRICTION
floatingObject.initializeMass(150)
floatingObject.initializeRadius(INITIAL_RADIOUS - 2)
floatingObject.initializeImageSize(INITIAL_IMAGE_SIZE - 20)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 1)'
if (payload.node.savedPayload === undefined) {
// floatingObject.angleToParentToggle()
}
}
function level_4() {
floatingObject.targetFriction = FRICTION
floatingObject.friction = INITIAL_FRICTION
floatingObject.initializeMass(75)
floatingObject.initializeRadius(INITIAL_RADIOUS - 3)
floatingObject.initializeImageSize(INITIAL_IMAGE_SIZE - 30)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)'
if (payload.node.savedPayload === undefined) {
// floatingObject.angleToParentToggle()
}
}
function level_5() {
floatingObject.targetFriction = FRICTION
floatingObject.friction = INITIAL_FRICTION
floatingObject.initializeMass(50)
floatingObject.initializeRadius(INITIAL_RADIOUS - 4)
floatingObject.initializeImageSize(INITIAL_IMAGE_SIZE - 40)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.RED + ', 1)'
}
function level_6() {
floatingObject.targetFriction = FRICTION
floatingObject.friction = INITIAL_FRICTION
floatingObject.initializeMass(25)
floatingObject.initializeRadius(INITIAL_RADIOUS - 5)
floatingObject.initializeImageSize(INITIAL_IMAGE_SIZE - 50)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.RED + ', 1)'
}
}
function destroyUiObject(payload) {
if (payload === undefined) { return }
floatingLayer.removeFloatingObject(payload.floatingObject.handle)
payload.floatingObject.finalize()
payload.floatingObject = undefined
payload.uiObject.finalize()
payload.uiObject = undefined
payload.referenceParent = undefined
payload.parent = undefined
payload.chainParent = undefined
payload.node.savedPayload = undefined
}
}
@@ -0,0 +1,366 @@
function newUiObjectTitle() {
const MODULE_NAME = 'UI Object Title'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
fitFunction: undefined,
isVisibleFunction: undefined,
allwaysVisible: undefined,
editMode: undefined,
container: undefined,
payload: undefined,
isDefault: undefined,
enterEditMode: enterEditMode,
exitEditMode: exitEditMode,
physics: physics,
draw: draw,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.frame.radius = 0
let selfFocusEventSubscriptionId
let selfNotFocuskEventSubscriptionId
let selfMouseClickEventSubscriptionId
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(selfFocusEventSubscriptionId)
thisObject.container.eventHandler.stopListening(selfNotFocuskEventSubscriptionId)
thisObject.container.eventHandler.stopListening(selfMouseClickEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
thisObject.fitFunction = undefined
}
function initialize(payload) {
thisObject.payload = payload
thisObject.allwaysVisible = false // Default value
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isTitleAllwaysVisible === true) {
thisObject.allwaysVisible = true
}
}
selfFocusEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onFocus', onFocus)
selfNotFocuskEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onNotFocus', onNotFocus)
selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
}
function getContainer(point) {
if (AT_FULL_SCREEN_MODE === true) { return } // Fullscreen mode does not allow INPUT elements
let container
if (thisObject.editMode === true) {
if (point.x === VERY_LARGE_NUMBER) {
/* The the mouse leaves the canvas, and event of mouse over with a ridiculous coordinate is triggered so that
anyone can react. In our case, this object has an html input element that is not part of the canvas, so the event is
triggered. We compensate recognizing this coordinate and returning our container. */
return thisObject.container
}
}
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
} else {
return undefined
}
}
function physics() {
inheritancePhysics()
defaultPhysics()
}
function defaultPhysics() {
if (thisObject.payload.title !== 'New ' + thisObject.payload.node.type && thisObject.payload.title !== 'My ' + thisObject.payload.node.type) {
thisObject.isDefault = false
} else {
thisObject.isDefault = true
}
}
function inheritancePhysics() {
if (thisObject.payload.title === undefined) { return }
/* It is possible to override the default title by setting the APP SCHEMA property 'title' */
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition.title !== undefined) {
thisObject.payload.title = ''
thisObject.payload.node.name = ''
let separator = ''
for (let i = 0; i < nodeDefinition.title.length; i++) {
let titleReference = nodeDefinition.title[i]
switch (titleReference) {
case 'Use Parent': {
let nodeToUse = thisObject.payload.parentNode
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
thisObject.payload.title = thisObject.payload.title + separator + nodeToUse.payload.title
thisObject.payload.node.name = thisObject.payload.node.name + separator + nodeToUse.payload.node.name
}
break
}
case 'Use Reference Parent': {
let nodeToUse = thisObject.payload.node.payload.referenceParent
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
thisObject.payload.title = thisObject.payload.title + separator + nodeToUse.payload.title
thisObject.payload.node.name = thisObject.payload.node.name + separator + nodeToUse.payload.node.name
}
break
}
case 'Use Reference Parent Type': {
let nodeToUse = thisObject.payload.node.payload.referenceParent
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
thisObject.payload.title = thisObject.payload.title + separator + nodeToUse.type
thisObject.payload.node.name = thisObject.payload.node.name + separator + nodeToUse.type
}
break
}
case 'Use Reference Grandparent': {
let nodeToUse = thisObject.payload.node.payload.referenceParent
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
nodeToUse = thisObject.payload.node.payload.referenceParent.payload.referenceParent
if (nodeToUse !== undefined) {
thisObject.payload.title = thisObject.payload.title + separator + nodeToUse.payload.title
thisObject.payload.node.name = thisObject.payload.node.name + separator + nodeToUse.payload.node.name
}
}
break
}
case 'Use Reference Parent Parent': {
let nodeToUse = thisObject.payload.node.payload.referenceParent
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
nodeToUse = thisObject.payload.node.payload.referenceParent.payload.parentNode
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
thisObject.payload.title = thisObject.payload.title + separator + nodeToUse.payload.title
thisObject.payload.node.name = thisObject.payload.node.name + separator + nodeToUse.payload.node.name
}
}
break
}
case 'Use Reference Parent Parent Parent': {
let nodeToUse = thisObject.payload.node.payload.referenceParent
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
nodeToUse = thisObject.payload.node.payload.referenceParent.payload.parentNode
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
nodeToUse = thisObject.payload.node.payload.referenceParent.payload.parentNode.payload.parentNode
if (nodeToUse !== undefined && nodeToUse.payload !== undefined) {
thisObject.payload.title = thisObject.payload.title + separator + nodeToUse.payload.title
thisObject.payload.node.name = thisObject.payload.node.name + separator + nodeToUse.payload.node.name
}
}
}
break
}
default: {
if (titleReference.indexOf('Use Child @') === 0) {
let propertyName = titleReference.substring(titleReference.indexOf('@') + 1, titleReference.length)
let childNode = thisObject.payload.node[propertyName]
if (childNode === undefined) { break }
thisObject.payload.title = thisObject.payload.title + separator + childNode.name
thisObject.payload.node.name = thisObject.payload.node.name + separator + childNode.name
}
}
}
separator = ' '
}
}
/* The name becomes the title. */
if (thisObject.payload.node.name !== undefined) {
thisObject.payload.title = thisObject.payload.node.name
}
let title = trimTitle(thisObject.payload.title)
/* Here we set the dimensions and position of this object */
const FRAME_HEIGHT = 25
const Y_OFFSET = -20
const FRAME_WIDTH = (title.length + 2) / 2 * thisObject.payload.floatingObject.currentFontSize * FONT_ASPECT_RATIO * 1.2 * 2
if (thisObject.isOnFocus === true) {
thisObject.container.frame.position.x = 0 - FRAME_WIDTH / 2
thisObject.container.frame.position.y = 0 - thisObject.container.frame.radius * 1 / 2 - thisObject.payload.floatingObject.currentFontSize * FONT_ASPECT_RATIO + Y_OFFSET - FRAME_HEIGHT
} else {
thisObject.container.frame.position.x = 0 - FRAME_WIDTH / 2
thisObject.container.frame.position.y = 0 - thisObject.payload.floatingObject.currentImageSize / 2 - FRAME_HEIGHT
}
thisObject.container.frame.width = FRAME_WIDTH
thisObject.container.frame.height = FRAME_HEIGHT
if (thisObject.editMode === true) {
let inputPosition = {
x: 0,
y: 0 + CURRENT_TOP_MARGIN + Y_OFFSET
}
inputPosition = thisObject.container.frame.frameThisPoint(inputPosition)
if (inputPosition.y < CURRENT_TOP_MARGIN) { exitEditMode() }
let inputDiv = document.getElementById('inputDiv')
inputDiv.style = 'position:absolute; top:' + inputPosition.y + 'px; left:' + inputPosition.x + 'px; z-index:1; '
}
}
function onFocus() {
thisObject.isOnFocus = true
}
function onNotFocus() {
thisObject.isOnFocus = false
exitEditMode()
}
function onMouseClick(event) {
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition.title !== undefined) { return }
let checkPoint = {
x: 0,
y: 0
}
checkPoint = thisObject.container.frame.frameThisPoint(checkPoint)
if (thisObject.isVisibleFunction(checkPoint) === true) {
enterEditMode()
}
}
function exitEditMode() {
if (thisObject.editMode === true) {
thisObject.editMode = false
let input = document.getElementById('input')
input.style.display = 'none'
if (input.value.length > 2) {
thisObject.payload.title = input.value
thisObject.payload.node.name = input.value
}
}
let inputDiv = document.getElementById('inputDiv')
inputDiv.style = 'position:absolute; top:' + '-100' + 'px; left:' + '-100' + 'px; z-index:1; '
}
function enterEditMode() {
const WIDTH = thisObject.container.frame.width
const HEIGHT = thisObject.container.frame.height
let fontSize = thisObject.payload.floatingObject.currentFontSize
thisObject.editMode = true
let input = document.getElementById('input')
input.value = thisObject.payload.title
let backgroundColor = '0, 0, 0'
if (thisObject.payload.uiObject.codeEditor !== undefined) {
if (thisObject.payload.uiObject.codeEditor.visible === true) {
backgroundColor = '204, 88, 53'
}
}
input.style = 'resize: none; border: none; outline: none; box-shadow: none; overflow:hidden; font-family: Saira Condensed; font-size: ' + fontSize + 'px; background-color: rgb(' + backgroundColor + ');color:rgb(255, 255, 255); width: ' + WIDTH + 'px; height: ' + HEIGHT + 'px'
input.style.display = 'block'
input.focus()
}
function draw() {
if (thisObject.isOnFocus === true || thisObject.allwaysVisible === true || thisObject.isDefault === false) {
if (thisObject.payload.uiObject.codeEditor !== undefined) {
if (thisObject.payload.uiObject.codeEditor.visible !== true) {
drawTitleBackground()
}
} else {
drawTitleBackground()
}
drawText()
}
}
function drawTitleBackground() {
if (thisObject.editMode !== true) {
let params = {
cornerRadius: 3,
lineWidth: 0.1,
container: thisObject.container,
borderColor: UI.projects.superalgos.spaces.floatingSpace.style.backgroundColor,
backgroundColor: UI.projects.superalgos.spaces.floatingSpace.style.backgroundColor,
castShadow: false,
opacity: 0.25
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
}
}
function drawText() {
if (thisObject.editMode !== true) {
let radius = thisObject.container.frame.radius
let labelPoint
let fontSize = thisObject.payload.floatingObject.currentFontSize
let label
if (radius > 6 && (thisObject.isOnFocus === true || thisObject.allwaysVisible === true || thisObject.isDefault === false)) {
browserCanvasContext.strokeStyle = thisObject.payload.floatingObject.typeStrokeStyle
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
label = thisObject.payload.title
if (label !== undefined) {
label = trimTitle(label)
labelPoint = {
x: 5,
y: thisObject.container.frame.height * 0.8
}
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint)
if (UI.projects.superalgos.spaces.floatingSpace.inMapMode === true) {
labelPoint = UI.projects.superalgos.spaces.floatingSpace.transformPointToMap(labelPoint)
labelPoint.x = labelPoint.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO
labelPoint.y = labelPoint.y - 35
let nodeDefinition = getNodeDefinition(thisObject.payload.node)
if (nodeDefinition !== undefined) {
if (nodeDefinition.isHierarchyHead !== true && nodeDefinition.isProjectHead !== true) {
return
}
}
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = thisObject.payload.floatingObject.typeStrokeStyle
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
}
}
}
function trimTitle(title) {
if (title === undefined) { return }
const MAX_LABEL_LENGTH = 50
if (title.length > MAX_LABEL_LENGTH) {
title = title.substring(0, MAX_LABEL_LENGTH) + '...'
}
return title
}
}
@@ -0,0 +1,700 @@
function newLayer() {
const MODULE_NAME = 'Layer'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
container: undefined,
status: LAYER_STATUS.OFF,
fitFunction: undefined,
payload: undefined,
definition: undefined,
panels: undefined,
baseAsset: undefined,
quotedAsset: undefined,
market: undefined,
exchange: undefined,
bot: undefined,
productDefinition: undefined,
dataMine: undefined,
plotterModule: undefined,
exchangeIcon: undefined,
plotterTypeIcon: undefined,
baseAssetIcon: undefined,
quotedAssetIcon: undefined,
networkNode: undefined,
checkStatusAtShutDown: checkStatusAtShutDown,
physics: physics,
draw: draw,
turnOff: turnOff,
turnOn: turnOn,
setDatetime: setDatetime,
setTimeFrame: setTimeFrame,
onMarketFileLoaded: onMarketFileLoaded,
onDailyFileLoaded: onDailyFileLoaded,
onSingleFileLoaded: onSingleFileLoaded,
onFileSequenceLoaded: onFileSequenceLoaded,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize,
finalize: finalize
}
let LOADING_FILL_STYLE = 'rgba(234, 143, 23, @Opacity)'
let LOADED_FILL_STYLE = 'rgba(45, 232, 28, @Opacity)'
let UNLOADED_FILL_STYLE = 'rgba(226, 226, 226, @Opacity)'
let LOADING_STROKE_STYLE = 'rgba(234, 143, 23, @Opacity)'
let LOADED_STROKE_STYLE = 'rgba(45, 232, 28, @Opacity)'
let UNLOADED_STROKE_STYLE = 'rgba(226, 226, 226, @Opacity)'
let marketFileProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
}
let dailyFileProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
}
let singleFileProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
}
let fileSequenceProgressBar = {
value: 0,
animatedValue: 0,
fillStyle: UNLOADED_FILL_STYLE,
strokeStyle: UNLOADED_STROKE_STYLE,
opacity: 0.00
}
let timeFrame = INITIAL_TIME_PERIOD
let datetime = NEW_SESSION_INITIAL_DATE
/* Add an Event Handler */
thisObject.eventHandler = newEventHandler()
let imagesLoaded = 0
let onMouseClickEventSuscriptionId
let panelsVisibleButton
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseClickEventSuscriptionId)
thisObject.container.finalize()
thisObject.eventHandler.finalize()
thisObject.container = undefined
thisObject.eventHandler = undefined
thisObject.status = undefined
thisObject.fitFunction = undefined
thisObject.payload = undefined
thisObject.definition = undefined
thisObject.panels = undefined
timeFrame = undefined
datetime = undefined
LOADING_FILL_STYLE = undefined
LOADED_FILL_STYLE = undefined
UNLOADED_FILL_STYLE = undefined
LOADING_STROKE_STYLE = undefined
LOADED_STROKE_STYLE = undefined
UNLOADED_STROKE_STYLE = undefined
marketFileProgressBar = undefined
dailyFileProgressBar = undefined
singleFileProgressBar = undefined
fileSequenceProgressBar = undefined
panelsVisibleButton = undefined
thisObject.baseAsset = undefined
thisObject.quotedAsset = undefined
thisObject.market = undefined
thisObject.exchange = undefined
thisObject.plotterModule = undefined
thisObject.exchangeIcon = undefined
thisObject.plotterTypeIcon = undefined
thisObject.baseAssetIcon = undefined
thisObject.quotedAssetIcon = undefined
thisObject.networkNode = undefined
thisObject.bot = undefined
thisObject.productDefinition = undefined
thisObject.dataMine = undefined
}
function initialize(callBackFunction) {
/* Create this objects continer */
try {
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME + ' ' + thisObject.payload.node.id)
thisObject.container.isDraggeable = false
thisObject.container.isClickeable = true
/* Lets set the basic dimensions of this thisObject. */
let position = {
x: 0,
y: 0
}
thisObject.container.frame.position = position
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL
thisObject.container.frame.height = 70
let functionLibraryProtocolNode = newProtocolNode()
let lightingPath =
'->Layer->' +
'Data Product->' +
'Data Product Folder->Data Product Folder->Data Product Folder->Data Product Folder->Data Product Folder->' +
'Bot Products->Data Mine Products->Trading Mine Products->' +
'Market Data Products->Exchange Data Products->' +
'Session Reference->Market Trading Products->Exchange Trading Products->' +
'Data Mines Data->Trading Mines Data->Data Storage->Network Node->' +
'Data Storage->Network Node->' +
'Backtesting Session->Paper Trading Session->Forward Testing Session->Live Trading Session->' +
'Trading System Reference->Trading Engine Reference->Trading System->Trading Engine->' +
'Market->Market Base Asset->Asset->' +
'Market Quoted Asset->Asset->' +
'Exchange Markets->Crypto Exchange->' +
'Product Definition->' +
'Product Definition Folder->Product Definition Folder->Product Definition Folder->Product Definition Folder->Product Definition Folder->' +
'Sensor Bot->Indicator Bot->Trading Bot->' +
'Data Mine->Trading Mine->' +
'Dataset Definition->' +
'Record Definition->Record Property->Formula->' +
'Data Building Procedure->Procedure Loop->Javascript Code->Procedure Initialization->Javascript Code->' +
'Calculations Procedure->Procedure Loop->Javascript Code->Procedure Initialization->Javascript Code->' +
'Plotter Module->Plotter->' +
'Shapes->' +
'Chart Points->Point->Point Formula->' +
'Polygon->Polygon Condition->Polygon Body->Style->Style Condition->Style->' +
'Polygon Border->Style->Style Condition->Style->' +
'Polygon Vertex->Point->' +
'Image->Image Condition->Image Position->Point->' +
'Text->Text Condition->Text Position->Point->Text Formula->Text Style->' +
'Plotter Panel->Javascript Code->Panel Data->Data Formula->Text Style->' +
'Nodes Highlights->Nodes Values->Nodes Errors->Nodes Warnings->Nodes Infos->Nodes Status->Nodes Progress->Nodes Running->Nodes Announcements->Record Values->'
thisObject.definition = functionLibraryProtocolNode.getProtocolNode(thisObject.payload.node, false, true, true, false, false, lightingPath)
/* Without this I can not continue, because I can not even show error. */
if (thisObject.payload === undefined) {
console.log(MODULE_NAME + ' ' + 'thisObject.payload === undefined')
return
}
if (thisObject.payload.uiObject === undefined) {
console.log(MODULE_NAME + ' ' + 'thisObject.payload.uiObject === undefined')
return
}
if (thisObject.payload.node === undefined) {
console.log(MODULE_NAME + ' ' + 'thisObject.payload.node === undefined')
return
}
/* Here we validate that we have all the needed information */
if (UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Data Product', undefined, false, true, true, true) === undefined) {
thisObject.payload.uiObject.setErrorMessage('Data Product not Found')
return
}
if (UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Market', undefined, false, true, true, true) === undefined) {
thisObject.payload.uiObject.setErrorMessage('Market not Found')
return
}
thisObject.productDefinition = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Product Definition', undefined, false, true, true, true)
if (thisObject.productDefinition === undefined) {
thisObject.payload.uiObject.setErrorMessage('Product Definition not Found')
return
}
thisObject.bot = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Sensor Bot', undefined, false, true, true, true)
if (thisObject.bot === undefined) {
thisObject.bot = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Indicator Bot', undefined, false, true, true, true)
}
if (thisObject.bot === undefined) {
thisObject.bot = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Trading Bot', undefined, false, true, true, true)
}
if (thisObject.bot === undefined) {
thisObject.payload.uiObject.setErrorMessage('Bot not Found')
return
}
thisObject.dataMine = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Data Mine', undefined, false, true, true, true)
if (thisObject.dataMine === undefined) {
thisObject.dataMine = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Trading Mine', undefined, false, true, true, true)
if (thisObject.dataMine === undefined) {
thisObject.payload.uiObject.setErrorMessage('Data Mine or Trading Mine not Found')
return
}
}
thisObject.exchange = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Crypto Exchange', undefined, false, true, true, true)
if (thisObject.exchange === undefined) {
thisObject.payload.uiObject.setErrorMessage('Crypto Exchange not Found')
return
}
thisObject.baseAsset = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Market Base Asset', undefined, false, true, true, true)
if (thisObject.baseAsset !== undefined) {
thisObject.baseAsset = thisObject.baseAsset.referenceParent
}
if (thisObject.baseAsset === undefined) {
thisObject.payload.uiObject.setErrorMessage('Market Base Asset not Found')
return
}
thisObject.quotedAsset = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Market Quoted Asset', undefined, false, true, true, true)
if (thisObject.quotedAsset !== undefined) {
thisObject.quotedAsset = thisObject.quotedAsset.referenceParent
}
if (thisObject.quotedAsset === undefined) {
thisObject.payload.uiObject.setErrorMessage('Market Quoted Asset not Found')
return
}
thisObject.plotterModule = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Plotter Module', undefined, false, false, false, true)
if (thisObject.plotterModule === undefined) {
thisObject.payload.uiObject.setErrorMessage('Plotter Module not Found')
return
}
thisObject.networkNode = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(thisObject.definition, 'Network Node', undefined, false, true, true, true)
if (thisObject.networkNode === undefined) {
thisObject.payload.uiObject.setErrorMessage('Network Node not Found')
return
}
/* Lets listen to our own events to react when we have a Mouse Click */
onMouseClickEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
/* Get ready to draw this layer */
thisObject.market = thisObject.baseAsset.config.codeName + '/' + thisObject.quotedAsset.config.codeName
thisObject.exchangeIcon = getIcon(thisObject.exchange)
if (thisObject.plotterModule.config.icon !== undefined) {
thisObject.plotterTypeIcon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', thisObject.plotterModule.config.icon)
}
thisObject.baseAssetIcon = getIcon(thisObject.baseAsset)
thisObject.quotedAssetIcon = getIcon(thisObject.quotedAsset)
function getIcon(node) {
let nodeDefinition = getNodeDefinition(node)
let iconName
let icon
if (nodeDefinition.alternativeIcons !== undefined) {
for (let i = 0; i < nodeDefinition.alternativeIcons.length; i++) {
let alternativeIcon = nodeDefinition.alternativeIcons[i]
if (alternativeIcon.codeName === node.config.codeName) {
iconName = alternativeIcon.iconName
}
}
}
if (iconName !== undefined) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', iconName)
} else {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', nodeDefinition.icon)
}
return icon
}
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) }
}
}
function checkStatusAtShutDown() {
/* Mechanism to recover a layer that was left loading the last time the browser was shut dowm. */
let storedValue = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'status')
if (storedValue !== undefined) {
if (storedValue === LAYER_STATUS.LOADING) {
resetProgressBars()
changeStatusTo(LAYER_STATUS.LOADING)
}
}
}
function getContainer(point) {
if (panelsVisibleButton !== undefined) {
let container = panelsVisibleButton.getContainer(point)
if (container !== undefined) {
return container
}
}
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function setDatetime(pDatetime) {
/*
When the datetime changes from one day to another, this forces cursors to potentially load more files, thus we reset this counter and
get ready to receive events on files loaded.
*/
let currentDate = Math.trunc(datetime.valueOf() / ONE_DAY_IN_MILISECONDS)
let newDate = Math.trunc(pDatetime.valueOf() / ONE_DAY_IN_MILISECONDS)
datetime = pDatetime
if (currentDate !== newDate) {
if (timeFrame <= _1_HOUR_IN_MILISECONDS) {
dailyFileProgressBar.animatedValue = 0
}
}
}
function setTimeFrame(pTimeFrame) {
/*
When the time period below or equal to 1 hour changes, this forces cursors to potentially load more files, thus we reset this counter and
get ready to receive events on files loaded.
*/
if (timeFrame !== pTimeFrame) {
timeFrame = pTimeFrame
if (timeFrame <= _1_HOUR_IN_MILISECONDS) {
dailyFileProgressBar.animatedValue = 0
}
}
}
function onMarketFileLoaded(event) {
if (event.totalValue === 0) {
marketFileProgressBar.value = 100
return
}
marketFileProgressBar.value = Math.trunc((event.currentValue + event.filesNotLoaded) * 100 / event.totalValue)
marketFileProgressBar.fillStyle = LOADING_FILL_STYLE
marketFileProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (marketFileProgressBar.value > 100) { marketFileProgressBar.value = 100 }
}
function onDailyFileLoaded(event) {
if (event.totalValue === 0) {
dailyFileProgressBar.value = 100
return
}
dailyFileProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue)
dailyFileProgressBar.fillStyle = LOADING_FILL_STYLE
dailyFileProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (dailyFileProgressBar.value > 100) { dailyFileProgressBar.value = 100 }
}
function onSingleFileLoaded(event) {
if (event.totalValue === 0) {
singleFileProgressBar.value = 100
return
}
singleFileProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue)
singleFileProgressBar.fillStyle = LOADING_FILL_STYLE
singleFileProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (singleFileProgressBar.value > 100) { singleFileProgressBar.value = 100 }
}
function onFileSequenceLoaded(event) {
if (event.totalValue === 0) {
fileSequenceProgressBar.value = 100
return
}
fileSequenceProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue)
fileSequenceProgressBar.fillStyle = LOADING_FILL_STYLE
fileSequenceProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (fileSequenceProgressBar.value > 100) { fileSequenceProgressBar.value = 100 }
}
function turnOff() {
if (thisObject.status !== LAYER_STATUS.OFF) {
resetProgressBars()
changeStatusTo(LAYER_STATUS.OFF)
}
}
function turnOn() {
if (thisObject.status === LAYER_STATUS.OFF) {
resetProgressBars()
changeStatusTo(LAYER_STATUS.LOADING)
}
}
function onMouseClick(event) {
switch (thisObject.status) {
case LAYER_STATUS.ON:
resetProgressBars()
changeStatusTo(LAYER_STATUS.OFF)
break
case LAYER_STATUS.OFF:
resetProgressBars()
changeStatusTo(LAYER_STATUS.LOADING)
break
case LAYER_STATUS.LOADING:
changeStatusTo(LAYER_STATUS.OFF)
break
}
}
function resetProgressBars() {
marketFileProgressBar.animatedValue = 0
marketFileProgressBar.value = 0
marketFileProgressBar.fillStyle = UNLOADED_FILL_STYLE
marketFileProgressBar.strokeStyle = UNLOADED_STROKE_STYLE
dailyFileProgressBar.animatedValue = 0
dailyFileProgressBar.value = 0
dailyFileProgressBar.fillStyle = UNLOADED_FILL_STYLE
dailyFileProgressBar.strokeStyle = UNLOADED_STROKE_STYLE
singleFileProgressBar.animatedValue = 0
singleFileProgressBar.value = 0
singleFileProgressBar.fillStyle = UNLOADED_FILL_STYLE
singleFileProgressBar.strokeStyle = UNLOADED_STROKE_STYLE
fileSequenceProgressBar.animatedValue = 0
fileSequenceProgressBar.value = 0
fileSequenceProgressBar.fillStyle = UNLOADED_FILL_STYLE
fileSequenceProgressBar.strokeStyle = UNLOADED_STROKE_STYLE
}
function physics() {
statusPhysics()
childrenPhysics()
}
function childrenPhysics() {
/* Panels Visible Button Setup */
if (thisObject.status === LAYER_STATUS.ON) {
if (panelsVisibleButton === undefined) {
if (thisObject.panels !== undefined) {
if (thisObject.panels.length > 0) {
panelsVisibleButton = newPanelsVisibleButton()
let storedValue = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'showPanels')
if (storedValue !== undefined) {
if (storedValue === true || storedValue === false) {
panelsVisibleButton.showPanels = storedValue
}
}
panelsVisibleButton.initialize(thisObject.panels)
panelsVisibleButton.container.connectToParent(thisObject.container)
}
}
} else {
UI.projects.superalgos.utilities.nodeConfig.savePropertyAtNodeConfig(thisObject.payload, 'showPanels', panelsVisibleButton.showPanels)
}
}
}
function statusPhysics() {
/* We retrieve the stored status at the config. */
try {
let storedValue = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'status')
if (storedValue !== undefined) {
if (storedValue !== thisObject.status) {
if (storedValue === LAYER_STATUS.ON && thisObject.status === LAYER_STATUS.OFF) {
resetProgressBars()
changeStatusTo(LAYER_STATUS.LOADING)
}
if (storedValue === LAYER_STATUS.OFF) {
resetProgressBars()
changeStatusTo(LAYER_STATUS.OFF)
}
}
} else {
resetProgressBars()
changeStatusTo(LAYER_STATUS.OFF)
}
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
if (
thisObject.status === LAYER_STATUS.LOADING &&
marketFileProgressBar.value === 100 &&
dailyFileProgressBar.value === 100
) {
changeStatusTo(LAYER_STATUS.ON)
}
}
function changeStatusTo(newStatus) {
if (thisObject.status !== newStatus) {
thisObject.status = newStatus
if (thisObject.status === LAYER_STATUS.OFF) {
if (panelsVisibleButton !== undefined) {
panelsVisibleButton.finalize()
panelsVisibleButton = undefined
}
}
UI.projects.superalgos.utilities.nodeConfig.savePropertyAtNodeConfig(thisObject.payload, 'status', thisObject.status)
let eventData = thisObject
thisObject.container.eventHandler.raiseEvent('Status Changed', eventData)
}
}
function draw() {
drawLayer()
if (panelsVisibleButton !== undefined) {
panelsVisibleButton.draw()
}
}
function drawLayer() {
drawLayerDisplay()
}
function drawProgressBar(progressBar, lineWidth, offsetY) {
const ANIMATED_INCREMENT = 5
const OPACITY_INCREMENT = 0.01
const OPACITY_MIN = 1
let point1
let point2
let horizontalMargin = 12
if (progressBar.value === 0) {
return
}
/* Animate */
if (progressBar.animatedValue < progressBar.value) {
progressBar.animatedValue = progressBar.animatedValue + ANIMATED_INCREMENT
progressBar.opacity = progressBar.opacity + OPACITY_INCREMENT
}
if (progressBar.animatedValue >= 100) {
progressBar.animatedValue = 100
progressBar.opacity = progressBar.opacity - OPACITY_INCREMENT
if (progressBar.opacity < OPACITY_MIN) { progressBar.opacity = OPACITY_MIN }
progressBar.strokeStyle = LOADED_STROKE_STYLE.replace('@Opacity', progressBar.opacity.toString())
}
point1 = {
x: 0 + horizontalMargin,
y: thisObject.container.frame.height + offsetY
}
point2 = {
x: (thisObject.container.frame.width - horizontalMargin * 2) * progressBar.animatedValue / 100 + horizontalMargin,
y: thisObject.container.frame.height + offsetY
}
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point1 = thisObject.fitFunction(point1)
point2 = thisObject.fitFunction(point2)
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = progressBar.strokeStyle.replace('@Opacity', progressBar.opacity.toString())
browserCanvasContext.setLineDash([2, 4])
browserCanvasContext.lineWidth = lineWidth
browserCanvasContext.stroke()
}
function drawLayerDisplay() {
let label1 = thisObject.payload.node.name
let label2 = thisObject.exchange.name.substring(0, 15) + ' - ' + thisObject.market
let label3 = thisObject.status.toUpperCase()
if (label1 !== undefined) {
label1 = label1.substring(0, 30)
}
let backgroundColor = UI_COLOR.BLACK
const RED_LINE_HIGHT = 4
const OPACITY = 0.75
let params = {
cornerRadius: 0,
lineWidth: 1,
container: thisObject.container,
borderColor: UI_COLOR.RUSTED_RED,
castShadow: false,
backgroundColor: backgroundColor,
opacity: OPACITY
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
let parentLabel1FontSize = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload.parentNode.payload, 'label1FontSize')
let parentLabel2FontSize = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload.parentNode.payload, 'label2FontSize')
let parentLabel3FontSize = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload.parentNode.payload, 'label3FontSize')
let label1FontSize = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'label1FontSize')
let label2FontSize = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'label2FontSize')
let label3FontSize = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'label3FontSize')
if (parentLabel1FontSize !== undefined) {
label1FontSize = parentLabel1FontSize
}
if (parentLabel2FontSize !== undefined) {
label2FontSize = parentLabel2FontSize
}
if (parentLabel3FontSize !== undefined) {
label3FontSize = parentLabel3FontSize
}
if (label1FontSize === undefined) {
if (label1.length > 20) {
label1FontSize = 12
} else {
label1FontSize = 15
}
}
if (label2FontSize === undefined) {
label2FontSize = 10
}
if (label3FontSize === undefined) {
label3FontSize = 9
}
UI.projects.superalgos.utilities.drawPrint.drawLabel(label1, 1 / 2, 5.2 / 10, -5, 0, label1FontSize, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label2, 1 / 2, 8.2 / 10, -5, 0, label2FontSize, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label3, 1 / 2, 9.5 / 10, -5, 0, label3FontSize, thisObject.container)
drawProgressBar(marketFileProgressBar, 2, -45 + 18)
drawProgressBar(dailyFileProgressBar, 2, -46 + 18)
drawProgressBar(singleFileProgressBar, 2, -47 + 18)
drawProgressBar(fileSequenceProgressBar, 2, -48 + 18)
UI.projects.superalgos.utilities.drawPrint.drawIcon(thisObject.exchangeIcon, 1 / 8, 2 / 10, 0, 0, 14, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawIcon(thisObject.plotterTypeIcon, 7 / 8, 2 / 10, 0, 0, 14, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawIcon(thisObject.baseAssetIcon, 3.4 / 8, 2 / 10, 0, 0, 14, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawIcon(thisObject.quotedAssetIcon, 4.6 / 8, 2 / 10, 0, 0, 14, thisObject.container)
}
}
@@ -0,0 +1,522 @@
function newLayersPanel() {
let thisObject = {
name: 'Layers Panel',
fitFunction: undefined,
container: undefined,
layers: [],
payload: undefined,
isVisible: true,
upDownButton: undefined,
leftRightButton: undefined,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize()
thisObject.container.isDraggeable = true
thisObject.container.isWheelable = true
thisObject.container.detectMouseOver = true
let isInitialized = false
let mouseOverCounter = 0
let layersMap = new Map()
let visibleLayers = []
let firstVisibleLayer = 1
const LAYER_SEPARATION = 0
let headerHeight = 40
let footerHeight = 10
let layerHeight = 70
let desiredVisibleLayers = 5
let posibleVisibleLayers = 5
let desiredPanelHeight = (layerHeight + LAYER_SEPARATION) * desiredVisibleLayers + headerHeight + footerHeight
let posiblePanelHeight = (layerHeight + LAYER_SEPARATION) * posibleVisibleLayers + headerHeight + footerHeight
let onMouseWheelEventSuscriptionId
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
let isMouseOver
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSuscriptionId)
thisObject.container.eventHandler.stopListening(onMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
thisObject.upDownButton.finalize()
thisObject.upDownButton = undefined
thisObject.leftRightButton.finalize()
thisObject.leftRightButton = undefined
layersMap = undefined
visibleLayers = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject = undefined
}
function initialize() {
thisObject.container.name = thisObject.payload.node.name
thisObject.container.frame.containerName = thisObject.container.name
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL
thisObject.container.frame.height = headerHeight
let position = { // Default position
x: UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.x,
y: UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y
}
thisObject.container.frame.position = position
UI.projects.superalgos.utilities.loadSaveFrame.loadFrame(thisObject.payload, thisObject.container.frame)
thisObject.upDownButton = newUpDownButton()
thisObject.upDownButton.parentContainer = thisObject.container
thisObject.upDownButton.container.frame.parentFrame = thisObject.container.frame
thisObject.upDownButton.fitFunction = thisObject.fitFunction
thisObject.upDownButton.initialize()
thisObject.leftRightButton = newLeftRightButton()
thisObject.leftRightButton.parentContainer = thisObject.container
thisObject.leftRightButton.container.frame.parentFrame = thisObject.container.frame
thisObject.leftRightButton.fitFunction = thisObject.fitFunction
thisObject.leftRightButton.initialize()
onMouseWheelEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
onMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
readObjectState()
isInitialized = true
}
function onMouseOver(event) {
isMouseOver = true
}
function onMouseNotOver() {
isMouseOver = false
}
function saveObjectStateVisibleLayers() {
UI.projects.superalgos.utilities.nodeConfig.savePropertyAtNodeConfig(thisObject.payload, 'visibleLayers', desiredVisibleLayers)
}
function saveObjectStatePanelLocation() {
let panelLocation = {
upOrDown: thisObject.upDownButton.status,
leftOrRight: thisObject.leftRightButton.status
}
UI.projects.superalgos.utilities.nodeConfig.savePropertyAtNodeConfig(thisObject.payload, 'panelLocation', panelLocation)
}
function readObjectState() {
let storedValue
storedValue = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'visibleLayers')
if (isNaN(storedValue) || storedValue === null || storedValue === undefined) {
// not using this value
saveObjectStateVisibleLayers() // this overrides any invalid value at the config.
return
} else {
if (storedValue < 0) { storedValue = 0 }
if (storedValue > thisObject.layers.length) {
storedValue = thisObject.layers.length
}
if (storedValue !== desiredVisibleLayers) {
desiredVisibleLayers = storedValue
desiredPanelHeight = (layerHeight + LAYER_SEPARATION) * desiredVisibleLayers + headerHeight + footerHeight
calculateVisbleLayers()
}
}
storedValue = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(thisObject.payload, 'panelLocation')
if (storedValue === null || storedValue === undefined) {
// not using this value
saveObjectStatePanelLocation() // this overrides any invalid value at the config.
return
} else {
if (storedValue.upOrDown !== 'up' && storedValue.upOrDown !== 'down') {
saveObjectStatePanelLocation() // this overrides any invalid value at the config.
return
}
if (storedValue.leftOrRight !== 'left' && storedValue.leftOrRight !== 'right') {
saveObjectStatePanelLocation() // this overrides any invalid value at the config.
return
}
thisObject.upDownButton.setStatus(storedValue.upOrDown)
thisObject.leftRightButton.setStatus(storedValue.leftOrRight)
saveObjectStatePanelLocation()
}
}
function removeLayer(id) {
let layer = layersMap.get(id)
layersMap.delete(id)
layer.turnOff()
layer.container.eventHandler.stopListening(layer.onLayerStatusChangedEventSuscriptionId)
layer.container.eventHandler.stopListening(layer.onMouseWheelEventSuscriptionId)
layer.finalize()
}
function addLayer(layerNode) {
/* Now we create Product objects */
let layer = newLayer()
layer.payload = layerNode.payload
layer.nodeId = layerNode.payload.node.id
layer.fitFunction = thisObject.fitFunction
/* Initialize it */
layer.initialize(onInitialized)
function onInitialized(err) {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
layersMap.set(layerNode.id, layer)
/* Container Stuff */
layer.container.frame.parentFrame = thisObject.container.frame
layer.container.parentContainer = thisObject.container
layer.container.isWheelable = true
/* Add to the Product Array */
thisObject.layers.push(layer)
/* Listen to Status Changes Events */
layer.onLayerStatusChangedEventSuscriptionId = layer.container.eventHandler.listenToEvent('Status Changed', onLayerStatusChanged)
layer.onMouseWheelEventSuscriptionId = layer.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
layer.checkStatusAtShutDown()
return
}
}
}
function onMouseWheel(event) {
delta = event.wheelDelta
if (delta > 0) {
delta = -1
} else {
delta = 1
}
if (event.y - thisObject.container.frame.position.y - CURRENT_TOP_MARGIN < headerHeight) { // Mouse wheel over the header, not a layer
desiredVisibleLayers = desiredVisibleLayers + delta
if (desiredVisibleLayers < 0) { desiredVisibleLayers = 0 }
if (desiredVisibleLayers > thisObject.layers.length) { desiredVisibleLayers = thisObject.layers.length }
} else {
firstVisibleLayer = firstVisibleLayer + delta
}
desiredPanelHeight = (layerHeight + LAYER_SEPARATION) * desiredVisibleLayers + headerHeight + footerHeight
calculateVisbleLayers()
saveObjectStateVisibleLayers()
}
function panelSizePhysics() {
if (isInitialized === false || thisObject.isHidden === true) { return }
let viewPortHeight = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y
if (viewPortHeight < headerHeight) {
thisObject.visible = false
} else {
thisObject.visible = true
}
if (thisObject.visible === false) { return }
if (desiredPanelHeight > viewPortHeight) {
posibleVisibleLayers = Math.trunc((viewPortHeight - headerHeight - footerHeight) / (layerHeight + LAYER_SEPARATION))
} else {
posibleVisibleLayers = desiredVisibleLayers
}
if (thisObject.layers.length < posibleVisibleLayers) { posibleVisibleLayers = thisObject.layers.length }
if (posibleVisibleLayers === 0) {
posiblePanelHeight = (layerHeight + LAYER_SEPARATION) * posibleVisibleLayers + headerHeight
} else {
posiblePanelHeight = (layerHeight + LAYER_SEPARATION) * posibleVisibleLayers + headerHeight + footerHeight
}
thisObject.container.frame.height = posiblePanelHeight
}
function calculateVisbleLayers() {
panelSizePhysics()
let availableSlots = posibleVisibleLayers
if (firstVisibleLayer < 1) { firstVisibleLayer = 1 }
if (firstVisibleLayer > (thisObject.layers.length - availableSlots + 1)) { firstVisibleLayer = thisObject.layers.length - availableSlots + 1 }
visibleLayers = []
for (let i = 0; i < thisObject.layers.length; i++) {
if (i + 1 >= firstVisibleLayer && i + 1 < firstVisibleLayer + availableSlots) {
let layer = thisObject.layers[i]
layer.container.frame.position.x = 0
layer.container.frame.position.y = (layerHeight + LAYER_SEPARATION) * visibleLayers.length + headerHeight
/* Add to Visible Product Array */
visibleLayers.push(layer)
}
}
}
function onLayerStatusChanged(layer) {
thisObject.container.eventHandler.raiseEvent('Layer Status Changed', layer)
}
function getContainer(point, purpose) {
if (isInitialized === false || thisObject.visible === false || thisObject.isHidden === true) { return }
let container
if (isMouseOver === true && purpose !== GET_CONTAINER_PURPOSE.MOUSE_OVER) {
container = thisObject.upDownButton.getContainer(point)
if (container !== undefined) { return container }
container = thisObject.leftRightButton.getContainer(point)
if (container !== undefined) { return container }
}
/* First we check if thisObject point is inside thisObject space. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
/* Now we see which is the inner most container that has it */
for (let i = 0; i < visibleLayers.length; i++) {
container = visibleLayers[i].getContainer(point)
if (container !== undefined) {
let checkPoint = {
x: point.x,
y: point.y
}
checkPoint = thisObject.fitFunction(checkPoint)
if (point.x === checkPoint.x && point.y === checkPoint.y) {
if (purpose !== GET_CONTAINER_PURPOSE.MOUSE_OVER) {
return container
}
}
}
}
/* The point does not belong to any inner container, so we return the current container. */
let checkPoint = {
x: point.x,
y: point.y
}
checkPoint = thisObject.fitFunction(checkPoint)
if (point.x === checkPoint.x && point.y === checkPoint.y) {
return thisObject.container
}
}
}
function childrenPhysics() {
for (let i = 0; i < thisObject.layers.length; i++) {
let layer = thisObject.layers[i]
layer.physics()
}
}
function syncWithConfigPhysics() {
readObjectState()
}
function physics() {
if (isInitialized === false) { return }
if (thisObject.payload.node === undefined) { return }
thisObject.upDownButton.physics()
thisObject.leftRightButton.physics()
UI.projects.superalgos.utilities.loadSaveFrame.saveFrame(thisObject.payload, thisObject.container.frame)
syncWithConfigPhysics()
/*
The overall idea here is that we need to keep syncronized the panel with the layers that are
defined at the Designer. Users can connect or disconnect any objext resulting in changes in which
are valid layers and which not at any point in time. So what we do here is trying to keep the panel
only with the layers that are connected to the Charting Space hiriarcy.
To achieve this, first we are going to move all session related cards to a local array. Then we are
going to check for layers at the designer, and will move back the cards which still have layers well
defined to where they were.
If we find new layers we will add them at that point. Finally, the cards that still remain at the
local array after all the layers at the designer have been processed, are turned off and discarded.
*/
childrenPhysics()
let localLayers = []
moveToLocalLayers()
syncWithDesignerLayers()
/* At this poins all the cards still at the local array need to be removed from the panel. */
turnOffUnusedLayers()
calculateVisbleLayers()
function syncWithDesignerLayers() {
if (thisObject.payload.node === undefined) { return }
let layerManager = thisObject.payload.node
let layers = UI.projects.superalgos.utilities.branches.nodeBranchToArray(layerManager, 'Layer')
for (let p = 0; p < layers.length; p++) {
let layerNode = layers[p]
let found = removeFromLocalLayers(layerNode.id)
if (found !== true) {
let layer = addLayer(layerNode)
if (layer !== undefined) {
onLayerStatusChanged(layer)
}
}
}
}
function moveToLocalLayers() {
removeNext()
function removeNext() {
for (let i = 0; i < thisObject.layers.length; i++) {
let layer = thisObject.layers[i]
thisObject.layers.splice(i, 1)
localLayers.push(layer)
removeNext()
}
}
}
function removeFromLocalLayers(id) {
for (let i = 0; i < localLayers.length; i++) {
let layer = localLayers[i]
if (layer.payload === undefined) { continue }
if (layer.payload.node === undefined) { continue }
if (layer.payload.node.id === id) {
thisObject.layers.push(layer)
localLayers.splice(i, 1)
return true
}
}
}
function turnOffUnusedLayers() {
for (let i = 0; i < localLayers.length; i++) {
let layer = localLayers[i]
removeLayer(layer.nodeId)
}
}
}
function draw() {
if (isInitialized === false || thisObject.visible === false || thisObject.isHidden === true) { return }
// thisObject.container.frame.draw(false, false, false, thisObject.fitFunction)
drawHeader()
for (let i = 0; i < visibleLayers.length; i++) {
visibleLayers[i].draw()
}
drawScrollBar()
if (isMouseOver === true) {
thisObject.upDownButton.draw()
thisObject.leftRightButton.draw()
}
}
function drawHeader() {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.node === undefined) { return }
if (thisObject.payload.node.payload.parentNode === undefined) { return }
if (thisObject.payload.node.payload.parentNode.payload.parentNode === undefined) { return }
let label1 = thisObject.payload.node.payload.parentNode.payload.parentNode.name.substring(0, 18)
let label2 = thisObject.payload.node.payload.parentNode.name.substring(0, 18)
let label3 = ''
let icon1 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.payload.parentNode.payload.parentNode.project, thisObject.payload.node.payload.parentNode.payload.parentNode.type)
let icon2 = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(thisObject.payload.node.payload.parentNode.project, thisObject.payload.node.payload.parentNode.type)
let backgroundColor = UI_COLOR.BLACK
let params = {
cornerRadius: 5,
lineWidth: 1,
container: thisObject.container,
borderColor: UI_COLOR.RUSTED_RED,
castShadow: false,
backgroundColor: backgroundColor,
opacity: 1
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label1, 1 / 2, 0, 0, 15, 9, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label2, 1 / 2, 0, 0, 30, 9, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon1, 1 / 8, 0, 0, 20, 28, thisObject.container)
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon2, 7 / 8, 0, 0, 20, 28, thisObject.container)
}
function drawScrollBar() {
if (thisObject.layers.length > posibleVisibleLayers && posibleVisibleLayers > 0) {
let xOffset = 4
let barTopPoint = {
x: thisObject.container.frame.width - xOffset,
y: headerHeight
}
let barBottomPoint = {
x: thisObject.container.frame.width - xOffset,
y: thisObject.container.frame.height - footerHeight
}
let ratio = posibleVisibleLayers / thisObject.layers.length
let handleHeight = (posibleVisibleLayers * (layerHeight + LAYER_SEPARATION)) * ratio
let handleTopPoint = {
x: thisObject.container.frame.width - xOffset,
y: headerHeight + (layerHeight + LAYER_SEPARATION) * ratio * (firstVisibleLayer - 1)
}
let handleBottomPoint = {
x: thisObject.container.frame.width - xOffset,
y: handleTopPoint.y + handleHeight
}
barTopPoint = thisObject.container.frame.frameThisPoint(barTopPoint)
barBottomPoint = thisObject.container.frame.frameThisPoint(barBottomPoint)
handleTopPoint = thisObject.container.frame.frameThisPoint(handleTopPoint)
handleBottomPoint = thisObject.container.frame.frameThisPoint(handleBottomPoint)
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(barTopPoint.x, barTopPoint.y)
browserCanvasContext.lineTo(barBottomPoint.x, barBottomPoint.y)
browserCanvasContext.closePath()
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 1
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREY + ', ' + 1 + ')'
browserCanvasContext.stroke()
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(handleTopPoint.x, handleTopPoint.y)
browserCanvasContext.lineTo(handleBottomPoint.x, handleBottomPoint.y)
browserCanvasContext.closePath()
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 4
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + 1 + ')'
browserCanvasContext.stroke()
}
}
}
@@ -0,0 +1,243 @@
function newLeftRightButton() {
let thisObject = {
container: undefined,
fitFunction: undefined,
parentContainer: undefined,
status: undefined,
setStatus: setStatus,
physics: physics,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize,
finalize: finalize
}
let isInitialized = false
/* Cointainer stuff */
thisObject.container = newContainer()
thisObject.container.name = 'Left Right Button'
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.frame.containerName = 'Left Right Button'
thisObject.status = 'left'
let leftPosition = {}
let rightPosition = {}
let transitionPosition = {}
let onMouseClickEventSuscriptionId
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseClickEventSuscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.parentContainer = undefined
thisObject.status = undefined
leftPosition = undefined
rightPosition = undefined
transitionPosition = undefined
}
function initialize() {
thisObject.container.frame.width = 12
thisObject.container.frame.height = 12
let position = {
x: thisObject.container.frame.parentFrame.width * 2.25 / 8 - thisObject.container.frame.width / 2,
y: 40 * 4 / 8 - thisObject.container.frame.height / 2
}
thisObject.container.frame.position = position
leftPosition.x = thisObject.parentContainer.frame.position.x
leftPosition.y = thisObject.parentContainer.frame.position.y
rightPosition.x = thisObject.parentContainer.frame.position.x
rightPosition.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y
transitionPosition.x = leftPosition.x
transitionPosition.y = leftPosition.y
/* Lets listen to our own events to react when we have a Mouse Click */
onMouseClickEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
isInitialized = true
}
function setStatus(value) {
if (value === 'left' && thisObject.status === 'right') {
thisObject.status = 'going left'
}
if (value === 'right' && thisObject.status === 'left') {
thisObject.status = 'going right'
}
}
function onMouseClick(event) {
if (thisObject.status === 'left') {
transitionPosition.x = leftPosition.x
transitionPosition.y = leftPosition.y
thisObject.status = 'going right'
} else {
transitionPosition.x = rightPosition.x
transitionPosition.y = rightPosition.y
thisObject.status = 'going left'
}
}
function physics() {
if (isInitialized === false) { return }
leftPosition.x = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.x
leftPosition.y = thisObject.parentContainer.frame.position.y
rightPosition.x = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.x
rightPosition.y = thisObject.parentContainer.frame.position.y
if (thisObject.status === 'going right') {
if (transitionPosition.x < rightPosition.x) {
transitionPosition.x = transitionPosition.x + 50
thisObject.parentContainer.frame.position.x = transitionPosition.x
} else {
thisObject.parentContainer.frame.position.x = rightPosition.x
thisObject.status = 'right'
}
}
if (thisObject.status === 'going left') {
if (transitionPosition.x > leftPosition.x) {
transitionPosition.x = transitionPosition.x - 50
thisObject.parentContainer.frame.position.x = transitionPosition.x
} else {
thisObject.parentContainer.frame.position.x = leftPosition.x
thisObject.status = 'left'
}
}
}
function draw() {
if (isInitialized === false) { return }
drawButton()
}
function getContainer(point, purpose) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function drawButton() {
let point1
let point2
let point3
switch (thisObject.status) {
case 'left': {
point1 = {
x: 3,
y: 3
}
point2 = {
x: 3,
y: thisObject.container.frame.height - 3
}
point3 = {
x: thisObject.container.frame.width - 3,
y: thisObject.container.frame.height / 2
}
break
}
case 'going right': {
point1 = {
x: 4,
y: 4
}
point2 = {
x: 4,
y: thisObject.container.frame.height - 4
}
point3 = {
x: thisObject.container.frame.width - 4,
y: thisObject.container.frame.height / 2
}
break
}
case 'going left': {
point1 = {
x: thisObject.container.frame.width - 4,
y: 4
}
point2 = {
x: thisObject.container.frame.width - 4,
y: thisObject.container.frame.height - 4
}
point3 = {
x: 4,
y: thisObject.container.frame.height / 2
}
break
}
case 'right': {
point1 = {
x: thisObject.container.frame.width - 3,
y: 3
}
point2 = {
x: thisObject.container.frame.width - 3,
y: thisObject.container.frame.height - 3
}
point3 = {
x: 3,
y: thisObject.container.frame.height / 2
}
break
}
}
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
if (thisObject.fitFunction !== undefined) {
point1 = thisObject.fitFunction(point1)
point2 = thisObject.fitFunction(point2)
point3 = thisObject.fitFunction(point3)
}
/* Lets start the drawing. */
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.lineTo(point1.x, point1.y)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(250, 250, 250, 1)'
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
browserCanvasContext.fillStyle = 'rgba(250, 250, 250, 1)'
browserCanvasContext.fill()
}
}
@@ -0,0 +1,379 @@
/*
The Panel Space y the place wehre all panels live, no matter who create them.
*/
function newSuperalgosPanelSpace() {
let thisObject = {
visible: true,
container: undefined,
unHide: unHide,
hide: hide,
createNewPanel: createNewPanel,
destroyPanel: destroyPanel,
getPanel: getPanel,
physics: physics,
draw: draw,
panels: [],
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
}
let container = newContainer()
container.initialize()
thisObject.container = container
thisObject.container.isDraggeable = false
container.frame.containerName = 'Panels Space'
return thisObject
function initialize() {
/* The space does not create any Panels for itself, it just sits and waits others need panels. */
}
function createNewPanel(pType, pParameters, pOwner, pSession) {
let panel
switch (pType) {
case 'Layers Panel':
{
panel = newLayersPanel()
panel.fitFunction = UI.projects.superalgos.spaces.chartingSpace.fitFunction
panel.container.isVisibleFunction = UI.projects.superalgos.spaces.chartingSpace.isThisPointVisible
panel.type = 'Layers Panel'
break
}
case 'Plotter Panel':
{
if (pParameters.panelNode.config.isLegacy !== true) {
panel = newPlotterPanel()
panel.fitFunction = UI.projects.superalgos.spaces.chartingSpace.fitFunction
panel.container.isVisibleFunction = UI.projects.superalgos.spaces.chartingSpace.isThisPointVisible
panel.session = pSession
panel.initialize(pParameters.panelNode)
} else {
panel = getNewPlotterPanel(pParameters.dataMine, pParameters.plotterCodeName, pParameters.moduleCodeName, pParameters.panelNode.config.codeName)
panel.fitFunction = UI.projects.superalgos.spaces.chartingSpace.fitFunction
panel.container.isVisibleFunction = UI.projects.superalgos.spaces.chartingSpace.isThisPointVisible
panel.session = pSession
panel.initialize()
}
panel.type = 'Plotter Panel'
break
}
}
panel.owner = pOwner
thisObject.panels.push(panel)
panel.handle = newUniqueId()
return panel.handle
}
function unHide(owner, type) {
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = thisObject.panels[i]
if (panel.owner === owner && panel.type === type) {
panel.isHidden = false
}
}
}
function hide(owner, type) {
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = thisObject.panels[i]
if (panel.owner === owner && panel.type === type) {
panel.isHidden = true
}
}
}
function destroyPanel(pPanelHandle) {
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = thisObject.panels[i]
if (panel.handle === pPanelHandle) {
if (panel.finalize !== undefined) {
panel.finalize()
}
thisObject.panels.splice(i, 1) // Delete item from array.
return
}
}
}
function getPanel(pPanelHandle) {
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = thisObject.panels[i]
if (panel.handle === pPanelHandle) {
return panel
}
}
}
function physics() {
if (thisObject.visible !== true) { return }
childrenPhysics()
positioningPhysics()
}
function childrenPhysics() {
if (thisObject.panels !== undefined) {
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = thisObject.panels[i]
let owner = UI.projects.superalgos.spaces.chartingSpace.inViewport.get(panel.owner)
if (owner !== undefined) {
if (panel.physics !== undefined) {
panel.physics()
}
}
}
}
}
function positioningPhysics() {
if (thisObject.panels !== undefined) {
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = thisObject.panels[i]
if (panel.isVisible === false || panel.isHidden === true) { continue }
/* setting the speed of the panel */
if (panel.container.speed === undefined) {
panel.container.speed = {
x: 2,
y: 2
}
}
/* Trying to move the panel and see if it is possible */
let centerPoint = {
x: panel.container.frame.position.x,
y: panel.container.frame.position.y
}
centerPoint.x = centerPoint.x + panel.container.frame.width / 2
centerPoint.y = centerPoint.y + panel.container.frame.height / 2
/* Lets see which quadrant the panel is at */
let verticalLine = (UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.x - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.x) / 2 + UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.x
let horizontalLine = (UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.y) / 2 + UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.y
if (panel.upDownButton !== undefined) {
if (panel.upDownButton.status === 'up') {
if (panel.leftRightButton !== undefined) {
if (panel.leftRightButton.status === 'left') {
panel.gravitatesTowards = 'topLeft'
} else {
panel.gravitatesTowards = 'topRight'
}
} else {
if (centerPoint.x < verticalLine) {
panel.gravitatesTowards = 'topLeft'
} else {
panel.gravitatesTowards = 'topRight'
}
}
} else {
if (panel.leftRightButton !== undefined) {
if (panel.leftRightButton.status === 'left') {
panel.gravitatesTowards = 'bottomLeft'
} else {
panel.gravitatesTowards = 'bottomRight'
}
} else {
if (centerPoint.x < verticalLine) {
panel.gravitatesTowards = 'bottomLeft'
} else {
panel.gravitatesTowards = 'bottomRight'
}
}
}
} else {
if (centerPoint.x < verticalLine && centerPoint.y < horizontalLine) {
panel.gravitatesTowards = 'topLeft'
}
if (centerPoint.x >= verticalLine && centerPoint.y < horizontalLine) {
panel.gravitatesTowards = 'topRight'
}
if (centerPoint.x < verticalLine && centerPoint.y >= horizontalLine) {
panel.gravitatesTowards = 'bottomLeft'
}
if (centerPoint.x >= verticalLine && centerPoint.y >= horizontalLine) {
panel.gravitatesTowards = 'bottomRight'
}
}
/* According to the quadrant we push the panels to the sides */
if (panel.gravitatesTowards === 'topLeft' || panel.gravitatesTowards === 'bottomLeft') {
panel.container.frame.position.x = panel.container.frame.position.x - panel.container.speed.x
if (panel.leftRightButton !== undefined) {
if (panel.leftRightButton.status === 'left' || panel.leftRightButton.status === 'right') { // we avoid pushing other panels while in transition
}
}
isOverlapping(i, panel.container)
if (panel.container.frame.position.x < 0) {
panel.container.frame.position.x = 0
}
} else {
panel.container.frame.position.x = panel.container.frame.position.x + panel.container.speed.x
isOverlapping(i, panel.container)
if (panel.container.frame.position.x + panel.container.frame.width > browserCanvas.width) {
panel.container.frame.position.x = browserCanvas.width - panel.container.frame.width
}
}
if (panel.container.frame.height <= UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.y) {
if (panel.gravitatesTowards === 'topLeft' || panel.gravitatesTowards === 'topRight') {
panel.container.frame.position.y = panel.container.frame.position.y - panel.container.speed.y
isOverlapping(i, panel.container)
if (panel.container.frame.position.y < UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y) {
panel.container.frame.position.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topLeft.y
}
} else {
panel.container.frame.position.y = panel.container.frame.position.y + panel.container.speed.y
isOverlapping(i, panel.container)
if (panel.container.frame.position.y + panel.container.frame.height > UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y) {
panel.container.frame.position.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y - panel.container.frame.height
}
}
}
}
}
function isOverlapping(currentIndex, currentContainer) {
let corner1 = {
x: currentContainer.frame.position.x,
y: currentContainer.frame.position.y
}
let corner2 = {
x: currentContainer.frame.position.x + currentContainer.frame.width,
y: currentContainer.frame.position.y
}
let corner3 = {
x: currentContainer.frame.position.x + currentContainer.frame.width,
y: currentContainer.frame.position.y + currentContainer.frame.height
}
let corner4 = {
x: currentContainer.frame.position.x,
y: currentContainer.frame.position.y + currentContainer.frame.height
}
for (let i = 0; i < currentIndex; i++) {
let panel = thisObject.panels[i]
if (panel.leftRightButton !== undefined) {
if (panel.leftRightButton.status !== 'left' && panel.leftRightButton.status !== 'right') { // we avoid pushing other panels while in transition
continue
}
}
if (panel.isVisible === true && panel.isHidden === false) {
if (isThisPointInsideThisFrame(corner1, panel.container.frame) === true) {
pushOut(currentContainer, panel.container, panel.gravitatesTowards)
}
if (isThisPointInsideThisFrame(corner2, panel.container.frame) === true) {
pushOut(currentContainer, panel.container, panel.gravitatesTowards)
}
if (isThisPointInsideThisFrame(corner3, panel.container.frame) === true) {
pushOut(currentContainer, panel.container, panel.gravitatesTowards)
}
if (isThisPointInsideThisFrame(corner4, panel.container.frame) === true) {
pushOut(currentContainer, panel.container, panel.gravitatesTowards)
}
}
}
function pushOut(currentContainer, controlContainer, corner) {
switch (corner) {
case 'topLeft': {
currentContainer.frame.position.x = controlContainer.frame.position.x + controlContainer.frame.width
break
}
case 'topRight': {
currentContainer.frame.position.x = controlContainer.frame.position.x - currentContainer.frame.width
break
}
case 'bottomLeft': {
currentContainer.frame.position.x = controlContainer.frame.position.x + controlContainer.frame.width
break
}
case 'bottomRight': {
currentContainer.frame.position.x = controlContainer.frame.position.x - currentContainer.frame.width
break
}
}
}
function isThisPointInsideThisFrame(point, frame) {
let corner1 = {
x: frame.position.x,
y: frame.position.y
}
let corner2 = {
x: frame.position.x + frame.width,
y: frame.position.y
}
let corner3 = {
x: frame.position.x + frame.width,
y: frame.position.y + frame.height
}
let corner4 = {
x: frame.position.x,
y: frame.position.y + frame.height
}
if (point.x >= corner1.x && point.y >= corner1.y && point.x <= corner3.x && point.y <= corner3.y) {
return true
} else {
return false
}
}
return false
}
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
if (thisObject.visible !== true) { return }
thisObject.container.frame.draw(false, false)
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = thisObject.panels[i]
let owner = UI.projects.superalgos.spaces.chartingSpace.inViewport.get(panel.owner)
if (owner !== undefined) {
if (panel.isVisible === true && panel.isHidden === false) {
panel.draw()
}
}
}
}
function getContainer(point, purpose) {
if (thisObject.visible !== true) { return }
if (purpose === GET_CONTAINER_PURPOSE.DRAGGING && point.shiftKey !== false) {return}
let container
/*
We search for the container of panels in the oposite direction than we do it for drawing them,
so panels overlapping others are picked firt although they are drawn last.
*/
for (let i = thisObject.panels.length - 1; i >= 0; i--) {
let panel = thisObject.panels[i]
let owner = UI.projects.superalgos.spaces.chartingSpace.inViewport.get(panel.owner)
if (owner !== undefined) {
if (panel.isVisible === true && panel.isHidden === false) {
container = panel.getContainer(point, purpose)
}
}
if (container !== undefined) {
container.space = 'Panels Space'
return container
}
}
// thisObject.container.space = 'Panels Space'
// return thisObject.container
}
}
@@ -0,0 +1,84 @@
function newPanelsVisibleButton() {
let thisObject = {
container: undefined,
fitFunction: undefined,
parentContainer: undefined,
panels: undefined,
showPanels: true,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize,
finalize: finalize
}
/* Cointainer stuff */
thisObject.container = newContainer()
thisObject.container.name = 'Panels Visible Button'
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.frame.containerName = 'Panels Visible Button'
let onMouseClickEventSuscriptionId
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseClickEventSuscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.parentContainer = undefined
thisObject.panels = undefined
}
function initialize(panels) {
thisObject.panels = panels
setPanelVisibility()
thisObject.container.frame.width = 25
thisObject.container.frame.height = 25
let position = {
x: thisObject.container.frame.width * 1 / 8,
y: 45
}
thisObject.container.frame.position = position
/* Lets listen to our own events to react when we have a Mouse Click */
onMouseClickEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
}
function onMouseClick(event) {
if (thisObject.showPanels === false) {
thisObject.showPanels = true
} else {
thisObject.showPanels = false
}
setPanelVisibility()
}
function setPanelVisibility() {
for (let i = 0; i < thisObject.panels.length; i++) {
let panel = UI.projects.superalgos.spaces.panelSpace.getPanel(thisObject.panels[i])
panel.isVisible = thisObject.showPanels
}
}
function getContainer(point) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function draw() {
let icon
if (thisObject.showPanels === true) {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'plotter-panel')
} else {
icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndName( 'Superalgos', 'toggle-panel-off')
}
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon, 1 / 2, 1 / 2, 0, 0, 14, thisObject.container)
}
}
@@ -0,0 +1,183 @@
function newPlotterPanel() {
const MODULE_NAME = 'Plotter Panel'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
fitFunction: undefined,
container: undefined,
isVisible: true,
onRecordChange: onRecordChange,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize('Plotter Panel')
let heightFactor = 1
let currentRecord
let upDownButton
let panelNode
return thisObject
function finalize() {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.isVisible = undefined
heightFactor = undefined
currentRecord = undefined
upDownButton.finalize()
upDownButton = undefined
panelNode = undefined
}
function initialize(pPanelNode) {
panelNode = pPanelNode
thisObject.container.frame.containerName = panelNode.name
thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL
thisObject.container.frame.position.x = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width - thisObject.container.frame.width * Math.random() * 8
thisObject.container.frame.position.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y - thisObject.container.frame.height - thisObject.container.frame.height * Math.random() * 1.5
upDownButton = newUpDownButton()
upDownButton.parentContainer = thisObject.container
upDownButton.container.frame.parentFrame = thisObject.container.frame
upDownButton.fitFunction = thisObject.fitFunction
upDownButton.initialize()
}
function getContainer(point) {
if (thisObject.isVisible !== true) { return }
let container
container = upDownButton.getContainer(point)
if (container !== undefined) { return container }
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
let checkPoint = {
x: point.x,
y: point.y
}
checkPoint = thisObject.fitFunction(checkPoint)
if (point.x === checkPoint.x && point.y === checkPoint.y) {
return thisObject.container
}
}
}
function onRecordChange(pCurrentRecord) {
currentRecord = pCurrentRecord
}
function draw() {
if (thisObject.isVisible !== true) { return }
thisObject.container.frame.draw(false, false, true, thisObject.fitFunction)
plotCurrentRecordData()
upDownButton.draw()
}
function plotCurrentRecordData() {
const frameBodyHeight = thisObject.container.frame.getBodyHeight()
const frameTitleHeight = thisObject.container.frame.height - frameBodyHeight
const X_AXIS = thisObject.container.frame.width / 2
const Y_AXIS = frameTitleHeight + frameBodyHeight / 2
const PANEL_HEIGHT = UI_PANEL.HEIGHT.NORMAL
if (currentRecord === undefined) { return }
let record = currentRecord
/* First we execute code if provided. */
if (panelNode.javascriptCode !== undefined) {
try {
eval(panelNode.javascriptCode.code)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] plotCurrentRecordData -> err = ' + err.stack) }
if (ERROR_LOG === true) { logger.write('[ERROR] plotCurrentRecordData -> javascriptCode.code = ' + panelNode.javascriptCode.code) }
}
}
/* Second we go through the panel data. */
if (panelNode.panelData === undefined) { return }
for (let i = 0; i < panelNode.panelData.length; i++) {
let panelData = panelNode.panelData[i]
let labelText = panelData.name
let labelPosition = i * 10 + 12
let valuePosition = i * 10 + 17
let value = 'No value defined.'
if (valuePosition > 100) {
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * 1.25
}
if (valuePosition > 125) {
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * 1.50
}
if (valuePosition > 150) {
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * 1.75
}
if (valuePosition > 175) {
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * 2.00
}
if (panelData.dataFormula !== undefined) {
try {
value = eval(panelData.dataFormula.code)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] plotCurrentRecordData -> err = ' + err.stack) }
if (ERROR_LOG === true) { logger.write('[ERROR] plotCurrentRecordData -> dataFormula.code = ' + panelData.dataFormula.code) }
}
}
if (panelData.config.valueDecimals !== undefined) {
if (value !== undefined) {
if (isNaN(value) === false) {
value = dynamicDecimals(value, panelData.config.valueDecimals)
}
}
}
if (panelData.config.labelText !== undefined) {
labelText = panelData.config.labelText
}
if (panelData.config.labelPosition !== undefined) {
labelPosition = panelData.config.labelPosition
}
if (panelData.config.valuePosition !== undefined) {
valuePosition = panelData.config.valuePosition
}
let opacity = '1.00'
let fontSize = 14
let paletteColor
if (panelData.textStyle !== undefined) {
if (panelData.textStyle.config.fontSize !== undefined) { fontSize = panelData.textStyle.config.fontSize }
if (panelData.textStyle.config.opacity !== undefined) { opacity = panelData.textStyle.config.opacity }
if (panelData.textStyle.config.paletteColor !== undefined) { paletteColor = eval(panelData.textStyle.config.paletteColor) }
}
UI.projects.superalgos.utilities.drawPrint.printLabel(labelText, X_AXIS, UI_PANEL.HEIGHT.NORMAL * labelPosition / 100 / heightFactor, '0.60', undefined, undefined, true, thisObject.container, thisObject.fitFunction)
UI.projects.superalgos.utilities.drawPrint.printLabel(value, X_AXIS, UI_PANEL.HEIGHT.NORMAL * valuePosition / 100 / heightFactor, opacity, fontSize, paletteColor, true, thisObject.container, thisObject.fitFunction, false, true)
}
}
}
@@ -0,0 +1,244 @@
function newUpDownButton() {
let thisObject = {
container: undefined,
fitFunction: undefined,
parentContainer: undefined,
status: undefined,
setStatus: setStatus,
physics: physics,
draw: draw,
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize,
finalize: finalize
}
let isInitialized = false
/* Cointainer stuff */
thisObject.container = newContainer()
thisObject.container.name = 'Up Down Button'
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.frame.containerName = 'Up Down Button'
thisObject.status = 'up'
let upPosition = {}
let downPosition = {}
let transitionPosition = {}
let onMouseClickEventSuscriptionId
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseClickEventSuscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.parentContainer = undefined
thisObject.status = undefined
upPosition = undefined
downPosition = undefined
transitionPosition = undefined
}
function initialize() {
thisObject.container.frame.width = 12
thisObject.container.frame.height = 12
let position = {
x: thisObject.container.frame.parentFrame.width * 5.75 / 8 - thisObject.container.frame.width / 2,
y: 40 * 4 / 8 - thisObject.container.frame.height / 2
}
thisObject.container.frame.position = position
upPosition.x = thisObject.parentContainer.frame.position.x
upPosition.y = thisObject.parentContainer.frame.position.y
downPosition.x = thisObject.parentContainer.frame.position.x
downPosition.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y
transitionPosition.x = upPosition.x
transitionPosition.y = upPosition.y
/* Lets listen to our own events to react when we have a Mouse Click */
onMouseClickEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
isInitialized = true
}
function setStatus(value) {
if (value === 'up' && thisObject.status === 'down') {
thisObject.status = 'going up'
}
if (value === 'down' && thisObject.status === 'up') {
thisObject.status = 'going down'
}
}
function onMouseClick(event) {
if (thisObject.status === 'up') {
transitionPosition.x = upPosition.x
transitionPosition.y = upPosition.y
thisObject.status = 'going down'
} else {
transitionPosition.x = downPosition.x
transitionPosition.y = downPosition.y
thisObject.status = 'going up'
}
}
function physics() {
if (isInitialized === false) { return }
upPosition.x = thisObject.parentContainer.frame.position.x
upPosition.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.topRight.y
downPosition.x = thisObject.parentContainer.frame.position.x
downPosition.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomRight.y
if (thisObject.status === 'going down') {
if (transitionPosition.y < downPosition.y) {
transitionPosition.y = transitionPosition.y + 50
thisObject.parentContainer.frame.position.y = transitionPosition.y
} else {
thisObject.parentContainer.frame.position.y = downPosition.y
thisObject.status = 'down'
}
}
if (thisObject.status === 'going up') {
if (transitionPosition.y > upPosition.y) {
transitionPosition.y = transitionPosition.y - 50
thisObject.parentContainer.frame.position.y = transitionPosition.y
} else {
thisObject.parentContainer.frame.position.y = upPosition.y
thisObject.status = 'up'
}
}
}
function draw() {
if (isInitialized === false) { return }
drawButton()
}
function getContainer(point, purpose) {
let container
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function drawButton() {
let point1
let point2
let point3
switch (thisObject.status) {
case 'up': {
point1 = {
x: 3,
y: 3
}
point2 = {
x: thisObject.container.frame.width - 3,
y: 3
}
point3 = {
x: thisObject.container.frame.width / 2,
y: thisObject.container.frame.height - 3
}
break
}
case 'going down': {
point1 = {
x: 4,
y: 4
}
point2 = {
x: thisObject.container.frame.width - 4,
y: 4
}
point3 = {
x: thisObject.container.frame.width / 2,
y: thisObject.container.frame.height - 4
}
break
}
case 'going up': {
point1 = {
x: 4,
y: thisObject.container.frame.height - 4
}
point2 = {
x: thisObject.container.frame.width - 4,
y: thisObject.container.frame.height - 4
}
point3 = {
x: thisObject.container.frame.width / 2,
y: 4
}
break
}
case 'down': {
point1 = {
x: 3,
y: thisObject.container.frame.height - 3
}
point2 = {
x: thisObject.container.frame.width - 3,
y: thisObject.container.frame.height - 3
}
point3 = {
x: thisObject.container.frame.width / 2,
y: 3
}
break
}
}
/* Now the transformations. */
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
if (thisObject.fitFunction !== undefined) {
point1 = thisObject.fitFunction(point1)
point2 = thisObject.fitFunction(point2)
point3 = thisObject.fitFunction(point3)
}
/* Lets start the drawing. */
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.lineTo(point1.x, point1.y)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(250, 250, 250, 1)'
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
browserCanvasContext.fillStyle = 'rgba(250, 250, 250, 1)'
browserCanvasContext.fill()
}
}
@@ -0,0 +1,109 @@
function newListItem() {
const MODULE_NAME = 'List Item'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
container: undefined,
fitFunction: undefined,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize()
thisObject.container.isDraggeable = false
thisObject.container.isWheelable = false
thisObject.container.detectMouseOver = true
thisObject.container.isClickeable = true
thisObject.container.frame.width = SIDE_PANEL_WIDTH * 0.75
thisObject.container.frame.height = SIDE_PANEL_WIDTH * 0.75
let name
let project
let type
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
let onMouseClickEventSubscriptionId
let isMouseOver = false
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(onMouseClickEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
}
function initialize(pName, pProject, pType) {
name = pName
project = pProject
type = pType
onMouseOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
onMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
}
function getContainer(point) {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
}
}
function onMouseOver(event) {
isMouseOver = true
}
function onMouseNotOver() {
isMouseOver = false
}
function onMouseClick(event) {
UI.projects.superalgos.spaces.designSpace.workspace.replaceWorkspaceByLoadingOne(name)
}
function physics() {
}
function draw() {
let icon = UI.projects.superalgos.spaces.designSpace.getIconByProjectAndType(project, type)
let backgroundColor = UI_COLOR.BLACK
let labelColor
const RED_LINE_HIGHT = 4
const OPACITY = 1
let params = {
cornerRadius: 0,
lineWidth: 1,
container: thisObject.container,
borderColor: UI_COLOR.RUSTED_RED,
castShadow: false,
backgroundColor: backgroundColor,
opacity: OPACITY
}
if (isMouseOver === false) {
labelColor = UI_COLOR.WHITE
} else {
labelColor = UI_COLOR.TITANIUM_YELLOW
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
UI.projects.superalgos.utilities.drawPrint.drawLabel(name, 1 / 2, 3.0 / 10, -5, 0, 15, thisObject.container, labelColor)
UI.projects.superalgos.utilities.drawPrint.drawLabel(type, 1 / 2, 7.2 / 10, -5, 0, 15, thisObject.container, labelColor)
UI.projects.superalgos.utilities.drawPrint.drawIcon(icon, 1 / 2, 1 / 2, 0, 0, 80, thisObject.container)
}
}
@@ -0,0 +1,269 @@
function newListView() {
const MODULE_NAME = 'List View'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
fitFunction: undefined,
container: undefined,
listItems: [],
payload: undefined,
isVisible: false,
resize: resize,
turnOn: turnOn,
turnOff: turnOff,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize()
thisObject.container.isDraggeable = false
thisObject.container.isWheelable = true
thisObject.container.detectMouseOver = true
let isInitialized = false
let listItemsMap = new Map()
let visibleListItems = []
let firstVisibleListItem
let headerHeight = 40
let footerHeight = 30
let listItemHeight = SIDE_PANEL_WIDTH * 0.75
let posibleVisibleListItems
let itemSeparation
let onMouseWheelEventSuscriptionId
return thisObject
function finalize() {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSuscriptionId)
listItemsMap = undefined
visibleListItems = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject = undefined
}
function initialize() {
thisObject.container.name = MODULE_NAME
thisObject.container.frame.containerName = thisObject.container.name
thisObject.container.frame.width = SIDE_PANEL_WIDTH * 0.75
let position = { // Default position
x: SIDE_PANEL_WIDTH * 0.25 / 2,
y: 20
}
thisObject.container.frame.position = position
onMouseWheelEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
resize()
turnOn()
}
function resize() {
thisObject.container.frame.height = browserCanvas.height - thisObject.container.frame.position.y * 2
let spaceForListItems = (thisObject.container.frame.height - headerHeight - footerHeight)
posibleVisibleListItems = Math.trunc(spaceForListItems / (listItemHeight))
if ((posibleVisibleListItems - 1) !== 0) {
itemSeparation = (spaceForListItems - listItemHeight * posibleVisibleListItems) / (posibleVisibleListItems - 1)
} else {
itemSeparation = 0
}
}
function turnOn() {
firstVisibleListItem = 1
callWebServer(undefined, 'ListWorkspaces', onResponse)
function onResponse(err, text) {
if (err && err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> Could not load the list of your workspaces from the backend. ') }
return
}
let workspacelist = JSON.parse(text)
thisObject.listItems = []
for (let i = 0; i < workspacelist.length; i++) {
let workspace = workspacelist[i].replace('.json', '')
let listItem = newListItem()
listItem.initialize(workspace, 'Superalgos', 'Workspace')
listItem.container.connectToParent(thisObject.container, false, false)
thisObject.listItems.push(listItem)
}
calculateVisbleListItems()
isInitialized = true
thisObject.isVisible = true
}
}
function turnOff() {
thisObject.isVisible = false
}
function onMouseWheel(event) {
delta = event.wheelDelta
if (delta > 0) {
delta = -1
} else {
delta = 1
}
firstVisibleListItem = firstVisibleListItem + delta
calculateVisbleListItems()
}
function calculateVisbleListItems() {
let availableSlots = Math.trunc(posibleVisibleListItems)
if (firstVisibleListItem < 1) { firstVisibleListItem = 1 }
if (firstVisibleListItem > (thisObject.listItems.length - availableSlots + 1)) { firstVisibleListItem = thisObject.listItems.length - availableSlots + 1 }
visibleListItems = []
for (let i = 0; i < thisObject.listItems.length; i++) {
if (i + 1 >= firstVisibleListItem && i + 1 < firstVisibleListItem + availableSlots) {
let listItem = thisObject.listItems[i]
listItem.container.frame.position.x = 0
listItem.container.frame.position.y = (listItemHeight + itemSeparation) * visibleListItems.length + headerHeight
/* Add to Visible Product Array */
visibleListItems.push(listItem)
}
}
}
function getContainer(point, purpose) {
if (isInitialized === false || thisObject.isVisible === false) { return }
let container
/* First we check if thisObject point is inside thisObject space. */
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
/* Now we see which is the inner most container that has it */
for (let i = 0; i < visibleListItems.length; i++) {
container = visibleListItems[i].getContainer(point)
if (container !== undefined) {
if (container.isForThisPurpose(purpose) === true) {
return container
}
}
}
return thisObject.container
}
}
function childrenPhysics() {
for (let i = 0; i < thisObject.listItems.length; i++) {
let listItem = thisObject.listItems[i]
listItem.physics()
}
}
function physics() {
if (isInitialized === false || thisObject.isVisible === false) { return }
childrenPhysics()
}
function draw() {
if (isInitialized === false || thisObject.isVisible === false) { return }
drawBackground()
drawChildren()
drawScrollBar()
}
function drawChildren() {
for (let i = 0; i < visibleListItems.length; i++) {
let listItem = visibleListItems[i]
if (listItem !== undefined) {
listItem.draw()
}
}
}
function drawBackground() {
let label = 'Available Workspaces'
let backgroundColor = UI_COLOR.WHITE
let params = {
cornerRadius: 5,
lineWidth: 1,
container: thisObject.container,
borderColor: UI_COLOR.RUSTED_RED,
castShadow: false,
backgroundColor: backgroundColor,
opacity: 1
}
UI.projects.superalgos.utilities.drawPrint.roundedCornersBackground(params)
UI.projects.superalgos.utilities.drawPrint.drawLabel(label, 1 / 2, 0, 0, 25, 15, thisObject.container, UI_COLOR.BLACK)
}
function drawScrollBar() {
if (thisObject.listItems.length > posibleVisibleListItems && posibleVisibleListItems > 0) {
let xOffset = 4
let barTopPoint = {
x: thisObject.container.frame.width - xOffset,
y: headerHeight
}
let barBottomPoint = {
x: thisObject.container.frame.width - xOffset,
y: thisObject.container.frame.height - footerHeight
}
let ratio = (posibleVisibleListItems * listItemHeight + (posibleVisibleListItems - 1) * itemSeparation) / (thisObject.listItems.length * listItemHeight + (thisObject.listItems.length - 1) * itemSeparation)
let handleHeight = posibleVisibleListItems * (listItemHeight * ratio) + (posibleVisibleListItems - 1) * itemSeparation * ratio
let handleTopPoint = {
x: thisObject.container.frame.width - xOffset,
y: headerHeight + (listItemHeight * ratio * (firstVisibleListItem - 1) + itemSeparation * ratio * (firstVisibleListItem - 1))
}
let handleBottomPoint = {
x: thisObject.container.frame.width - xOffset,
y: handleTopPoint.y + handleHeight
}
barTopPoint = thisObject.container.frame.frameThisPoint(barTopPoint)
barBottomPoint = thisObject.container.frame.frameThisPoint(barBottomPoint)
handleTopPoint = thisObject.container.frame.frameThisPoint(handleTopPoint)
handleBottomPoint = thisObject.container.frame.frameThisPoint(handleBottomPoint)
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(barTopPoint.x, barTopPoint.y)
browserCanvasContext.lineTo(barBottomPoint.x, barBottomPoint.y)
browserCanvasContext.closePath()
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 1
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREY + ', ' + 1 + ')'
browserCanvasContext.stroke()
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(handleTopPoint.x, handleTopPoint.y)
browserCanvasContext.lineTo(handleBottomPoint.x, handleBottomPoint.y)
browserCanvasContext.closePath()
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.lineWidth = 4
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + 1 + ')'
browserCanvasContext.stroke()
}
}
}
@@ -0,0 +1,336 @@
function newSidePanelTab() {
const MODULE_NAME = 'Side Panel Tab'
let thisObject = {
screenside: undefined,
pointerDirection: undefined,
container: undefined,
index: 0,
open: open,
close: close,
resize: resize,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize
}
const TAB_WIDTH = 25
const TAB_HEIGHT = TOP_SPACE_HEIGHT * 2
const ANIMATION_STEP = 100
let isInitialized = false
let animation = 'none'
let ORIGINAL_PARENT_POSITON
let xOffset = 0
thisObject.container = newContainer()
thisObject.container.name = MODULE_NAME
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
return thisObject
function initialize(screenside, index) {
thisObject.screenside = screenside
if (index !== undefined) {
thisObject.index = index
}
switch (thisObject.screenside) {
case 'left': {
thisObject.pointerDirection = 'left'
break
}
case 'right': {
thisObject.pointerDirection = 'right'
break
}
}
thisObject.container.frame.width = TAB_WIDTH
thisObject.container.frame.height = TAB_HEIGHT
thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
resize()
isInitialized = true
}
function resize() {
switch (thisObject.screenside) {
case 'left': {
thisObject.container.frame.position.x = 0 + thisObject.container.parentContainer.frame.width
break
}
case 'right': {
thisObject.container.frame.position.x = 0 - TAB_WIDTH
break
}
}
ORIGINAL_PARENT_POSITON = thisObject.container.parentContainer.frame.position.x
setClosed()
}
function open() {
animation = 'opening'
thisObject.container.eventHandler.raiseEvent('opening')
}
function close() {
animation = 'closing'
thisObject.container.eventHandler.raiseEvent('closing')
}
function onMouseClick(event) {
switch (thisObject.screenside) {
case 'left': {
if (thisObject.pointerDirection === 'left') {
animation = 'opening'
thisObject.container.eventHandler.raiseEvent('opening')
} else {
animation = 'closing'
thisObject.container.eventHandler.raiseEvent('closing')
}
break
}
case 'right': {
if (thisObject.pointerDirection === 'left') {
animation = 'closing'
thisObject.container.eventHandler.raiseEvent('closing')
} else {
animation = 'opening'
thisObject.container.eventHandler.raiseEvent('opening')
}
break
}
}
}
function getContainer(point) {
let container
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
} else {
return undefined
}
}
function physics() {
if (isInitialized === false) { return }
positionPhysics()
animate()
}
function positionPhysics() {
if (UI.projects.superalgos.spaces.chartingSpace.viewport !== undefined) {
thisObject.container.frame.position.y = browserCanvas.height / 2 - TAB_HEIGHT / 2 // TOP_SPACE_HEIGHT + UI.projects.superalgos.spaces.chartingSpace.viewport.marginAmount + TAB_HEIGHT * thisObject.index
}
}
function draw() {
if (isInitialized === false) { return }
borders()
arrow()
}
function animate() {
if (animation === 'opening') {
xOffset = xOffset + ANIMATION_STEP
switch (thisObject.screenside) {
case 'left': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON + xOffset
break
}
case 'right': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON - xOffset
break
}
}
if (xOffset >= thisObject.container.parentContainer.frame.width) {
setOpened()
thisObject.container.eventHandler.raiseEvent('opened')
}
}
if (animation === 'closing') {
xOffset = xOffset - ANIMATION_STEP
switch (thisObject.screenside) {
case 'left': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON + xOffset
break
}
case 'right': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON - xOffset
break
}
}
if (xOffset <= 0) {
setClosed()
thisObject.container.eventHandler.raiseEvent('closed')
}
}
}
function setOpened() {
animation = 'none'
xOffset = thisObject.container.parentContainer.frame.width
thisObject.container.parentContainer.status = 'visible'
switch (thisObject.screenside) {
case 'left': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON + xOffset
thisObject.pointerDirection = 'right'
break
}
case 'right': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON - xOffset
thisObject.pointerDirection = 'left'
break
}
}
}
function setClosed() {
animation = 'none'
xOffset = 0
thisObject.container.parentContainer.status = 'hidden'
switch (thisObject.screenside) {
case 'left': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON
thisObject.pointerDirection = 'left'
break
}
case 'right': {
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON
thisObject.pointerDirection = 'right'
break
}
}
}
function arrow() {
let point1
let point2
let point3
if (thisObject.pointerDirection === 'left') {
point1 = {
x: TAB_WIDTH * 3.5 / 10,
y: TAB_HEIGHT * 12.5 / 30
}
point2 = {
x: TAB_WIDTH * 6.5 / 10,
y: TAB_HEIGHT * 15 / 30
}
point3 = {
x: TAB_WIDTH * 3.5 / 10,
y: TAB_HEIGHT * 17.5 / 30
}
} else {
point1 = {
x: TAB_WIDTH * 6.5 / 10,
y: TAB_HEIGHT * 12.5 / 30
}
point2 = {
x: TAB_WIDTH * 3.5 / 10,
y: TAB_HEIGHT * 15 / 30
}
point3 = {
x: TAB_WIDTH * 6.5 / 10,
y: TAB_HEIGHT * 17.5 / 30
}
}
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.closePath()
let opacity = 1
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREY + ', ' + opacity + ''
browserCanvasContext.fill()
}
function borders() {
let point1
let point2
let point3
let point4
point1 = {
x: 0,
y: 0
}
point2 = {
x: TAB_WIDTH,
y: 0
}
point3 = {
x: TAB_WIDTH,
y: TAB_HEIGHT
}
point4 = {
x: 0,
y: TAB_HEIGHT
}
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
point4 = thisObject.container.frame.frameThisPoint(point4)
let opacity
/* Shadow */
for (let i = 0; i <= 5; i++) {
opacity = 1 - (i / 100) - 0.93
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x + i, point1.y + i)
browserCanvasContext.lineTo(point2.x + i, point2.y + i)
browserCanvasContext.lineTo(point3.x + i, point3.y + i)
browserCanvasContext.lineTo(point4.x + i, point4.y + i)
browserCanvasContext.lineTo(point1.x + i, point1.y + i)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', ' + opacity + ''
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
}
/* Background and Border */
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
browserCanvasContext.lineTo(point1.x, point1.y)
browserCanvasContext.closePath()
opacity = 1
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ''
browserCanvasContext.fill()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREY + ', ' + opacity + ''
browserCanvasContext.lineWidth = 0.3
browserCanvasContext.stroke()
}
}
@@ -0,0 +1,168 @@
function newSuperalgosSideSpace() {
const MODULE_NAME = 'Side Space'
let thisObject = {
sidePanelTab: undefined,
container: undefined,
physics: physics,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
let isInitialized = false
thisObject.container = newContainer()
thisObject.container.name = MODULE_NAME
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = true
thisObject.container.status = 'hidden'
let listView
resize()
let openingEventSubscriptionId
let closedEventSubscriptionId
let browserResizedEventSubscriptionId
return thisObject
function initialize() {
thisObject.sidePanelTab = newSidePanelTab()
thisObject.sidePanelTab.container.connectToParent(thisObject.container, false, false)
thisObject.sidePanelTab.initialize('left')
browserResizedEventSubscriptionId = canvas.eventHandler.listenToEvent('Browser Resized', resize)
initializeListView()
isInitialized = true
}
function finalize() {
canvas.eventHandler.stopListening(browserResizedEventSubscriptionId)
thisObject.sidePanelTab.container.eventHandler.stopListening(openingEventSubscriptionId)
thisObject.sidePanelTab.container.eventHandler.stopListening(closedEventSubscriptionId)
}
function initializeListView() {
listView = newListView()
listView.initialize()
listView.container.connectToParent(thisObject.container, false, false)
openingEventSubscriptionId = thisObject.sidePanelTab.container.eventHandler.listenToEvent('opening', listView.turnOn)
closedEventSubscriptionId = thisObject.sidePanelTab.container.eventHandler.listenToEvent('closed', listView.turnOff)
}
function resize() {
thisObject.container.frame.width = SIDE_PANEL_WIDTH
thisObject.container.frame.height = browserCanvas.height // - TOP_SPACE_HEIGHT
thisObject.container.frame.position.x = -SIDE_PANEL_WIDTH
thisObject.container.frame.position.y = 0 // TOP_SPACE_HEIGHT
if (listView !== undefined) {
listView.resize()
}
if (thisObject.sidePanelTab !== undefined) {
thisObject.sidePanelTab.resize()
}
}
function getContainer(point, purpose) {
let container
container = thisObject.sidePanelTab.getContainer(point, purpose)
if (container !== undefined) { return container }
container = listView.getContainer(point, purpose)
if (container !== undefined) { return container }
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
} else {
return undefined
}
}
function physics() {
thisObject.sidePanelTab.physics()
listView.physics()
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
if (isInitialized === false) { return }
borders()
thisObject.sidePanelTab.draw()
listView.draw()
}
function borders() {
let point1
let point2
let point3
let point4
point1 = {
x: 0,
y: 0
}
point2 = {
x: thisObject.container.frame.width,
y: 0
}
point3 = {
x: thisObject.container.frame.width,
y: thisObject.container.frame.height
}
point4 = {
x: 0,
y: thisObject.container.frame.height
}
point1 = thisObject.container.frame.frameThisPoint(point1)
point2 = thisObject.container.frame.frameThisPoint(point2)
point3 = thisObject.container.frame.frameThisPoint(point3)
point4 = thisObject.container.frame.frameThisPoint(point4)
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
browserCanvasContext.lineTo(point1.x, point1.y)
browserCanvasContext.closePath()
let opacity = 1
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.LIGHT_GREY + ', ' + opacity + ''
browserCanvasContext.fill()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREY + ', ' + opacity + ''
browserCanvasContext.lineWidth = 0.3
browserCanvasContext.stroke()
/* Shadow */
if (thisObject.container.status !== 'hidden') {
for (let i = 0; i <= 30; i++) {
opacity = 1 - (i / 300) - 0.95
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point2.x + i, point2.y)
browserCanvasContext.lineTo(point3.x + i, point3.y)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', ' + opacity + ''
browserCanvasContext.lineWidth = 1
browserCanvasContext.stroke()
}
}
}
}
@@ -0,0 +1,109 @@
function newSuperalgosTopSpace() {
let thisObject = {
container: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize
}
thisObject.container = newContainer()
thisObject.container.initialize()
resize()
thisObject.container.isDraggeable = false
let backgroundImage
let logoImage
return thisObject
function initialize() {
canvas.eventHandler.listenToEvent('Browser Resized', resize)
backgroundImage = new Image()
logoImage = new Image()
loadImage('superalgos-header-background', backgroundImage)
loadImage('superalgos-logo-for-color-background', logoImage)
function loadImage(name, image) {
const PATH = 'Images/'
image.onload = onImageLoad
image.fileName = name
function onImageLoad() {
image.canDraw = true
}
image.src = PATH + name + '.png'
}
}
function resize() {
thisObject.container.frame.width = browserCanvas.width
thisObject.container.frame.height = TOP_SPACE_HEIGHT
thisObject.container.frame.position.x = 0
try {
thisObject.container.frame.position.y = UI.projects.superalgos.spaces.chartingSpace.viewport.visibleArea.bottomLeft.y
} catch (e) { }
}
function getContainer(point) {
}
function draw() {
if (CAN_SPACES_DRAW === false) { return }
thisObject.container.frame.draw(false, false)
drawBackground()
return
}
function drawBackground() {
/* Solid Color */
let opacity = 1
browserCanvasContext.beginPath()
browserCanvasContext.rect(0, 0, thisObject.container.frame.width, thisObject.container.frame.height)
if (ARE_WE_RECORDING_A_VIDEO === true) {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + opacity + ')'
} else {
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')'
}
browserCanvasContext.closePath()
browserCanvasContext.fill()
/* Background Image */
if (backgroundImage !== undefined) {
if (backgroundImage.canDraw === true) {
let imagePosition = {
x: 0,
y: 0
}
browserCanvasContext.drawImage(
backgroundImage, imagePosition.x,
imagePosition.y,
browserCanvas.width,
TOP_SPACE_HEIGHT - 2)
}
}
/* Logo Image */
if (logoImage !== undefined) {
if (logoImage.canDraw === true) {
let imagePosition = {
x: 10,
y: 0
}
browserCanvasContext.drawImage(
logoImage, imagePosition.x,
imagePosition.y,
215,
TOP_SPACE_HEIGHT - 2)
}
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,66 @@
function newSuperalgosUtilitiesBranches() {
thisObject = {
nodeBranchToArray: nodeBranchToArray,
findInBranch: findInBranch
}
return thisObject
function nodeBranchToArray(node, nodeType) {
/*
This function scans a node branch for a certain node type and
return an array of with all the nodes of that type found.
*/
if (node === undefined) { return }
if (nodeType === undefined) { return }
let resultArray = []
scanNodeBranch(node, nodeType)
return resultArray
function scanNodeBranch(startingNode) {
if (startingNode === undefined) { return }
let nodeDefinition = getNodeDefinition(startingNode)
if (nodeDefinition === undefined) { return }
if (startingNode.type === nodeType) {
resultArray.push(startingNode)
return
}
if (nodeDefinition.properties === undefined) { return }
let lastNodePropertyName
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
if (lastNodePropertyName === property.name) { continue } // Some nodes have a single property por multiple child node types. We need to check repeated properties only once so as no to duplicate results.
switch (property.type) {
case 'node': {
scanNodeBranch(startingNode[property.name])
lastNodePropertyName = property.name
}
break
case 'array': {
let startingNodePropertyArray = startingNode[property.name]
for (let m = 0; m < startingNodePropertyArray.length; m++) {
scanNodeBranch(startingNodePropertyArray[m])
}
break
}
}
}
}
}
function findInBranch(startingNode, nodeType, errorNode, connectedViaPayload) {
/*
This function finds a node in a brach and reports an error if it could not be found.
*/
let nodeFound = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(startingNode, nodeType, undefined, connectedViaPayload, true, false, false)
if (nodeFound === undefined) {
errorNode.payload.uiObject.setErrorMessage('Could not find ' + nodeType + ' at ' + startingNode.type + ' ' + startingNode.name)
return
} else {
return nodeFound
}
}
}
@@ -0,0 +1,44 @@
function newSuperalgosUtilitiesClipboard() {
thisObject = {
fallbackCopyTextToClipboard: fallbackCopyTextToClipboard,
copyTextToClipboard: copyTextToClipboard
}
return thisObject
function fallbackCopyTextToClipboard(text) {
var textArea = document.createElement("textarea");
textArea.value = text;
// Avoid scrolling to bottom
textArea.style.top = "0";
textArea.style.left = "0";
textArea.style.position = "fixed";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
//console.log('Fallback: Copying text command was ' + msg);
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
}
document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
if (!navigator.clipboard) {
fallbackCopyTextToClipboard(text);
return;
}
navigator.clipboard.writeText(text).then(function () {
//console.log('Async: Copying to clipboard was successful!');
}, function (err) {
console.error('Async: Could not copy text: ', err);
});
}
}
@@ -0,0 +1,26 @@
function newSuperalgosUtilitiesCoordinateTransformations() {
thisObject = {
transformThisPoint: transformThisPoint,
unTransformThisPoint: unTransformThisPoint
}
return thisObject
function transformThisPoint(point, container) {
/* We make the point relative to the current frame */
point = container.frame.frameThisPoint(point)
/* We pass this point through the UI.projects.superalgos.spaces.chartingSpace.viewport lends, meaning we apply the UI.projects.superalgos.spaces.chartingSpace.viewport zoom and displacement. */
point = UI.projects.superalgos.spaces.chartingSpace.viewport.transformThisPoint(point)
return point
}
function unTransformThisPoint(point, container) {
point = UI.projects.superalgos.spaces.chartingSpace.viewport.unTransformThisPoint(point)
point = container.frame.unframeThisPoint(point)
return point
}
}
@@ -0,0 +1,66 @@
function newSuperalgosUtilitiesDateRateTransformations() {
thisObject = {
getDateFromPointAtBrowserCanvas: getDateFromPointAtBrowserCanvas,
getDateFromPointAtChartsSpace: getDateFromPointAtChartsSpace,
getDateFromPointAtContainer: getDateFromPointAtContainer,
getRateFromPointAtBrowserCanvas: getRateFromPointAtBrowserCanvas,
getRateFromPointAtChartingSpace: getRateFromPointAtChartingSpace,
getRateFromPointAtContainer: getRateFromPointAtContainer,
getMilisecondsFromPoint: getMilisecondsFromPoint
}
return thisObject
function getDateFromPointAtBrowserCanvas(point, container, coordinateSystem) {
point = UI.projects.superalgos.utilities.coordinateTransformations.unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getDateFromPointAtChartsSpace(point, container, coordinateSystem) {
point = container.frame.unframeThisPoint(point)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getDateFromPointAtContainer(point, container, coordinateSystem) {
point = coordinateSystem.unInverseTransform(point, container.frame.height)
let date = new Date(point.x)
return date
}
function getRateFromPointAtBrowserCanvas(point, container, coordinateSystem) {
point = UI.projects.superalgos.utilities.coordinateTransformations.unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getRateFromPointAtChartingSpace(point, container, coordinateSystem) {
point = container.frame.unframeThisPoint(point)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getRateFromPointAtContainer(point, container, coordinateSystem) {
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.y
}
function getMilisecondsFromPoint(point, container, coordinateSystem) {
point = UI.projects.superalgos.utilities.coordinateTransformations.unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.x
}
}
@@ -0,0 +1,21 @@
function newSuperalgosUtilitiesDates() {
thisObject = {
formatDate: formatDate
}
return thisObject
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('-');
}
}
@@ -0,0 +1,69 @@
function newSuperalgosUtilitiesDownload() {
thisObject = {
downloadText: downloadText,
downloadCanvas: downloadCanvas,
downloadPanorama: downloadPanorama,
addToMarketPanorama: addToMarketPanorama
}
return thisObject
function downloadText(filename, text) {
let element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
function downloadCanvas(filename, canvasToUse) {
let data = canvasToUse.toDataURL('image/png', 1)
/* Change MIME type to trick the browser to downlaod the file instead of displaying it */
data = data.replace(/^data:image\/[^;]*/, 'data:application/octet-stream')
/* In addition to <a>'s "download" attribute, you can define HTTP-style headers */
data = data.replace(/^data:application\/octet-stream/, 'data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=' + filename + '.png')
let element = document.createElement('a')
element.setAttribute('href', data)
element.setAttribute('download', filename + '.PNG')
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
function downloadPanorama(filename) {
let INITIAL_WIDTH = 800
let FINAL_WIDTH = browserCanvas.width - INITIAL_WIDTH
if (ARE_WE_RECORDING_A_MARKET_PANORAMA === false) {
/* We start recording the panorame. */
ARE_WE_RECORDING_A_MARKET_PANORAMA = true
marketPanoramaCanvas = document.createElement('canvas')
marketPanoramaCanvas.width = INITIAL_WIDTH * 50
marketPanoramaCanvas.height = browserCanvas.height
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, 0, 0, INITIAL_WIDTH, browserCanvas.height, 0, 0, INITIAL_WIDTH, browserCanvas.height)
CURRENT_PANORAMA_POSITION = INITIAL_WIDTH
} else {
/* We stop recording and download the resulting image. */
ARE_WE_RECORDING_A_MARKET_PANORAMA = false
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, browserCanvas.width - FINAL_WIDTH, 0, FINAL_WIDTH, browserCanvas.height, CURRENT_PANORAMA_POSITION, 0, FINAL_WIDTH, browserCanvas.height)
let finalResultCanvas = document.createElement('canvas')
finalResultCanvas.width = CURRENT_PANORAMA_POSITION + FINAL_WIDTH
finalResultCanvas.height = browserCanvas.height
finalResultCanvas.getContext('2d').drawImage(marketPanoramaCanvas, 0, 0, finalResultCanvas.width, browserCanvas.height, 0, 0, finalResultCanvas.width, browserCanvas.height)
downloadCanvas(filename, finalResultCanvas)
marketPanoramaCanvas = undefined
}
}
function addToMarketPanorama() {
let SECTION_WIDTH = 80 * 2
let INITIAL_POSITION = 800 - SECTION_WIDTH
marketPanoramaCanvas.getContext('2d').drawImage(browserCanvas, INITIAL_POSITION, 0, SECTION_WIDTH, browserCanvas.height, CURRENT_PANORAMA_POSITION, 0, SECTION_WIDTH, browserCanvas.height)
CURRENT_PANORAMA_POSITION = CURRENT_PANORAMA_POSITION + SECTION_WIDTH
}
}
@@ -0,0 +1,232 @@
function newSuperalgosUtilitiesDrawPrint() {
thisObject = {
roundedCornersBackground: roundedCornersBackground,
drawLabel: drawLabel,
drawIcon: drawIcon,
drawContainerBackground: drawContainerBackground,
printLabel: printLabel
}
return thisObject
function roundedCornersBackground(params) {
if (params.xOffset === undefined) { params.xOffset = 0 }
borderPoint1 = {
x: params.cornerRadius + params.xOffset,
y: params.cornerRadius
}
borderPoint2 = {
x: params.container.frame.width - params.cornerRadius,
y: params.cornerRadius
}
borderPoint3 = {
x: params.container.frame.width - params.cornerRadius,
y: params.container.frame.height - params.cornerRadius
}
borderPoint4 = {
x: params.cornerRadius + params.xOffset,
y: params.container.frame.height - params.cornerRadius
}
/* Now the transformations. */
if (params.coordinateSystem !== undefined) { // For instance Candles would use this
borderPoint1 = params.coordinateSystem.transformThisPoint(borderPoint1)
borderPoint2 = params.coordinateSystem.transformThisPoint(borderPoint2)
borderPoint3 = params.coordinateSystem.transformThisPoint(borderPoint3)
borderPoint4 = params.coordinateSystem.transformThisPoint(borderPoint4)
} else {
if (params.outsideViewPort === true) { // If the element is not affected by zoom
borderPoint1 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(borderPoint1, params.container)
borderPoint2 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(borderPoint2, params.container)
borderPoint3 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(borderPoint3, params.container)
borderPoint4 = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(borderPoint4, params.container)
} else { // For instance Panels use this
borderPoint1 = params.container.frame.frameThisPoint(borderPoint1)
borderPoint2 = params.container.frame.frameThisPoint(borderPoint2)
borderPoint3 = params.container.frame.frameThisPoint(borderPoint3)
borderPoint4 = params.container.frame.frameThisPoint(borderPoint4)
}
}
if (params.fitFunction !== undefined) {
borderPoint1 = params.fitFunction(borderPoint1)
borderPoint2 = params.fitFunction(borderPoint2)
borderPoint3 = params.fitFunction(borderPoint3)
borderPoint4 = params.fitFunction(borderPoint4)
}
browserCanvasContext.setLineDash([0, 0])
/* Shadow */
if (params.castShadow === true) {
let SHADOW_OFFSET = 2
browserCanvasContext.beginPath()
browserCanvasContext.arc(borderPoint1.x + SHADOW_OFFSET, borderPoint1.y + SHADOW_OFFSET, params.cornerRadius, 1.0 * Math.PI, 1.5 * Math.PI)
browserCanvasContext.lineTo(borderPoint2.x + SHADOW_OFFSET, borderPoint2.y - params.cornerRadius + SHADOW_OFFSET)
browserCanvasContext.arc(borderPoint2.x + SHADOW_OFFSET, borderPoint2.y + SHADOW_OFFSET, params.cornerRadius, 1.5 * Math.PI, 2.0 * Math.PI)
browserCanvasContext.lineTo(borderPoint3.x + params.cornerRadius + SHADOW_OFFSET, borderPoint3.y + SHADOW_OFFSET)
browserCanvasContext.arc(borderPoint3.x + SHADOW_OFFSET, borderPoint3.y + SHADOW_OFFSET, params.cornerRadius, 0 * Math.PI, 0.5 * Math.PI)
browserCanvasContext.lineTo(borderPoint4.x + SHADOW_OFFSET, borderPoint4.y + params.cornerRadius + SHADOW_OFFSET)
browserCanvasContext.arc(borderPoint4.x + SHADOW_OFFSET, borderPoint4.y + SHADOW_OFFSET, params.cornerRadius, 0.5 * Math.PI, 1.0 * Math.PI)
browserCanvasContext.lineTo(borderPoint1.x - params.cornerRadius + SHADOW_OFFSET, borderPoint1.y + SHADOW_OFFSET)
browserCanvasContext.closePath()
browserCanvasContext.lineWidth = 10
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', ' + 0.01 + ')'
browserCanvasContext.stroke()
browserCanvasContext.lineWidth = 5
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', ' + 0.01 + ')'
browserCanvasContext.stroke()
browserCanvasContext.lineWidth = 1
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.BLACK + ', ' + 0.15 + ')'
browserCanvasContext.stroke()
}
/* Background */
browserCanvasContext.beginPath()
browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, params.cornerRadius, 1.0 * Math.PI, 1.5 * Math.PI)
browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - params.cornerRadius)
browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, params.cornerRadius, 1.5 * Math.PI, 2.0 * Math.PI)
browserCanvasContext.lineTo(borderPoint3.x + params.cornerRadius, borderPoint3.y)
browserCanvasContext.arc(borderPoint3.x, borderPoint3.y, params.cornerRadius, 0 * Math.PI, 0.5 * Math.PI)
browserCanvasContext.lineTo(borderPoint4.x, borderPoint4.y + params.cornerRadius)
browserCanvasContext.arc(borderPoint4.x, borderPoint4.y, params.cornerRadius, 0.5 * Math.PI, 1.0 * Math.PI)
browserCanvasContext.lineTo(borderPoint1.x - params.cornerRadius, borderPoint1.y)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + params.backgroundColor + ', ' + params.opacity + ')'
browserCanvasContext.fill()
browserCanvasContext.lineWidth = params.lineWidth
browserCanvasContext.strokeStyle = 'rgba(' + params.borderColor + ', ' + params.opacity + ')'
browserCanvasContext.stroke()
}
function drawLabel(label, xFactor, yFactor, xOffset, yOffset, fontSize, container, fontColor, noFrameX, noFrameY, opacity) {
if (label === undefined) { return }
if (fontColor === undefined) { fontColor = UI_COLOR.WHITE }
let fontOffset = label.length * fontSize * FONT_ASPECT_RATIO + 10
if (opacity === undefined) { opacity = 1 }
let labelPoint = {
x: container.frame.width * xFactor + xOffset - fontOffset / 2,
y: container.frame.height * yFactor + yOffset
}
labelPoint = container.frame.frameThisPoint(labelPoint)
if (noFrameX !== undefined) {
labelPoint.x = noFrameX + xOffset
}
if (noFrameY !== undefined) {
labelPoint.y = noFrameY + yOffset
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + fontColor + ', ' + opacity + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
function drawIcon(icon, xFactor, yFactor, xOffset, yOffset, imageSize, container) {
if (icon !== undefined) {
if (icon.canDrawIcon === true) {
let imagePosition = {
x: container.frame.width * xFactor + xOffset - imageSize / 2,
y: container.frame.height * yFactor + yOffset - imageSize / 2
}
imagePosition = container.frame.frameThisPoint(imagePosition)
browserCanvasContext.drawImage(
icon, imagePosition.x,
imagePosition.y,
imageSize,
imageSize)
}
}
}
function drawContainerBackground(container, color, opacity, fitFunction) {
let fromPoint = {
x: 0,
y: 0
}
let toPoint = {
x: container.frame.width,
y: container.frame.height
}
fromPoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(fromPoint, container)
toPoint = UI.projects.superalgos.utilities.coordinateTransformations.transformThisPoint(toPoint, container)
fromPoint = fitFunction(fromPoint)
toPoint = fitFunction(toPoint)
browserCanvasContext.beginPath()
browserCanvasContext.rect(fromPoint.x, fromPoint.y, toPoint.x - fromPoint.x, toPoint.y - fromPoint.y)
browserCanvasContext.fillStyle = 'rgba(' + color + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
}
function printLabel(labelToPrint, x, y, opacity, fontSize, color, center, container, fitFunction, noDecimals, fixedDecimals) {
if (labelToPrint === undefined) { return }
let labelPoint
if (color === undefined) { color = UI_COLOR.DARK }
if (fontSize === undefined) { fontSize = 10 };
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
let label = labelToPrint
if (isNaN(label) === false && label !== '') {
if (fixedDecimals !== true) {
label = dynamicDecimals(labelToPrint)
}
label = label.toLocaleString()
if (noDecimals === true) {
label = Math.trunc(label)
}
}
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
if (center === true) {
labelPoint = {
x: x - xOffset,
y: y
}
} else {
labelPoint = {
x: x,
y: y
}
}
if (container !== undefined) {
labelPoint = container.frame.frameThisPoint(labelPoint)
}
if (fitFunction !== undefined) {
labelPoint = fitFunction(labelPoint)
}
browserCanvasContext.fillStyle = 'rgba(' + color + ', ' + opacity + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
}
@@ -0,0 +1,99 @@
function newSuperalgosUtilitiesFolders() {
thisObject = {
asymetricalFolderStructureCloning: asymetricalFolderStructureCloning
}
return thisObject
function asymetricalFolderStructureCloning(
originNode,
destinationNode,
originObjectsArrayPropertyName,
originFoldersArrayPropertyName,
destinationFoldersArrayPropertyName,
clonedObjectType,
destinationFolderType,
originObjectArrayPropertyName,
functionLibraryUiObjectsFromNodes
) {
/*
This function will scan one branch of the workspace, and recreate
a similar structure in some other place, based on the parameters
sent to the function is what types of nodes are going to be mapped
into which other types.
*/
if (originNode === undefined) { return }
if (destinationNode === undefined) { return }
/* Now we go down through all the children of the origin node, recreating at the destination node the same children structure*/
let nodeDefinition = getNodeDefinition(originNode)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.name) {
case originObjectsArrayPropertyName: {
let originNodePropertyArray = originNode[property.name]
for (let m = 0; m < originNodePropertyArray.length; m++) {
let originObject = originNodePropertyArray[m]
if (originObjectArrayPropertyName === undefined) {
/*
In this first Use Case, we are going to connect each orgin object clone
to its origin object counter part.
*/
let clonedObject = functionLibraryUiObjectsFromNodes.addUIObject(destinationNode, clonedObjectType)
clonedObject.payload.referenceParent = originObject
} else {
/*
In this second Use Case, we are going to connect an inner object that is
inside the origin object at an array. We recognize we have to do this
because we did receive this array proeprty name.
*/
let originObjectArray = originObject[originObjectArrayPropertyName]
for (let n = 0; n < originObjectArray.length; n++) {
let originObjectArrayItem = originObjectArray[n]
let clonedObject = functionLibraryUiObjectsFromNodes.addUIObject(destinationNode, clonedObjectType)
clonedObject.payload.referenceParent = originObjectArrayItem
}
}
}
break
}
case originFoldersArrayPropertyName: {
let originNodePropertyArray = originNode[property.name]
let destinationNodePropertyArray = destinationNode[destinationFoldersArrayPropertyName]
for (let m = 0; m < originNodePropertyArray.length; m++) {
let originFolder = originNodePropertyArray[m]
let found = false
let destinationFolder
for (let n = 0; n < destinationNodePropertyArray.length; n++) {
destinationFolder = destinationNodePropertyArray[n]
if (originFolder.name === destinationFolder.name) {
found = true
}
}
if (found === false) {
destinationFolder = functionLibraryUiObjectsFromNodes.addUIObject(destinationNode, destinationFolderType)
destinationFolder.name = originFolder.name
}
asymetricalFolderStructureCloning(
originFolder,
destinationFolder,
originObjectsArrayPropertyName,
originFoldersArrayPropertyName,
destinationFoldersArrayPropertyName,
clonedObjectType,
destinationFolderType,
originObjectArrayPropertyName,
functionLibraryUiObjectsFromNodes
)
}
break
}
}
}
}
}
}
@@ -0,0 +1,71 @@
function newSuperalgosUtilitiesHierarchy() {
thisObject = {
getHiriarchyMap: getHiriarchyMap,
getHiriarchyHead: getHiriarchyHead
}
return thisObject
function getHiriarchyMap(rootNode) {
/*
This function scans a node hiriatchy recursively and creates a Map by Id of all the nodes of it.
*/
let hiriatchyMap = new Map()
evalNode(rootNode)
return hiriatchyMap
function evalNode(node) {
if (node === undefined) { return }
hiriatchyMap.set(node.id, node)
/* Now we go down through all this node children */
let nodeDefinition = getNodeDefinition(node)
if (nodeDefinition === undefined) { return }
if (nodeDefinition.properties !== undefined) {
let previousPropertyName // Since there are cases where there are many properties with the same name,because they can hold nodes of different types but only one at the time, we have to avoind counting each property of those as individual children.
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
if (property.name !== previousPropertyName) {
if (node[property.name] !== undefined) {
evalNode(node[property.name])
}
previousPropertyName = property.name
}
break
}
case 'array': {
if (node[property.name] !== undefined) {
let nodePropertyArray = node[property.name]
for (let m = 0; m < nodePropertyArray.length; m++) {
evalNode(nodePropertyArray[m])
}
}
break
}
}
}
}
}
}
function getHiriarchyHead(initialNode) {
let headNode
stepBackwards(initialNode)
return headNode
function stepBackwards(node) {
if (node === undefined) { return }
if (node.payload === undefined) { return }
if (node.payload.parentNode === undefined) {
headNode = node
} else {
stepBackwards(node.payload.parentNode)
}
}
}
}
@@ -0,0 +1,33 @@
function newSuperalgosUtilitiesLoadSaveFrame() {
thisObject = {
saveFrame: saveFrame,
loadFrame: loadFrame
}
return thisObject
function saveFrame(payload, frame) {
payload.frame = {
position: {
x: frame.position.x,
y: frame.position.y
},
width: frame.width,
height: frame.height,
radius: frame.radius
}
}
function loadFrame(payload, frame) {
if (payload.node.savedPayload !== undefined) {
if (payload.node.savedPayload.frame !== undefined) {
frame.position.x = payload.node.savedPayload.frame.position.x
frame.position.y = payload.node.savedPayload.frame.position.y
frame.width = payload.node.savedPayload.frame.width
frame.height = payload.node.savedPayload.frame.height
frame.radius = payload.node.savedPayload.frame.radius
payload.node.savedPayload.frame = undefined
}
}
}
}
@@ -0,0 +1,23 @@
function newSuperalgosUtilitiesMenu() {
thisObject = {
menuClickOfNodeArray: menuClickOfNodeArray,
menuClick: menuClick
}
return thisObject
function menuClickOfNodeArray(nodeArray, action, confirm) {
for (let j = 0; j < nodeArray.length; j++) {
let node = nodeArray[j]
menuClick(node, action, confirm)
}
}
function menuClick(node, action, confirm) {
let menu = node.payload.uiObject.menu
menu.internalClick(action)
if (confirm === true) {
menu.internalClick(action)
}
}
}
@@ -0,0 +1,96 @@
function newSuperalgosUtilitiesMeshes() {
thisObject = {
findNodeInNodeMesh: findNodeInNodeMesh
}
return thisObject
function findNodeInNodeMesh(node, nodeType, nodeName, connectedViaPayload, findInChildren, findInParents, findInReferenceParents) {
/*
This function scans a node mesh for a certain node type and
returns the first instance found. Please specify either nodeType
or nodeName.
*/
const MAX_DEPTH = 100
let nodeFound
scanNodeMesh(node, 0)
return nodeFound
function scanNodeMesh(startingNode, depth) {
if (startingNode === undefined) { return }
if (connectedViaPayload === true) {
if (startingNode.payload === undefined) { return }
}
if (nodeFound !== undefined) { return }
if (depth >= MAX_DEPTH) { return }
let nodeDefinition = getNodeDefinition(startingNode)
if (nodeDefinition === undefined) { return }
if (nodeType !== undefined) {
if (startingNode.type === nodeType) {
nodeFound = startingNode
return
}
}
if (nodeName !== undefined) {
if (startingNode.name === nodeName) {
nodeFound = startingNode
return
}
}
/* We scan through this node children */
if (findInChildren === true) {
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
scanNodeMesh(startingNode[property.name], depth + 1)
}
break
case 'array': {
let startingNodePropertyArray = startingNode[property.name]
if (startingNodePropertyArray !== undefined) {
for (let m = 0; m < startingNodePropertyArray.length; m++) {
scanNodeMesh(startingNodePropertyArray[m], depth + 1)
}
}
break
}
}
}
}
}
/* We scan parents nodes. */
if (findInParents === true) {
if (connectedViaPayload === true) {
if (startingNode.payload.parentNode !== undefined) {
scanNodeMesh(startingNode.payload.parentNode, depth + 1)
}
} else {
if (startingNode.parentNode !== undefined) {
scanNodeMesh(startingNode.parentNode, depth + 1)
}
}
}
/* We scan reference parents too. */
if (findInReferenceParents === true) {
if (connectedViaPayload === true) {
if (startingNode.payload.referenceParent !== undefined) {
scanNodeMesh(startingNode.payload.referenceParent, depth + 1)
}
} else {
if (startingNode.referenceParent !== undefined) {
scanNodeMesh(startingNode.referenceParent, depth + 1)
}
}
}
}
}
}
@@ -0,0 +1,244 @@
function newSuperalgosUtilitiesNodeChildren() {
thisObject = {
isMissingChildren: isMissingChildren,
findChildReferencingThisNode: findChildReferencingThisNode,
findOrCreateChildWithReference: findOrCreateChildWithReference,
findAndRecreateChildWithReference: findAndRecreateChildWithReference,
findChildIndexAtParentNode: findChildIndexAtParentNode,
isMissingChildrenByName: isMissingChildrenByName
}
return thisObject
function isMissingChildren(startingNode, checkNode, checkReferenceParent) {
/*
This functioin scan all the children of a node and returns true or false
depending if the checkNode is a missing children.
*/
if (startingNode === undefined) { return }
if (checkNode === undefined) { return }
let nodeDefinition = getNodeDefinition(startingNode)
if (nodeDefinition === undefined) { return }
/* We scan through this node children */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
let child = startingNode[property.name]
if (child === undefined) { continue }
if (checkReferenceParent !== true) {
if (child.id === checkNode.id) {
return false
}
} else {
if (child.payload !== undefined) {
if (child.payload.referenceParent !== undefined) {
if (child.payload.referenceParent.id === checkNode.id) {
return false
}
}
}
}
}
break
case 'array': {
let startingNodePropertyArray = startingNode[property.name]
if (startingNodePropertyArray !== undefined) {
for (let m = 0; m < startingNodePropertyArray.length; m++) {
let arrayItem = startingNodePropertyArray[m]
if (checkReferenceParent !== true) {
if (arrayItem.id === checkNode.id) {
return false
}
} else {
if (arrayItem.payload !== undefined) {
if (arrayItem.payload.referenceParent !== undefined) {
if (arrayItem.payload.referenceParent.id === checkNode.id) {
return false
}
}
}
}
}
}
break
}
}
}
return true
}
}
function findChildReferencingThisNode(startingNode, checkNode) {
/*
This functioin scan all the children of a node and returns the child
that is referencing the checkNode.
*/
if (startingNode === undefined) { return }
if (checkNode === undefined) { return }
let nodeDefinition = getNodeDefinition(startingNode)
if (nodeDefinition === undefined) { return }
/* We scan through this node children */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
let child = startingNode[property.name]
if (child.payload !== undefined) {
if (child.payload.referenceParent !== undefined) {
if (child.payload.referenceParent.id === checkNode.id) {
return child
}
}
}
}
break
case 'array': {
let startingNodePropertyArray = startingNode[property.name]
if (startingNodePropertyArray !== undefined) {
for (let m = 0; m < startingNodePropertyArray.length; m++) {
let arrayItem = startingNodePropertyArray[m]
if (arrayItem.payload !== undefined) {
if (arrayItem.payload.referenceParent !== undefined) {
if (arrayItem.payload.referenceParent.id === checkNode.id) {
return arrayItem
}
}
}
}
}
break
}
}
}
return true
}
}
function findOrCreateChildWithReference(startingNode, childType, referencedNode, functionLibraryUiObjectsFromNodes) {
/*
This function find the child node of starting node that references
refereced node. If there is none, then it creates a child and stablish
the referecen.
*/
let child
if (isMissingChildren(startingNode, referencedNode, true) === true) {
child = functionLibraryUiObjectsFromNodes.addUIObject(startingNode, childType)
child.payload.referenceParent = referencedNode
} else {
child = findChildReferencingThisNode(startingNode, referencedNode)
}
return child
}
function findAndRecreateChildWithReference(startingNode, childType, referencedNode, rootNodes, functionLibraryUiObjectsFromNodes, functionLibraryNodeDeleter) {
/*
This function finds the child of the starting node that references
the reference node and if found it deletes it. Existing or not
it creates it again with the child type specified.
*/
let child
child = findChildReferencingThisNode(startingNode, referencedNode)
if (child !== undefined) {
functionLibraryNodeDeleter.deleteUIObject(child, rootNodes)
}
child = functionLibraryUiObjectsFromNodes.addUIObject(startingNode, childType)
child.payload.referenceParent = referencedNode
return child
}
function findChildIndexAtParentNode(startingNode) {
/*
This functioin scan all the children of a node's parent and returns the child
index at the node property array that contains it.
*/
if (startingNode === undefined) { return }
if (startingNode.payload === undefined) { return }
if (startingNode.payload.parentNode === undefined) { return }
let parentNode = startingNode.payload.parentNode
let nodeDefinition = getNodeDefinition(parentNode)
if (nodeDefinition === undefined) { return }
/* We scan through this parent node children */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
/* We ignore these types of children. */
}
break
case 'array': {
let startingNodePropertyArray = parentNode[property.name]
if (startingNodePropertyArray !== undefined) {
for (let m = 0; m < startingNodePropertyArray.length; m++) {
let arrayItem = startingNodePropertyArray[m]
if (arrayItem.id === startingNode.id) {
return m
}
}
}
break
}
}
}
}
}
function isMissingChildrenByName(startingNode, nodeName) {
/*
This functioin scan all the children of a node and returns true or false
depending if the node has a children with a certain name.
*/
if (startingNode === undefined) { return }
let nodeDefinition = getNodeDefinition(startingNode)
if (nodeDefinition === undefined) { return }
/* We scan through this node children */
if (nodeDefinition.properties !== undefined) {
for (let i = 0; i < nodeDefinition.properties.length; i++) {
let property = nodeDefinition.properties[i]
switch (property.type) {
case 'node': {
let child = startingNode[property.name]
if (child !== undefined) {
if (child.name === nodeName) {
return false
}
}
}
break
case 'array': {
let startingNodePropertyArray = startingNode[property.name]
if (startingNodePropertyArray !== undefined) {
for (let m = 0; m < startingNodePropertyArray.length; m++) {
let arrayItem = startingNodePropertyArray[m]
if (arrayItem.name === nodeName) {
return false
}
}
}
break
}
}
}
return true
}
}
}
@@ -0,0 +1,27 @@
function newSuperalgosUtilitiesNodeConfig() {
thisObject = {
savePropertyAtNodeConfig: savePropertyAtNodeConfig,
loadPropertyFromNodeConfig: loadPropertyFromNodeConfig
}
return thisObject
function savePropertyAtNodeConfig(payload, propertyName, value) {
try {
let config = JSON.parse(payload.node.config)
config[propertyName] = value
payload.node.config = JSON.stringify(config, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function loadPropertyFromNodeConfig(payload, propertyName) {
try {
let config = JSON.parse(payload.node.config)
return config[propertyName]
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
}
@@ -0,0 +1,27 @@
function newSuperalgosUtilitiesTutorial() {
thisObject = {
saveTutorial: saveTutorial,
loadTutorial: loadTutorial
}
return thisObject
function saveTutorial(payload, tutorial) {
payload.tutorial = {
status: tutorial.status
}
}
function loadTutorial(payload, tutorial) {
if (payload.tutorial !== undefined) {
tutorial.status = payload.tutorial.status
return
}
if (payload.node.savedPayload !== undefined) {
if (payload.node.savedPayload.tutorial !== undefined) {
tutorial.status = payload.node.savedPayload.tutorial.status
payload.node.savedPayload.tutorial = undefined
}
}
}
}