Merge pull request #138 from Superalgos/develop

Pre-Release
This commit is contained in:
Luis Fernando Molina authored and GitHub committed 2020-02-19 10:29:13 +01:00
commit 00a6e686a9
3448 files changed
+566483 -263

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
#PORT NUMBERS: If any of these ports are already in use by a different app, please pick a new number between 1 and 50000.
WEB_SERVER_PORT=9999
WEB_SOCKETS_PORT=8080
# TASK MANAGER VARIABLES:
TASK_SERVER_PATH=./TaskServer
# TASK SERVER VARIABLES:
INTER_PROCESS_FILES_PATH=./Inter-Process-Files
STORAGE_PATH=./Data-Storage
PLOTTERS_PATH=./Legacy-Code
USE_KEYVAULT=false
WRITE_LOGS_TO_FILES=true
BOTS_PATH=./Legacy-Code
LOG_PATH=./Log-Files
# WEB SERVER VARIABLES:
#Log options
CONSOLE_LOG=false
CONSOLE_ERROR_LOG=true
LOG_FILE_CONTENT=false
# Server commands
REINITIALIZE_COMMAND=sdnacGYGdw756dnxasxbGGGjsdbd5576576gfdsxgvbnFFF
PATH_TO_CANVAS_APP=./CanvasApp
PATH_TO_FILES_COMPONENT=./Files-Component/src
PATH_TO_WEB_SERVER=./WebServer/
GATEWAY_ENDPOINT=https://demo-api-dev.superalgos.org/graphql
+6 -6
View File
@@ -2,21 +2,21 @@
We are thrilled you are interested in contributing to this project. Your help may be essential to the project's success and we want you in!
Superalgos is a collective project, currently at a very early stage. We not only welcome contributions but may even choose to incentivize relevant contributions via the project's native crypto token.
Superalgos is a collective project, currently at a very early stage. We not only welcome contributions but may even choose to incentivize relevant contributions via the project's native crypto token, to be deployed in the near future.
Please read the [Join the Dev Team]( https://superalgos.org/developers-join-dev-team.shtml) page in our website to learn more about how you may become a relevant member of the Superalgos Project and even make a living of contributing code.
Contributions are deemed _voluntary work_, irrespective of the incentives that may be in place, and are subject to the conditions described in the software [LICENSE](https://github.com/Superalgos/DesktopApp/blob/master/LICENSE).
Contributions are deemed _voluntary work_, irrespective of the incentives that may be in place, and are subject to the conditions described in the software [LICENSE](LICENSE).
## Getting Started
First step is to download, install and start using the app. The release includes all source code which constitutes your development environment right out of the package. The app runs uncompilled on the actual code.
First step is to fork this repository and start using the app. The repository includes all source code which constitutes your development environment. The app runs uncompilled on the actual code.
* The priority at this moment is the stabilization of existing functionality. Your first contribution will be using and testing the app, and reporting any bugs you may find.
* The priority at this moment is the stabilization of existing functionality. Your first contribution will be using, learning, and testing the app, and reporting any bugs you may find.
* You may debug and remove bugs yourself, and submit pull requests to the corresponding repositories. The name of the folder containing the code maps each of the repositories involved in the release.
* You may debug and remove bugs yourself, and submit pull requests.
* Additionally, you may contribute helping improve the README and building the documentation in each of the repositories involved.
* Another top priority is building a robust base of indicators and technical studies. This is done from the UI, using the functionality managed by data mines.
As you engage with other developers and the Core Team, we will get to know you and develop a relationship, so that you may later participate in core development tasks.
+172
View File
@@ -0,0 +1,172 @@
function newAnimation () {
const MODULE_NAME = 'Animation'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
/*
Essentially, what the animation object does, is to call several functions in order to draw the content of each frame.
To do that, it has an array of functions that need to be called, and it just goes one by one through them. His parent object
is responsible for providing more functions to call, or removing functions from its list when they are not longer needed.
*/
let animationLoopHandle // This is the handle to the animation loop. With this handle we can cancel the loop, for instance.
let callBackFunctions = new Map()
let thisObject = {
start: start,
stop: stop,
addCallBackFunction: addCallBackFunction,
removeCallBackFunction: removeCallBackFunction,
initialize: initialize,
finalize: finalize
}
let totalConsumption = 0
let totalCounter = 0
let pointerIcon
let videoRecorder
return thisObject
function finalize () {
thisObject.stop()
pointerIcon = undefined
videoRecorder = undefined
}
function initialize () {
videoRecorder = newVideoRecorder()
}
function start () {
animationLoop() // Inside this function the animation process is started, and at the same time it creates a loop.
}
function stop () {
window.cancelAnimationFrame(animationLoopHandle)
}
function addCallBackFunction (key, callBack) {
callBackFunctions.set(key, callBack)
}
function removeCallBackFunction (key) {
callBackFunctions.delete(key)
}
function animationLoop () {
try {
if (window.canvasApp.visible === true) {
/* We set the canvas to its normal width and height */
browserCanvas.width = window.innerWidth
browserCanvas.height = window.innerHeight - CURRENT_TOP_MARGIN
/* First thing is to clear the actual canvas */
// clearBrowserCanvas()
/* We loop through the callback functions collections and execute them all. */
let performanceMap = new Map()
let totalTimeConsumed = 0
let totalElements = 0
let chanceToExecute
let randomNumber
let mustExecute
// console.clear()
let row = 0
for (const [key, callBackFunction] of callBackFunctions.entries()) {
row++
switch (key) {
case 'Floating Space Physics':
chanceToExecute = 50
randomNumber = Math.random() * 100 * chanceToExecute
if (randomNumber > 100 - chanceToExecute) { mustExecute = true } else { mustExecute = false }
break
default: {
mustExecute = true
}
}
let timeConsumed = 0
if (mustExecute === true) {
let t0 = performance.now()
callBackFunction()
let t1 = performance.now()
timeConsumed = t1 - t0
if (key === 'Charting Space Draw') {
if (Math.random() * 100 > 99) {
totalConsumption = 0
totalCounter = 0
}
totalConsumption = totalConsumption + timeConsumed
totalCounter = totalCounter + 1
}
performanceMap.set(key, timeConsumed)
totalTimeConsumed = totalTimeConsumed + timeConsumed
totalElements++
}
}
/* Performance Check */
if (SHOW_ANIMATION_PERFORMACE === true) {
row = 0
for (const [key, timeConsumed] of performanceMap.entries()) {
row++
labelToPrint = key + ' ' + timeConsumed.toFixed(4)
printLabel(labelToPrint, 10, 100 + row * 30, 1, 20, UI_COLOR.RED)
let percentage = timeConsumed * 100 / totalTimeConsumed
labelToPrint = key + ' ' + percentage.toFixed(1) + '%'
printLabel(labelToPrint, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
}
/* Other Variables */
row++
printLabel(DEBUG.variable1, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
row++
printLabel(DEBUG.variable2, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
row++
printLabel(DEBUG.variable3, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
row++
printLabel(DEBUG.variable4, 300, 100 + row * 30, 1, 20, UI_COLOR.RED)
}
} else {
browserCanvas.width = 1
browserCanvas.height = 1
}
/* Media Recording */
if (areWeRecording === true) {
videoRecorder.recordCanvas()
}
/* We request the next frame to be drawn, and stablishing a loop */
/* Use this code for full animation speed. */
animationLoopHandle = window.requestAnimationFrame(animationLoop)
/* Use this code for max 10 frames per second animation speed, if the app is consumming too much of your CPU. */
/*
setTimeout(nextLoop, 100)
function nextLoop () {
animationLoopHandle = window.requestAnimationFrame(animationLoop)
}
*/
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] animationLoop -> err = ' + err.stack) }
}
}
function clearBrowserCanvas () {
browserCanvasContext.beginPath()
browserCanvasContext.rect(0, 0, browserCanvas.width, browserCanvas.height)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
browserCanvasContext.closePath()
browserCanvasContext.fill()
}
}
+990
View File
@@ -0,0 +1,990 @@
let browserCanvasContext // The context of the canvas object.
let stepsInitializationCounter = 0 // This counter the initialization steps required to be able to turn off the splash screen.
let marketInitializationCounter = 0 // This counter the initialization of markets required to be able to turn off the splash screen.
let splashScreenNeeded = true
function newCanvas () {
const MODULE_NAME = 'Canvas'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
/* Mouse event related variables. */
let containerDragStarted = false
let floatingObjectDragStarted = false
let floatingObjectBeingDragged
let containerBeingDragged
let viewPortBeingDragged = false
let ignoreNextClick = false
let dragVector = {
downX: 0,
downY: 0,
upX: 0,
upY: 0
}
/* canvas object */
let thisObject = {
eventHandler: undefined,
topSpace: undefined,
chartingSpace: undefined,
floatingSpace: undefined,
panelsSpace: undefined,
cockpitSpace: undefined,
bottomSpace: undefined,
designSpace: undefined,
animation: undefined,
mouse: undefined,
initialize: initialize,
finalize: finalize
}
thisObject.eventHandler = newEventHandler()
let splashScreen
let lastContainerMouseOver
let lastShortcutKeyRejection
thisObject.mouse = {
position: {
x: 0,
y: 0
},
action: ''
}
return thisObject
function finalize () {
try {
thisObject.chartingSpace.finalize()
thisObject.floatingSpace.finalize()
browserCanvas.removeEventListener('mousedown', onMouseDown, false)
browserCanvas.removeEventListener('mouseup', onMouseUp, false)
browserCanvas.removeEventListener('mousemove', onMouseMove, false)
browserCanvas.removeEventListener('click', onMouseClick, false)
browserCanvas.removeEventListener('mouseout', onMouseOut, false)
if (browserCanvas.removeEventListener) {
browserCanvas.removeEventListener('mousewheel', onMouseWheel, false)// IE9, Chrome, Safari, Opera
browserCanvas.removeEventListener('DOMMouseScroll', onMouseWheel, false) // Firefox
} else browserCanvas.detachEvent('onmousewheel', onMouseWheel) // IE 6/7/8
browserCanvas.removeEventListener('dragenter', onDragEnter, false)
browserCanvas.removeEventListener('dragleave', onDragLeave, false)
browserCanvas.removeEventListener('dragover', onDragOver, false)
browserCanvas.removeEventListener('drop', onDragDrop, false)
browserCanvas.removeEventListener('keydown', onKeyDown, false)
browserCanvas.removeEventListener('keyup', onKeyUp, false)
splashScreen = undefined
lastContainerMouseOver = undefined
hisObject.mouse = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) }
}
}
function initialize () {
try {
initializeBrowserCanvas()
addCanvasEvents()
/* Instantiate all the children spaces of Canvas object */
thisObject.floatingSpace = newFloatingSpace()
thisObject.floatingSpace.initialize()
thisObject.topSpace = newTopSpace()
thisObject.topSpace.initialize()
thisObject.designSpace = newDesignSpace()
thisObject.designSpace.initialize()
thisObject.cockpitSpace = newCockpitSpace()
thisObject.cockpitSpace.initialize()
thisObject.panelsSpace = newPanelsSpace()
thisObject.panelsSpace.initialize()
thisObject.chartingSpace = newChartingSpace()
thisObject.chartingSpace.initialize()
thisObject.bottomSpace = thisObject.cockpitSpace
splashScreen = newSplashScreen()
splashScreen.initialize()
let animation = newAnimation()
animation.initialize()
thisObject.animation = animation
/* Low Level Infraestructure First */
animation.addCallBackFunction('System Event Handler Physics', systemEventHandler.physics)
/* Spcaces Physics */
animation.addCallBackFunction('CockpitSpace Physics', thisObject.cockpitSpace.physics)
animation.addCallBackFunction('Floating Space Physics', thisObject.floatingSpace.physics)
animation.addCallBackFunction('Charting Space Physics', thisObject.chartingSpace.physics)
animation.addCallBackFunction('Design Space Physics', thisObject.designSpace.physics)
animation.addCallBackFunction('Panels Space Physics', thisObject.panelsSpace.physics)
/* Spcaces Drawing */
animation.addCallBackFunction('Floating Space Draw', thisObject.floatingSpace.draw)
animation.addCallBackFunction('Charting Space Draw', thisObject.chartingSpace.draw)
animation.addCallBackFunction('Panels Space', thisObject.panelsSpace.draw)
animation.addCallBackFunction('CockpitSpace Draw', thisObject.cockpitSpace.draw)
animation.addCallBackFunction('Design Space Draw', thisObject.designSpace.draw)
animation.addCallBackFunction('Top Space Draw', thisObject.topSpace.draw)
animation.addCallBackFunction('Splash Screen Draw', splashScreen.draw)
animation.start()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) }
}
}
function initializeBrowserCanvas () {
try {
browserCanvasContext = browserCanvas.getContext('2d')
browserCanvasContext.font = 'Saira Condensed'
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initializeBrowserCanvas -> err = ' + err.stack) }
}
}
function addCanvasEvents () {
try {
canvas.eventHandler.listenToEvent('Browser Resized', browserResized)
/* Keyboard events */
window.addEventListener('keydown', onKeyDown, true)
window.addEventListener('keyup', onKeyUp, true)
/* Mouse Events */
browserCanvas.addEventListener('mousedown', onMouseDown, false)
browserCanvas.addEventListener('mouseup', onMouseUp, false)
browserCanvas.addEventListener('mousemove', onMouseMove, false)
browserCanvas.addEventListener('click', onMouseClick, false)
browserCanvas.addEventListener('mouseout', onMouseOut, false)
if (browserCanvas.addEventListener) {
browserCanvas.addEventListener('mousewheel', onMouseWheel, false) // IE9, Chrome, Safari, Opera
browserCanvas.addEventListener('DOMMouseScroll', onMouseWheel, false) // Firefox
} else browserCanvas.attachEvent('onmousewheel', onMouseWheel)// IE 6/7/8
/* Dragging Files Over the Canvas */
browserCanvas.addEventListener('dragenter', onDragEnter, false)
browserCanvas.addEventListener('dragleave', onDragLeave, false)
browserCanvas.addEventListener('dragover', onDragOver, false)
browserCanvas.addEventListener('drop', onDragDrop, false)
// Disables the context menu when you right mouse click the canvas.
browserCanvas.oncontextmenu = function (e) {
e.preventDefault()
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] addCanvasEvents -> err = ' + err.stack) }
}
}
function browserResized () {
try {
browserCanvas = document.getElementById('canvas')
browserCanvas.width = window.innerWidth
browserCanvas.height = window.innerHeight - CURRENT_TOP_MARGIN
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] browserResized -> err = ' + err.stack) }
}
}
function checkMediaRecording (event) {
if ((event.ctrlKey === true || event.metaKey === true)) {
let constructorParams
switch (event.keyCode) {
case 119: { // F8
downloadCanvas('Superalgos.image.capture')
return
break
}
case 120: { // F9
constructorParams = { format: 'gif', workersPath: 'externalScripts/', framerate: 8, name: 'Superalgos.video.capture'}
break
}
case 121: { // F10
constructorParams = { format: 'webm', framerate: 8, name: 'Superalgos.video.capture' }
break
}
default: return
}
if (areWeRecording === false) {
console.log('RECORDING', constructorParams.format)
mediaRecorder = new CCapture(constructorParams)
mediaRecorder.start()
areWeRecording = true
} else {
console.log('SAVING', constructorParams.format)
areWeRecording = false
mediaRecorder.stop()
mediaRecorder.save()
}
}
}
function onKeyUp (event) {
thisObject.mouse.event = event
thisObject.mouse.action = 'key up'
}
function onKeyDown (event) {
thisObject.mouse.event = event
thisObject.mouse.action = 'key down'
checkMediaRecording(event)
let nodeOnFocus = canvas.designSpace.workspace.getNodeThatIsOnFocus()
if (nodeOnFocus !== undefined) {
if (nodeOnFocus.payload.uiObject.codeEditor !== undefined) {
if (nodeOnFocus.payload.uiObject.codeEditor.visible === true) {
return
}
}
if (nodeOnFocus.payload.uiObject.configEditor !== undefined) {
if (nodeOnFocus.payload.uiObject.configEditor.visible === true) {
return
}
}
if (nodeOnFocus.payload.uiObject.formulaEditor !== undefined) {
if (nodeOnFocus.payload.uiObject.formulaEditor.visible === true) {
return
}
}
if (nodeOnFocus.payload.uiObject.conditionEditor !== undefined) {
if (nodeOnFocus.payload.uiObject.conditionEditor.visible === true) {
return
}
}
if (nodeOnFocus.payload.uiObject.uiObjectTitle !== undefined) {
if (nodeOnFocus.payload.uiObject.uiObjectTitle.editMode === true) {
return
}
}
}
if ((event.ctrlKey === true || event.metaKey === true) && event.altKey === true && event.shiftKey === true && event.keyCode === 123) { // Dev Tool when used with F12
if (nodeOnFocus !== undefined) {
console.log(nodeOnFocus)
return
}
}
if ((event.ctrlKey === true || event.metaKey === true) && event.altKey === true && event.shiftKey === true && event.keyCode === 122) { // Dev Tool when used with F11
if (SHOW_ANIMATION_PERFORMACE === false) {
SHOW_ANIMATION_PERFORMACE = true
} else {
SHOW_ANIMATION_PERFORMACE = false
}
return
}
if (event.shiftKey === true && (event.ctrlKey === true || event.metaKey === true) && event.code === 'ArrowUp') {
thisObject.cockpitSpace.toTop()
return
}
if (event.shiftKey === true && (event.ctrlKey === true || event.metaKey === true) && event.code === 'ArrowDown') {
thisObject.cockpitSpace.toBottom()
return
}
if (event.shiftKey === true && (event.ctrlKey === true || event.metaKey === true) && event.code === 'ArrowLeft') {
thisObject.cockpitSpace.moveUp()
return
}
if (event.shiftKey === true && (event.ctrlKey === true || event.metaKey === true) && event.code === 'ArrowRight') {
thisObject.cockpitSpace.moveDown()
return
}
if (event.shiftKey === true && event.ctrlKey === false && event.code === 'ArrowLeft') {
canvas.chartingSpace.oneScreenLeft()
return
}
if (event.shiftKey === true && event.ctrlKey === false && event.code === 'ArrowRight') {
canvas.chartingSpace.oneScreenRight()
return
}
if (event.shiftKey === true && event.code === 'ArrowUp') {
canvas.chartingSpace.oneScreenUp()
return
}
if (event.shiftKey === true && event.code === 'ArrowDown') {
canvas.chartingSpace.oneScreenDown()
return
}
if ((event.ctrlKey === true || event.metaKey === true) && event.shiftKey === false && event.code === 'ArrowLeft') {
let displaceVector = canvas.floatingSpace.oneScreenLeft()
dragVector.downX = dragVector.downX + displaceVector.x
dragVector.downY = dragVector.downY + displaceVector.y
checkDrag()
return
}
if ((event.ctrlKey === true || event.metaKey === true) && event.shiftKey === false && event.code === 'ArrowRight') {
let displaceVector = canvas.floatingSpace.oneScreenRight()
dragVector.downX = dragVector.downX + displaceVector.x
dragVector.downY = dragVector.downY + displaceVector.y
checkDrag()
return
}
if ((event.ctrlKey === true || event.metaKey === true) && event.code === 'ArrowUp') {
let displaceVector = canvas.floatingSpace.oneScreenUp()
dragVector.downX = dragVector.downX + displaceVector.x
dragVector.downY = dragVector.downY + displaceVector.y
checkDrag()
return
}
if ((event.ctrlKey === true || event.metaKey === true) && event.code === 'ArrowDown') {
let displaceVector = canvas.floatingSpace.oneScreenDown()
dragVector.downX = dragVector.downX + displaceVector.x
dragVector.downY = dragVector.downY + displaceVector.y
checkDrag()
return
}
if (event.code === 'Period') {
if (nodeOnFocus !== undefined) {
nodeOnFocus.payload.uiObject.setValue('Id: ' + nodeOnFocus.id)
return
}
}
if ((event.ctrlKey === true || event.metaKey === true) && event.altKey === true) {
if ((event.keyCode >= 48 && event.keyCode <= 57) || (event.keyCode >= 65 && event.keyCode <= 90)) {
/* From here we prevent the default behaviour */
event.preventDefault()
let nodeUsingThisKey = canvas.designSpace.workspace.getNodeByShortcutKey(event.key)
if (nodeOnFocus === undefined && nodeUsingThisKey !== undefined) {
/* Then we displace the whole workspace to center it at the node using this key */
nodeUsingThisKey = canvas.floatingSpace.positionAtNode(nodeUsingThisKey)
return
}
/* If there is a node in focus, we try to assign the key to it. */
if (nodeUsingThisKey !== undefined && nodeOnFocus !== undefined) {
if (nodeUsingThisKey.id === nodeOnFocus.id) {
nodeOnFocus.payload.uiObject.shortcutKey = ''
nodeOnFocus.payload.uiObject.setValue('Shortcut Key Removed ')
return
} else {
if (lastShortcutKeyRejection !== event.key + nodeUsingThisKey.type + ' ' + nodeUsingThisKey.name) {
/* The first time we show a warning that this key is in use. */
nodeOnFocus.payload.uiObject.setErrorMessage('Key already in use by ' + nodeUsingThisKey.type + ' ' + nodeUsingThisKey.name)
lastShortcutKeyRejection = event.key + nodeUsingThisKey.type + ' ' + nodeUsingThisKey.name
return
} else {
/* After the warning, we allow the key to be re-assigned */
nodeUsingThisKey.payload.uiObject.shortcutKey = ''
nodeUsingThisKey === undefined
}
}
}
/* If there is not node using this key and a node in focus, we assign this key to this node */
if (nodeUsingThisKey === undefined && nodeOnFocus !== undefined) {
nodeOnFocus.payload.uiObject.shortcutKey = event.key
nodeOnFocus.payload.uiObject.setValue('Shortcut Key: Ctrl + Alt + ' + event.key)
}
return
}
}
if (event.ctrlKey === true && event.altKey === true && nodeOnFocus !== undefined) {
if (nodeOnFocus.payload.uiObject.shortcutKey !== undefined && nodeOnFocus.payload.uiObject.shortcutKey !== '') {
nodeOnFocus.payload.uiObject.setValue('Shortcut Key: Ctrl + Alt + ' + nodeOnFocus.payload.uiObject.shortcutKey)
}
}
}
function onDragEnter (event) {
try {
event.preventDefault()
event.stopPropagation()
thisObject.cockpitSpace.toTop()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDragEnter -> err = ' + err.stack) }
}
}
function onDragLeave (event) {
try {
event.preventDefault()
event.stopPropagation()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDragLeave -> err = ' + err.stack) }
}
}
function onDragOver (event) {
try {
event.preventDefault()
event.stopPropagation()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDragOver -> err = ' + err.stack) }
}
}
function onDragDrop (event) {
try {
event.preventDefault()
event.stopPropagation()
let files = event.dataTransfer.files
handleFiles(files)
function handleFiles (files) {
([...files]).forEach(loadFileData)
}
function loadFileData (file) {
let reader = new FileReader()
reader.readAsText(file)
reader.onloadend = function () {
let mousePosition = {
x: event.x,
y: event.y
}
thisObject.designSpace.workspace.spawn(reader.result, mousePosition)
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDragDrop -> err = ' + err.stack) }
}
}
function onMouseDown (event) {
try {
thisObject.mouse.event = event
thisObject.mouse.position.x = event.pageX
thisObject.mouse.position.y = event.pageY - CURRENT_TOP_MARGIN
switch (event.buttons) {
case 1: {
thisObject.mouse.action = 'clicking with left button'
break
}
case 2: {
thisObject.mouse.action = 'clicking with right button'
break
}
}
let point = event
point.x = event.pageX
point.y = event.pageY - CURRENT_TOP_MARGIN
dragVector.downX = point.x
dragVector.downY = point.y
let container
/* We check if the mouse is over an element of the Design Space / */
container = thisObject.designSpace.getContainer(point)
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container
containerDragStarted = true
containerBeingDragged.eventHandler.raiseEvent('onDragStarted', point)
return
}
if (container !== undefined && container.isDraggeable === false) {
return
}
/* We check if the mouse is over an element of the Top Space / */
container = thisObject.topSpace.getContainer(point)
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container
containerDragStarted = true
containerBeingDragged.eventHandler.raiseEvent('onDragStarted', point)
return
}
/* We check if the mouse is over an element of the CockpitSpace / */
container = thisObject.cockpitSpace.getContainer(point)
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container
containerDragStarted = true
containerBeingDragged.eventHandler.raiseEvent('onDragStarted', point)
return
}
if (container !== undefined && container.isClickeable === true) {
/* We dont want to mess up with the click */
return
}
/* We check if the mouse is over a panel/ */
container = thisObject.panelsSpace.getContainer(point)
if (container !== undefined && container.isDraggeable === true && event.shiftKey === false) {
containerBeingDragged = container
containerDragStarted = true
containerBeingDragged.eventHandler.raiseEvent('onDragStarted', point)
return
}
if (container !== undefined && container.isClickeable === true) {
/* We dont want to mess up with the click */
return
}
/* we check if it is over any of the existing containers at the Charting Space. */
container = thisObject.chartingSpace.getContainer(point, GET_CONTAINER_PURPOSE.DRAGGING)
if (container !== undefined) {
if (container.isDraggeable === true) {
containerBeingDragged = container
containerDragStarted = true
containerBeingDragged.eventHandler.raiseEvent('onDragStarted', point)
return
} else {
if (container.isClickeable === false) {
viewPortBeingDragged = true
}
return
}
}
container = thisObject.floatingSpace.getContainer(point)
if (container !== undefined && container.isDraggeable === true) {
containerBeingDragged = container
containerDragStarted = true
floatingObjectDragStarted = true
containerBeingDragged.eventHandler.raiseEvent('onDragStarted', point)
return
}
if (container !== undefined && container.isClickeable === true) {
/* We dont want to mess up with the click */
return
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onMouseDown -> err = ' + err.stack) }
}
}
function onMouseClick (event) {
try {
if (ignoreNextClick === true) {
ignoreNextClick = false
return
}
let point = event
point.x = event.pageX
point.y = event.pageY - CURRENT_TOP_MARGIN
let container
/* We check if the mouse is over an element of the Design Space / */
container = thisObject.designSpace.getContainer(point)
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point)
return
}
/* We check if the mouse is over an element of the Top Space / */
container = thisObject.topSpace.getContainer(point)
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point)
return
}
/* We check if the mouse is over an element of the CockpitSpace / */
container = thisObject.cockpitSpace.getContainer(point)
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point)
return
}
/* We check if the mouse is over a panel/ */
container = thisObject.panelsSpace.getContainer(point)
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point)
return
}
/* If it is not, then we check if it is over any of the existing containers at the Charting Space. */
container = thisObject.chartingSpace.getContainer(point, GET_CONTAINER_PURPOSE.MOUSE_CLICK)
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point)
return
}
/* We check if the mouse is over a floatingObject/ */
container = thisObject.floatingSpace.getContainer(point)
if (container !== undefined && container.isClickeable === true) {
container.eventHandler.raiseEvent('onMouseClick', point)
return
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onMouseClick -> err = ' + err.stack) }
}
}
function onMouseOut (event) {
deactivateDragging(event)
/* When the mouse leaves the canvas, our elements needs to react to the fact that the mouse is over a far away place */
let thisEvent = {
pageX: VERY_LARGE_NUMBER,
pageY: VERY_LARGE_NUMBER
}
onMouseOver(thisEvent)
}
function onMouseUp (event) {
deactivateDragging(event)
}
function onMouseMove (event) {
try {
thisObject.mouse.event = event
thisObject.mouse.position.x = event.pageX
thisObject.mouse.position.y = event.pageY - CURRENT_TOP_MARGIN
thisObject.mouse.action = 'moving'
/* Processing the event */
let point = event
point.x = event.pageX
point.y = event.pageY - CURRENT_TOP_MARGIN
if (canvas.chartingSpace.viewport !== undefined) {
canvas.chartingSpace.viewport.mousePosition.x = point.x
canvas.chartingSpace.viewport.mousePosition.y = point.y
}
if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) {
if (floatingObjectDragStarted === true) {
let targetContainer = thisObject.floatingSpace.getContainer(point)
if (targetContainer !== undefined) {
if (targetContainer.id !== containerBeingDragged.id) {
containerBeingDragged.eventHandler.raiseEvent('onDragFinished', point)
containerBeingDragged = undefined
containerDragStarted = false
floatingObjectDragStarted = false
browserCanvas.style.cursor = 'auto'
ignoreNextClick = true
return
}
} else {
containerBeingDragged.eventHandler.raiseEvent('onDragFinished', point)
containerDragStarted = false
containerBeingDragged = undefined
floatingObjectDragStarted = false
browserCanvas.style.cursor = 'auto'
ignoreNextClick = true
return
}
}
dragVector.upX = point.x
dragVector.upY = point.y
checkDrag(event)
}
onMouseOver(event)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onMouseMove -> err = ' + err.stack) }
}
}
function onMouseOver (event) {
try {
let point = event
point.x = event.pageX
point.y = event.pageY - CURRENT_TOP_MARGIN
if (containerDragStarted === true) {
containerBeingDragged.eventHandler.raiseEvent('onMouseOver', point)
return
}
/* Then we check who is the current object underneeth the mounse. */
let container
/* We check if the mouse is over an element of the Strategy Space / */
if (thisObject.designSpace !== undefined) {
container = thisObject.designSpace.getContainer(point)
if (container !== undefined && container.detectMouseOver === true) {
containerFound()
return
}
}
/* We check if the mouse is over an element of the Top Space / */
if (thisObject.topSpace !== undefined) {
container = thisObject.topSpace.getContainer(point)
if (container !== undefined && container.detectMouseOver === true) {
containerFound()
return
}
}
/* We check if the mouse is over an element of the CockpitSpace / */
if (thisObject.cockpitSpace !== undefined) {
container = thisObject.cockpitSpace.getContainer(point)
if (container !== undefined && container.detectMouseOver === true) {
containerFound()
return
}
}
/* We check if the mouse is over a panel/ */
if (thisObject.panelsSpace !== undefined) {
container = thisObject.panelsSpace.getContainer(point)
if (container !== undefined && container.detectMouseOver === true) {
containerFound()
return
}
}
/* If it is not, then we check if it is over any of the existing containers at the Charting Space. */
if (thisObject.chartingSpace !== undefined) {
container = thisObject.chartingSpace.getContainer(point, GET_CONTAINER_PURPOSE.MOUSE_OVER)
if (container !== undefined && container.detectMouseOver === true) {
containerFound()
return
}
}
/* We check if the mouse is over a floatingObject/ */
if (thisObject.floatingSpace !== undefined) {
container = thisObject.floatingSpace.getContainer(point)
if (container !== undefined && container.detectMouseOver === true) {
containerFound()
return
}
}
function containerFound () {
if (lastContainerMouseOver !== undefined) {
if (container.id !== lastContainerMouseOver.id) {
lastContainerMouseOver.eventHandler.raiseEvent('onMouseNotOver', point)
}
}
container.eventHandler.raiseEvent('onMouseOver', point)
lastContainerMouseOver = container
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onMouseOver -> err = ' + err.stack) }
}
}
function onMouseWheel (event) {
try {
thisObject.mouse.event = event
thisObject.mouse.position.x = event.pageX
thisObject.mouse.position.y = event.pageY - CURRENT_TOP_MARGIN
thisObject.mouse.action = 'wheel'
// cross-browser wheel delta
var event = window.event || event // old IE support
event.delta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail))
/* We try first with panels. */
let point = {
x: event.pageX,
y: event.pageY - CURRENT_TOP_MARGIN
}
event.mousePosition = point
let container
container = canvas.panelsSpace.getContainer({ x: point.x, y: point.y })
if (container !== undefined && container.isWheelable === true) {
container.eventHandler.raiseEvent('onMouseWheel', event)
return false // This instructs the browser not to take the event and scroll the page.
}
/* We try the CockpitSpace. */
container = canvas.cockpitSpace.getContainer({ x: point.x, y: point.y })
if (container !== undefined && container.isWheelable === true) {
container.eventHandler.raiseEvent('onMouseWheel', event)
return false // This instructs the browser not to take the event and scroll the page.
}
/* Charting Space. */
container = canvas.chartingSpace.getContainer({ x: point.x, y: point.y }, GET_CONTAINER_PURPOSE.MOUSE_WHEEL)
if (container !== undefined && container.isWheelable === true) {
container.eventHandler.raiseEvent('onMouseWheel', event)
return false // This instructs the browser not to take the event and scroll the page.
}
if (container !== undefined) {
canvas.chartingSpace.viewport.onMouseWheel(event)
return false
}
/* We try second with floating objects. */
container = canvas.floatingSpace.getContainer({ x: point.x, y: point.y })
if (container !== undefined && container.isWheelable === true) {
container.eventHandler.raiseEvent('onMouseWheel', event)
return false // This instructs the browser not to take the event and scroll the page.
}
return false
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onMouseWheel -> err = ' + err.stack) }
}
}
function deactivateDragging (event) {
try {
if (containerDragStarted || viewPortBeingDragged || floatingObjectDragStarted) {
thisObject.eventHandler.raiseEvent('Drag Finished', undefined)
}
if (
containerDragStarted ||
floatingObjectDragStarted ||
viewPortBeingDragged
) {
ignoreNextClick = true
}
/* Turn off all the possible things that can be dragged. */
containerDragStarted = false
floatingObjectDragStarted = false
viewPortBeingDragged = false
if (containerBeingDragged !== undefined) {
containerBeingDragged.eventHandler.raiseEvent('onDragFinished', event)
containerBeingDragged = undefined
}
browserCanvas.style.cursor = 'auto'
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] deactivateDragging -> err = ' + err.stack) }
}
}
function checkDrag (event) {
try {
if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) {
thisObject.mouse.event = event
thisObject.mouse.position.x = event.pageX
thisObject.mouse.position.y = event.pageY - CURRENT_TOP_MARGIN
thisObject.mouse.action = 'dragging'
browserCanvas.style.cursor = 'grabbing'
thisObject.eventHandler.raiseEvent('Dragging', undefined)
if (viewPortBeingDragged) {
let displaceVector = {
x: dragVector.upX - dragVector.downX,
y: dragVector.upY - dragVector.downY
}
canvas.chartingSpace.viewport.displace(displaceVector)
}
if (containerDragStarted) {
if (containerBeingDragged !== undefined) {
if (containerBeingDragged.space === 'Charting Space') {
let downCopy = {
x: dragVector.downX,
y: dragVector.downY
}
let downNoZoom
downNoZoom = canvas.chartingSpace.viewport.unTransformThisPoint(downCopy)
let upCopy = {
x: dragVector.upX,
y: dragVector.upY
}
let upNoZoom
upNoZoom = canvas.chartingSpace.viewport.unTransformThisPoint(upCopy)
displaceVector = {
x: upNoZoom.x - downNoZoom.x,
y: upNoZoom.y - downNoZoom.y
}
let moveSucceed = containerBeingDragged.displace(displaceVector)
if (moveSucceed === false) {
deactivateDragging(event)
}
} else {
let displaceVector = {
x: dragVector.upX - dragVector.downX,
y: dragVector.upY - dragVector.downY
}
let moveSucceed = containerBeingDragged.displace(displaceVector)
if (moveSucceed === false) {
deactivateDragging(event)
}
}
}
}
/* Finally we set the starting point of the new dragVector at this current point. */
dragVector.downX = dragVector.upX
dragVector.downY = dragVector.upY
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] checkDrag -> err = ' + err.stack) }
}
}
}
+139
View File
@@ -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
}
+262
View File
@@ -0,0 +1,262 @@
/*
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,
maxHeight: undefined,
maxWidth: undefined,
scale: undefined,
eventHandler: undefined,
autoMinXScale: true,
autoMaxXScale: true,
autoMinYScale: true,
autoMaxYScale: true,
physics: physics,
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.scale = {
x: 0,
y: 0
}
thisObject.eventHandler = newEventHandler()
thisObject.eventHandler.name = 'Coordinate System'
let newXMax = -VERY_LARGE_NUMBER
let newXMin = VERY_LARGE_NUMBER
let noXValueReported = true
let newYMax = -VERY_LARGE_NUMBER
let newYMin = VERY_LARGE_NUMBER
let noYValueReported = true
return thisObject
function finalize () {
thisObject.eventHandler.finalize()
thisObject.eventHandler = undefined
}
function initialize (minValue, maxValue, pMaxWidth, pMaxHeight) {
/* Defines the min and max value of rate that we are going to transport to the available screen at the center position. */
thisObject.min.x = minValue.x
thisObject.max.x = maxValue.x
thisObject.min.y = minValue.y
thisObject.max.y = maxValue.y
thisObject.maxWidth = pMaxWidth
thisObject.maxHeight = pMaxHeight
recalculateScale()
}
function physics () {
let mustRecalculate = false
if ((thisObject.autoMinXScale === true || thisObject.autoMaxXScale === true) && noXValueReported === false) {
if (thisObject.autoMaxXScale === true && thisObject.max.x !== newXMax) {
thisObject.max.x = newXMax
mustRecalculate = true
}
if (thisObject.autoMaxXScale === true) {
newXMax = -VERY_LARGE_NUMBER
}
if (thisObject.autoMinXScale === true && thisObject.min.x !== newXMin) {
thisObject.min.x = newXMin
newXMin = VERY_LARGE_NUMBER
mustRecalculate = true
}
if (thisObject.autoMinXScale === true) {
newXMin = VERY_LARGE_NUMBER
}
/* Reseting this to start over at each cycle. */
noXValueReported = true
}
if ((thisObject.autoMinYScale === true || thisObject.autoMaxYScale === true) && noYValueReported === false) {
if (thisObject.autoMaxYScale === true && thisObject.max.y !== newYMax) {
thisObject.max.y = newYMax
mustRecalculate = true
}
if (thisObject.autoMaxYScale === true) {
newYMax = -VERY_LARGE_NUMBER
}
if (thisObject.autoMinYScale === true && thisObject.min.y !== newYMin) {
thisObject.min.y = newYMin
newYMin = VERY_LARGE_NUMBER
mustRecalculate = true
}
if (thisObject.autoMinYScale === true) {
newYMin = VERY_LARGE_NUMBER
}
/* Reseting this to start over at each cycle. */
noYValueReported = true
}
if (mustRecalculate === true) {
recalculateScale()
}
}
function reportXValue (value) {
if (thisObject.autoMinXScale === true) {
if (value < newXMin) { newXMin = value }
noXValueReported = false
}
if (thisObject.autoMaxXScale === true) {
if (value > newXMax) { newXMax = value }
noXValueReported = false
}
}
function reportYValue (value) {
if (thisObject.autoMinYScale === true) {
if (value < newYMin) { newYMin = value }
noYValueReported = false
}
if (thisObject.autoMaxYScale === true) {
if (value > newYMax) { newYMax = value }
noYValueReported = false
}
}
function zoomX (factor, mousePosition, container) {
let mouseAtCointainer = unTransformThisPoint(mousePosition, container)
let leftDistance = mouseAtCointainer.x
let rightDistance = container.frame.width - mouseAtCointainer.x
let diff = thisObject.max.x - thisObject.min.x
let min = thisObject.min.x + diff * factor * leftDistance / (container.frame.width / 2)
let max = thisObject.max.x - diff * factor * rightDistance / (container.frame.width / 2)
if (min < max) {
thisObject.min.x = min
thisObject.max.x = max
thisObject.recalculateScale()
}
}
function zoomY (factor, mousePosition, container) {
let mouseAtCointainer = unTransformThisPoint(mousePosition, container)
let topDistance = mouseAtCointainer.y
let bottomDistance = container.frame.height - mouseAtCointainer.y
let diff = thisObject.max.y - thisObject.min.y
let min = thisObject.min.y + diff * factor * bottomDistance / (container.frame.height / 2)
let max = thisObject.max.y - diff * factor * topDistance / (container.frame.height / 2)
if (min < max) {
thisObject.min.y = min
thisObject.max.y = max
thisObject.recalculateScale()
}
}
function recalculateScale (event) {
thisObject.scale.x = thisObject.maxWidth / (thisObject.max.x - thisObject.min.x)
thisObject.scale.y = thisObject.maxHeight / (thisObject.max.y - thisObject.min.y)
thisObject.eventHandler.raiseEvent('Scale Changed', event)
}
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,
y: thisObject.maxHeight - (point.y - thisObject.min.y) * thisObject.scale.y
}
return point
}
function transformThisPoint2 (point) {
point = {
x: (point.x - thisObject.min.x) * thisObject.scale.x,
y: (thisObject.maxHeight - point.y - thisObject.min.y) * thisObject.scale.y
}
return point
}
function unInverseTransform (point, inverseY) {
point = {
x: (point.x / thisObject.scale.x) + thisObject.min.x,
y: (inverseY - point.y) / thisObject.scale.y + thisObject.min.y
}
return point
}
function inverseTransformUncappedY (point, inverseY) {
point = {
x: (point.x - thisObject.min.x) * thisObject.scale.x,
y: (inverseY - point.y) * thisObject.scale.y
}
return point
}
}
+475
View File
@@ -0,0 +1,475 @@
function newEdgeEditor () {
const MODULE_NAME = 'Edge Editor'
let thisObject = {
container: undefined,
fitFunction: undefined,
isVisible: true,
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 buttonUsedForDragging
let isMouseOver
let whereIsMouseOver = 'outside'
let coordinateSystem
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
let onDragStartedEventSubscriptionId
let mouse = {
position: {
x: 0,
y: 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
}
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) {
isMouseOver = true
mouse = {
position: {
x: event.x,
y: event.y
}
}
}
function onMouseNotOver () {
isMouseOver = false
}
function onDragStarted (event) {
switch (event.buttons) {
case 1: {
buttonUsedForDragging = 'left mouse button'
break
}
case 2: {
buttonUsedForDragging = 'right mouse button'
break
}
}
}
function getContainer (event, purpose) {
if (thisObject.container.frame.isThisPointHere(event, undefined, undefined, -EDGE_SIZE) === true && event.shiftKey !== true) {
let point = {
x: event.x,
y: event.y
}
point = unTransformThisPoint(point, thisObject.container)
if (point.x <= 0) {
whereIsMouseOver = 'left'
return thisObject.container
}
if (point.x >= thisObject.container.frame.width) {
whereIsMouseOver = 'right'
return thisObject.container
}
if (point.y <= 0) {
whereIsMouseOver = 'top'
return thisObject.container
}
if (point.y >= thisObject.container.frame.height) {
whereIsMouseOver = 'bottom'
return thisObject.container
}
whereIsMouseOver = 'center'
switch (purpose) {
case GET_CONTAINER_PURPOSE.MOUSE_OVER:
return // We will let the Time Machine to handle this situation.
break
case GET_CONTAINER_PURPOSE.DRAGGING:
return thisObject.container
break
}
}
}
function physics () {
if (thisObject.container.frame.position.x === 0 && thisObject.container.frame.position.y === 0) { return }
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 = 100
const MIN_HEIGHT = 50
switch (whereIsMouseOver) {
case 'center': {
switch (buttonUsedForDragging) {
case 'right mouse button': {
/* 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 = thisObject.container.parentContainer.frame.position.x + dragVector.x
thisObject.container.parentContainer.frame.position.y = thisObject.container.parentContainer.frame.position.y + dragVector.y
thisObject.container.parentContainer.eventHandler.raiseEvent('onDisplace')
break
}
case 'left mouse button': {
let point = {
x: -dragVector.x,
y: -dragVector.y
}
let newMinDate = getDateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
let newMaxRate = getRateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
let xDifferenceMaxMin = coordinateSystem.max.x - coordinateSystem.min.x
let yDifferenceMaxMin = coordinateSystem.max.y - coordinateSystem.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)
}
}
thisObject.container.parentContainer.eventHandler.raiseEvent('onMouseOver', mouse.position)
break
}
case 'top' : {
if (thisObject.container.parentContainer.frame.height - dragVector.y < MIN_HEIGHT && dragVector.y > 0) {
return
}
let point = {
x: dragVector.x,
y: dragVector.y
}
let newMaxRate = getRateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
thisObject.container.parentContainer.frame.position.y = thisObject.container.parentContainer.frame.position.y + dragVector.y
thisObject.container.parentContainer.frame.height = thisObject.container.parentContainer.frame.height - dragVector.y
switch (buttonUsedForDragging) {
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 'right mouse button': {
coordinateSystem.maxHeight = thisObject.container.parentContainer.frame.height
coordinateSystem.recalculateScale()
break
}
}
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
break
}
case 'bottom' : {
if (thisObject.container.parentContainer.frame.height + dragVector.y < MIN_HEIGHT && dragVector.y < 0) {
return
}
let point = {
x: dragVector.x,
y: dragVector.y + thisObject.container.frame.height
}
let newMinRate = getRateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
thisObject.container.parentContainer.frame.height = thisObject.container.parentContainer.frame.height + dragVector.y
switch (buttonUsedForDragging) {
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 'right mouse button': {
coordinateSystem.maxHeight = thisObject.container.parentContainer.frame.height
coordinateSystem.recalculateScale()
break
}
}
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
break
}
case 'left' : {
if (thisObject.container.parentContainer.frame.width - dragVector.x < MIN_WIDTH && dragVector.x > 0) {
return
}
let point = {
x: dragVector.x,
y: dragVector.y
}
let newMinDate = getDateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
thisObject.container.parentContainer.frame.position.x = thisObject.container.parentContainer.frame.position.x + dragVector.x
thisObject.container.parentContainer.frame.width = thisObject.container.parentContainer.frame.width - dragVector.x
switch (buttonUsedForDragging) {
case 'left mouse button': {
coordinateSystem.min.x = newMinDate.valueOf()
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
coordinateSystem.recalculateScale()
break
}
case 'right mouse button': {
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
coordinateSystem.recalculateScale()
break
}
}
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
break
}
case 'right' : {
if (thisObject.container.parentContainer.frame.width + dragVector.x < MIN_WIDTH && dragVector.x < 0) {
return
}
let point = {
x: dragVector.x + thisObject.container.frame.width,
y: dragVector.y
}
let newMaxDate = getDateFromPointAtContainer(point, thisObject.container.parentContainer, coordinateSystem)
thisObject.container.parentContainer.frame.width = thisObject.container.parentContainer.frame.width + dragVector.x
switch (buttonUsedForDragging) {
case 'left mouse button': {
coordinateSystem.max.x = newMaxDate.valueOf()
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
coordinateSystem.recalculateScale()
break
}
case 'right mouse button': {
coordinateSystem.maxWidth = thisObject.container.parentContainer.frame.width
coordinateSystem.recalculateScale()
break
}
}
thisObject.container.parentContainer.eventHandler.raiseEvent('Dimmensions Changed', event)
break
}
}
}
function drawForeground () {
let MARGIN = 1
let edgeSize
let lineWidth
if (whereIsMouseOver === 'outside' || isMouseOver === false) {
edgeSize = EDGE_SIZE / 2
lineWidth = 0.1
} else {
edgeSize = EDGE_SIZE
lineWidth = 0.5
}
const OPACITY = 1
pointA1 = {
x: 0,
y: 0
}
pointA2 = {
x: thisObject.container.frame.width,
y: 0
}
pointA3 = {
x: thisObject.container.frame.width,
y: thisObject.container.frame.height
}
pointA4 = {
x: 0,
y: thisObject.container.frame.height
}
pointB1 = {
x: 0,
y: 0
}
pointB2 = {
x: thisObject.container.frame.width,
y: 0
}
pointB3 = {
x: thisObject.container.frame.width,
y: thisObject.container.frame.height
}
pointB4 = {
x: 0,
y: thisObject.container.frame.height
}
pointA1 = transformThisPoint(pointA1, thisObject.container)
pointA2 = transformThisPoint(pointA2, thisObject.container)
pointA3 = transformThisPoint(pointA3, thisObject.container)
pointA4 = transformThisPoint(pointA4, thisObject.container)
pointB1 = transformThisPoint(pointB1, thisObject.container)
pointB2 = transformThisPoint(pointB2, thisObject.container)
pointB3 = transformThisPoint(pointB3, thisObject.container)
pointB4 = transformThisPoint(pointB4, thisObject.container)
pointA1 = {
x: pointA1.x - MARGIN,
y: pointA1.y - MARGIN
}
pointA2 = {
x: pointA2.x + MARGIN,
y: pointA2.y - MARGIN
}
pointA3 = {
x: pointA3.x + MARGIN,
y: pointA3.y + MARGIN
}
pointA4 = {
x: pointA4.x - MARGIN,
y: pointA4.y + MARGIN
}
pointB1 = {
x: pointB1.x - edgeSize,
y: pointB1.y - edgeSize
}
pointB2 = {
x: pointB2.x + edgeSize,
y: pointB2.y - edgeSize
}
pointB3 = {
x: pointB3.x + edgeSize,
y: pointB3.y + edgeSize
}
pointB4 = {
x: pointB4.x - edgeSize,
y: pointB4.y + edgeSize
}
pointA1 = canvas.chartingSpace.viewport.fitIntoViewport(pointA1)
pointA2 = canvas.chartingSpace.viewport.fitIntoViewport(pointA2)
pointA3 = canvas.chartingSpace.viewport.fitIntoViewport(pointA3)
pointA4 = canvas.chartingSpace.viewport.fitIntoViewport(pointA4)
pointB1 = canvas.chartingSpace.viewport.fitIntoViewport(pointB1)
pointB2 = canvas.chartingSpace.viewport.fitIntoViewport(pointB2)
pointB3 = canvas.chartingSpace.viewport.fitIntoViewport(pointB3)
pointB4 = canvas.chartingSpace.viewport.fitIntoViewport(pointB4)
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(pointA1.x, pointA1.y)
browserCanvasContext.lineTo(pointA2.x, pointA2.y)
browserCanvasContext.lineTo(pointB2.x, pointB2.y)
browserCanvasContext.lineTo(pointB1.x, pointB1.y)
browserCanvasContext.lineTo(pointA1.x, pointA1.y)
browserCanvasContext.closePath()
drawEdge('top')
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(pointA2.x, pointA2.y)
browserCanvasContext.lineTo(pointA3.x, pointA3.y)
browserCanvasContext.lineTo(pointB3.x, pointB3.y)
browserCanvasContext.lineTo(pointB2.x, pointB2.y)
browserCanvasContext.lineTo(pointA2.x, pointA2.y)
browserCanvasContext.closePath()
drawEdge('right')
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(pointA3.x, pointA3.y)
browserCanvasContext.lineTo(pointA4.x, pointA4.y)
browserCanvasContext.lineTo(pointB4.x, pointB4.y)
browserCanvasContext.lineTo(pointB3.x, pointB3.y)
browserCanvasContext.lineTo(pointA3.x, pointA3.y)
browserCanvasContext.closePath()
drawEdge('bottom')
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(pointA4.x, pointA4.y)
browserCanvasContext.lineTo(pointA1.x, pointA1.y)
browserCanvasContext.lineTo(pointB1.x, pointB1.y)
browserCanvasContext.lineTo(pointB4.x, pointB4.y)
browserCanvasContext.lineTo(pointA4.x, pointA4.y)
browserCanvasContext.closePath()
drawEdge('left')
function drawEdge (edgeType) {
if (whereIsMouseOver === edgeType && 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()
}
}
}
+309
View File
@@ -0,0 +1,309 @@
function newPlottersManager () {
const MODULE_NAME = 'Plotters Manager'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let timeFrame = INITIAL_TIME_PERIOD
let datetime = NEW_SESSION_INITIAL_DATE
let thisObject = {
fitFunction: undefined,
container: undefined,
payload: undefined,
connectors: [],
setDatetime: setDatetime,
setTimeFrame: setTimeFrame,
setCoordinateSystem: setCoordinateSystem,
draw: draw,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
thisObject.connectors = []
let initializationReady = false
let layersPanel
let onLayerStatusChangedEventSuscriptionId
let coordinateSystem
setupContainer()
return thisObject
function setupContainer () {
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
}
function finalize () {
layersPanel.container.eventHandler.stopListening(onLayerStatusChangedEventSuscriptionId)
layersPanel = undefined
for (let i = 0; i < thisObject.connectors.length; i++) {
let connector = thisObject.connectors[i]
/* Then the panels. */
for (let j = 0; j < connector.panels.length; j++) {
canvas.panelsSpace.destroyPanel(connector.panels[j])
connector.panels[j] = undefined
}
connector.panels = undefined
/* Finalize the plotters */
if (connector.plotter.finalize !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.plotter.onRecordChangeEventsSubscriptionId)
connector.plotter.finalize()
}
connector.plotter = undefined
/* Finally the Storage Objects */
finalizeStorage(connector.storage)
connector.storage = undefined
connector = undefined
}
thisObject.connectors = []
coordinateSystem = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
}
function finalizeStorage (storage) {
storage.eventHandler.stopListening(storage.onMarketFileLoadedLayerEventsSubscriptionId)
storage.eventHandler.stopListening(storage.onDailyFileLoadedLayerEventsSubscriptionId)
storage.eventHandler.stopListening(storage.onSingleFileLoadedLayerEventsSubscriptionId)
storage.eventHandler.stopListening(storage.onFileSequenceLoadedLayerEventsSubscriptionId)
storage.eventHandler.stopListening(storage.onDailyFileLoadedPlotterEventsSubscriptionId)
storage.finalize()
}
function initialize (pLayersPanel) {
/* Remember the Layers Panel */
layersPanel = pLayersPanel
/* Listen to the event of change of status */
onLayerStatusChangedEventSuscriptionId = layersPanel.container.eventHandler.listenToEvent('Layer Status Changed', onLayerStatusChanged)
}
function initializePlotter (layer) {
try {
/* Before Initializing a Plotter, we need the Storage it will use, loaded with the files it will initially need. */
let storage = newProductStorage(layer.payload.node.id)
/*
Before Initializing the Storage, we will put the Layer to listen to the events the storage will raise every time a file is loaded,
so that the UI can somehow show this. There are different types of events.
*/
for (let i = 0; i < layer.definition.referenceParent.referenceParent.datasets.length; i++) {
let dataset = layer.definition.referenceParent.referenceParent.datasets[i]
switch (dataset.code.type) {
case 'Market Files': {
storage.onMarketFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Market File Loaded', layer.onMarketFileLoaded)
}
break
case 'Daily Files': {
storage.onDailyFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', layer.onDailyFileLoaded)
}
break
case 'Single File': {
storage.onSingleFileLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('Single File Loaded', layer.onSingleFileLoaded)
}
break
case 'File Sequence': {
storage.onFileSequenceLoadedLayerEventsSubscriptionId = storage.eventHandler.listenToEvent('File Sequence Loaded', layer.onFileSequenceLoaded)
}
break
default: {
if (ERROR_LOG === true) {
logger.write('[ERROR] initializePlotter -> Dataset Type Incorrect or Undefined -> dataset.type = ' + dataset.type)
}
return
}
}
}
let baseAsset = layer.definition.referenceParent.parentNode.referenceParent.baseAsset.referenceParent.code.codeName
let quotedAsset = layer.definition.referenceParent.parentNode.referenceParent.quotedAsset.referenceParent.code.codeName
let market = {
baseAsset: baseAsset,
quotedAsset: quotedAsset
}
let product = layer.definition.referenceParent.referenceParent
let bot = layer.definition.referenceParent.referenceParent.parentNode
let dataMine = layer.definition.referenceParent.referenceParent.parentNode.parentNode
let exchange = layer.definition.referenceParent.parentNode.referenceParent.parentNode.parentNode
let plotterModule = layer.definition.referenceParent.referenceParent.referenceParent
let session
if (layer.definition.referenceParent.parentNode.parentNode !== undefined) {
if (layer.definition.referenceParent.parentNode.parentNode.type === 'Session Reference') {
if (layer.definition.referenceParent.parentNode.parentNode.referenceParent !== undefined) {
session = layer.definition.referenceParent.parentNode.parentNode.referenceParent
}
}
}
storage.initialize(
dataMine,
bot,
session,
product,
exchange,
market,
datetime,
timeFrame,
onProductStorageInitialized
)
function onProductStorageInitialized (err) {
try {
if (err.result === GLOBAL.DEFAULT_OK_RESPONSE.result) {
/* Now we have all the initial data loaded and ready to be delivered to the new instance of the plotter. */
let plotter
if (plotterModule.code.isLegacy !== true) {
plotter = newPlotter()
} else {
plotter = getNewPlotter(dataMine.code.codeName, plotterModule.parentNode.code.codeName, plotterModule.code.codeName)
}
plotter.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
plotter.container.frame.position.x = thisObject.container.frame.width / 2 - plotter.container.frame.width / 2
plotter.container.frame.position.y = thisObject.container.frame.height / 2 - plotter.container.frame.height / 2
plotter.fitFunction = thisObject.fitFunction
plotter.initialize(storage, datetime, timeFrame, coordinateSystem, onPlotterInizialized, product)
function onPlotterInizialized () {
try {
let connector = {
layer: layer,
plotter: plotter,
storage: storage
}
/* Let the Plotter listen to the event of Cursor Files loaded, so that it can react recalculating if needed. */
plotter.onDailyFileLoadedPlotterEventsSubscriptionId = storage.eventHandler.listenToEvent('Daily File Loaded', plotter.onDailyFileLoaded)
/* Lets load now this plotter panels. */
connector.panels = []
if (product !== undefined) {
for (let i = 0; i < plotterModule.panels.length; i++) {
let panel = plotterModule.panels[i]
let parameters = {
dataMine: dataMine.code.codeName,
plotterCodeName: plotterModule.parentNode.code.codeName,
moduleCodeName: plotterModule.code.codeName,
panelNode: panel
}
let owner = thisObject.payload.node.payload.parentNode.id // Panels are owned by the time machine.
let plotterPanelHandle = canvas.panelsSpace.createNewPanel('Plotter Panel', parameters, owner, layer.session)
let plotterPanel = canvas.panelsSpace.getPanel(plotterPanelHandle)
/* Connect Panel to the Plotter via an Event. */
connector.plotter.onRecordChangeEventsSubscriptionId = connector.plotter.container.eventHandler.listenToEvent('Current Record Changed', plotterPanel.onRecordChange)
connector.panels.push(plotterPanelHandle)
}
connector.layer.panels = connector.panels
}
thisObject.connectors.push(connector)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> onProductStorageInitialized -> onPlotterInizialized -> err = ' + err.stack) }
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> onProductStorageInitialized -> err = ' + err.stack) }
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initializePlotter -> err = ' + err.stack) }
}
}
function onLayerStatusChanged (layer) {
if (layer.status === LAYER_STATUS.LOADING) {
/* Lets see if we can find the Plotter of this card on our Active Plotters list, other wise we will initialize it */
let found = false
for (let i = 0; i < thisObject.connectors.length; i++) {
let connector = thisObject.connectors[i]
if (connector.layer.payload.node.id === layer.payload.node.id) {
found = true
}
}
if (found === false) {
initializePlotter(layer, onProductPlotterInitialized)
function onProductPlotterInitialized (err) {
/* There is no policy yet of what to do if this fails. */
}
}
}
if (layer.status === LAYER_STATUS.OFF) {
/* If the plotter of this card is not on our Active Plotters list, then we remove it. */
for (let i = 0; i < thisObject.connectors.length; i++) {
let connector = thisObject.connectors[i]
if (connector.layer.payload.node.id === layer.payload.node.id) {
/* Then the panels. */
for (let j = 0; j < connector.panels.length; j++) {
canvas.panelsSpace.destroyPanel(connector.panels[j])
}
/* Finally the Storage Objects */
if (connector.plotter.finalize !== undefined) {
connector.plotter.container.eventHandler.stopListening(connector.plotter.onRecordChangeEventsSubscriptionId)
connector.plotter.container.finalize()
connector.plotter.finalize()
}
finalizeStorage(connector.storage)
thisObject.connectors.splice(i, 1) // Delete item from array.
return // We already found the product woth changes and processed it.
}
}
}
}
function setTimeFrame (pTimeFrame) {
timeFrame = pTimeFrame
for (let i = 0; i < thisObject.connectors.length; i++) {
let connector = thisObject.connectors[i]
connector.layer.setTimeFrame(timeFrame)
connector.storage.setTimeFrame(timeFrame)
connector.plotter.setTimeFrame(timeFrame)
}
}
function setDatetime (pDatetime) {
datetime = pDatetime
for (let i = 0; i < thisObject.connectors.length; i++) {
let connector = thisObject.connectors[i]
connector.layer.setDatetime(pDatetime)
connector.storage.setDatetime(pDatetime)
connector.plotter.setDatetime(pDatetime)
}
}
function setCoordinateSystem (pCoordinateSystem) {
coordinateSystem = pCoordinateSystem
for (let i = 0; i < thisObject.connectors.length; i++) {
let connector = thisObject.connectors[i]
connector.plotter.setCoordinateSystem(coordinateSystem)
}
}
function getContainer (point) {
}
function draw () {
if (thisObject.connectors === undefined) { return } // We need to wait
/* First the Product Plotters. */
for (let i = 0; i < thisObject.connectors.length; i++) {
let connector = thisObject.connectors[thisObject.connectors.length - i - 1]
connector.plotter.draw()
}
}
}
+629
View File
@@ -0,0 +1,629 @@
/*
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,
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()
let mouse = {
position: {
x: 0,
y: 0
}
}
let drawScales = false
let syncWithDesignerLoop = 0
let timelineChartsMap = new Map()
let onViewportPositionChangedEventSuscriptionId
let onViewportZoomChangedEventSuscriptionId
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 = TIME_MACHINE_WIDTH
thisObject.container.frame.height = TIME_MACHINE_HEIGHT
}
function finalize () {
canvas.chartingSpace.viewport.eventHandler.stopListening(onViewportPositionChangedEventSuscriptionId)
canvas.chartingSpace.viewport.eventHandler.stopListening(onViewportZoomChangedEventSuscriptionId)
timeMachineCoordinateSystem.eventHandler.stopListening(onScaleChangedEventSubscriptionId)
if (thisObject.timeScale !== undefined) {
finalizeTimeScale()
}
if (thisObject.rateScale !== undefined) {
finalizeRateScale()
}
if (thisObject.timeFrameScale !== undefined) {
finalizeTimeFrameScale()
}
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSuscriptionId)
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
let timelineChart = thisObject.timelineCharts[i]
timelineChart.container.eventHandler.stopListening(timelineChart.onChildrenMouseOverEventSuscriptionId)
timelineChart.finalize()
}
thisObject.timelineCharts = undefined
thisObject.fitFunction = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
thisObject.edgeEditor = undefined
mouse = undefined
timelineChartsMap = undefined
timeMachineCoordinateSystem.finalize()
timeMachineCoordinateSystem = undefined
}
function finalizeTimeScale () {
if (thisObject.timeScale === undefined) { return }
thisObject.timeScale.container.eventHandler.stopListening(timeScaleMouseOverEventSuscriptionId)
thisObject.timeScale.finalize()
thisObject.timeScale = undefined
}
function finalizeRateScale () {
if (thisObject.rateScale === undefined) { return }
thisObject.rateScale.container.eventHandler.stopListening(rateScaleMouseOverEventSuscriptionId)
thisObject.rateScale.finalize()
thisObject.rateScale = undefined
}
function finalizeTimeFrameScale () {
if (thisObject.timeFrameScale === undefined) { return }
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleEventSuscriptionId)
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleMouseOverEventSuscriptionId)
thisObject.timeFrameScale.finalize()
thisObject.timeFrameScale = undefined
}
function initialize (callBackFunction) {
timeFrame = INITIAL_TIME_PERIOD
loadFrame(thisObject.payload, thisObject.container.frame)
// thisObject.container.frame.position.x = 0
// thisObject.container.frame.position.y = 0
recalculateCoordinateSystem()
recalculateCurrentDatetime()
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
onViewportPositionChangedEventSuscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent('Position Changed', onViewportPositionChanged)
onViewportZoomChangedEventSuscriptionId = canvas.chartingSpace.viewport.eventHandler.listenToEvent('Zoom Changed', onViewportZoomChanged)
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 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 onViewportZoomChanged (event) {
if (thisObject.container.frame.isInViewPort()) {
recalculateCurrentDatetime()
}
}
function onViewportPositionChanged () {
if (thisObject.container.frame.isInViewPort()) {
recalculateCurrentDatetime()
}
}
function onScaleChanged () {
recalculateCurrentDatetime()
}
function recalculateCurrentDatetime () {
/*
The view port was moved or the view port zoom level was changed and the center of the screen points to a different datetime that we
must calculate.
*/
let center = {
x: (canvas.chartingSpace.viewport.visibleArea.bottomRight.x - canvas.chartingSpace.viewport.visibleArea.bottomLeft.x) / 2,
y: (canvas.chartingSpace.viewport.visibleArea.bottomRight.y - canvas.chartingSpace.viewport.visibleArea.topRight.y) / 2
}
center = unTransformThisPoint(center, thisObject.container)
center = timeMachineCoordinateSystem.unInverseTransform(center, thisObject.container.frame.height)
datetime = new Date(center.x)
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
let timelineChart = thisObject.timelineCharts[i]
timelineChart.setDatetime(datetime)
}
}
function fitFunction (point, fullVisible, margin, topMargin, bottomMargin) {
/* We prevent a point to be out of the container AND out of the Charting Space in general */
let returnPoint = {
x: point.x,
y: point.y
}
let upCorner = {
x: 0,
y: 0
}
let bottonCorner = {
x: thisObject.container.frame.width,
y: thisObject.container.frame.height
}
upCorner = transformThisPoint(upCorner, thisObject.container)
bottonCorner = transformThisPoint(bottonCorner, thisObject.container)
/* Checking against the container limits. */
if (margin === undefined) { margin = 0 }
if (topMargin === undefined) { topMargin = 0 }
if (bottomMargin === undefined) { bottomMargin = 0 }
if (returnPoint.x - margin < upCorner.x) { returnPoint.x = upCorner.x + margin }
if (returnPoint.x + margin > bottonCorner.x) { returnPoint.x = bottonCorner.x - margin }
if (returnPoint.y - margin - topMargin < upCorner.y) { returnPoint.y = upCorner.y + margin + topMargin }
if (returnPoint.y + margin + bottomMargin > bottonCorner.y) { returnPoint.y = bottonCorner.y - margin - bottomMargin }
returnPoint = canvas.chartingSpace.fitFunction(returnPoint, fullVisible)
return returnPoint
}
function physics () {
thisObject.edgeEditor.physics()
timeMachineCoordinateSystem.physics()
saveFrame(thisObject.payload, thisObject.container.frame)
if (thisObject.container.frame.isInViewPort()) {
childrenPhysics()
syncWithDesigner()
}
panelPhysics()
}
function panelPhysics () {
if (thisObject.container.frame.isInViewPort() && canvas.chartingSpace.viewport.zoomTargetLevel > ZOOM_OUT_THRESHOLD_FOR_HIDDING_PANELS) {
canvas.panelsSpace.unHide(thisObject.payload.node.id, 'Layers Panel')
canvas.panelsSpace.unHide(thisObject.payload.node.id, 'Plotter Panel')
} else {
canvas.panelsSpace.hide(thisObject.payload.node.id, 'Layers Panel')
canvas.panelsSpace.hide(thisObject.payload.node.id, 'Plotter Panel')
}
}
function syncWithDesigner () {
syncWithDesignerTimelineCharts()
syncWithDesignerScales()
}
function syncWithDesignerScales () {
if (thisObject.payload.node === undefined) {
finalizeTimeScale()
finalizeRateScale()
finalizeTimeFrameScale()
return
}
if (thisObject.payload.node.timeScale === undefined && thisObject.timeScale !== undefined) {
finalizeTimeScale()
}
if (thisObject.payload.node.timeScale !== undefined && thisObject.timeScale === undefined) {
initializeTimeScale()
}
if (thisObject.payload.node.rateScale === undefined && thisObject.rateScale !== undefined) {
finalizeRateScale()
}
if (thisObject.payload.node.rateScale !== undefined && thisObject.rateScale === undefined) {
initializeRateScale()
}
if (thisObject.payload.node.timeFrameScale === undefined && thisObject.timeFrameScale !== undefined) {
finalizeTimeFrameScale()
}
if (thisObject.payload.node.timeFrameScale !== undefined && thisObject.timeFrameScale === undefined) {
initializeTimeFrameScale()
}
}
function syncWithDesignerTimelineCharts () {
syncWithDesignerLoop = syncWithDesignerLoop + 0.00000000001
for (let j = 0; j < thisObject.payload.node.timelineCharts.length; j++) {
let node = thisObject.payload.node.timelineCharts[j]
let timelineChart = timelineChartsMap.get(node.id)
if (timelineChart === undefined) {
/* The timeline timelineChart node is new, thus we need to initialize a new timelineChart */
initializeTimelineChart(node, syncWithDesignerLoop)
} else {
/* The time machine already exists, we tag it as existing at the current loop. */
timelineChart.syncWithDesignerLoop = syncWithDesignerLoop
}
}
/* We check all the timeMachines we have to see if we need to remove any of them */
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
let timelineChart = thisObject.timelineCharts[i]
if (timelineChart.syncWithDesignerLoop < syncWithDesignerLoop) {
/* Must be removed */
timelineChart.container.eventHandler.stopListening(timelineChart.onChildrenMouseOverEventSuscriptionId)
timelineChart.finalize()
timelineChartsMap.delete(timelineChart.nodeId)
thisObject.timelineCharts.splice(i, 1)
/* We remove one at the time */
return
}
}
function initializeTimelineChart (node, syncWithDesignerLoop) {
let timelineChart = newTimelineChart()
timelineChart.syncWithDesignerLoop = syncWithDesignerLoop
timelineChart.payload = node.payload
timelineChart.nodeId = node.id
timelineChartsMap.set(node.id, timelineChart)
timelineChart.payload.uiObject.setValue('Loading...')
/* Setting up the new timeline timelineChart. */
timelineChart.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
timelineChart.container.fitFunction = thisObject.container.fitFunction
timelineChart.fitFunction = thisObject.fitFunction
timelineChart.container.frame.width = thisObject.container.frame.width
timelineChart.container.frame.height = thisObject.container.frame.height
timelineChart.container.frame.position.x = 0
timelineChart.container.frame.position.y = 0
timelineChart.initialize(timeMachineCoordinateSystem, timeFrame)
/* we will store the event suscription id as a property of the timelineChart, to avoid keeping it an a separate array */
timelineChart.onChildrenMouseOverEventSuscriptionId = timelineChart.container.eventHandler.listenToEvent('onChildrenMouseOver', onChildrenMouseOver)
thisObject.timelineCharts.push(timelineChart)
timelineChart.payload.uiObject.setValue('')
function onChildrenMouseOver (event) {
thisObject.container.eventHandler.raiseEvent('onMouseOver', event)
}
}
}
function childrenPhysics () {
if (thisObject.timeScale !== undefined) {
thisObject.timeScale.physics()
}
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.physics()
}
if (thisObject.timeFrameScale !== undefined) {
thisObject.timeFrameScale.physics()
}
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
let timelineChart = thisObject.timelineCharts[i]
timelineChart.physics()
}
}
function drawBackground () {
drawChartsBackground()
if (thisObject.container.frame.isInViewPort()) {
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
let timelineChart = thisObject.timelineCharts[thisObject.timelineCharts.length - i - 1]
timelineChart.drawBackground()
}
}
}
function drawChartsBackground () {
drawContainerBackground(thisObject.container, UI_COLOR.WHITE, 0.5, thisObject.fitFunction)
}
function draw () {
if (thisObject.payload === undefined) { return }
if (thisObject.payload.node === undefined) { return }
if (thisObject.container.frame.isInViewPort()) {
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
let timelineChart = thisObject.timelineCharts[thisObject.timelineCharts.length - i - 1]
timelineChart.draw()
}
if (drawScales === true) {
if (thisObject.timeScale !== undefined && thisObject.timeScale.isVisible === true) { thisObject.timeScale.draw() }
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.draw() }
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.draw() }
}
} else {
let icon = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
if (icon !== undefined) {
if (icon.canDrawIcon === true) {
let imageSize = 40
let imagePosition = {
x: thisObject.container.frame.width / 2,
y: thisObject.container.frame.height / 2
}
imagePosition = transformThisPoint(imagePosition, thisObject.container)
imagePosition = thisObject.fitFunction(imagePosition, true)
browserCanvasContext.drawImage(
icon,
imagePosition.x - imageSize / 2,
imagePosition.y - imageSize / 2,
imageSize,
imageSize)
}
}
}
}
function drawForeground () {
if (thisObject.container.frame.isInViewPort()) {
for (let i = 0; i < thisObject.timelineCharts.length; i++) {
let timelineChart = thisObject.timelineCharts[thisObject.timelineCharts.length - i - 1]
timelineChart.drawForeground()
}
if (drawScales === true) {
if (thisObject.timeScale !== undefined && thisObject.timeScale.isVisible === true) { thisObject.timeScale.drawForeground() }
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.drawForeground() }
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.drawForeground() }
}
drawLabel()
thisObject.edgeEditor.drawForeground()
}
}
function drawLabel () {
/* Draw Title Above the Container */
let position = {
x: 0,
y: 0
}
let imageSize = 25
let fontSize = 25
let opacity = 1
let icon = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
position = transformThisPoint(position, thisObject.container)
printLabel(thisObject.payload.node.name, position.x + 30, position.y - 10, opacity, fontSize)
if (icon !== undefined) {
if (icon.canDrawIcon === true) {
browserCanvasContext.drawImage(
icon, position.x - 0,
position.y - 30,
imageSize,
imageSize)
}
}
}
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
)
}
}
+407
View File
@@ -0,0 +1,407 @@
function newTimelineChart () {
const MODULE_NAME = 'Timeline Chart'
const INFO_LOG = false
const INTENSIVE_LOG = false
const ERROR_LOG = true
let logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let timeFrame = INITIAL_TIME_PERIOD
let datetime = NEW_SESSION_INITIAL_DATE
let thisObject = {
container: undefined,
fitFunction: undefined,
rateScale: undefined,
timeFrameScale: undefined,
payload: undefined,
layersManager: undefined,
plotterManager: undefined,
upstreamTimeFrame: undefined,
setDatetime: setDatetime,
setTimeFrame: setTimeFrame,
physics: physics,
draw: draw,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
let timeMachineCoordinateSystem
let timelineChartCoordinateSystem = newCoordinateSystem()
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 () {
coordinateSystem.eventHandler.stopListening(scaleChangedEventSubscriptionId)
if (thisObject.layersManager !== undefined) {
finalizeLayersManager()
}
if (thisObject.rateScale !== undefined) {
finalizeRateScale()
}
if (thisObject.timeFrameScale !== undefined) {
finalizeTimeFrameScale()
}
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSuscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
mouse = undefined
logger = undefined
timeMachineCoordinateSystem = undefined
timelineChartCoordinateSystem.finalize()
timelineChartCoordinateSystem = undefined
coordinateSystem = undefined
layersPanel = undefined
layersPanelHandle = undefined
}
function finalizeLayersManager () {
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.finalize()
}
thisObject.plotterManager = undefined
thisObject.layersManager = undefined
canvas.panelsSpace.destroyPanel(layersPanelHandle)
}
function finalizeTimeFrameScale () {
if (thisObject.timeFrameScale === undefined) { return }
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleEventSuscriptionId)
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleMouseOverEventSuscriptionId)
thisObject.timeFrameScale.finalize()
thisObject.timeFrameScale = undefined
if (thisObject.upstreamTimeFrame !== undefined) {
timeFrame = thisObject.upstreamTimeFrame
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setTimeFrame(timeFrame)
}
}
}
function finalizeRateScale () {
if (thisObject.rateScale === undefined) { return }
thisObject.rateScale.container.eventHandler.stopListening(rateScaleMouseOverEventSuscriptionId)
thisObject.container.parentContainer.eventHandler.stopListening(rateScaleUpstreamEventSuscriptionId)
thisObject.rateScale.finalize()
thisObject.rateScale = undefined
/* Resets the local container with the dimessions of its parent, the Time Machine */
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.container.frame.height = thisObject.container.parentContainer.frame.height
thisObject.container.frame.width = thisObject.container.parentContainer.frame.width
}
function initialize (pTimeMachineCoordinateSystem, pTimeFrame) {
/* We load the logow we will need for the background. */
timeMachineCoordinateSystem = pTimeMachineCoordinateSystem
coordinateSystem = timeMachineCoordinateSystem
initializeCoordinateSystem()
timeFrame = pTimeFrame
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
scaleChangedEventSubscriptionId = timeMachineCoordinateSystem.eventHandler.listenToEvent('Scale Changed', onScaleChanged)
}
function initializeCoordinateSystem () {
let minValue = {
x: timeMachineCoordinateSystem.min.x,
y: 0
}
let maxValue = {
x: timeMachineCoordinateSystem.max.x,
y: nextPorwerOf10(MAX_DEFAULT_RATE_SCALE_VALUE) / 4
}
if (thisObject.rateScale !== undefined) {
minValue.y = thisObject.rateScale.minValue
maxValue.y = thisObject.rateScale.maxValue
}
timelineChartCoordinateSystem.initialize(
minValue,
maxValue,
thisObject.container.frame.width,
thisObject.container.frame.height
)
}
function initializeLayersManager () {
let owner = thisObject.payload.node.payload.parentNode.id // The real owner is the Time Machine
layersPanelHandle = canvas.panelsSpace.createNewPanel('Layers Panel', undefined, owner)
thisObject.layersManager = canvas.panelsSpace.getPanel(layersPanelHandle)
thisObject.layersManager.payload = thisObject.payload.node.layersManager.payload
thisObject.layersManager.initialize()
/* Initialize the Plotter Manager */
thisObject.plotterManager = newPlottersManager()
thisObject.plotterManager.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
thisObject.plotterManager.container.frame.position.x = 0
thisObject.plotterManager.container.frame.position.y = 0
thisObject.plotterManager.fitFunction = thisObject.fitFunction
thisObject.plotterManager.payload = thisObject.payload
thisObject.plotterManager.initialize(thisObject.layersManager)
thisObject.plotterManager.setTimeFrame(timeFrame)
thisObject.plotterManager.setDatetime(datetime)
thisObject.plotterManager.setCoordinateSystem(coordinateSystem)
}
function initializeRateScale () {
thisObject.rateScale = newRateScale()
thisObject.rateScale.fitFunction = thisObject.fitFunction
thisObject.rateScale.payload = thisObject.payload.node.rateScale.payload
rateScaleMouseOverEventSuscriptionId = thisObject.rateScale.container.eventHandler.listenToEvent('onMouseOverScale', rateScaleMouseOver)
thisObject.rateScale.initialize(timelineChartCoordinateSystem, thisObject.container.parentContainer, thisObject.container)
function rateScaleMouseOver (event) {
thisObject.container.eventHandler.raiseEvent('onChildrenMouseOver', event)
}
}
function initializeTimeFrameScale () {
thisObject.timeFrameScale = newTimeFrameScale()
thisObject.timeFrameScale.fitFunction = thisObject.fitFunction
thisObject.timeFrameScale.payload = thisObject.payload.node.timeFrameScale.payload
timeFrameScaleEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('Time Frame Value Changed', timeFrameScaleValueChanged)
timeFrameScaleMouseOverEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('onMouseOverScale', timeFrameScaleMouseOver)
thisObject.timeFrameScale.initialize(thisObject.container.parentContainer)
function timeFrameScaleValueChanged (event) {
let currentTimeFrame = timeFrame
timeFrame = event.timeFrame
if (timeFrame !== currentTimeFrame) {
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setTimeFrame(timeFrame)
}
}
}
function timeFrameScaleMouseOver (event) {
thisObject.container.eventHandler.raiseEvent('onChildrenMouseOver', event)
}
}
function onScaleChanged (event) {
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.onUpstreamScaleChanged(event)
}
timelineChartCoordinateSystem.min.x = timeMachineCoordinateSystem.min.x
timelineChartCoordinateSystem.max.x = timeMachineCoordinateSystem.max.x
timelineChartCoordinateSystem.maxHeight = timeMachineCoordinateSystem.maxHeight
timelineChartCoordinateSystem.maxWidth = timeMachineCoordinateSystem.maxWidth
timelineChartCoordinateSystem.autoMinXScale = timeMachineCoordinateSystem.autoMinXScale
timelineChartCoordinateSystem.autoMaxXScale = timeMachineCoordinateSystem.autoMaxXScale
timelineChartCoordinateSystem.recalculateScale()
}
function setTimeFrame (pTimeFrame) {
timeFrame = pTimeFrame
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setTimeFrame(timeFrame)
}
}
function setDatetime (pDatetime) {
datetime = pDatetime
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setDatetime(datetime)
}
}
function onMouseOver (event) {
/* This event gets to the timelinechart container because it inherits it from the time machine container, which is the one raising Mouse Over and Mouse not Over Events to its children. */
drawScales = true
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.onMouseOverSomeTimeMachineContainer(event)
}
if (thisObject.timeFrameScale !== undefined) {
thisObject.timeFrameScale.onMouseOverSomeTimeMachineContainer(event)
}
mouse.position.x = event.x
mouse.position.y = event.y
}
function onMouseNotOver (event) {
/* This event is inherited from the Time Machine */
drawScales = false
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.visible = false
}
if (thisObject.timeFrameScale !== undefined) {
thisObject.timeFrameScale.visible = false
}
}
function getContainer (point, purpose) {
let container
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) {
container = thisObject.rateScale.getContainer(point, purpose)
if (container !== undefined) {
if (container.isForThisPurpose(purpose)) {
return container
}
}
}
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) {
container = thisObject.timeFrameScale.getContainer(point, purpose)
if (container !== undefined) {
if (container.isForThisPurpose(purpose)) {
return container
}
}
}
return container
}
function physics () {
thisObjectPhysics()
childrenPhysics()
syncWithDesignerScales()
syncWithDesignerLayersManager()
}
function thisObjectPhysics () {
timelineChartCoordinateSystem.physics()
}
function syncWithDesignerLayersManager () {
if (thisObject.payload.node === undefined) {
finalizeLayersManager()
return
}
if (thisObject.payload.node.layersManager === undefined && thisObject.layersManager !== undefined) {
finalizeLayersManager()
}
if (thisObject.payload.node.layersManager !== undefined && thisObject.layersManager === undefined) {
initializeLayersManager()
}
}
function syncWithDesignerScales () {
if (thisObject.payload.node === undefined) {
finalizeRateScale()
finalizeTimeFrameScale()
return
}
if (thisObject.payload.node.rateScale === undefined && thisObject.rateScale !== undefined) {
finalizeRateScale()
coordinateSystem = timeMachineCoordinateSystem
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setCoordinateSystem(coordinateSystem)
}
}
if (thisObject.payload.node.rateScale !== undefined && thisObject.rateScale === undefined) {
initializeRateScale()
coordinateSystem = timelineChartCoordinateSystem
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setCoordinateSystem(coordinateSystem)
}
}
if (thisObject.payload.node.timeFrameScale === undefined && thisObject.timeFrameScale !== undefined) {
finalizeTimeFrameScale()
}
if (thisObject.payload.node.timeFrameScale !== undefined && thisObject.timeFrameScale === undefined) {
initializeTimeFrameScale()
}
}
function childrenPhysics () {
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.layersOn = thisObject.plotterManager.connectors.length
thisObject.rateScale.physics()
}
if (thisObject.timeFrameScale !== undefined) {
thisObject.timeFrameScale.layersOn = thisObject.plotterManager.connectors.length
thisObject.timeFrameScale.physics()
}
}
function drawBackground () {
if (thisObject.container.frame.isInViewPort()) {
drawChartsBackground()
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.draw()
}
}
}
function draw () {
if (thisObject.container.frame.isInViewPort()) {
if (drawScales === true) {
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.draw() }
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.draw() }
}
}
}
function drawForeground () {
if (thisObject.container.frame.isInViewPort()) {
if (drawScales === true) {
if (thisObject.timeFrameScale !== undefined && thisObject.timeFrameScale.isVisible === true) { thisObject.timeFrameScale.drawForeground() }
if (thisObject.rateScale !== undefined && thisObject.rateScale.isVisible === true) { thisObject.rateScale.drawForeground() }
}
}
}
function drawChartsBackground () {
drawContainerBackground(thisObject.container, UI_COLOR.WHITE, 0, thisObject.fitFunction)
}
}
+400
View File
@@ -0,0 +1,400 @@
function newViewport () {
const MODULE_NAME = 'Viewport'
const MIN_ZOOM_LEVEL = 0
const MAX_ZOOM_LEVEL = 500
let ANIMATION_INCREMENT = 0.25
let ANIMATION_STEPS = 5
let TOP_MARGIN = 40 + TOP_SPACE_HEIGHT
let BOTTOM_MARGIN = 42 + COCKPIT_SPACE_HEIGHT
let LEFT_MARGIN = 0
let RIGHT_MARGIN = 0
let MARGINS = {
TOP: TOP_MARGIN,
BOTTOM: BOTTOM_MARGIN,
LEFT: LEFT_MARGIN,
RIGHT: RIGHT_MARGIN
}
let thisObject = {
visibleArea: undefined,
width: undefined,
height: undefined,
eventHandler: undefined,
zoomTargetLevel: undefined,
zoomLevel: undefined,
mousePosition: undefined,
margins: MARGINS,
payload: undefined,
changeZoom: changeZoom,
onMouseWheel: onMouseWheel,
transformThisPoint: transformThisPoint,
unTransformThisPoint: unTransformThisPoint,
isThisPointVisible: isThisPointVisible,
isThisPointInViewport: isThisPointInViewport,
fitIntoVisibleArea: fitIntoVisibleArea,
fitIntoViewport: fitIntoViewport,
displace: displace,
physics: physics,
raiseEvents: raiseEvents,
resize: resize,
initialize: initialize,
finalize: finalize
}
let increment = 0.035
let position = {
x: 0,
y: 0
}
let targetPosition = {
x: 0,
y: 0
}
let positionIncrement = {
x: 0,
y: 0
}
thisObject.mousePosition = {
x: 0,
y: 0
}
thisObject.eventHandler = newEventHandler()
/* Initial default value */
thisObject.zoomLevel = MIN_ZOOM_LEVEL
thisObject.zoomTargetLevel = MIN_ZOOM_LEVEL
INITIAL_TIME_PERIOD = recalculatePeriod(thisObject.zoomLevel)
return thisObject
function finalize () {
thisObject.eventHandler.finalize()
thisObject.payload = undefined
thisObject = undefined
}
function initialize () {
if (thisObject.payload !== undefined) {
/* Read the position from the frame structure */
let frame = {
position: {
x: 0,
y: 0
}
}
loadFrame(thisObject.payload, frame)
if (!isNaN(frame.position.x)) {
position.x = frame.position.x
}
if (!isNaN(frame.position.y)) {
position.y = frame.position.y
}
}
resize()
readObjectState()
}
function resize () {
TOP_MARGIN = 40 + TOP_SPACE_HEIGHT
BOTTOM_MARGIN = 42 + browserCanvas.height - COCKPIT_SPACE_POSITION
LEFT_MARGIN = 0
RIGHT_MARGIN = 0
MARGINS = {
TOP: TOP_MARGIN,
BOTTOM: BOTTOM_MARGIN,
LEFT: LEFT_MARGIN,
RIGHT: RIGHT_MARGIN
}
thisObject.visibleArea = {
topLeft: { x: LEFT_MARGIN, y: TOP_MARGIN },
topRight: { x: browserCanvas.width - RIGHT_MARGIN, y: TOP_MARGIN },
bottomRight: { x: browserCanvas.width - RIGHT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN},
bottomLeft: { x: LEFT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN}
}
thisObject.width = thisObject.visibleArea.topRight.x - thisObject.visibleArea.topLeft.x
thisObject.height = thisObject.visibleArea.bottomRight.y - thisObject.visibleArea.topLeft.y
thisObject.center = {
x: LEFT_MARGIN + thisObject.width / 2,
y: TOP_MARGIN + thisObject.height / 2
}
}
function raiseEvents () {
let event = {
newPosition: position
}
thisObject.eventHandler.raiseEvent('Position Changed', event)
}
function physics () {
animationPhysics()
positioningPhysics()
readObjectState()
}
function positioningPhysics () {
if (thisObject.payload === undefined) { return }
/* Save the position at the frame lavel */
let frame = {}
frame.position = position
saveFrame(thisObject.payload, frame)
}
function animationPhysics () {
if (thisObject.zoomLevel < thisObject.zoomTargetLevel) {
if (thisObject.zoomTargetLevel - thisObject.zoomLevel < ANIMATION_INCREMENT) {
ANIMATION_INCREMENT = Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel)
}
thisObject.zoomLevel = thisObject.zoomLevel + ANIMATION_INCREMENT
changeZoom(thisObject.zoomLevel - ANIMATION_INCREMENT, thisObject.zoomLevel)
}
if (thisObject.zoomLevel > thisObject.zoomTargetLevel) {
if (thisObject.zoomLevel - thisObject.zoomTargetLevel < ANIMATION_INCREMENT) {
ANIMATION_INCREMENT = Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel)
}
thisObject.zoomLevel = thisObject.zoomLevel - ANIMATION_INCREMENT
changeZoom(thisObject.zoomLevel + ANIMATION_INCREMENT, thisObject.zoomLevel)
}
if (positionIncrement.y !== 0) {
if (Math.trunc(Math.abs(targetPosition.y - position.y) * 1000) >= Math.trunc(Math.abs(positionIncrement.y) * 1000)) {
position.y = position.y + positionIncrement.y
} else {
positionIncrement.y = 0
}
}
}
function onMouseWheel (event) {
if ((event.ctrlKey === true || event.metaKey === true)) { return }
let morePower = 1
let amount = event.delta
if (event.buttons === 4) { morePower = 2 } // Mouse wheel pressed.
/* We adjust the sensitivity for Mac Users */
let isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
if (isMac) { amount = amount / 5 }
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 = thisObject.zoomTargetLevel + amount * morePower
ANIMATION_INCREMENT = Math.abs(thisObject.zoomTargetLevel - thisObject.zoomLevel) / ANIMATION_STEPS
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) {
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) {
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
let testPoint = unTransformThisPoint(thisObject.mousePosition, newLevel)
saveObjectState()
targetPosition.x = position.x
targetPosition.y = position.y
positionIncrement = {
x: 0,
y: 0
}
thisObject.eventHandler.raiseEvent('Zoom Changed')
}
function transformThisPoint (point, level) {
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 (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 (point.y > COCKPIT_SPACE_POSITION) {
return false
} else {
return true
}
}
function saveObjectState () {
if (thisObject.payload === undefined) { return }
/* Save the zoom at the node config, so that the user can change it if he wishes to. */
try {
let code = JSON.parse(thisObject.payload.node.code)
code.zoom = (thisObject.zoomTargetLevel - MIN_ZOOM_LEVEL) / (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) * 100
code.zoom = code.zoom.toFixed(2)
thisObject.payload.node.code = JSON.stringify(code)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function readObjectState () {
if (thisObject.payload === undefined) { return }
/* Read the zoom level from the node config */
try {
let code = JSON.parse(thisObject.payload.node.code)
if (isNaN(code.zoom) || code.zoom === null || code.zoom === undefined) {
saveObjectState()
return
}
code.zoom = code.zoom / 100 * (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL) + MIN_ZOOM_LEVEL
if (code.zoom < MIN_ZOOM_LEVEL) { code.zoom = MIN_ZOOM_LEVEL }
if (code.zoom > MAX_ZOOM_LEVEL) { code.zoom = MAX_ZOOM_LEVEL }
if (code.zoom.toFixed(2) !== thisObject.zoomTargetLevel.toFixed(2)) {
newZoomLevel(code.zoom)
} else {
saveObjectState()
}
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
function newZoomLevel (level) {
thisObject.zoomLevel = level
thisObject.zoomTargetLevel = 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
}
}
}
+120
View File
@@ -0,0 +1,120 @@
function newQuotedAssetalances () {
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()
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)
}
}
+169
View File
@@ -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 = window.canvasApp.topMargin
AT_FULL_SCREEN_MODE = false
}
}
function goFullscreen () {
if (browserCanvas.requestFullscreen) {
browserCanvas.requestFullscreen()
} else if (browserCanvas.mozRequestFullScreen) {
browserCanvas.mozRequestFullScreen()
} else if (browserCanvas.webkitRequestFullscreen) {
browserCanvas.webkitRequestFullscreen()
} else if (browserCanvas.msRequestFullscreen) { browserCanvas.msRequestFullscreen() }
}
function goOutFullscreen () {
if (document.exitFullscreen) {
document.exitFullscreen()
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen()
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen()
} else if (document.msExitFullscreen) { document.msExitFullscreen() }
}
function physics () {
positionPhysics()
}
function positionPhysics () {
thisObject.container.frame.position.x = thisObject.container.parentContainer.frame.width - thisObject.container.frame.width
thisObject.container.frame.position.y = 6
}
function draw () {
if (thisObject.visible !== true) { return }
drawBackground()
drawText()
}
function drawBackground () {
let params = {
cornerRadius: 3,
lineWidth: 0.01,
container: thisObject.container,
borderColor: UI_COLOR.DARK,
castShadow: false,
opacity: 1
}
if (isMouseOver === true) {
params.backgroundColor = UI_COLOR.TURQUOISE
} else {
params.backgroundColor = UI_COLOR.DARK_TURQUOISE
}
roundedCornersBackground(params)
}
function drawText () {
let fontSize
let label
let xOffset
let yOffset
const OPACITY = 1
/* We put the params.VALUE in the middle */
fontSize = 15
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
label = 'FS'
let labelPoint = {
x: thisObject.container.frame.width / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO,
y: thisObject.container.frame.height - 9
}
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
}
+259
View File
@@ -0,0 +1,259 @@
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: thisObject.params.LEFT_OFFSET,
y: COCKPIT_SPACE_POSITION - COCKPIT_SPACE_HEIGHT / 2 - 9
}
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, RADIUS + RED_LINE_HIGHT, 0.85 * Math.PI, 2.15 * Math.PI)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')'
browserCanvasContext.fill()
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, RADIUS, 0.0 * Math.PI, 2.0 * Math.PI)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + OPACITY + ')'
browserCanvasContext.fill()
/* We draw the circle bar */
const DEFAULT_THICKNESS = 2
const VALUE_THICKNESS = 8
const VALUE_BG_THICKNESS = 1
const BAR_RADIUS = RADIUS * 0.85
let BAR_START_ANGLE = 0.85 * Math.PI
let BAR_END_ANGLE = 2.15 * Math.PI
let CURRENT_VALUE_ANGLE = thisObject.params.VALUE * (BAR_END_ANGLE - BAR_START_ANGLE) / thisObject.params.MAX_VALUE + BAR_START_ANGLE
let MIN_VALUE_ANGLE = thisObject.params.MIN_VALUE * (BAR_END_ANGLE - BAR_START_ANGLE) / thisObject.params.MAX_VALUE + BAR_START_ANGLE
let INIT_VALUE_ANGLE = thisObject.params.INIT_VALUE * (BAR_END_ANGLE - BAR_START_ANGLE) / thisObject.params.MAX_VALUE + BAR_START_ANGLE
let PROFIT_VALUE_ANGLE = CURRENT_VALUE_ANGLE
if (CURRENT_VALUE_ANGLE > INIT_VALUE_ANGLE) { CURRENT_VALUE_ANGLE = INIT_VALUE_ANGLE }
if (CURRENT_VALUE_ANGLE < MIN_VALUE_ANGLE) { CURRENT_VALUE_ANGLE = MIN_VALUE_ANGLE }
if (PROFIT_VALUE_ANGLE > BAR_END_ANGLE) { PROFIT_VALUE_ANGLE = BAR_END_ANGLE }
if (
thisObject.params.VALUE > 0 &&
thisObject.params.ASSET_NAME === thisObject.params.BASE_ASSET &&
thisObject.params.POSITION_TAKEN === false
) {
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, BAR_START_ANGLE, MIN_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, MIN_VALUE_ANGLE, CURRENT_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, CURRENT_VALUE_ANGLE, INIT_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
if (PROFIT_VALUE_ANGLE > INIT_VALUE_ANGLE) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, INIT_VALUE_ANGLE, PROFIT_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_BG_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
}
browserCanvasContext.setLineDash([2, 3])
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, BAR_START_ANGLE, MIN_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, MIN_VALUE_ANGLE, CURRENT_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, CURRENT_VALUE_ANGLE, INIT_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RED + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
if (PROFIT_VALUE_ANGLE > INIT_VALUE_ANGLE) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIUS, INIT_VALUE_ANGLE, PROFIT_VALUE_ANGLE)
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = VALUE_THICKNESS
browserCanvasContext.stroke()
browserCanvasContext.closePath()
}
}
/* Common Variables */
let fontSize
let label
let xOffset
let yOffset
/* We put the thisObject.params.VALUE in the middle */
fontSize = 22
if (thisObject.params.VALUE > 999) {
fontSize = 18
}
if (thisObject.params.VALUE > 9999) {
fontSize = 14
}
if (thisObject.params.VALUE > 99999) {
fontSize = 10
}
browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY
label = thisObject.params.VALUE
if (isNaN(label) === false) {
label = Number(label)
label = Math.trunc(label * Math.pow(10, thisObject.params.DECIMALS)) / Math.pow(10, thisObject.params.DECIMALS)
if (label === 0) { label = label.toFixed(2) } else { label = label.toLocaleString() }
}
// 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)
}
}
+262
View File
@@ -0,0 +1,262 @@
function newContainer () {
let thisObject = {
id: Math.trunc(Math.random() * 10000000),
type: 'Rectangle',
frame: undefined,
eventHandler: undefined,
parentContainer: undefined,
isDraggeable: true,
notDraggingOnX: false,
notDraggingOnY: false,
isClickeable: false,
isWheelable: false,
detectMouseOver: false,
name: undefined,
fitFunction: undefined,
isVisibleFunction: undefined,
displace: displace,
initialize: initialize,
finalize: finalize,
connectToParent: connectToParent,
isForThisPurpose: isForThisPurpose
}
let connectedToParentWidth = false
let connectedToParentHeight = false
let connectedToParentRadius = false
let onDimmensionsChangedParentEvent = false
let onMouseOverParentEvent = false
let onMouseNotOverParentEvent = false
let onFocusParentEvent = false
let onNotFocusParentEvent = false
let onDisplaceParentEvent = false
let onDragStartedParentEvent = false
let onDragFinishedParentEvent = false
let isConnectedToParent = false
let dimensionsChangedEventSubscriptionId
let onMouseOverEventSubscriptionId
let onMouseNotOverEventSubscriptionId
let onFocusEventSubscriptionId
let onNotFocusEventSubscriptionId
let onDisplaceEventSubscriptionId
let onDragStartedEventSubscriptionId
let onDragFinishedEventSubscriptionId
return thisObject
function finalize () {
if (isConnectedToParent === true) {
thisObject.parentContainer.eventHandler.stopListening(dimensionsChangedEventSubscriptionId)
thisObject.parentContainer.eventHandler.stopListening(onMouseOverEventSubscriptionId)
thisObject.parentContainer.eventHandler.stopListening(onMouseNotOverEventSubscriptionId)
thisObject.parentContainer.eventHandler.stopListening(onFocusEventSubscriptionId)
thisObject.parentContainer.eventHandler.stopListening(onNotFocusEventSubscriptionId)
thisObject.parentContainer.eventHandler.stopListening(onDisplaceEventSubscriptionId)
thisObject.parentContainer.eventHandler.stopListening(onDragStartedEventSubscriptionId)
thisObject.parentContainer.eventHandler.stopListening(onDragFinishedEventSubscriptionId)
thisObject.parentContainer = undefined
thisObject.eventHandler.finalize()
thisObject.frame.finalize()
}
}
function initialize (pName, pType) {
thisObject.name = pName
thisObject.type = pType
thisObject.frame = newFrame()
thisObject.frame.initialize(pType)
if (pName !== undefined) {
thisObject.frame.containerName = pName
}
thisObject.frame.container = thisObject
thisObject.eventHandler = newEventHandler()
thisObject.eventHandler.name = pName
}
function connectToParent (
parentContainer,
onWidth,
onHeight,
onRadius,
onDimmensionsChangedEvent,
onMouseOverEvent,
onMouseNotOverEvent,
onFocusEvent,
onNotFocusEvent,
onDisplaceEvent,
onDragStartedEvent,
onDragFinishedEvent
) {
connectedToParentWidth = onWidth
connectedToParentHeight = onHeight
connectedToParentRadius = onRadius
onDimmensionsChangedParentEvent = onDimmensionsChangedEvent
onMouseOverParentEvent = onMouseOverEvent
onMouseNotOverParentEvent = onMouseNotOverEvent
onFocusParentEvent = onFocusEvent
onNotFocusParentEvent = onNotFocusEvent
onDisplaceParentEvent = onDisplaceEvent
onDragStartedParentEvent = onDragStartedEvent
onDragFinishedParentEvent = onDragFinishedEvent
isConnectedToParent = true
thisObject.frame.parentFrame = parentContainer.frame
thisObject.parentContainer = parentContainer
if (onDimmensionsChangedParentEvent === true) {
dimensionsChangedEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('Dimmensions Changed', onParentDimmensionsChanged)
}
if (onMouseOverParentEvent === true) {
onMouseOverEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onMouseOver', onMouseOver)
}
if (onMouseNotOverParentEvent === true) {
onMouseNotOverEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
}
if (onFocusParentEvent === true) {
onFocusEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onFocus', onFocus)
}
if (onNotFocusParentEvent === true) {
onNotFocusEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onNotFocus', onNotFocus)
}
if (onDisplaceParentEvent === true) {
onDisplaceEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onDisplace', onDisplace)
}
if (onDragStartedParentEvent === true) {
onDragStartedEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onDragStarted', onDragStarted)
}
if (onDragFinishedParentEvent === true) {
onDragFinishedEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onDragFinished', onDragFinished)
}
if (connectedToParentWidth) {
thisObject.frame.width = thisObject.parentContainer.frame.width
}
if (connectedToParentHeight) {
thisObject.frame.height = thisObject.parentContainer.frame.height
}
if (connectedToParentRadius) {
thisObject.frame.radius = thisObject.parentContainer.frame.radius
}
}
function onParentDimmensionsChanged (event) {
let dimmensionsChanged = false
if (connectedToParentWidth) {
thisObject.frame.width = thisObject.parentContainer.frame.width
dimmensionsChanged = true
}
if (connectedToParentHeight) {
thisObject.frame.height = thisObject.parentContainer.frame.height
dimmensionsChanged = true
}
if (connectedToParentRadius) {
thisObject.frame.radius = thisObject.parentContainer.frame.radius
dimmensionsChanged = true
}
if (dimmensionsChanged) {
thisObject.eventHandler.raiseEvent('Dimmensions Changed', event)
}
}
function onMouseOver (event) {
thisObject.eventHandler.raiseEvent('onMouseOver', event)
}
function onMouseNotOver (event) {
thisObject.eventHandler.raiseEvent('onMouseNotOver', event)
}
function onFocus (event) {
thisObject.eventHandler.raiseEvent('onFocus', event)
}
function onNotFocus (event) {
thisObject.eventHandler.raiseEvent('onNotFocus', event)
}
function onDisplace (event) {
thisObject.eventHandler.raiseEvent('onDisplace', event)
}
function onDragStarted (event) {
thisObject.eventHandler.raiseEvent('onDragStarted', event)
}
function onDragFinished (event) {
thisObject.eventHandler.raiseEvent('onDragFinished', event)
}
function isForThisPurpose (purpose) {
if (purpose !== undefined) {
switch (purpose) {
case GET_CONTAINER_PURPOSE.MOUSE_OVER:
if (thisObject.detectMouseOver === true) {
return true
}
break
case GET_CONTAINER_PURPOSE.MOUSE_WHEEL:
if (thisObject.isWheelable === true) {
return true
}
break
case GET_CONTAINER_PURPOSE.MOUSE_CLICK:
if (thisObject.isClickeable === true) {
return true
}
break
case GET_CONTAINER_PURPOSE.DRAGGING:
if (thisObject.isDraggeable === true) {
return true
}
break
default: { return false }
}
}
return false
}
function displace (point) {
/* This function will move the container according to the vector received. If it has a visible function will use it
to see if the container can be moved there or not. It wont if the center will not be visible.
Returns true if move was possible, false if not. */
let checkPoint = {}
if (thisObject.isVisibleFunction === undefined) {
drag()
return true
} else {
checkPoint.x = thisObject.frame.position.x + point.x + thisObject.frame.width / 2
checkPoint.y = thisObject.frame.position.y + point.y + thisObject.frame.height / 2
let isVisible = thisObject.isVisibleFunction(checkPoint)
if (isVisible === true) {
drag()
return true
} else {
return false
}
}
function drag () {
if (thisObject.notDraggingOnX === false) {
thisObject.frame.position.x = thisObject.frame.position.x + point.x
}
if (thisObject.notDraggingOnY === false) {
thisObject.frame.position.y = thisObject.frame.position.y + point.y
}
thisObject.eventHandler.raiseEvent('onDisplace', event)
}
}
}
+131
View File
@@ -0,0 +1,131 @@
function newSidePanel () {
const MODULE_NAME = 'Side Panel'
let thisObject = {
areas: [],
sidePanelTab: undefined,
container: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize
}
let isInitialized = false
thisObject.container = newContainer()
thisObject.container.name = MODULE_NAME
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.isDraggeable = false
thisObject.container.status = 'hidden'
resize()
return thisObject
function initialize () {
thisObject.sidePanelTab = newSidePanelTab()
thisObject.sidePanelTab.container.connectToParent(thisObject.container, false, false)
thisObject.sidePanelTab.initialize()
canvas.eventHandler.listenToEvent('Browser Resized', resize)
isInitialized = true
}
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
}
function getContainer (point) {
let container
container = thisObject.sidePanelTab.getContainer(point)
if (container !== undefined) { return container }
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
} else {
return undefined
}
}
function draw () {
if (isInitialized === false) { return }
borders()
thisObject.sidePanelTab.draw()
for (let i = 0; i < thisObject.areas.length; i++) {
let area = thisObject.areas[i]
area.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()
}
}
}
}
+216
View File
@@ -0,0 +1,216 @@
function newSidePanelTab () {
const MODULE_NAME = 'Side Panel Tab'
let thisObject = {
pointerDirection: 'left',
container: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize
}
const TAB_WIDTH = 25
const TAB_HEIGHT = 60
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 () {
thisObject.container.frame.width = TAB_WIDTH
thisObject.container.frame.height = TAB_HEIGHT
thisObject.container.frame.position.x = 0 + thisObject.container.parentContainer.frame.width
thisObject.container.frame.position.y = 20
ORIGINAL_PARENT_POSITON = thisObject.container.parentContainer.frame.position.x
thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
isInitialized = true
}
function onMouseClick (event) {
if (thisObject.pointerDirection === 'left') {
animation = 'opening'
} else {
animation = 'closing'
}
}
function getContainer (point) {
let container
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
return thisObject.container
} else {
return undefined
}
}
function draw () {
if (isInitialized === false) { return }
animate()
borders()
arrow()
}
function animate () {
const STEP = 50
if (animation === 'opening') {
xOffset = xOffset + STEP
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON + xOffset
if (xOffset > thisObject.container.parentContainer.frame.width) {
animation = 'none'
xOffset = thisObject.container.parentContainer.frame.width
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON + xOffset
thisObject.container.parentContainer.status = 'visible'
thisObject.pointerDirection = 'right'
}
}
if (animation === 'closing') {
xOffset = xOffset - STEP
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON + xOffset
if (xOffset < 0) {
animation = 'none'
xOffset = 0
thisObject.container.parentContainer.frame.position.x = ORIGINAL_PARENT_POSITON
thisObject.container.parentContainer.status = 'hidden'
thisObject.pointerDirection = 'left'
}
}
}
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,220 @@
function newChainAttachDetach () {
thisObject = {
chainDetachNode: chainDetachNode,
chainAttachNode: chainAttachNode
}
return thisObject
function chainDetachNode (node, rootNodes) {
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 = APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition !== undefined) {
/* Detach from parent */
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = APP_SCHEMA_MAP.get(node.payload.parentNode.type)
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 = APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition !== undefined) {
node.payload.parentNode = attachToNode
node.payload.chainParent = attachToNode
/* Attach to new parent */
if (node.payload.parentNode !== undefined) {
let parentNodeDefinition = APP_SCHEMA_MAP.get(node.payload.parentNode.type)
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,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 = APP_SCHEMA_MAP.get(parentNode.type)
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 = APP_SCHEMA_MAP.get(childNode.type)
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,173 @@
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 = APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition !== undefined) {
let object = {
type: node.type,
name: node.name,
code: node.code
}
/* 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 = APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition !== undefined) {
let object = {
type: node.type,
name: node.name,
code: node.code
}
/* 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)
},
uiObject: {
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,128 @@
function newNodeDeleter () {
thisObject = {
deleteWorkspace: deleteWorkspace,
deleteUIObject: deleteUIObject
}
return thisObject
function destroyUiObject (node) {
canvas.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) {
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
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.parentNode !== undefined) {
let parentNodeDefinition = APP_SCHEMA_MAP.get(node.payload.parentNode.type)
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) {
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.onMenuItemClick = undefined
node.handle = undefined
node.payload = undefined
node.cleaned = true
}
}
@@ -0,0 +1,56 @@
function newOnFocus () {
thisObject = {
getNodeThatIsOnFocus: getNodeThatIsOnFocus
}
return thisObject
function getNodeThatIsOnFocus (node) {
if (node === undefined) { return }
if (node.payload === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
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
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++) {
child = getNodeThatIsOnFocus(nodePropertyArray[m])
if (child !== undefined) {
return child
}
}
}
}
break
}
}
}
}
}
}
}
@@ -0,0 +1,189 @@
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, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, lightingPath) {
if (node === undefined) { return }
if (node.payload === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition !== undefined) {
if (removePersonalData === true && nodeDefinition.isPersonalData === true) { return }
let object = {
type: node.type,
name: node.name,
code: node.code
}
/* 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 (node[property.name] !== undefined) {
if (property.name !== previousPropertyName) {
if (lightingPath === undefined) {
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseCode, includeIds, includeReferencesInSavedPayload, includePayload)
} else {
let newLightingPath = getNewLightingPath(lightingPath, node.type, property.childType)
if (newLightingPath !== undefined) {
object[property.name] = getProtocolNode(node[property.name], removePersonalData, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
previousPropertyName = property.name
}
}
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, parseCode, 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, parseCode, 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, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
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, parseCode, includeIds, includePayload, includeReferencesInSavedPayload, newLightingPath)
}
}
if (parseCode && object.code !== undefined && nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
try {
object.code = JSON.parse(node.code)
} 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.code = ' + node.code) }
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 + '->')
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)
},
uiObject: {
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 (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,24 @@
function newReferenceAttachDetach () {
thisObject = {
referenceDetachNode: referenceDetachNode,
referenceAttachNode: referenceAttachNode
}
return thisObject
function referenceDetachNode (node) {
completeDetachment(node)
}
function referenceAttachNode (node, attachToNode, rootNodes) {
completeAttachment(node, attachToNode)
}
function completeAttachment (node, attachToNode) {
node.payload.referenceParent = attachToNode
}
function completeDetachment (node) {
node.payload.referenceParent = undefined
}
}
@@ -0,0 +1,81 @@
function newSessionFunctions () {
thisObject = {
runSession: runSession,
stopSession: stopSession
}
return thisObject
function runSession (node, functionLibraryProtocolNode, callBackFunction) {
/* We can not run a sessionif its parent process is not running. Less if it does not have a parent. */
if (node.payload.parentNode === undefined) {
node.payload.uiObject.setErrorMessage('Session needs a Process Instance parent to be able to run.')
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
if (node.payload.parentNode.payload.uiObject.isRunning !== true) {
node.payload.uiObject.setErrorMessage('Session needs a Process Instance parent to be running to be able to run.')
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
if (node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Parent Process Instance need to reference a Process Definition.')
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
node.payload.uiObject.run(callBackFunction)
let key = node.name + '-' + node.type + '-' + node.id
let lightingPath = '' +
'Trading System->' +
'Parameters->' +
'Base Asset->Time Range->Time Frame->Slippage->Fee Structure->' +
'Exchange Account Asset->Asset->' +
'Strategy->' +
'Trigger Stage->Trigger On Event->Trigger Off Event->Take Position Event->' +
'Announcement->Telegram Bot->' +
'Open Stage->Initial Definition->Open Execution->' +
'Position Size->Position Rate->Formula->' +
'Initial Stop->Initial Take Profit->' +
'Manage Stage->' +
'Stop->Take Profit->' +
'Phase->Formula->Next Phase Event->' +
'Situation->Condition->Javascript Code->' +
'Announcement->Telegram Bot->' +
'Close Stage->Close Execution->'
let tradingSystem = functionLibraryProtocolNode.getProtocolNode(node.payload.referenceParent, false, true, true, false, false, lightingPath)
lightingPath = '' +
'Backtesting Session->Paper Trading Session->Fordward Testing Session->Live Trading Session->' +
'Parameters->' +
'Base Asset->Time Range->Time Frame->Slippage->Fee Structure->' +
'Exchange Account Asset->Asset->'
let session = functionLibraryProtocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath)
/* Raise event to run the session */
let event = {
session: JSON.stringify(session),
tradingSystem: JSON.stringify(tradingSystem)
}
systemEventHandler.raiseEvent(key, 'Run 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 key = node.name + '-' + node.type + '-' + node.id
systemEventHandler.raiseEvent(key, 'Stop Session')
node.payload.uiObject.stop(callBackFunction)
}
}
@@ -0,0 +1,55 @@
function newShortcutKeys () {
thisObject = {
getNodeByShortcutKey: getNodeByShortcutKey
}
return thisObject
function getNodeByShortcutKey (node, searchingKey) {
if (node === undefined) { return }
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
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
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++) {
child = getNodeByShortcutKey(nodePropertyArray[m], searchingKey)
if (child !== undefined) {
return child
}
}
}
}
break
}
}
}
}
}
}
}
@@ -0,0 +1,110 @@
function newTaskFunctions () {
thisObject = {
runTask: runTask,
stopTask: stopTask,
runAllTasks: runAllTasks,
stopAllTasks: stopAllTasks
}
return thisObject
function runTask (node, functionLibraryProtocolNode, callBackFunction) {
/* Check if it is possible to Run or not */
if (node.bot === undefined) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
if (node.bot.processes.length === 0) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
for (let i = 0; i < node.bot.processes.length; i++) {
let process = node.bot.processes[i]
process.payload.uiObject.run()
}
let lightingPath = '->Task->' +
'Sensor Bot Instance->' +
'Indicator Bot Instance->' +
'Trading Bot Instance->' +
'Sensor Process Instance->Indicator Process Instance->Trading Process Instance->' +
'Market Reference->' +
'Key Instance->Exchange Account Key->' +
'Market->Exchange Markets->Crypto Exchange->' +
'Market Base Asset->Market Quoted Asset->Asset->' +
'Backtesting Session->Live Trading Session->Paper Trading Session->Fordward Testing Session->' +
'Process Definition->' +
'Process Output->Output Dataset->Dataset Definition->Product Definition->' +
'Process Dependencies->' +
'Status Dependency->Status Report->Process Definition->' +
'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->' +
'Indicator Bot->' +
'Trading Bot->' +
'Data Mine->'
let definition = functionLibraryProtocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath)
let event = {
taskId: node.id,
taskName: node.name,
definition: JSON.stringify(definition) // <- We need to do this workaround in order no to send unescaped charactars to the taskManager.
}
if (node.payload.parentNode === undefined) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
systemEventHandler.raiseEvent('Task Server', 'Debug Task Started', event)
return
}
node.payload.uiObject.run(callBackFunction)
systemEventHandler.raiseEvent('Task Manager', 'Run Task', event)
}
function stopTask (node, functionLibraryProtocolNode, callBackFunction) {
let event = {
taskId: node.id,
taskName: node.name
}
systemEventHandler.raiseEvent('Task Manager', 'Stop Task', event)
node.payload.uiObject.stop(callBackFunction)
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 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')
}
}
}
@@ -0,0 +1,413 @@
function newUiObjectsFromNodes () {
thisObject = {
recreateWorkspace: recreateWorkspace,
tryToConnectChildrenWithReferenceParents: tryToConnectChildrenWithReferenceParents,
createUiObjectFromNode: createUiObjectFromNode,
addUIObject: addUIObject,
addMissingChildren: addMissingChildren
}
let mapOfReferenceChildren = new Map()
let mapOfNodes
let tasksToRun
let sessionsToRun
return thisObject
function recreateWorkspace (node, replacingCurrentWorkspace) {
mapOfNodes = new Map()
tasksToRun = []
sessionsToRun = []
/* 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 (replacingCurrentWorkspace === true) {
// We need to wait all tasks that were potentially running to stop
setTimeout(runTasks, 70000)
// We give a few seconds for the tasks to start
setTimeout(runSessions, 80000)
} else {
runTasks()
// We give a few seconds for the tasks to start
setTimeout(runSessions, 10000)
}
}
function runTasks () {
for (let i = 0; i < tasksToRun.length; i++) {
let node = tasksToRun[i]
node.payload.uiObject.menu.internalClick('Run Task')
}
tasksToRun = undefined
}
function runSessions () {
for (let i = 0; i < sessionsToRun.length; i++) {
let node = sessionsToRun[i]
node.payload.uiObject.menu.internalClick('Run Session')
}
sessionsToRun = undefined
}
function tryToConnectChildrenWithReferenceParents () {
/* We reconstruct here the reference relationships. */
for (const [key, node] of mapOfNodes) {
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)
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)
}
}
}
}
function createUiObjectFromNode (node, parentNode, chainParent, positionOffset) {
/* Get node definition */
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
if (nodeDefinition !== undefined) {
/* Resolve Initial Values */
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
if (node.code === undefined) {
node.code = nodeDefinition.initialValues.code
}
}
}
/* 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 = APP_SCHEMA_MAP.get(parentNode.type)
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
}
}
}
}
}
}
function addUIObject (parentNode, type) {
let object = {
name: 'New ' + type,
type: type
}
let parentNodeDefinition = APP_SCHEMA_MAP.get(parentNode.type)
if (parentNodeDefinition !== undefined) {
/* Resolve Initial Values */
let nodeDefinition = APP_SCHEMA_MAP.get(object.type)
if (nodeDefinition.isHierarchyHead === true) {
parentNode.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]
}
}
}
}
}
}
}
if (nodeDefinition !== undefined) {
if (nodeDefinition.initialValues !== undefined) {
if (nodeDefinition.initialValues.code !== undefined) {
object.code = nodeDefinition.initialValues.code
}
}
}
/* 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 = APP_SCHEMA_MAP.get(node.type)
/* 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 {
let testNode = mapOfNodes.get(node.id)
if (testNode !== undefined && testNode.cleaned !== true) {
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.onMenuItemClick = canvas.designSpace.workspace.onMenuItemClick
node.payload = payload
node.type = uiObjectType
/* Now we mount the floating object where the UIOBject will be laying on top of */
canvas.floatingSpace.uiObjectConstructor.createUiObject(userAddingNew, payload)
mapOfNodes.set(node.id, node)
/* Check if there are tasks to run */
if (userAddingNew === false && uiObjectType === 'Task' && node.savedPayload !== undefined) {
if (node.savedPayload.uiObject.isRunning === true) {
tasksToRun.push(node)
}
}
/* Check if there are sessions to run */
if (userAddingNew === false && node.savedPayload !== undefined) {
if (uiObjectType === 'Live Trading Session' || uiObjectType === 'Fordward Testing Session' || uiObjectType === 'Backtesting Session' || uiObjectType === 'Paper Trading Session') {
if (node.savedPayload.uiObject.isRunning === true) {
sessionsToRun.push(node)
}
}
}
}
}
@@ -0,0 +1,371 @@
function newWorkspace () {
const MODULE_NAME = 'Workspace'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
workspaceNode: undefined,
tradingSystem: undefined,
container: undefined,
enabled: false,
nodeChildren: undefined,
getNodeThatIsOnFocus: getNodeThatIsOnFocus,
getNodeByShortcutKey: getNodeByShortcutKey,
stopAllRunningTasks: stopAllRunningTasks,
onMenuItemClick: onMenuItemClick,
physics: physics,
draw: draw,
spawn: spawn,
chainDetachNode: chainDetachNode,
chainAttachNode: chainAttachNode,
referenceDetachNode: referenceDetachNode,
referenceAttachNode: referenceAttachNode,
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isClickeable = false
thisObject.container.isDraggeable = false
thisObject.container.isWheelable = false
thisObject.container.detectMouseOver = false
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
spawnPosition = {
x: canvas.floatingSpace.container.frame.width / 2,
y: canvas.floatingSpace.container.frame.height / 2
}
thisObject.workspaceNode = {}
thisObject.workspaceNode.rootNodes = []
let functionLibraryReferenceAttachDetach = newReferenceAttachDetach()
let functionLibraryChainAttachDetach = newChainAttachDetach()
let functionLibraryNodeDeleter = newNodeDeleter()
let functionLibraryUiObjectsFromNodes = newUiObjectsFromNodes()
let functionLibraryProtocolNode = newProtocolNode()
let functionLibraryNodeCloning = newNodeCloning()
let functionLibraryTaskFunctions = newTaskFunctions()
let functionLibrarySessionFunctions = newSessionFunctions()
let functionLibraryShortcutKeys = newShortcutKeys()
let functionLibraryOnFocus = newOnFocus()
thisObject.nodeChildren = newNodeChildren()
let workingAtTask = 0
let circularProgressBar = newBusyProgressBar()
circularProgressBar.fitFunction = canvas.floatingSpace.fitIntoVisibleArea
let droppedNode
return thisObject
function finalize () {
thisObject.definition = undefined
thisObject.container.finalize()
thisObject.container = undefined
thisObject.workspaceNode = undefined
circularProgressBar.finalize()
circularProgressBar = undefined
}
function initialize () {
try {
let savedWorkspace = window.localStorage.getItem(CANVAS_APP_NAME + '.' + 'Workspace')
if (savedWorkspace === null) {
thisObject.workspaceNode.type = 'Workspace'
thisObject.workspaceNode.name = 'My Workspace'
} else {
thisObject.workspaceNode = JSON.parse(savedWorkspace)
}
functionLibraryUiObjectsFromNodes.recreateWorkspace(thisObject.workspaceNode)
thisObject.enabled = true
setInterval(saveWorkspace, 5000)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) }
}
}
function chainDetachNode (node) {
functionLibraryChainAttachDetach.chainDetachNode(node, thisObject.workspaceNode.rootNodes)
}
function chainAttachNode (node, attachToNode) {
functionLibraryChainAttachDetach.chainAttachNode(node, attachToNode, thisObject.workspaceNode.rootNodes)
}
function referenceDetachNode (node) {
functionLibraryReferenceAttachDetach.referenceDetachNode(node)
}
function referenceAttachNode (node, attachToNode) {
functionLibraryReferenceAttachDetach.referenceAttachNode(node, attachToNode, thisObject.workspaceNode.rootNodes)
}
function saveWorkspace () {
let textToSave = stringifyWorkspace()
window.localStorage.setItem(CANVAS_APP_NAME + '.' + 'Workspace', textToSave)
}
function physics () {
if (thisObject.enabled !== true) { return }
if (workingAtTask > 0) {
circularProgressBar.physics()
switch (workingAtTask) {
case 1:
stopAllRunningTasks()
workingAtTask++
break
case 2:
functionLibraryNodeDeleter.deleteWorkspace(thisObject.workspaceNode, thisObject.workspaceNode.rootNodes)
workingAtTask++
break
case 3:
thisObject.workspaceNode = droppedNode
droppedNode = undefined
workingAtTask++
break
case 4:
functionLibraryUiObjectsFromNodes.recreateWorkspace(thisObject.workspaceNode, true)
workingAtTask++
break
case 5:
canvas.chartingSpace.reset()
workingAtTask++
break
case 6:
workingAtTask = 0
circularProgressBar.visible = false
break
}
}
}
function draw () {
if (circularProgressBar !== undefined) {
circularProgressBar.draw()
}
}
function stringifyWorkspace (removePersonalData) {
let stringifyReadyNodes = []
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let node = functionLibraryProtocolNode.getProtocolNode(rootNode, removePersonalData, false, true, true, true)
if (node) {
stringifyReadyNodes.push(node)
}
}
let workspace = {
type: 'Workspace',
name: thisObject.workspaceNode.name,
rootNodes: stringifyReadyNodes
}
return JSON.stringify(workspace)
}
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) {
for (let i = 0; i < networkNode.dataMining.taskManagers.length; i++) {
let taskManager = networkNode.dataMining.taskManagers[i]
taskManager.payload.uiObject.menu.internalClick('Stop All Tasks')
}
}
if (networkNode.testingEnvironment !== undefined) {
for (let i = 0; i < networkNode.testingEnvironment.taskManagers.length; i++) {
let taskManager = networkNode.testingEnvironment.taskManagers[i]
taskManager.payload.uiObject.menu.internalClick('Stop All Tasks')
}
}
if (networkNode.productionEnvironment !== undefined) {
for (let i = 0; i < networkNode.productionEnvironment.taskManagers.length; i++) {
let taskManager = networkNode.productionEnvironment.taskManagers[i]
taskManager.payload.uiObject.menu.internalClick('Stop All Tasks')
}
}
}
}
}
}
}
function getNodeByShortcutKey (searchingKey) {
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let node = functionLibraryShortcutKeys.getNodeByShortcutKey(rootNode, searchingKey)
if (node !== undefined) { return node }
}
}
function getNodeThatIsOnFocus () {
for (let i = 0; i < thisObject.workspaceNode.rootNodes.length; i++) {
let rootNode = thisObject.workspaceNode.rootNodes[i]
let node = functionLibraryOnFocus.getNodeThatIsOnFocus(rootNode)
if (node !== undefined) { return node }
}
}
function spawn (nodeText, mousePointer) {
try {
let point = {
x: mousePointer.x,
y: mousePointer.y
}
point = canvas.floatingSpace.container.frame.unframeThisPoint(point)
spawnPosition.x = point.x
spawnPosition.y = point.y
droppedNode = JSON.parse(nodeText)
if (droppedNode.type === 'Workspace') {
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 - droppedNode.savedPayload.position.x,
y: spawnPosition.y - droppedNode.savedPayload.position.y
}
thisObject.workspaceNode.rootNodes.push(droppedNode)
functionLibraryUiObjectsFromNodes.createUiObjectFromNode(droppedNode, undefined, undefined, positionOffset)
functionLibraryUiObjectsFromNodes.tryToConnectChildrenWithReferenceParents()
droppedNode = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] spawn -> err = ' + err.stack) }
}
}
async function onMenuItemClick (payload, action, relatedUiObject, callBackFunction) {
switch (action) {
case 'Add UI Object':
{
functionLibraryUiObjectsFromNodes.addUIObject(payload.node, relatedUiObject)
}
break
case 'Add Missing Children':
{
functionLibraryUiObjectsFromNodes.addMissingChildren(payload.node)
}
break
case 'Delete UI Object':
{
functionLibraryNodeDeleter.deleteUIObject(payload.node, thisObject.workspaceNode.rootNodes)
}
break
case 'Share Workspace':
{
let text = stringifyWorkspace(true)
let fileName = 'Share - ' + payload.node.type + ' - ' + payload.node.name + '.json'
downloadText(fileName, text)
}
break
case 'Backup Workspace':
{
let text = stringifyWorkspace(false)
let fileName = 'Backup - ' + payload.node.type + ' - ' + payload.node.name + '.json'
downloadText(fileName, text)
}
break
case 'Edit Code':
break
case 'Share':
{
let text = JSON.stringify(functionLibraryProtocolNode.getProtocolNode(payload.node, true, false, true, true, true))
let nodeName = payload.node.name
if (nodeName === undefined) {
nodeName = ''
} else {
nodeName = '.' + nodeName
}
let fileName = 'Share - ' + payload.node.type + ' - ' + nodeName + '.json'
downloadText(fileName, text)
}
break
case 'Backup':
{
let text = JSON.stringify(functionLibraryProtocolNode.getProtocolNode(payload.node, false, false, true, true, true))
let nodeName = payload.node.name
if (nodeName === undefined) {
nodeName = ''
} else {
nodeName = ' ' + nodeName
}
let fileName = 'Backup - ' + payload.node.type + ' - ' + nodeName + '.json'
downloadText(fileName, text)
}
break
case 'Clone':
{
let text = JSON.stringify(functionLibraryNodeCloning.getNodeClone(payload.node))
let nodeName = payload.node.name
if (nodeName === undefined) {
nodeName = ''
} else {
nodeName = ' ' + nodeName
}
let fileName = 'Clone - ' + payload.node.type + ' - ' + nodeName + '.json'
downloadText(fileName, text)
}
break
case 'Run Task':
{
functionLibraryTaskFunctions.runTask(payload.node, functionLibraryProtocolNode, callBackFunction)
}
break
case 'Stop Task':
{
functionLibraryTaskFunctions.stopTask(payload.node, functionLibraryProtocolNode, callBackFunction)
}
break
case 'Run All Tasks':
{
functionLibraryTaskFunctions.runAllTasks(payload.node, functionLibraryProtocolNode)
}
break
case 'Stop All Tasks':
{
functionLibraryTaskFunctions.stopAllTasks(payload.node, functionLibraryProtocolNode)
}
break
case 'Run Session':
{
functionLibrarySessionFunctions.runSession(payload.node, functionLibraryProtocolNode, callBackFunction)
}
break
case 'Stop Session':
{
functionLibrarySessionFunctions.stopSession(payload.node, functionLibraryProtocolNode, callBackFunction)
}
break
}
}
}
+46
View File
@@ -0,0 +1,46 @@

function newEventHandler () {
let thisObject = {
name: undefined, // This is for debugging purposes only.
listenToEvent: listenToEvent,
stopListening: stopListening,
raiseEvent: raiseEvent,
finalize: finalize
}
let eventHandlers = [] // Here we store all the functions we will call when an event is raiseed.
return thisObject
function finalize () {
eventHandlers = []
}
function listenToEvent (eventType, handler, extraData) {
let eventSubscriptionId = Math.trunc(Math.random() * 1000000)
eventHandlers.push([eventType, handler, extraData, eventSubscriptionId])
return eventSubscriptionId
}
function stopListening (pEventSubscriptionId) {
for (let i = 0; i < eventHandlers.length; i++) {
if (pEventSubscriptionId === eventHandlers[i][3]) {
eventHandlers.splice(i, 1)
return
}
}
}
function raiseEvent (eventType, event) {
for (var i = 0; i < eventHandlers.length; i++) {
/* We will execute all the functions listening to this event type. */
if (eventHandlers[i][0] === eventType) {
let handler = eventHandlers[i][1]
let extraData = eventHandlers[i][2]
handler(event, extraData)
}
}
}
}
@@ -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()
}
}
+213
View File
@@ -0,0 +1,213 @@
function newCircularMenu () {
const MODULE_NAME = 'Circular Menu'
let thisObject = {
container: undefined,
isDeployed: undefined,
internalClick: internalClick,
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 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.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 3 possible rings of icons, we will go through each of them here. */
let amplitudeArray = [80, 50, 40]
let initialAngleArray = [220, 205, 200]
for (let j = 1; j < 4; 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)
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 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 = 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 * 4
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()
}
}
}
}
+437
View File
@@ -0,0 +1,437 @@
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,
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,
internalClick: internalClick,
physics: physics,
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 = 30
let isMouseOver = false
let selfMouseOverEventSubscriptionId
let selfMouseClickEventSubscriptionId
let selfMouseNotOverEventSubscriptionId
let labelToPrint = ''
let defaultBackgroudColor = UI_COLOR.RED
let backgroundColorToUse = UI_COLOR.RED
let temporaryStatus = 0
let temporaryStatusCounter = 0
const EXTRA_MOUSE_OVER_ICON_SIZE = 6
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)
if (thisObject.type === 'Icon & Text') {
thisObject.container.frame.width = 150
} else {
thisObject.container.frame.width = 50
}
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 physics () {
if (thisObject.dontShowAtFullscreen === true && AT_FULL_SCREEN_MODE === true) { return }
const 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
break
}
case 2: {
radiusGrowthFactor = 3.5
break
}
case 3: {
radiusGrowthFactor = 2
break
}
}
} else {
radiusGrowthFactor = 4
}
thisObject.container.frame.position.x = thisObject.container.frame.radius * radiusGrowthFactor / 7 * Math.cos(toRadians(thisObject.angle)) - thisObject.currentRadius * 1.5
thisObject.container.frame.position.y = thisObject.container.frame.radius * radiusGrowthFactor / 7 * Math.sin(toRadians(thisObject.angle)) - thisObject.container.frame.height / 2
/* 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
}
/* 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
}
}
iconPhysics()
}
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 = canvas.designSpace.iconCollection.get(thisObject.secondaryIcon)
thisObject.iconOff = canvas.designSpace.iconCollection.get(thisObject.secondaryIcon)
} else {
if (thisObject.relatedUiObject !== undefined) {
thisObject.iconOn = canvas.designSpace.iconByUiObjectType.get(thisObject.relatedUiObject)
thisObject.iconOff = canvas.designSpace.iconByUiObjectType.get(thisObject.relatedUiObject)
} else {
if (thisObject.iconPathOn !== undefined && thisObject.iconPathOff !== undefined) {
thisObject.iconOn = canvas.designSpace.iconCollection.get(thisObject.iconPathOn)
thisObject.iconOff = canvas.designSpace.iconCollection.get(thisObject.iconPathOff)
} else {
thisObject.iconOn = canvas.designSpace.iconCollection.get(thisObject.icons[thisObject.actionStatus()])
thisObject.iconOff = canvas.designSpace.iconCollection.get(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
}
}
function onMouseNotOver (point) {
isMouseOver = false
}
function internalClick () {
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(thisObject.payload, thisObject.action, 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, 250, STATUS_WAITING_CONFIRMATION)
return
}
/* A Click during confirmation executes the pre-defined action. */
if (temporaryStatus === STATUS_WAITING_CONFIRMATION || temporaryStatus === STATUS_PRIMARY_WORK_DONE) {
executeAction()
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(thisObject.payload, thisObject.action, thisObject.relatedUiObject, 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(thisObject.payload, thisObject.secondaryAction, thisObject.relatedUiObject, 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, 100, 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, 100, STATUS_PRIMARY_WORK_DONE)
}
} else {
if (thisObject.workFailedLabel != undefined) {
setStatus(thisObject.workFailedLabel, UI_COLOR.TITANIUM_YELLOW, 100, 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, 100, 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, 100, STATUS_SECONDARY_WORK_DONE)
}
} else {
if (thisObject.secondaryWorkFailedLabel != undefined) {
setStatus(thisObject.secondaryWorkFailedLabel, UI_COLOR.TITANIUM_YELLOW, 100, 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: 3,
lineWidth: 0.1,
container: thisObject.container,
borderColor: UI_COLOR.DARK,
backgroundColor: backgroundColor,
castShadow: false,
xOffset: 40
}
if (isMouseOver === true) {
params.opacity = 1
} else {
params.opacity = 0.8
}
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 = thisObject.currentRadius + EXTRA_MOUSE_OVER_ICON_SIZE
} else {
iconSize = thisObject.currentRadius
}
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') {
let labelPoint
let fontSize = 10
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
if (thisObject.currentRadius >= thisObject.targetRadius) {
labelPoint = {
x: menuPosition.x + thisObject.currentRadius + 20,
y: menuPosition.y + fontSize * FONT_ASPECT_RATIO
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
browserCanvasContext.fillText(labelToPrint, labelPoint.x, labelPoint.y)
}
}
}
}
}
@@ -0,0 +1,119 @@
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
return thisObject
function finalize () {
let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id
systemEventHandler.stopListening(key, eventSubscriptionIdHeartbeat)
thisObject.container = undefined
thisObject.payload = undefined
thisObject.fitFunction = undefined
}
function initialize (payload) {
thisObject.payload = payload
for (let i = 0; i < 60; i++) {
opacityCounters.push(0)
}
let key = thisObject.payload.node.name + '-' + thisObject.payload.node.type + '-' + thisObject.payload.node.id
systemEventHandler.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
thisObject.payload.uiObject.setValue(message.event.processingDate)
}
function getContainer (point) {
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) {
const VISIBLE_RADIUS = thisObject.container.frame.radius * 2
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] / 1000
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 / 2
browserCanvasContext.setLineDash([3, 4])
browserCanvasContext.stroke()
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + OPACITY + ')'
browserCanvasContext.lineWidth = 0 + opacityCounters[i] / 100 / 2
browserCanvasContext.setLineDash([3, 4])
browserCanvasContext.stroke()
}
}
}
+215
View File
@@ -0,0 +1,215 @@
function newCodeEditor () {
const MODULE_NAME = 'Code Editor'
let thisObject = {
isVisibleFunction: undefined,
iconOK: undefined,
iconNOT_OK: 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
return thisObject
function finalize () {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.iconOK = undefined
thisObject.iconNOT_OK = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
}
function initialize () {
/* Load Images */
thisObject.iconOK = new Image()
thisObject.iconOK.onload = onImageLoad
function onImageLoad () {
thisObject.iconNOT_OK = new Image()
thisObject.iconNOT_OK.onload = onImageLoad
function onImageLoad () {
thisObject.canDrawIcon = true
}
thisObject.iconNOT_OK.src = window.canvasApp.urlPrefix + thisObject.imagePathNOT_OK
}
// thisObject.iconOK.src = window.canvasApp.urlPrefix + thisObject.imagePathOK
// thisObject.icon = thisObject.iconOK // The default value is ON.
}
function deactivate () {
if (thisObject.visible === true) {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.code = textArea.value
}
}
function activate (payload) {
thisObject.visible = true
thisObject.payload = payload
thisObject.rawRadius = 8
thisObject.targetRadius = thisObject.container.frame.radius
thisObject.currentRadius = 0
thisObject.payload.uiObject.setErrorMessage('', 0)
let textArea = document.getElementById('textArea')
textArea.value = payload.node.code
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + UI_FONT.PRIMARY + ';' +
'font-size: 12px;' +
'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()
}
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.8 * 2
thisObject.container.frame.height = thisObject.container.frame.radius * 1 * 2
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 * 2
if (radius > 0.5) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius * 1.3 + 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 * 1.3, 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 (label !== undefined && 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)
}
}
}
}
+215
View File
@@ -0,0 +1,215 @@
function newConditionEditor () {
const MODULE_NAME = 'Condition Editor'
let thisObject = {
isVisibleFunction: undefined,
iconOK: undefined,
iconNOT_OK: 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
return thisObject
function finalize () {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.iconOK = undefined
thisObject.iconNOT_OK = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
}
function initialize () {
/* Load Images */
thisObject.iconOK = new Image()
thisObject.iconOK.onload = onImageLoad
function onImageLoad () {
thisObject.iconNOT_OK = new Image()
thisObject.iconNOT_OK.onload = onImageLoad
function onImageLoad () {
thisObject.canDrawIcon = true
}
thisObject.iconNOT_OK.src = window.canvasApp.urlPrefix + thisObject.imagePathNOT_OK
}
// thisObject.iconOK.src = window.canvasApp.urlPrefix + thisObject.imagePathOK
// thisObject.icon = thisObject.iconOK // The default value is ON.
}
function deactivate () {
if (thisObject.visible === true) {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.code = textArea.value
}
}
function activate (payload) {
thisObject.visible = true
thisObject.payload = payload
thisObject.rawRadius = 8
thisObject.targetRadius = thisObject.container.frame.radius
thisObject.currentRadius = 0
thisObject.payload.uiObject.setErrorMessage('', 0)
let textArea = document.getElementById('textArea')
textArea.value = payload.node.code
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + UI_FONT.PRIMARY + ';' +
'font-size: 12px;' +
'background-color: rgb(' + UI_COLOR.GREEN + ');' +
'color:rgb(255, 255, 255);' +
'width: ' + thisObject.container.frame.width + 'px;' +
'height: ' + thisObject.container.frame.height + 'px'
textArea.style.display = 'block'
textArea.focus()
}
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.8 * 2
thisObject.container.frame.height = thisObject.container.frame.radius * 1 * 2
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 * 2
if (radius > 0.5) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius * 1.3 + 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 * 1.3, 0, Math.PI * 2, true)
browserCanvasContext.closePath()
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', ' + 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 (label !== undefined && 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)
}
}
}
}
+222
View File
@@ -0,0 +1,222 @@
function newConfigEditor () {
const MODULE_NAME = 'Config Editor'
let thisObject = {
isVisibleFunction: undefined,
iconOK: undefined,
iconNOT_OK: 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 = 0.6
return thisObject
function finalize () {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.iconOK = undefined
thisObject.iconNOT_OK = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
}
function initialize () {
/* Load Images */
thisObject.iconOK = new Image()
thisObject.iconOK.onload = onImageLoad
function onImageLoad () {
thisObject.iconNOT_OK = new Image()
thisObject.iconNOT_OK.onload = onImageLoad
function onImageLoad () {
thisObject.canDrawIcon = true
}
thisObject.iconNOT_OK.src = window.canvasApp.urlPrefix + thisObject.imagePathNOT_OK
}
// thisObject.iconOK.src = window.canvasApp.urlPrefix + thisObject.imagePathOK
// thisObject.icon = thisObject.iconOK // The default value is ON.
}
function deactivate () {
if (thisObject.visible === true) {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.code = textArea.value
try {
let code = JSON.parse(thisObject.payload.node.code)
} catch (err) {
thisObject.payload.uiObject.setErrorMessage(err.message, 10)
}
}
}
function activate (payload) {
thisObject.visible = true
thisObject.payload = payload
thisObject.rawRadius = 8
thisObject.targetRadius = thisObject.container.frame.radius
thisObject.currentRadius = 0
thisObject.payload.uiObject.setErrorMessage('', 0)
let textArea = document.getElementById('textArea')
textArea.value = payload.node.code
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + UI_FONT.PRIMARY + ';' +
'font-size: 12px;' +
'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()
}
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.8 * 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 * 1.3 + 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 * 1.3, 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 (label !== undefined && 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)
}
}
}
}
+733
View File
@@ -0,0 +1,733 @@
/*
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,
changeTargetRepulsion: changeTargetRepulsion,
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
return thisObject
function finalize () {
invisibleFloatingObjects = []
visibleFloatingObjects = []
}
function initialize () {
/* We dont need to initialize anything right now. */
}
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 }
}
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[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 makeVisible () {
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
if (floatingObject.isFrozen === false && floatingObject.isParentCollapsed === false) {
visibleFloatingObjects.push(floatingObject)
invisibleFloatingObjects.splice(i, 1) // Delete item from array.
makeVisible()
return // Only one at the time.
}
}
}
function makeInvisible () {
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
if (floatingObject.isFrozen === true || floatingObject.isParentCollapsed === true) {
invisibleFloatingObjects.push(floatingObject)
visibleFloatingObjects.splice(i, 1) // Delete item from array.
makeInvisible()
return // Only one at the time.
}
}
}
/******************************************/
/* */
/* Physics Engine Follows */
/* */
/******************************************/
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()
applyPhysics()
function applyPhysics () {
/* This function makes all the calculations to apply phisycs on all visible floatingObjects in this layer. */
try {
for (let i = 0; i < invisibleFloatingObjects.length; i++) {
let floatingObject = invisibleFloatingObjects[i]
floatingObject.physics()
}
for (let i = 0; i < visibleFloatingObjects.length; i++) {
let floatingObject = visibleFloatingObjects[i]
floatingObject.physics()
/* From here on, only if they are not too far. */
if (canvas.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)
proximityBetweenFloatingObjects(i)
}
} 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 > canvas.floatingSpace.container.frame.width) {
floatingObject.container.frame.position.x = canvas.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 > canvas.floatingSpace.container.frame.height) {
floatingObject.container.frame.position.y = canvas.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 changeTargetRepulsion (pDelta) {
try {
if (pDelta > 0) {
pDelta = 1
} else {
pDelta = -1
}
maxTargetRepulsionForce = maxTargetRepulsionForce + pDelta / 1000
if (maxTargetRepulsionForce < 0.0000000001) {
maxTargetRepulsionForce = 0.0000000001
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] changeTargetRepulsion -> 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) }
}
}
}
+566
View File
@@ -0,0 +1,566 @@
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: ANGLE_TO_PARENT.RANGE_90,
distanceToParent: DISTANCE_TO_PARENT.PARENT_100X,
isCollapsed: false,
isParentCollapsed: false,
frozenManually: false,
collapsedManually: false,
getPinStatus: getPinStatus,
getFreezeStatus: getFreezeStatus,
getCollapseStatus: getCollapseStatus,
getAngleToParent: getAngleToParent,
getDistanceToParent: getDistanceToParent,
nearbyFloatingObjects: [],
setPosition: setPosition,
pinToggle: pinToggle,
freezeToggle: freezeToggle,
collapseToggle: collapseToggle,
angleToParentToggle: angleToParentToggle,
distanceToParentToggle: distanceToParentToggle,
physics: physics,
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
let selfMouseOverEventSubscriptionId
let selfMouseClickEventSubscriptionId
let spaceMouseOverEventSubscriptionId
let spaceFocusAquiredEventSubscriptionId
let lastParentAngle
return thisObject
function finalize () {
thisObject.container.eventHandler.stopListening(selfMouseOverEventSubscriptionId)
thisObject.container.eventHandler.stopListening(selfMouseClickEventSubscriptionId)
canvas.floatingSpace.container.eventHandler.stopListening(spaceMouseOverEventSubscriptionId)
canvas.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 = canvas.floatingSpace.container.eventHandler.listenToEvent('onMouseOver', mouseOverFlotingSpace)
spaceFocusAquiredEventSubscriptionId = canvas.floatingSpace.container.eventHandler.listenToEvent('onFocusAquired', someoneAquiredFocus)
/* Assign a position and speed */
thisObject.initializeCurrentPosition(thisObject.payload.targetPosition)
thisObject.radomizeCurrentSpeed()
}
function getContainer (point) {
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === 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 getAngleToParent () {
return thisObject.angleToParent
}
function getDistanceToParent () {
return thisObject.distanceToParent
}
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 physics () {
collapsePhysics()
frozenPhysics()
/* From here on, only if they are not too far. */
if (canvas.floatingSpace.isItFar(thisObject.payload)) { return }
thisObjectPhysics()
thisObject.payload.uiObject.physics()
positionContraintsPhysics()
}
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 collapsePhysics () {
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 positionContraintsPhysics () {
if (thisObject.angleToParent !== ANGLE_TO_PARENT.NOT_FIXED && thisObject.isOnFocus !== true) {
let parent = thisObject.payload.chainParent
if (parent === undefined) { return }
if (parent.payload === undefined) { return }
if (parent.payload.position === undefined) { return }
let 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 ...
let parentChildren = canvas.designSpace.workspace.nodeChildren.childrenCount(parent, thisObject.payload.node)
let axisCount = parentChildren.childrenCount
let axisIndex = parentChildren.childIndex
let baseAngle = 0
let angleToParentAngle
if (parent.payload.distance !== undefined) {
switch (thisObject.distanceToParent) {
case DISTANCE_TO_PARENT.PARENT_025X:
distanceToParent = parent.payload.distance / 4
break
case DISTANCE_TO_PARENT.PARENT_050X:
distanceToParent = parent.payload.distance / 2
break
case DISTANCE_TO_PARENT.PARENT_100X:
distanceToParent = parent.payload.distance
break
case DISTANCE_TO_PARENT.PARENT_150X:
distanceToParent = parent.payload.distance * 1.5
break
case DISTANCE_TO_PARENT.PARENT_200X:
distanceToParent = parent.payload.distance * 2
break
}
}
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.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 (distanceToParent > 2000 || thisObject.isPinned === true) { return } // this is introduced to avoid edges cases when importing workspaces.
newPosition = {
x: parent.payload.position.x + distanceToParent * Math.cos(toRadians(thisObject.payload.angle)),
y: parent.payload.position.y + distanceToParent * Math.sin(toRadians(thisObject.payload.angle))
}
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 () {
// The radius also have a target.
if (Math.abs(thisObject.container.frame.radius - thisObject.targetRadius) >= 15) {
if (thisObject.container.frame.radius < thisObject.targetRadius) {
thisObject.container.frame.radius = thisObject.container.frame.radius + 15
} else {
thisObject.container.frame.radius = thisObject.container.frame.radius - 15
}
thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event)
}
// The imageSize also have a target.
if (Math.abs(thisObject.currentImageSize - thisObject.targetImageSize) >= 10) {
if (thisObject.currentImageSize < thisObject.targetImageSize) {
thisObject.currentImageSize = thisObject.currentImageSize + 10
} else {
thisObject.currentImageSize = thisObject.currentImageSize - 10
}
}
// The fontSize also have a target.
if (Math.abs(thisObject.currentFontSize - thisObject.targetFontSize) >= 1) {
if (thisObject.currentFontSize < thisObject.targetFontSize) {
thisObject.currentFontSize = thisObject.currentFontSize + 1
} else {
thisObject.currentFontSize = thisObject.currentFontSize - 1
}
}
/* 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 onMouseOver (point) {
if (thisObject.isOnFocus === false) {
thisObject.targetRadius = thisObject.rawRadius * 6.0
thisObject.targetImageSize = thisObject.rawImageSize * 2.0
thisObject.targetFontSize = thisObject.rawFontSize * 2.0
thisObject.payload.uiObject.container.eventHandler.raiseEvent('onFocus', point)
thisObject.positionLocked = true
canvas.floatingSpace.container.eventHandler.raiseEvent('onFocusAquired', thisObject.container)
thisObject.isOnFocus = true
}
}
function mouseOverFlotingSpace (point) {
removeFocus()
}
function someoneAquiredFocus (container) {
if (container === undefined) {
return
}
if (thisObject.container === undefined) {
return
}
if (container.id !== thisObject.container.id) {
removeFocus()
}
}
function removeFocus () {
if (thisObject.payload === undefined) { return }
if (thisObject.isOnFocus === true) {
thisObject.targetRadius = thisObject.rawRadius * 1
thisObject.targetImageSize = thisObject.rawImageSize * 1
thisObject.targetFontSize = thisObject.rawFontSize * 1
thisObject.payload.uiObject.container.eventHandler.raiseEvent('onNotFocus')
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 (canvas.floatingSpace.isItFar(thisObject.payload)) { return }
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === true) { return }
thisObject.payload.uiObject.drawBackground()
}
function drawMiddleground () {
if (canvas.floatingSpace.isItFar(thisObject.payload)) { return }
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === true) { return }
thisObject.payload.uiObject.drawMiddleground()
}
function drawForeground () {
if (canvas.floatingSpace.isItFar(thisObject.payload)) { return }
if ((thisObject.isCollapsed === true && thisObject.collapsedManually === false) || thisObject.isParentCollapsed === true) { return }
thisObject.payload.uiObject.drawForeground()
}
function drawOnFocus () {
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
thisObject.container.frame.radius = radius / 3
thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event)
}
function initializeImageSize (suggestedValue) {
var size = suggestedValue
if (size < 2) {
size = 2
}
thisObject.rawImageSize = size
thisObject.targetImageSize = size
thisObject.currentImageSize = size / 3
}
function initializeFontSize (suggestedValue) {
var size = suggestedValue
if (size < 3) {
size = 3
}
thisObject.rawFontSize = size
thisObject.targetFontSize = size
thisObject.currentFontSize = size / 3
}
function 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 () {
}
}
+215
View File
@@ -0,0 +1,215 @@
function newFormulaEditor () {
const MODULE_NAME = 'Formula Editor'
let thisObject = {
isVisibleFunction: undefined,
iconOK: undefined,
iconNOT_OK: 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
return thisObject
function finalize () {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.iconOK = undefined
thisObject.iconNOT_OK = undefined
thisObject.payload = undefined
thisObject.isVisibleFunction = undefined
}
function initialize () {
/* Load Images */
thisObject.iconOK = new Image()
thisObject.iconOK.onload = onImageLoad
function onImageLoad () {
thisObject.iconNOT_OK = new Image()
thisObject.iconNOT_OK.onload = onImageLoad
function onImageLoad () {
thisObject.canDrawIcon = true
}
thisObject.iconNOT_OK.src = window.canvasApp.urlPrefix + thisObject.imagePathNOT_OK
}
// thisObject.iconOK.src = window.canvasApp.urlPrefix + thisObject.imagePathOK
// thisObject.icon = thisObject.iconOK // The default value is ON.
}
function deactivate () {
if (thisObject.visible === true) {
thisObject.visible = false
let textArea = document.getElementById('textArea')
textArea.style.display = 'none'
thisObject.payload.node.code = textArea.value
}
}
function activate (payload) {
thisObject.visible = true
thisObject.payload = payload
thisObject.rawRadius = 8
thisObject.targetRadius = thisObject.container.frame.radius
thisObject.currentRadius = 0
thisObject.payload.uiObject.setErrorMessage('', 0)
let textArea = document.getElementById('textArea')
textArea.value = payload.node.code
textArea.style = 'resize: none;' +
' border: none;' +
' outline: none;' +
'box-shadow: none;' +
'overflow:hidden;' +
'font-family: ' + UI_FONT.PRIMARY + ';' +
'font-size: 12px;' +
'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()
}
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.8 * 2
thisObject.container.frame.height = thisObject.container.frame.radius * 1 * 2
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 * 2
if (radius > 0.5) {
browserCanvasContext.beginPath()
browserCanvasContext.arc(position.x, position.y, radius * 1.3 + 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 * 1.3, 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 (label !== undefined && 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,483 @@
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 = canvas.floatingSpace.fitIntoVisibleArea
floatingObject.container.connectToParent(canvas.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
}
}
/* For brand new objects being created directly by the user, we will make them inherit some properties from their parents. */
if (userAddingNew === true) {
floatingObject.angleToParent = payload.parentNode.payload.floatingObject.angleToParent
floatingObject.distanceToParent = payload.parentNode.payload.floatingObject.distanceToParent
}
let uiObject = newUiObject()
payload.uiObject = uiObject
uiObject.fitFunction = canvas.floatingSpace.fitIntoVisibleArea
uiObject.isVisibleFunction = canvas.floatingSpace.isThisPointVisible
let menuItemsInitialValues = getMenuItemsInitialValues(uiObject, floatingObject, payload)
for (let i = 0; i < APP_SCHEMA_ARRAY.length; i++) {
let schemaNode = APP_SCHEMA_ARRAY[i]
if (schemaNode.type === payload.node.type) {
let menuItems = schemaNode.menuItems
for (let j = 0; j < menuItems.length; j++) {
let item = menuItems[j]
item.angle = undefined
if (item.action.indexOf('Add ') >= 0 && item.action.indexOf('Missing') >= 0) {
item.action = 'Add Missing Children'
}
if (item.action.indexOf('Delete ') >= 0) {
// item.action = 'Delete UI Object'
}
if (item.action.indexOf('Configure ') >= 0) {
if (schemaNode.editors.config === true) {
// item.actionFunction = 'uiObject.configEditor.activate'
}
}
if (item.action.indexOf('Edit ') >= 0) {
if (schemaNode.editors.code === true) {
// item.actionFunction = 'uiObject.codeEditor.activate'
}
}
if (item.actionFunction === undefined) {
// item.actionFunction = 'payload.onMenuItemClick'
}
}
}
}
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: 'menu-fix-pinned',
iconPathOff: 'menu-fix-unpinned',
rawRadius: 8,
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: 8,
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: 8,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Freeze / Unfreeze',
actionFunction: floatingObject.freezeToggle,
actionStatus: floatingObject.getFreezeStatus,
currentStatus: true,
label: undefined,
visible: true,
iconPathOn: 'menu-mobility-unfreeze',
iconPathOff: 'menu-mobility-freeze',
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Collapse / Uncollapse',
actionFunction: floatingObject.collapseToggle,
actionStatus: floatingObject.getCollapseStatus,
currentStatus: false,
label: undefined,
visible: true,
iconPathOn: 'menu-tree-plus',
iconPathOff: 'menu-tree-minus',
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
ring: 1
}
)
menuItemsInitialValues.push(
{
action: 'Backup',
actionFunction: floatingObject.payload.onMenuItemClick,
label: undefined,
visible: true,
iconPathOn: 'menu-backup',
iconPathOff: 'menu-backup',
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
ring: 2
}
)
menuItemsInitialValues.push(
{
action: 'Clone',
actionFunction: floatingObject.payload.onMenuItemClick,
label: undefined,
visible: true,
iconPathOn: 'clone',
iconPathOff: 'clone',
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
ring: 2
}
)
if (isPersonalData !== true) {
menuItemsInitialValues.push(
{
action: 'Share',
actionFunction: floatingObject.payload.onMenuItemClick,
label: undefined,
visible: true,
iconPathOn: 'menu-share',
iconPathOff: 'menu-share',
rawRadius: 8,
targetRadius: 0,
currentRadius: 0,
ring: 2
}
)
}
}
function getMenuItemsInitialValues (uiObject, floatingObject, payload) {
let menuItemsInitialValues = []
let nodeDefinition = APP_SCHEMA_MAP.get(payload.node.type)
if (nodeDefinition !== undefined) {
if (nodeDefinition.editors !== undefined) {
if (nodeDefinition.editors.config === true) {
uiObject.configEditor = newConfigEditor()
uiObject.configEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.configEditor.initialize()
uiObject.configEditor.container.connectToParent(uiObject.container, false, false, true, true, false, false, false, false)
}
if (nodeDefinition.editors.code === true) {
uiObject.codeEditor = newCodeEditor()
uiObject.codeEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.codeEditor.initialize()
uiObject.codeEditor.container.connectToParent(uiObject.container, false, false, true, true, false, false, false, false)
}
if (nodeDefinition.editors.formula === true) {
uiObject.formulaEditor = newFormulaEditor()
uiObject.formulaEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.formulaEditor.initialize()
uiObject.formulaEditor.container.connectToParent(uiObject.container, false, false, true, true, false, false, false, false)
}
if (nodeDefinition.editors.condition === true) {
uiObject.conditionEditor = newConditionEditor()
uiObject.conditionEditor.isVisibleFunction = uiObject.isVisibleFunction
uiObject.conditionEditor.initialize()
uiObject.conditionEditor.container.connectToParent(uiObject.container, false, false, true, true, false, false, false, false)
}
}
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) {
newMenuItem.actionFunction = eval(menutItemDefinition.actionFunction)
}
/* Adding default values */
if (newMenuItem.visible === undefined) {
newMenuItem.visible = true
}
if (newMenuItem.rawRadius === undefined) {
newMenuItem.rawRadius = 8
}
if (newMenuItem.targetRadius === undefined) {
newMenuItem.targetRadius = 0
}
if (newMenuItem.currentRadius === undefined) {
newMenuItem.currentRadius = 0
}
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
switch (payload.node.type) {
case 'Workspace': {
level_0()
floatingObject.angleToParent = ANGLE_TO_PARENT.RANGE_360
break
}
default: {
let nodeDefinition = APP_SCHEMA_MAP.get(payload.node.type)
if (nodeDefinition !== undefined) {
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(45)
floatingObject.initializeImageSize(80)
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(45)
floatingObject.initializeImageSize(80)
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(40)
floatingObject.initializeImageSize(70)
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(35)
floatingObject.initializeImageSize(60)
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(30)
floatingObject.initializeImageSize(50)
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(25)
floatingObject.initializeImageSize(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(20)
floatingObject.initializeImageSize(30)
floatingObject.initializeFontSize(INITIAL_FONT_SIZE)
floatingObject.fillStyle = 'rgba(' + UI_COLOR.RED + ', 1)'
}
floatingObject.labelStrokeStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
}
function destroyUiObject (payload) {
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
}
}
+298
View File
@@ -0,0 +1,298 @@
function newUiObjectTitle () {
const MODULE_NAME = 'UI Object Title'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
isVisibleFunction: undefined,
allwaysVisible: undefined,
editMode: undefined,
container: undefined,
payload: 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
}
function initialize (payload) {
thisObject.payload = payload
thisObject.allwaysVisible = false // Default value
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
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 () {
if (thisObject.payload.title === undefined) { return }
/* It is possible to override the default title by setting the APP SCHEMA property 'title' */
let nodeDefinition = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
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 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 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
}
}
separator = ' '
}
}
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
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
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 = APP_SCHEMA_MAP.get(thisObject.payload.node.type)
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
}
}
}
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) {
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_COLOR.BLACK,
backgroundColor: UI_COLOR.BLACK,
castShadow: false,
opacity: 0.25
}
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)) {
browserCanvasContext.strokeStyle = thisObject.payload.floatingObject.labelStrokeStyle
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)
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = thisObject.payload.floatingObject.labelStrokeStyle
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
}
}
+511
View File
@@ -0,0 +1,511 @@
function newFrame () {
const PANEL_CORNERS_RADIUS = 5
const TITLE_BAR_HEIGHT = 15 // this must be grater than radius
let thisObject = {
type: 'Rectangle',
containerName: '', // This is for debugging purposes only.
parentFrame: undefined, // Here we store the parent cointainer zoom object.
radius: 0,
offset: undefined,
position: undefined,
container: undefined,
width: browserCanvas.width,
height: browserCanvas.height,
getBodyHeight: getBodyHeight,
draw: draw,
fitIntoFrame: fitIntoFrame,
frameThisPoint: frameThisPoint, // This function changes the actual frame coordinate system to the screen coordinate system.
unframeThisPoint: unframeThisPoint,
isThisPointHere: isThisPointHere, // This function return true is the point received as parameter lives within this frame.
isThisScreenPointHere: isThisScreenPointHere,
isInViewPort: isInViewPort,
initialize: initialize,
finalize: finalize
}
return thisObject
function finalize () {
thisObject.parentFrame = undefined
thisObject.position = undefined
thisObject.offset = undefined
}
function initialize (pType) {
if (pType !== undefined) { thisObject.type = pType }
thisObject.position = {
x: 0,
y: 0
}
thisObject.offset = {
x: 0,
y: 0
}
}
function getBodyHeight () {
return thisObject.height - TITLE_BAR_HEIGHT
}
function isInViewPort () {
/* This function is usefull to know if the object who has this frame is currently appearing at least in part at the canvas.chartingSpace.viewport */
point1 = {
x: 0,
y: 0
}
point3 = {
x: thisObject.width,
y: thisObject.height
}
/* Now the transformations. */
point1 = transformThisPoint(point1, thisObject.container)
point3 = transformThisPoint(point3, thisObject.container)
if (point1.x < canvas.chartingSpace.viewport.visibleArea.topRight.x && point1.y < canvas.chartingSpace.viewport.visibleArea.bottomRight.y && point3.x > canvas.chartingSpace.viewport.visibleArea.bottomLeft.x && point3.y > canvas.chartingSpace.viewport.visibleArea.topLeft.y) {
return true
} else {
return false
}
}
function frameThisPoint (point) {
/* We need not to modify the point received, so me make a copy of it. */
let checkPoint = {
x: point.x,
y: point.y
}
let parentPoint = {
x: 0,
y: 0
}
let returnPoint = {
x: 0,
y: 0
}
if (thisObject.parentFrame !== undefined) {
parentPoint = thisObject.parentFrame.frameThisPoint(checkPoint)
returnPoint.x = parentPoint.x + thisObject.position.x + thisObject.offset.x
returnPoint.y = parentPoint.y + thisObject.position.y + thisObject.offset.y
} else {
returnPoint.x = checkPoint.x + thisObject.position.x + thisObject.offset.x
returnPoint.y = checkPoint.y + thisObject.position.y + thisObject.offset.y
}
return returnPoint
}
function unframeThisPoint (point) {
/* We need not to modify the point received, so me make a copy of it. */
let checkPoint = {
x: point.x,
y: point.y
}
let parentPoint = {
x: 0,
y: 0
}
let returnPoint = {
x: 0,
y: 0
}
if (thisObject.parentFrame !== undefined) {
parentPoint = thisObject.parentFrame.unframeThisPoint(checkPoint)
returnPoint.x = parentPoint.x - thisObject.position.x
returnPoint.y = parentPoint.y - thisObject.position.y
} else {
returnPoint.x = checkPoint.x - thisObject.position.x
returnPoint.y = checkPoint.y - thisObject.position.y
}
return returnPoint
}
function fitIntoFrame (point) {
/* Here we check the boundaries of the resulting points, so they dont go out of the visible area. */
if (point.x > thisObject.width) {
point.x = thisObject.width
}
if (point.x < 0) {
point.x = 0
}
if (point.y > thisObject.height) {
point.y = thisObject.height
}
if (point.y < 0) {
point.y = 0
}
return point
}
function isThisPointHere (point, outsideViewPort, dontTransform, padding) {
// The second parameter is usefull when you want to check a point that you already know is outside the viewport.
// The padding is a distance to the borders of the container. Can be either negative (outside, to increase the cointainer size) or positive (inside to decrease the cointainer size)
if (padding === undefined) { padding = 0 }
/* We need not to modify the point received, so me make a copy of it. */
let checkPoint = {
x: point.x,
y: point.y
}
/* The point received is on the screen coordinates system, which already has zoom and displacement applied. We need to remove the zoom and displacement
in order to have the point on the containers coordinate system and be able to compare it with its dimmensions. */
if (dontTransform === false || dontTransform === undefined) {
if (outsideViewPort === true) {
checkPoint = thisObject.container.frame.unframeThisPoint(checkPoint)
} else {
checkPoint = unTransformThisPoint(checkPoint, thisObject.container)
}
}
/* Now we check if the resulting point is whin the current Frame. */
if (thisObject.type === 'Circle') {
let distance = Math.sqrt(Math.pow(thisObject.position.x - point.x, 2) + Math.pow(thisObject.position.y - point.y, 2))
if (distance < thisObject.radius) {
return true
} else {
return false
}
}
if (thisObject.type === 'Rectangle') {
if (checkPoint.x < 0 + padding || checkPoint.y < 0 + padding || checkPoint.x > thisObject.width - padding || checkPoint.y > thisObject.height - padding) {
return false
} else {
return true
}
}
}
function isThisScreenPointHere (point) {
let checkPoint = {
x: point.x,
y: point.y
}
let thisPoint = {
x: thisObject.position.x,
y: thisObject.position.y
}
if (thisObject.parentFrame !== undefined) {
thisPoint = thisObject.parentFrame.frameThisPoint(thisPoint)
}
/* Now we check if the resulting point is whin the current Frame. */
if (thisObject.type === 'Circle') {
let distance = Math.sqrt(Math.pow(thisPoint.x - checkPoint.x, 2) + Math.pow(thisPoint.y - checkPoint.y, 2))
if (distance < thisObject.radius) {
return true
} else {
return false
}
}
if (thisObject.type === 'Rectangle') {
if (checkPoint.x < 0 || checkPoint.y < 0 || checkPoint.x > thisObject.width || checkPoint.y > thisObject.height) {
return false
} else {
return true
}
}
}
function draw (drawGrid, drawBorders, drawBackground, fitFunction, style) {
if (drawBorders === true) {
borders(fitFunction, style)
}
if (drawGrid === true) {
grid(fitFunction)
}
if (drawBackground === true) {
background(fitFunction)
}
}
function background (fitFunction) {
let params = {
cornerRadius: 5,
lineWidth: 0.1,
opacity: 0.75,
container: thisObject.container,
borderColor: UI_COLOR.DARK,
backgroundColor: UI_COLOR.WHITE,
fitFunction: fitFunction
}
roundedCornersBackground(params)
titleBarPoint1 = {
x: 0,
y: TITLE_BAR_HEIGHT
}
titleBarPoint2 = {
x: thisObject.width,
y: TITLE_BAR_HEIGHT
}
/* Now the transformations. */
titleBarPoint1 = frameThisPoint(titleBarPoint1)
titleBarPoint2 = frameThisPoint(titleBarPoint2)
if (fitFunction !== undefined) {
titleBarPoint1 = fitFunction(titleBarPoint1)
titleBarPoint2 = fitFunction(titleBarPoint2)
}
/* We paint the title bar now */
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 1)'
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(titleBarPoint1.x, titleBarPoint1.y)
browserCanvasContext.lineTo(borderPoint1.x - PANEL_CORNERS_RADIUS, borderPoint1.y)
browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, PANEL_CORNERS_RADIUS, 1.0 * Math.PI, 1.5 * Math.PI)
browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - PANEL_CORNERS_RADIUS)
browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, PANEL_CORNERS_RADIUS, 1.5 * Math.PI, 2.0 * Math.PI)
browserCanvasContext.lineTo(titleBarPoint2.x, titleBarPoint2.y)
browserCanvasContext.closePath()
browserCanvasContext.fill()
browserCanvasContext.lineWidth = 0.1
browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 0.75)'
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke()
/* print the title */
let labelPoint
let fontSize = 10
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
let label = thisObject.containerName
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
let yOffset = (TITLE_BAR_HEIGHT - fontSize) / 2 + 2
labelPoint = {
x: thisObject.width / 2 - xOffset,
y: TITLE_BAR_HEIGHT - yOffset
}
labelPoint = thisObject.frameThisPoint(labelPoint)
if (fitFunction !== undefined) {
labelPoint = fitFunction(labelPoint)
}
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
function borders (fitFunction, style) {
/* Lest get the important points of the drawing so as to apply the needed transformations. */
let point1
let point2
let point3
let point4
point1 = {
x: 0,
y: 0
}
point2 = {
x: thisObject.width,
y: 0
}
point3 = {
x: thisObject.width,
y: thisObject.height
}
point4 = {
x: 0,
y: thisObject.height
}
/* Now the transformations. */
point1 = transformThisPoint(point1, thisObject.container)
point2 = transformThisPoint(point2, thisObject.container)
point3 = transformThisPoint(point3, thisObject.container)
point4 = transformThisPoint(point4, thisObject.container)
if (fitFunction !== undefined) {
point1 = fitFunction(point1)
point2 = fitFunction(point2)
point3 = fitFunction(point3)
point4 = fitFunction(point4)
}
/* Lets start the drawing. */
browserCanvasContext.beginPath()
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
browserCanvasContext.lineTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
browserCanvasContext.lineTo(point1.x, point1.y)
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(' + style.color + ', ' + style.opacity + ')'
browserCanvasContext.lineWidth = style.lineWidth
browserCanvasContext.setLineDash(style.lineDash)
browserCanvasContext.stroke()
browserCanvasContext.closePath()
}
function grid (fitFunction, smallLines) {
if (smallLines === true) {
/* Small Lines */
let step = thisObject.width / 100
browserCanvasContext.beginPath()
for (let i = 0; i < thisObject.width; i = i + step) {
for (let j = 0; j < thisObject.height; j = j + step) {
let point1 = {
x: 0,
y: j
}
let point2 = {
x: thisObject.width,
y: j
}
point1 = transformThisPoint(point1, thisObject.container)
point2 = transformThisPoint(point2, thisObject.container)
if (fitFunction !== undefined) {
point1 = fitFunction(point1)
point2 = fitFunction(point2)
}
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
}
let point3 = {
x: thisObject.width,
y: thisObject.height
}
let point4 = {
x: 0,
y: thisObject.height
}
point3 = transformThisPoint(point3, thisObject.container)
point4 = transformThisPoint(point4, thisObject.container)
if (fitFunction !== undefined) {
point3 = fitFunction(point3)
point4 = fitFunction(point4)
}
browserCanvasContext.moveTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
}
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(150, 150, 150, 0.1)'
browserCanvasContext.lineWidth = 1
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke()
}
/* Main Lines */
let step = thisObject.width / 20
browserCanvasContext.beginPath()
for (let i = 0; i < thisObject.width; i = i + step) {
for (let j = 0; j < thisObject.height; j = j + step) {
let point1 = {
x: 0,
y: j
}
let point2 = {
x: thisObject.width,
y: j
}
point1 = transformThisPoint(point1, thisObject.container)
point2 = transformThisPoint(point2, thisObject.container)
if (fitFunction !== undefined) {
point1 = fitFunction(point1)
point2 = fitFunction(point2)
}
browserCanvasContext.moveTo(point1.x, point1.y)
browserCanvasContext.lineTo(point2.x, point2.y)
}
let point3 = {
x: i,
y: 0
}
let point4 = {
x: i,
y: thisObject.height
}
point3 = transformThisPoint(point3, thisObject.container)
point4 = transformThisPoint(point4, thisObject.container)
if (fitFunction !== undefined) {
point3 = fitFunction(point3)
point4 = fitFunction(point4)
}
browserCanvasContext.moveTo(point3.x, point3.y)
browserCanvasContext.lineTo(point4.x, point4.y)
}
browserCanvasContext.closePath()
browserCanvasContext.strokeStyle = 'rgba(100, 100, 100, 0.2)'
browserCanvasContext.lineWidth = 1
browserCanvasContext.setLineDash([0, 0])
browserCanvasContext.stroke()
}
}
+221
View File
@@ -0,0 +1,221 @@
/* User Interface Colors */
const CANVAS_APP_NAME = 'Canvas App'
const SUPPORTED_EXCHANGES = ["Poloniex"];
const SUPPORTED_MARKETS = [
{
baseAsset: "USDT",
quotedAsset: "BTC",
}
];
const DEFAULT_EXCHANGE = "Poloniex";
const DEFAULT_MARKET = {
baseAsset: "USDT",
quotedAsset: "BTC",
};
UI_COLOR = {
DARK: "48, 48, 54",
LIGHT: "234, 226, 222",
GREY: "150, 150, 150",
LIGHT_GREY: "247, 247, 247",
WHITE: "255, 255, 255",
BLACK: "0, 0, 0",
GOLDEN_ORANGE: "240, 162, 2",
RUSTED_RED: "204, 88, 53",
GREEN: "188, 214, 67",
RED: "223, 70, 60",
PATINATED_TURQUOISE: "27,153,139",
TITANIUM_YELLOW: "244,228,9",
MANGANESE_PURPLE: "91,80,122",
TURQUOISE: "74,207,217",
DARK_TURQUOISE: "2,149,170"
};
/* User Interface Fonts */
UI_FONT = {
PRIMARY: "Saira Condensed",
SECONDARY: "Source Code Pro"
};
const DEBUG = {}
const ZOOM_OUT_THRESHOLD_FOR_HIDDING_PANELS = 5 // This regulates some behavious changes that happens when the user zoom out below this level.
const ZOOM_OUT_THRESHOLD_FOR_CHANGING_TIME_FRAME = 5 // This help regulate when to change the Time Frame base on the level of zoom out.
const ZOOM_OUT_THRESHOLD_FOR_PACKING_OBJECTS_AT_THE_BOTTOM_OR_TOP_OF_VIEWPORT = 5
let FONT_ASPECT_RATIO = 0.32;
const GET_CONTAINER_PURPOSE = {
MOUSE_OVER: 1,
MOUSE_WHEEL: 2,
MOUSE_CLICK: 3,
DRAGGING: 4
}
const ANGLE_TO_PARENT = {
NOT_FIXED: 0,
RANGE_360: 1,
RANGE_180: 2,
RANGE_90: 3,
RANGE_45: 4
}
const DISTANCE_TO_PARENT = {
NOT_FIXED: 0,
PARENT_025X: 1,
PARENT_050X: 2,
PARENT_100X: 3,
PARENT_150X: 4,
PARENT_200X: 5
}
/* User Interface Panels */
UI_PANEL = {
WIDTH: {
SMALL: 100,
NORMAL: 150,
MEDIUM: 200,
LARGE: 250,
X_LARGE: 350
},
HEIGHT: {
SMALL: 65,
MEDIUM: 90,
NORMAL: 300,
LARGE: 450
}
};
let marketFilesPeriods =
'[' +
'[' + 24 * 60 * 60 * 1000 + ',' + '"24-hs"' + ']' + ',' +
'[' + 12 * 60 * 60 * 1000 + ',' + '"12-hs"' + ']' + ',' +
'[' + 8 * 60 * 60 * 1000 + ',' + '"08-hs"' + ']' + ',' +
'[' + 6 * 60 * 60 * 1000 + ',' + '"06-hs"' + ']' + ',' +
'[' + 4 * 60 * 60 * 1000 + ',' + '"04-hs"' + ']' + ',' +
'[' + 3 * 60 * 60 * 1000 + ',' + '"03-hs"' + ']' + ',' +
'[' + 2 * 60 * 60 * 1000 + ',' + '"02-hs"' + ']' + ',' +
'[' + 1 * 60 * 60 * 1000 + ',' + '"01-hs"' + ']' + ']';
marketFilesPeriods = JSON.parse(marketFilesPeriods);
let dailyFilePeriods =
'[' +
'[' + 45 * 60 * 1000 + ',' + '"45-min"' + ']' + ',' +
'[' + 40 * 60 * 1000 + ',' + '"40-min"' + ']' + ',' +
'[' + 30 * 60 * 1000 + ',' + '"30-min"' + ']' + ',' +
'[' + 20 * 60 * 1000 + ',' + '"20-min"' + ']' + ',' +
'[' + 15 * 60 * 1000 + ',' + '"15-min"' + ']' + ',' +
'[' + 10 * 60 * 1000 + ',' + '"10-min"' + ']' + ',' +
'[' + 05 * 60 * 1000 + ',' + '"05-min"' + ']' + ',' +
'[' + 04 * 60 * 1000 + ',' + '"04-min"' + ']' + ',' +
'[' + 03 * 60 * 1000 + ',' + '"03-min"' + ']' + ',' +
'[' + 02 * 60 * 1000 + ',' + '"02-min"' + ']' + ',' +
'[' + 01 * 60 * 1000 + ',' + '"01-min"' + ']' + ']';
dailyFilePeriods = JSON.parse(dailyFilePeriods);
SHOW_ANIMATION_PERFORMACE = false;
let testUser = window.localStorage.getItem("test_user")
let LOGGED_IN_USER_LOCAL_STORAGE_KEY
let LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE_KEY
if (testUser !== null) {
LOGGED_IN_USER_LOCAL_STORAGE_KEY = "test_user"
LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE_KEY = "test_access_token"
} else {
LOGGED_IN_USER_LOCAL_STORAGE_KEY = "user"
LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE_KEY = "access_token"
}
const DEFAULT_CONFIG_TEXT = '// Write your config here'
const DEFAULT_FORMULA_TEXT = '// Write your formula here'
const DEFAULT_CODE_TEXT = '// Write your code here'
const MAX_DEFAULT_RATE_SCALE_VALUE = 35000; // This is needed to know the scale of the market time line.
const WIDHTER_VOLUME_BAR_BASE_FACTOR = 2.5;
const LESS_WIDHTER_VOLUME_BAR_TOP_FACTOR = 1 / 4;
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
const _12_HOURS_IN_MILISECONDS = 12 * 60 * 60 * 1000;
const _8_HOURS_IN_MILISECONDS = 8 * 60 * 60 * 1000;
const _6_HOURS_IN_MILISECONDS = 6 * 60 * 60 * 1000;
const _4_HOURS_IN_MILISECONDS = 4 * 60 * 60 * 1000;
const _3_HOURS_IN_MILISECONDS = 3 * 60 * 60 * 1000;
const _2_HOURS_IN_MILISECONDS = 2 * 60 * 60 * 1000;
const _1_HOUR_IN_MILISECONDS = 1 * 60 * 60 * 1000;
const _45_MINUTES_IN_MILISECONDS = 45 * 60 * 1000;
const _40_MINUTES_IN_MILISECONDS = 40 * 60 * 1000;
const _30_MINUTES_IN_MILISECONDS = 30 * 60 * 1000;
const _20_MINUTES_IN_MILISECONDS = 20 * 60 * 1000;
const _15_MINUTES_IN_MILISECONDS = 15 * 60 * 1000;
const _10_MINUTES_IN_MILISECONDS = 10 * 60 * 1000;
const _5_MINUTES_IN_MILISECONDS = 5 * 60 * 1000;
const _4_MINUTES_IN_MILISECONDS = 4 * 60 * 1000;
const _3_MINUTES_IN_MILISECONDS = 3 * 60 * 1000;
const _2_MINUTES_IN_MILISECONDS = 2 * 60 * 1000;
const _1_MINUTE_IN_MILISECONDS = 1 * 60 * 1000;
let NEW_SESSION_INITIAL_DATE = new Date(); // This value will be overwritten at the canvas.chartingSpace.viewport.initialize if the user had a prevous session with this same browser.
let INITIAL_ZOOM_LEVEL = -28.25 // This is the zoom level at the view port in which the APP starts.
let INITIAL_TIME_PERIOD = ONE_DAY_IN_MILISECONDS // This value will be overwritten at the canvas.chartingSpace.viewport.initialize if the user had a prevous session with this same browser.
let VERY_LARGE_NUMBER = 100000000000000
let CURRENT_TOP_MARGIN = window.canvasApp.topMargin
let AT_FULL_SCREEN_MODE = false
let maxDate = new Date();
maxDate.setMilliseconds(0);
maxDate.setDate(maxDate.getDate() + 365 * 1); // We might have charts that projects data into the future.
const MIN_PLOTABLE_DATE = new Date(2015, 0, 1, 0, 0, 0);
const MAX_PLOTABLE_DATE = maxDate;
const TOP_SPACE_HEIGHT = 40
const COCKPIT_SPACE_HEIGHT = 30;
const BREAKPOINT_HEIGHT = 15;
const SIDE_PANEL_WIDTH = 450
let COCKPIT_SPACE_POSITION = browserCanvas.height - COCKPIT_SPACE_HEIGHT
const LAYER_STATUS = {
ON: 'on',
LOADING: 'loading',
OFF: 'off'
};
let spawnPosition // this is used in several places.
/* Here we list the valid Time Periods: */
const PERIOD_24_HS = "24-hs";
const PERIOD_12_HS = "12-hs";
const PERIOD_06_HS = "06-hs";
const PERIOD_03_HS = "03-hs";
const PERIOD_01_HS = "01-hs";
const PERIOD_30_MIN = "30-min";
const PERIOD_10_MIN = "10-min";
const PERIOD_05_MIN = "05-min";
const PERIOD_01_MIN = "01-min";
/*
We define here the size of the chartingSpace. It has to bee enough big in order to accomodate all the charts we expect to display in this space.
*/
const TIME_MACHINE_WIDTH = 320;
const TIME_MACHINE_HEIGHT = 120;
let mediaRecorder // to downloadText canvas animation as a mediaRecorder
let areWeRecording = false
function toRadians(angle) {
return angle * (Math.PI / 180);
}
+531
View File
@@ -0,0 +1,531 @@
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,
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.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.container.eventHandler.stopListening(onMouseClickEventSuscriptionId)
}
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->Single Market Data->' +
'Session Independent Data->Session Based Data->' +
'Session Reference->Backtesting Session->Paper Trading Session->Fordward Testing Session->Live Trading Session->' +
'Market->Market Base Asset->Asset->' +
'Market Quoted Asset->Asset->' +
'Exchange Markets->Crypto Exchange->' +
'Product Definition->' +
'Sensor Bot->Indicator Bot->Trading Bot->' +
'Data 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 Body->Style->Style Condition->Style->' +
'Polygon Border->Style->Style Condition->Style->' +
'Polygon Vertex->Point->' +
'Plotter Panel->Javascript Code->Panel Data->Data Formula->'
thisObject.definition = functionLibraryProtocolNode.getProtocolNode(thisObject.payload.node, false, true, true, false, false, lightingPath)
/* Here we validate that we have all the needed information */
if (thisObject.definition.referenceParent === undefined) { return }
if (thisObject.definition.referenceParent.parentNode === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.parentNode === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.parentNode.parentNode === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.baseAsset === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.baseAsset.referenceParent === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.quotedAsset === undefined) { return }
if (thisObject.definition.referenceParent.parentNode.referenceParent.quotedAsset.referenceParent === undefined) { return }
if (thisObject.definition.referenceParent.referenceParent === undefined) { return }
if (thisObject.definition.referenceParent.referenceParent.parentNode === undefined) { return }
if (thisObject.definition.referenceParent.referenceParent.parentNode.parentNode === undefined) { return }
/* Lets listen to our own events to react when we have a Mouse Click */
onMouseClickEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) }
}
}
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) {
marketFileProgressBar.value = Math.trunc(event.totalValue * 100 / event.totalValue)
marketFileProgressBar.fillStyle = LOADING_FILL_STYLE
marketFileProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (marketFileProgressBar.value > 100) { marketFileProgressBar.value = 100 }
}
function onDailyFileLoaded (event) {
dailyFileProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue)
dailyFileProgressBar.fillStyle = LOADING_FILL_STYLE
dailyFileProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (dailyFileProgressBar.value > 100) { dailyFileProgressBar.value = 100 }
}
function onSingleFileLoaded (event) {
singleFileProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue)
singleFileProgressBar.fillStyle = LOADING_FILL_STYLE
singleFileProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (singleFileProgressBar.value > 100) { singleFileProgressBar.value = 100 }
}
function onFileSequenceLoaded (event) {
fileSequenceProgressBar.value = Math.trunc(event.currentValue * 100 / event.totalValue)
fileSequenceProgressBar.fillStyle = LOADING_FILL_STYLE
fileSequenceProgressBar.strokeStyle = LOADING_STROKE_STYLE
if (fileSequenceProgressBar.value > 100) { fileSequenceProgressBar.value = 100 }
}
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 = 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 {
savePropertyAtNodeConfig(thisObject.payload, 'showPanels', panelsVisibleButton.showPanels)
}
}
}
function statusPhysics () {
/* We retrieve the stored status at the config. */
try {
let storedValue = loadPropertyFromNodeConfig(thisObject.payload, 'status')
if (storedValue !== undefined) {
if (storedValue !== thisObject.status) {
if (storedValue === LAYER_STATUS.ON) {
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.
}
/* Check when the loading finishes */
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
}
}
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([1, 4])
browserCanvasContext.lineWidth = lineWidth
browserCanvasContext.stroke()
}
function drawLayerDisplay () {
let baseAsset = thisObject.definition.referenceParent.parentNode.referenceParent.baseAsset.referenceParent
let quotedAsset = thisObject.definition.referenceParent.parentNode.referenceParent.quotedAsset.referenceParent
let market = baseAsset.code.codeName + '/' + quotedAsset.code.codeName
let exchange = thisObject.definition.referenceParent.parentNode.referenceParent.parentNode.parentNode
let plotterModule = thisObject.definition.referenceParent.referenceParent.referenceParent
let label1 = thisObject.payload.node.name
let label2 = exchange.name.substring(0, 15) + ' - ' + market
let label3 = thisObject.status.toUpperCase()
if (label1 !== undefined) {
label1 = label1.substring(0, 22)
}
let icon1 = getIcon(exchange)
let icon2
if (plotterModule.code.icon !== undefined) {
icon2 = canvas.designSpace.iconCollection.get(plotterModule.code.icon)
}
let icon3 = getIcon(baseAsset)
let icon4 = getIcon(quotedAsset)
function getIcon (node) {
let nodeDefinition = APP_SCHEMA_MAP.get(node.type)
let iconName
if (nodeDefinition.alternativeIcons !== undefined) {
for (let i = 0; i < nodeDefinition.alternativeIcons.length; i++) {
alternativeIcon = nodeDefinition.alternativeIcons[i]
if (alternativeIcon.codeName === node.code.codeName) {
iconName = alternativeIcon.iconName
}
}
}
if (iconName !== undefined) {
icon = canvas.designSpace.iconCollection.get(iconName)
} else {
icon = canvas.designSpace.iconCollection.get(nodeDefinition.icon)
}
return icon
}
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
}
roundedCornersBackground(params)
drawLabel(label1, 1 / 2, 6 / 10, -5, 0, 17, thisObject.container)
drawLabel(label2, 1 / 2, 8.2 / 10, -5, 0, 9, thisObject.container)
drawLabel(label3, 1 / 2, 9.5 / 10, -5, 0, 9, thisObject.container)
drawProgressBar(marketFileProgressBar, 1, -45)
drawProgressBar(dailyFileProgressBar, 1, -46)
drawProgressBar(singleFileProgressBar, 1, -47)
drawProgressBar(fileSequenceProgressBar, 1, -48)
drawIcon(icon1, 1 / 8, 2 / 10, 0, 0, 14, thisObject.container)
drawIcon(icon2, 7 / 8, 2 / 10, 0, 0, 14, thisObject.container)
drawIcon(icon3, 3.4 / 8, 2 / 10, 0, 0, 14, thisObject.container)
drawIcon(icon4, 4.6 / 8, 2 / 10, 0, 0, 14, thisObject.container)
}
}
+458
View File
@@ -0,0 +1,458 @@
function newLayersPanel () {
let thisObject = {
name: 'Layers Panel',
fitFunction: undefined,
container: undefined,
layers: [],
payload: undefined,
isVisible: true,
panelTabButton: 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
let isInitialized = false
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
return thisObject
function finalize () {
thisObject.container.eventHandler.stopListening(onMouseWheelEventSuscriptionId)
thisObject.panelTabButton.finalize()
thisObject.panelTabButton = 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: canvas.chartingSpace.viewport.visibleArea.topLeft.x,
y: canvas.chartingSpace.viewport.visibleArea.topLeft.y
}
thisObject.container.frame.position = position
loadFrame(thisObject.payload, thisObject.container.frame)
thisObject.panelTabButton = newPanelTabButton()
thisObject.panelTabButton.parentContainer = thisObject.container
thisObject.panelTabButton.container.frame.parentFrame = thisObject.container.frame
thisObject.panelTabButton.fitFunction = thisObject.fitFunction
thisObject.panelTabButton.initialize()
onMouseWheelEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
readObjectState()
isInitialized = true
}
function saveObjectStateVisibleLayers () {
savePropertyAtNodeConfig(thisObject.payload, 'visibleLayers', desiredVisibleLayers)
}
function saveObjectStatePanelLocation () {
savePropertyAtNodeConfig(thisObject.payload, 'panelLocation', thisObject.panelTabButton.status)
}
function readObjectState () {
let storedValue
storedValue = 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 = 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 !== 'up' && storedValue !== 'down') {
saveObjectStatePanelLocation() // this overrides any invalid value at the config.
return
}
thisObject.panelTabButton.setStatus(storedValue)
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)
return layer
}
}
}
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.visible === false || thisObject.isHidden === true) { return }
let viewPortHeight = canvas.chartingSpace.viewport.visibleArea.bottomLeft.y - canvas.chartingSpace.viewport.visibleArea.topLeft.y
if (viewPortHeight < headerHeight) {
thisObject.visible = false
} else {
thisObject.visible = true
}
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) {
if (isInitialized === false || thisObject.visible === false || thisObject.isHidden === true) { return }
let container
container = thisObject.panelTabButton.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) {
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 }
thisObject.panelTabButton.physics()
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 () {
let layerManager = thisObject.payload.node
for (let p = 0; p < layerManager.layers.length; p++) {
let layerNode = layerManager.layers[p]
let found = removeFromLocalLayers(layerNode.id)
if (found !== true) {
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.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()
thisObject.panelTabButton.draw()
}
function drawHeader () {
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 = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.payload.parentNode.payload.parentNode.type)
let icon2 = canvas.designSpace.iconByUiObjectType.get(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
}
roundedCornersBackground(params)
drawLabel(label1, 1 / 2, 0, 0, 15, 9, thisObject.container)
drawLabel(label2, 1 / 2, 0, 0, 30, 9, thisObject.container)
drawIcon(icon1, 1 / 8, 0, 0, 20, 28, thisObject.container)
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()
}
}
}
+253
View File
@@ -0,0 +1,253 @@
function newPanelTabButton () {
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 = 'Panel Tab Button'
thisObject.container.initialize()
thisObject.container.isClickeable = true
thisObject.container.frame.containerName = 'Panel Tab Button'
/* Animation to hide the pannel */
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 = 10
thisObject.container.frame.height = 10
var position = {
x: thisObject.parentContainer.frame.width - 14,
y: 1
}
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 = canvas.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 = canvas.chartingSpace.viewport.visibleArea.topRight.y
downPosition.x = thisObject.parentContainer.frame.position.x
downPosition.y = canvas.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) {
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 */
return thisObject.container
} else {
/* This point does not belong to thisObject space. */
return undefined
}
}
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()
}
}
+84
View File
@@ -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++) {
panel = canvas.panelsSpace.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 = canvas.designSpace.iconCollection.get('plotter-panel')
} else {
icon = canvas.designSpace.iconCollection.get('toggle-panel-off')
}
drawIcon(icon, 1 / 2, 1 / 2, 0, 0, 14, thisObject.container)
}
}
+185
View File
@@ -0,0 +1,185 @@
function newPlotterPanel () {
const MODULE_NAME = 'Plotter Panel'
const ERROR_LOG = true
const INTENSIVE_LOG = false
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 panelTabButton
let panelNode
return thisObject
function finalize () {
thisObject.container.finalize()
thisObject.container = undefined
thisObject.fitFunction = undefined
thisObject.isVisible = undefined
heightFactor = undefined
currentRecord = undefined
panelTabButton.finalize()
panelTabButton = 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 = canvas.chartingSpace.viewport.visibleArea.topRight.x - thisObject.container.frame.width - thisObject.container.frame.width * Math.random() * 8
thisObject.container.frame.position.y = canvas.chartingSpace.viewport.visibleArea.bottomLeft.y - thisObject.container.frame.height - thisObject.container.frame.height * Math.random() * 1.5
panelTabButton = newPanelTabButton()
panelTabButton.parentContainer = thisObject.container
panelTabButton.container.frame.parentFrame = thisObject.container.frame
panelTabButton.fitFunction = thisObject.fitFunction
panelTabButton.initialize()
}
function getContainer (point) {
if (thisObject.isVisible !== true) { return }
let container
container = panelTabButton.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()
panelTabButton.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 = frameTitleHeight + frameBodyHeight
if (currentRecord === undefined) { return }
if (currentRecord.data === undefined) { return }
let record = currentRecord.data
/* 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 + 10
let valuePosition = i * 10 + 15
let value = 'No value defined.'
if (valuePosition > 100) {
heightFactor = 2
thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * heightFactor
}
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 = ' + panelNode.dataFormula.code) }
}
}
if (panelData.code.valueDecimals !== undefined) {
value = value.toFixed(panelData.code.valueDecimals)
}
if (panelData.code.labelText !== undefined) {
labelText = panelData.code.labelText
}
if (panelData.code.labelPosition !== undefined) {
labelPosition = panelData.code.labelPosition
}
if (panelData.code.valuePosition !== undefined) {
valuePosition = panelData.code.valuePosition
}
printLabel(labelText, X_AXIS, PANEL_HEIGHT * labelPosition / 100 / heightFactor, '1')
printLabel(value, X_AXIS, PANEL_HEIGHT * valuePosition / 100 / heightFactor, '0.50')
}
function printLabel (labelToPrint, x, y, opacity) {
let labelPoint
let fontSize = 10
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY
let label = '' + labelToPrint
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
labelPoint = {
x: x - xOffset,
y: y
}
labelPoint = thisObject.container.frame.frameThisPoint(labelPoint)
labelPoint = thisObject.fitFunction(labelPoint)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', ' + opacity + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
}
browserCanvasContext.closePath()
browserCanvasContext.fill()
}
}
+821
View File
@@ -0,0 +1,821 @@
function newPlotter () {
const MODULE_NAME = 'Plotter'
const ERROR_LOG = true
const INTENSIVE_LOG = false
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 plotterModuleConfig
let slotHeight = (canvas.chartingSpace.viewport.visibleArea.bottomRight.y - canvas.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 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)
canvas.chartingSpace.viewport.eventHandler.stopListening(zoomChangedEventSubscriptionId)
canvas.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
plotterModuleConfig = 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 = canvas.chartingSpace.viewport.eventHandler.listenToEvent('Zoom Changed', onViewportZoomChanged)
offsetChangedEventSubscriptionId = canvas.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 = getDateFromPointAtBrowserCanvas(event, thisObject.container, coordinateSystem)
userPositionDate = userPosition.valueOf()
}
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) {
let newMarketFile = marketFiles.getFile(pTimeFrame)
if (newMarketFile !== undefined) {
marketFile = newMarketFile
recalculate()
}
} else {
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame)
if (newFileCursor !== undefined) {
fileCursor = newFileCursor
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()
plotChart()
} 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.code.isCalculated !== true) {
record[property.code.codeName] = dataFile[i][j]
}
}
if (
(record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) &&
(record.end >= coordinateSystem.min.x && record.begin <= coordinateSystem.max.x)
) {
record.previous = previous
jsonifiedArray.push(record)
previous = record
if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) {
thisObject.currentRecord = record
thisObject.container.eventHandler.raiseEvent('Current Record Changed', thisObject.currentRecord)
}
}
}
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 code 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.code.isCalculated === true) {
if (property.formula !== undefined) {
if (property.formula.code !== undefined) {
try {
let newValue = eval(property.formula.code)
let currentRecord = product
currentRecord[property.code.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) { return } // We need to wait until there is a fileCursor
if (fileCursor.files.size === 0) { return } // We need to wait until there are files in the cursor
let daysOnSides = getSideDays(timeFrame)
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem)
let rightDate = getDateFromPointAtBrowserCanvas(canvas.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)
}
/* Lests check if all the visible screen is going to be covered by candle-record. */
let lowerEnd = leftDate.valueOf()
let upperEnd = rightDate.valueOf()
if (records.length > 0) {
if (records[0].begin > lowerEnd || records[records.length - 1].end < upperEnd) {
setTimeout(recalculate, 2000)
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] recalculateUsingDailyFiles -> err = ' + err.stack) }
}
}
function recalculateUsingMarketFiles () {
try {
if (marketFile === undefined) { return } // Initialization not complete yet.
let daysOnSides = getSideDays(timeFrame)
let leftDate = getDateFromPointAtBrowserCanvas(canvas.chartingSpace.viewport.visibleArea.topLeft, thisObject.container, coordinateSystem)
let rightDate = getDateFromPointAtBrowserCanvas(canvas.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 recalculateScale () {
try {
if (coordinateSystem.maxValue > 0) { return } // Already calculated.
/* First we calculate the default scale */
let minValue = {
x: MIN_PLOTABLE_DATE.valueOf(),
y: 0
}
let maxValue = {
x: MAX_PLOTABLE_DATE.valueOf(),
y: nextPorwerOf10(MAX_DEFAULT_RATE_SCALE_VALUE) / 4 // TODO: This 4 is temporary
}
coordinateSystem.initialize(
minValue,
maxValue,
thisObject.container.frame.width,
thisObject.container.frame.height
)
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] recalculateScale -> err = ' + err.stack) }
}
}
function plotChart () {
try {
/* Clean the pannel at places where there is no record. */
let currentRecord = {
data: undefined
}
thisObject.container.eventHandler.raiseEvent('Current Record Changed', currentRecord)
for (let i = 0; i < records.length; i++) {
let record = records[i]
if (i == 0) {
record.previous = record
} 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 = transformThisPoint(beginPoint, thisObject.container)
endPoint = transformThisPoint(endPoint, thisObject.container)
beginPoint = canvas.chartingSpace.viewport.fitIntoVisibleArea(beginPoint)
endPoint = canvas.chartingSpace.viewport.fitIntoVisibleArea(endPoint)
beginPoint = thisObject.fitFunction(beginPoint)
endPoint = thisObject.fitFunction(endPoint)
if (endPoint.x < canvas.chartingSpace.viewport.visibleArea.bottomLeft.x || beginPoint.x > canvas.chartingSpace.viewport.visibleArea.bottomRight.x) {
continue
}
let atMousePosition = false
if (userPositionDate >= record.begin && userPositionDate <= record.end) {
atMousePosition = true
let currentRecord = {
data: record
}
thisObject.container.eventHandler.raiseEvent('Current Record Changed', currentRecord)
}
/* 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
}
/* Only calculate the datapoints for this record, if we have not calculate it before. */
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 dataPoint = {
x: x,
y: y
}
/* Contributing to Auto-Scale */
coordinateSystem.reportYValue(dataPoint.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.
*/
dataPoint = coordinateSystem.transformThisPoint(dataPoint)
dataPoint = transformThisPoint(dataPoint, thisObject.container)
dataPoint = canvas.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
/* Store the data point at the local map */
dataPoints.set(point.id, dataPoint)
if (plotterModuleConfig !== undefined) {
if (plotterModuleConfig.slot !== undefined) {
/* We reset the y coordinate since it will be transformed with another coordinate system to fit into a slot. */
dataPoint.y = (-1) * y * coordinateSystem.scale.y + (plotterModuleConfig.slot.number - 1) * slotHeight + canvas.chartingSpace.viewport.visibleArea.topLeft.y
}
}
}
}
}
/* Remember this datapoints, so that we do not need to calculate them again. */
record.dataPoints = dataPoints
}
for (let j = 0; j < productDefinition.referenceParent.shapes.polygons.length; j++) {
let polygon = productDefinition.referenceParent.shapes.polygons[j]
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.code !== undefined) {
if (polygon.polygonBody.style.code.default !== undefined) {
let bodyStyle = polygon.polygonBody.style.code.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.code
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.code.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBody.style.code.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.code !== undefined) {
if (polygon.polygonBorder.style.code.default !== undefined) {
let borderStyle = polygon.polygonBorder.style.code.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.code
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.code.atMousePosition !== undefined) {
let atMousePositionStyleDefinition = polygon.polygonBorder.style.code.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)
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 = canvas.chartingSpace.viewport.fitIntoVisibleArea(dataPoint)
dataPoint = thisObject.fitFunction(dataPoint)
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()
}
}
}
if (coordinateSystem.autoMinYScale === true || coordinateSystem.autosMaxScale === true) {
mustRecalculateDataPoints = true
} else {
mustRecalculateDataPoints = false
}
logged = false
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] plotChart -> 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 () {
try {
recalculate()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] onDragFinished -> err = ' + err.stack) }
}
}
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()
}
}
}
+82
View File
@@ -0,0 +1,82 @@
let canvas
let markets
let ecosystem = newEcosystem()
let systemEventHandler
let APP_SCHEMA_MAP = new Map()
let APP_SCHEMA_ARRAY = []
function newDashboard () {
const MODULE_NAME = 'Dashboard'
const ERROR_LOG = true
const INTENSIVE_LOG = false
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
start: start
}
const DEBUG_START_UP_DELAY = 0 // 3000; // This is a waiting time in case there is a need to debug the very first steps of initialization, to be able to hit F12 on time.
return thisObject
function start () {
try {
setBrowserEvents()
systemEventHandler = newSystemEventHandler()
systemEventHandler.initialize(setUpAppSchema)
function setUpAppSchema () {
APP_SCHEMA_ARRAY = getAppSchema()
for (let i = 0; i < APP_SCHEMA_ARRAY.length; i++) {
let nodeDefinition = APP_SCHEMA_ARRAY[i]
let key = nodeDefinition.type
APP_SCHEMA_MAP.set(key, nodeDefinition)
}
startCanvas()
}
function startCanvas () {
/* If this method is executed for a second time, it should finalize the current execution structure */
if (canvas !== undefined) { canvas.finalize() }
setTimeout(delayedStart, DEBUG_START_UP_DELAY)
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] start -> err = ' + err.stack) }
}
}
function delayedStart () {
try {
/* For now, we are supporting only one market. */
let market = {
id: 2,
baseAsset: 'USDT',
quotedAsset: 'BTC'
}
markets = new Map()
markets.set(market.id, market)
canvas = newCanvas()
canvas.initialize()
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] delayedStart -> err = ' + err.stack) }
}
}
function setBrowserEvents () {
window.onbeforeunload = onBrowserClosed
function onBrowserClosed () {
// canvas.designSpace.workspace.stopAllRunningTasks()
}
}
}
+333
View File
@@ -0,0 +1,333 @@

function newProductStorage (name) {
const MODULE_NAME = 'Product Storage'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
/*
This object will initialize children objects that will end up loading the data of each set defined at each product of the bot received at initialization.
Once all the underlaying objects are fully initialized it will callback.
At the same time it will raise an event for each underlaying file being loaded, so that the UI can reflect the progress to the end user.
Product Storage
|
|-----> SingleFile
|
|-----> FileSequence
|
|-----> DailyFiles -----> FileCursor
|
|-----> MarketFiles
*/
let thisObject = {
eventHandler: undefined,
marketFiles: [],
dailyFiles: [],
singleFile: [],
fileSequences: [],
setDatetime: setDatetime,
setTimeFrame: setTimeFrame,
initialize: initialize,
finalize: finalize
}
thisObject.eventHandler = newEventHandler()
/* We name the event Handler to easy debugging. */
thisObject.eventHandler.name = 'Storage-' + name
let datetime
let timeFrame
return thisObject
function finalize () {
try {
for (let i = 0; i < thisObject.marketFiles.length; i++) {
let marketFile = thisObject.marketFiles[i]
marketFile.finalize()
}
thisObject.marketFiles = undefined
for (let i = 0; i < thisObject.dailyFiles.length; i++) {
let dailyFile = thisObject.dailyFiles[i]
dailyFile.finalize()
}
thisObject.dailyFiles = undefined
for (let i = 0; i < thisObject.fileSequences.length; i++) {
let fileSequence = thisObject.fileSequences[i]
fileSequence.finalize()
}
thisObject.fileSequences = undefined
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) }
}
}
function initialize (dataMine, bot, session, product, exchange, market, pDatetime, pTimeFrame, callBackFunction) {
try {
datetime = pDatetime
timeFrame = pTimeFrame
let dataSetsToLoad = 0
let dataSetsLoaded = 0
for (let i = 0; i < product.datasets.length; i++) {
let dataset = product.datasets[i]
switch (dataset.code.type) {
case 'Market Files': {
dataSetsToLoad++
let marketFiles = newMarketFiles()
marketFiles.initialize(dataMine, bot, session, product, dataset, exchange, market, onMarketFileReady)
thisObject.marketFiles.push(marketFiles)
}
break
case 'Daily Files': {
dataSetsToLoad++
let dailyFiles = newDailyFiles()
dailyFiles.initialize(dataMine, bot, session, product, dataset, exchange, market, pDatetime, pTimeFrame, onDailyFileReady)
thisObject.dailyFiles.push(dailyFiles)
}
break
case 'Single File': {
dataSetsToLoad++
let singleFile = newSingleFile()
singleFile.initialize(dataMine, bot, session, product, dataset, exchange, market, onSingleFileReady)
thisObject.singleFile.push(singleFile)
}
break
case 'File Sequence': {
dataSetsToLoad++
let fileSequences = newFileSequence()
fileSequences.initialize(dataMine, bot, session, product, dataset, exchange, market, onFileSequenceReady)
thisObject.fileSequences.push(fileSequences)
}
break
default:
if (ERROR_LOG === true) { logger.write('[WARN] initialize -> dataset with no type defined or type not supported -> dataset.code.type = ' + dataset.code.type) }
}
function onMarketFileReady (err, pCaller) {
try {
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
break
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
}
let event = {
totalValue: pCaller.getExpectedFiles(),
currentValue: pCaller.getFilesLoaded(),
filesNotLoaded: pCaller.getFilesNotLoaded()
}
thisObject.eventHandler.raiseEvent('Market File Loaded', event)
if (event.filesNotLoaded === event.totalValue) {
dataSetsToLoad--
checkInitializeComplete()
return
}
if (event.currentValue + event.filesNotLoaded === event.totalValue) {
dataSetsLoaded++
checkInitializeComplete()
}
} catch (err) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
function onDailyFileReady (err, pCaller) {
try {
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
break
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
if (err.message === 'Dataset Unavailable.') {
dataSetsToLoad--
checkInitializeComplete()
return
} else {
callBackFunction(err)
return
}
}
default: {
callBackFunction(err)
return
}
}
let event = {
totalValue: pCaller.getExpectedFiles(),
currentValue: pCaller.getFilesLoaded()
}
thisObject.eventHandler.raiseEvent('Daily File Loaded', event)
if (event.currentValue === event.totalValue) {
dataSetsLoaded++
checkInitializeComplete()
}
} catch (err) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
function onSingleFileReady (err, pCaller) {
try {
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
break
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
callBackFunction(err)
return
}
default: {
callBackFunction(err)
return
}
}
let event = {
totalValue: 1,
currentValue: 1
}
thisObject.eventHandler.raiseEvent('Single File Loaded', event)
if (event.currentValue === event.totalValue) {
dataSetsLoaded++
checkInitializeComplete()
}
} catch (err) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
function onFileSequenceReady (err, pCaller) {
try {
switch (err.result) {
case GLOBAL.DEFAULT_OK_RESPONSE.result: {
break
}
case GLOBAL.DEFAULT_FAIL_RESPONSE.result: {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
case GLOBAL.CUSTOM_FAIL_RESPONSE.result: {
callBackFunction(err)
return
}
default: {
callBackFunction(err)
return
}
}
let event
if (pCaller !== undefined) {
event = {
totalValue: pCaller.getExpectedFiles(),
currentValue: pCaller.getFilesLoaded()
}
} else { // When there are no data the reference to the caller wont arrive here.
event = {
totalValue: 1,
currentValue: 1
}
}
thisObject.eventHandler.raiseEvent('File Sequence Loaded', event)
if (event.currentValue === event.totalValue) {
dataSetsLoaded++
checkInitializeComplete()
}
} catch (err) {
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
function checkInitializeComplete () {
try {
if (dataSetsLoaded === dataSetsToLoad) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE)
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> checkInitializeComplete -> err = ' + err.stack) }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) }
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
}
}
function setDatetime (pDatetime) {
/* If there is a change in the day, then we take some actions, otherwise, we dont. */
let currentDate = Math.trunc(datetime.valueOf() / ONE_DAY_IN_MILISECONDS)
let newDate = Math.trunc(pDatetime.valueOf() / ONE_DAY_IN_MILISECONDS)
datetime = new Date(pDatetime)
if (currentDate !== newDate) {
if (timeFrame <= _1_HOUR_IN_MILISECONDS) {
for (let i = 0; i < thisObject.dailyFiles.length; i++) {
thisObject.dailyFiles[i].setDatetime(pDatetime)
}
}
}
}
function setTimeFrame (pTimeFrame) {
/* We are going to filter out the cases in which the timeFrame received is the same that the one we already know. */
if (timeFrame !== pTimeFrame) {
timeFrame = pTimeFrame
if (timeFrame <= _1_HOUR_IN_MILISECONDS) {
for (let i = 0; i < thisObject.dailyFiles.length; i++) {
thisObject.dailyFiles[i].setTimeFrame(pTimeFrame, datetime)
}
}
}
}
}
+194
View File
@@ -0,0 +1,194 @@
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 = 3
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === true) {
currentStatus = 4
}
}
function onMouseWheel (event) {
let factor
let delta = event.wheelDelta
if (delta < 0) {
delta = -1
} else {
delta = 1
}
currentStatus = currentStatus + delta
if (currentStatus === 5) { currentStatus = 1 }
if (currentStatus === 0) { currentStatus = 4 }
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 = true
update()
return
}
case 4: {
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 = canvas.designSpace.iconCollection.get('toggle-auto-time-scale-manual')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === false) {
icon = canvas.designSpace.iconCollection.get('toggle-auto-time-scale-auto-min')
}
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === true) {
icon = canvas.designSpace.iconCollection.get('toggle-auto-time-scale-auto-max')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === true) {
icon = canvas.designSpace.iconCollection.get('toggle-auto-time-scale-auto-min-max')
}
drawIcon(icon, 0, 0, 0, 0, ICON_SIZE, thisObject.container)
break
}
case 'Y': {
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === false) {
icon = canvas.designSpace.iconCollection.get('toggle-auto-scale-manual')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === false) {
icon = canvas.designSpace.iconCollection.get('toggle-auto-scale-auto-min')
}
if (thisObject.autoMinScale === false && thisObject.autoMaxScale === true) {
icon = canvas.designSpace.iconCollection.get('toggle-auto-scale-auto-max')
}
if (thisObject.autoMinScale === true && thisObject.autoMaxScale === true) {
icon = canvas.designSpace.iconCollection.get('toggle-auto-scale-auto-min-max')
}
drawIcon(icon, 0, 0, 0, 0, ICON_SIZE, thisObject.container)
break
}
}
}
}
+45
View File
@@ -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
}
roundedCornersBackground(params)
/* Place the Text */
label1 = label1.substring(0, 18)
label2 = label2.substring(0, 20)
label3 = label3.substring(0, 20)
drawLabel(label1, 1 / 2, 92 / 100, 0, 0, 9, container)
drawLabel(label2, 1 / 2, 42 / 100, 0, 0, 17, container)
drawLabel(label3, 1 / 2, 67 / 100, 0, 0, 9, container)
drawIcon(icon1, 1 / 8, 1 / 2, 0, 0, 28, container)
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'
}
roundedCornersBackground(params)
}
+423
View File
@@ -0,0 +1,423 @@
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,
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 coordinateSystem
let limitingContainer
let rateCalculationsContainer
let mouse = {
position: {
x: 0,
y: 0
}
}
let scaleDisplayTimer = 0
let autoScaleButton
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
rateCalculationsContainer = undefined
mouse = 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)
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
}
}
mouse = {
position: {
x: event.x,
y: event.y
}
}
}
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 (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 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 code = JSON.parse(thisObject.payload.node.code)
code.minValue = coordinateSystem.min.y
code.maxValue = coordinateSystem.max.y
code.autoMinScale = coordinateSystem.autoMinYScale
code.autoMaxScale = coordinateSystem.autoMaxYScale
thisObject.payload.node.code = JSON.stringify(code, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function readObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
if (
(isNaN(code.minValue) || code.minValue === null || code.minValue === undefined) ||
(isNaN(code.maxValue) || code.maxValue === null || code.maxValue === undefined)
) {
// not using this value
} else {
if (
thisObject.minValue !== code.minValue ||
thisObject.maxValue !== code.maxValue ||
coordinateSystem.autoMinYScale !== code.autoMinScale ||
coordinateSystem.autoMaxYScale !== code.autoMaxScale
) {
thisObject.minValue = code.minValue
thisObject.maxValue = code.maxValue
coordinateSystem.min.y = thisObject.minValue
coordinateSystem.max.y = thisObject.maxValue
if (code.autoMinScale !== undefined && (code.autoMinScale === true || code.autoMinScale === false) && code.autoMaxScale !== undefined && (code.autoMaxScale === true || code.autoMaxScale === false)) {
coordinateSystem.autoMinYScale = code.autoMinScale
coordinateSystem.autoMaxYScale = code.autoMaxScale
autoScaleButton.setStatus(code.autoMinScale, code.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 (draggeableContainer.frame.position.y === 0) { return }
let dragVector = {
x: draggeableContainer.frame.position.x,
y: draggeableContainer.frame.position.y
}
draggeableContainer.frame.position.x = 0
draggeableContainer.frame.position.y = 0
let point = {
x: 0,
y: -dragVector.y
}
let newMaxRate = getRateFromPointAtContainer(point, limitingContainer, coordinateSystem)
let yDifferenceMaxMin = coordinateSystem.max.y - coordinateSystem.min.y
coordinateSystem.min.y = newMaxRate - yDifferenceMaxMin
coordinateSystem.max.y = newMaxRate
coordinateSystem.recalculateScale()
}
function onUpstreamScaleChanged (event) {
if (event === undefined) { return }
if (event.type === 'center dragged') {
let point = {
x: event.dragVector.x,
y: -event.dragVector.y
}
let newMinDate = getDateFromPointAtContainer(point, rateCalculationsContainer, coordinateSystem)
let newMaxRate = getRateFromPointAtContainer(point, rateCalculationsContainer, coordinateSystem)
let xDifferenceMaxMin = coordinateSystem.max.x - coordinateSystem.min.x
let yDifferenceMaxMin = coordinateSystem.max.y - coordinateSystem.min.y
coordinateSystem.min.x = newMinDate.valueOf()
coordinateSystem.max.x = newMinDate.valueOf() + xDifferenceMaxMin
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 = 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 = 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 = transformThisPoint(upCorner, limitingContainer)
bottonCorner = 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: mouse.position.y
}
thisObject.rate = getRateFromPointAtBrowserCanvas(ratePoint, rateCalculationsContainer, coordinateSystem)
/* rateScale Positioning */
ratePoint = {
x: limitingContainer.frame.width,
y: 0
}
ratePoint = transformThisPoint(ratePoint, limitingContainer.frame.container)
ratePoint.y = 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
}
}
function draw () {
drawScaleBox()
autoScaleButton.draw()
if (visible === false) {
drawScaleDisplayCover(thisObject.container)
}
}
function drawForeground () {
if (isMouseOver === true) {
drawScaleBox()
autoScaleButton.draw()
}
}
function drawScaleBox () {
if (thisObject.rate === undefined) { return }
if (thisObject.payload === undefined) { return }
if (thisObject.payload.node === undefined) { return }
let rate = thisObject.rate
if (rate < coordinateSystem.min.y) {
rate = coordinateSystem.min.y
}
if (rate > coordinateSystem.max.y) {
rate = coordinateSystem.max.y
}
let label = (rate - Math.trunc(rate)).toFixed(2)
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' }
let icon1 = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.payload.parentNode.type)
let icon2 = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
let backgroundColor = UI_COLOR.BLACK
if (scaleDisplayTimer > 0) {
label2 = (coordinateSystem.scale.y * 10000).toFixed(2)
label3 = 'SCALE'
}
drawScaleDisplay(label1, label2, label3, 0, 0, 0, icon1, icon2, thisObject.container, backgroundColor)
}
}
+350
View File
@@ -0,0 +1,350 @@
function newTimeFrameScale () {
const MODULE_NAME = 'Time Frame Scale'
let thisObject = {
timeFrame: undefined,
container: undefined,
fitFunction: undefined,
payload: undefined,
isVisible: true,
layersOn: undefined,
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
const MIN_HEIGHT = 50
let previousIsVisible = 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
let mouse = {
position: {
x: 0,
y: 0
}
}
setupContainer()
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)
canvas.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
mouse = undefined
}
function initialize (pLimitingContainer) {
limitingContainer = pLimitingContainer
readObjectState()
newTimeFrame()
onMouseWheelEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
onViewportZoomChangedEventSubscriptionId = canvas.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
}
}
mouse = {
position: {
x: event.x,
y: event.y
}
}
}
function onMouseOver (event) {
isMouseOver = true
event.containerId = thisObject.container.id
thisObject.container.eventHandler.raiseEvent('onMouseOverScale', event)
}
function onMouseNotOver () {
isMouseOver = false
}
function physics () {
readObjectState()
positioningPhysics()
zoomOutPhysics()
}
function zoomOutPhysics () {
if ((thisObject.isVisible === true && previousIsVisible === false) && (canvas.chartingSpace.viewport.zoomTargetLevel >= ZOOM_OUT_THRESHOLD_FOR_CHANGING_TIME_FRAME)) {
let event = {}
event.timeFrame = thisObject.timeFrame
thisObject.container.eventHandler.raiseEvent('Time Frame Value Changed', event)
previousIsVisible = true
}
if ((thisObject.isVisible === false && previousIsVisible === true) || (canvas.chartingSpace.viewport.zoomTargetLevel < ZOOM_OUT_THRESHOLD_FOR_CHANGING_TIME_FRAME)) {
let event = {}
event.timeFrame = ONE_DAY_IN_MILISECONDS
thisObject.container.eventHandler.raiseEvent('Time Frame Value Changed', event)
previousIsVisible = false
}
}
function positioningPhysics () {
/* Container Limits */
let upCorner = {
x: 0,
y: 0
}
let bottonCorner = {
x: limitingContainer.frame.width,
y: limitingContainer.frame.height
}
upCorner = transformThisPoint(upCorner, limitingContainer)
bottonCorner = 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 = transformThisPoint(timePoint, limitingContainer.frame.container)
timePoint.x = 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
}
}
function onViewportZoomChanged (event) {
if (event !== undefined) { // it is undefined when the level is just being animated.
if (event.shiftKey === false) { 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) {
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 code = JSON.parse(thisObject.payload.node.code)
code.value = timeFrameLabel
thisObject.payload.node.code = JSON.stringify(code)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function readObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
if (code.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 (code.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 = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.payload.parentNode.type)
let icon2 = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
let backgroundColor = UI_COLOR.BLACK
drawScaleDisplay(label1, label2, label3, 0, 0, 0, icon1, icon2, thisObject.container, backgroundColor)
}
}
+281
View File
@@ -0,0 +1,281 @@
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,
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 mouse = {
position: {
x: 0,
y: 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
mouse = 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
}
}
mouse = {
position: {
x: event.x,
y: event.y
}
}
}
function onMouseOver (event) {
isMouseOver = true
event.containerId = thisObject.container.id
thisObject.container.eventHandler.raiseEvent('onMouseOverScale', event)
}
function onMouseNotOver () {
isMouseOver = false
}
function onMouseWheel (event) {
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 code = JSON.parse(thisObject.payload.node.code)
code.fromDate = (new Date(coordinateSystem.min.x)).toISOString()
code.toDate = (new Date(coordinateSystem.max.x)).toISOString()
code.autoMinScale = coordinateSystem.autoMinXScale
code.autoMaxScale = coordinateSystem.autoMaxXScale
thisObject.payload.node.code = JSON.stringify(code, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function readObjectState () {
try {
let code = JSON.parse(thisObject.payload.node.code)
if (
(isNaN(Date.parse(code.fromDate)) || code.fromDate === null || code.fromDate === undefined) ||
(isNaN(Date.parse(code.toDate)) || code.toDate === null || code.toDate === undefined)
) {
// not using this value
} else {
if (thisObject.fromDate !== Date.parse(code.fromDate) || thisObject.toDate !== Date.parse(code.toDate)) {
thisObject.fromDate = Date.parse(code.fromDate)
thisObject.toDate = Date.parse(code.toDate)
coordinateSystem.min.x = thisObject.fromDate
coordinateSystem.max.x = thisObject.toDate
if (code.autoMinScale !== undefined && (code.autoMinScale === true || code.autoMinScale === false) && code.autoMaxScale !== undefined && (code.autoMaxScale === true || code.autoMaxScale === false)) {
coordinateSystem.autoMinXScale = code.autoMinScale
coordinateSystem.autoMaxXScale = code.autoMaxScale
autoScaleButton.setStatus(code.autoMinScale, code.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 = transformThisPoint(upCorner, limitingContainer)
bottonCorner = transformThisPoint(bottonCorner, limitingContainer)
upCorner = limitingContainer.fitFunction(upCorner, true)
bottonCorner = limitingContainer.fitFunction(bottonCorner, true)
/* Mouse Position Date Calculation */
let timePoint = {
x: mouse.position.x,
y: 0
}
let mouseDate = getDateFromPointAtBrowserCanvas(timePoint, limitingContainer, coordinateSystem)
thisObject.date = new Date(mouseDate)
/* timeScale Positioning */
timePoint = {
x: 0,
y: 0
}
timePoint = transformThisPoint(timePoint, limitingContainer.frame.container)
timePoint.x = 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
}
}
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 label = thisObject.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]
let icon1 = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.payload.parentNode.type)
let icon2 = canvas.designSpace.iconByUiObjectType.get(thisObject.payload.node.type)
let backgroundColor = UI_COLOR.BLACK
drawScaleDisplay(label1, label2, label3, 0, 0, 0, icon1, icon2, thisObject.container, backgroundColor)
}
}
+403
View File
@@ -0,0 +1,403 @@
/*
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 newChartingSpace () {
const MODULE_NAME = 'Charting Space'
const ERROR_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
visible: undefined,
container: undefined,
inViewport: undefined,
timeMachines: undefined,
viewport: undefined,
payload: undefined,
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()
return thisObject
function reset () {
finalize()
initialSetup()
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
thisObject.viewport.finalize()
thisObject.viewport = undefined
thisObject.payload = undefined
}
function initialize () {
let rootNodes = canvas.designSpace.workspace.workspaceNode.rootNodes
for (let i = 0; i < rootNodes.length; i++) {
let rootNode = rootNodes[i]
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)
}
function getContainer (point, purpose) {
if (thisObject.visible !== true) { 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) {
containerFound = container
} else {
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
containerFound = container
}
}
}
}
if (containerFound !== undefined) {
containerFound.space = 'Charting Space'
return containerFound
}
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
thisObject.container.space = 'Charting Space'
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 () {
let displaceVector = {
x: 0,
y: browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
canvas.chartingSpace.viewport.displace(displaceVector)
}
function oneScreenDown () {
let displaceVector = {
x: 0,
y: -browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
canvas.chartingSpace.viewport.displace(displaceVector)
}
function oneScreenLeft () {
let displaceVector = {
x: browserCanvas.width * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100,
y: 0
}
canvas.chartingSpace.viewport.displace(displaceVector, true)
}
function oneScreenRight () {
let displaceVector = {
x: -browserCanvas.width * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100,
y: 0
}
canvas.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 () {
if (thisObject.viewport !== undefined) {
thisObject.viewport.physics()
}
thisObjectPhysics()
childrenPhysics()
syncWithDesigner()
}
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.container.frame.position.x = browserCanvas.width / 2 - TIME_MACHINE_WIDTH / 2
timeMachine.container.frame.position.y = browserCanvas.height / 2 - TIME_MACHINE_HEIGHT / 2
timeMachine.initialize(onTimeMachineInitialized)
function onTimeMachineInitialized () {
thisObject.timeMachines.push(timeMachine)
timeMachine.payload.uiObject.setValue('')
if (canvas.chartingSpace.viewport !== undefined) {
canvas.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 <= 0 / 100) {
thisObject.visible = false
} else {
thisObject.visible = true
}
if (canvas.chartingSpace.viewport !== undefined) {
canvas.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 () {
drawSpaceBackground()
for (let i = 0; i < thisObject.timeMachines.length; i++) {
let timeMachine = thisObject.timeMachines[thisObject.timeMachines.length - i - 1]
timeMachine.drawBackground()
}
}
function draw () {
if (thisObject.visible !== true) { 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()
}
}
+314
View File
@@ -0,0 +1,314 @@
function newCockpitSpace () {
const MODULE_NAME = 'CockpitSpace'
let thisObject = {
container: undefined,
status: 'BOTTOM',
assetBalances: undefined,
fullscreen: undefined,
toTop: toTop,
toBottom: toBottom,
toMiddle: toMiddle,
moveUp: moveUp,
moveDown: moveDown,
draw: draw,
physics: physics,
getContainer: getContainer,
finalize: finalize,
initialize: initialize
}
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
return thisObject
function finalize () {
thisObject.container.eventHandler.stopListening(selfMouseClickEventSubscriptionId)
thisObject.container.eventHandler.stopListening(canvasBrowserResizedEventSubscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.assetBalances = undefined
thisObject.fullscreen = undefined
}
function initialize () {
thisObject.container.frame.position.x = 0
let INITIAL_POSITION
if (canvas.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 = 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
}
canvasBrowserResizedEventSubscriptionId = canvas.eventHandler.listenToEvent('Browser Resized', resize)
selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick)
thisObject.assetBalances = newQuotedAssetalances()
thisObject.assetBalances.initialize()
thisObject.fullscreen = newFullScreen()
thisObject.fullscreen.container.connectToParent(thisObject.container)
thisObject.fullscreen.initialize()
}
function onMouseClick (event) {
}
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 = COCKPIT_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 physics () {
thisObjectPhysics()
childrenPhysics()
}
function childrenPhysics () {
thisObject.fullscreen.physics()
}
function thisObjectPhysics () {
/* Check the limits */
thisObject.status = 'MIDDLE'
if (canvas.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'
canvas.designSpace.makeInvisible()
canvas.floatingSpace.makeInvisible()
} else {
canvas.designSpace.makeVisible()
canvas.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'
canvas.panelsSpace.visible = false
} else {
canvas.panelsSpace.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 (canvas.chartingSpace.viewport !== undefined) {
canvas.chartingSpace.viewport.resize()
}
}
function getContainer (point) {
let container
// container = thisObject.fullscreen.getContainer(point)
// if (container !== undefined) { return container }
if (thisObject.container.frame.isThisPointHere(point, true) === true) {
thisObject.container.space = 'Cockpit Space'
return thisObject.container
} else {
return undefined
}
}
function draw () {
thisObject.container.frame.draw(false, false)
drawBackground()
thisObject.assetBalances.draw()
// 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)
browserCanvasContext.beginPath()
browserCanvasContext.rect(zeroPoint.x, zeroPoint.y, thisObject.container.frame.width, thisObject.container.frame.height)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK_TURQUOISE + ', ' + 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 (canvas.designSpace.workspace.enabled === true) {
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()
}
}
+324
View File
@@ -0,0 +1,324 @@
function newDesignSpace () {
const MODULE_NAME = 'Strategy Space'
let thisObject = {
sidePanel: undefined,
container: undefined,
iconCollection: undefined,
iconByUiObjectType: undefined,
workspace: undefined,
physics: physics,
draw: draw,
getContainer: getContainer,
makeVisible: makeVisible,
makeInvisible: makeInvisible,
initialize: initialize
}
let container = newContainer()
container.initialize()
thisObject.container = container
container.isDraggeable = false
thisObject.iconCollection = new Map()
thisObject.iconByUiObjectType = new Map()
return thisObject
function initialize () {
loadIconCollection()
buildIconByUiObjectTypeMap()
thisObject.workspace = newWorkspace()
thisObject.workspace.initialize()
}
function buildIconByUiObjectTypeMap () {
/* Take types-icons relationships defined at the schema */
for (let i = 0; i < APP_SCHEMA_ARRAY.length; i++) {
let nodeDefinition = APP_SCHEMA_ARRAY[i]
let iconName = nodeDefinition.icon
if (iconName !== undefined) {
let icon = thisObject.iconCollection.get(iconName)
thisObject.iconByUiObjectType.set(nodeDefinition.type, icon)
}
}
}
function loadIconCollection () {
const iconsNames = [
'analysis',
'analysis-1',
'approve',
'attach',
'attractive',
'pyramid',
'brainstorming',
'broken-link',
'chat',
'chronometer',
'compass',
'competition',
'content',
'design-tool',
'grid',
'headphones',
'html',
'image',
'layout',
'loading',
'login',
'pantone',
'paper-plane',
'photo-camera',
'piggy-bank',
'pipette',
'pixel',
'placeholder',
'planning',
'promotion',
'pyramid',
'quality',
'responsive',
'schedule',
'search',
'security',
'settings',
'sitemap',
'startup',
'support',
'tap',
'menu-fix-pinned',
'menu-fix-unpinned',
'targeting',
'task',
'testing',
'text',
'timeline',
'tools',
'delete',
'upload',
'vector',
'video-player',
'menu-mobility-freeze',
'menu-mobility-unfreeze',
'menu-tree-minus',
'menu-tree-plus',
'menu-backup',
'menu-share',
'stop',
'stage-open',
'stage-close',
'stage-trigger',
'stage-trigger-trigger-on',
'stage-trigger-trigger-off',
'stage-trigger-take-position',
'menu-tensor-fixed-angles',
'menu-tensor-free-angles',
'stage-open-position-size',
'stage-open-take-profit',
'stage-open-postion-rate',
'session-live-trading',
'session-paper-trading',
'session-backtesting',
'session-forward-testing',
'network',
'network-node',
'bot-trading',
'layer-manager',
'process',
'bot-indicator',
'bot-sensor',
'time-period',
'data-mine',
'procedure-loop',
'calculations-procedure',
'data-building-procedure',
'procedure-initialization',
'process-definition',
'output-dataset',
'data-dependency',
'product-definition',
'plotter-module',
'status-dependency',
'record-property',
'record-definition',
'plotter',
'plotter-panel',
'dataset-definition',
'status-report',
'execution-finished-event',
'process-dependencies',
'process-output',
'social-bot',
'execution-started-event',
'shapes',
'chart-point',
'style',
'chart-points',
'shapes-polygon-vertex',
'shapes-polygon-border',
'shapes-polygon-body',
'chart-point-formula',
'style-condition',
'shapes-polygon',
'data-entry',
'data-formula',
'clone',
'exchange-account-asset',
'exchange-account-key',
'user-keys',
'user-assets',
'asset',
'exchange-accounts',
'user-account',
'market',
'exchange-assets',
'crypto-exchanges',
'crypto-exchange',
'exchange-markets',
'charting-space',
'time-line-chart',
'time-frame-scale',
'time-scale',
'rate-scale',
'time-machine',
'data-product',
'single-market-data',
'data-storage',
'dataset',
'viewport',
'bitfinex',
'binance',
'kucoin',
'bittrex',
'kraken',
'poloniex',
'upbit',
'monero',
'tether',
'tron',
'stellar',
'qtum',
'neo',
'litecoin',
'ethereum-classic',
'ethereum',
'eos',
'dash',
'cardano',
'bitcoin-cash',
'bitcoin',
'binance-coin',
'trend',
'oscillator',
'moving-average',
'histogram',
'band',
'volume',
'candles',
'bitmex',
'liquid',
'hitbtc',
'us-dollar',
'distance-to-parent-200',
'distance-to-parent-150',
'distance-to-parent-100',
'distance-to-parent-050',
'distance-to-parent-025',
'distance-to-parent-000',
'angle-to-parent-360',
'angle-to-parent-180',
'angle-to-parent-090',
'angle-to-parent-045',
'angle-to-parent-000',
'data-mining',
'initial-definition',
'next-phase-event',
'testing-environment',
'production-environment',
'task-manager',
'session-based-data',
'session-independent-data',
'session-reference',
'dashboard',
'toggle-auto-scale-manual',
'toggle-auto-scale-auto-min-max',
'toggle-auto-scale-auto-max',
'toggle-auto-scale-auto-min',
'toggle-panel-off',
'toggle-auto-time-scale-auto-min',
'toggle-auto-time-scale-auto-max',
'toggle-auto-time-scale-auto-min-max',
'toggle-auto-time-scale-manual',
'mouse-pointer',
'mouse-left-click',
'mouse-right-click',
'mouse-wheel-up',
'mouse-wheel-down',
'mouse-wheel-click',
'key-alt',
'key-shift',
'key-ctrl',
'hand-drag',
'key-down',
'key-left',
'key-right',
'key-up'
]
for (let i = 0; i < iconsNames.length; i++) {
let name = iconsNames[i]
loadImage(name)
}
function loadImage (name) {
const PATH = 'Images/Icons/style-01/'
let image = new Image()
image.onload = onImageLoad
image.fileName = name
function onImageLoad () {
image.canDrawIcon = true
}
image.src = window.canvasApp.urlPrefix + PATH + name + '.png'
thisObject.iconCollection.set(name, image)
}
}
function physics () {
thisObject.workspace.physics()
}
function makeVisible () {
visible = true
}
function makeInvisible () {
visible = false
}
function getContainer (point) {
let container
if (thisObject.sidePanel !== undefined) {
container = thisObject.sidePanel.getContainer(point)
if (container !== undefined) {
container.space = 'Design Space'
return container
}
}
return
}
function draw () {
if (thisObject.sidePanel !== undefined) {
thisObject.sidePanel.draw()
}
if (thisObject.workspace !== undefined) {
thisObject.workspace.draw()
}
}
}
+283
View File
@@ -0,0 +1,283 @@
function newFloatingSpace () {
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,
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.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
const PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT = 25
let eventSubscriptionId
return thisObject
function finalize () {
thisObject.container.eventHandler.stopListening(eventSubscriptionId)
thisObject.floatingLayer.finalize()
thisObject.uiObjectConstructor.finalize()
thisObject.container.finalize()
thisObject.floatingLayer = undefined
thisObject.uiObjectConstructor = undefined
thisObject.container = undefined
}
function initialize (callBackFunction) {
thisObject.floatingLayer = newFloatingLayer()
thisObject.floatingLayer.initialize()
thisObject.uiObjectConstructor = newUiObjectConstructor()
thisObject.uiObjectConstructor.initialize(thisObject.floatingLayer)
eventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel)
}
function isItFar (payload, dontCheckParent) {
/* If for any reason the paylaod is undefined we return false */
if (payload === undefined) { 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'
) {
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 () {
let displaceVector = {
x: 0,
y: browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
thisObject.container.displace(displaceVector)
return displaceVector
}
function oneScreenDown () {
let displaceVector = {
x: 0,
y: -browserCanvas.height * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100
}
thisObject.container.displace(displaceVector)
return displaceVector
}
function oneScreenLeft () {
let displaceVector = {
x: browserCanvas.width * PERCENTAGE_OF_SCREEN_FOR_DISPLACEMENT / 100,
y: 0
}
thisObject.container.displace(displaceVector)
return displaceVector
}
function oneScreenRight () {
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 onMouseWheel (event) {
thisObject.floatingLayer.changeTargetRepulsion(event.wheelDelta)
}
function makeVisible () {
visible = true
}
function makeInvisible () {
visible = false
}
function getContainer (point) {
let 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 === true) {
browserZoomPhysics()
thisObject.floatingLayer.physics()
}
}
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 (visible === true) {
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(' + UI_COLOR.BLACK + ', 1)'
browserCanvasContext.closePath()
browserCanvasContext.fill()
}
}
+353
View File
@@ -0,0 +1,353 @@
/*
The Panel Space y the place wehre all panels live, no matter who create them.
*/
function newPanelsSpace () {
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 = canvas.chartingSpace.fitFunction
panel.container.isVisibleFunction = canvas.chartingSpace.isThisPointVisible
panel.type = 'Layers Panel'
break
}
case 'Plotter Panel':
{
if (pParameters.panelNode.code.isLegacy !== true) {
panel = newPlotterPanel()
panel.fitFunction = canvas.chartingSpace.fitFunction
panel.container.isVisibleFunction = canvas.chartingSpace.isThisPointVisible
panel.session = pSession
panel.initialize(pParameters.panelNode)
} else {
panel = getNewPlotterPanel(pParameters.dataMine, pParameters.plotterCodeName, pParameters.moduleCodeName, pParameters.panelNode.code.codeName)
panel.fitFunction = canvas.chartingSpace.fitFunction
panel.container.isVisibleFunction = canvas.chartingSpace.isThisPointVisible
panel.session = pSession
panel.initialize()
}
panel.type = 'Plotter Panel'
break
}
}
panel.owner = pOwner
thisObject.panels.push(panel)
panel.handle = Math.floor((Math.random() * 10000000) + 1)
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 = canvas.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 = (canvas.chartingSpace.viewport.visibleArea.topRight.x - canvas.chartingSpace.viewport.visibleArea.topLeft.x) / 2 + canvas.chartingSpace.viewport.visibleArea.topLeft.x
let horizontalLine = (canvas.chartingSpace.viewport.visibleArea.bottomRight.y - canvas.chartingSpace.viewport.visibleArea.topRight.y) / 2 + canvas.chartingSpace.viewport.visibleArea.topRight.y
if (panel.panelTabButton !== undefined) {
if (panel.panelTabButton.status === 'up') {
if (centerPoint.x < verticalLine) {
panel.gravitatesTowards = 'topLeft'
} else {
panel.gravitatesTowards = 'topRight'
}
} 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
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 <= canvas.chartingSpace.viewport.visibleArea.bottomRight.y - canvas.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 < canvas.chartingSpace.viewport.visibleArea.topLeft.y) {
panel.container.frame.position.y = canvas.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 > canvas.chartingSpace.viewport.visibleArea.bottomRight.y) {
panel.container.frame.position.y = canvas.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.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 (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 = canvas.chartingSpace.inViewport.get(panel.owner)
if (owner !== undefined) {
if (panel.isVisible === true && panel.isHidden === false) {
panel.draw()
}
}
}
}
function getContainer (point) {
if (thisObject.visible !== true) { 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 = canvas.chartingSpace.inViewport.get(panel.owner)
if (owner !== undefined) {
if (panel.isVisible === true && panel.isHidden === false) {
container = panel.getContainer(point)
}
}
if (container !== undefined) {
container.space = 'Panels Space'
return container
}
}
thisObject.container.space = 'Panels Space'
return thisObject.container
}
}
+108
View File
@@ -0,0 +1,108 @@
function newTopSpace () {
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 = window.canvasApp.urlPrefix + 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 = canvas.chartingSpace.viewport.visibleArea.bottomLeft.y
} catch (e) { }
}
function getContainer (point) {
}
function draw () {
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 (areWeRecording === 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,
150,
TOP_SPACE_HEIGHT - 2)
}
}
}
}
+157
View File
@@ -0,0 +1,157 @@
/*
The Splash Screen is to show some 'loading...' controls while the app is being loaded on the background. After the loading is complete the Splash Screens dissapears for good.
*/
function newSplashScreen () {
let thisObject = {
container: undefined,
draw: draw,
timeMachines: [],
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize
}
var container = newContainer()
container.initialize()
thisObject.container = container
resize()
container.frame.containerName = 'Splash Screen'
container.frame.position.x = 0
container.frame.position.y = 0
container.isDraggeable = false
let fadeOutCounter = 0
let opacity = 1
let logo
let canDrawLogo = false
return thisObject
function initialize () {
logo = new Image()
logo.onload = onImageLoad
function onImageLoad () {
canDrawLogo = true
}
logo.src = window.canvasApp.urlPrefix + 'Images/superalgos-logo.png'
canvas.eventHandler.listenToEvent('Browser Resized', resize)
}
function resize () {
thisObject.container.frame.width = browserCanvas.width
thisObject.container.frame.height = browserCanvas.height
}
function draw () {
if (splashScreenNeeded === false) {
stepsInitializationCounter = 100
canDrawLogo = false
fadeOutCounter++
if (fadeOutCounter > 2) {
return
}
opacity = opacity - 1
}
thisObject.container.frame.draw(false, false)
/* Set the background. */
browserCanvasContext.beginPath()
browserCanvasContext.rect(0, 0, thisObject.container.frame.width, thisObject.container.frame.height)
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + opacity + ')'
browserCanvasContext.closePath()
browserCanvasContext.fill()
if (canDrawLogo === false) { return }
/* First the AA Logo. */
let imageHeight = 192 / 2
let imageWidth = 720 / 2
let yDisplacement = -60
let xDisplacement = -60
let imagePoint = {
x: thisObject.container.frame.width * 1 / 2 - imageWidth / 2 + xDisplacement,
y: thisObject.container.frame.height * 1 / 2 - imageHeight / 2 + yDisplacement
}
imagePoint = thisObject.container.frame.frameThisPoint(imagePoint)
browserCanvasContext.drawImage(logo, imagePoint.x, imagePoint.y, imageWidth, imageHeight)
/* Second the % of Advance. */
let label = '' + Math.trunc(stepsInitializationCounter) + ' %'
stepsInitializationCounter = stepsInitializationCounter + 5.0
if (stepsInitializationCounter > 99) {
splashScreenNeeded = false
stepsInitializationCounter = 99
}
let fontSize = 15
let labelPoint = {
x: thisObject.container.frame.width / 2 - label.length / 2 * fontSize * FONT_ASPECT_RATIO - 22,
y: thisObject.container.frame.height / 2 + fontSize / 2 + fontSize * 0.1 + 90 + yDisplacement
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(0, 0, 0, ' + opacity + ')'
browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y)
let title
let titlePoint
/* Algo Bots Competitions Sub Title */
fontSize = 35
title = 'Beta'
titlePoint = {
x: thisObject.container.frame.width / 2 - title.length / 2 * fontSize * FONT_ASPECT_RATIO - 20,
y: thisObject.container.frame.height / 2 + 70 + yDisplacement
}
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.font = 'Saira Condensed'
browserCanvasContext.fillStyle = 'rgba(0, 0, 0, ' + opacity + ')'
browserCanvasContext.fillText(title, titlePoint.x, titlePoint.y)
}
function getContainer (point) {
var container
/* First we check if this point is inside this space. */
if (thisObject.container.frame.isThisPointHere(point) === true) {
/* Now we see which is the inner most container that has it */
// add validation of inner most containers here.
/* The point does not belong to any inner container, so we return the current container. */
return thisObject.container
} else {
/* This point does not belong to this space. */
return undefined
}
}
}
+156
View File
@@ -0,0 +1,156 @@
function newSystemEventHandler () {
/* Web Sockets Connection */
const MODULE_NAME = 'System Event Handler'
const ERROR_LOG = true
const INFO_LOG = true
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
const WEB_SOCKETS_URL = 'ws://localhost:8080'
let WEB_SOCKETS_CONNECTION
let thisObject = {
initialize: initialize,
physics: physics,
createEventHandler: createEventHandler,
deleteEventHandler: deleteEventHandler,
listenToEvent: listenToEvent,
stopListening: stopListening,
raiseEvent: raiseEvent
}
let eventListeners = new Map()
let responseWaiters = new Map()
return thisObject
function initialize (callBackFunction) {
setuptWebSockets(callBackFunction)
}
function sendCommand (command, responseCallBack, eventsCallBack) {
if (command.action === 'listenToEvent') {
let key
if (command.callerId !== undefined) {
key = command.eventHandlerName + '-' + command.eventType + '-' + command.callerId
} else {
key = command.eventHandlerName + '-' + command.eventType
}
eventListeners.set(key, eventsCallBack)
}
if (command.callerId && responseCallBack) {
responseWaiters.set(command.callerId, responseCallBack)
}
WEB_SOCKETS_CONNECTION.send(JSON.stringify(command))
}
function createEventHandler (eventHandlerName, callerId, responseCallBack) {
let eventCommand = {
action: 'createEventHandler',
eventHandlerName: eventHandlerName,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
function deleteEventHandler (eventHandlerName, callerId, responseCallBack) {
let eventCommand = {
action: 'deleteEventHandler',
eventHandlerName: eventHandlerName,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
function listenToEvent (eventHandlerName, eventType, extraData, callerId, responseCallBack, eventsCallBack) {
let eventCommand = {
action: 'listenToEvent',
eventHandlerName: eventHandlerName,
eventType: eventType,
extraData: extraData,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack, eventsCallBack)
}
function stopListening (eventHandlerName, eventSubscriptionId, callerId, responseCallBack) {
let eventCommand = {
action: 'stopListening',
eventHandlerName: eventHandlerName,
eventSubscriptionId: eventSubscriptionId,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
function raiseEvent (eventHandlerName, eventType, event, callerId, responseCallBack) {
let eventCommand = {
action: 'raiseEvent',
eventHandlerName: eventHandlerName,
eventType: eventType,
event: event,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
function physics () {
if (WEB_SOCKETS_CONNECTION !== undefined) {
if (WEB_SOCKETS_CONNECTION.readyState === 3) { // Connection closed. May happen after computer goes to sleep.
setuptWebSockets(onOpen)
function onOpen () {
if (INFO_LOG === true) { logger.write('[INFO] setuptWebSockets -> Found Web Sockets Connection Closed. Reconnected to WebSockets Server.') }
}
}
}
}
function setuptWebSockets (callBackFunction) {
try {
WEB_SOCKETS_CONNECTION = new WebSocket(WEB_SOCKETS_URL)
WEB_SOCKETS_CONNECTION.onopen = () => {
console.log('Websocket connection opened.')
}
WEB_SOCKETS_CONNECTION.onerror = error => {
console.log('WebSocket error:' + JSON.stringify(error))
}
WEB_SOCKETS_CONNECTION.onopen = () => {
if (callBackFunction !== undefined) {
callBackFunction()
}
}
WEB_SOCKETS_CONNECTION.onmessage = e => {
// console.log('Websoked Message Received: ' + e.data)
let message = JSON.parse(e.data)
if (message.action === 'Event Raised') {
let key
if (message.callerId !== undefined) {
key = message.eventHandlerName + '-' + message.eventType + '-' + message.callerId
} else {
key = message.eventHandlerName + '-' + message.eventType
}
let handler = eventListeners.get(key)
if (handler) {
handler(message)
}
return
}
if (message.action === 'Event Server Response') {
let handler = responseWaiters.get(message.callerId)
if (handler) {
handler(message)
}
return
}
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] setuptWebSockets -> err = ' + err.stack) }
}
}
}
+247
View File
@@ -0,0 +1,247 @@
function drawContainerBackground (container, color, opacity, fitFunction) {
let fromPoint = {
x: 0,
y: 0
}
let toPoint = {
x: container.frame.width,
y: container.frame.height
}
fromPoint = transformThisPoint(fromPoint, container)
toPoint = 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 savePropertyAtNodeConfig (payload, propertyName, value) {
try {
let code = JSON.parse(payload.node.code)
code[propertyName] = value
payload.node.code = JSON.stringify(code, null, 4)
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
function loadPropertyFromNodeConfig (payload, propertyName) {
try {
let code = JSON.parse(payload.node.code)
return code[propertyName]
} catch (err) {
// we ignore errors here since most likely they will be parsing errors.
}
}
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
}
}
}
function convertTimeFrameToName (pTimeFrame) {
for (let i = 0; i < dailyFilePeriods.length; i++) {
let period = dailyFilePeriods[i]
if (period[0] === pTimeFrame) {
return period[1]
}
}
for (let i = 0; i < marketFilesPeriods.length; i++) {
let period = marketFilesPeriods[i]
if (period[0] === pTimeFrame) {
return period[1]
}
}
}
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) {
let data = browserCanvas.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 transformThisPoint (point, container) {
/* We make the point relative to the current frame */
point = container.frame.frameThisPoint(point)
/* We pass this point through the canvas.chartingSpace.viewport lends, meaning we apply the canvas.chartingSpace.viewport zoom and displacement. */
point = canvas.chartingSpace.viewport.transformThisPoint(point)
return point
}
function unTransformThisPoint (point, container) {
point = canvas.chartingSpace.viewport.unTransformThisPoint(point)
point = container.frame.unframeThisPoint(point)
return point
}
function nextPorwerOf10 (number) {
for (let i = -10; i <= 10; i++) {
if (number < Math.pow(10, i)) {
return Math.pow(10, i)
}
}
}
function pad (str, max) {
str = str.toString()
return str.length < max ? pad('0' + str, max) : str
}
function getDateFromPointAtBrowserCanvas (point, container, coordinateSystem) {
point = 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 = 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 = unTransformThisPoint(point, container)
point = coordinateSystem.unInverseTransform(point, container.frame.height)
return point.x
}
function moveToUserPosition (container, currentDate, currentRate, coordinateSystem, ignoreX, ignoreY, mousePosition) {
let targetPoint = {
x: currentDate.valueOf(),
y: currentRate
}
/* Put this point in the coordinate system of the canvas.chartingSpace.viewport */
targetPoint = coordinateSystem.transformThisPoint(targetPoint)
targetPoint = transformThisPoint(targetPoint, container)
let displaceVector
let targetNoZoom = canvas.chartingSpace.viewport.unTransformThisPoint(targetPoint)
let mouseNoZoom = canvas.chartingSpace.viewport.unTransformThisPoint(mousePosition)
displaceVector = {
x: mouseNoZoom.x - targetNoZoom.x,
y: mouseNoZoom.y - targetNoZoom.y
}
if (ignoreX) { displaceVector.x = 0 }
if (ignoreY) { displaceVector.y = 0 }
container.displace(displaceVector)
}
function removeTime (datetime) {
if (datetime === undefined) { return }
let dateOnly = new Date(Math.trunc(datetime.valueOf() / ONE_DAY_IN_MILISECONDS) * ONE_DAY_IN_MILISECONDS)
return dateOnly
}
function printLabel (labelToPrint, x, y, opacity, fontSize, color) {
let labelPoint
if (color === undefined) { color = UI_COLOR.DARK }
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
let label = '' + labelToPrint
let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO
browserCanvasContext.fillStyle = 'rgba(' + color + ', ' + opacity + ')'
browserCanvasContext.fillText(label, x, y)
}
function newUniqueId () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8)
return v.toString(16)
})
}
@@ -0,0 +1,142 @@
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 = transformThisPoint(borderPoint1, params.container)
borderPoint2 = transformThisPoint(borderPoint2, params.container)
borderPoint3 = transformThisPoint(borderPoint3, params.container)
borderPoint4 = 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) {
if (label === undefined) { return }
let fontOffset = label.length * fontSize * FONT_ASPECT_RATIO + 10
let labelPoint = {
x: container.frame.width * xFactor + xOffset - fontOffset / 2,
y: container.frame.height * yFactor + yOffset
}
labelPoint = container.frame.frameThisPoint(labelPoint)
browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY
browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)'
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)
}
}
}
+173
View File
@@ -0,0 +1,173 @@
function newVideoRecorder () {
let thisObject = {
recordCanvas: recordCanvas
}
let lastAction
return thisObject
function recordCanvas () {
{
const DISTANCE_BETWEEN_ICONS = 35
const ICON_SIZES = 50
let mousePointerIcon = canvas.designSpace.iconCollection.get('mouse-pointer')
let draggingIcon = canvas.designSpace.iconCollection.get('hand-drag')
let leftClickIcon = canvas.designSpace.iconCollection.get('mouse-left-click')
let rightClickIcon = canvas.designSpace.iconCollection.get('mouse-right-click')
let wheelClickIcon = canvas.designSpace.iconCollection.get('mouse-wheel-click')
let imagePosition
let buttonPressedIcon
if (canvas.mouse.action === 'key down' && lastAction === 'dragging') {
canvas.mouse.action = 'dragging'
}
switch (canvas.mouse.action) {
case 'moving': {
pointerIcon = mousePointerIcon
break
}
case 'dragging': {
pointerIcon = draggingIcon
break
}
case 'wheel': {
if (canvas.mouse.event.delta > 0) {
pointerIcon = canvas.designSpace.iconCollection.get('mouse-wheel-up')
} else {
pointerIcon = canvas.designSpace.iconCollection.get('mouse-wheel-down')
}
break
}
case 'key down': {
pointerIcon = mousePointerIcon
break
}
case 'key up': {
pointerIcon = mousePointerIcon
break
}
}
lastAction = canvas.mouse.action
imagePosition = {
x: canvas.mouse.position.x,
y: canvas.mouse.position.y
}
drawMousePointer(pointerIcon, imagePosition, ICON_SIZES)
switch (canvas.mouse.event.buttons) {
case 0: {
buttonPressedIcon = undefined
break
}
case 1: {
buttonPressedIcon = leftClickIcon
break
}
case 2: {
buttonPressedIcon = rightClickIcon
break
}
case 3: {
buttonPressedIcon = undefined
break
}
case 4: {
buttonPressedIcon = wheelClickIcon
break
}
}
let firstRow = DISTANCE_BETWEEN_ICONS * 1 + ICON_SIZES * 1
let secondRow = DISTANCE_BETWEEN_ICONS * 1 + ICON_SIZES * 2
let icon
imagePosition = {
x: canvas.mouse.position.x + DISTANCE_BETWEEN_ICONS * 2,
y: canvas.mouse.position.y
}
drawMousePointer(buttonPressedIcon, imagePosition, ICON_SIZES)
if (canvas.mouse.event.shiftKey === true) {
icon = canvas.designSpace.iconCollection.get('key-shift')
imagePosition = {
x: canvas.mouse.position.x - DISTANCE_BETWEEN_ICONS * 3,
y: canvas.mouse.position.y + firstRow
}
drawMousePointer(icon, imagePosition, ICON_SIZES)
}
if (canvas.mouse.event.ctrlKey === true || canvas.mouse.event.metaKey === true) {
icon = canvas.designSpace.iconCollection.get('key-ctrl')
imagePosition = {
x: canvas.mouse.position.x - DISTANCE_BETWEEN_ICONS * 3,
y: canvas.mouse.position.y + secondRow
}
drawMousePointer(icon, imagePosition, ICON_SIZES)
}
if (canvas.mouse.event.altKey === true) {
icon = canvas.designSpace.iconCollection.get('key-alt')
imagePosition = {
x: canvas.mouse.position.x + DISTANCE_BETWEEN_ICONS * 3 + ICON_SIZES * 0,
y: canvas.mouse.position.y + secondRow
}
drawMousePointer(icon, imagePosition, ICON_SIZES)
}
if (canvas.mouse.event.code === 'ArrowUp') {
icon = canvas.designSpace.iconCollection.get('key-up')
imagePosition = {
x: canvas.mouse.position.x - 0,
y: canvas.mouse.position.y + firstRow
}
drawMousePointer(icon, imagePosition, ICON_SIZES)
}
if (canvas.mouse.event.code === 'ArrowDown') {
icon = canvas.designSpace.iconCollection.get('key-down')
imagePosition = {
x: canvas.mouse.position.x - 0,
y: canvas.mouse.position.y + secondRow
}
drawMousePointer(icon, imagePosition, ICON_SIZES)
}
if (canvas.mouse.event.code === 'ArrowLeft') {
icon = canvas.designSpace.iconCollection.get('key-left')
imagePosition = {
x: canvas.mouse.position.x - DISTANCE_BETWEEN_ICONS * 0 - ICON_SIZES * 1,
y: canvas.mouse.position.y + secondRow
}
drawMousePointer(icon, imagePosition, ICON_SIZES)
}
if (canvas.mouse.event.code === 'ArrowRight') {
icon = canvas.designSpace.iconCollection.get('key-right')
imagePosition = {
x: canvas.mouse.position.x + DISTANCE_BETWEEN_ICONS * 0 + ICON_SIZES * 1,
y: canvas.mouse.position.y + secondRow
}
drawMousePointer(icon, imagePosition, ICON_SIZES)
}
function drawMousePointer (icon, imagePosition, imageSize) {
if (icon !== undefined) {
if (icon.canDrawIcon === true) {
browserCanvasContext.drawImage(
icon, imagePosition.x,
imagePosition.y,
imageSize,
imageSize)
}
}
}
mediaRecorder.capture(browserCanvas)
}
}
}
+21
View File
@@ -0,0 +1,21 @@
function newWebDebugLog () {
try {
let thisObject = {
write: write,
fileName: 'undefined'
}
return thisObject
function write (pText) {
console.log(spacePad(thisObject.fileName, 50) + ' : ' + pText)
function spacePad (str, max) {
str = str.toString()
return str.length < max ? spacePad(' ' + str, max) : str
}
}
} catch (err) {
console.log(spacePad(MODULE_NAME, 50) + ' : ' + '[ERROR] WebDebugLog --> err = ' + err.stack)
}
}
+74
View File
@@ -0,0 +1,74 @@
function Stack(){
Object.defineProperties(
this,
{
add:{
enumerable:true,
writable:false,
value:addToStack
},
next:{
enumerable:true,
writable:false,
value:run
},
clear:{
enumerable:true,
writable:false,
value:clearStack
},
contents:{
enumerable:false,
get:getStack,
set:setStack
},
autoRun:{
enumerable:true,
writable:true,
value:true
},
stop:{
enumerable:true,
writable:true,
value:false
}
}
);
var stack=[];
var running=false;
var stop=false;
function clearStack(){
stack=[];
return stack;
}
function getStack(){
return stack;
}
function setStack(val){
stack=val;
return stack;
}
function addToStack(){
for(var i in arguments){
stack.unshift(arguments[i]);
}
if(!running && !this.stop && this.autoRun){
this.next();
}
}
function run(){
running=true;
if(stack.length<1 || this.stop){
running=false;
return;
}
stack.shift().bind(this)();
}
}
+18
View File
@@ -0,0 +1,18 @@
var Stack=require('../stack');
//create a new Stack instance
var stack=new Stack;
stack.autoRun=false;
for(var i=0; i<50; i++){
//add a bunch of stuff to the stack
stack.add(makeRequest.bind(stack,i));
}
stack.next();
function makeRequest(index){
//do stuff
console.log(`making LIFO request ${index}`);
this.next();
}
+59
View File
@@ -0,0 +1,59 @@
{
"_from": "easy-stack@^1.0.0",
"_id": "easy-stack@1.0.0",
"_inBundle": false,
"_integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g=",
"_location": "/easy-stack",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "easy-stack@^1.0.0",
"name": "easy-stack",
"escapedName": "easy-stack",
"rawSpec": "^1.0.0",
"saveSpec": null,
"fetchSpec": "^1.0.0"
},
"_requiredBy": [
"/js-queue"
],
"_resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz",
"_shasum": "12c91b3085a37f0baa336e9486eac4bf94e3e788",
"_spec": "easy-stack@^1.0.0",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\js-queue",
"author": {
"name": "Brandon Nozaki Miller"
},
"bugs": {
"url": "https://github.com/RIAEvangelist/easy-stack/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Simple JS stack with auto run for node and browsers",
"engines": {
"node": ">=6.0.0"
},
"homepage": "https://github.com/RIAEvangelist/easy-stack#readme",
"keywords": [
"stack",
"node",
"js",
"auto",
"run",
"execute",
"browser",
"react"
],
"license": "DBAD",
"main": "stack.js",
"name": "easy-stack",
"repository": {
"type": "git",
"url": "git+https://github.com/RIAEvangelist/easy-stack.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "1.0.0"
}
+39
View File
@@ -0,0 +1,39 @@
class Stack{
constructor(){
this.stack=[];
this.autoRun=true;
this.running=false;
this.stop=false;
}
clear(){
this.stack=[];
return this.stack;
}
contents(val){
if(val){
this.stack=val;
}
return this.stack;
}
add(...callbacks){
this.stack.push(...callbacks);
if(!this.running && !this.stop && this.autoRun){
this.next();
}
}
next(){
this.running=true;
if(this.stack.length<1 || this.stop){
this.running=false;
return;
}
this.stack.pop().bind(this)();
}
}
module.exports=Stack;
+28
View File
@@ -0,0 +1,28 @@
{
"name": "event-pubsub",
"description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!",
"main": "event-pubsub.js",
"authors": [
"Brandon Nozaki Miller"
],
"license": "DBAD",
"keywords": [
"event",
"events",
"pubsub",
"node",
"browser"
],
"homepage": "https://github.com/RIAEvangelist/event-pubsub",
"moduleType": [
"globals",
"node"
],
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}
+143
View File
@@ -0,0 +1,143 @@
'use strict';
function EventPubSub() {
this._events_={};
this.publish=this.trigger=this.emit=emit;
this.subscribe=this.on=on;
this.once=once;
this.unSubscribe=this.off=off;
this.emit$=emit$;
function on(type,handler,once){
if(!handler){
throw new ReferenceError('handler not defined.');
}
if(!this._events_[type]){
this._events_[type]=[];
}
if(once){
handler._once_ = once;
}
this._events_[type].push(handler);
return this;
}
function once(type,handler){
return this.on(type, handler, true);
}
function off(type,handler){
if(!this._events_[type]){
return this;
}
if(!handler){
throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler');
}
if(handler=='*'){
delete this._events_[type];
return this;
}
var handlers=this._events_[type];
while(handlers.includes(handler)){
handlers.splice(
handlers.indexOf(handler),
1
);
}
if(handlers.length<1){
delete this._events_[type];
}
return this;
}
function emit(type){
this.emit$.apply(this, arguments);
if(!this._events_[type]){
return this;
}
arguments.splice=Array.prototype.splice;
arguments.splice(0,1);
var handlers=this._events_[type];
var onceHandled=[];
for(var i in handlers){
var handler=handlers[i];
handler.apply(this, arguments);
if(handler._once_){
onceHandled.push(handler);
}
}
for(var i in onceHandled){
this.off(
type,
onceHandled[i]
);
}
return this;
}
function emit$(type, args){
if(!this._events_['*']){
return this;
}
var catchAll=this._events_['*'];
args.shift=Array.prototype.shift;
args.shift(type);
for(var handler of catchAll){
handler.apply(this, args);
}
return this;
}
return this;
}
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.includes called on null or undefined');
}
var O = Object(this);
var len = parseInt(O.length, 10) || 0;
if (len === 0) {
return false;
}
var n = parseInt(arguments[1], 10) || 0;
var k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {k = 0;}
}
var currentElement;
while (k < len) {
currentElement = O[k];
if (searchElement === currentElement ||
(searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
return true;
}
k++;
}
return false;
};
}
module.exports=EventPubSub;
+99
View File
@@ -0,0 +1,99 @@
'use strict';
class EventPubSub {
constructor( scope ) {
this._events_ = {};
this.publish = this.trigger = this.emit;
this.subscribe = this.on;
this.unSubscribe = this.off;
}
on( type, handler, once ) {
if ( !handler ) {
throw new ReferenceError( 'handler not defined.' );
}
if ( !this._events_[ type ] ) {
this._events_[ type ] = [];
}
if(once){
handler._once_ = once;
}
this._events_[ type ].push( handler );
return this;
}
once( type, handler ) {
return this.on( type, handler, true );
}
off( type, handler ) {
if ( !this._events_[ type ] ) {
return this;
}
if ( !handler ) {
throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' );
}
if ( handler == '*' ) {
delete this._events_[ type ];
return this;
}
const handlers = this._events_[ type ];
while ( handlers.includes( handler ) ) {
handlers.splice(
handlers.indexOf( handler ),
1
);
}
if ( handlers.length < 1 ) {
delete this._events_[ type ];
}
return this;
}
emit( type, ...args ) {
if ( !this._events_[ type ] ) {
return this.emit$( type, ...args );
}
const handlers = this._events_[ type ];
const onceHandled=[];
for ( let handler of handlers ) {
handler.apply( this, args );
if(handler._once_){
onceHandled.push(handler);
}
}
for(let handler of onceHandled){
this.off(type,handler);
}
return this.emit$( type, ...args );
}
emit$( type, ...args ) {
if ( !this._events_[ '*' ] ) {
return this;
}
const catchAll = this._events_[ '*' ];
for ( let handler of catchAll ) {
handler.call( this, type, ...args );
}
return this;
}
}
module.exports = EventPubSub;
+141
View File
@@ -0,0 +1,141 @@
'use strict';
window.EventPubSub=function EventPubSub() {
this._events_={};
this.publish=this.trigger=this.emit=emit;
this.subscribe=this.on=on;
this.once=once;
this.unSubscribe=this.off=off;
this.emit$=emit$;
function on(type,handler,once){
if(!handler){
throw new ReferenceError('handler not defined.');
}
if(!this._events_[type]){
this._events_[type]=[];
}
if(once){
handler._once_ = once;
}
this._events_[type].push(handler);
return this;
}
function once(type,handler){
return this.on(type, handler, true);
}
function off(type,handler){
if(!this._events_[type]){
return this;
}
if(!handler){
throw new ReferenceError('handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler');
}
if(handler=='*'){
delete this._events_[type];
return this;
}
var handlers=this._events_[type];
while(handlers.includes(handler)){
handlers.splice(
handlers.indexOf(handler),
1
);
}
if(handlers.length<1){
delete this._events_[type];
}
return this;
}
function emit(type){
this.emit$.apply(this, arguments);
if(!this._events_[type]){
return this;
}
arguments.splice=Array.prototype.splice;
arguments.splice(0,1);
var handlers=this._events_[type];
var onceHandled=[];
for(var i in handlers){
var handler=handlers[i];
handler.apply(this, arguments);
if(handler._once_){
onceHandled.push(handler);
}
}
for(var i in onceHandled){
this.off(
type,
onceHandled[i]
);
}
return this;
}
function emit$(type, args){
if(!this._events_['*']){
return this;
}
var catchAll=this._events_['*'];
args.shift=Array.prototype.shift;
args.shift(type);
for(var handler of catchAll){
handler.apply(this, args);
}
return this;
}
return this;
}
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.includes called on null or undefined');
}
var O = Object(this);
var len = parseInt(O.length, 10) || 0;
if (len === 0) {
return false;
}
var n = parseInt(arguments[1], 10) || 0;
var k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {k = 0;}
}
var currentElement;
while (k < len) {
currentElement = O[k];
if (searchElement === currentElement ||
(searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
return true;
}
k++;
}
return false;
};
}
+130
View File
@@ -0,0 +1,130 @@
'use strict';
window.EventPubSub=class EventPubSub {
constructor( scope ) {
this._events_ = {};
this.publish = this.trigger = this.emit;
this.subscribe = this.on;
this.unSubscribe = this.off;
}
on( type, handler, once ) {
if ( !handler ) {
throw new ReferenceError( 'handler not defined.' );
}
if ( !this._events_[ type ] ) {
this._events_[ type ] = [];
}
if(once){
handler._once_ = once;
}
this._events_[ type ].push( handler );
return this;
}
once( type, handler ) {
return this.on( type, handler, true );
}
off( type, handler ) {
if ( !this._events_[ type ] ) {
return this;
}
if ( !handler ) {
throw new ReferenceError( 'handler not defined. if you wish to remove all handlers from the event please pass "*" as the handler' );
}
if ( handler == '*' ) {
delete this._events_[ type ];
return this;
}
const handlers = this._events_[ type ];
while ( handlers.includes( handler ) ) {
handlers.splice(
handlers.indexOf( handler ),
1
);
}
if ( handlers.length < 1 ) {
delete this._events_[ type ];
}
return this;
}
emit( type, ...args ) {
if ( !this._events_[ type ] ) {
return this.emit$( type, ...args );
}
const handlers = this._events_[ type ];
const onceHandled=[];
for ( let handler of handlers ) {
handler.apply( this, args );
if(handler._once_){
onceHandled.push(handler);
}
}
for(let handler of onceHandled){
this.off(type,handler);
}
return this.emit$( type, ...args );
}
emit$( type, ...args ) {
if ( !this._events_[ '*' ] ) {
return this;
}
const catchAll = this._events_[ '*' ];
for ( let handler of catchAll ) {
handler.call( this, type, ...args );
}
return this;
}
}
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.includes called on null or undefined');
}
var O = Object(this);
var len = parseInt(O.length, 10) || 0;
if (len === 0) {
return false;
}
var n = parseInt(arguments[1], 10) || 0;
var k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {k = 0;}
}
var currentElement;
while (k < len) {
currentElement = O[k];
if (searchElement === currentElement ||
(searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
return true;
}
k++;
}
return false;
};
}
+8
View File
@@ -0,0 +1,8 @@
'use strict';
let EventPubSub = require('./es5');
if(process.version[1]>5){
EventPubSub = require('./es6');
}
module.exports=EventPubSub;
+59
View File
@@ -0,0 +1,59 @@
{
"_from": "event-pubsub@4.3.0",
"_id": "event-pubsub@4.3.0",
"_inBundle": false,
"_integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==",
"_location": "/event-pubsub",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "event-pubsub@4.3.0",
"name": "event-pubsub",
"escapedName": "event-pubsub",
"rawSpec": "4.3.0",
"saveSpec": null,
"fetchSpec": "4.3.0"
},
"_requiredBy": [
"/node-ipc"
],
"_resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz",
"_shasum": "f68d816bc29f1ec02c539dc58c8dd40ce72cb36e",
"_spec": "event-pubsub@4.3.0",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\node-ipc",
"author": {
"name": "Brandon Nozaki Miller"
},
"bugs": {
"url": "https://github.com/RIAEvangelist/event-pubsub/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Super light and fast Extensible PubSub events and EventEmitters for Node and the browser with support for ES6 by default, and ES5 versions for older verions of node and older IE/Safari versions. Easy for any developer level. No frills, just high speed pubsub events!",
"directories": {
"example": "examples"
},
"engines": {
"node": ">=4.0.0"
},
"homepage": "https://github.com/RIAEvangelist/event-pubsub",
"keywords": [
"event",
"events",
"pubsub",
"node",
"browser"
],
"license": "Unlicense",
"main": "event-pubsub.js",
"name": "event-pubsub",
"repository": {
"type": "git",
"url": "git+https://github.com/RIAEvangelist/event-pubsub.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "4.3.0"
}
+71
View File
@@ -0,0 +1,71 @@
function Message() {
Object.defineProperties(
this, {
data: {
enumerable: true,
get: getData,
set: setData
},
type: {
enumerable: true,
get: getType,
set: setType
},
load:{
enumarable:true,
writable:false,
value:parse
},
JSON: {
enumerable: true,
get: getJSON
}
}
);
var type = '';
var data = {};
function getType() {
return type;
}
function getData() {
return data;
}
function getJSON() {
return JSON.stringify(
{
type: type,
data: data
}
);
}
function setType(value) {
type = value;
}
function setData(value) {
data = value;
}
function parse(message){
try{
var message=JSON.parse(message);
type=message.type;
data=message.data;
}catch(err){
var badMessage=message;
type='error',
data={
message:'Invalid JSON response format',
err:err,
response:badMessage
}
}
}
}
module.exports=Message;
+75
View File
@@ -0,0 +1,75 @@
(
function(){
function Message() {
Object.defineProperties(
this, {
data: {
enumerable: true,
get: getData,
set: setData
},
type: {
enumerable: true,
get: getType,
set: setType
},
load:{
enumarable:true,
writable:false,
value:parse
},
JSON: {
enumerable: true,
get: getJSON
}
}
);
var type = '';
var data = {};
function getType() {
return type;
}
function getData() {
return data;
}
function getJSON() {
return JSON.stringify(
{
type: type,
data: data
}
);
}
function setType(value) {
type = value;
}
function setData(value) {
data = value;
}
function parse(message){
try{
var message=JSON.parse(message);
type=message.type;
data=message.data;
}catch(err){
var badMessage=message;
type='error',
data={
message:'Invalid JSON response format',
err:err,
response:badMessage
}
}
}
}
window.message=Message;
}
)();
+81
View File
@@ -0,0 +1,81 @@
{
"_from": "js-message@1.0.5",
"_id": "js-message@1.0.5",
"_inBundle": false,
"_integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU=",
"_location": "/js-message",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "js-message@1.0.5",
"name": "js-message",
"escapedName": "js-message",
"rawSpec": "1.0.5",
"saveSpec": null,
"fetchSpec": "1.0.5"
},
"_requiredBy": [
"/node-ipc"
],
"_resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
"_shasum": "2300d24b1af08e89dd095bc1a4c9c9cfcb892d15",
"_spec": "js-message@1.0.5",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\node-ipc",
"author": {
"name": "Brandon Nozaki Miller"
},
"bugs": {
"url": "https://github.com/RIAEvangelist/js-message/issues"
},
"bundleDependencies": false,
"dependencies": {},
"deprecated": false,
"description": "normalized JS Object and JSON message and event protocol for node.js, vanialla js, react.js, components, actions, stores and dispatchers",
"devDependencies": {},
"engines": {
"node": ">=0.6.0"
},
"homepage": "https://github.com/RIAEvangelist/js-message#readme",
"keywords": [
"message",
"normalize",
"events",
"js",
"json",
"protocol",
"ipc",
"node",
"nodejs",
"node.js",
"react",
"react.js",
"reactjs",
"websocket",
"websockets",
"web",
"socket",
"sockets",
"ws",
"flux",
"reflux",
"component",
"components",
"store",
"stores",
"action",
"actions"
],
"license": "DBAD",
"main": "Message.js",
"name": "js-message",
"repository": {
"type": "git",
"url": "git+https://github.com/RIAEvangelist/js-message.git"
},
"scripts": {
"start": "node devServer.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "1.0.5"
}
+62
View File
@@ -0,0 +1,62 @@
{
"_from": "js-queue@2.0.0",
"_id": "js-queue@2.0.0",
"_inBundle": false,
"_integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=",
"_location": "/js-queue",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "js-queue@2.0.0",
"name": "js-queue",
"escapedName": "js-queue",
"rawSpec": "2.0.0",
"saveSpec": null,
"fetchSpec": "2.0.0"
},
"_requiredBy": [
"/node-ipc"
],
"_resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz",
"_shasum": "362213cf860f468f0125fc6c96abc1742531f948",
"_spec": "js-queue@2.0.0",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\Events-Server\\node_modules\\node-ipc",
"author": {
"name": "Brandon Nozaki Miller"
},
"bugs": {
"url": "https://github.com/RIAEvangelist/js-queue/issues"
},
"bundleDependencies": false,
"dependencies": {
"easy-stack": "^1.0.0"
},
"deprecated": false,
"description": "Simple JS queue with auto run for node and browsers",
"engines": {
"node": ">=1.0.0"
},
"homepage": "https://github.com/RIAEvangelist/js-queue#readme",
"keywords": [
"queue",
"node",
"js",
"auto",
"run",
"execute",
"browser",
"react"
],
"license": "DBAD",
"main": "queue.js",
"name": "js-queue",
"repository": {
"type": "git",
"url": "git+https://github.com/RIAEvangelist/js-queue.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "2.0.0"
}
+74
View File
@@ -0,0 +1,74 @@
function Queue(){
Object.defineProperties(
this,
{
add:{
enumerable:true,
writable:false,
value:addToQueue
},
next:{
enumerable:true,
writable:false,
value:run
},
clear:{
enumerable:true,
writable:false,
value:clearQueue
},
contents:{
enumerable:false,
get:getQueue,
set:setQueue
},
autoRun:{
enumerable:true,
writable:true,
value:true
},
stop:{
enumerable:true,
writable:true,
value:false
}
}
);
var queue=[];
var running=false;
var stop=false;
function clearQueue(){
queue=[];
return queue;
}
function getQueue(){
return queue;
}
function setQueue(val){
queue=val;
return queue;
}
function addToQueue(){
for(var i in arguments){
queue.push(arguments[i]);
}
if(!running && !this.stop && this.autoRun){
this.next();
}
}
function run(){
running=true;
if(queue.length<1 || this.stop){
running=false;
return;
}
queue.shift().bind(this)();
}
}
+76
View File
@@ -0,0 +1,76 @@
function Queue(asStack){
Object.defineProperties(
this,
{
add:{
enumerable:true,
writable:false,
value:addToQueue
},
next:{
enumerable:true,
writable:false,
value:run
},
clear:{
enumerable:true,
writable:false,
value:clearQueue
},
contents:{
enumerable:false,
get:getQueue,
set:setQueue
},
autoRun:{
enumerable:true,
writable:true,
value:true
},
stop:{
enumerable:true,
writable:true,
value:false
}
}
);
var queue=[];
var running=false;
var stop=false;
function clearQueue(){
queue=[];
return queue;
}
function getQueue(){
return queue;
}
function setQueue(val){
queue=val;
return queue;
}
function addToQueue(){
for(var i in arguments){
queue.push(arguments[i]);
}
if(!running && !this.stop && this.autoRun){
this.next();
}
}
function run(){
running=true;
if(queue.length<1 || this.stop){
running=false;
return;
}
queue.shift().bind(this)();
}
}
module.exports=Queue;
+3
View File
@@ -0,0 +1,3 @@
const Stack=require('easy-stack');
module.exports = Stack;
+257
View File
@@ -0,0 +1,257 @@
'use strict';
const net = require('net'),
tls = require('tls'),
EventParser = require('../entities/EventParser.js'),
Message = require('js-message'),
fs = require('fs'),
Queue = require('js-queue');
let Events = require('event-pubsub/es5');
if(process.version[1]>4){
Events = require('event-pubsub');
}
let eventParser = new EventParser();
class Client extends Events{
constructor(config,log){
super();
Object.assign(
this,
{
Client : Client,
config : config,
queue : new Queue,
socket : false,
connect : connect,
emit : emit,
log : log,
retriesRemaining:config.maxRetries||0,
explicitlyDisconnected: false
}
);
eventParser=new EventParser(this.config);
}
}
function emit(type,data){
this.log('dispatching event to ', this.id, this.path, ' : ', type, ',', data);
let message=new Message;
message.type=type;
message.data=data;
if(this.config.rawBuffer){
message=new Buffer(type,this.config.encoding);
}else{
message=eventParser.format(message);
}
if(!this.config.sync){
this.socket.write(message);
return;
}
this.queue.add(
syncEmit.bind(this,message)
);
}
function syncEmit(message){
this.log('dispatching event to ', this.id, this.path, ' : ', message);
this.socket.write(message);
}
function connect(){
//init client object for scope persistance especially inside of socket events.
let client=this;
client.log('requested connection to ', client.id, client.path);
if(!this.path){
client.log('\n\n######\nerror: ', client.id ,' client has not specified socket path it wishes to connect to.');
return;
}
const options={};
if(!client.port){
client.log('Connecting client on Unix Socket :', client.path);
options.path=client.path;
if (process.platform ==='win32' && !client.path.startsWith('\\\\.\\pipe\\')){
options.path = options.path.replace(/^\//, '');
options.path = options.path.replace(/\//g, '-');
options.path= `\\\\.\\pipe\\${options.path}`;
}
client.socket = net.connect(options);
}else{
options.host=client.path;
options.port=client.port;
if(client.config.interface.localAddress){
options.localAddress=client.config.interface.localAddress;
}
if(client.config.interface.localPort){
options.localPort=client.config.interface.localPort;
}
if(client.config.interface.family){
options.family=client.config.interface.family;
}
if(client.config.interface.hints){
options.hints=client.config.interface.hints;
}
if(client.config.interface.lookup){
options.lookup=client.config.interface.lookup;
}
if(!client.config.tls){
client.log('Connecting client via TCP to', options);
client.socket = net.connect(options);
}else{
client.log('Connecting client via TLS to', client.path ,client.port,client.config.tls);
if(client.config.tls.private){
client.config.tls.key=fs.readFileSync(client.config.tls.private);
}
if(client.config.tls.public){
client.config.tls.cert=fs.readFileSync(client.config.tls.public);
}
if(client.config.tls.trustedConnections){
if(typeof client.config.tls.trustedConnections === 'string'){
client.config.tls.trustedConnections=[client.config.tls.trustedConnections];
}
client.config.tls.ca=[];
for(let i=0; i<client.config.tls.trustedConnections.length; i++){
client.config.tls.ca.push(
fs.readFileSync(client.config.tls.trustedConnections[i])
);
}
}
Object.assign(client.config.tls,options);
client.socket = tls.connect(
client.config.tls
);
}
}
client.socket.setEncoding(this.config.encoding);
client.socket.on(
'error',
function(err){
client.log('\n\n######\nerror: ', err);
client.publish('error', err);
}
);
client.socket.on(
'connect',
function connectionMade(){
client.publish('connect');
client.retriesRemaining=client.config.maxRetries;
client.log('retrying reset');
}
);
client.socket.on(
'close',
function connectionClosed(){
client.log('connection closed' ,client.id , client.path,
client.retriesRemaining, 'tries remaining of', client.config.maxRetries
);
if(
client.config.stopRetrying ||
client.retriesRemaining<1 ||
client.explicitlyDisconnected
){
client.publish('disconnect');
client.log(
(client.config.id),
'exceeded connection rety amount of',
' or stopRetrying flag set.'
);
client.socket.destroy();
client.publish('destroy');
client=undefined;
return;
}
setTimeout(
function retryTimeout(){
client.retriesRemaining--;
client.connect();
}.bind(null,client),
client.config.retry
);
client.publish('disconnect');
}
);
client.socket.on(
'data',
function(data) {
client.log('## received events ##');
if(client.config.rawBuffer){
client.publish(
'data',
new Buffer(data,client.config.encoding)
);
if(!client.config.sync){
return;
}
client.queue.next();
return;
}
if(!this.ipcBuffer){
this.ipcBuffer='';
}
data=(this.ipcBuffer+=data);
if(data.slice(-1)!=eventParser.delimiter || data.indexOf(eventParser.delimiter) == -1){
client.log('Messages are large, You may want to consider smaller messages.');
return;
}
this.ipcBuffer='';
const events = eventParser.parse(data);
const eCount = events.length;
for(let i=0; i<eCount; i++){
let message=new Message;
message.load(events[i]);
client.log('detected event', message.type, message.data);
client.publish(
message.type,
message.data
);
}
if(!client.config.sync){
return;
}
client.queue.next();
}
);
}
module.exports=Client;
+402
View File
@@ -0,0 +1,402 @@
'use strict';
const net = require('net'),
tls = require('tls'),
fs = require('fs'),
dgram = require('dgram'),
EventParser = require('../entities/EventParser.js'),
Message = require('js-message');
let Events = require('event-pubsub/es5');
if(process.version[1]>4){
Events = require('event-pubsub');
}
let eventParser = new EventParser();
class Server extends Events{
constructor(path,config,log,port){
super();
Object.assign(
this,
{
config : config,
path : path,
port : port,
udp4 : false,
udp6 : false,
log : log,
server : false,
sockets : [],
emit : emit,
broadcast : broadcast
}
);
eventParser=new EventParser(this.config);
this.on(
'close',
serverClosed.bind(this)
);
}
onStart(socket){
this.trigger(
'start',
socket
);
}
stop(){
this.server.close();
}
start(){
if(!this.path){
this.log('Socket Server Path not specified, refusing to start');
return;
}
if(this.config.unlink){
fs.unlink(
this.path,
startServer.bind(this)
);
}else{
startServer.bind(this)();
}
}
}
function emit(socket, type, data){
this.log('dispatching event to socket', ' : ', type, data);
let message=new Message;
message.type=type;
message.data=data;
if(this.config.rawBuffer){
this.log(this.config.encoding)
message=new Buffer(type,this.config.encoding);
}else{
message=eventParser.format(message);
}
if(this.udp4 || this.udp6){
if(!socket.address || !socket.port){
this.log('Attempting to emit to a single UDP socket without supplying socket address or port. Redispatching event as broadcast to all connected sockets');
this.broadcast(type,data);
return;
}
this.server.write(
message,
socket
);
return;
}
socket.write(message);
}
function broadcast(type,data){
this.log('broadcasting event to all known sockets listening to ', this.path,' : ', ((this.port)?this.port:''), type, data);
let message=new Message;
message.type=type;
message.data=data;
if(this.config.rawBuffer){
message=new Buffer(type,this.config.encoding);
}else{
message=eventParser.format(message);
}
if(this.udp4 || this.udp6){
for(let i=1, count=this.sockets.length; i<count; i++){
this.server.write(message,this.sockets[i]);
}
}else{
for(let i=0, count=this.sockets.length; i<count; i++){
this.sockets[i].write(message);
}
}
}
function serverClosed(){
for(let i=0, count=this.sockets.length; i<count; i++){
let socket=this.sockets[i];
let destroyedSocketId=false;
if(socket){
if(socket.readable){
continue;
}
}
if(socket.id){
destroyedSocketId=socket.id;
}
this.log('socket disconnected',destroyedSocketId.toString());
if(socket && socket.destroy){
socket.destroy();
}
this.sockets.splice(i,1);
this.publish('socket.disconnected', socket, destroyedSocketId);
return;
}
}
function gotData(socket,data,UDPSocket){
let sock=((this.udp4 || this.udp6)? UDPSocket : socket);
if(this.config.rawBuffer){
data=new Buffer(data,this.config.encoding);
this.publish(
'data',
data,
sock
);
return;
}
if(!this.ipcBuffer){
this.ipcBuffer='';
}
data=(this.ipcBuffer+=data);
if(data.slice(-1)!=eventParser.delimiter || data.indexOf(eventParser.delimiter) == -1){
this.log('Messages are large, You may want to consider smaller messages.');
return;
}
this.ipcBuffer='';
data=eventParser.parse(data);
while(data.length>0){
let message=new Message;
message.load(data.shift());
// Only set the sock id if it is specified.
if (message.data && message.data.id){
sock.id=message.data.id;
}
this.log('received event of : ',message.type,message.data);
this.publish(
message.type,
message.data,
sock
);
}
}
function socketClosed(socket){
this.publish(
'close',
socket
);
}
function serverCreated(socket) {
this.sockets.push(socket);
if(socket.setEncoding){
socket.setEncoding(this.config.encoding);
}
this.log('## socket connection to server detected ##');
socket.on(
'close',
socketClosed.bind(this)
);
socket.on(
'error',
function(err){
this.log('server socket error',err);
this.publish('error',err);
}.bind(this)
);
socket.on(
'data',
gotData.bind(this,socket)
);
socket.on(
'message',
function(msg,rinfo) {
if (!rinfo){
return;
}
this.log('Received UDP message from ', rinfo.address, rinfo.port);
let data;
if(this.config.rawSocket){
data=new Buffer(msg,this.config.encoding);
}else{
data=msg.toString();
}
socket.emit('data',data,rinfo);
}.bind(this)
);
this.publish(
'connect',
socket
);
if(this.config.rawBuffer){
return;
}
}
function startServer() {
this.log(
'starting server on ',this.path,
((this.port)?`:${this.port}`:'')
);
if(!this.udp4 && !this.udp6){
this.log('starting TLS server',this.config.tls);
if(!this.config.tls){
this.server=net.createServer(
serverCreated.bind(this)
);
}else{
startTLSServer.bind(this)();
}
}else{
this.server=dgram.createSocket(
((this.udp4)? 'udp4':'udp6')
);
this.server.write=UDPWrite.bind(this);
this.server.on(
'listening',
function UDPServerStarted() {
serverCreated.bind(this)(this.server);
}.bind(this)
);
}
this.server.on(
'error',
function(err){
this.log('server error',err);
this.publish(
'error',
err
);
}.bind(this)
);
this.server.maxConnections=this.config.maxConnections;
if(!this.port){
this.log('starting server as', 'Unix || Windows Socket');
if (process.platform ==='win32'){
this.path = this.path.replace(/^\//, '');
this.path = this.path.replace(/\//g, '-');
this.path= `\\\\.\\pipe\\${this.path}`;
}
this.server.listen(
this.path,
this.onStart.bind(this)
);
return;
}
if(!this.udp4 && !this.udp6){
this.log('starting server as', (this.config.tls?'TLS':'TCP'));
this.server.listen(
this.port,
this.path,
this.onStart.bind(this)
);
return;
}
this.log('starting server as',((this.udp4)? 'udp4':'udp6'));
this.server.bind(
this.port,
this.path
);
this.onStart(
{
address : this.path,
port : this.port
}
);
}
function startTLSServer(){
this.log('starting TLS server',this.config.tls);
if(this.config.tls.private){
this.config.tls.key=fs.readFileSync(this.config.tls.private);
}else{
this.config.tls.key=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/private/server.key`);
}
if(this.config.tls.public){
this.config.tls.cert=fs.readFileSync(this.config.tls.public);
}else{
this.config.tls.cert=fs.readFileSync(`${__dirname}/../local-node-ipc-certs/server.pub`);
}
if(this.config.tls.dhparam){
this.config.tls.dhparam=fs.readFileSync(this.config.tls.dhparam);
}
if(this.config.tls.trustedConnections){
if(typeof this.config.tls.trustedConnections === 'string'){
this.config.tls.trustedConnections=[this.config.tls.trustedConnections];
}
this.config.tls.ca=[];
for(let i=0; i<this.config.tls.trustedConnections.length; i++){
this.config.tls.ca.push(
fs.readFileSync(this.config.tls.trustedConnections[i])
);
}
}
this.server=tls.createServer(
this.config.tls,
serverCreated.bind(this)
);
}
function UDPWrite(message,socket){
let data=new Buffer(message, this.config.encoding);
this.server.send(
data,
0,
data.length,
socket.port,
socket.address,
function(err, bytes) {
if(err){
this.log('error writing data to socket',err);
this.publish(
'error',
function(err){
this.publish('error',err);
}
);
}
}
);
}
module.exports=Server;
+80
View File
@@ -0,0 +1,80 @@
'use strict';
/*eslint no-magic-numbers: ["error", { "ignore": [ 0] }]*/
/**
* @module entities
*/
const os = require('os');
/**
* @class Defaults
* @description Defaults Entity
*/
class Defaults{
/**
* @constructor
* @method constructor
* @return {void}
*/
constructor(){
this.appspace='app.';
this.socketRoot='/tmp/';
this.id=os.hostname();
this.encoding='utf8';
this.rawBuffer=false;
this.sync=false;
this.unlink=true;
this.delimiter='\f';
this.silent=false;
this.logDepth=5;
this.logInColor=true;
this.logger=console.log.bind(console);
this.maxConnections=100;
this.retry=500;
this.maxRetries=Infinity;
this.stopRetrying=false;
this.IPType=getIPType();
this.tls=false;
this.networkHost = (this.IPType == 'IPv6') ? '::1' : '127.0.0.1';
this.networkPort = 8000;
this.interface={
localAddress:false,
localPort:false,
family:false,
hints:false,
lookup:false
}
}
}
/**
* method to get ip type
*
* @method getIPType
* @return {string} ip type
*/
function getIPType() {
const networkInterfaces = os.networkInterfaces();
let IPType = '';
if (networkInterfaces
&& Array.isArray(networkInterfaces)
&& networkInterfaces.length > 0) {
// getting the family of first network interface available
IPType = networkInterfaces [
Object.keys( networkInterfaces )[0]
][0].family;
}
return IPType;
}
module.exports=Defaults;
+32
View File
@@ -0,0 +1,32 @@
'use strict';
const Defaults = require('./Defaults.js');
class Parser{
constructor(config){
if(!config){
config=new Defaults;
}
this.delimiter=config.delimiter;
}
format(message){
if(!message.data && message.data!==false && message.data!==0){
message.data={};
}
if(message.data['_maxListeners']){
message.data={};
}
message=message.JSON+this.delimiter;
return message;
}
parse(data){
let events=data.split(this.delimiter);
events.pop();
return events;
}
}
module.exports=Parser;
@@ -0,0 +1,44 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'goodbye';
ipc.config.retry= 1500;
ipc.config.maxRetries= 10;
ipc.connectToNet(
'world',
function(){
ipc.of.world.on(
'connect',
function(){
ipc.log('## connected to world ##', ipc.config.delay);
ipc.of.world.emit(
'app.message',
{
id : ipc.config.id,
message : 'goodbye'
}
);
}
);
ipc.of.world.on(
'disconnect',
function(){
ipc.log('disconnected from world');
}
);
ipc.of.world.on(
'kill.connection',
function(data){
ipc.log('world requested kill.connection');
ipc.disconnect('world');
}
);
}
);
@@ -0,0 +1,50 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'hello';
ipc.config.retry= 1500;
ipc.config.maxRetries=10;
ipc.connectToNet(
'world',
function(){
ipc.of.world.on(
'connect',
function(){
ipc.log('## connected to world ##', ipc.config.delay);
ipc.of.world.emit(
'app.message',
{
id : ipc.config.id,
message : 'hello'
}
);
}
);
ipc.of.world.on(
'disconnect',
function(){
ipc.log('disconnected from world');
}
);
ipc.of.world.on(
'app.message',
function(data){
ipc.log('got a message from world : ', data.message);
}
);
ipc.of.world.on(
'kill.connection',
function(data){
ipc.log('world requested kill.connection');
ipc.disconnect('world');
}
);
}
);
@@ -0,0 +1,51 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'world';
ipc.config.retry= 1500;
var messages={
goodbye:false,
hello:false
};
ipc.serveNet(
function(){
ipc.server.on(
'app.message',
function(data,socket){
ipc.log('got a message from', (data.id), (data.message));
messages[data.id]=true;
ipc.server.emit(
socket,
'app.message',
{
id : ipc.config.id,
message : data.message+' world!'
}
);
if(messages.hello && messages.goodbye){
ipc.log('got all required events, telling clients to kill connection');
ipc.server.broadcast(
'kill.connection',
{
id:ipc.config.id
}
);
}
}
);
}
);
ipc.server.start();
@@ -0,0 +1,39 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'hello';
ipc.config.retry= 1500;
ipc.connectToNet(
'world',
function(){
ipc.of.world.on(
'connect',
function(){
ipc.log('## connected to world ##', ipc.config.delay);
ipc.of.world.emit(
'message',
'hello'
);
}
);
ipc.of.world.on(
'disconnect',
function(){
ipc.log('disconnected from world');
}
);
ipc.of.world.on(
'message',
function(data){
ipc.log('got a message from world : ', data);
}
);
}
);
@@ -0,0 +1,44 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'world';
ipc.config.retry= 1500;
ipc.config.maxConnections=1;
ipc.serveNet(
function(){
ipc.server.on(
'message',
function(data,socket){
ipc.log('got a message : ', data);
ipc.server.emit(
socket,
'message',
data+' world!'
);
}
);
ipc.server.on(
'socket.disconnected',
function(data,socket){
console.log('DISCONNECTED\n\n',arguments);
}
);
}
);
ipc.server.on(
'error',
function(err){
ipc.log('Got an ERROR!',err);
}
);
ipc.server.start();
@@ -0,0 +1,46 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'hello';
ipc.config.retry= 1500;
ipc.config.sync= true;
ipc.connectToNet(
'world',
function(){
ipc.of.world.on(
'connect',
function(){
ipc.log('## connected to world ##', ipc.config.delay);
//queue up a bunch of requests to be sent synchronously
for(var i=0; i<10; i++){
ipc.of.world.emit(
'message',
'hello'+i
);
}
}
);
ipc.of.world.on(
'disconnect',
function(){
ipc.log('disconnected from world');
}
);
ipc.of.world.on(
'message',
function(data){
ipc.log('got a message from world : ', data,'\n\n');
}
);
}
);
console.log(ipc);
@@ -0,0 +1,45 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'world';
ipc.config.retry= 1500;
ipc.config.sync = true;
ipc.serveNet(
function(){
ipc.server.on(
'message',
function(data,socket){
ipc.log('got a message : ', data);
//fake some synch procedural code
setTimeout(
function(){
ipc.server.emit(
socket,
'message',
data+' world!'
);
},
3000
);
}
);
ipc.server.on(
'socket.disconnected',
function(data,socket){
console.log(arguments);
}
);
}
);
ipc.server.start();
@@ -0,0 +1,35 @@
const ipc=require('../../../node-ipc');
/***************************************\
*
* You should start both hello and world
* then you will see them communicating.
*
* *************************************/
ipc.config.id = 'hello';
ipc.config.retry= 1500;
ipc.config.rawBuffer=true;
ipc.config.encoding='ascii';
ipc.connectToNet(
'world',
function(){
ipc.of.world.on(
'connect',
function(){
ipc.log('## connected to world ##', ipc.config.delay);
ipc.of.world.emit(
'hello'
);
}
);
ipc.of.world.on(
'data',
function(data){
ipc.log('got a message from world : ', data,data.toString());
}
);
}
);
Loaded 100 of 3448 files, more files were not shown because too many files have changed in this diff. Show more