diff --git a/Animation.js b/Animation.js index 063725ada..d27dc114c 100644 --- a/Animation.js +++ b/Animation.js @@ -131,8 +131,6 @@ function newAnimation () { } function clearBrowserCanvas () { - if (INFO_LOG === true) { logger.write('[INFO] clearBrowserCanvas -> Entering function.') } - browserCanvasContext.beginPath() browserCanvasContext.rect(0, 0, browserCanvas.width, browserCanvas.height) diff --git a/Canvas.js b/Canvas.js index fceef9090..3bc45b757 100644 --- a/Canvas.js +++ b/Canvas.js @@ -9,7 +9,6 @@ function newCanvas () { const MODULE_NAME = 'Canvas' const INFO_LOG = false const ERROR_LOG = true - const INTENSIVE_LOG = false const logger = newWebDebugLog() logger.fileName = MODULE_NAME @@ -37,6 +36,7 @@ function newCanvas () { chartSpace: undefined, floatingSpace: undefined, panelsSpace: undefined, + cockpitSpace: undefined, bottomSpace: undefined, strategySpace: undefined, animation: undefined, @@ -47,44 +47,9 @@ function newCanvas () { thisObject.eventHandler = newEventHandler() let splashScreen - + let lastContainerMouseOver return thisObject -/* - The canvas object represents a layer on top of the browser canvas object. - - Graphically, thiscanvas object has 5 spaces: - - 1. The "Top Space": It is where Team and User information is displayed. - 2. The "Chart Space": It is where the charts are plotted. - 3. The "Floating Space": It is where floating elements live. There is a physics engine for this layer that allows these elements to flow. - 4. The "Panels Space": It is where panels live. --> This space has yet to be develop, currently pannels are somehow at the Chart Space. - 5. The "Bottom Space": Includes UIControls that other panels can add there. - 6. The "Strategy Spece": Functionality to manage Strategies - - All these spaces are child objects of the Canvas object. - - Canvas - | - | - ---> topSpace - | - | - ---> chartSpace - | - | - ---> flaotingSpace - | - | - ---> panelsSpace - | - | - ---> bottomSpace - | - | - ---> strategySpace -*/ - function finalize () { try { if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') } @@ -96,6 +61,7 @@ function newCanvas () { browserCanvas.removeEventListener('mouseup', onMouseUp, false) browserCanvas.removeEventListener('mousemove', onMouseMove, false) browserCanvas.removeEventListener('click', onMouseClick, false) + browserCanvas.removeEventListener('mouseout', onMouseOut, false) /* Mouse wheel events. */ @@ -128,8 +94,8 @@ function newCanvas () { thisObject.strategySpace = newStrategySpace() await thisObject.strategySpace.initialize() - thisObject.bottomSpace = newBottomSpace() - thisObject.bottomSpace.initialize() + thisObject.cockpitSpace = newCockpitSpace() + thisObject.cockpitSpace.initialize() thisObject.panelsSpace = newPanelsSpace() thisObject.panelsSpace.initialize() @@ -140,6 +106,8 @@ function newCanvas () { thisObject.chartSpace = newChartSpace() thisObject.chartSpace.initialize(onCharSpaceInitialized) + thisObject.bottomSpace = thisObject.cockpitSpace + function onCharSpaceInitialized (err) { try { if (INFO_LOG === true) { logger.write('[INFO] initialize -> onCharSpaceInitialized -> Entering function.') } @@ -167,16 +135,18 @@ function newCanvas () { /* Here we add all the functions that will be called during the animation cycle. */ - animation.addCallBackFunction('ViewPort Draw', viewPort.draw, onFunctionAdded) + animation.addCallBackFunction('Floating Space Draw', thisObject.floatingSpace.draw, onFunctionAdded) + animation.addCallBackFunction('Floating Space Physics', thisObject.floatingSpace.physics, onFunctionAdded) animation.addCallBackFunction('Chart Space Background', thisObject.chartSpace.drawBackground, onFunctionAdded) - animation.addCallBackFunction('Chart Space', thisObject.chartSpace.draw, onFunctionAdded) - animation.addCallBackFunction('Floating Space', thisObject.floatingSpace.floatingLayer.physicsLoop, onFunctionAdded) + animation.addCallBackFunction('Chart Space Draw', thisObject.chartSpace.draw, onFunctionAdded) + animation.addCallBackFunction('Chart Space Physics', thisObject.chartSpace.physics, onFunctionAdded) animation.addCallBackFunction('Panels Space', thisObject.panelsSpace.draw, onFunctionAdded) animation.addCallBackFunction('ViewPort Animate', viewPort.animate, onFunctionAdded) - animation.addCallBackFunction('Bottom Space', thisObject.bottomSpace.draw, onFunctionAdded) - animation.addCallBackFunction('Top Space', thisObject.topSpace.draw, onFunctionAdded) - animation.addCallBackFunction('Strategy Space', thisObject.strategySpace.draw, onFunctionAdded) - animation.addCallBackFunction('Splash Screen', splashScreen.draw, onFunctionAdded) + animation.addCallBackFunction('CockpitSpace Draw', thisObject.cockpitSpace.draw, onFunctionAdded) + animation.addCallBackFunction('CockpitSpace Physics', thisObject.cockpitSpace.physics, onFunctionAdded) + animation.addCallBackFunction('Top Space Draw', thisObject.topSpace.draw, onFunctionAdded) + animation.addCallBackFunction('Strategy Space Draw', thisObject.strategySpace.draw, onFunctionAdded) + animation.addCallBackFunction('Splash Screen Draw', splashScreen.draw, onFunctionAdded) animation.start(onStart) function onFunctionAdded (err) { @@ -259,6 +229,7 @@ function newCanvas () { browserCanvas.addEventListener('mouseup', onMouseUp, false) browserCanvas.addEventListener('mousemove', onMouseMove, false) browserCanvas.addEventListener('click', onMouseClick, false) + browserCanvas.addEventListener('mouseout', onMouseOut, false) /* Mouse wheel events. */ @@ -331,9 +302,9 @@ function newCanvas () { return } - /* We check if the mouse is over an element of the Bottom Space / */ + /* We check if the mouse is over an element of the CockpitSpace / */ - container = thisObject.bottomSpace.getContainer(point) + container = thisObject.cockpitSpace.getContainer(point) if (container !== undefined && container.isDraggeable === true) { containerBeingDragged = container @@ -356,26 +327,34 @@ function newCanvas () { return } - /* We check if the mouse is over a floatingObject/ */ - - floatingObjectBeingDragged = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y) - - if (floatingObjectBeingDragged >= 0) { - floatingObjectDragStarted = true - return - } - - /* If it is not, then we check if it is over any of the existing containers at the Chart Space. */ + /* we check if it is over any of the existing containers at the Chart Space. */ container = thisObject.chartSpace.getContainer(point) + if (container !== undefined) { + if (container.isDraggeable === true) { + containerBeingDragged = container + containerDragStarted = true + return + } else { + viewPortBeingDragged = true + return + } + } + + container = thisObject.floatingSpace.getContainer(point) + if (container !== undefined && container.isDraggeable === true) { containerBeingDragged = container containerDragStarted = true + floatingObjectDragStarted = true return } - viewPortBeingDragged = true + 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) } } @@ -414,9 +393,9 @@ function newCanvas () { return } - /* We check if the mouse is over an element of the Bottom Space / */ + /* We check if the mouse is over an element of the CockpitSpace / */ - container = thisObject.bottomSpace.getContainer(point) + container = thisObject.cockpitSpace.getContainer(point) if (container !== undefined && container.isClickeable === true) { container.eventHandler.raiseEvent('onMouseClick', point) @@ -429,17 +408,6 @@ function newCanvas () { if (container !== undefined && container.isClickeable === true) { container.eventHandler.raiseEvent('onMouseClick', point) - return - } - - /* We check if the mouse is over a floatingObject/ */ - - let floatingObjectBeingClicked = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y) - - if (floatingObjectBeingClicked >= 0) { - let floatingObject = thisObject.floatingSpace.floatingLayer.getFloatingObject(undefined, floatingObjectBeingClicked) - floatingObject.eventHandler.raiseEvent('onMouseClick', point) - return } @@ -451,15 +419,36 @@ function newCanvas () { 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 onMouseUp (event) { - try { - if (INFO_LOG === true) { logger.write('[INFO] onMouseUp -> Entering function.') } + 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 deactivateDragging (event) { + try { if (containerDragStarted || viewPortBeingDragged || floatingObjectDragStarted) { thisObject.eventHandler.raiseEvent('Drag Finished', undefined) } @@ -487,8 +476,6 @@ function newCanvas () { function onMouseMove (event) { try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] onMouseMove -> Entering function.') } - let point = { x: event.pageX, y: event.pageY - window.canvasApp.topMargin @@ -499,12 +486,22 @@ function newCanvas () { if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) { if (floatingObjectDragStarted === true) { - if (thisObject.floatingSpace.floatingLayer.isInsideFloatingObject(floatingObjectBeingDragged, point.x, point.y) === false) { - /* This means that the user stop moving the mouse and the floatingObject floatingObject out of the pointer. - In this case we cancell the drag operation . */ - + let targetContainer = thisObject.floatingSpace.getContainer(point) + if (targetContainer !== undefined) { + if (targetContainer.id !== containerBeingDragged.id) { + containerBeingDragged = undefined + containerDragStarted = false + floatingObjectDragStarted = false + browserCanvas.style.cursor = 'auto' + ignoreNextClick = true + return + } + } else { + containerDragStarted = false + containerBeingDragged = undefined floatingObjectDragStarted = false browserCanvas.style.cursor = 'auto' + ignoreNextClick = true return } } @@ -523,12 +520,6 @@ function newCanvas () { function onMouseOver (event) { try { - if (INFO_LOG === true) { logger.write('[INFO] onMouseOver -> Entering function.') } - - /* First we raise the event signaling theat the mouse is potentially over another item, so that the current item can turn itself off. */ - - thisObject.eventHandler.raiseEvent('onMouseNotOver') - /* Then we check who is the current object underneeth the mounse. */ let point = { @@ -540,58 +531,78 @@ function newCanvas () { /* We check if the mouse is over an element of the Strategy Space / */ - container = thisObject.strategySpace.getContainer(point) + if (thisObject.strategySpace !== undefined) { + container = thisObject.strategySpace.getContainer(point) - if (container !== undefined && container.detectMouseOver === true) { - container.eventHandler.raiseEvent('onMouseOver', point) - return + if (container !== undefined && container.detectMouseOver === true) { + containerFound() + return + } } /* We check if the mouse is over an element of the Top Space / */ - container = thisObject.topSpace.getContainer(point) + if (thisObject.topSpace !== undefined) { + container = thisObject.topSpace.getContainer(point) - if (container !== undefined && container.detectMouseOver === true) { - container.eventHandler.raiseEvent('onMouseOver', point) - return + if (container !== undefined && container.detectMouseOver === true) { + containerFound() + return + } } - /* We check if the mouse is over an element of the Bottom Space / */ + /* We check if the mouse is over an element of the CockpitSpace / */ - container = thisObject.bottomSpace.getContainer(point) + if (thisObject.cockpitSpace !== undefined) { + container = thisObject.cockpitSpace.getContainer(point) - if (container !== undefined && container.detectMouseOver === true) { - container.eventHandler.raiseEvent('onMouseOver', point) - return + if (container !== undefined && container.detectMouseOver === true) { + containerFound() + return + } } /* We check if the mouse is over a panel/ */ - container = thisObject.panelsSpace.getContainer(point) + if (thisObject.panelsSpace !== undefined) { + container = thisObject.panelsSpace.getContainer(point) - if (container !== undefined && container.detectMouseOver === true) { - container.eventHandler.raiseEvent('onMouseOver', point) - return - } - - /* We check if the mouse is over a floatingObject/ */ - - let floatingObjectBeingClicked = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y) - - if (floatingObjectBeingClicked >= 0) { - let floatingObject = thisObject.floatingSpace.floatingLayer.getFloatingObject(undefined, floatingObjectBeingClicked) - floatingObject.eventHandler.raiseEvent('onMouseOver', point) - - return + if (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 Chart Space. */ - container = thisObject.chartSpace.getContainer(point, GET_CONTAINER_PURPOSE.MOUSE_OVER) + if (thisObject.chartSpace !== undefined) { + container = thisObject.chartSpace.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) + } + } - if (container !== undefined && container.detectMouseOver === true) { container.eventHandler.raiseEvent('onMouseOver', point) - return + lastContainerMouseOver = container } } catch (err) { if (ERROR_LOG === true) { logger.write('[ERROR] onMouseOver -> err = ' + err.stack) } @@ -614,45 +625,46 @@ function newCanvas () { } event.mousePosition = point + let container + container = canvas.panelsSpace.getContainer({ x: point.x, y: point.y }) - let panelContainer = canvas.panelsSpace.getContainer({ x: point.x, y: point.y }) - - if (panelContainer !== undefined && panelContainer.isWheelable === true) { - panelContainer.eventHandler.raiseEvent('Mouse Wheel', event) + 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 second with floating objects. */ + /* We try the CockpitSpace. */ - let floatingObjectIndex = canvas.floatingSpace.floatingLayer.isInside(point.x, point.y) + container = canvas.cockpitSpace.getContainer({ x: point.x, y: point.y }) - if (floatingObjectIndex > 0) { - canvas.floatingSpace.floatingLayer.changeTargetRepulsion(event.wheelDelta) + 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 Bottom Space. */ + /* Chart Space. */ - let bottomContainer = canvas.bottomSpace.getContainer({ x: point.x, y: point.y }) - - if (bottomContainer !== undefined && bottomContainer.isWheelable === true) { - bottomContainer.eventHandler.raiseEvent('Mouse Wheel', event) + container = canvas.chartSpace.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. } - /* Finally we try the Chart Space. */ - - let chartContainer = canvas.chartSpace.getContainer({ x: point.x, y: point.y }, GET_CONTAINER_PURPOSE.MOUSE_WHEEL) - - if (chartContainer !== undefined && chartContainer.isWheelable === true) { - chartContainer.eventHandler.raiseEvent('Mouse Wheel', event) - return false // This instructs the browser not to take the event and scroll the page. - } else { - /* If all the above fails, we fallback into applying zoom to the viewPort */ - + if (container !== undefined) { viewPort.applyZoom(delta) + 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) } } @@ -660,8 +672,6 @@ function newCanvas () { function checkDrag (event) { try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] checkDrag -> Entering function.') } - if (containerDragStarted === true || floatingObjectDragStarted === true || viewPortBeingDragged === true) { let point = { x: event.pageX, @@ -671,15 +681,6 @@ function newCanvas () { browserCanvas.style.cursor = 'grabbing' thisObject.eventHandler.raiseEvent('Dragging', undefined) - let targetFloatingObject = thisObject.floatingSpace.floatingLayer.isInside(point.x, point.y) - - if (floatingObjectDragStarted) { - let floatingObject = thisObject.floatingSpace.floatingLayer.getFloatingObject(undefined, floatingObjectBeingDragged) - - floatingObject.currentPosition.x = dragVector.upX - floatingObject.currentPosition.y = dragVector.upY - } - if (containerDragStarted || viewPortBeingDragged) { /* The parameters received have been captured with zoom applied. We must remove the zoom in order to correctly modify the displacement. */ @@ -710,8 +711,10 @@ function newCanvas () { } if (containerBeingDragged !== undefined) { - containerBeingDragged.frame.position.x = containerBeingDragged.frame.position.x + displaceVector.x - containerBeingDragged.frame.position.y = containerBeingDragged.frame.position.y + displaceVector.y + let moveSucceed = containerBeingDragged.displace(displaceVector) + if (moveSucceed === false) { + deactivateDragging(event) + } } } diff --git a/ChartUtilities.js b/ChartsSpace/ChartUtilities.js similarity index 100% rename from ChartUtilities.js rename to ChartsSpace/ChartUtilities.js diff --git a/PlottersManager.js b/ChartsSpace/PlottersManager.js similarity index 99% rename from PlottersManager.js rename to ChartsSpace/PlottersManager.js index 99e544dcb..dd693d6d6 100644 --- a/PlottersManager.js +++ b/ChartsSpace/PlottersManager.js @@ -221,7 +221,7 @@ function newPlottersManager () { let plotter = getNewPlotter(competition.plotter.host, competition.plotter.codeName, competition.plotter.moduleName) - plotter.container.connectToParent(thisObject.container, true, true) + plotter.container.connectToParent(thisObject.container, true, true, false, true, true, 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 @@ -285,7 +285,7 @@ function newPlottersManager () { botAvatar.src = window.canvasApp.context.fbProfileImages.get(TEAM + '-' + BOT) - competitionPlotter.plotter.payload[k].profile.downLabel = bot.displayName + competitionPlotter.plotter.payload[k].profile.title = bot.displayName competitionPlotter.plotter.payload[k].profile.imageId = imageId competitionPlotter.plotter.payload[k].profile.botAvatar = botAvatar @@ -463,7 +463,7 @@ function newPlottersManager () { let plotter = getNewPlotter(pProductCard.product.plotter.devTeam, pProductCard.product.plotter.codeName, pProductCard.product.plotter.moduleName) - plotter.container.connectToParent(thisObject.container, true, true) + plotter.container.connectToParent(thisObject.container, true, true, false, true, true, 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 @@ -525,8 +525,8 @@ function newPlottersManager () { if (productPlotter.plotter.payload !== undefined) { let imageId = pProductCard.bot.devTeam + '.' + pProductCard.bot.profilePicture - productPlotter.plotter.payload.profile.upLabel = pProductCard.product.shortDisplayName - productPlotter.plotter.payload.profile.downLabel = pProductCard.bot.displayName + productPlotter.plotter.payload.profile.subTitle = pProductCard.product.shortDisplayName + productPlotter.plotter.payload.profile.title = pProductCard.bot.displayName productPlotter.plotter.payload.profile.imageId = imageId productPlotter.plotter.payload.profile.botAvatar = pProductCard.bot.avatar diff --git a/TimeLineCoordinateSystem.js b/ChartsSpace/TimeLineCoordinateSystem.js similarity index 100% rename from TimeLineCoordinateSystem.js rename to ChartsSpace/TimeLineCoordinateSystem.js diff --git a/TimeMachine.js b/ChartsSpace/TimeMachine.js similarity index 84% rename from TimeMachine.js rename to ChartsSpace/TimeMachine.js index d25a9aaa1..b5a373126 100644 --- a/TimeMachine.js +++ b/ChartsSpace/TimeMachine.js @@ -1,4 +1,4 @@ - /* +/* 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. @@ -37,7 +37,7 @@ function newTimeMachine () { thisObject.container.frame.position.y = browserCanvas.height / 2 - TIME_MACHINE_HEIGHT / 2 let controlPanelHandle // We need this to destroy the Panel when this object is itself destroyed or no longer needs it... - // ... also to request a reference to the object for the cases we need it. + // ... also to request a reference to the object for the cases we need it. const SEPARATION_BETWEEN_TIMELINE_CHARTS = 1.5 let timeScale @@ -63,7 +63,7 @@ function newTimeMachine () { function initialize (callBackFunction) { if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } - /* Each Time Machine has a Control Panel. */ + /* Each Time Machine has a Control Panel. */ let panelOwner = 'Global' controlPanelHandle = canvas.panelsSpace.createNewPanel('Time Control Panel', undefined, panelOwner) @@ -76,13 +76,13 @@ function newTimeMachine () { moveToUserPosition(thisObject.container, timeLineCoordinateSystem, false, false, event.mousePosition) }) - /* First, we initialize the market that we are going to show first on screen. Later all the other markets will be initialized on the background. */ + /* First, we initialize the market that we are going to show first on screen. Later all the other markets will be initialized on the background. */ let position = 0 // This defines the position of each chart respect to each other. let timelineChart = newTimelineChart() - timelineChart.container.connectToParent(thisObject.container, true, true) + timelineChart.container.connectToParent(thisObject.container, true, true, false, true, true, true) timelineChart.container.frame.height = thisObject.container.frame.height timelineChart.container.frame.position.x = thisObject.container.frame.width / 2 - timelineChart.container.frame.width / 2 @@ -103,10 +103,10 @@ function newTimeMachine () { controlPanel.container.eventHandler.listenToEvent('Datetime Changed', timelineChart.setDatetime, undefined) timelineChart.container.eventHandler.listenToEvent('Datetime Changed', controlPanel.setDatetime) - /* Each Time Machine has a Time Scale and a Right Scale. */ + /* Each Time Machine has a Time Scale and a Right Scale. */ timeScale = newTimeScale() - timeScale.container.connectToParent(thisObject.container, false, false) + timeScale.container.connectToParent(thisObject.container, false, false, false, true, true, true) timeScale.container.eventHandler.listenToEvent('Lenght Percentage Changed', function (event) { thisObject.container.frame.width = TIME_MACHINE_WIDTH * event.lenghtPercentage / 100 thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event) @@ -115,7 +115,7 @@ function newTimeMachine () { timeScale.initialize(timeLineCoordinateSystem) rigthScale = newRateScale() - rigthScale.container.connectToParent(thisObject.container, false, false) + rigthScale.container.connectToParent(thisObject.container, false, false, false, true, true, true) rigthScale.container.eventHandler.listenToEvent('Height Percentage Changed', function (event) { thisObject.container.frame.height = TIME_MACHINE_HEIGHT * event.heightPercentage / 100 thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event) @@ -143,10 +143,10 @@ function newTimeMachine () { let market = SUPPORTED_MARKETS[j] if ( - exchange === DEFAULT_EXCHANGE && - market.assetA === DEFAULT_MARKET.assetA && - market.assetB === DEFAULT_MARKET.assetB - ) { continue } + exchange === DEFAULT_EXCHANGE && + market.assetA === DEFAULT_MARKET.assetA && + market.assetB === DEFAULT_MARKET.assetB + ) { continue } initializeTimelineChart(exchange, market) } @@ -157,7 +157,7 @@ function newTimeMachine () { let timelineChart = newTimelineChart() - timelineChart.container.connectToParent(thisObject.container, true, true) + timelineChart.container.connectToParent(thisObject.container, true, true, false, true, true, true) timelineChart.container.frame.height = thisObject.container.frame.height @@ -186,27 +186,6 @@ function newTimeMachine () { } } - function drawBackground () { - for (let i = 0; i < this.charts.length; i++) { - let chart = this.charts[i] - chart.drawBackground() - } - } - - function draw () { - if (thisObject.container.frame.isInViewPort()) { - for (let i = 0; i < this.charts.length; i++) { - let chart = this.charts[i] - chart.draw() - } - - if (timeScale !== undefined) { timeScale.draw() } - if (rigthScale !== undefined) { rigthScale.draw() } - - // thisObject.container.frame.draw(false, true, false) - } - } - function getContainer (point, purpose) { let container @@ -232,7 +211,9 @@ function newTimeMachine () { container = this.charts[i].getContainer(point) if (container !== undefined) { if (container.isForThisPurpose(purpose)) { - return container + if (thisObject.container.frame.isThisPointHere(point) === true) { + return container + } } } } @@ -247,6 +228,46 @@ function newTimeMachine () { } } + function drawBackground () { + thisBackground() + + if (thisObject.container.frame.isInViewPort()) { + for (let i = 0; i < this.charts.length; i++) { + let chart = this.charts[i] + chart.drawBackground() + } + } + } + + function draw () { + if (thisObject.container.frame.isInViewPort()) { + for (let i = 0; i < this.charts.length; i++) { + let chart = this.charts[i] + chart.draw() + } + + if (timeScale !== undefined) { timeScale.draw() } + if (rigthScale !== undefined) { rigthScale.draw() } + + // thisObject.container.frame.draw(false, true, false) + } + } + + function thisBackground () { + let params = { + cornerRadius: 15, + lineWidth: 5, + opacity: 1, + container: thisObject.container, + borderColor: UI_COLOR.RUSTED_RED, + backgroundColor: UI_COLOR.WHITE, + fitFunction: thisObject.fitFunction, + coordinateSystem: timeLineCoordinateSystem + } + + roundedCornersBackground(params) + } + function recalculateScale () { if (INFO_LOG === true) { logger.write('[INFO] recalculateScale -> Entering function.') } @@ -261,10 +282,10 @@ function newTimeMachine () { } timeLineCoordinateSystem.initialize( - minValue, - maxValue, - thisObject.container.frame.width, - thisObject.container.frame.height - ) + minValue, + maxValue, + thisObject.container.frame.width, + thisObject.container.frame.height + ) } } diff --git a/ChartsSpace/TimelineChart.js b/ChartsSpace/TimelineChart.js new file mode 100644 index 000000000..f9d1aad60 --- /dev/null +++ b/ChartsSpace/TimelineChart.js @@ -0,0 +1,511 @@ +function newTimelineChart () { + const MODULE_NAME = 'Timeline Chart' + const INFO_LOG = false + const INTENSIVE_LOG = false + const ERROR_LOG = true + const logger = newWebDebugLog() + logger.fileName = MODULE_NAME + + let timeLineCoordinateSystem + + let timePeriod = INITIAL_TIME_PERIOD + let datetime = NEW_SESSION_INITIAL_DATE + + let thisObject = { + container: undefined, + fitFunction: undefined, + setDatetime: setDatetime, + drawBackground: drawBackground, + draw: draw, + getContainer: getContainer, + initialize: initialize, + finalize: finalize + } + + thisObject.container = newContainer() + thisObject.container.initialize(MODULE_NAME) + thisObject.container.detectMouseOver = true + + thisObject.fitFunction = canvas.chartSpace.fitIntoVisibleArea + + let initializationReady = false + + let productsPanel + + /* Background */ + let logoAssetA + let logoAssetB + let logoExchange + let logoAA + let canDrawLogoA = false + let canDrawLogoB = false + let canDrawLogoExchange = false + let canDrawLogoAA = false + + let plotterManager + let exchange + let market + + let productsPanelHandle + let timePeriodScale + + return thisObject + + function finalize () { + try { + if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') } + + plotterManager.finalize() + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) } + } + } + + function initialize (pExchange, pMarket, pTimeLineCoordinateSystem, callBackFunction) { + try { + if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } + + /* We load the logow we will need for the background. */ + exchange = pExchange + market = pMarket + timeLineCoordinateSystem = pTimeLineCoordinateSystem + + thisObject.container.eventHandler.listenToEvent('onMouseOver', function (event) { + saveUserPosition(thisObject.container, timeLineCoordinateSystem, event) + }) + + let panelOwner = exchange + ' ' + market.assetB + '/' + market.assetA + productsPanelHandle = canvas.panelsSpace.createNewPanel('Products Panel', undefined, panelOwner) + let productsPanel = canvas.panelsSpace.getPanel(productsPanelHandle, panelOwner) + productsPanel.initialize(exchange, market) + + logoA = new Image() + logoB = new Image() + logoExchange = new Image() + logoAA = new Image() + + logoA.onload = onImageALoaded + + function onImageALoaded () { + canDrawLogoA = true + } + + logoB.onload = onImageBLoaded + + function onImageBLoaded () { + canDrawLogoB = true + } + + logoExchange.onload = onImageExchangeLoaded + + function onImageExchangeLoaded () { + canDrawLogoExchange = true + } + + logoAA.onload = onImageAALoaded + + function onImageAALoaded () { + canDrawLogoAA = true + } + + logoA.src = window.canvasApp.urlPrefix + 'Images/tether-logo-background.png' + logoB.src = window.canvasApp.urlPrefix + 'Images/bitcoin-logo-background.png' + logoExchange.src = window.canvasApp.urlPrefix + 'Images/' + exchange + '-logo-background.png' + logoAA.src = window.canvasApp.urlPrefix + 'Images/sa-logo-background.png' + + // moveToUserPosition(thisObject.container, timeLineCoordinateSystem, undefined, undefined, undefined, true) + timePeriod = INITIAL_TIME_PERIOD + datetime = NEW_SESSION_INITIAL_DATE + + /* Event Subscriptions - we need this events to be fired first here and then in active Plotters. */ + + viewPort.eventHandler.listenToEvent('Offset Changed', onOffsetChanged) + viewPort.eventHandler.listenToEvent('Zoom Changed', onZoomChanged) + + /* Initialize the Plotter Manager */ + + plotterManager = newPlottersManager() + + plotterManager.container.connectToParent(thisObject.container, true, true, false, true, true, true) + + plotterManager.container.frame.position.x = 0 + plotterManager.container.frame.position.y = 0 + + plotterManager.initialize(productsPanel, pExchange, pMarket, onPlotterManagerReady) + + function onPlotterManagerReady (err) { + if (INFO_LOG === true) { logger.write('[INFO] initialize -> onPlotterManagerReady -> Entering function.') } + + if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { + if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> onPlotterManagerReady -> Plotter Manager Initialization Failed. ') } + if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> onPlotterManagerReady -> err= ' + err.stack) } + + callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) + return + } + + timePeriodScale = newTimePeriodScale() + timePeriodScale.container.connectToParent(thisObject.container, false, false, false, true, true, true) + timePeriodScale.container.eventHandler.listenToEvent('Time Period Changed', function (event) { + let currentTimePeriod = timePeriod + timePeriod = event.timePeriod + if (timePeriod !== currentTimePeriod) { + plotterManager.setTimePeriod(timePeriod) + } + }) + + timePeriodScale.initialize(timeLineCoordinateSystem) + + initializationReady = true + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) + return + } + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) } + callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) + } + } + + function onZoomChanged (event) { + if (INFO_LOG === true) { logger.write('[INFO] onZoomChanged -> Entering function.') } + + if (initializationReady === true) { + recalculateCurrentDatetime() + + // saveUserPosition(thisObject.container, timeLineCoordinateSystem) + } + } + + function setDatetime (pDatetime) { + if (INFO_LOG === true) { logger.write('[INFO] setDatetime -> Entering function.') } + + /* This function is used when the time is changed through the user interface, but without zooming or panning. */ + /* No matter if the day changed or not, we need to inform all visible Plotters. */ + + if (thisObject.container.frame.isInViewPort()) { + plotterManager.setDatetime(pDatetime) + plotterManager.positionAtDatetime(pDatetime) + } + } + + function onOffsetChanged () { + if (INFO_LOG === true) { logger.write('[INFO] onOffsetChanged -> Entering function.') } + + if (initializationReady === true) { + if (thisObject.container.frame.isInViewPort()) { + recalculateCurrentDatetime() + // saveUserPosition(thisObject.container, timeLineCoordinateSystem) + } + } + } + + function recalculateCurrentDatetime () { + if (INFO_LOG === true) { logger.write('[INFO] recalculateCurrentDatetime -> Entering function.') } + + /* + + 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: (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.bottomLeft.x) / 2, + y: (viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topRight.y) / 2 + } + + center = unTransformThisPoint(center, thisObject.container) + center = timeLineCoordinateSystem.unInverseTransform(center, thisObject.container.frame.height) + + let newDate = new Date(0) + newDate.setUTCSeconds(center.x / 1000) + + datetime = newDate + + plotterManager.setDatetime(datetime) + + thisObject.container.eventHandler.raiseEvent('Datetime Changed', datetime) + } + + function getContainer (point) { + if (INFO_LOG === true) { logger.write('[INFO] getContainer -> Entering function.') } + + let container + + container = timePeriodScale.getContainer(point) + + if (container !== undefined) { return container } + + return container + } + + function tooTiny () { + if (viewPort.zoomLevel < Math.trunc(-28.25 * 100) / 100) { + return true + } else { + return false + } + } + + function tooSmall () { + if (viewPort.zoomLevel < Math.trunc(-27.25 * 100) / 100) { + return true + } else { + return false + } + } + + function drawBackground () { + if (thisObject.container.frame.isInViewPort()) { + if (window.CHART_ON_FOCUS === '') { + window.CHART_ON_FOCUS = exchange + ' ' + market.assetB + '/' + market.assetA + + drawChartsBackgroundImages() + } + } + } + + function draw () { + if (thisObject.container.frame.isInViewPort()) { + drawChartsBackground() + plotterManager.draw() + timePeriodScale.draw() + } + } + + function drawChartsBackground () { + /* We will paint some transparent background here. */ + + let opacity = '0.9' + + let fromPoint = { + x: 0, + y: 0 + } + + let toPoint = { + x: thisObject.container.frame.width, + y: thisObject.container.frame.height + } + + fromPoint = transformThisPoint(fromPoint, thisObject.container) + toPoint = transformThisPoint(toPoint, thisObject.container) + + fromPoint = canvas.chartSpace.fitIntoVisibleArea(fromPoint) + toPoint = canvas.chartSpace.fitIntoVisibleArea(toPoint) + + 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() + } + + function drawChartsBackgroundImages () { + if (canDrawLogoA === false || canDrawLogoB === false || canDrawLogoExchange === false || canDrawLogoAA === false) { return } + + /* Fist we calculate the corners of the current frame so as not to draw imaages ourside of it */ + + let fromPoint = { + x: 0, + y: 0 + } + + let toPoint = { + x: thisObject.container.frame.width, + y: thisObject.container.frame.height + } + + fromPoint = transformThisPoint(fromPoint, thisObject.container) + toPoint = transformThisPoint(toPoint, thisObject.container) + + /* Second we calculate the points for the images themselves */ + + let backgroundLogoPoint1 + let backgroundLogoPoint2 + + let imageHeight = 42 + let imageWidth = 150 + + const MAX_COLUMNS = 16 + const MAX_ROWS = 5 + const Y_TOP_MARGIN = 30 + const MIN_ROW_HIGHT = 100 + + let point1 = { + x: viewPort.visibleArea.topLeft.x, + y: viewPort.visibleArea.topLeft.y + } + + backgroundLogoPoint1 = { + x: getDateFromPoint(point1, thisObject.container, timeLineCoordinateSystem).valueOf(), + y: getRateFromPoint(point1, thisObject.container, timeLineCoordinateSystem) + } + + let point2 = { + x: viewPort.visibleArea.topLeft.x + imageWidth * 8, + y: viewPort.visibleArea.topLeft.y + } + + backgroundLogoPoint2 = { + x: getDateFromPoint(point2, thisObject.container, timeLineCoordinateSystem).valueOf(), + y: getRateFromPoint(point2, thisObject.container, timeLineCoordinateSystem) + } + + let currentCorner = { + x: getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, timeLineCoordinateSystem).valueOf(), + y: getRateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, timeLineCoordinateSystem) + } + + currentCorner.x = Math.trunc(currentCorner.x / (backgroundLogoPoint2.x - backgroundLogoPoint1.x)) * (backgroundLogoPoint2.x - backgroundLogoPoint1.x) + + let rowHight = (viewPort.visibleArea.bottomLeft.y - viewPort.visibleArea.topLeft.y) / 4.5 + if (rowHight < MIN_ROW_HIGHT) { rowHight = MIN_ROW_HIGHT } + + imagePoint = timeLineCoordinateSystem.transformThisPoint(currentCorner) + imagePoint = transformThisPoint(imagePoint, thisObject.container) + + let offSet = 0 + let imagePosition = { + x: 0, + y: 0 + } + + for (let j = 0; j < MAX_ROWS; j++) { + if (offSet === -imageWidth * 8) { + offSet = -imageWidth * 4 - imageWidth + } else { + offSet = -imageWidth * 8 + } + + for (let i = 0; i < MAX_COLUMNS; i = i + 4) { + let logo = logoA + + imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet + imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN + + if ( + imagePosition.x > fromPoint.x && + imagePosition.x + imageWidth < toPoint.x && + imagePosition.y > fromPoint.y && + imagePosition.y + imageHeight < toPoint.y + ) { + let checkPoint = { + x: imagePosition.x, + y: imagePosition.y + imageHeight + } + + checkPoint = thisObject.fitFunction(checkPoint) + if (checkPoint.y === imagePosition.y + imageHeight) { + browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) + } + } + } + } + + offSet = 0 + + for (let j = 0; j < MAX_ROWS; j++) { + if (offSet === -imageWidth * 8) { + offSet = -imageWidth * 4 - imageWidth + } else { + offSet = -imageWidth * 8 + } + + for (let i = 1; i < MAX_COLUMNS; i = i + 4) { + let logo = logoB + + imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet + imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN + + if ( + imagePosition.x > fromPoint.x && + imagePosition.x + imageWidth < toPoint.x && + imagePosition.y > fromPoint.y && + imagePosition.y + imageHeight < toPoint.y + ) { + let checkPoint = { + x: imagePosition.x, + y: imagePosition.y + imageHeight + } + + checkPoint = thisObject.fitFunction(checkPoint) + if (checkPoint.y === imagePosition.y + imageHeight) { + browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) + } + } + } + } + + offSet = 0 + + for (let j = 0; j < MAX_ROWS; j++) { + if (offSet === -imageWidth * 8) { + offSet = -imageWidth * 4 - imageWidth + } else { + offSet = -imageWidth * 8 + } + + for (let i = 2; i < MAX_COLUMNS; i = i + 4) { + let logo = logoExchange + + imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet + imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN + + if ( + imagePosition.x > fromPoint.x && + imagePosition.x + imageWidth < toPoint.x && + imagePosition.y > fromPoint.y && + imagePosition.y + imageHeight < toPoint.y + ) { + let checkPoint = { + x: imagePosition.x, + y: imagePosition.y + imageHeight + } + + checkPoint = thisObject.fitFunction(checkPoint) + if (checkPoint.y === imagePosition.y + imageHeight) { + browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) + } + } + } + } + + offSet = 0 + + for (let j = 0; j < MAX_ROWS; j++) { + if (offSet === -imageWidth * 8) { + offSet = -imageWidth * 4 - imageWidth + } else { + offSet = -imageWidth * 8 + } + + for (let i = 3; i < MAX_COLUMNS; i = i + 4) { + let logo = logoAA + + imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet + imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN + + if ( + imagePosition.x > fromPoint.x && + imagePosition.x + imageWidth < toPoint.x && + imagePosition.y > fromPoint.y && + imagePosition.y + imageHeight < toPoint.y + ) { + let checkPoint = { + x: imagePosition.x, + y: imagePosition.y + imageHeight + } + + checkPoint = thisObject.fitFunction(checkPoint) + if (checkPoint.y === imagePosition.y + imageHeight) { + browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) + } + } + } + } + } +} diff --git a/ViewPort.js b/ChartsSpace/ViewPort.js similarity index 94% rename from ViewPort.js rename to ChartsSpace/ViewPort.js index 70d4aeae1..264c5b07b 100644 --- a/ViewPort.js +++ b/ChartsSpace/ViewPort.js @@ -10,11 +10,12 @@ function newViewPort () { const CONSOLE_LOG = true let ANIMATION_INCREMENT = 0.25 - const TOP_MARGIN = 15 + TOP_SPACE_HEIGHT - const BOTTOM_MARGIN = 15 + BOTTOM_SPACE_HEIGHT - const LEFT_MARGIN = 50 - const RIGHT_MARGIN = 50 - const MARGINS = { + + let TOP_MARGIN = 15 + TOP_SPACE_HEIGHT + let BOTTOM_MARGIN = 20 + COCKPIT_SPACE_HEIGHT + let LEFT_MARGIN = 50 + let RIGHT_MARGIN = 50 + let MARGINS = { TOP: TOP_MARGIN, BOTTOM: BOTTOM_MARGIN, LEFT: LEFT_MARGIN, @@ -23,6 +24,8 @@ function newViewPort () { let thisObject = { visibleArea: undefined, + width: undefined, + height: undefined, eventHandler: undefined, zoomTargetLevel: undefined, zoomLevel: undefined, @@ -42,6 +45,7 @@ function newViewPort () { animate: animate, draw: draw, raiseEvents: raiseEvents, + resize: resize, initialize: initialize } @@ -74,6 +78,22 @@ function newViewPort () { return thisObject function initialize () { + resize() + readObjectState() + } + + function resize () { + TOP_MARGIN = 15 + TOP_SPACE_HEIGHT + BOTTOM_MARGIN = 20 + browserCanvas.height - COCKPIT_SPACE_POSITION + LEFT_MARGIN = 50 + RIGHT_MARGIN = 50 + 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 }, @@ -81,7 +101,8 @@ function newViewPort () { bottomLeft: { x: LEFT_MARGIN, y: browserCanvas.height - BOTTOM_MARGIN} } - readObjectState() + thisObject.width = thisObject.visibleArea.topRight.x - thisObject.visibleArea.topLeft.x + thisObject.height = thisObject.visibleArea.bottomRight.y - thisObject.visibleArea.topLeft.y } function getDisplacement () { diff --git a/CockpitSpace/AssetBalances.js b/CockpitSpace/AssetBalances.js new file mode 100644 index 000000000..5b7db2c35 --- /dev/null +++ b/CockpitSpace/AssetBalances.js @@ -0,0 +1,122 @@ + +function newAssetBalances () { + 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.container.frame.position.x = thisObject.container.frame.width / 2 - speedometer.container.frame.width / 2 + speedometer.container.frame.position.y = thisObject.container.frame.height / 2 - speedometer.container.frame.height / 2 + + 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() + } + + drawAssetBalances() + } + + function drawAssetBalances () { + 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 + + 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) + } +} diff --git a/CockpitSpace/Speedometer.js b/CockpitSpace/Speedometer.js new file mode 100644 index 000000000..e93c434ba --- /dev/null +++ b/CockpitSpace/Speedometer.js @@ -0,0 +1,237 @@ + +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 = 5 + const RADIOUS = 50 + const OPACITY = 1 + + let centerPoint = { + x: thisObject.params.LEFT_OFFSET, + y: COCKPIT_SPACE_POSITION - COCKPIT_SPACE_HEIGHT / 2 + } + + browserCanvasContext.beginPath() + browserCanvasContext.arc(centerPoint.x, centerPoint.y, RADIOUS + 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, RADIOUS, 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_RADIOUS = RADIOUS * 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 (thisObject.params.VALUE > 0) { + browserCanvasContext.setLineDash([0, 0]) + + browserCanvasContext.beginPath() + browserCanvasContext.arc(centerPoint.x, centerPoint.y, BAR_RADIOUS, 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_RADIOUS, 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_RADIOUS, 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_RADIOUS, 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_RADIOUS, 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_RADIOUS, 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_RADIOUS, 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_RADIOUS, 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 + + browserCanvasContext.font = 'bold ' + fontSize + 'px ' + UI_FONT.PRIMARY + + label = thisObject.params.VALUE + if (isNaN(label) === false) { + label = Number(label) + if (label === 0) { label = label.toFixed(2) } else { label = label.toLocaleString() } + } + + label = label.substring(0, 5) + + 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 + } + + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', ' + OPACITY + ')' + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) + } +} + diff --git a/CompetitionStorage.js b/CompetitionStorage.js index aebec6a93..b10a06b2a 100644 --- a/CompetitionStorage.js +++ b/CompetitionStorage.js @@ -94,7 +94,7 @@ function newCompetitionStorage (pName) { case GLOBAL.CUSTOM_FAIL_RESPONSE.result: { if (INFO_LOG === true) { logger.write('[INFO] initialize -> onFileSequenceReady -> Received CUSTOM FAIL Response.') } - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onFileSequenceReady -> err.message = ' + err.message) } + if (INFO_LOG === true) { logger.write('[INFO] initialize -> onFileSequenceReady -> err= ' + err.stack) } if (INFO_LOG === true) { logger.write('[INFO] initialize -> onFileSequenceReady -> This bot has not starting competing yet.') } break diff --git a/Container.js b/Container.js index cacb0bec1..2b467470f 100644 --- a/Container.js +++ b/Container.js @@ -1,14 +1,22 @@ function newContainer () { let thisObject = { + id: Math.trunc(Math.random() * 10000000), + type: 'Rectangle', frame: undefined, displacement: 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, @@ -17,11 +25,23 @@ function newContainer () { 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 isConnectedToParent = false let dimensionsChangedEventSubscriptionId let onMouseOverEventSubscriptionId let onMouseNotOverEventSubscriptionId + let onFocusEventSubscriptionId + let onNotFocusEventSubscriptionId + let onDisplaceEventSubscriptionId return thisObject @@ -30,14 +50,21 @@ function newContainer () { 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 = undefined + thisObject.eventHandler.finalize() } } - function initialize (pName) { + function initialize (pName, pType) { thisObject.name = pName + thisObject.type = pType thisObject.frame = newFrame() - thisObject.frame.initialize() + thisObject.frame.initialize(pType) thisObject.frame.containerName = pName thisObject.frame.container = thisObject @@ -49,18 +76,53 @@ function newContainer () { thisObject.displacement.containerName = pName } - function connectToParent (parentContainer, onWidth, onHeight) { + function connectToParent ( + parentContainer, + onWidth, + onHeight, + onRadius, + onDimmensionsChangedEvent, + onMouseOverEvent, + onMouseNotOverEvent, + onFocusEvent, + onNotFocusEvent, + onDisplaceEvent + ) { connectedToParentWidth = onWidth connectedToParentHeight = onHeight + connectedToParentRadius = onRadius + + onDimmensionsChangedParentEvent = onDimmensionsChangedEvent + onMouseOverParentEvent = onMouseOverEvent + onMouseNotOverParentEvent = onMouseNotOverEvent + onFocusParentEvent = onFocusEvent + onNotFocusParentEvent = onNotFocusEvent + onDisplaceParentEvent = onDisplaceEvent + isConnectedToParent = true thisObject.displacement.parentDisplacement = parentContainer.displacement thisObject.frame.parentFrame = parentContainer.frame thisObject.parentContainer = parentContainer - dimensionsChangedEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('Dimmensions Changed', onParentDimmensionsChanged) - onMouseOverEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onMouseOver', onMouseOver) - onMouseNotOverEventSubscriptionId = thisObject.parentContainer.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver) + 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 (connectedToParentWidth) { thisObject.frame.width = thisObject.parentContainer.frame.width @@ -68,6 +130,9 @@ function newContainer () { if (connectedToParentHeight) { thisObject.frame.height = thisObject.parentContainer.frame.height } + if (connectedToParentRadius) { + thisObject.frame.radius = thisObject.parentContainer.frame.radius + } } function onParentDimmensionsChanged (event) { @@ -80,6 +145,10 @@ function newContainer () { 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) @@ -94,6 +163,18 @@ function newContainer () { 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 isForThisPurpose (purpose) { if (purpose !== undefined) { switch (purpose) { @@ -118,4 +199,37 @@ function newContainer () { } 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) + } + } } diff --git a/ControlsToolBox/SidePanel.js b/ControlsToolBox/SidePanel.js index 6b68073e3..c6f0e772a 100644 --- a/ControlsToolBox/SidePanel.js +++ b/ControlsToolBox/SidePanel.js @@ -9,9 +9,6 @@ function newSidePanel () { initialize: initialize } - const SIDE_PANEL_WIDTH = 450 - const SIDE_PANEL_TAB_WIDTH = 400 - let isInitialized = false thisObject.container = newContainer() diff --git a/EventHandler.js b/EventHandler.js index ad843afeb..da29745a9 100644 --- a/EventHandler.js +++ b/EventHandler.js @@ -4,13 +4,18 @@ function newEventHandler () { name: undefined, // This is for debugging purposes only. listenToEvent: listenToEvent, stopListening: stopListening, - raiseEvent: raiseEvent + raiseEvent: raiseEvent, + finalize: finalize } - var eventHandlers = [] // Here we store all the functions we will call when an event is raiseed. + 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]) diff --git a/FloatingSpace/CircularMenu.js b/FloatingSpace/CircularMenu.js new file mode 100644 index 000000000..d79c9c099 --- /dev/null +++ b/FloatingSpace/CircularMenu.js @@ -0,0 +1,134 @@ + +function newCircularMenu () { + const MODULE_NAME = 'Circular Menu' + + 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 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 */ + + for (let i = 0; i < menuItemsInitialValues.length; i++) { + let menuItem = newCircularMenuItem() + let menuItemInitialValue = menuItemsInitialValues[i] + + menuItem.action = menuItemInitialValue.action + menuItem.actionFunction = menuItemInitialValue.actionFunction + menuItem.label = menuItemInitialValue.label + menuItem.workingLabel = menuItemInitialValue.workingLabel + menuItem.workDoneLabel = menuItemInitialValue.workDoneLabel + menuItem.workFailedLabel = menuItemInitialValue.workFailedLabel + 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.relatedStrategyPart = menuItemInitialValue.relatedStrategyPart + + if (menuItem.label === undefined) { + menuItem.type = 'Icon Only' + } else { + menuItem.type = 'Icon & Text' + } + + menuItem.initialize(payload) + menuItem.container.connectToParent(thisObject.container, false, false, true, true, false, false, true, true) + menuItems.push(menuItem) + } + + 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 menutItem = menuItems[i] + container = menutItem.getContainer(point) + if (container !== undefined) { return container } + } + } + } + + function physics () { + for (let i = 0; i < menuItems.length; i++) { + let menutItem = menuItems[i] + menutItem.physics() + } + } + + function onFocus () { + for (let i = 0; i < menuItems.length; i++) { + let menutItem = menuItems[i] + menutItem.targetRadius = menutItem.rawRadius * 1.5 + menutItem.isDeployed = true + } + thisObject.isDeployed = true + } + + function onNotFocus () { + for (let i = 0; i < menuItems.length; i++) { + let menutItem = menuItems[i] + menutItem.targetRadius = menutItem.rawRadius * 0 - i * 5 + menutItem.isDeployed = false + } + thisObject.isDeployed = false + } + + function drawBackground (pFloatingObject) { + for (let i = 0; i < menuItems.length; i++) { + let menutItem = menuItems[i] + menutItem.drawBackground() + } + } + + function drawForeground (pFloatingObject) { + for (let i = 0; i < menuItems.length; i++) { + let menutItem = menuItems[i] + menutItem.drawForeground() + } + } +} diff --git a/FloatingSpace/CircularMenuItem.js b/FloatingSpace/CircularMenuItem.js new file mode 100644 index 000000000..30553ac7a --- /dev/null +++ b/FloatingSpace/CircularMenuItem.js @@ -0,0 +1,249 @@ + +function newCircularMenuItem () { + const MODULE_NAME = 'Circular Menu Iem' + + let thisObject = { + type: undefined, + isDeployed: undefined, + iconOn: undefined, + iconOff: undefined, + currentIcon: undefined, + action: undefined, + actionFunction: undefined, + label: undefined, + workingLabel: undefined, + workDoneLabel: undefined, + workFailedLabel: undefined, + visible: false, + iconPathOn: undefined, + iconPathOff: undefined, + rawRadius: undefined, + targetRadius: undefined, + currentRadius: undefined, + angle: undefined, + container: undefined, + payload: undefined, + relatedStrategyPart: undefined, + 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 + + const EXTRA_MOUSE_OVER_ICON_SIZE = 2 + 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.currentIcon = undefined + thisObject.payload = undefined + thisObject.actionFunction = 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 + } + } + + function getContainer (point) { + let container + if (thisObject.isDeployed === true) { + if (thisObject.container.frame.isThisPointHere(point, true, false) === true) { + return thisObject.container + } else { + return undefined + } + } + } + + function physics () { + const INCREASE_STEP = 0.25 + + 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 + } + } + + thisObject.container.frame.position.x = thisObject.container.frame.radius * 3 / 7 * Math.cos(toRadians(thisObject.angle)) - thisObject.currentRadius * 1.5 + thisObject.container.frame.position.y = thisObject.container.frame.radius * 3 / 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 */ + + temporaryStatus-- + if (temporaryStatus < 0) { + temporaryStatus = 0 + } + if (temporaryStatus === 0) { + labelToPrint = thisObject.label + backgroundColorToUse = defaultBackgroudColor + } + + iconPhysics() + } + + function iconPhysics () { + if (thisObject.relatedStrategyPart !== undefined) { + thisObject.iconOn = canvas.strategySpace.iconByPartType.get(thisObject.relatedStrategyPart) + thisObject.iconOff = canvas.strategySpace.iconByPartType.get(thisObject.relatedStrategyPart) + } else { + thisObject.iconOn = canvas.strategySpace.iconCollection.get(thisObject.iconPathOn) + thisObject.iconOff = canvas.strategySpace.iconCollection.get(thisObject.iconPathOff) + } + + /* 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 + } + + async function onMouseClick (event) { + if (temporaryStatus === 0) { + if (thisObject.workingLabel !== undefined) { + setTemporaryStatus(thisObject.workingLabel, UI_COLOR.GREY, 500) + } + + thisObject.currentStatus = await thisObject.actionFunction(thisObject.payload, thisObject.action) + + if (thisObject.currentStatus === true) { + if (thisObject.workDoneLabel !== undefined) { + setTemporaryStatus(thisObject.workDoneLabel, UI_COLOR.PATINATED_TURQUOISE, 250) + } + } else { + if (thisObject.workFailedLabel != undefined) { + setTemporaryStatus(thisObject.workFailedLabel, UI_COLOR.TITANIUM_YELLOW, 500) + } + } + } + } + + function setTemporaryStatus (text, backgroundColor, waitingCycles) { + labelToPrint = text + backgroundColorToUse = backgroundColor + temporaryStatus = waitingCycles + } + + function drawBackground () { + if (thisObject.container.frame.position.x > 0 && thisObject.isDeployed === true && thisObject.currentRadius >= thisObject.targetRadius) { + if (thisObject.type === 'Icon & Text') { + let params = { + cornerRadius: 3, + lineWidth: 0.1, + container: thisObject.container, + borderColor: UI_COLOR.DARK, + backgroundColor: backgroundColorToUse, + castShadow: false + } + + if (isMouseOver === true) { + params.opacity = 1 + } else { + params.opacity = 0.8 + } + + roundedCornersBackground(params) + } + } + } + + function drawForeground () { + 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.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 + 10, + 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) + } + } + } + } +} diff --git a/FloatingSpace/CodeEditor.js b/FloatingSpace/CodeEditor.js new file mode 100644 index 000000000..0d3b28d1d --- /dev/null +++ b/FloatingSpace/CodeEditor.js @@ -0,0 +1,215 @@ + +function newCodeEditor () { + const MODULE_NAME = 'Circular Menu Iem' + + 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 + + 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(204, 88, 53);' + + '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 + thisObject.container.frame.height = thisObject.container.frame.radius * 1 + + let textAreaPosition = { + x: 0 - thisObject.container.frame.width / 2, + y: 0 + thisObject.container.frame.height * 2 / 7 + } + + textAreaPosition = thisObject.container.frame.frameThisPoint(textAreaPosition) + if (thisObject.visible === true) { + let checkPosition = { + x: textAreaPosition.x, + y: textAreaPosition.y - window.canvasApp.topMargin + } + 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 + + 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) + } + } + } +} + diff --git a/FloatingSpace/FloatingLayer.js b/FloatingSpace/FloatingLayer.js index 0f83cf7e8..f3889b6f1 100644 --- a/FloatingSpace/FloatingLayer.js +++ b/FloatingSpace/FloatingLayer.js @@ -1,6 +1,4 @@ -  -function newFloatingLayer () { - /* +/* 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. @@ -11,23 +9,25 @@ function newFloatingLayer () { 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. Strategy Parts: These are small balls that represent parts of an strategy. */ +function newFloatingLayer () { const MODULE_NAME = 'Floating Layer' const INFO_LOG = false - let INTENSIVE_LOG = false const ERROR_LOG = true const logger = newWebDebugLog() logger.fileName = MODULE_NAME let thisObject = { addFloatingObject: addFloatingObject, - killFloatingObject: killFloatingObject, + removeFloatingObject: removeFloatingObject, getFloatingObject: getFloatingObject, - physicsLoop: physicsLoop, - isInside: isInside, - isInsideFloatingObject: isInsideFloatingObject, + physics: physics, changeTargetRepulsion: changeTargetRepulsion, + draw: draw, + getContainer: getContainer, initialize: initialize, finalize: finalize } @@ -52,93 +52,46 @@ function newFloatingLayer () { let visibleFloatingObjects = [] - /* - The creator of the floatingObject at any time can decide to get rid of it and kill it. But we dont want the object just to dissapear because - that doesnt look good. What this module does is to remove it from the visible or invisible layer where they are and move them to the - dyingFloatingObjects array. Object in this array have a short animation until they finally graphically dissapear and at thay point they are also - removed from the dying array for good. - */ - - let dyingFloatingObjects = [] - - let maxTargetRepulsionForce = 0.003 + let maxTargetRepulsionForce = 0.001 let currentHandle = 0 return thisObject function finalize () { - try { - if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') } - - invisibleFloatingObjects = [] - visibleFloatingObjects = [] - dyingFloatingObjects = [] - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) } - } + invisibleFloatingObjects = [] + visibleFloatingObjects = [] } - function initialize (callBackFunction) { - try { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } + function initialize () { - /* We dont need to initialize anything right now. */ - - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err.message = ' + err.message) } - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) } - } + /* We dont need to initialize anything right now. */ } - function addFloatingObject (pFloatingObject, callBackFunction) { - /* - As you can see here, even though the floating objects are created outside this layer, its creator it is not supossed to keep - the reference to the object, so that the managment of the objects references can live entirely inside this module. What the - creator keeps, is a handle to the object which it can use to retrieve the floating object when needed. - */ + function getContainer (point) { + let container - try { - if (INFO_LOG === true) { logger.write('[INFO] addFloatingObject -> Entering function.') } - - invisibleFloatingObjects.push(pFloatingObject) - - if (INFO_LOG === true) { logger.write('[INFO] addFloatingObject -> invisibleFloatingObjects.length = ' + invisibleFloatingObjects.length) } - - currentHandle++ - - pFloatingObject.handle = currentHandle // Math.floor((Math.random() * 10000000) + 1); - - if (INFO_LOG === true) { logger.write('[INFO] addFloatingObject -> pFloatingObject.handle = ' + pFloatingObject.handle) } - if (INFO_LOG === true) { logger.write('[INFO] addFloatingObject -> pFloatingObject.type = ' + pFloatingObject.type) } - - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] addFloatingObject -> err.message = ' + err.message) } - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) } + for (let i = 0; i < visibleFloatingObjects.length; i++) { + let floatingObject = visibleFloatingObjects[i] + container = floatingObject.getContainer(point) + if (container !== undefined) { return container } } + + return container } - function killFloatingObject (pFloatingObjectHandle, callBackFunction) { + function addFloatingObject (pFloatingObject) { + currentHandle++ + pFloatingObject.handle = currentHandle // Math.floor((Math.random() * 10000000) + 1); + invisibleFloatingObjects.push(pFloatingObject) + } + + function removeFloatingObject (pFloatingObjectHandle) { try { - /* - The floting object to be killed can be either at the visible or the invisible array. What we do here is look for it - at each of the arrays until we find it. Once found, we remove it and is sent to the dying floating objects array. - */ - - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> Entering function.') } - for (let i = 0; i < invisibleFloatingObjects.length; i++) { let floatingObject = invisibleFloatingObjects[i] if (floatingObject.handle === pFloatingObjectHandle) { invisibleFloatingObjects.splice(i, 1) // Delete item from array. - - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> floatingObject.handle = ' + floatingObject.handle) } - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> Removing floatingObject from invisibleFloatingObjects.') } - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> invisibleFloatingObjects.length = ' + invisibleFloatingObjects.length) } - - sendToDie(floatingObject) return } } @@ -148,95 +101,15 @@ function newFloatingLayer () { if (floatingObject.handle === pFloatingObjectHandle) { visibleFloatingObjects.splice(i, 1) // Delete item from array. - - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> floatingObject.handle = ' + floatingObject.handle) } - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> Removing floatingObject from visibleFloatingObjects.') } - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> visibleFloatingObjects.length = ' + visibleFloatingObjects.length) } - - sendToDie(floatingObject) return } } - if (ERROR_LOG === true) { logger.write('[ERROR] killFloatingObject -> Floating Object Not Found.') } - if (ERROR_LOG === true) { logger.write('[ERROR] killFloatingObject -> Floating Object cannot be killed.') } - if (ERROR_LOG === true) { logger.write('[ERROR] killFloatingObject -> pFloatingObjectHandle = ' + pFloatingObjectHandle) } - - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) } - - function sendToDie (pFloatingObject) { - try { - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> sendToDie -> Entering function.') } - - /* Lets mofigy the targerRadius */ - - pFloatingObject.targetRadius = 0 - - /* Lets transfer the payload to a new payload structure. */ - - let payload = {} - - switch (pFloatingObject.type) { - - case 'Profile Ball': { - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> sendToDie -> Profile Ball -> Entering function.') } - - if (pFloatingObject.payload.profile.visible === false) { return } - - payload.profile = { - position: { - x: pFloatingObject.payload.profile.position.x, - y: pFloatingObject.payload.profile.position.y - }, - visible: pFloatingObject.payload.profile.visible, - botAvatar: pFloatingObject.payload.profile.botAvatar - } - - pFloatingObject.payload = payload - break - } - case 'Note': { - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> sendToDie -> Note -> Entering function.') } - - if (pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].visible === false) { return } - - payload.notes = [] - let note = { - title: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].title, - body: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].body, - date: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].date, - rate: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].rate, - position: { - x: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].position.x, - y: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].position.y - }, - visible: pFloatingObject.payload.notes[pFloatingObject.payloadNoteIndex].visible - } - payload.notes.push(note) - pFloatingObject.payloadNoteIndex = 0 - - pFloatingObject.payload = payload - break - } - default: { - break - } - } - - dyingFloatingObjects.push(pFloatingObject) - - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> sendToDie -> Adding floatingObject to dyingFloatingObjects.') } - if (INFO_LOG === true) { logger.write('[INFO] killFloatingObject -> sendToDie -> dyingFloatingObjects.length = ' + dyingFloatingObjects.length) } - - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] killFloatingObject -> err.message = ' + err.message) } - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) } - } - } + if (ERROR_LOG === true) { logger.write('[ERROR] removeFloatingObject -> Floating Object Not Found.') } + if (ERROR_LOG === true) { logger.write('[ERROR] removeFloatingObject -> Floating Object cannot be killed.') } + if (ERROR_LOG === true) { logger.write('[ERROR] removeFloatingObject -> pFloatingObjectHandle = ' + pFloatingObjectHandle) } } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] killFloatingObject -> err.message = ' + err.message) } - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) } + if (ERROR_LOG === true) { logger.write('[ERROR] removeFloatingObject -> err= ' + err.stack) } } } @@ -278,7 +151,132 @@ function newFloatingLayer () { } } } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] getFloatingObject -> err.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] getFloatingObject -> err= ' + err.stack) } + } + } + + function draw () { + drawVisibleObjects() + + function drawVisibleObjects () { + /* We draw all the visibleFloatingObjects. */ + + 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() + } + + for (let i = 0; i < visibleFloatingObjects.length; i++) { + let floatingObject = visibleFloatingObjects[i] + floatingObject.drawOnFocus() + } + + makeVisible() + } + + function makeVisible () { + try { + /* Now we check if any of the created FloatingObjects where enabled to run under the Physics Engine. */ + + for (let i = 0; i < invisibleFloatingObjects.length; i++) { + let floatingObject = invisibleFloatingObjects[i] + + let payload = { + position: undefined, + visible: false + } + + switch (floatingObject.type) { + + case 'Profile Ball': { + payload.targetPosition = floatingObject.payload.profile.position + payload.visible = floatingObject.payload.profile.visible + break + } + case 'Note': { + if (floatingObject.payload.notes[floatingObject.payloadNoteIndex] !== undefined) { + payload.targetPosition = floatingObject.payload.notes[floatingObject.payloadNoteIndex].position + payload.visible = floatingObject.payload.notes[floatingObject.payloadNoteIndex].visible + } + break + } + case 'Strategy Part': { + payload.targetPosition = floatingObject.payload.targetPosition + payload.visible = floatingObject.payload.visible + break + } + default: { + break + } + } + + if (payload.visible === true) { + visibleFloatingObjects.push(floatingObject) + + invisibleFloatingObjects.splice(i, 1) // Delete item from array. + + return // Only one at the time. + } + } + + makeInvisible() + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] physics -> makeVisible -> err= ' + err.stack) } + } + } + + function makeInvisible () { + try { + /* Finally we check if any of the currently visible floatingObjects has become invisible and must be removed from the Physics Engine. */ + + for (let i = 0; i < visibleFloatingObjects.length; i++) { + let floatingObject = visibleFloatingObjects[i] + + let payload = { + position: undefined, + visible: true + } + + switch (floatingObject.type) { + + case 'Profile Ball': { + payload.visible = floatingObject.payload.profile.visible + break + } + case 'Note': { + payload.visible = floatingObject.payload.notes[floatingObject.payloadNoteIndex].visible + break + } + case 'Strategy Part': { + payload.visible = floatingObject.payload.visible + break + } + default: { + break + } + } + + if (payload.visible === false) { + invisibleFloatingObjects.push(floatingObject) + + visibleFloatingObjects.splice(i, 1) // Delete item from array. + + return // Only one at the time. + } + } + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] physics -> makeInvisible -> err= ' + err.stack) } + } } } @@ -288,7 +286,7 @@ function newFloatingLayer () { /* */ /******************************************/ - function physicsLoop () { + 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: @@ -304,31 +302,23 @@ function newFloatingLayer () { */ try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> Entering function.') } - applyPhysics() function applyPhysics () { /* This function makes all the calculations to apply phisycs on all visible floatingObjects in this layer. */ try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> applyPhysics -> Entering function.') } - for (let i = 0; i < visibleFloatingObjects.length; i++) { let floatingObject = visibleFloatingObjects[i] - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> Change position based on speed.') } - - floatingObject.currentPosition.x = floatingObject.currentPosition.x + floatingObject.currentSpeed.x - floatingObject.currentPosition.y = floatingObject.currentPosition.y + floatingObject.currentSpeed.y - - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> Apply some friction to desaccelerate.') } + 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 + } floatingObject.currentSpeed.x = floatingObject.currentSpeed.x * floatingObject.friction // Desaceleration factor. floatingObject.currentSpeed.y = floatingObject.currentSpeed.y * floatingObject.friction // Desaceleration factor. - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> Gives a minimun speed towards their taget.') } - let payload = { position: undefined, visible: false @@ -337,35 +327,38 @@ function newFloatingLayer () { switch (floatingObject.type) { case 'Profile Ball': { - payload.position = floatingObject.payload.profile.position + payload.targetPosition = floatingObject.payload.profile.position payload.visible = floatingObject.payload.profile.visible break } case 'Note': { - payload.position = floatingObject.payload.notes[floatingObject.payloadNoteIndex].position + payload.targetPosition = floatingObject.payload.notes[floatingObject.payloadNoteIndex].position payload.visible = floatingObject.payload.notes[floatingObject.payloadNoteIndex].visible break } + case 'Strategy Part': { + payload.targetPosition = floatingObject.payload.targetPosition + payload.visible = floatingObject.payload.visible + break + } default: { break } } - if (floatingObject.currentPosition.x < payload.position.x) { + 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.currentPosition.y < payload.position.y) { + 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 } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> Set a maximun speed.') } - const MAX_SPEED = 50 if (floatingObject.currentSpeed.x > MAX_SPEED) { @@ -384,39 +377,10 @@ function newFloatingLayer () { floatingObject.currentSpeed.y = -MAX_SPEED } - // The radius also have a target. - - if (Math.abs(floatingObject.currentRadius - floatingObject.targetRadius) >= 1) { - if (floatingObject.currentRadius < floatingObject.targetRadius) { - floatingObject.currentRadius = floatingObject.currentRadius + 0.5 - } else { - floatingObject.currentRadius = floatingObject.currentRadius - 0.5 - } - } - - // The imageSize also have a target. - - if (Math.abs(floatingObject.currentImageSize - floatingObject.targetImageSize) >= 1) { - if (floatingObject.currentImageSize < floatingObject.targetImageSize) { - floatingObject.currentImageSize = floatingObject.currentImageSize + 1 - } else { - floatingObject.currentImageSize = floatingObject.currentImageSize - 1 - } - } - - // The fontSize also have a target. - - if (Math.abs(floatingObject.currentFontSize - floatingObject.targetFontSize) >= 0.2) { - if (floatingObject.currentFontSize < floatingObject.targetFontSize) { - floatingObject.currentFontSize = floatingObject.currentFontSize + 0.2 - } else { - floatingObject.currentFontSize = floatingObject.currentFontSize - 0.2 - } - } - // We let the Floating Object animate the physics loops by itself. + checkBoundaries(floatingObject) - floatingObject.physicsLoop() + floatingObject.physics() /* Collision Control */ @@ -428,220 +392,51 @@ function newFloatingLayer () { /* Calculate repulsion force produced by all other floatingObjects */ - currentRepulsionForce(i) + repulsionForceBetweenFloatingObjects(i) targetRepulsionForce(i) gravityForce(floatingObject, payload) } - - drawVisibleObjects() } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physicsLoop -> applyPhysics -> err.message = ' + err.message) } - } - } - - function drawVisibleObjects () { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> drawVisibleObjects -> Entering function.') } - - /* We draw all the visibleFloatingObjects. */ - - 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[visibleFloatingObjects.length - i - 1] - floatingObject.drawForeground() - } - - makeVisible() - } catch (err) { - if (ERROR_LOG === true && INTENSIVE_LOG === true) { logger.write('[ERROR] physicsLoop -> drawVisibleObjects -> err.message = ' + err.message) } - } - } - - function makeVisible () { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> makeVisible -> Entering function.') } - - /* Now we check if any of the created FloatingObjects where enabled to run under the Physics Engine. */ - - for (let i = 0; i < invisibleFloatingObjects.length; i++) { - let floatingObject = invisibleFloatingObjects[i] - - let payload = { - position: undefined, - visible: false - } - - switch (floatingObject.type) { - - case 'Profile Ball': { - payload.position = floatingObject.payload.profile.position - payload.visible = floatingObject.payload.profile.visible - break - } - case 'Note': { - if (floatingObject.payload.notes[floatingObject.payloadNoteIndex] !== undefined) { - payload.position = floatingObject.payload.notes[floatingObject.payloadNoteIndex].position - payload.visible = floatingObject.payload.notes[floatingObject.payloadNoteIndex].visible - } - - break - } - default: { - break - } - } - - if (payload.visible === true) { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> payload.visible = ' + payload.visible) } - - /* The first time that the floatingObject becomes visible, we need to do this. */ - - floatingObject.radomizeCurrentPosition(payload.position) - floatingObject.radomizeCurrentSpeed() - - visibleFloatingObjects.push(floatingObject) - - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject.handle = ' + floatingObject.handle) } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject added to visibleFloatingObjects') } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> visibleFloatingObjects.length = ' + visibleFloatingObjects.length) } - - invisibleFloatingObjects.splice(i, 1) // Delete item from array. - - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject.handle = ' + floatingObject.handle) } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject removed from invisibleFloatingObjects') } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> invisibleFloatingObjects.length = ' + invisibleFloatingObjects.length) } - - return // Only one at the time. - } - } - - makeInvisible() - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physicsLoop -> makeVisible -> err.message = ' + err.message) } - } - } - - function makeInvisible () { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> makeInvisible -> Entering function.') } - - /* Finally we check if any of the currently visible floatingObjects has become invisible and must be removed from the Physics Engine. */ - - for (let i = 0; i < visibleFloatingObjects.length; i++) { - let floatingObject = visibleFloatingObjects[i] - - let payload = { - position: undefined, - visible: true - } - - switch (floatingObject.type) { - - case 'Profile Ball': { - payload.visible = floatingObject.payload.profile.visible - break - } - case 'Note': { - payload.visible = floatingObject.payload.notes[floatingObject.payloadNoteIndex].visible - break - } - default: { - break - } - } - - if (payload.visible === false) { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> payload.visible = ' + payload.visible) } - - invisibleFloatingObjects.push(floatingObject) - - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject.handle = ' + floatingObject.handle) } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject added to invisibleFloatingObjects') } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> invisibleFloatingObjects.length = ' + invisibleFloatingObjects.length) } - - visibleFloatingObjects.splice(i, 1) // Delete item from array. - - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject.handle = ' + floatingObject.handle) } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> floatingObject removed from visibleFloatingObjects') } - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> visibleFloatingObjects.length = ' + visibleFloatingObjects.length) } - - return // Only one at the time. - } - } - - animateDyingObjects() - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physicsLoop -> makeInvisible -> err.message = ' + err.message) } - } - } - - function animateDyingObjects () { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> animateDyingObjects -> Entering function.') } - - /* We animate some parts of the dying objects */ - - for (let i = 0; i < dyingFloatingObjects.length; i++) { - let floatingObject = dyingFloatingObjects[i] - - if (Math.abs(floatingObject.currentRadius - floatingObject.targetRadius) >= 5) { - let speed = Math.random() - - floatingObject.currentRadius = floatingObject.currentRadius - speed * 3 - } else { - /* Here is when the floatingObjects are definetelly killed. */ - - dyingFloatingObjects.splice(i, 1) // Delete item from array. - break // only one at the time. - } - } - - drawDyingObjects() - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physicsLoop -> animateDyingObjects -> err.message = ' + err.message) } - } - } - - function drawDyingObjects () { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] physicsLoop -> drawDyingObjects -> Entering function.') } - - /* We also draw all the dyingFloatingObjects */ - - for (let i = 0; i < dyingFloatingObjects.length; i++) { - let floatingObject = dyingFloatingObjects[i] - floatingObject.drawBackground() - } - - for (let i = 0; i < dyingFloatingObjects.length; i++) { - let floatingObject = dyingFloatingObjects[dyingFloatingObjects.length - i - 1] - floatingObject.drawForeground() - } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physicsLoop -> drawDyingObjects -> err.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] physics -> applyPhysics -> err= ' + err.stack) } } } } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physicsLoop -> err.message = ' + err.message) } + 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 { - if (INTENSIVE_LOG === true) { logger.write('[INFO] gravityForce -> Entering function.') } - /* 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 - var d = Math.sqrt(Math.pow(payload.position.x - floatingObject.currentPosition.x, 2) + Math.pow(payload.position.y - floatingObject.currentPosition.y, 2)) // ... we calculate the distance ... + var 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 ... var 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. @@ -650,13 +445,13 @@ function newFloatingLayer () { } var pos1 = { - x: floatingObject.currentPosition.x, - y: floatingObject.currentPosition.y + x: floatingObject.container.frame.position.x, + y: floatingObject.container.frame.position.y } var pos2 = { - x: payload.position.x, - y: payload.position.y + x: payload.targetPosition.x, + y: payload.targetPosition.y } var posDiff = { // Next we need the vector resulting from the 2 positions. @@ -664,29 +459,29 @@ function newFloatingLayer () { y: pos2.y - pos1.y } - var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. - x: posDiff.x / d, - y: posDiff.y / d + if (d !== 0) { + var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. + x: posDiff.x / d, + y: posDiff.y / d + } + + var forceVector = { + x: unitVector.x * force, + y: unitVector.y * force + } + + /* We add the force vector to the speed vector */ + + floatingObject.currentSpeed.x = floatingObject.currentSpeed.x + forceVector.x + floatingObject.currentSpeed.y = floatingObject.currentSpeed.y + forceVector.y } - - var forceVector = { - x: unitVector.x * force, - y: unitVector.y * force - } - - /* We add the force vector to the speed vector */ - - 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.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] gravityForce -> err= ' + err.stack) } } } - function currentRepulsionForce (currentFloatingObject) { + function repulsionForceBetweenFloatingObjects (currentFloatingObject) { try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] currentRepulsionForce -> Entering function.') } - /* We generate a repulsion force between floatingObjects, that prevents them to be collisioning so often. */ const coulomb = 2 @@ -701,7 +496,7 @@ function newFloatingLayer () { var floatingObject2 = visibleFloatingObjects[i] // So, for each floatingObject... - var d = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)) // ... we calculate the distance ... + var 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 ... var force = coulomb * floatingObject2.currentMass / (d * d) // ... and with it the repulsion force. @@ -712,13 +507,13 @@ function newFloatingLayer () { } var pos1 = { - x: floatingObject1.currentPosition.x, - y: floatingObject1.currentPosition.y + x: floatingObject1.container.frame.position.x, + y: floatingObject1.container.frame.position.y } var pos2 = { - x: floatingObject2.currentPosition.x, - y: floatingObject2.currentPosition.y + x: floatingObject2.container.frame.position.x, + y: floatingObject2.container.frame.position.y } var posDiff = { // Next we need the vector resulting from the 2 positions. @@ -743,14 +538,12 @@ function newFloatingLayer () { } } } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] currentRepulsionForce -> err.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] repulsionForceBetweenFloatingObjects -> err= ' + err.stack) } } } function targetRepulsionForce (currentFloatingObject) { try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] targetRepulsionForce -> Entering function.') } - /* We generate a repulsion force between floatingObjects, that prevents them to be collisioning so often. */ const coulomb = 2 @@ -769,11 +562,15 @@ function newFloatingLayer () { switch (floatingObject2.type) { case 'Profile Ball': { - payload.position = floatingObject2.payload.profile.position + payload.targetPosition = floatingObject2.payload.profile.position break } case 'Note': { - payload.position = floatingObject2.payload.notes[floatingObject2.payloadNoteIndex].position + payload.targetPosition = floatingObject2.payload.notes[floatingObject2.payloadNoteIndex].position + break + } + case 'Strategy Part': { + payload.targetPosition = floatingObject2.payload.targetPosition break } default: { @@ -781,7 +578,7 @@ function newFloatingLayer () { } } - var d = Math.sqrt(Math.pow(payload.position.x - floatingObject1.currentPosition.x, 2) + Math.pow(payload.position.y - floatingObject1.currentPosition.y, 2)) // ... we calculate the distance ... + var 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 ... var force = coulomb * floatingObject2.currentMass / (d * d) // ... and with it the repulsion force. @@ -792,13 +589,13 @@ function newFloatingLayer () { } var pos1 = { - x: floatingObject1.currentPosition.x, - y: floatingObject1.currentPosition.y + x: floatingObject1.container.frame.position.x, + y: floatingObject1.container.frame.position.y } var pos2 = { - x: payload.position.x, - y: payload.position.y + x: payload.targetPosition.x, + y: payload.targetPosition.y } var posDiff = { // Next we need the vector resulting from the 2 positions. @@ -806,30 +603,30 @@ function newFloatingLayer () { y: pos2.y - pos1.y } - var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. - x: posDiff.x / d, - y: posDiff.y / d + if (d !== 0) { + var unitVector = { // To find the unit vector, we divide each component by the magnitude of the vector. + x: posDiff.x / d, + y: posDiff.y / d + } + + var forceVector = { + x: unitVector.x * force, + y: unitVector.y * force + } + + /* We substract the force vector to the speed vector of the current floatingObject */ + + floatingObject1.currentSpeed.x = floatingObject1.currentSpeed.x - forceVector.x + floatingObject1.currentSpeed.y = floatingObject1.currentSpeed.y - forceVector.y } - - var forceVector = { - x: unitVector.x * force, - y: unitVector.y * force - } - - /* We substract the force vector to the speed vector of the current floatingObject */ - - 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.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] targetRepulsionForce -> err= ' + err.stack) } } } function changeTargetRepulsion (pDelta) { try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] changeTargetRepulsion -> Entering function.') } - if (pDelta > 0) { pDelta = 1 } else { @@ -842,20 +639,18 @@ function newFloatingLayer () { maxTargetRepulsionForce = 0.0001 } } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] changeTargetRepulsion -> err.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] changeTargetRepulsion -> err= ' + err.stack) } } } function colliding (floatingObject1, floatingObject2) { try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] colliding -> Entering function.') } - /* This function detects weather 2 floatingObjects collide with each other. */ - var r1 = floatingObject1.currentRadius - var r2 = floatingObject2.currentRadius + var r1 = floatingObject1.container.frame.radius + var r2 = floatingObject2.container.frame.radius - var distance = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)) + var 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. @@ -868,66 +663,19 @@ function newFloatingLayer () { return true } else return true } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] colliding -> err.message = ' + err.message) } - } - } - - function isInside (x, y) { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] isInside -> Entering function.') } - - /* This function detects weather the point x,y is inside any of the floatingObjects. */ - - for (var i = 0; i < visibleFloatingObjects.length; i++) { - var floatingObject = visibleFloatingObjects[i] - var distance = Math.sqrt(Math.pow(floatingObject.currentPosition.x - x, 2) + Math.pow(floatingObject.currentPosition.y - y, 2)) - - if (distance < floatingObject.currentRadius) { - return i - } - } - return -1 - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] isInside -> err.message = ' + err.message) } - } - } - - function isInsideFloatingObject (floatingObjectIndex, x, y) { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] isInsideFloatingObject -> Entering function.') } - - /* This function detects weather the point x,y is inside one particular floatingObjects. */ - - var floatingObject = visibleFloatingObjects[floatingObjectIndex] - var distance = Math.sqrt(Math.pow(floatingObject.currentPosition.x - x, 2) + Math.pow(floatingObject.currentPosition.y - y, 2)) - - if (distance < floatingObject.currentRadius) { - return true - } - - return false - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] isInsideFloatingObject -> err.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] colliding -> err= ' + err.stack) } } } function distance (x1, y1, x2, y2) { - try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] distance -> Entering function.') } - - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] distance -> err.message = ' + err.message) } - } + return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) } function resolveCollision (floatingObject1, floatingObject2) { try { - if (INTENSIVE_LOG === true) { logger.write('[INFO] resolveCollision -> Entering function.') } - /* This function changes speed and position of floatingObjects that are in collision */ - var collisionision_angle = Math.atan2((floatingObject2.currentPosition.y - floatingObject1.currentPosition.y), (floatingObject2.currentPosition.x - floatingObject1.currentPosition.x)) + var collisionision_angle = Math.atan2((floatingObject2.container.frame.position.y - floatingObject1.container.frame.position.y), (floatingObject2.container.frame.position.x - floatingObject1.container.frame.position.x)) var speed1 = Math.sqrt(floatingObject1.currentSpeed.x * floatingObject1.currentSpeed.x + floatingObject1.currentSpeed.y * floatingObject1.currentSpeed.y) // Magnitude of Speed Vector for floatingObject 1 var speed2 = Math.sqrt(floatingObject2.currentSpeed.x * floatingObject2.currentSpeed.x + floatingObject2.currentSpeed.y * floatingObject2.currentSpeed.y) // Magnitude of Speed Vector for floatingObject 2 @@ -955,13 +703,13 @@ function newFloatingLayer () { floatingObject2.currentSpeed.y = sinAngle * final_xspeed_2 + cosAngle * final_yspeed_2 var pos1 = { - x: floatingObject1.currentPosition.x, - y: floatingObject1.currentPosition.y + x: floatingObject1.container.frame.position.x, + y: floatingObject1.container.frame.position.y } var pos2 = { - x: floatingObject2.currentPosition.x, - y: floatingObject2.currentPosition.y + x: floatingObject2.container.frame.position.x, + y: floatingObject2.container.frame.position.y } // get the mtd @@ -970,10 +718,10 @@ function newFloatingLayer () { y: pos1.y - pos2.y } - var d = Math.sqrt(Math.pow(floatingObject2.currentPosition.x - floatingObject1.currentPosition.x, 2) + Math.pow(floatingObject2.currentPosition.y - floatingObject1.currentPosition.y, 2)) + var 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 - var scalar = (((floatingObject1.currentRadius + floatingObject2.currentRadius) - d) / d) + var scalar = (((floatingObject1.container.frame.radius + floatingObject2.container.frame.radius) - d) / d) var minTD = { x: posDiff.x * scalar, @@ -992,10 +740,14 @@ function newFloatingLayer () { pos2.x = pos2.x - minTD.x * (im2 / (im1 + im2)) pos2.y = pos2.y - minTD.y * (im2 / (im1 + im2)) - floatingObject1.currentPosition = pos1 - floatingObject2.currentPosition = pos2 + if (floatingObject1.positionLocked === false) { + floatingObject1.container.frame.position = pos1 + } + if (floatingObject2.positionLocked === false) { + floatingObject2.container.frame.position = pos2 + } } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] resolveCollision -> err.message = ' + err.message) } + if (ERROR_LOG === true) { logger.write('[ERROR] resolveCollision -> err= ' + err.stack) } } } } diff --git a/FloatingSpace/FloatingObject.js b/FloatingSpace/FloatingObject.js index 6afa87e03..818d734da 100644 --- a/FloatingSpace/FloatingObject.js +++ b/FloatingSpace/FloatingObject.js @@ -1,155 +1,221 @@ -  + function newFloatingObject () { const MODULE_NAME = 'Floating Object' - const INFO_LOG = false - const INTENSIVE_LOG = false const ERROR_LOG = true const logger = newWebDebugLog() logger.fileName = MODULE_NAME let thisObject = { - - physicsLoop: physicsLoop, - eventHandler: undefined, - + 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. - - physicsEnabled: false, - + 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. + 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, + pinToggle: pinToggle, + physics: physics, initializeMass: initializeMass, initializeRadius: initializeRadius, initializeImageSize: initializeImageSize, initializeFontSize: initializeFontSize, - - imageId: undefined, - - currentPosition: 0, // Current x,y position of the floating object at the floating object's layer, where there is no displacement or zoom. This position is always changing towards the target position. - currentSpeed: 0, // This is the current speed of the floating object. - currentRadius: 0, // This is the current radius of the floating object, including its zoom applied. - currentMass: 0, // This is the current mass of the floating object, including its zoom applied. - - friction: 0, // This is a factor that will ultimatelly desacelerate the floating object. - - rawMass: 0, // This is the mass value without zoom. - rawRadius: 0, // This is the radius of this floating object without zoom. - - targetRadius: 0, // This is the target radius of the floating object with zoom applied. It should be animated until reaching this value. - - fillStyle: '', - - labelStrokeStyle: '', - radomizeCurrentPosition: radomizeCurrentPosition, radomizeCurrentSpeed: radomizeCurrentSpeed, - drawBackground: drawBackground, + 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. - - linkedObject: undefined, // This is a reference to the object that this floating object is representing. - linkedObjectType: '', // Since there might be floating objects for different types of objects, here we store the type of object we are linking to. - - container: undefined, // This is a pointer to the object where the floating object belongs to. + getContainer: getContainer, + finalize: finalize, initialize: initialize - } - let underlayingObject + thisObject.container = newContainer() + thisObject.container.initialize(MODULE_NAME, 'Circle') + thisObject.container.isClickeable = true + thisObject.container.isDraggeable = true + thisObject.container.detectMouseOver = true + thisObject.container.frame.radius = 0 + thisObject.container.frame.position.x = 0 + thisObject.container.frame.position.y = 0 - thisObject.eventHandler = newEventHandler() + let selfMouseOverEventSubscriptionId + let selfMouseClickEventSubscriptionId + let spaceMouseOverEventSubscriptionId + let spaceFocusAquiredEventSubscriptionId return thisObject - function initialize (pType, callBackFunction) { - try { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } + function finalize () { + thisObject.container.eventHandler.stopListening(selfMouseOverEventSubscriptionId) + thisObject.container.eventHandler.stopListening(selfMouseClickEventSubscriptionId) + canvas.floatingSpace.container.eventHandler.stopListening(spaceMouseOverEventSubscriptionId) + canvas.floatingSpace.container.eventHandler.stopListening(spaceFocusAquiredEventSubscriptionId) - switch (pType) { + thisObject.container.finalize() + thisObject.container = undefined + thisObject.payload = undefined + thisObject.fitFunction = undefined + } - case 'Profile Ball': { - underlayingObject = newProfileBall() - underlayingObject.initialize(onInitialized) + function initialize (type, payload) { + thisObject.payload = payload + thisObject.type = type - function onInitialized (err) { + 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) - break - } - case 'Note': { - underlayingObject = newNote() - underlayingObject.initialize(onInitialized) + /* Assign a position and speed */ - function onInitialized (err) { + thisObject.radomizeCurrentPosition(thisObject.payload.targetPosition) + thisObject.radomizeCurrentSpeed() + } - } - break - } - default: { - break - } + function getContainer (point) { + 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 pinToggle () { + if (thisObject.isPinned !== true) { + thisObject.isPinned = true + thisObject.positionLocked = true + } else { + thisObject.isPinned = false + } + return thisObject.isPinned + } + + function physics () { + thisObjectPhysics() + thisObject.payload.uiObject.physics() + } + + function thisObjectPhysics () { + // The radius also have a target. + + if (Math.abs(thisObject.container.frame.radius - thisObject.targetRadius) >= 3) { + if (thisObject.container.frame.radius < thisObject.targetRadius) { + thisObject.container.frame.radius = thisObject.container.frame.radius + 3 + } else { + thisObject.container.frame.radius = thisObject.container.frame.radius - 3 } + thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event) + } - thisObject.type = pType + // The imageSize also have a target. - thisObject.eventHandler.listenToEvent('onMouseOver', onMouseOver) - canvas.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver) - thisObject.eventHandler.listenToEvent('onMouseClick', onMouseClick) + if (Math.abs(thisObject.currentImageSize - thisObject.targetImageSize) >= 1) { + if (thisObject.currentImageSize < thisObject.targetImageSize) { + thisObject.currentImageSize = thisObject.currentImageSize + 2 + } else { + thisObject.currentImageSize = thisObject.currentImageSize - 2 + } + } - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err.message = ' + err.message) } - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) } + // The fontSize also have a target. + + if (Math.abs(thisObject.currentFontSize - thisObject.targetFontSize) >= 0.2) { + if (thisObject.currentFontSize < thisObject.targetFontSize) { + thisObject.currentFontSize = thisObject.currentFontSize + 0.2 + } else { + thisObject.currentFontSize = thisObject.currentFontSize - 0.2 + } + } + + /* 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 physicsLoop (callBackFunction) { - try { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } + function mouseOverFlotingSpace (point) { + removeFocus() + } - underlayingObject.physicsLoop() - - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] physicsLoop -> err.message = ' + err.message) } - if (callBackFunction !== undefined) { callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) } + function someoneAquiredFocus (container) { + if (container.id !== thisObject.container.id) { + removeFocus() } } - function onMouseOver () { - thisObject.targetRadius = thisObject.rawRadius * 1.5 - thisObject.targetImageSize = thisObject.rawImageSize * 1.5 - thisObject.targetFontSize = thisObject.rawFontSize * 1.5 + function removeFocus () { + if (thisObject.isOnFocus === true) { + thisObject.targetRadius = thisObject.rawRadius * 1 + thisObject.targetImageSize = thisObject.rawImageSize * 1 + thisObject.targetFontSize = thisObject.rawFontSize * 1 - underlayingObject.onMouseOver() - } + thisObject.payload.uiObject.container.eventHandler.raiseEvent('onNotFocus') - function onMouseNotOver () { - thisObject.targetRadius = thisObject.rawRadius * 1 - thisObject.targetImageSize = thisObject.rawImageSize * 1 - thisObject.targetFontSize = thisObject.rawFontSize * 1 - - underlayingObject.onMouseNotOver() + if (thisObject.isPinned !== true) { + thisObject.positionLocked = false + } + thisObject.isOnFocus = false + } } function onMouseClick (pPoint) { - underlayingObject.onMouseClick(pPoint, thisObject) + let event = { + point: pPoint, + parent: thisObject + } + thisObject.payload.uiObject.container.eventHandler.raiseEvent('onMouseClick', event) } function drawBackground () { - underlayingObject.drawBackground(thisObject) + thisObject.payload.uiObject.drawBackground() + } + + function drawMiddleground () { + thisObject.payload.uiObject.drawMiddleground() } function drawForeground () { - underlayingObject.drawForeground(thisObject) + thisObject.payload.uiObject.drawForeground() + } + + function drawOnFocus () { + thisObject.payload.uiObject.drawOnFocus() } function initializeMass (suggestedValue) { - var mass = suggestedValue + let mass = suggestedValue if (mass < 0.1) { mass = 0.1 } @@ -159,14 +225,16 @@ function newFloatingObject () { } function initializeRadius (suggestedValue) { - var radius = suggestedValue + let radius = suggestedValue if (radius < 2) { radius = 2 } thisObject.rawRadius = radius thisObject.targetRadius = radius - thisObject.currentRadius = radius / 3 + thisObject.container.frame.radius = radius / 3 + + thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event) } function initializeImageSize (suggestedValue) { @@ -192,12 +260,19 @@ function newFloatingObject () { } function radomizeCurrentPosition (arroundPoint) { - var position = { + let position = { x: Math.floor((Math.random() * (200) - 100)) + arroundPoint.x, y: Math.floor((Math.random() * (200) - 100)) + arroundPoint.y } - thisObject.currentPosition = position + // thisObject.container.frame.position = thisObject.container.frame.frameThisPoint(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 () { @@ -227,14 +302,8 @@ function newFloatingObject () { function updateMass () { - // thisObject.currentMass = thisObject.rawMass + thisObject.rawMass * thisObject.container.zoom.incrementM * thisObject.container.zoom.levelM; - } function updateRadius () { - - // thisObject.targetRadius = thisObject.rawRadius + thisObject.rawRadius * thisObject.container.zoom.incrementR * thisObject.container.zoom.levelR; - } } - diff --git a/FloatingSpace/Note.js b/FloatingSpace/Note.js index ed8de1b4e..6bb4e5858 100644 --- a/FloatingSpace/Note.js +++ b/FloatingSpace/Note.js @@ -1,24 +1,45 @@  function newNote () { + const MODULE_NAME = 'Note' + let thisObject = { - - physicsLoop: physicsLoop, - onMouseOver: onMouseOver, - onMouseClick: onMouseClick, - onMouseNotOver: onMouseNotOver, + container: undefined, + physics: physics, drawBackground: drawBackground, + drawMiddleground: drawMiddleground, drawForeground: drawForeground, + drawOnFocus: drawOnFocus, + getContainer: getContainer, 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 + return thisObject - function initialize (callBackFunction) { - callBackFunction() + function initialize () { + thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver) + thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick) + thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver) } - function physicsLoop () { + function getContainer (point) { + let container + + if (thisObject.container.frame.isThisPointHere(point, true) === true) { + return thisObject.container + } else { + return undefined + } + } + + function physics () { } @@ -30,8 +51,9 @@ function newNote () { } - function onMouseClick (pPoint, pFloatingObject) { - + function onMouseClick (event) { + pPoint = event.point + pFloatingObject = event.parent } function drawBackground (pFloatingObject) { @@ -42,11 +64,11 @@ function newNote () { point = viewPort.fitIntoVisibleArea(point) - if (pFloatingObject.currentRadius > 1) { + if (pFloatingObject.container.frame.radius > 1) { /* Target Line */ browserCanvasContext.beginPath() - browserCanvasContext.moveTo(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y) + browserCanvasContext.moveTo(pFloatingObject.container.frame.position.x, pFloatingObject.container.frame.position.y) browserCanvasContext.lineTo(point.x, point.y) browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)' browserCanvasContext.setLineDash([4, 2]) @@ -55,7 +77,7 @@ function newNote () { browserCanvasContext.setLineDash([0, 0]) } - if (pFloatingObject.currentRadius > 0.5) { + if (pFloatingObject.container.frame.radius > 0.5) { /* Target Spot */ var radius = 1 @@ -68,12 +90,20 @@ function newNote () { } } + function drawOnFocus () { + + } + + function drawMiddleground () { + + } + function drawForeground (pFloatingObject) { - const BUBBLE_CORNERS_RADIOUS = 5 + const BUBBLE_CORNERS_RADIUS = 5 const TITLE_BAR_HEIGHT = 14 - const BUBBLE_WIDTH = BUBBLE_CORNERS_RADIOUS + pFloatingObject.currentRadius * 4 - const BUBBLE_HEIGHT = BUBBLE_CORNERS_RADIOUS + pFloatingObject.currentRadius * 2 + const BUBBLE_WIDTH = BUBBLE_CORNERS_RADIUS + pFloatingObject.container.frame.radius * 4 + const BUBBLE_HEIGHT = BUBBLE_CORNERS_RADIUS + pFloatingObject.container.frame.radius * 2 let borderPoint1 let borderPoint2 @@ -81,31 +111,31 @@ function newNote () { let borderPoint4 let intialDisplace = { - x: pFloatingObject.currentPosition.x - BUBBLE_WIDTH / 2, - y: pFloatingObject.currentPosition.y - BUBBLE_HEIGHT / 2 + x: pFloatingObject.container.frame.position.x - BUBBLE_WIDTH / 2, + y: pFloatingObject.container.frame.position.y - BUBBLE_HEIGHT / 2 } - if (pFloatingObject.currentRadius > 5) { + if (pFloatingObject.container.frame.radius > 5) { /* Rounded Background */ borderPoint1 = { - x: intialDisplace.x + BUBBLE_CORNERS_RADIOUS, - y: intialDisplace.y + BUBBLE_CORNERS_RADIOUS + x: intialDisplace.x + BUBBLE_CORNERS_RADIUS, + y: intialDisplace.y + BUBBLE_CORNERS_RADIUS } borderPoint2 = { - x: intialDisplace.x + BUBBLE_WIDTH - BUBBLE_CORNERS_RADIOUS, - y: intialDisplace.y + BUBBLE_CORNERS_RADIOUS + x: intialDisplace.x + BUBBLE_WIDTH - BUBBLE_CORNERS_RADIUS, + y: intialDisplace.y + BUBBLE_CORNERS_RADIUS } borderPoint3 = { - x: intialDisplace.x + BUBBLE_WIDTH - BUBBLE_CORNERS_RADIOUS, - y: intialDisplace.y + BUBBLE_HEIGHT - BUBBLE_CORNERS_RADIOUS + x: intialDisplace.x + BUBBLE_WIDTH - BUBBLE_CORNERS_RADIUS, + y: intialDisplace.y + BUBBLE_HEIGHT - BUBBLE_CORNERS_RADIUS } borderPoint4 = { - x: intialDisplace.x + BUBBLE_CORNERS_RADIOUS, - y: intialDisplace.y + +BUBBLE_HEIGHT - BUBBLE_CORNERS_RADIOUS + x: intialDisplace.x + BUBBLE_CORNERS_RADIUS, + y: intialDisplace.y + +BUBBLE_HEIGHT - BUBBLE_CORNERS_RADIUS } titleBarPoint1 = { @@ -123,14 +153,14 @@ function newNote () { browserCanvasContext.fillStyle = 'rgba(255, 249, 196, 0.75)' browserCanvasContext.beginPath() - browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, BUBBLE_CORNERS_RADIOUS, 1.0 * Math.PI, 1.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - BUBBLE_CORNERS_RADIOUS) - browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, BUBBLE_CORNERS_RADIOUS, 1.5 * Math.PI, 2.0 * Math.PI) - browserCanvasContext.lineTo(borderPoint3.x + BUBBLE_CORNERS_RADIOUS, borderPoint3.y) - browserCanvasContext.arc(borderPoint3.x, borderPoint3.y, BUBBLE_CORNERS_RADIOUS, 0 * Math.PI, 0.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint4.x, borderPoint4.y + BUBBLE_CORNERS_RADIOUS) - browserCanvasContext.arc(borderPoint4.x, borderPoint4.y, BUBBLE_CORNERS_RADIOUS, 0.5 * Math.PI, 1.0 * Math.PI) - browserCanvasContext.lineTo(borderPoint1.x - BUBBLE_CORNERS_RADIOUS, borderPoint1.y) + browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, BUBBLE_CORNERS_RADIUS, 1.0 * Math.PI, 1.5 * Math.PI) + browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - BUBBLE_CORNERS_RADIUS) + browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, BUBBLE_CORNERS_RADIUS, 1.5 * Math.PI, 2.0 * Math.PI) + browserCanvasContext.lineTo(borderPoint3.x + BUBBLE_CORNERS_RADIUS, borderPoint3.y) + browserCanvasContext.arc(borderPoint3.x, borderPoint3.y, BUBBLE_CORNERS_RADIUS, 0 * Math.PI, 0.5 * Math.PI) + browserCanvasContext.lineTo(borderPoint4.x, borderPoint4.y + BUBBLE_CORNERS_RADIUS) + browserCanvasContext.arc(borderPoint4.x, borderPoint4.y, BUBBLE_CORNERS_RADIUS, 0.5 * Math.PI, 1.0 * Math.PI) + browserCanvasContext.lineTo(borderPoint1.x - BUBBLE_CORNERS_RADIUS, borderPoint1.y) browserCanvasContext.closePath() @@ -146,10 +176,10 @@ function newNote () { browserCanvasContext.beginPath() browserCanvasContext.moveTo(titleBarPoint1.x, titleBarPoint1.y) - browserCanvasContext.lineTo(borderPoint1.x - BUBBLE_CORNERS_RADIOUS, borderPoint1.y) - browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, BUBBLE_CORNERS_RADIOUS, 1.0 * Math.PI, 1.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - BUBBLE_CORNERS_RADIOUS) - browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, BUBBLE_CORNERS_RADIOUS, 1.5 * Math.PI, 2.0 * Math.PI) + browserCanvasContext.lineTo(borderPoint1.x - BUBBLE_CORNERS_RADIUS, borderPoint1.y) + browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, BUBBLE_CORNERS_RADIUS, 1.0 * Math.PI, 1.5 * Math.PI) + browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - BUBBLE_CORNERS_RADIUS) + browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, BUBBLE_CORNERS_RADIUS, 1.5 * Math.PI, 2.0 * Math.PI) browserCanvasContext.lineTo(titleBarPoint2.x, titleBarPoint2.y) browserCanvasContext.closePath() @@ -160,12 +190,12 @@ function newNote () { browserCanvasContext.stroke() } - if (pFloatingObject.currentRadius > 0.5) { + if (pFloatingObject.container.frame.radius > 0.5) { /* Image */ let imagePosition = { - x: pFloatingObject.currentPosition.x, - y: pFloatingObject.currentPosition.y + BUBBLE_HEIGHT / 2 + x: pFloatingObject.container.frame.position.x, + y: pFloatingObject.container.frame.position.y + BUBBLE_HEIGHT / 2 } if (pFloatingObject.payloadImageId !== undefined) { @@ -187,10 +217,10 @@ function newNote () { /* Labels */ - if (pFloatingObject.currentRadius > 6) { + if (pFloatingObject.container.frame.radius > 6) { browserCanvasContext.strokeStyle = pFloatingObject.labelStrokeStyle - const SIZE_PERCENTAGE = Math.trunc(pFloatingObject.currentRadius / pFloatingObject.targetRadius * 100) / 100 + const SIZE_PERCENTAGE = Math.trunc(pFloatingObject.container.frame.radius / pFloatingObject.targetRadius * 100) / 100 let ALPHA if (pFloatingObject.targetRadius > 0) { @@ -198,7 +228,7 @@ function newNote () { } else { // Object is dying... - ALPHA = Math.trunc((0.5 - (100 - pFloatingObject.currentRadius / 100)) * 100) / 100 + ALPHA = Math.trunc((0.5 - (100 - pFloatingObject.container.frame.radius / 100)) * 100) / 100 if (ALPHA < 0) { ALPHA = 0 } } @@ -214,7 +244,7 @@ function newNote () { if (label !== undefined) { if (SIZE_PERCENTAGE > 0.9) { - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO let yOffset = (TITLE_BAR_HEIGHT - fontSize) / 2 + 2 @@ -283,8 +313,8 @@ function newNote () { let labelRow = labelRows[i] let startingPosition = { - x: pFloatingObject.currentPosition.x, - y: pFloatingObject.currentPosition.y - labelRows.length / 2 * (fontSize * FONT_ASPECT_RATIO + 10) + x: pFloatingObject.container.frame.position.x, + y: pFloatingObject.container.frame.position.y - labelRows.length / 2 * (fontSize * FONT_ASPECT_RATIO + 10) } labelPoint = { @@ -292,7 +322,7 @@ function newNote () { y: startingPosition.y + (i + 1) * (fontSize * FONT_ASPECT_RATIO + 10) } - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = 'rgba(60, 60, 60, ' + ALPHA + ')' browserCanvasContext.fillText(labelRow, labelPoint.x, labelPoint.y) } diff --git a/FloatingSpace/NoteSets.js b/FloatingSpace/NoteSets.js index d3e2ce42e..f61a55c67 100644 --- a/FloatingSpace/NoteSets.js +++ b/FloatingSpace/NoteSets.js @@ -23,7 +23,8 @@ function newNoteSets () { let thisObject = { createNoteSet: createNoteSet, destroyNoteSet: destroyNoteSet, - initialize: initialize + initialize: initialize, + finalize: finalize } let noteSets = [] @@ -31,21 +32,13 @@ function newNoteSets () { return thisObject - function initialize (pFloatingLayer, callBackFunction) { - /* - During the initialization process, we receive the floatingLayer where all the floatingObjects we will be creating here will live at. - */ + function initialize (pFloatingLayer) { + floatingLayer = pFloatingLayer + } - try { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } - - floatingLayer = pFloatingLayer - - callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE) - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) } - callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) - } + function finalize () { + floatingLayer.finalize() + floatingLayer = undefined } function createNoteSet (pPayload, pEventHandler, callBackFunction) { @@ -131,19 +124,7 @@ function newNoteSets () { Each time we identify a floatingObject that is not at the raw data anymore, we request the floatinglayer to kill it. */ - floatingLayer.killFloatingObject(floatingNote.floatingHandle, onObjectKilled) - - function onObjectKilled (err) { - if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { - if (ERROR_LOG === true) { logger.write('[ERROR] createNoteSet -> onNotesChanged -> Remove old Notes -> Floating Object Not Found.') } - if (ERROR_LOG === true) { logger.write('[ERROR] createNoteSet -> onNotesChanged -> Remove old Notes -> Floating Object cannot be killed.') } - if (ERROR_LOG === true) { logger.write('[ERROR] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingNote.floatingHandle = ' + floatingNote.floatingHandle) } - return - } - - if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> floatingNote.floatingHandle = ' + floatingNote.floatingHandle) } - if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Remove old Notes -> Removed from Layer.') } - } + floatingLayer.removeFloatingObject(floatingNote.floatingHandle) } else { newFloatingNotes.push(floatingNote) @@ -232,21 +213,18 @@ function newNoteSets () { */ let floatingObject = newFloatingObject() - floatingObject.initialize('Note', onInitialized) + floatingObject.initialize('Note', '', floatingLayer) - function onInitialized (err) { - if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> Entering function.') } + floatingObject.payload = noteSet.payload + floatingObject.payloadNoteIndex = i + floatingObject.payloadImageId = noteSet.imageId - floatingObject.payload = noteSet.payload - floatingObject.payloadNoteIndex = i - floatingObject.payloadImageId = noteSet.imageId + floatingObject.friction = 0.995 - floatingObject.friction = 0.995 - - floatingObject.initializeMass(200) + floatingObject.initializeMass(200) // let bodyText = pNewNotes[i].body; - let radius + let radius /* if (bodyText.length < 100) { @@ -255,27 +233,26 @@ function newNoteSets () { radius = bodyText.length; } */ - radius = 50 + radius = 50 - floatingObject.initializeRadius(radius) - floatingObject.initializeImageSize(15) + floatingObject.initializeRadius(radius) + floatingObject.initializeImageSize(15) - floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 0.5)' - floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)' + floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 0.5)' + floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)' - floatingLayer.addFloatingObject(floatingObject) + floatingLayer.addFloatingObject(floatingObject) - if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> New Note added to Layer.') } + if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> New Note added to Layer.') } - plotterNote.floatingHandle = floatingObject.handle + plotterNote.floatingHandle = floatingObject.handle - if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> plotterNote.floatingHandle = ' + plotterNote.floatingHandle) } + if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> plotterNote.floatingHandle = ' + plotterNote.floatingHandle) } - newFloatingNotes.push(plotterNote) + newFloatingNotes.push(plotterNote) - if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> Added to newFloatingNotes.') } - if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> newFloatingNotes.length = ' + newFloatingNotes.length) } - } + if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> Added to newFloatingNotes.') } + if (INFO_LOG === true) { logger.write('[INFO] createNoteSet -> onNotesChanged -> Add new Notes -> onInitialized -> newFloatingNotes.length = ' + newFloatingNotes.length) } } else { newFloatingNotes.push(floatingNote) @@ -322,7 +299,7 @@ function newNoteSets () { for (let j = 0; j < noteSet.floatingNotes.length; j++) { let floatingNote = noteSet.floatingNotes[j] - floatingLayer.killFloatingObject(floatingNote.floatingHandle) + floatingLayer.removeFloatingObject(floatingNote.floatingHandle) } noteSets.splice(i, 1) // Delete item from array. diff --git a/FloatingSpace/ProfileBall.js b/FloatingSpace/ProfileBall.js index 8675a3003..18b853346 100644 --- a/FloatingSpace/ProfileBall.js +++ b/FloatingSpace/ProfileBall.js @@ -1,22 +1,31 @@ function newProfileBall () { + const MODULE_NAME = 'Profile Ball' + let thisObject = { - - physicsLoop: physicsLoop, - onMouseOver: onMouseOver, - onMouseClick: onMouseClick, - onMouseNotOver: onMouseNotOver, + container: undefined, + physics: physics, drawBackground: drawBackground, + drawMiddleground: drawMiddleground, drawForeground: drawForeground, + drawOnFocus: drawOnFocus, + getContainer: getContainer, 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 ballStringMenu = [ { visible: false, - imagePathOn: 'Images/menu.icon.on.1.gif', - imagePathOff: 'Images/menu.icon.off.1.gif', + iconPathOn: 'Images/menu.icon.on.1.gif', + iconPathOff: 'Images/menu.icon.off.1.gif', rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -24,8 +33,8 @@ function newProfileBall () { }/*, { visible: false, - imagePathOn: "Images/menu.icon.on.2.gif", - imagePathOff: "Images/menu.icon.off.2.gif", + iconPathOn: "Images/menu.icon.on.2.gif", + iconPathOff: "Images/menu.icon.off.2.gif", rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -33,8 +42,8 @@ function newProfileBall () { }, { visible: false, - imagePathOn: "Images/menu.icon.on.3.gif", - imagePathOff: "Images/menu.icon.off.3.gif", + iconPathOn: "Images/menu.icon.on.3.gif", + iconPathOff: "Images/menu.icon.off.3.gif", rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -42,8 +51,8 @@ function newProfileBall () { }, { visible: false, - imagePathOn: "Images/menu.icon.on.4.gif", - imagePathOff: "Images/menu.icon.off.4.gif", + iconPathOn: "Images/menu.icon.on.4.gif", + iconPathOff: "Images/menu.icon.off.4.gif", rawRadius: 8, targetRadius: 0, currentRadius: 0, @@ -53,35 +62,39 @@ function newProfileBall () { return thisObject - function initialize (callBackFunction) { + function initialize () { for (let i = 0; i < ballStringMenu.length; i++) { let menuItem = ballStringMenu[i] - menuItem.iconOn = new Image() - menuItem.iconOn.onload = onImageLoad - function onImageLoad () { menuItem.iconOff = new Image() - menuItem.iconOff.onload = onImageLoad - function onImageLoad () { menuItem.canDrawIcon = true } - - menuItem.iconOff.src = window.canvasApp.urlPrefix + menuItem.imagePathOff + menuItem.iconOff.src = window.canvasApp.urlPrefix + menuItem.iconPathOff } - - menuItem.iconOn.src = window.canvasApp.urlPrefix + menuItem.imagePathOn - + menuItem.iconOn.src = window.canvasApp.urlPrefix + menuItem.iconPathOn menuItem.icon = menuItem.iconOn // The default value is ON. } - callBackFunction() + thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver) + thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick) + thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver) } - function physicsLoop () { + function getContainer (point) { + let container + + if (thisObject.container.frame.isThisPointHere(point, true) === true) { + return thisObject.container + } else { + return undefined + } + } + + function physics () { // The menuItems also have a target. for (let i = 0; i < ballStringMenu.length; i++) { @@ -113,9 +126,12 @@ function newProfileBall () { } } - function onMouseClick (pPoint, pFloatingObject) { + function onMouseClick (event) { /* What we need to do here is to check which menu item was clicked, if any. */ + pPoint = event.point + pFloatingObject = event.parent + let menuItemIndex for (let i = 0; i < ballStringMenu.length; i++) { @@ -123,8 +139,8 @@ function newProfileBall () { if (menuItem.canDrawIcon === true && menuItem.currentRadius > 1) { let position = { - x: pFloatingObject.currentPosition.x + pFloatingObject.currentImageSize / 2 * Math.cos(toRadians(menuItem.angle)), - y: pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2 * Math.sin(toRadians(menuItem.angle)) + x: pFloatingObject.container.frame.position.x + pFloatingObject.currentImageSize / 2 * Math.cos(toRadians(menuItem.angle)), + y: pFloatingObject.container.frame.position.y - pFloatingObject.currentImageSize / 2 * Math.sin(toRadians(menuItem.angle)) } browserCanvasContext.drawImage(menuItem.icon, position.x, position.y, menuItem.currentRadius * 2, menuItem.currentRadius * 2) @@ -169,17 +185,17 @@ function newProfileBall () { function drawBackground (pFloatingObject) { let point = { - x: pFloatingObject.payload.profile.position.x, - y: pFloatingObject.payload.profile.position.y + x: pFloatingObject.payload.targetPosition.x, + y: pFloatingObject.payload.targetPosition.y } point = viewPort.fitIntoVisibleArea(point) - if (pFloatingObject.currentRadius > 1) { + if (pFloatingObject.container.frame.radius > 1) { /* Target Line */ browserCanvasContext.beginPath() - browserCanvasContext.moveTo(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y) + browserCanvasContext.moveTo(pFloatingObject.container.frame.position.x, pFloatingObject.container.frame.position.y) browserCanvasContext.lineTo(point.x, point.y) browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)' browserCanvasContext.setLineDash([4, 2]) @@ -188,7 +204,7 @@ function newProfileBall () { browserCanvasContext.setLineDash([0, 0]) } - if (pFloatingObject.currentRadius > 0.5) { + if (pFloatingObject.container.frame.radius > 0.5) { /* Target Spot */ var radius = 1 @@ -201,24 +217,32 @@ function newProfileBall () { } } + function drawOnFocus () { + + } + + function drawMiddleground () { + + } + function drawForeground (pFloatingObject) { - if (pFloatingObject.currentRadius > 5) { + if (pFloatingObject.container.frame.radius > 5) { /* Contourn */ browserCanvasContext.beginPath() - browserCanvasContext.arc(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y, pFloatingObject.currentRadius, 0, Math.PI * 2, true) + browserCanvasContext.arc(pFloatingObject.container.frame.position.x, pFloatingObject.container.frame.position.y, pFloatingObject.container.frame.radius, 0, Math.PI * 2, true) browserCanvasContext.closePath() browserCanvasContext.strokeStyle = 'rgba(30, 30, 30, 0.75)' browserCanvasContext.lineWidth = 1 browserCanvasContext.stroke() } - if (pFloatingObject.currentRadius > 0.5) { + if (pFloatingObject.container.frame.radius > 0.5) { /* Main FloatingObject */ var alphaA - if (pFloatingObject.currentRadius < 3) { + if (pFloatingObject.container.frame.radius < 3) { alphaA = 1 } else { alphaA = 0.75 @@ -227,7 +251,7 @@ function newProfileBall () { alphaA = 0.75 browserCanvasContext.beginPath() - browserCanvasContext.arc(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y, pFloatingObject.currentRadius, 0, Math.PI * 2, true) + browserCanvasContext.arc(pFloatingObject.container.frame.position.x, pFloatingObject.container.frame.position.y, pFloatingObject.container.frame.radius, 0, Math.PI * 2, true) browserCanvasContext.closePath() browserCanvasContext.fillStyle = pFloatingObject.fillStyle @@ -243,12 +267,12 @@ function newProfileBall () { if (image !== null && image !== undefined) { browserCanvasContext.save() browserCanvasContext.beginPath() - browserCanvasContext.arc(pFloatingObject.currentPosition.x, pFloatingObject.currentPosition.y, pFloatingObject.currentImageSize / 2, 0, Math.PI * 2, true) + browserCanvasContext.arc(pFloatingObject.container.frame.position.x, pFloatingObject.container.frame.position.y, pFloatingObject.currentImageSize / 2, 0, Math.PI * 2, true) browserCanvasContext.closePath() browserCanvasContext.clip() - browserCanvasContext.drawImage(image, pFloatingObject.currentPosition.x - pFloatingObject.currentImageSize / 2, pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize, pFloatingObject.currentImageSize) + browserCanvasContext.drawImage(image, pFloatingObject.container.frame.position.x - pFloatingObject.currentImageSize / 2, pFloatingObject.container.frame.position.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize, pFloatingObject.currentImageSize) browserCanvasContext.beginPath() - browserCanvasContext.arc(pFloatingObject.currentPosition.x - pFloatingObject.currentImageSize / 2, pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize / 2, 0, Math.PI * 2, true) + browserCanvasContext.arc(pFloatingObject.container.frame.position.x - pFloatingObject.currentImageSize / 2, pFloatingObject.container.frame.position.y - pFloatingObject.currentImageSize / 2, pFloatingObject.currentImageSize / 2, 0, Math.PI * 2, true) browserCanvasContext.clip() browserCanvasContext.closePath() browserCanvasContext.restore() @@ -262,8 +286,8 @@ function newProfileBall () { if (menuItem.canDrawIcon === true && menuItem.currentRadius > 1) { let position = { - x: pFloatingObject.currentPosition.x + pFloatingObject.currentImageSize / 2 * Math.cos(toRadians(menuItem.angle)), - y: pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2 * Math.sin(toRadians(menuItem.angle)) + x: pFloatingObject.container.frame.position.x + pFloatingObject.currentImageSize / 2 * Math.cos(toRadians(menuItem.angle)), + y: pFloatingObject.container.frame.position.y - pFloatingObject.currentImageSize / 2 * Math.sin(toRadians(menuItem.angle)) } browserCanvasContext.drawImage(menuItem.icon, position.x - menuItem.currentRadius, position.y - menuItem.currentRadius, menuItem.currentRadius * 2, menuItem.currentRadius * 2) @@ -272,38 +296,38 @@ function newProfileBall () { /* Label Text */ - if (pFloatingObject.currentRadius > 6) { + if (pFloatingObject.container.frame.radius > 6) { browserCanvasContext.strokeStyle = pFloatingObject.labelStrokeStyle let labelPoint let fontSize = pFloatingObject.currentFontSize - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY let label - label = pFloatingObject.payload.profile.upLabel + label = pFloatingObject.payload.profile.subTitle if (label !== undefined) { labelPoint = { - x: pFloatingObject.currentPosition.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO, - y: pFloatingObject.currentPosition.y - pFloatingObject.currentImageSize / 2 - fontSize * FONT_ASPECT_RATIO - 10 + x: pFloatingObject.container.frame.position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO, + y: pFloatingObject.container.frame.position.y - pFloatingObject.currentImageSize / 2 - fontSize * FONT_ASPECT_RATIO - 10 } - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = pFloatingObject.labelStrokeStyle browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) } - label = pFloatingObject.payload.profile.downLabel + label = pFloatingObject.payload.profile.title if (label !== undefined) { labelPoint = { - x: pFloatingObject.currentPosition.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO, - y: pFloatingObject.currentPosition.y + pFloatingObject.currentImageSize / 2 + fontSize * FONT_ASPECT_RATIO + 15 + x: pFloatingObject.container.frame.position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO, + y: pFloatingObject.container.frame.position.y + pFloatingObject.currentImageSize / 2 + fontSize * FONT_ASPECT_RATIO + 15 } - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = pFloatingObject.labelStrokeStyle browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) } diff --git a/FloatingSpace/ProfileBalls.js b/FloatingSpace/ProfileBalls.js index de67bfca6..45f53e013 100644 --- a/FloatingSpace/ProfileBalls.js +++ b/FloatingSpace/ProfileBalls.js @@ -1,4 +1,4 @@ -  + function newProfileBalls () { const MODULE_NAME = 'Profile Balls' const INFO_LOG = false @@ -6,11 +6,11 @@ function newProfileBalls () { const logger = newWebDebugLog() logger.fileName = MODULE_NAME - /* + /* - This object deals with Profile Balls, a type of Floating Object that shows profile info in a floating ball. + This object deals with Profile Balls, a type of Floating Object that shows profile info in a floating ball. - */ + */ let thisObject = { @@ -25,54 +25,38 @@ function newProfileBalls () { return thisObject - function finalize () { - try { - if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') } - - floatingLayer.finalize() - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) } - } + function initialize (pFloatingLayer) { + floatingLayer = pFloatingLayer } - function initialize (pFloatingLayer, callBackFunction) { - try { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } - - floatingLayer = pFloatingLayer - - callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE) - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) } - callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) - } + function finalize () { + floatingLayer.finalize() + floatingLayer = undefined } function createNewProfileBall (pPayload, callBackFunction) { let floatingObject = newFloatingObject() - floatingObject.initialize('Profile Ball', onInitialized) + floatingObject.initialize('Profile Ball', '', floatingLayer) - function onInitialized (err) { - floatingObject.payload = pPayload + floatingObject.payload = pPayload - floatingObject.friction = 0.995 + floatingObject.friction = 0.995 - floatingObject.initializeMass(100) - floatingObject.initializeRadius(30) - floatingObject.initializeImageSize(50) - floatingObject.initializeFontSize(10) + floatingObject.initializeMass(100) + floatingObject.initializeRadius(30) + floatingObject.initializeImageSize(50) + floatingObject.initializeFontSize(10) - floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 0.5)' - floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)' + floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 0.5)' + floatingObject.labelStrokeStyle = 'rgba(60, 60, 60, 0.50)' - floatingLayer.addFloatingObject(floatingObject) + floatingLayer.addFloatingObject(floatingObject) - callBackFunction(GLOBAL.CUSTOM_OK_RESPONSE, floatingObject.handle) - } + callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE, floatingObject.handle) } function destroyProfileBall (pFloatingObjectHandle) { - floatingLayer.killFloatingObject(pFloatingObjectHandle) + floatingLayer.removeFloatingObject(pFloatingObjectHandle) } } diff --git a/FloatingSpace/StrategyPart.js b/FloatingSpace/StrategyPart.js new file mode 100644 index 000000000..aab937faa --- /dev/null +++ b/FloatingSpace/StrategyPart.js @@ -0,0 +1,369 @@ + +function newStrategyPart () { + const MODULE_NAME = 'Strategy Part' + const ERROR_LOG = true + + const logger = newWebDebugLog() + logger.fileName = MODULE_NAME + + let thisObject = { + fitFunction: undefined, + isVisibleFunction: undefined, + type: undefined, + menu: undefined, + isOnFocus: false, + container: undefined, + payload: undefined, + codeEditor: undefined, + partTitle: undefined, + physics: physics, + drawBackground: drawBackground, + drawMiddleground: drawMiddleground, + drawForeground: drawForeground, + drawOnFocus: drawOnFocus, + 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 icon + + let selfFocusEventSubscriptionId + let selfNotFocuskEventSubscriptionId + let selfDisplaceEventSubscriptionId + + return thisObject + + function finalize () { + thisObject.container.eventHandler.stopListening(selfFocusEventSubscriptionId) + thisObject.container.eventHandler.stopListening(selfNotFocuskEventSubscriptionId) + thisObject.container.eventHandler.stopListening(selfDisplaceEventSubscriptionId) + + thisObject.container.finalize() + thisObject.container = undefined + thisObject.payload = undefined + thisObject.menu.finalize() + thisObject.menu = undefined + thisObject.partTitle.finalize() + thisObject.partTitle = undefined + thisObject.fitFunction = undefined + thisObject.isVisibleFunction = undefined + + if (thisObject.codeEditor !== undefined) { + thisObject.codeEditor.finalize() + thisObject.codeEditor = undefined + } + + icon = undefined + } + + function initialize (payload, menuItemsInitialValues) { + thisObject.payload = payload + +/* Initialize the Menu */ + + thisObject.menu = newCircularMenu() + thisObject.menu.initialize(menuItemsInitialValues, thisObject.payload) + thisObject.menu.container.connectToParent(thisObject.container, false, false, true, true, false, false, true, true) + +/* Initialize Part Title */ + + thisObject.partTitle = newStrategyPartTitle() + thisObject.partTitle.isVisibleFunction = thisObject.isVisibleFunction + thisObject.partTitle.container.connectToParent(thisObject.container, false, false, true, true, false, false, true, true) + thisObject.partTitle.initialize(thisObject.payload) + +/* Load Part Image */ + + iconPhysics() + + selfFocusEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onFocus', onFocus) + selfNotFocuskEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onNotFocus', onNotFocus) + selfDisplaceEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onDisplace', onDisplace) + } + + function getContainer (point) { + let container + + if (thisObject.codeEditor !== undefined) { + container = thisObject.codeEditor.getContainer(point) + if (container !== undefined) { return container } + } + + container = thisObject.partTitle.getContainer(point) + if (container !== undefined) { return container } + + container = thisObject.menu.getContainer(point) + if (container !== undefined) { return container } + + if (thisObject.container.frame.isThisPointHere(point, true) === true) { + return thisObject.container + } else { + return undefined + } + } + + function physics () { + thisObject.menu.physics() + thisObject.partTitle.physics() + + if (thisObject.codeEditor !== undefined) { + thisObject.codeEditor.physics() + } + + if (thisObject.payload.chainParent === undefined) { + thisObject.payload.targetPosition.x = canvas.floatingSpace.container.frame.width / 2, + thisObject.payload.targetPosition.y = canvas.floatingSpace.container.frame.height / 2 + } else { + thisObject.payload.targetPosition.x = thisObject.payload.chainParent.payload.position.x + thisObject.payload.targetPosition.y = thisObject.payload.chainParent.payload.position.y + } + + iconPhysics() + } + + function iconPhysics () { + icon = canvas.strategySpace.iconByPartType.get(thisObject.payload.node.type) + } + + function onFocus () { + thisObject.isOnFocus = true + } + + function onNotFocus () { + thisObject.isOnFocus = false + if (thisObject.codeEditor !== undefined) { + thisObject.codeEditor.deactivate() + } + } + + function onDisplace (event) { + thisObject.partTitle.exitEditMode() + } + + function drawBackground () { + if (thisObject.isOnFocus === false) { + drawConnectingLine() + thisObject.menu.drawBackground() + } + } + + function drawMiddleground () { + if (thisObject.isOnFocus === false) { + drawText() + thisObject.partTitle.draw() + } + } + + function drawForeground () { + if (thisObject.isOnFocus === false) { + drawBodyAndPicture() + thisObject.menu.drawForeground() + } + } + + function drawOnFocus () { + if (thisObject.isOnFocus === true) { + drawConnectingLine() + thisObject.menu.drawBackground() + + if (thisObject.codeEditor !== undefined) { + thisObject.codeEditor.drawBackground() + thisObject.codeEditor.drawForeground() + } + + drawText() + thisObject.partTitle.draw() + + if (thisObject.codeEditor !== undefined) { + if (thisObject.codeEditor.visible === false) { + drawBodyAndPicture() + thisObject.menu.drawForeground() + } + } else { + drawBodyAndPicture() + thisObject.menu.drawForeground() + } + } + } + + function drawConnectingLine () { + if (thisObject.payload.chainParent === undefined) { return } + + let targetPoint = { + x: thisObject.payload.targetPosition.x, + y: thisObject.payload.targetPosition.y + } + + let position = { + x: 0, + y: 0 + } + + targetPoint = canvas.floatingSpace.container.frame.frameThisPoint(targetPoint) + position = thisObject.container.frame.frameThisPoint(position) + + if (thisObject.container.frame.radius > 1) { + /* Target Line */ + + browserCanvasContext.beginPath() + browserCanvasContext.moveTo(position.x, position.y) + browserCanvasContext.lineTo(targetPoint.x, targetPoint.y) + browserCanvasContext.strokeStyle = 'rgba(204, 204, 204, 0.5)' + browserCanvasContext.setLineDash([1, 4]) + browserCanvasContext.lineWidth = 1 + browserCanvasContext.stroke() + browserCanvasContext.setLineDash([0, 0]) + } + + if (thisObject.container.frame.radius > 0.5) { + /* Target Spot */ + + let radius = 1 + + browserCanvasContext.beginPath() + browserCanvasContext.arc(targetPoint.x, targetPoint.y, radius, 0, Math.PI * 2, true) + browserCanvasContext.closePath() + browserCanvasContext.fillStyle = 'rgba(30, 30, 30, 1)' + browserCanvasContext.fill() + } + } + + function drawText () { +/* Text Follows */ + let position = { + x: 0, + y: 0 + } + + position = thisObject.container.frame.frameThisPoint(position) + + let radius = thisObject.container.frame.radius + /* Label Text */ + let labelPoint + let fontSize = thisObject.payload.floatingObject.currentFontSize + let label + + if (radius > 6) { + const MAX_LABEL_LENGTH = 30 + + label = thisObject.payload.subTitle + label = addIndexNumber(label) + + if (label !== undefined) { + if (label.length > MAX_LABEL_LENGTH) { + label = label.substring(0, MAX_LABEL_LENGTH) + '...' + } + + labelPoint = { + x: position.x - label.length / 2 * fontSize * FONT_ASPECT_RATIO - 5, + y: position.y + radius * 2 / 3 + fontSize * FONT_ASPECT_RATIO + 15 + } + + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY + browserCanvasContext.fillStyle = thisObject.payload.floatingObject.labelStrokeStyle + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) + } + } + } + + function addIndexNumber (label) { + switch (thisObject.payload.node.type) { + case 'Phase': { + let parent = thisObject.payload.parentNode + for (let i = 0; i < parent.phases.length; i++) { + let phase = parent.phases[i] + if (phase.id === thisObject.payload.node.id) { + label = label + ' #' + (i + 1) + return label + } + } + break + } + case 'Situation': { + let parent = thisObject.payload.parentNode + for (let i = 0; i < parent.situations.length; i++) { + let situation = parent.situations[i] + if (situation.id === thisObject.payload.node.id) { + label = label + ' #' + (i + 1) + return label + } + } + break + } + case 'Condition': { + let parent = thisObject.payload.parentNode + for (let i = 0; i < parent.conditions.length; i++) { + let condition = parent.conditions[i] + if (condition.id === thisObject.payload.node.id) { + label = label + ' #' + (i + 1) + return label + } + } + break + } + default: { + return label + } + } + } + + function drawBodyAndPicture () { + let position = { + x: thisObject.container.frame.position.x, + y: thisObject.container.frame.position.y + } + + position = thisObject.container.frame.frameThisPoint(position) + + let radius = thisObject.container.frame.radius + + if (radius > 0.5) { + const VISIBLE_RADIUS = 5 + + let visiblePosition = { + x: thisObject.container.frame.position.x, + y: thisObject.container.frame.position.y + } + + visiblePosition = thisObject.container.frame.frameThisPoint(visiblePosition) + visiblePosition = thisObject.fitFunction(visiblePosition) + + browserCanvasContext.beginPath() + browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS, 0, Math.PI * 2, true) + browserCanvasContext.closePath() + + browserCanvasContext.fillStyle = thisObject.payload.floatingObject.fillStyle + + browserCanvasContext.fill() + + browserCanvasContext.beginPath() + browserCanvasContext.arc(visiblePosition.x, visiblePosition.y, VISIBLE_RADIUS / 2, 0, Math.PI * 2, true) + browserCanvasContext.closePath() + + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.BLACK + ', 1)' + + browserCanvasContext.fill() + } + + /* Image */ + + if (icon !== undefined) { + if (icon.canDrawIcon === true) { + browserCanvasContext.drawImage( + icon, position.x - thisObject.payload.floatingObject.currentImageSize / 2, + position.y - thisObject.payload.floatingObject.currentImageSize / 2, + thisObject.payload.floatingObject.currentImageSize, + thisObject.payload.floatingObject.currentImageSize) + } + } + } +} diff --git a/FloatingSpace/StrategyPartConstructor.js b/FloatingSpace/StrategyPartConstructor.js new file mode 100644 index 000000000..a4715cd3b --- /dev/null +++ b/FloatingSpace/StrategyPartConstructor.js @@ -0,0 +1,606 @@ + +function newStrategyPartConstructor () { + const MODULE_NAME = 'Strategy Part Constructor' + const ERROR_LOG = true + const logger = newWebDebugLog() + logger.fileName = MODULE_NAME + + let thisObject = { + + createStrategyPart: createStrategyPart, + destroyStrategyPart: destroyStrategyPart, + initialize: initialize, + finalize: finalize + + } + + let floatingLayer + + return thisObject + + function finalize () { + floatingLayer = undefined + + payload.uiObject.finalize() + payload.uiObject = undefined + } + + function initialize (pFloatingLayer) { + floatingLayer = pFloatingLayer + } + + function createStrategyPart (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('Strategy Part', payload) + payload.floatingObject = floatingObject + + let strategyPart = newStrategyPart() + strategyPart.fitFunction = canvas.floatingSpace.fitIntoVisibleArea + strategyPart.isVisibleFunction = canvas.floatingSpace.isThisPointVisible + let menuItemsInitialValues = getMenuItemsInitialValues(strategyPart, floatingObject, payload) + strategyPart.initialize(payload, menuItemsInitialValues) + strategyPart.container.connectToParent(floatingObject.container, false, false, true, true, false, false, true, true, true) + payload.uiObject = strategyPart + + setFloatingObjectBasicProperties(floatingObject, payload) + + floatingLayer.addFloatingObject(floatingObject) + + return + } + + function getMenuItemsInitialValues (strategyPart, floatingObject, payload) { + let menuItemsInitialValues = [] + switch (payload.node.type) { + case 'Trading System': { + floatingObject.isPinned = true + floatingObject.positionLocked = true + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: true, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Reload Trading System', + actionFunction: payload.onMenuItemClick, + label: 'Reload', + visible: false, + iconPathOn: 'vector', + iconPathOff: 'vector', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -60 + }, + { + action: 'Save Trading System', + actionFunction: payload.onMenuItemClick, + label: 'Save Changes', + workingLabel: 'Saving...', + workDoneLabel: 'Saved', + workFailedLabel: 'Not Saved', + visible: false, + iconPathOn: 'upload', + iconPathOff: 'upload', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -20 + }, + { + action: 'New Strategy', + actionFunction: payload.onMenuItemClick, + label: 'New Strategy', + visible: false, + iconPathOn: 'quality', + iconPathOff: 'quality', + relatedStrategyPart: 'Strategy', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 20 + }, + { + action: 'Open Settings', + actionFunction: payload.onMenuItemClick, + label: 'Settings', + visible: false, + iconPathOn: 'tools', + iconPathOff: 'tools', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 60 + }] + break + } + case 'Strategy': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Delete Strategy', + actionFunction: payload.onMenuItemClick, + label: 'Delete This Strategy', + visible: false, + iconPathOn: 'trash', + iconPathOff: 'trash', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -20 + }, + { + action: 'Open Settings', + actionFunction: payload.onMenuItemClick, + label: 'Settings', + visible: false, + iconPathOn: 'tools', + iconPathOff: 'tools', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 20 + }] + break + } + case 'Strategy Entry Event': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Add Situation', + actionFunction: payload.onMenuItemClick, + label: 'Add Situation', + visible: false, + iconPathOn: 'attractive', + iconPathOff: 'attractive', + relatedStrategyPart: 'Situation', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }] + break + } + case 'Strategy Exit Event': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Add Situation', + actionFunction: payload.onMenuItemClick, + label: 'Add Situation', + visible: false, + iconPathOn: 'attractive', + iconPathOff: 'attractive', + relatedStrategyPart: 'Situation', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }] + break + } + case 'Trade Entry Event': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Add Situation', + actionFunction: payload.onMenuItemClick, + label: 'Add Situation', + visible: false, + iconPathOn: 'attractive', + iconPathOff: 'attractive', + relatedStrategyPart: 'Situation', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }] + break + } + case 'Stop': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Add Phase', + actionFunction: payload.onMenuItemClick, + label: 'Add Phase', + visible: false, + iconPathOn: 'placeholder', + iconPathOff: 'placeholder', + relatedStrategyPart: 'Phase', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }] + break + } + case 'Take Profit': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Add Phase', + actionFunction: payload.onMenuItemClick, + label: 'Add Phase', + visible: false, + iconPathOn: 'placeholder', + iconPathOff: 'placeholder', + relatedStrategyPart: 'Phase', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }] + break + } + case 'Phase': { + strategyPart.codeEditor = newCodeEditor() + strategyPart.codeEditor.isVisibleFunction = strategyPart.isVisibleFunction + strategyPart.codeEditor.initialize() + strategyPart.codeEditor.container.connectToParent(strategyPart.container, false, false, true, true, false, false, false, false) + + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Edit Code', + actionFunction: strategyPart.codeEditor.activate, + label: 'Edit Code', + visible: false, + iconPathOn: 'html', + iconPathOff: 'html', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 40 + }, + { + action: 'Add Situation', + actionFunction: payload.onMenuItemClick, + label: 'Add Situation', + visible: false, + iconPathOn: 'attractive', + iconPathOff: 'attractive', + relatedStrategyPart: 'Situation', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 0 + }, + { + action: 'Delete Phase', + actionFunction: payload.onMenuItemClick, + label: 'Delete This Phase', + visible: false, + iconPathOn: 'trash', + iconPathOff: 'trash', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -40 + }] + break + } + case 'Situation': { + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Add Condition', + actionFunction: payload.onMenuItemClick, + label: 'Add Condition', + visible: false, + iconPathOn: 'testing', + iconPathOff: 'testing', + relatedStrategyPart: 'Condition', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 20 + }, + { + action: 'Delete Situation', + actionFunction: payload.onMenuItemClick, + label: 'Delete This Situation', + visible: false, + iconPathOn: 'trash', + iconPathOff: 'trash', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -20 + }] + break + } + case 'Condition': { + strategyPart.codeEditor = newCodeEditor() + strategyPart.codeEditor.isVisibleFunction = strategyPart.isVisibleFunction + strategyPart.codeEditor.initialize() + strategyPart.codeEditor.container.connectToParent(strategyPart.container, false, false, true, true, false, false, false, false) + + menuItemsInitialValues = [ + { + action: 'Pin / Unpin', + actionFunction: floatingObject.pinToggle, + currentStatus: false, + label: undefined, + visible: false, + iconPathOn: 'target', + iconPathOff: 'security', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -135 + }, + { + action: 'Edit Code', + actionFunction: strategyPart.codeEditor.activate, + label: 'Edit Code', + visible: false, + iconPathOn: 'html', + iconPathOff: 'html', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: 20 + }, + { + action: 'Delete Condition', + actionFunction: payload.onMenuItemClick, + label: 'Delete This Condition', + visible: false, + iconPathOn: 'trash', + iconPathOff: 'trash', + rawRadius: 8, + targetRadius: 0, + currentRadius: 0, + angle: -20 + }] + break + } + default: { + if (ERROR_LOG === true) { logger.write('[ERROR] getMenuItemsInitialValues -> Part Type not Recognized -> type = ' + payload.node.type) } + } + } + + return menuItemsInitialValues + } + + function setFloatingObjectBasicProperties (floatingObject, payload) { + const FRICTION = 0.97 + + switch (payload.node.type) { + case 'Trading System': { + level_0() + break + } + case 'Strategy': { + level_1() + break + } + case 'Strategy Entry Event': { + level_2() + break + } + case 'Strategy Exit Event': { + level_2() + break + } + case 'Trade Entry Event': { + level_2() + break + } + case 'Trade Exit Event': { + level_2() + break + } + case 'Stop': { + level_2() + break + } + case 'Take Profit': { + level_2() + break + } + case 'Phase': { + level_3() + break + } + case 'Situation': { + level_4() + break + } + case 'Condition': { + level_5() + break + } + default: { + if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> Part Type not Recognized -> type = ' + payload.node.type) } + return + } + } + + function level_0 () { + floatingObject.friction = 0.93 + + floatingObject.initializeMass(500) + floatingObject.initializeRadius(45) + floatingObject.initializeImageSize(80) + floatingObject.initializeFontSize(10) + + floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)' + } + + function level_1 () { + floatingObject.friction = 0.94 + + floatingObject.initializeMass(250) + floatingObject.initializeRadius(45) + floatingObject.initializeImageSize(80) + floatingObject.initializeFontSize(10) + + floatingObject.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)' + } + + function level_2 () { + floatingObject.friction = FRICTION + + floatingObject.initializeMass(50) + floatingObject.initializeRadius(40) + floatingObject.initializeImageSize(70) + floatingObject.initializeFontSize(10) + + floatingObject.fillStyle = 'rgba(' + UI_COLOR.GREEN + ', 1)' + } + + function level_3 () { + floatingObject.friction = FRICTION + + floatingObject.initializeMass(10) + floatingObject.initializeRadius(35) + floatingObject.initializeImageSize(60) + floatingObject.initializeFontSize(10) + + floatingObject.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 1)' + } + + function level_4 () { + floatingObject.friction = FRICTION + + floatingObject.initializeMass(10) + floatingObject.initializeRadius(30) + floatingObject.initializeImageSize(50) + floatingObject.initializeFontSize(10) + + floatingObject.fillStyle = 'rgba(' + UI_COLOR.TITANIUM_YELLOW + ', 1)' + } + + function level_5 () { + floatingObject.friction = FRICTION + + floatingObject.initializeMass(10) + floatingObject.initializeRadius(25) + floatingObject.initializeImageSize(30) + floatingObject.initializeFontSize(10) + + floatingObject.fillStyle = 'rgba(' + UI_COLOR.RED + ', 1)' + } + + floatingObject.labelStrokeStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)' + } + + function destroyStrategyPart (payload) { + floatingLayer.removeFloatingObject(payload.floatingObject.handle) + + payload.floatingObject.finalize() + payload.floatingObject = undefined + + payload.uiObject.finalize() + payload.uiObject = undefined + } +} diff --git a/FloatingSpace/StrategyPartTitle.js b/FloatingSpace/StrategyPartTitle.js new file mode 100644 index 000000000..8597bff14 --- /dev/null +++ b/FloatingSpace/StrategyPartTitle.js @@ -0,0 +1,260 @@ + +function newStrategyPartTitle () { + const MODULE_NAME = 'Strategy Part 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 + + switch (payload.node.type) { + case 'Trading System': { + break + } + case 'Strategy': { + thisObject.allwaysVisible = true + break + } + case 'Strategy Entry Event': { + break + } + case 'Strategy Exit Event': { + break + } + case 'Trade Entry Event': { + break + } + case 'Stop': { + break + } + case 'Take Profit': { + break + } + case 'Phase': { + break + } + case 'Situation': { + break + } + case 'Condition': { + break + } + default: { + if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> Part Type not Recognized -> type = ' + payload.node.type) } + } + } + + selfFocusEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onFocus', onFocus) + selfNotFocuskEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onNotFocus', onNotFocus) + selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick) + } + + function getContainer (point) { + 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 () { + let title = trimTitle(thisObject.payload.title) + + const FRAME_HEIGHT = 25 + const FRAME_WIDTH = title.length / 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 - 10 - FRAME_HEIGHT + + thisObject.container.frame.width = FRAME_WIDTH + thisObject.container.frame.height = FRAME_HEIGHT + + if (thisObject.editMode === true) { + let inputPosition = { + x: 0, + y: 0 + window.canvasApp.topMargin + } + + inputPosition = thisObject.container.frame.frameThisPoint(inputPosition) + + if (inputPosition.y < window.canvasApp.topMargin) { 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 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; 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: 0, + 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) { + const MAX_LABEL_LENGTH = 25 + if (title.length > MAX_LABEL_LENGTH) { + title = title.substring(0, MAX_LABEL_LENGTH) + '...' + } + return title + } +} + diff --git a/Frame.js b/Frame.js index f7b3eec4f..a726eae7d 100644 --- a/Frame.js +++ b/Frame.js @@ -1,57 +1,63 @@ -  -function newFrame () { - const PANEL_CORNERS_RADIOUS = 5 - const TITLE_BAR_HEIGHT = 14 // this must be grater than radius - let frame = { +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, + position: undefined, + container: undefined, width: browserCanvas.width, height: browserCanvas.height, - position: undefined, getBodyHeight: getBodyHeight, draw: draw, - container: undefined, + fitIntoFrame: fitIntoFrame, frameThisPoint: frameThisPoint, // This function changes the actual frame coordinate system to the screen coordinate system. unframeThisPoint: unframeThisPoint, - fitIntoFrame: fitIntoFrame, isThisPointHere: isThisPointHere, // This function return true is the point received as parameter lives within this frame. + isThisScreenPointHere: isThisScreenPointHere, isInViewPort: isInViewPort, canYouMoveHere: canYouMoveHere, - canYouZoomHere: canYouZoomHere, initialize: initialize } - return frame + return thisObject - function initialize () { - var position = { + function initialize (pType) { + if (pType !== undefined) { thisObject.type = pType } + + let position = { x: 0, y: 0 } - this.position = position + thisObject.position = position } function getBodyHeight () { - return frame.height - TITLE_BAR_HEIGHT + 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 viewPort */ + point1 = { x: 0, y: 0 } point3 = { - x: frame.width, - y: frame.height + x: thisObject.width, + y: thisObject.height } - /* Now the transformations. */ + /* Now the transformations. */ - point1 = transformThisPoint(point1, frame.container) - point3 = transformThisPoint(point3, frame.container) + point1 = transformThisPoint(point1, thisObject.container) + point3 = transformThisPoint(point3, thisObject.container) if (point1.x < viewPort.visibleArea.topRight.x && point1.y < viewPort.visibleArea.bottomRight.y && point3.x > viewPort.visibleArea.bottomLeft.x && point3.y > viewPort.visibleArea.topLeft.y) { return true @@ -60,19 +66,81 @@ function newFrame () { } } + 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 + 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 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 > frame.width) { - point.x = frame.width + if (point.x > thisObject.width) { + point.x = thisObject.width } if (point.x < 0) { point.x = 0 } - if (point.y > frame.height) { - point.y = frame.height + if (point.y > thisObject.height) { + point.y = thisObject.height } if (point.y < 0) { @@ -82,158 +150,71 @@ function newFrame () { return point } - function frameThisPoint (point) { - if (this.parentFrame !== undefined) { - point = this.parentFrame.frameThisPoint(point) - } - - point.x = point.x + frame.position.x - point.y = point.y + frame.position.y - - return point - } - - function unframeThisPoint (point) { - if (this.parentFrame !== undefined) { - point = this.parentFrame.unframeThisPoint(point) - } - - point.x = point.x - this.position.x - point.y = point.y - this.position.y - - return point - } - function canYouMoveHere (tempDisplacement) { - /* + /* - The current frame has a position and a displacement. We need to check that none of the boundaries points of the frame fall outside of its container frame. - First we apply the theoreticall displacement. + The current frame has a position and a displacement. We need to check that none of the boundaries points of the frame fall outside of its container frame. + First we apply the theoreticall displacement. - */ + */ point1 = { - x: this.position.x, - y: this.position.y + x: thisObject.position.x, + y: thisObject.position.y } point2 = { - x: this.position.x + this.width, - y: this.position.y + x: thisObject.position.x + thisObject.width, + y: thisObject.position.y } point3 = { - x: this.position.x + this.width, - y: this.position.y + this.height + x: thisObject.position.x + thisObject.width, + y: thisObject.position.y + thisObject.height } point4 = { - x: this.position.x, - y: this.position.y + this.height + x: thisObject.position.x, + y: thisObject.position.y + thisObject.height } - /* Now the transformations. */ + /* Now the transformations. */ - if (this.parentFrame !== undefined) { - // If there is not a parent then there is no point to check bounderies. + if (thisObject.parentFrame !== undefined) { + // If there is not a parent then there is no point to check bounderies. - point1 = this.parentFrame.frameThisPoint(point1) - point2 = this.parentFrame.frameThisPoint(point2) - point3 = this.parentFrame.frameThisPoint(point3) - point4 = this.parentFrame.frameThisPoint(point4) + point1 = thisObject.parentFrame.frameThisPoint(point1) + point2 = thisObject.parentFrame.frameThisPoint(point2) + point3 = thisObject.parentFrame.frameThisPoint(point3) + point4 = thisObject.parentFrame.frameThisPoint(point4) - /* We apply the temporary displacement. */ + /* We apply the temporary displacement. */ point1 = tempDisplacement.displaceThisPoint(point1) point2 = tempDisplacement.displaceThisPoint(point2) point3 = tempDisplacement.displaceThisPoint(point3) point4 = tempDisplacement.displaceThisPoint(point4) - /* We add the actual displacement. */ + /* We add the actual displacement. */ - point1 = this.container.displacement.displaceThisPoint(point1) - point2 = this.container.displacement.displaceThisPoint(point2) - point3 = this.container.displacement.displaceThisPoint(point3) - point4 = this.container.displacement.displaceThisPoint(point4) + point1 = thisObject.container.displacement.displaceThisPoint(point1) + point2 = thisObject.container.displacement.displaceThisPoint(point2) + point3 = thisObject.container.displacement.displaceThisPoint(point3) + point4 = thisObject.container.displacement.displaceThisPoint(point4) - if (this.parentFrame.isThisPointHere(point1) === false) { + if (thisObject.parentFrame.isThisPointHere(point1) === false) { return false } - if (this.parentFrame.isThisPointHere(point2) === false) { + if (thisObject.parentFrame.isThisPointHere(point2) === false) { return false } - if (this.parentFrame.isThisPointHere(point3) === false) { + if (thisObject.parentFrame.isThisPointHere(point3) === false) { return false } - if (this.parentFrame.isThisPointHere(point4) === false) { - return false - } - } - - return true - } - - function canYouZoomHere (tempZoom) { - point1 = { - x: this.position.x, - y: this.position.y - } - - point2 = { - x: this.position.x + this.width, - y: this.position.y - } - - point3 = { - x: this.position.x + this.width, - y: this.position.y + this.height - } - - point4 = { - x: this.position.x, - y: this.position.y + this.height - } - - /* Now the transformations. */ - - if (this.parentFrame !== undefined) { - // If there is not a parent then there is no point to check bounderies. - - point1 = this.parentFrame.frameThisPoint(point1) - point2 = this.parentFrame.frameThisPoint(point2) - point3 = this.parentFrame.frameThisPoint(point3) - point4 = this.parentFrame.frameThisPoint(point4) - - /* We add the actual displacement. */ - - point1 = this.container.displacement.displaceThisPoint(point1) - point2 = this.container.displacement.displaceThisPoint(point2) - point3 = this.container.displacement.displaceThisPoint(point3) - point4 = this.container.displacement.displaceThisPoint(point4) - - /* We temp zoom. */ - - point1 = tempZoom.zoomThisPoint(point1) - point2 = tempZoom.zoomThisPoint(point2) - point3 = tempZoom.zoomThisPoint(point3) - point4 = tempZoom.zoomThisPoint(point4) - - if (this.parentFrame.isThisPointHere(point1) === false) { - return false - } - - if (this.parentFrame.isThisPointHere(point2) === false) { - return false - } - - if (this.parentFrame.isThisPointHere(point3) === false) { - return false - } - - if (this.parentFrame.isThisPointHere(point4) === false) { + if (thisObject.parentFrame.isThisPointHere(point4) === false) { return false } } @@ -242,61 +223,104 @@ function newFrame () { } function isThisPointHere (point, outsideViewPort, dontTransform) { - // The second parameter is usefull when you want to check a point that you already know is outside the viewport. + // The second parameter is usefull when you want to check a point that you already know is outside the viewport. - /* We need not to modify the point received, so me make a copy of it. */ + /* We need not to modify the point received, so me make a copy of it. */ - var checkPoint = { + 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. */ + /* 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 = this.container.displacement.undisplaceThisPoint(checkPoint) - checkPoint = this.container.frame.unframeThisPoint(checkPoint) + checkPoint = thisObject.container.displacement.undisplaceThisPoint(checkPoint) + checkPoint = thisObject.container.frame.unframeThisPoint(checkPoint) } else { - checkPoint = unTransformThisPoint(checkPoint, frame.container) + checkPoint = unTransformThisPoint(checkPoint, thisObject.container) } } - /* Now we check if the resulting point is whin the current Frame. */ + /* Now we check if the resulting point is whin the current Frame. */ - if (checkPoint.x < 0 || checkPoint.y < 0 || checkPoint.x > frame.width || checkPoint.y > frame.height) { - /* The point received is not in this frame */ + if (thisObject.type === 'Circle') { + let distance = Math.sqrt(Math.pow(thisObject.position.x - point.x, 2) + Math.pow(thisObject.position.y - point.y, 2)) - return false - } else { - /* The point is within this frame. */ + if (distance < thisObject.radius) { + return true + } else { + return false + } + } - return true + 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) { + function isThisScreenPointHere (point) { + let checkPoint = { + x: point.x, + y: point.y + } + + let thisPoint = { + x: thisObject.position.x, + y: thisObject.position.y + } + + 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) { if (drawBorders === true) { - borders() + borders(fitFunction) } if (drawGrid === true) { - grid() + grid(fitFunction) } if (drawBackground === true) { - background() + background(fitFunction) } } - function background () { + function background (fitFunction) { let params = { - cornerRadious: 5, + cornerRadius: 5, lineWidth: 0.1, opacity: 0.75, - container: frame.container, + container: thisObject.container, borderColor: UI_COLOR.DARK, - backgroundColor: UI_COLOR.WHITE + backgroundColor: UI_COLOR.WHITE, + fitFunction: fitFunction } roundedCornersBackground(params) @@ -307,25 +331,30 @@ function newFrame () { } titleBarPoint2 = { - x: frame.width, + x: thisObject.width, y: TITLE_BAR_HEIGHT } - /* Now the transformations. */ + /* Now the transformations. */ titleBarPoint1 = frameThisPoint(titleBarPoint1) titleBarPoint2 = frameThisPoint(titleBarPoint2) - /* We paint the title bar now */ + if (fitFunction !== undefined) { + titleBarPoint1 = fitFunction(titleBarPoint1) + titleBarPoint2 = fitFunction(titleBarPoint2) + } - browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 0.75)' + /* 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_RADIOUS, borderPoint1.y) - browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, PANEL_CORNERS_RADIOUS, 1.0 * Math.PI, 1.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - PANEL_CORNERS_RADIOUS) - browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, PANEL_CORNERS_RADIOUS, 1.5 * Math.PI, 2.0 * Math.PI) + browserCanvasContext.lineTo(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() @@ -335,31 +364,35 @@ function newFrame () { browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.MANGANESE_PURPLE + ', 0.75)' browserCanvasContext.stroke() - /* print the title */ + /* print the title */ let labelPoint let fontSize = 10 - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY - let label = frame.containerName + let label = thisObject.containerName let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO let yOffset = (TITLE_BAR_HEIGHT - fontSize) / 2 + 2 labelPoint = { - x: frame.width / 2 - xOffset, + x: thisObject.width / 2 - xOffset, y: TITLE_BAR_HEIGHT - yOffset } - labelPoint = frame.frameThisPoint(labelPoint) + 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 () { - /* Lest get the important points of the drawing so as to apply the needed transformations. */ + function borders (fitFunction) { + /* Lest get the important points of the drawing so as to apply the needed transformations. */ let point1 let point2 @@ -372,28 +405,35 @@ function newFrame () { } point2 = { - x: frame.width, + x: thisObject.width, y: 0 } point3 = { - x: frame.width, - y: frame.height + x: thisObject.width, + y: thisObject.height } point4 = { x: 0, - y: frame.height + y: thisObject.height } - /* Now the transformations. */ + /* Now the transformations. */ - point1 = transformThisPoint(point1, frame.container) - point2 = transformThisPoint(point2, frame.container) - point3 = transformThisPoint(point3, frame.container) - point4 = transformThisPoint(point4, frame.container) + point1 = transformThisPoint(point1, thisObject.container) + point2 = transformThisPoint(point2, thisObject.container) + point3 = transformThisPoint(point3, thisObject.container) + point4 = transformThisPoint(point4, thisObject.container) - /* Lets start the drawing. */ + 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) @@ -410,45 +450,55 @@ function newFrame () { browserCanvasContext.closePath() } - function grid (smallLines) { + function grid (fitFunction, smallLines) { if (smallLines === true) { - /* Small Lines */ + /* Small Lines */ - var step = frame.width / 100 + let step = thisObject.width / 100 browserCanvasContext.beginPath() - for (var i = 0; i < frame.width; i = i + step) { - for (var j = 0; j < frame.height; j = j + step) { + 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: frame.width, + x: thisObject.width, y: j } - point1 = transformThisPoint(point1, frame.container) - point2 = transformThisPoint(point2, frame.container) + 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: frame.width, - y: frame.height + x: thisObject.width, + y: thisObject.height } let point4 = { x: 0, - y: frame.height + y: thisObject.height } - point3 = transformThisPoint(point3, frame.container) - point4 = transformThisPoint(point4, frame.container) + 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) @@ -459,26 +509,31 @@ function newFrame () { browserCanvasContext.stroke() } - /* Main Lines */ + /* Main Lines */ - var step = frame.width / 20 + let step = thisObject.width / 20 browserCanvasContext.beginPath() - for (var i = 0; i < frame.width; i = i + step) { - for (var j = 0; j < frame.height; j = j + step) { + 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: frame.width, + x: thisObject.width, y: j } - point1 = transformThisPoint(point1, frame.container) - point2 = transformThisPoint(point2, frame.container) + 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) @@ -491,11 +546,16 @@ function newFrame () { let point4 = { x: i, - y: frame.height + y: thisObject.height } - point3 = transformThisPoint(point3, frame.container) - point4 = transformThisPoint(point4, frame.container) + 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) diff --git a/Globals.js b/Globals.js index 4fa5de32a..7fb404879 100644 --- a/Globals.js +++ b/Globals.js @@ -19,7 +19,7 @@ UI_COLOR = { DARK: "48, 48, 54", LIGHT: "234, 226, 222", GREY: "150, 150, 150", - LIGHT_GREY: "247, 247, 247", + LIGHT_GREY: "247, 247, 247", WHITE: "255, 255, 255", BLACK: "0, 0, 0", GOLDEN_ORANGE: "240, 162, 2", @@ -28,7 +28,9 @@ UI_COLOR = { RED: "223, 70, 60", PATINATED_TURQUOISE: "27,153,139", TITANIUM_YELLOW: "244,228,9", - MANGANESE_PURPLE: "91,80,122" + MANGANESE_PURPLE: "91,80,122", + TURQUOISE: "74,207,217", + DARK_TURQUOISE: "2,149,170" }; /* User Interface Fonts */ @@ -121,6 +123,8 @@ function convertTimePeriodToName(pTimePeriod) { window.AT_BREAKPOINT = false; +const LOGGED_IN_USER_LOCAL_STORAGE = "xuser" +const LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE = "xaccess_token" const USDT_BTC_HTH = 19900; // This is needed to know the scale of the market time line. @@ -151,6 +155,7 @@ const _1_MINUTE_IN_MILISECONDS = 1 * 60 * 1000; let NEW_SESSION_INITIAL_DATE = new Date(); // This value will be overwritten at the 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 viewPort.initialize if the user had a prevous session with this same browser. +let VERY_LARGE_NUMBER = 100000000000 let maxDate = new Date(); maxDate.setMilliseconds(0); @@ -160,8 +165,10 @@ const MIN_PLOTABLE_DATE = new Date(2015, 0, 1, 0, 0, 0); const MAX_PLOTABLE_DATE = maxDate; const TOP_SPACE_HEIGHT = 5; -const BOTTOM_SPACE_HEIGHT = 35; +const COCKPIT_SPACE_HEIGHT = 40; const BREAKPOINT_HEIGHT = 15; +const SIDE_PANEL_WIDTH = 450 +let COCKPIT_SPACE_POSITION = browserCanvas.height - COCKPIT_SPACE_HEIGHT const PRODUCT_CARD_STATUS = { ON: 'on', diff --git a/Panels/PanelTabButton.js b/Panels/PanelTabButton.js index a1d44c195..fe41ecbf6 100644 --- a/Panels/PanelTabButton.js +++ b/Panels/PanelTabButton.js @@ -1,8 +1,9 @@ function newPanelTabButton () { let thisObject = { container: undefined, - draw: draw, + fitFunction: undefined, parentContainer: undefined, + draw: draw, getContainer: getContainer, // returns the inner most container that holds the point received by parameter. initialize: initialize } @@ -203,6 +204,12 @@ function newPanelTabButton () { 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() @@ -220,4 +227,3 @@ function newPanelTabButton () { browserCanvasContext.fill() } } - diff --git a/ProductCard.js b/Panels/ProductCard.js similarity index 94% rename from ProductCard.js rename to Panels/ProductCard.js index 46512e69c..f98d94155 100644 --- a/ProductCard.js +++ b/Panels/ProductCard.js @@ -16,15 +16,13 @@ function newProductCard () { bot: undefined, product: undefined, code: undefined, - + fitFunction: undefined, setDatetime: setDatetime, setTimePeriod: setTimePeriod, - onMarketFileLoaded: onMarketFileLoaded, onDailyFileLoaded: onDailyFileLoaded, onSingleFileLoaded: onSingleFileLoaded, onFileSequenceLoaded: onFileSequenceLoaded, - getContainer: getContainer, // returns the inner most container that holds the point received by parameter. initialize: initialize } @@ -429,6 +427,11 @@ function newProductCard () { */ + let fitImagePoint = { + x: 0, + y: 0 + } + const devTeamImageSize = 20 const botImageSize = 20 const plotterImageSize = { @@ -448,6 +451,8 @@ function newProductCard () { teamImagePoint = thisObject.container.frame.frameThisPoint(teamImagePoint) + fitImagePoint = thisObject.fitFunction(teamImagePoint) + let teamImage if (legacyTeamAvatarLoaded === true) { @@ -458,7 +463,7 @@ function newProductCard () { teamImage = teamAvatar } - if (teamImage !== undefined) { + if (teamImage !== undefined && teamImagePoint.y === fitImagePoint.y) { if (teamImage.naturalHeight !== 0) { /* The image is rounded before being displayed. */ @@ -485,6 +490,7 @@ function newProductCard () { } botImagePoint = thisObject.container.frame.frameThisPoint(botImagePoint) + fitImagePoint = thisObject.fitFunction(botImagePoint) let imageId = thisObject.bot.devTeam + '.' + thisObject.bot.profilePicture @@ -493,7 +499,7 @@ function newProductCard () { botImage = thisObject.bot.avatar - if (botImage !== undefined) { + if (botImage !== undefined && botImagePoint.y === fitImagePoint.y) { if (botImage.naturalHeight !== 0) { /* The image is rounded before being displayed. */ @@ -522,11 +528,17 @@ function newProductCard () { } plotterImagePoint = thisObject.container.frame.frameThisPoint(plotterImagePoint) + fitImagePoint = { + x: 0, + y: plotterImagePoint.y + plotterImageSize.height + } + + fitImagePoint = thisObject.fitFunction(fitImagePoint) let imageId = thisObject.product.plotter.devTeam + '.' + thisObject.product.plotter.codeName + '.' + thisObject.product.plotter.moduleName + '.' + thisObject.product.plotter.profilePicture let plotterImage = legacyPlotterBanner - if (plotterImage !== undefined) { + if (plotterImage !== undefined && plotterImagePoint.y + plotterImageSize.height === fitImagePoint.y) { if (plotterImage.naturalHeight !== 0) { browserCanvasContext.drawImage(plotterImage, plotterImagePoint.x, plotterImagePoint.y, plotterImageSize.width, plotterImageSize.height) } @@ -588,6 +600,11 @@ function newProductCard () { point3 = thisObject.container.frame.frameThisPoint(point3) point4 = thisObject.container.frame.frameThisPoint(point4) + point1 = thisObject.fitFunction(point1) + point2 = thisObject.fitFunction(point2) + point3 = thisObject.fitFunction(point3) + point4 = thisObject.fitFunction(point4) + browserCanvasContext.beginPath() browserCanvasContext.moveTo(point1.x, point1.y) browserCanvasContext.lineTo(point2.x, point2.y) @@ -609,7 +626,7 @@ function newProductCard () { let labelPoint let fontSize = 10 - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY let label @@ -625,8 +642,9 @@ function newProductCard () { } labelPoint = thisObject.container.frame.frameThisPoint(labelPoint) + labelPoint = thisObject.fitFunction(labelPoint) - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)' browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) @@ -641,8 +659,9 @@ function newProductCard () { } labelPoint = thisObject.container.frame.frameThisPoint(labelPoint) + labelPoint = thisObject.fitFunction(labelPoint) - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)' browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) } @@ -664,8 +683,9 @@ function newProductCard () { } labelPoint = thisObject.container.frame.frameThisPoint(labelPoint) + labelPoint = thisObject.fitFunction(labelPoint) - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)' browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) @@ -728,6 +748,11 @@ function newProductCard () { point3 = thisObject.container.frame.frameThisPoint(point3) point4 = thisObject.container.frame.frameThisPoint(point4) + point1 = thisObject.fitFunction(point1) + point2 = thisObject.fitFunction(point2) + point3 = thisObject.fitFunction(point3) + point4 = thisObject.fitFunction(point4) + browserCanvasContext.beginPath() browserCanvasContext.moveTo(point1.x, point1.y) browserCanvasContext.lineTo(point2.x, point2.y) @@ -790,6 +815,11 @@ function newProductCard () { point3 = thisObject.container.frame.frameThisPoint(point3) point4 = thisObject.container.frame.frameThisPoint(point4) + point1 = thisObject.fitFunction(point1) + point2 = thisObject.fitFunction(point2) + point3 = thisObject.fitFunction(point3) + point4 = thisObject.fitFunction(point4) + browserCanvasContext.beginPath() browserCanvasContext.moveTo(point1.x, point1.y) browserCanvasContext.lineTo(point2.x, point2.y) @@ -852,6 +882,11 @@ function newProductCard () { point3 = thisObject.container.frame.frameThisPoint(point3) point4 = thisObject.container.frame.frameThisPoint(point4) + point1 = thisObject.fitFunction(point1) + point2 = thisObject.fitFunction(point2) + point3 = thisObject.fitFunction(point3) + point4 = thisObject.fitFunction(point4) + browserCanvasContext.beginPath() browserCanvasContext.moveTo(point1.x, point1.y) browserCanvasContext.lineTo(point2.x, point2.y) @@ -914,6 +949,11 @@ function newProductCard () { point3 = thisObject.container.frame.frameThisPoint(point3) point4 = thisObject.container.frame.frameThisPoint(point4) + point1 = thisObject.fitFunction(point1) + point2 = thisObject.fitFunction(point2) + point3 = thisObject.fitFunction(point3) + point4 = thisObject.fitFunction(point4) + browserCanvasContext.beginPath() browserCanvasContext.moveTo(point1.x, point1.y) browserCanvasContext.lineTo(point2.x, point2.y) @@ -929,4 +969,3 @@ function newProductCard () { browserCanvasContext.stroke() } } - diff --git a/Panels/ProductsPanel.js b/Panels/ProductsPanel.js index 0c532a7e0..5f690130c 100644 --- a/Panels/ProductsPanel.js +++ b/Panels/ProductsPanel.js @@ -1,245 +1,260 @@ - function newProductsPanel () { - let thisObject = { - container: undefined, - getLoadingProductCards: getLoadingProductCards, - draw: draw, - getContainer: getContainer, // returns the inner most container that holds the point received by parameter. - initialize: initialize - } +function newProductsPanel () { + let thisObject = { + fitFunction: undefined, + container: undefined, + getLoadingProductCards: getLoadingProductCards, + draw: draw, + getContainer: getContainer, // returns the inner most container that holds the point received by parameter. + initialize: initialize + } - /* Cointainer stuff */ + /* Cointainer stuff */ - var container = newContainer() + let container = newContainer() - container.initialize() + container.initialize() - container.isDraggeable = true - container.isWheelable = true + container.isDraggeable = true + container.isWheelable = true - thisObject.container = container + thisObject.container = container - let isInitialized = false - let productCards = [] + let isInitialized = false + let productCards = [] - let visibleProductCards = [] - let firstVisibleCard = 1 + let visibleProductCards = [] + let firstVisibleCard = 1 - /* Needed Variables */ + /* Needed Variables */ - let lastY = 5 - let panelTabButton + let lastY = 5 + let panelTabButton - let exchange - let market + let exchange + let market - return thisObject + return thisObject - function initialize (pExchange, pMarket) { - exchange = pExchange - market = pMarket + function initialize (pExchange, pMarket) { + exchange = pExchange + market = pMarket - thisObject.container.name = 'Layers @ ' + exchange + ' ' + market.assetB + '/' + market.assetA - thisObject.container.frame.containerName = thisObject.container.name - thisObject.container.frame.width = UI_PANEL.WIDTH.LARGE - thisObject.container.frame.height = UI_PANEL.HEIGHT.LARGE // viewPort.visibleArea.bottomLeft.y - viewPort.visibleArea.topLeft.y // UI_PANEL.HEIGHT.LARGE; + thisObject.container.name = 'Layers @ ' + exchange + ' ' + market.assetB + '/' + market.assetA + thisObject.container.frame.containerName = thisObject.container.name + thisObject.container.frame.width = UI_PANEL.WIDTH.LARGE + thisObject.container.frame.height = UI_PANEL.HEIGHT.LARGE // viewPort.visibleArea.bottomLeft.y - viewPort.visibleArea.topLeft.y // UI_PANEL.HEIGHT.LARGE; - var position = { - x: viewPort.visibleArea.topLeft.x, - y: viewPort.visibleArea.topLeft.y// viewPort.visibleArea.bottomLeft.y - thisObject.container.frame.height - } + let position = { + x: viewPort.visibleArea.topLeft.x, + y: viewPort.visibleArea.topLeft.y// viewPort.visibleArea.bottomLeft.y - thisObject.container.frame.height + } - thisObject.container.frame.position = position + thisObject.container.frame.position = position - panelTabButton = newPanelTabButton() - panelTabButton.parentContainer = thisObject.container - panelTabButton.container.frame.parentFrame = thisObject.container.frame - panelTabButton.initialize() + panelTabButton = newPanelTabButton() + panelTabButton.parentContainer = thisObject.container + panelTabButton.container.frame.parentFrame = thisObject.container.frame + panelTabButton.fitFunction = thisObject.fitFunction + panelTabButton.initialize() - /* Get the current teams of the logged in user. */ + /* Get the current teams of the logged in user. */ - let storedTeams = window.localStorage.getItem('userTeams') - let userTeams - let userTeam = {slug: ''} - if (storedTeams !== null && storedTeams !== undefined && storedTeams !== '') { - userTeams = JSON.parse(storedTeams) - userTeam = userTeams[0] // Currently we assume a user can be at only one team. - } - if (userTeam === undefined) { userTeam = {slug: ''} } + let storedTeams = window.localStorage.getItem('userTeams') + let userTeams + let userTeam = {slug: ''} + if (storedTeams !== null && storedTeams !== undefined && storedTeams !== '') { + userTeams = JSON.parse(storedTeams) + userTeam = userTeams[0] // Currently we assume a user can be at only one team. + } + if (userTeam === undefined) { userTeam = {slug: ''} } - /* First thing is to build the productCards array */ + /* First thing is to build the productCards array */ - let devTeams = ecosystem.getTeams() + let devTeams = ecosystem.getTeams() - for (let i = 0; i < devTeams.length; i++) { - let devTeam = devTeams[i] + for (let i = 0; i < devTeams.length; i++) { + let devTeam = devTeams[i] - for (let j = 0; j < devTeam.bots.length; j++) { - let bot = devTeam.bots[j] + for (let j = 0; j < devTeam.bots.length; j++) { + let bot = devTeam.bots[j] - if (bot.type !== 'Indicator' && bot.cloneId === undefined) { continue } - if (bot.type === 'Indicator' && (devTeam.codeName !== 'AAMasters' && devTeam.codeName !== userTeam.slug)) { continue } + if (bot.type !== 'Indicator' && bot.cloneId === undefined) { continue } + if (bot.type === 'Indicator' && (devTeam.codeName !== 'AAMasters' && devTeam.codeName !== userTeam.slug)) { continue } - if (bot.products !== undefined) { - for (let k = 0; k < bot.products.length; k++) { - let product = bot.products[k] + if (bot.products !== undefined) { + for (let k = 0; k < bot.products.length; k++) { + let product = bot.products[k] - if (window.localStorage.getItem('Show AAMaster Layers') === null) { - if (product.shareWith !== 'Public' && devTeam.codeName !== userTeam.slug) { continue } - } - /* Now we create Product objects */ + if (window.localStorage.getItem('Show AAMaster Layers') === null) { + if (product.shareWith !== 'Public' && devTeam.codeName !== userTeam.slug) { continue } + } + /* Now we create Product objects */ - let productCard = newProductCard() + let productCard = newProductCard() - productCard.devTeam = devTeam - productCard.bot = bot - productCard.product = product + productCard.devTeam = devTeam + productCard.bot = bot + productCard.product = product + productCard.fitFunction = thisObject.fitFunction + productCard.code = exchange + '-' + market.assetB + '/' + market.assetA + '-' + devTeam.codeName + '-' + bot.codeName + '-' + product.codeName - productCard.code = exchange + '-' + market.assetB + '/' + market.assetA + '-' + devTeam.codeName + '-' + bot.codeName + '-' + product.codeName + /* Initialize it */ - /* Initialize it */ + productCard.initialize() - productCard.initialize() + /* Container Stuff */ - /* Container Stuff */ + productCard.container.displacement.parentDisplacement = thisObject.container.displacement + productCard.container.frame.parentFrame = thisObject.container.frame + productCard.container.parentContainer = thisObject.container + productCard.container.isWheelable = true - productCard.container.displacement.parentDisplacement = thisObject.container.displacement - productCard.container.frame.parentFrame = thisObject.container.frame - productCard.container.parentContainer = thisObject.container - productCard.container.isWheelable = true + /* Positioning within thisObject Panel */ - /* Positioning within thisObject Panel */ + let position = { + x: 10, + y: thisObject.container.frame.height - thisObject.container.frame.getBodyHeight() + } - let position = { - x: 10, - y: thisObject.container.frame.height - thisObject.container.frame.getBodyHeight() - } + productCard.container.frame.position.x = position.x + productCard.container.frame.position.y = position.y + lastY - productCard.container.frame.position.x = position.x - productCard.container.frame.position.y = position.y + lastY + lastY = lastY + productCard.container.frame.height - lastY = lastY + productCard.container.frame.height + /* Add to the Product Array */ - /* Add to the Product Array */ + productCards.push(productCard) - productCards.push(productCard) + /* Add to Visible Product Array */ - /* Add to Visible Product Array */ + if (productCard.container.frame.position.y + productCard.container.frame.height < thisObject.container.frame.height) { + visibleProductCards.push(productCard) + } - if (productCard.container.frame.position.y + productCard.container.frame.height < thisObject.container.frame.height) { - visibleProductCards.push(productCard) - } + /* Listen to Status Changes Events */ - /* Listen to Status Changes Events */ + productCard.container.eventHandler.listenToEvent('Status Changed', onProductCardStatusChanged) + productCard.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel) + } + } + } + } - productCard.container.eventHandler.listenToEvent('Status Changed', onProductCardStatusChanged) - productCard.container.eventHandler.listenToEvent('Mouse Wheel', onMouseWheel) - } - } - } - } + thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel) + isInitialized = true + } - thisObject.container.eventHandler.listenToEvent('Mouse Wheel', onMouseWheel) - isInitialized = true - } + function onMouseWheel (event) { + delta = event.wheelDelta + if (delta > 0) { + delta = -1 + } else { + delta = 1 + } - function onMouseWheel (event) { - delta = event.wheelDelta - if (delta > 0) { - delta = -1 - } else { - delta = 1 - } + firstVisibleCard = firstVisibleCard + delta - firstVisibleCard = firstVisibleCard + delta + let availableSlots = visibleProductCards.length - let availableSlots = visibleProductCards.length + if (firstVisibleCard < 1) { firstVisibleCard = 1 } + if (firstVisibleCard > (productCards.length - availableSlots + 1)) { firstVisibleCard = productCards.length - availableSlots + 1 } - if (firstVisibleCard < 1) { firstVisibleCard = 1 } - if (firstVisibleCard > (productCards.length - availableSlots + 1)) { firstVisibleCard = productCards.length - availableSlots + 1 } + visibleProductCards = [] + let lastY = 5 - visibleProductCards = [] - var lastY = 5 + for (let i = 0; i < productCards.length; i++) { + if (i + 1 >= firstVisibleCard && i + 1 < firstVisibleCard + availableSlots) { + let productCard = productCards[i] - for (let i = 0; i < productCards.length; i++) { - if (i + 1 >= firstVisibleCard && i + 1 < firstVisibleCard + availableSlots) { - let productCard = productCards[i] + /* Positioning within thisObject Panel */ - /* Positioning within thisObject Panel */ + let position = { + x: 10, + y: thisObject.container.frame.height - thisObject.container.frame.getBodyHeight() + } + productCard.container.frame.position.x = position.x + productCard.container.frame.position.y = position.y + lastY - let position = { - x: 10, - y: thisObject.container.frame.height - thisObject.container.frame.getBodyHeight() - } - productCard.container.frame.position.x = position.x - productCard.container.frame.position.y = position.y + lastY + lastY = lastY + productCard.container.frame.height - lastY = lastY + productCard.container.frame.height + /* Add to Visible Product Array */ - /* Add to Visible Product Array */ + visibleProductCards.push(productCard) + } + } + } - visibleProductCards.push(productCard) - } - } - } + function onProductCardStatusChanged (pProductCard) { + thisObject.container.eventHandler.raiseEvent('Product Card Status Changed', pProductCard) + } - function onProductCardStatusChanged (pProductCard) { - thisObject.container.eventHandler.raiseEvent('Product Card Status Changed', pProductCard) - } + function getLoadingProductCards () { + /* Returns all productCards which status is LOADING */ - function getLoadingProductCards () { - /* Returns all productCards which status is LOADING */ + let onProducts = [] - let onProducts = [] + for (let i = 0; i < productCards.length; i++) { + if (productCards[i].status === PRODUCT_CARD_STATUS.LOADING) { + onProducts.push(productCards[i]) + } + } - for (let i = 0; i < productCards.length; i++) { - if (productCards[i].status === PRODUCT_CARD_STATUS.LOADING) { - onProducts.push(productCards[i]) - } - } + return onProducts + } - return onProducts - } + function getContainer (point) { + let container - function getContainer (point) { - var container + container = panelTabButton.getContainer(point) + if (container !== undefined) { return container } - container = panelTabButton.getContainer(point) - if (container !== undefined) { return container } + /* First we check if thisObject point is inside thisObject space. */ - /* 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 */ - 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 < visibleProductCards.length; i++) { + container = visibleProductCards[i].getContainer(point) - for (var i = 0; i < visibleProductCards.length; i++) { - container = visibleProductCards[i].getContainer(point) + if (container !== undefined) { + let checkPoint = { + x: point.x, + y: point.y + } - if (container !== undefined) { - /* We found an inner container which has the point. We return it. */ + checkPoint = thisObject.fitFunction(checkPoint) - return container - } - } + 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. */ + /* The point does not belong to any inner container, so we return the current container. */ - return thisObject.container - } else { - /* This point does not belong to thisObject space. */ + let checkPoint = { + x: point.x, + y: point.y + } - return undefined - } - } + checkPoint = thisObject.fitFunction(checkPoint) - function draw () { - if (isInitialized === false) { return } + if (point.x === checkPoint.x && point.y === checkPoint.y) { + return thisObject.container + } + } + } - thisObject.container.frame.draw(false, false, true) + function draw () { + if (isInitialized === false) { return } - for (let i = 0; i < visibleProductCards.length; i++) { - visibleProductCards[i].draw() - } + thisObject.container.frame.draw(false, false, true, thisObject.fitFunction) + + for (let i = 0; i < visibleProductCards.length; i++) { + visibleProductCards[i].draw() + } + + panelTabButton.draw() + } +} - panelTabButton.draw() - } - } diff --git a/Panels/TimeControlPanel.js b/Panels/TimeControlPanel.js index 7a1b51e8e..2f650b65c 100644 --- a/Panels/TimeControlPanel.js +++ b/Panels/TimeControlPanel.js @@ -115,7 +115,7 @@ function newTimeControlPanel () { labelPoint = thisObject.container.frame.frameThisPoint(labelPoint) - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)' browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) @@ -132,7 +132,7 @@ function newTimeControlPanel () { labelPoint = thisObject.container.frame.frameThisPoint(labelPoint) - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)' browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) @@ -151,7 +151,7 @@ function newTimeControlPanel () { labelPoint = thisObject.container.frame.frameThisPoint(labelPoint) - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY browserCanvasContext.fillStyle = 'rgba(60, 60, 60, 0.50)' browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y) } diff --git a/ProductStorage.js b/ProductStorage.js index 66c3ea939..bc0d98456 100644 --- a/ProductStorage.js +++ b/ProductStorage.js @@ -171,7 +171,7 @@ function newProductStorage (pName) { case GLOBAL.CUSTOM_FAIL_RESPONSE.result: { if (INFO_LOG === true) { logger.write('[INFO] initialize -> onMarketFileReady -> Received CUSTOM FAIL Response.') } - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onMarketFileReady -> err.message = ' + err.message) } + if (INFO_LOG === true) { logger.write('[INFO] initialize -> onMarketFileReady -> err= ' + err.stack) } callBackFunction(err) return @@ -227,7 +227,7 @@ function newProductStorage (pName) { case GLOBAL.CUSTOM_FAIL_RESPONSE.result: { if (INFO_LOG === true) { logger.write('[INFO] initialize -> onDailyFileReady -> Received CUSTOM FAIL Response.') } - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onDailyFileReady -> err.message = ' + err.message) } + if (INFO_LOG === true) { logger.write('[INFO] initialize -> onDailyFileReady -> err= ' + err.stack) } callBackFunction(err) return @@ -282,7 +282,7 @@ function newProductStorage (pName) { case GLOBAL.CUSTOM_FAIL_RESPONSE.result: { if (INFO_LOG === true) { logger.write('[INFO] initialize -> onSingleFileReady -> Received CUSTOM FAIL Response.') } - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onSingleFileReady -> err.message = ' + err.message) } + if (INFO_LOG === true) { logger.write('[INFO] initialize -> onSingleFileReady -> err= ' + err.stack) } callBackFunction(err) return @@ -334,7 +334,7 @@ function newProductStorage (pName) { case GLOBAL.CUSTOM_FAIL_RESPONSE.result: { if (INFO_LOG === true) { logger.write('[INFO] initialize -> onFileSequenceReady -> Received CUSTOM FAIL Response.') } - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onFileSequenceReady -> err.message = ' + err.message) } + if (INFO_LOG === true) { logger.write('[INFO] initialize -> onFileSequenceReady -> err= ' + err.stack) } callBackFunction(err) return diff --git a/Project.njsproj b/Project.njsproj index 4634a91ad..7cc00eb05 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -32,13 +32,13 @@ - + Code Code - + Code @@ -85,7 +85,7 @@ Code - + Code @@ -112,7 +112,7 @@ Code - + Code @@ -177,7 +177,7 @@ - + diff --git a/Scales/RateScale.js b/Scales/RateScale.js index 679dbe118..300587042 100644 --- a/Scales/RateScale.js +++ b/Scales/RateScale.js @@ -33,7 +33,7 @@ function newRateScale () { } } - let visible = false + let visible = true let timeLineCoordinateSystem return thisObject @@ -41,7 +41,7 @@ function newRateScale () { function initialize (pTimeLineCoordinateSystem) { timeLineCoordinateSystem = pTimeLineCoordinateSystem - thisObject.container.eventHandler.listenToEvent('Mouse Wheel', onMouseWheel) + thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel) thisObject.heightPercentage = window.localStorage.getItem(MODULE_NAME) if (!thisObject.heightPercentage) { diff --git a/Scales/TimePeriodScale.js b/Scales/TimePeriodScale.js index 4df23f8f5..55ba9a6b8 100644 --- a/Scales/TimePeriodScale.js +++ b/Scales/TimePeriodScale.js @@ -27,7 +27,7 @@ function newTimePeriodScale () { } } - let visible = false + let visible = true let timeLineCoordinateSystem let objectStorage = {} let filePeriodIndex = FILES_PERIOD_DEFAULT_VALUE @@ -40,7 +40,7 @@ function newTimePeriodScale () { function initialize (pTimeLineCoordinateSystem) { timeLineCoordinateSystem = pTimeLineCoordinateSystem - thisObject.container.eventHandler.listenToEvent('Mouse Wheel', onMouseWheel) + thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel) readObjectState() newTimePeriod() @@ -187,7 +187,7 @@ to be visible at the top of the viewPort. */ /* Lets start the drawing. */ - let displacement = viewPort.margins.BOTTOM - BOTTOM_SPACE_HEIGHT + let displacement = viewPort.margins.BOTTOM - COCKPIT_SPACE_HEIGHT /* browserCanvasContext.beginPath() @@ -209,35 +209,64 @@ to be visible at the top of the viewPort. */ thisObject.container.frame.width = point2.x - point1.x thisObject.container.frame.height = point3.y - point2.y - let point = { + /* Common Variables */ + + let label = timePeriodLabel.split('-') + let label1 = label[0] + let label2 = label[1].toUpperCase() + let fontSize1 = 25 + let fontSize2 = 10 + + /* We draw the circle container */ + + const RED_LINE_HIGHT = 5 + const RADIUS = 25 + const OPACITY = 1 + + let centerPoint = { x: mouse.position.x, + y: point1.y + viewPort.margins.BOTTOM - 5 + } + + browserCanvasContext.beginPath() + browserCanvasContext.arc(centerPoint.x, centerPoint.y, RADIUS + RED_LINE_HIGHT, 0.0 * Math.PI, 2.0 * Math.PI) + browserCanvasContext.closePath() + + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + OPACITY + ')' + browserCanvasContext.fill() + + browserCanvasContext.beginPath() + browserCanvasContext.arc(centerPoint.x, centerPoint.y, RADIUS, 0.0 * Math.PI, 2.0 * Math.PI) + browserCanvasContext.closePath() + + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', ' + OPACITY + ')' + browserCanvasContext.fill() + + /* Place the Text */ + + let xOffset1 = label1.length * fontSize1 * FONT_ASPECT_RATIO + + let labelPoint1 = { + x: mouse.position.x - xOffset1 / 2 - 3, y: point1.y + viewPort.margins.BOTTOM } - let label = timePeriodLabel - let fontSize = 10 + browserCanvasContext.font = fontSize1 + 'px ' + UI_FONT.PRIMARY + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)' - let xOffset = label.length * fontSize * FONT_ASPECT_RATIO + browserCanvasContext.fillText(label1, labelPoint1.x, labelPoint1.y) - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY - browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', 0.50)' + let xOffset2 = label2.length * fontSize2 * FONT_ASPECT_RATIO - if (point.x - xOffset / 2 < point1.x || point.x + xOffset / 2 > point2.x) { return } + let labelPoint2 = { + x: mouse.position.x - xOffset2 / 2 - 3, + y: point1.y + viewPort.margins.BOTTOM + fontSize2 + } - browserCanvasContext.fillText(label, point.x - xOffset / 2, point.y + fontSize + 1) -/* - browserCanvasContext.beginPath() + browserCanvasContext.font = fontSize2 + 'px ' + UI_FONT.PRIMARY + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.WHITE + ', 1)' - browserCanvasContext.moveTo(point.x, point1.y) - browserCanvasContext.lineTo(point.x, point5.y) - - browserCanvasContext.closePath() - - browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.DARK + ', 0.5)' - browserCanvasContext.lineWidth = 0.2 - browserCanvasContext.setLineDash([1, 5]) - browserCanvasContext.stroke() -*/ + browserCanvasContext.fillText(label2, labelPoint2.x, labelPoint2.y) } function saveObjectState () { @@ -265,3 +294,4 @@ to be visible at the top of the viewPort. */ thisObject.container.eventHandler.raiseEvent('Time Period Changed', event) } } + diff --git a/Scales/TimeScale.js b/Scales/TimeScale.js index 1516bcdef..5cc926436 100644 --- a/Scales/TimeScale.js +++ b/Scales/TimeScale.js @@ -27,7 +27,7 @@ function newTimeScale () { } } - let visible = false + let visible = true let timeLineCoordinateSystem return thisObject @@ -35,7 +35,7 @@ function newTimeScale () { function initialize (pTimeLineCoordinateSystem) { timeLineCoordinateSystem = pTimeLineCoordinateSystem - thisObject.container.eventHandler.listenToEvent('Mouse Wheel', onMouseWheel) + thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel) thisObject.lenghtPercentage = window.localStorage.getItem(MODULE_NAME) if (!thisObject.lenghtPercentage) { diff --git a/Spaces/BottomSpace.js b/Spaces/BottomSpace.js deleted file mode 100644 index eccf98ad2..000000000 --- a/Spaces/BottomSpace.js +++ /dev/null @@ -1,154 +0,0 @@ -  -function newBottomSpace () { - let thisObject = { - - container: undefined, - draw: draw, - getContainer: getContainer, // returns the inner most container that holds the point received by parameter. - createNewControl: createNewControl, - destroyControl: destroyControl, - getControl: getControl, - initialize: initialize - } - - var container = newContainer() - container.initialize() - thisObject.container = container - - container.isDraggeable = false - - controlsMap = new Map() - resize() - - return thisObject - - function initialize () { - window.canvasApp.eventHandler.listenToEvent('Browser Resized', resize) - } - - function createNewControl (pType, pDrawFunction, pOwner) { - let control - - switch (pType) { - - case 'Over The Line': - { - control = newUIControl() - control.initialize() - control.drawFunction = pDrawFunction - break - } - } - - let controlArray = controlsMap.get(pOwner) - if (controlArray === undefined) { - controlArray = [] - controlsMap.set(pOwner, controlArray) - } - - controlArray.push(control) - - control.handle = Math.floor((Math.random() * 10000000) + 1) - - return control.handle - } - - function destroyControl (pControlHandle) { - thisObject.controls = controlsMap.get('Global') - if (thisObject.controls !== undefined) { - for (let i = 0; i < thisObject.controls.length; i++) { - let control = thisObject.controls[i] - if (control.handle === pControlHandle) { - thisObject.controls.splice(i, 1) // Delete item from array. - return - } - } - } - - thisObject.controls = controlsMap.get(window.CHART_ON_FOCUS) - if (thisObject.controls !== undefined) { - for (let i = 0; i < thisObject.controls.length; i++) { - let control = thisObject.controls[i] - if (control.handle === pControlHandle) { - thisObject.controls.splice(i, 1) // Delete item from array. - return - } - } - } - } - - function getControl (pControlHandle, pOwner) { - thisObject.controls = controlsMap.get(pOwner) - if (thisObject.controls != undefined) { - for (let i = 0; i < thisObject.controls.length; i++) { - let control = thisObject.controls[i] - - if (control.handle === pControlHandle) { - return control - } - } - } - } - - function resize () { - container.frame.position.x = 0 - container.frame.position.y = viewPort.visibleArea.bottomLeft.y - - thisObject.container.frame.width = browserCanvas.width - thisObject.container.frame.height = BOTTOM_SPACE_HEIGHT - } - - function getContainer (point) { - let container - - return thisObject.container - } - - function draw () { - thisObject.container.frame.draw(false, false) - - drawBackground() - - thisObject.controls = controlsMap.get('Global') - if (thisObject.controls !== undefined) { - for (let i = 0; i < thisObject.controls.length; i++) { - let control = thisObject.controls[i] - control.draw() - } - } - - thisObject.controls = controlsMap.get(window.CHART_ON_FOCUS) - if (thisObject.controls !== undefined) { - for (let i = 0; i < thisObject.controls.length; i++) { - let control = thisObject.controls[i] - control.draw() - } - } - } - - function drawBackground () { - let opacity = 1 - - let zeroPoint = { - x: 0, - y: 0 - } - - zeroPoint = thisObject.container.frame.frameThisPoint(zeroPoint) - - let breakpointsHeight = 15 - const RED_LINE_HIGHT = 5 - - browserCanvasContext.beginPath() - browserCanvasContext.rect(zeroPoint.x, zeroPoint.y + breakpointsHeight, thisObject.container.frame.width, thisObject.container.frame.height) - browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', ' + opacity + ')' - browserCanvasContext.closePath() - browserCanvasContext.fill() - - browserCanvasContext.beginPath() - browserCanvasContext.rect(zeroPoint.x, zeroPoint.y + breakpointsHeight, thisObject.container.frame.width, RED_LINE_HIGHT) - browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', ' + opacity + ')' - browserCanvasContext.closePath() - browserCanvasContext.fill() - } -} diff --git a/Spaces/ChartSpace.js b/Spaces/ChartSpace.js index 25f51f709..2af37d1d0 100644 --- a/Spaces/ChartSpace.js +++ b/Spaces/ChartSpace.js @@ -1,4 +1,4 @@ - /* +/* 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 @@ -8,13 +8,16 @@ changes, then all charts in it are replotted with the corresponging data. function newChartSpace () { const MODULE_NAME = 'Chart Space' - const INFO_LOG = false const ERROR_LOG = true const logger = newWebDebugLog() logger.fileName = MODULE_NAME let thisObject = { + visible: true, container: undefined, + fitIntoVisibleArea: fitIntoVisibleArea, + isThisPointVisible: isThisPointVisible, + physics: physics, drawBackground: drawBackground, draw: draw, timeMachines: [], @@ -27,13 +30,12 @@ function newChartSpace () { thisObject.container.initialize(MODULE_NAME) thisObject.container.isDraggeable = false + thisObject.container.isWheelable = false return thisObject function finalize () { try { - if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') } - for (let i = 0; i < thisObject.timeMachines.length; i++) { let timeMachine = thisObject.timeMachines[i] timeMachine.finalize() @@ -44,32 +46,24 @@ function newChartSpace () { } function initialize (callBackFunction) { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } - let initializedCounter = 0 let toInitialize = 1 - /* We create the first of many possible time machines that could live at the Chart Space. */ + /* We create the first of many possible time machines that could live at the Chart Space. */ - var timeMachine = newTimeMachine() + let timeMachine = newTimeMachine() - // timeMachine.container.connectToParent(thisObject.container, true, true) - - /* We make the time machine a little bit smaller than the current space. */ - - timeMachine.container.frame.position.x = this.container.frame.width / 2 - timeMachine.container.frame.width / 2 - timeMachine.container.frame.position.y = this.container.frame.height / 2 - timeMachine.container.frame.height / 2 + /* We make the time machine a little bit smaller than the current space. */ + timeMachine.container.frame.position.x = thisObject.container.frame.width / 2 - timeMachine.container.frame.width / 2 + timeMachine.container.frame.position.y = thisObject.container.frame.height / 2 - timeMachine.container.frame.height / 2 + timeMachine.container.fitFunction = fitIntoVisibleArea timeMachine.initialize(onTimeMachineInitialized) function onTimeMachineInitialized (err) { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onTimeMachineInitialized -> Entering function.') } - initializedCounter++ if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onTimeMachineInitialized -> Initialization of a Time Machine failed.') } - callBackFunction(err) return } @@ -82,37 +76,126 @@ function newChartSpace () { } } + function getContainer (point, purpose) { + if (thisObject.visible !== true) { return } + + let container + + /* Now we see which is the inner most container that has it */ + + for (let i = 0; i < thisObject.timeMachines.length; i++) { + container = thisObject.timeMachines[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 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 / 2) { + returnPoint.y = COCKPIT_SPACE_POSITION + COCKPIT_SPACE_HEIGHT / 2 + } + + if (point.y < 0) { + returnPoint.y = 0 + } + + 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 () { + thisObject.container.frame.height = COCKPIT_SPACE_POSITION + + if (thisObject.container.frame.height <= 0 / 100) { + thisObject.visible = false + } else { + thisObject.visible = true + } + + viewPort.resize() + } + function drawBackground () { - for (var i = 0; i < thisObject.timeMachines.length; i++) { - var timeMachine = thisObject.timeMachines[i] + if (thisObject.visible !== true) { return } + + drawSpaceBackground() + + for (let i = 0; i < thisObject.timeMachines.length; i++) { + let timeMachine = thisObject.timeMachines[i] timeMachine.drawBackground() } } - function draw () { - // thisObject.container.frame.draw(false, false) + function drawSpaceBackground () { + let opacity = '1' + let fromPoint = { + x: 0, + y: 0 + } - for (var i = 0; i < thisObject.timeMachines.length; i++) { - var timeMachine = thisObject.timeMachines[i] + 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() + } + + function draw () { + if (thisObject.visible !== true) { return } + + for (let i = 0; i < thisObject.timeMachines.length; i++) { + let timeMachine = thisObject.timeMachines[i] timeMachine.draw() } } - - function getContainer (point, purpose) { - if (INFO_LOG === true) { logger.write('[INFO] getContainer -> Entering function.') } - - let container - - /* Now we see which is the inner most container that has it */ - - for (var i = 0; i < this.timeMachines.length; i++) { - container = this.timeMachines[i].getContainer(point, purpose) - if (container !== undefined) { - if (container.isForThisPurpose(purpose)) { - return container - } - } - } - return this.container - } } diff --git a/Spaces/CockpitSpace.js b/Spaces/CockpitSpace.js new file mode 100644 index 000000000..29096fa78 --- /dev/null +++ b/Spaces/CockpitSpace.js @@ -0,0 +1,231 @@ + + function newCockpitSpace () { + const MODULE_NAME = 'CockpitSpace' + + let thisObject = { + container: undefined, + status: 'BOTTOM', + assetBalances: undefined, + draw: draw, + physics: physics, + getContainer: getContainer, + finalize: finalize, + initialize: initialize + } + + thisObject.container = newContainer() + thisObject.container.initialize(MODULE_NAME) + thisObject.container.isClickeable = false + 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 + } + + function initialize () { + canvasBrowserResizedEventSubscriptionId = window.canvasApp.eventHandler.listenToEvent('Browser Resized', resize) + selfMouseClickEventSubscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseClick', onMouseClick) + + thisObject.assetBalances = newAssetBalances() + thisObject.assetBalances.initialize() + } + + function onMouseClick (event) { + + } + + function resize () { + thisObject.container.frame.position.x = 0 + thisObject.container.frame.position.y = browserCanvas.height - COCKPIT_SPACE_HEIGHT + + thisObject.container.frame.width = browserCanvas.width + thisObject.container.frame.height = COCKPIT_SPACE_HEIGHT + } + + function physics () { + /* Check the limits */ + + thisObject.status = 'MIDDLE' + + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE) + if (user !== null) { // Only if user is logged in + 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.strategySpace.makeInvisible() + } else { + canvas.strategySpace.makeVisible() + } + + if (thisObject.container.frame.position.y < browserCanvas.height * 0.5 / 100) { + thisObject.container.frame.position.y = 0 + thisObject.status = 'TOP' + canvas.panelsSpace.visible = false + } else { + canvas.panelsSpace.visible = true + } + + COCKPIT_SPACE_POSITION = thisObject.container.frame.position.y + viewPort.resize() + } + + function getContainer (point) { + if (thisObject.container.frame.isThisPointHere(point, true) === true) { + return thisObject.container + } else { + return undefined + } + } + + function draw () { + thisObject.container.frame.draw(false, false) + + drawBackground() + + thisObject.assetBalances.draw() + } + + function drawBackground () { + let opacity = 1 + + let zeroPoint = { + x: 0, + y: 0 + } + + const RED_LINE_HIGHT = 5 + + 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() + + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE) + if (user !== null) { // Only if user is logged in + 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() + } + } + diff --git a/Spaces/FloatingSpace.js b/Spaces/FloatingSpace.js index 0e0010638..1c9aeb5dd 100644 --- a/Spaces/FloatingSpace.js +++ b/Spaces/FloatingSpace.js @@ -1,51 +1,158 @@ -  + function newFloatingSpace () { const MODULE_NAME = 'Floating Space' - const INFO_LOG = false 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. - */ + /* + 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 profileBalls: undefined, + strategyPartConstructor: undefined, noteSets: undefined, + container: undefined, + fitIntoVisibleArea: fitIntoVisibleArea, + isThisPointVisible: isThisPointVisible, + 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 + thisObject.container.frame.width = browserCanvas.width * 10 + thisObject.container.frame.height = browserCanvas.height * 10 + 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 + return thisObject function finalize () { - try { - if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') } - - thisObject.floatingLayer.finalize() - thisObject.profileBalls.finalize() - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) } - } + thisObject.floatingLayer.finalize() + thisObject.profileBalls.finalize() + thisObject.strategyPartConstructor.finalize() + thisObject.noteSets.finalize() } function initialize (callBackFunction) { thisObject.floatingLayer = newFloatingLayer() - thisObject.floatingLayer.initialize(onFloatingLayerInitialized) + thisObject.floatingLayer.initialize() - function onFloatingLayerInitialized (err) { - thisObject.profileBalls = newProfileBalls() - thisObject.profileBalls.initialize(thisObject.floatingLayer, onProfileBallsInitialized) + thisObject.profileBalls = newProfileBalls() + thisObject.profileBalls.initialize(thisObject.floatingLayer) - function onProfileBallsInitialized (err) { - thisObject.noteSets = newNoteSets() - thisObject.noteSets.initialize(thisObject.floatingLayer, onNoteSetsInitialized) + thisObject.noteSets = newNoteSets() + thisObject.noteSets.initialize(thisObject.floatingLayer) - function onNoteSetsInitialized (err) { + thisObject.strategyPartConstructor = newStrategyPartConstructor() + thisObject.strategyPartConstructor.initialize(thisObject.floatingLayer) - } - } + thisObject.container.eventHandler.listenToEvent('onMouseWheel', onMouseWheel) + } + + 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 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) { return container } + + if (visible === true) { + return thisObject.container + } + } + + function physics () { + thisObject.floatingLayer.physics() + } + + 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() } } diff --git a/Spaces/PanelsSpace.js b/Spaces/PanelsSpace.js index 151d5af65..04753532f 100644 --- a/Spaces/PanelsSpace.js +++ b/Spaces/PanelsSpace.js @@ -6,6 +6,7 @@ The Panel Space y the place wehre all panels live, no matter who create them. function newPanelsSpace () { let thisObject = { + visible: true, container: undefined, createNewPanel: createNewPanel, destroyPanel: destroyPanel, @@ -48,11 +49,15 @@ function newPanelsSpace () { case 'Products Panel': { panel = newProductsPanel() + panel.fitFunction = canvas.chartSpace.fitIntoVisibleArea + panel.container.isVisibleFunction = canvas.chartSpace.isThisPointVisible break } case 'Plotter Panel': { panel = getNewPlotterPanel(pParameters.devTeam, pParameters.plotterCodeName, pParameters.moduleCodeName, pParameters.panelCodeName) + panel.fitFunction = canvas.chartSpace.fitIntoVisibleArea + panel.container.isVisibleFunction = canvas.chartSpace.isThisPointVisible panel.initialize() break } @@ -100,6 +105,8 @@ function newPanelsSpace () { } function draw () { + if (thisObject.visible !== true) { return } + thisObject.container.frame.draw(false, false) thisObject.panels = panelsMap.get('Global') @@ -120,6 +127,8 @@ function newPanelsSpace () { } function getContainer (point) { + if (thisObject.visible !== true) { return } + let container /* diff --git a/Spaces/StrategySpace.js b/Spaces/StrategySpace.js index befe0c9d4..e4bfcca0c 100644 --- a/Spaces/StrategySpace.js +++ b/Spaces/StrategySpace.js @@ -3,10 +3,14 @@ function newStrategySpace () { const MODULE_NAME = 'Strategy Space' let thisObject = { sidePanel: undefined, - strategyCollection: undefined, + workplace: undefined, container: undefined, + iconCollection: undefined, + iconByPartType: undefined, draw: draw, getContainer: getContainer, + makeVisible: makeVisible, + makeInvisible: makeInvisible, initialize: initialize } @@ -16,30 +20,147 @@ function newStrategySpace () { container.isDraggeable = false + thisObject.iconCollection = new Map() + thisObject.iconByPartType = new Map() + return thisObject async function initialize () { - thisObject.sidePanel = newSidePanel() - thisObject.sidePanel.initialize() + thisObject.workplace = newWorkspace() - thisObject.strategyCollection = newStrategyCollection() - thisObject.strategyCollection.container.connectToParent(thisObject.sidePanel.container, true, true) - await thisObject.strategyCollection.initialize() + thisObject.workplace.initialize() + await thisObject.workplace.loadFromStrategyzer() - thisObject.sidePanel.areas.push(thisObject.strategyCollection) + loadIconCollection() + buildIconByPartTypeMap() + } + + function buildIconByPartTypeMap () { + const relationshipArray = [ + ['Trading System', 'analysis'], + ['Strategy', 'quality'], + ['Strategy Entry Event', 'startup'], + ['Strategy Exit Event', 'support'], + ['Trade Entry Event', 'compass'], + ['Stop', 'pixel'], + ['Take Profit', 'competition'], + ['Phase', 'placeholder'], + ['Situation', 'attractive'], + ['Condition', 'testing'] + ] + + for (let i = 0; i < relationshipArray.length; i++) { + let record = relationshipArray[i] + let icon = thisObject.iconCollection.get(record[1]) + thisObject.iconByPartType.set(record[0], icon) + } + } + + function loadIconCollection () { + const iconsNames = [ + 'analysis', + 'analysis-1', + 'approve', + 'attach', + 'attractive', + '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', + 'target', + 'targeting', + 'task', + 'testing', + 'text', + 'timeline', + 'tools', + 'trash', + 'upload', + 'vector', + 'video-player' + ] + + 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 makeVisible () { + if (thisObject.workplace.isDeployed !== true) { + thisObject.workplace.deploydTradingSystem() + } + canvas.floatingSpace.makeVisible() + visible = true + } + + function makeInvisible () { + visible = false } function getContainer (point) { let container + if (thisObject.workplace !== undefined) { + container = thisObject.workplace.getContainer(point) + if (container !== undefined) { return container } + } + if (thisObject.sidePanel !== undefined) { container = thisObject.sidePanel.getContainer(point) if (container !== undefined) { return container } } + return } function draw () { - thisObject.sidePanel.draw() + if (thisObject.sidePanel !== undefined) { + thisObject.sidePanel.draw() + } } } diff --git a/StrategySpace/ConstDeleteStrategy.js b/StrategySpace/ConstDeleteStrategy.js new file mode 100644 index 000000000..e69de29bb diff --git a/StrategySpace/ConstGetStrategies.js b/StrategySpace/ConstGetStrategies.js new file mode 100644 index 000000000..aa77d1d5c --- /dev/null +++ b/StrategySpace/ConstGetStrategies.js @@ -0,0 +1,87 @@ +const GRAPHQL_QUERY_GET_STRATEGIES = Apollo.gql` + query($fbSlug: String!){ + + strategizer_StrategyByFb(fbSlug: $fbSlug){ + id + subStrategies(activeOnly: true){ + name + active + entryPoint{ + situations{ + name + conditions{ + name + code + } + } + } + exitPoint{ + situations{ + name + conditions{ + name + code + } + } + } + sellPoint{ + situations{ + name + conditions{ + name + code + } + } + } + buyPoint{ + situations{ + name + conditions{ + name + code + } + } + } + stopLoss{ + phases{ + name + code + situations{ + name + conditions{ + name + code + } + } + } + } + buyOrder{ + phases{ + name + code + situations{ + name + conditions{ + name + code + } + } + } + } + sellOrder{ + phases{ + name + code + situations{ + name + conditions{ + name + code + } + } + } + } + } + } + } + ` diff --git a/StrategySpace/ConstNewStrategy.js b/StrategySpace/ConstNewStrategy.js new file mode 100644 index 000000000..e69de29bb diff --git a/StrategySpace/ConstUpdateStrategy.js b/StrategySpace/ConstUpdateStrategy.js new file mode 100644 index 000000000..d84ce30cf --- /dev/null +++ b/StrategySpace/ConstUpdateStrategy.js @@ -0,0 +1,7 @@ +const GRAPHQL_MUTATION_UPDATE_STRATEGIES = Apollo.gql` + mutation strategizer_EditStrategy($id: ID!, $strategy: strategizer_StrategyInput!) { + strategizer_EditStrategy(id: $id, strategy: $strategy) { + id + } + } +` diff --git a/StrategySpace/StrategyCollection.js b/StrategySpace/StrategyCollection.js deleted file mode 100644 index 2f7b52400..000000000 --- a/StrategySpace/StrategyCollection.js +++ /dev/null @@ -1,264 +0,0 @@ - -function newStrategyCollection () { - const MODULE_NAME = 'Strategy Collection' - const ERROR_LOG = true - const logger = newWebDebugLog() - logger.fileName = MODULE_NAME - - let thisObject = { - strategies: undefined, - container: undefined, - draw: draw, - getContainer: getContainer, - initialize: initialize - } - - let colletionItems = [] - - thisObject.container = newContainer() - thisObject.container.name = MODULE_NAME - thisObject.container.initialize() - - thisObject.container.frame.width = 0 - thisObject.container.frame.height = 0 - - thisObject.container.frame.position.x = 0 - thisObject.container.frame.position.y = 0 - - thisObject.container.isDraggeable = false - thisObject.container.isClickeable = true - - return thisObject - - async function initialize () { - try { - const accessToken = window.localStorage.getItem('xaccess_token') - let user = window.localStorage.getItem('xuser') - - if (user === null) { - // if there is no user that means that we are logged off, which means this object can not be used. - return - } - - thisObject.container.eventHandler.listenToEvent('onMouseClick', onClick) - - user = JSON.parse(user) - - const authId = user.authId - - let sessionToken - - const apolloClient = new Apollo.lib.ApolloClient({ - networkInterface: Apollo.lib.createNetworkInterface({ - uri: window.canvasApp.graphQL.masterAppApiUrl, - transportBatching: true - }), - connectToDevTools: true - }) - - /* Getting the FB that own the Strategies */ - - let strategySimulationClone = '' - let clones = window.localStorage.getItem('userClones') - if (clones === null || clones === '') { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> no user clones found at local storage. Can not get Strategies without them. ') } - return - } - clones = JSON.parse(clones) - for (let i = 0; i < clones.length; i++) { - let clone = clones[i] - if (clone.botType === 'Indicator') { - strategySimulationClone = clone.botSlug - } - } - - /* Getting all Strategies */ - - const networkInterface = Apollo.lib.createNetworkInterface({ - uri: window.canvasApp.graphQL.masterAppApiUrl - }) - - networkInterface.use([{ - applyMiddleware (req, next) { - req.options.headers = { - authorization: `Bearer ${accessToken}` - } - next() - } - }]) - - const QUERY = Apollo.gql` - query($fbSlug: String!){ - - strategizer_StrategyByFb(fbSlug: $fbSlug){ - subStrategies(activeOnly: true){ - name - entryPoint{ - situations{ - name - conditions{ - name - code - } - } - } - exitPoint{ - situations{ - name - conditions{ - name - code - } - } - } - sellPoint{ - situations{ - name - conditions{ - name - code - } - } - } - buyPoint{ - situations{ - name - conditions{ - name - code - } - } - } - stopLoss{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - buyOrder{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - sellOrder{ - phases{ - name - code - situations{ - name - conditions{ - name - code - } - } - } - } - } - } - } - ` - - const getStrategies = () => { - return new Promise((resolve, reject) => { - apolloClient.query({ - query: QUERY, - variables: { fbSlug: strategySimulationClone} - }) - .then(response => { - window.localStorage.setItem('userStrategies', JSON.stringify(response.data.strategizer_StrategyByFb.subStrategies)) - thisObject.strategies = response.data.strategizer_StrategyByFb.subStrategies - createCollectionItems() - resolve({ strategies: response.data.strategizer_StrategyByFb.subStrategies}) - }) - .catch(error => { - console.log('apolloClient error getting user strategies', error.graphQLErrors, error.stack) - reject(error) - }) - }) - } - - // To avoid race conditions, add asynchronous fetches to array - let fetchDataPromises = [] - - fetchDataPromises.push(getStrategies()) - - // When all asynchronous fetches resolve, authenticate user or throw error. - await Promise.all(fetchDataPromises).then(result => { - - }, err => { - console.error('[ERROR] Login -> GraphQL Fetch Error -> err = ', err.stack) - }) - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) } - } - } - - function createCollectionItems () { - const TOP_MARGIN = 100 - const ITEMS_SEPARATION = 90 - - for (let i = 0; i < thisObject.strategies.length; i++) { - let strategy = thisObject.strategies[i] - let collectionItem = newStrategyCollectionItem() - - collectionItem.container.connectToParent(thisObject.container, false, false) - collectionItem.initialize() - collectionItem.strategy = strategy - collectionItem.container.frame.position.y = i * ITEMS_SEPARATION + TOP_MARGIN - - colletionItems.push(collectionItem) - - /* Load Strategies Icons */ - - let imageIndex = i + 1 - if (imageIndex > 14) { imageIndex = 14 } - - let strategyImage = loadEmoji('Symbols/Emoji Symbols-' + (112 + imageIndex) + '.png') - collectionItem.icon = strategyImage - } - } - - function onClick () { - - } - - function getContainer (point) { - let container - - /* First we check if this point is inside this object UI. */ - - if (thisObject.container.frame.isThisPointHere(point, true) === true) { - return this.container - } else { - /* This point does not belong to this space. */ - - return undefined - } - } - - function draw () { - if (colletionItems === undefined) { - return - } - - for (let i = 0; i < colletionItems.length; i++) { - let item = colletionItems[i] - item.draw() - } - } -} diff --git a/StrategySpace/StrategyCollectionItem.js b/StrategySpace/StrategyCollectionItem.js index efc1a0eae..2b1b8c920 100644 --- a/StrategySpace/StrategyCollectionItem.js +++ b/StrategySpace/StrategyCollectionItem.js @@ -2,6 +2,7 @@ function newStrategyCollectionItem () { const MODULE_NAME = 'Strategy Collection Item' let thisObject = { icon: undefined, + strategySource: undefined, strategy: undefined, container: undefined, draw: draw, @@ -17,10 +18,14 @@ function newStrategyCollectionItem () { thisObject.container.isClickeable = true thisObject.container.isDraggeable = false + let status = 'off' + return thisObject - function initialize () { - const ITEM_WIDTH = 430 + function initialize (strategy) { + thisObject.strategySource = strategy + + const ITEM_WIDTH = SIDE_PANEL_WIDTH - 20 const ITEM_HEIGHT = 80 thisObject.container.frame.width = ITEM_WIDTH @@ -37,12 +42,21 @@ function newStrategyCollectionItem () { } function onMouseClick (event) { - + if (status === 'off') { + canvas.floatingSpace.makeVisible() + thisObject.strategy = newTradingSystem() + thisObject.strategy.initialize(thisObject.strategySource) + status = 'on' + } else { + canvas.floatingSpace.makeInvisible() + thisObject.strategy.finalize() + status = 'off' + } } function getContainer (point) { let container - if (thisObject.container.frame.isThispointHere(point, true) === true) { + if (thisObject.container.frame.isThisPointHere(point, true) === true) { return thisObject.container } else { return undefined @@ -59,14 +73,14 @@ function newStrategyCollectionItem () { } function text () { - if (thisObject.strategy === undefined) { + if (thisObject.strategySource === undefined) { return } const LEFT_MARGIN = 80 const TOP_MARGIN = 45 - let strategy = thisObject.strategy + let strategy = thisObject.strategySource let labelpoint = { x: LEFT_MARGIN, @@ -76,7 +90,7 @@ function newStrategyCollectionItem () { labelpoint = thisObject.container.frame.frameThisPoint(labelpoint) let labelToPrint = strategy.name - labelToPrint = labelToPrint.toUpperCase() + labelToPrint = '' labelToPrint = labelToPrint.substring(0, 30) let opacity = 1 let fontSize = 15 @@ -86,7 +100,7 @@ function newStrategyCollectionItem () { function borders () { let params = { - cornerRadious: 8, + cornerRadius: 8, lineWidth: 0.1, opacity: 1, container: thisObject.container, @@ -161,4 +175,3 @@ function newStrategyCollectionItem () { browserCanvasContext.drawImage(thisObject.icon, point1.x - IMAGE_SIZE / 2, point1.y - IMAGE_SIZE / 2, IMAGE_SIZE, IMAGE_SIZE) } } - diff --git a/StrategySpace/TradingSystem.js b/StrategySpace/TradingSystem.js new file mode 100644 index 000000000..9cd76e864 --- /dev/null +++ b/StrategySpace/TradingSystem.js @@ -0,0 +1,410 @@ + +function newTradingSystem () { + const MODULE_NAME = 'Trading System' + + let thisObject = { + protocolData: undefined, + container: undefined, + getContainer: getContainer, + 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 + + return thisObject + + function finalize () { + destroyStrategyParts() + thisObject.protocolData = undefined + thisObject.container.finalize() + thisObject.container = undefined + } + + function initialize (protocolData) { + thisObject.protocolData = { + id: protocolData.id, + strategies: protocolData.subStrategies + } + generateStrategyParts() + } + + function getContainer (point) { + + } + + function createPart (partType, name, node, parentNode, chainParent, title) { + let payload = {} + if (chainParent === undefined) { + payload.targetPosition = { + x: canvas.floatingSpace.container.frame.width / 2, + y: canvas.floatingSpace.container.frame.height / 2 + } + } else { + payload.targetPosition = { + x: chainParent.payload.position.x, + y: chainParent.payload.position.y + } + } + + if (title !== undefined) { + payload.subTitle = title + } else { + payload.subTitle = partType + } + + payload.visible = true + payload.title = name + payload.node = node + payload.parentNode = parentNode + payload.chainParent = chainParent + payload.onMenuItemClick = onMenuItemClick + + if (node.id === undefined) { + node.id = newUniqueId() + } + node.payload = payload + node.type = partType + canvas.floatingSpace.strategyPartConstructor.createStrategyPart(payload) + } + + function destroyPart (node) { + canvas.floatingSpace.strategyPartConstructor.destroyStrategyPart(node.payload) + } + + function generateStrategyParts () { + let lastPhase + let tradingSystem = thisObject.protocolData + + createPart('Trading System', '', tradingSystem, undefined, undefined) + + for (m = 0; m < tradingSystem.strategies.length; m++) { + let strategy = tradingSystem.strategies[m] + createPart('Strategy', strategy.name, strategy, tradingSystem, tradingSystem) + + createPart('Strategy Entry Event', '', strategy.entryPoint, strategy, strategy) + for (let k = 0; k < strategy.entryPoint.situations.length; k++) { + let situation = strategy.entryPoint.situations[k] + createPart('Situation', situation.name, situation, strategy.entryPoint, strategy.entryPoint, 'Strategy Entry' + ' ' + 'Situation') + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + createPart('Condition', condition.name, condition, situation, situation, 'Condition') + } + } + + createPart('Strategy Exit Event', '', strategy.exitPoint, strategy, strategy) + for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + let situation = strategy.exitPoint.situations[k] + createPart('Situation', situation.name, situation, strategy.exitPoint, strategy.exitPoint, 'Strategy Exit' + ' ' + 'Situation') + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + createPart('Condition', condition.name, condition, situation, situation, 'Condition') + } + } + + createPart('Trade Entry Event', '', strategy.sellPoint, strategy, strategy) + for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + let situation = strategy.sellPoint.situations[k] + createPart('Situation', situation.name, situation, strategy.sellPoint, strategy.sellPoint, 'Trade Entry' + ' ' + 'Situation') + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + createPart('Condition', condition.name, condition, situation, situation, 'Condition') + } + } + + createPart('Stop', '', strategy.stopLoss, strategy, strategy) + for (let p = 0; p < strategy.stopLoss.phases.length; p++) { + let phase = strategy.stopLoss.phases[p] + + let chainParent + if (p === 0) { + chainParent = strategy.stopLoss + } else { + chainParent = lastPhase + } + lastPhase = phase + createPart('Phase', phase.name, phase, strategy.stopLoss, chainParent, 'Stop Phase') + + for (let k = 0; k < phase.situations.length; k++) { + let situation = phase.situations[k] + createPart('Situation', situation.name, situation, phase, phase, 'Situation') + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + createPart('Condition', condition.name, condition, situation, situation, 'Condition') + } + } + } + + createPart('Take Profit', '', strategy.buyOrder, strategy, strategy) + for (let p = 0; p < strategy.buyOrder.phases.length; p++) { + let phase = strategy.buyOrder.phases[p] + let chainParent + if (p === 0) { + chainParent = strategy.buyOrder + } else { + chainParent = lastPhase + } + lastPhase = phase + createPart('Phase', phase.name, phase, strategy.buyOrder, chainParent, 'Take Profit Phase') + + for (let k = 0; k < phase.situations.length; k++) { + let situation = phase.situations[k] + createPart('Situation', situation.name, situation, phase, phase, 'Situation') + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + createPart('Condition', condition.name, condition, situation, situation, 'Condition') + } + } + } + } + } + + function destroyStrategyParts () { + let strategy = thisObject.protocolData + destroyPart(strategy) + + destroyPart(strategy.entryPoint) + for (let k = 0; k < strategy.entryPoint.situations.length; k++) { + let situation = strategy.entryPoint.situations[k] + destroyPart(situation) + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + destroyPart(condition) + } + } + + destroyPart(strategy.exitPoint) + for (let k = 0; k < strategy.exitPoint.situations.length; k++) { + let situation = strategy.exitPoint.situations[k] + destroyPart(situation) + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + destroyPart(condition) + } + } + + destroyPart(strategy.sellPoint) + for (let k = 0; k < strategy.sellPoint.situations.length; k++) { + let situation = strategy.sellPoint.situations[k] + destroyPart(situation) + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + destroyPart(condition) + } + } + + destroyPart(strategy.stopLoss) + for (let p = 0; p < strategy.stopLoss.phases.length; p++) { + let phase = strategy.stopLoss.phases[p] + destroyPart(strategy.stopLoss) + + for (let k = 0; k < phase.situations.length; k++) { + let situation = phase.situations[k] + destroyPart(situation) + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + destroyPart(condition) + } + } + } + + destroyPart(strategy.buyOrder) + for (let p = 0; p < strategy.buyOrder.phases.length; p++) { + let phase = strategy.buyOrder.phases[p] + destroyPart(strategy.buyOrder) + + for (let k = 0; k < phase.situations.length; k++) { + let situation = phase.situations[k] + destroyPart(situation) + + for (let m = 0; m < situation.conditions.length; m++) { + let condition = situation.conditions[m] + destroyPart(condition) + } + } + } + } + + async function onMenuItemClick (payload, action) { + switch (action) { + case 'Save Trading System': + { + let result = await canvas.strategySpace.workplace.saveToStrategyzer() + return result + break + } + + case 'Open Settings': + break + case 'Delete Strategy': + + break + + case 'Reload Strategy': + + break + + case 'Save Strategy': + + break + + case 'Edit Code': + + break + case 'Add Phase': + { + let phaseParent = payload.node + let m = phaseParent.phases.length + let phase = { + name: 'New Phase', + code: '', + situations: [] + } + phaseParent.phases.push(phase) + let phaseChainParent + if (m > 0) { + phaseChainParent = phaseParent.phases[m - 1] + } else { + phaseChainParent = phaseParent + } + createPart('Phase', phase.name, phase, phaseParent, phaseChainParent, 'Phase') + } + break + case 'Add Situation': + { + let phase = payload.node + let m = phase.situations.length + let situation = { + name: 'New Situation', + conditions: [] + } + phase.situations.push(situation) + createPart('Situation', situation.name, situation, phase, phase, 'Situation') + } + break + case 'Add Condition': + { + let situation = payload.node + let m = situation.conditions.length + let condition = { + name: 'New Condition', + code: '' + } + situation.conditions.push(condition) + createPart('Condition', condition.name, condition, situation, situation, 'Condition') + } + break + case 'Delete Phase': { + deletePhase(payload.node) + break + } + case 'Delete Situation': { + deleteSituation(payload.node) + break + } + case 'Delete Condition': { + deleteCondition(payload.node) + break + } + default: + + } + } + + function deletePhase (node) { + let payload = node.payload + for (let k = 0; k < payload.parentNode.phases.length; k++) { + let phase = payload.parentNode.phases[k] + if (phase.id === node.id) { + for (let j = 0; j < phase.situations.length; j++) { + let situation = phase.situations[j] + for (let i = 0; i < situation.conditions.length; i++) { + let condition = situation.conditions[i] + destroyPart(condition) + cleanNode(condition) + } + situation.conditions = [] + destroyPart(situation) + phase.situations.splice(j, 1) + cleanNode(situation) + } + phase.situations = [] + /* Before deleting this phase we need to give its chainParent to the next phase down the chain */ + if (k < payload.parentNode.phases.length - 1) { + payload.parentNode.phases[k + 1].payload.chainParent = payload.chainParent + } + /* Continue destroying this phase */ + destroyPart(phase) + payload.parentNode.phases.splice(k, 1) + cleanNode(phase) + return + } + } + } + + function deleteSituation (node) { + let payload = node.payload + for (let j = 0; j < payload.parentNode.situations.length; j++) { + let situation = payload.parentNode.situations[j] + if (situation.id === node.id) { + for (let i = 0; i < situation.conditions.length; i++) { + let condition = situation.conditions[i] + destroyPart(condition) + cleanNode(condition) + } + situation.conditions = [] + destroyPart(situation) + payload.parentNode.situations.splice(j, 1) + cleanNode(situation) + return + } + } + } + + function deleteCondition (node) { + let payload = node.payload + for (let i = 0; i < payload.parentNode.conditions.length; i++) { + let condition = payload.parentNode.conditions[i] + if (condition.id === node.id) { + destroyPart(node) + payload.parentNode.conditions.splice(i, 1) + cleanNode(condition) + 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 + } +} diff --git a/StrategySpace/Workspace.js b/StrategySpace/Workspace.js new file mode 100644 index 000000000..d03cf2b35 --- /dev/null +++ b/StrategySpace/Workspace.js @@ -0,0 +1,359 @@ + +function newWorkspace () { + const MODULE_NAME = 'Workspace' + const ERROR_LOG = true + const logger = newWebDebugLog() + logger.fileName = MODULE_NAME + + let thisObject = { + isDeployed: false, + strategizerData: undefined, + container: undefined, + tradingSystem: undefined, + loadFromStrategyzer: loadFromStrategyzer, + saveToStrategyzer: saveToStrategyzer, + deploydTradingSystem: deploydTradingSystem, + draw: draw, + getContainer: getContainer, + initialize: initialize + } + + let colletionItems = [] + + thisObject.container = newContainer() + thisObject.container.name = MODULE_NAME + thisObject.container.initialize() + + thisObject.container.frame.width = 0 + thisObject.container.frame.height = 0 + + thisObject.container.frame.position.x = 0 + thisObject.container.frame.position.y = 0 + + thisObject.container.isDraggeable = false + thisObject.container.isClickeable = false + + return thisObject + + function initialize () { + + } + + async function saveToStrategyzer () { + try { + const accessToken = window.localStorage.getItem(LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE) + + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE) + if (user === null) { + if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> Can not save because user is not logged in. ') } + return + } + + user = JSON.parse(user) + + const authId = user.authId + + const apolloClient = new Apollo.lib.ApolloClient({ + networkInterface: Apollo.lib.createNetworkInterface({ + uri: window.canvasApp.graphQL.masterAppApiUrl, + transportBatching: true + }), + connectToDevTools: true + }) + + /* Updating all Strategies */ + + const networkInterface = Apollo.lib.createNetworkInterface({ + uri: window.canvasApp.graphQL.masterAppApiUrl + }) + + networkInterface.use([{ + applyMiddleware (req, next) { + req.options.headers = { + authorization: `Bearer ${accessToken}` + } + next() + } + }]) + + let dataToSave = buildGraphQLDataToSave() + + const updateStrategies = () => { + return new Promise((resolve, reject) => { + apolloClient.mutate({ + mutation: GRAPHQL_MUTATION_UPDATE_STRATEGIES, + variables: { + id: thisObject.strategizerData.id, + strategy: dataToSave.strategy + } + }) + .then(response => { + resolve(true) + }) + .catch(err => { + if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> ApolloClient error getting user strategies -> err = ' + err.stack) } + reject(err) + }) + }) + } + + let result = await updateStrategies() + + return result + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] saveToStrategyzer -> err = ' + err.stack) } + } + } + + function buildGraphQLDataToSave () { + let graphQL_Mutation = '' + + let dataToSave = { + strategy: { + subStrategies: [] + } + } + + for (m = 0; m < thisObject.tradingSystem.protocolData.strategies.length; m++) { + let workspaceStrategy = thisObject.tradingSystem.protocolData.strategies[m] + let strategy = { + name: workspaceStrategy.name, + active: workspaceStrategy.active, + entryPoint: { + situations: [] + }, + exitPoint: { + situations: [] + }, + sellPoint: { + situations: [] + }, + stopLoss: { + phases: [] + }, + buyOrder: { + phases: [] + } + } + + for (let k = 0; k < workspaceStrategy.entryPoint.situations.length; k++) { + let workspaceSituation = workspaceStrategy.entryPoint.situations[k] + let situation = { + name: workspaceSituation.name, + conditions: [] + } + + for (let m = 0; m < workspaceSituation.conditions.length; m++) { + let workspaceCondition = workspaceSituation.conditions[m] + let condition = { + name: workspaceCondition.name, + code: workspaceCondition.code + } + situation.conditions.push(condition) + } + strategy.entryPoint.situations.push(situation) + } + + for (let k = 0; k < workspaceStrategy.exitPoint.situations.length; k++) { + let workspaceSituation = workspaceStrategy.exitPoint.situations[k] + let situation = { + name: workspaceSituation.name, + conditions: [] + } + + for (let m = 0; m < workspaceSituation.conditions.length; m++) { + let workspaceCondition = workspaceSituation.conditions[m] + let condition = { + name: workspaceCondition.name, + code: workspaceCondition.code + } + situation.conditions.push(condition) + } + strategy.exitPoint.situations.push(situation) + } + + for (let k = 0; k < workspaceStrategy.sellPoint.situations.length; k++) { + let workspaceSituation = workspaceStrategy.sellPoint.situations[k] + let situation = { + name: workspaceSituation.name, + conditions: [] + } + + for (let m = 0; m < workspaceSituation.conditions.length; m++) { + let workspaceCondition = workspaceSituation.conditions[m] + let condition = { + name: workspaceCondition.name, + code: workspaceCondition.code + } + situation.conditions.push(condition) + } + strategy.sellPoint.situations.push(situation) + } + + for (let p = 0; p < workspaceStrategy.stopLoss.phases.length; p++) { + let workspacePhase = workspaceStrategy.stopLoss.phases[p] + let phase = { + name: workspacePhase.name, + code: workspacePhase.code, + situations: [] + } + + for (let k = 0; k < workspacePhase.situations.length; k++) { + let workspaceSituation = workspacePhase.situations[k] + let situation = { + name: workspaceSituation.name, + conditions: [] + } + + for (let m = 0; m < workspaceSituation.conditions.length; m++) { + let workspaceCondition = workspaceSituation.conditions[m] + let condition = { + name: workspaceCondition.name, + code: workspaceCondition.code + } + situation.conditions.push(condition) + } + phase.situations.push(situation) + } + strategy.stopLoss.phases.push(phase) + } + + for (let p = 0; p < workspaceStrategy.buyOrder.phases.length; p++) { + let workspacePhase = workspaceStrategy.buyOrder.phases[p] + let phase = { + name: workspacePhase.name, + code: workspacePhase.code, + situations: [] + } + + for (let k = 0; k < workspacePhase.situations.length; k++) { + let workspaceSituation = workspacePhase.situations[k] + let situation = { + name: workspaceSituation.name, + conditions: [] + } + + for (let m = 0; m < workspaceSituation.conditions.length; m++) { + let workspaceCondition = workspaceSituation.conditions[m] + let condition = { + name: workspaceCondition.name, + code: workspaceCondition.code + } + situation.conditions.push(condition) + } + phase.situations.push(situation) + } + strategy.buyOrder.phases.push(phase) + } + dataToSave.strategy.subStrategies.push(strategy) + } + + return dataToSave + } + + async function loadFromStrategyzer () { + try { + const accessToken = window.localStorage.getItem(LOGGED_IN_ACCESS_TOKEN_LOCAL_STORAGE) + + let user = window.localStorage.getItem(LOGGED_IN_USER_LOCAL_STORAGE) + if (user === null) { + // if there is no user that means that we are logged off, which means this object can not be used. + return + } + + user = JSON.parse(user) + + const authId = user.authId + + let sessionToken + + const apolloClient = new Apollo.lib.ApolloClient({ + networkInterface: Apollo.lib.createNetworkInterface({ + uri: window.canvasApp.graphQL.masterAppApiUrl, + transportBatching: true + }), + connectToDevTools: true + }) + + /* Getting the FB that own the Strategies */ + + let tradingSystemSimulationClone = '' + let clones = window.localStorage.getItem('userClones') + if (clones === null || clones === '') { + if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> no user clones found at local storage. Can not get Strategies without them. ') } + return + } + clones = JSON.parse(clones) + for (let i = 0; i < clones.length; i++) { + let clone = clones[i] + if (clone.botType === 'Indicator') { + tradingSystemSimulationClone = clone.botSlug + } + } + + /* Getting all Strategies */ + + const networkInterface = Apollo.lib.createNetworkInterface({ + uri: window.canvasApp.graphQL.masterAppApiUrl + }) + + networkInterface.use([{ + applyMiddleware (req, next) { + req.options.headers = { + authorization: `Bearer ${accessToken}` + } + next() + } + }]) + + const getStrategies = () => { + return new Promise((resolve, reject) => { + apolloClient.query({ + query: GRAPHQL_QUERY_GET_STRATEGIES, + variables: { fbSlug: tradingSystemSimulationClone} + }) + .then(response => { + window.localStorage.setItem('userStrategies', JSON.stringify(response.data.strategizer_StrategyByFb)) + thisObject.strategizerData = JSON.parse(JSON.stringify(response.data.strategizer_StrategyByFb)) + + resolve({ strategies: response.data.strategizer_StrategyByFb.subStrategies}) + }) + .catch(err => { + if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> ApolloClient error getting user strategies -> err = ' + err.stack) } + reject(err) + }) + }) + } + + // To avoid race conditions, add asynchronous fetches to array + let fetchDataPromises = [] + + fetchDataPromises.push(getStrategies()) + + // When all asynchronous fetches resolve, authenticate user or throw error. + await Promise.all(fetchDataPromises).then(result => { + + }, err => { + if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> GraphQL Fetch Error -> err = ' + err.stack) } + }) + } catch (err) { + if (ERROR_LOG === true) { logger.write('[ERROR] loadFromStrategyzer -> err = ' + err.stack) } + } + } + + function deploydTradingSystem () { + thisObject.tradingSystem = newTradingSystem() + thisObject.tradingSystem.initialize(thisObject.strategizerData) + thisObject.isDeployed = true + } + + function getContainer (point) { + let container + + return undefined + } + + function draw () { + + } +} diff --git a/TimelineChart.js b/TimelineChart.js deleted file mode 100644 index a5f15f160..000000000 --- a/TimelineChart.js +++ /dev/null @@ -1,484 +0,0 @@ - function newTimelineChart () { - const MODULE_NAME = 'Timeline Chart' - const INFO_LOG = false - const INTENSIVE_LOG = false - const ERROR_LOG = true - const logger = newWebDebugLog() - logger.fileName = MODULE_NAME - - let timeLineCoordinateSystem - - let timePeriod = INITIAL_TIME_PERIOD - let datetime = NEW_SESSION_INITIAL_DATE - - let thisObject = { - setDatetime: setDatetime, - container: undefined, - drawBackground: drawBackground, - draw: draw, - getContainer: getContainer, - initialize: initialize, - finalize: finalize - } - - thisObject.container = newContainer() - thisObject.container.initialize(MODULE_NAME) - thisObject.container.detectMouseOver = true - - let initializationReady = false - - let productsPanel - - /* Background */ - let logoAssetA - let logoAssetB - let logoExchange - let logoAA - let canDrawLogoA = false - let canDrawLogoB = false - let canDrawLogoExchange = false - let canDrawLogoAA = false - - let plotterManager - let exchange - let market - - let productsPanelHandle - let timePeriodScale - - return thisObject - - function finalize () { - try { - if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') } - - plotterManager.finalize() - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) } - } - } - - function initialize (pExchange, pMarket, pTimeLineCoordinateSystem, callBackFunction) { - try { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') } - - /* We load the logow we will need for the background. */ - exchange = pExchange - market = pMarket - timeLineCoordinateSystem = pTimeLineCoordinateSystem - - thisObject.container.eventHandler.listenToEvent('onMouseOver', function (event) { - saveUserPosition(thisObject.container, timeLineCoordinateSystem, event) - }) - - let panelOwner = exchange + ' ' + market.assetB + '/' + market.assetA - productsPanelHandle = canvas.panelsSpace.createNewPanel('Products Panel', undefined, panelOwner) - let productsPanel = canvas.panelsSpace.getPanel(productsPanelHandle, panelOwner) - productsPanel.initialize(exchange, market) - - logoA = new Image() - logoB = new Image() - logoExchange = new Image() - logoAA = new Image() - - logoA.onload = onImageALoaded - - function onImageALoaded () { - canDrawLogoA = true - } - - logoB.onload = onImageBLoaded - - function onImageBLoaded () { - canDrawLogoB = true - } - - logoExchange.onload = onImageExchangeLoaded - - function onImageExchangeLoaded () { - canDrawLogoExchange = true - } - - logoAA.onload = onImageAALoaded - - function onImageAALoaded () { - canDrawLogoAA = true - } - - logoA.src = window.canvasApp.urlPrefix + 'Images/tether-logo-background.png' - logoB.src = window.canvasApp.urlPrefix + 'Images/bitcoin-logo-background.png' - logoExchange.src = window.canvasApp.urlPrefix + 'Images/' + exchange + '-logo-background.png' - logoAA.src = window.canvasApp.urlPrefix + 'Images/sa-logo-background.png' - - // moveToUserPosition(thisObject.container, timeLineCoordinateSystem, undefined, undefined, undefined, true) - timePeriod = INITIAL_TIME_PERIOD - datetime = NEW_SESSION_INITIAL_DATE - - /* Event Subscriptions - we need this events to be fired first here and then in active Plotters. */ - - viewPort.eventHandler.listenToEvent('Offset Changed', onOffsetChanged) - viewPort.eventHandler.listenToEvent('Zoom Changed', onZoomChanged) - - /* Initialize the Plotter Manager */ - - plotterManager = newPlottersManager() - - plotterManager.container.connectToParent(thisObject.container, true, true) - - plotterManager.container.frame.position.x = 0 - plotterManager.container.frame.position.y = 0 - - plotterManager.initialize(productsPanel, pExchange, pMarket, onPlotterManagerReady) - - function onPlotterManagerReady (err) { - if (INFO_LOG === true) { logger.write('[INFO] initialize -> onPlotterManagerReady -> Entering function.') } - - if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> onPlotterManagerReady -> Plotter Manager Initialization Failed. ') } - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> onPlotterManagerReady -> err.message = ' + err.message) } - - callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) - return - } - - timePeriodScale = newTimePeriodScale() - timePeriodScale.container.connectToParent(thisObject.container, false, false) - timePeriodScale.container.eventHandler.listenToEvent('Time Period Changed', function (event) { - let currentTimePeriod = timePeriod - timePeriod = event.timePeriod - if (timePeriod !== currentTimePeriod) { - plotterManager.setTimePeriod(timePeriod) - } - }) - - timePeriodScale.initialize(timeLineCoordinateSystem) - - initializationReady = true - callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE) - return - } - } catch (err) { - if (ERROR_LOG === true) { logger.write('[ERROR] initialize -> err = ' + err.stack) } - callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) - } - } - - function onZoomChanged (event) { - if (INFO_LOG === true) { logger.write('[INFO] onZoomChanged -> Entering function.') } - - if (initializationReady === true) { - recalculateCurrentDatetime() - - // saveUserPosition(thisObject.container, timeLineCoordinateSystem) - } - } - - function setDatetime (pDatetime) { - if (INFO_LOG === true) { logger.write('[INFO] setDatetime -> Entering function.') } - - /* This function is used when the time is changed through the user interface, but without zooming or panning. */ - /* No matter if the day changed or not, we need to inform all visible Plotters. */ - - if (thisObject.container.frame.isInViewPort()) { - plotterManager.setDatetime(pDatetime) - plotterManager.positionAtDatetime(pDatetime) - } - } - - function onOffsetChanged () { - if (INFO_LOG === true) { logger.write('[INFO] onOffsetChanged -> Entering function.') } - - if (initializationReady === true) { - if (thisObject.container.frame.isInViewPort()) { - recalculateCurrentDatetime() - // saveUserPosition(thisObject.container, timeLineCoordinateSystem) - } - } - } - - function recalculateCurrentDatetime () { - if (INFO_LOG === true) { logger.write('[INFO] recalculateCurrentDatetime -> Entering function.') } - - /* - - 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: (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.bottomLeft.x) / 2, - y: (viewPort.visibleArea.bottomRight.y - viewPort.visibleArea.topRight.y) / 2 - } - - center = unTransformThisPoint(center, thisObject.container) - center = timeLineCoordinateSystem.unInverseTransform(center, thisObject.container.frame.height) - - let newDate = new Date(0) - newDate.setUTCSeconds(center.x / 1000) - - datetime = newDate - - plotterManager.setDatetime(datetime) - - thisObject.container.eventHandler.raiseEvent('Datetime Changed', datetime) - } - - function getContainer (point) { - if (INFO_LOG === true) { logger.write('[INFO] getContainer -> Entering function.') } - - let container - - container = timePeriodScale.getContainer(point) - - if (container !== undefined) { return container } - - return container - } - - function tooTiny () { - if (INTENSIVE_LOG === true) { logger.write('[INFO] tooTiny -> Entering function.') } - - if (viewPort.zoomLevel < Math.trunc(-28.25 * 100) / 100) { - return true - } else { - return false - } - } - - function tooSmall () { - if (INFO_LOG === true) { logger.write('[INFO] tooSmall -> Entering function.') } - - if (viewPort.zoomLevel < Math.trunc(-27.25 * 100) / 100) { - return true - } else { - return false - } - } - - function drawBackground () { - if (INTENSIVE_LOG === true) { logger.write('[INFO] drawBackground -> Entering function.') } - - if (thisObject.container.frame.isInViewPort()) { - if (window.CHART_ON_FOCUS === '') { - window.CHART_ON_FOCUS = exchange + ' ' + market.assetB + '/' + market.assetA - - drawChartsBackgroundImages() - } - } - } - - function draw () { - if (INTENSIVE_LOG === true) { logger.write('[INFO] draw -> Entering function.') } - - if (thisObject.container.frame.isInViewPort()) { - drawChartsBackground() - - // chartGrid.draw(thisObject.container, timeLineCoordinateSystem) - - timePeriodScale.draw() - plotterManager.draw() - } - } - - function drawChartsBackground () { - /* We will paint some transparent background here. */ - - let opacity = '0.9' - - let fromPoint = { - x: 0, - y: 0 - } - - let toPoint = { - x: thisObject.container.frame.width, - y: thisObject.container.frame.height - } - - fromPoint = transformThisPoint(fromPoint, thisObject.container) - toPoint = transformThisPoint(toPoint, thisObject.container) - - 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() - } - - function drawChartsBackgroundImages () { - if (INTENSIVE_LOG === true) { logger.write('[INFO] drawChartsBackground -> Entering function.') } - - if (canDrawLogoA === false || canDrawLogoB === false || canDrawLogoExchange === false || canDrawLogoAA === false) { return } - - /* Fist we calculate the corners of the current frame so as not to draw imaages ourside of it */ - - let fromPoint = { - x: 0, - y: 0 - } - - let toPoint = { - x: thisObject.container.frame.width, - y: thisObject.container.frame.height - } - - fromPoint = transformThisPoint(fromPoint, thisObject.container) - toPoint = transformThisPoint(toPoint, thisObject.container) - - /* Second we calculate the points for the images themselves */ - - let backgroundLogoPoint1 - let backgroundLogoPoint2 - - let imageHeight = 42 - let imageWidth = 150 - - let MAX_COLUMNS = 16 - let MAX_ROWS = 7 - let Y_TOP_MARGIN = 30 - - let point1 = { - x: viewPort.visibleArea.topLeft.x, - y: viewPort.visibleArea.topLeft.y - } - - backgroundLogoPoint1 = { - x: getDateFromPoint(point1, thisObject.container, timeLineCoordinateSystem).valueOf(), - y: getRateFromPoint(point1, thisObject.container, timeLineCoordinateSystem) - } - - let point2 = { - x: viewPort.visibleArea.topLeft.x + imageWidth * 8, - y: viewPort.visibleArea.topLeft.y - } - - backgroundLogoPoint2 = { - x: getDateFromPoint(point2, thisObject.container, timeLineCoordinateSystem).valueOf(), - y: getRateFromPoint(point2, thisObject.container, timeLineCoordinateSystem) - } - - let currentCorner = { - x: getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, timeLineCoordinateSystem).valueOf(), - y: getRateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, timeLineCoordinateSystem) - } - - currentCorner.x = Math.trunc(currentCorner.x / (backgroundLogoPoint2.x - backgroundLogoPoint1.x)) * (backgroundLogoPoint2.x - backgroundLogoPoint1.x) - - let rowHight = (viewPort.visibleArea.bottomLeft.y - viewPort.visibleArea.topLeft.y) / 4.5 - - imagePoint = timeLineCoordinateSystem.transformThisPoint(currentCorner) - imagePoint = transformThisPoint(imagePoint, thisObject.container) - - let offSet = 0 - let imagePosition = { - x: 0, - y: 0 - } - - for (let j = 0; j < MAX_ROWS; j++) { - if (offSet === -imageWidth * 8) { - offSet = -imageWidth * 4 - imageWidth - } else { - offSet = -imageWidth * 8 - } - - for (let i = 0; i < MAX_COLUMNS; i = i + 4) { - let logo = logoA - - imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet - imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN - - if ( - imagePosition.x > fromPoint.x && - imagePosition.x + imageWidth < toPoint.x && - imagePosition.y > fromPoint.y && - imagePosition.y + imageHeight < toPoint.y - ) { - browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) - } - } - } - - offSet = 0 - - for (let j = 0; j < MAX_ROWS; j++) { - if (offSet === -imageWidth * 8) { - offSet = -imageWidth * 4 - imageWidth - } else { - offSet = -imageWidth * 8 - } - - for (let i = 1; i < MAX_COLUMNS; i = i + 4) { - let logo = logoB - - imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet - imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN - - if ( - imagePosition.x > fromPoint.x && - imagePosition.x + imageWidth < toPoint.x && - imagePosition.y > fromPoint.y && - imagePosition.y + imageHeight < toPoint.y - ) { - browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) - } - } - } - - offSet = 0 - - for (let j = 0; j < MAX_ROWS; j++) { - if (offSet === -imageWidth * 8) { - offSet = -imageWidth * 4 - imageWidth - } else { - offSet = -imageWidth * 8 - } - - for (let i = 2; i < MAX_COLUMNS; i = i + 4) { - let logo = logoExchange - - imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet - imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN - - if ( - imagePosition.x > fromPoint.x && - imagePosition.x + imageWidth < toPoint.x && - imagePosition.y > fromPoint.y && - imagePosition.y + imageHeight < toPoint.y - ) { - browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) - } - } - } - - offSet = 0 - - for (let j = 0; j < MAX_ROWS; j++) { - if (offSet === -imageWidth * 8) { - offSet = -imageWidth * 4 - imageWidth - } else { - offSet = -imageWidth * 8 - } - - for (let i = 3; i < MAX_COLUMNS; i = i + 4) { - let logo = logoAA - - imagePosition.x = imagePoint.x + i * imageWidth * 2 + offSet - imagePosition.y = imagePoint.y + j * rowHight + Y_TOP_MARGIN - - if ( - imagePosition.x > fromPoint.x && - imagePosition.x + imageWidth < toPoint.x && - imagePosition.y > fromPoint.y && - imagePosition.y + imageHeight < toPoint.y - ) { - browserCanvasContext.drawImage(logo, imagePosition.x, imagePosition.y, imageWidth, imageHeight) - } - } - } - } - } diff --git a/TopSpace/CurrentEvent.js b/TopSpace/CurrentEvent.js index 81a5c92d3..b2831e277 100644 --- a/TopSpace/CurrentEvent.js +++ b/TopSpace/CurrentEvent.js @@ -70,7 +70,7 @@ function newCurrentEvent () { thisObject.container = container thisObject.container.frame.width = 150 - thisObject.container.frame.height = BOTTOM_SPACE_HEIGHT + thisObject.container.frame.height = COCKPIT_SPACE_HEIGHT resize() diff --git a/TopSpace/EndUser.js b/TopSpace/EndUser.js index 6edaf5b44..b8699eb69 100644 --- a/TopSpace/EndUser.js +++ b/TopSpace/EndUser.js @@ -12,7 +12,7 @@ function newEndUser () { thisObject.container = container thisObject.container.frame.width = 200 - thisObject.container.frame.height = BOTTOM_SPACE_HEIGHT + thisObject.container.frame.height = COCKPIT_SPACE_HEIGHT container.frame.position.x = viewPort.visibleArea.topRight.x - thisObject.container.frame.width * 5 container.frame.position.y = viewPort.visibleArea.bottomLeft.y + BREAKPOINT_HEIGHT diff --git a/TopSpace/Login.js b/TopSpace/Login.js index 7d242191c..61aa996c1 100644 --- a/TopSpace/Login.js +++ b/TopSpace/Login.js @@ -19,7 +19,7 @@ function newLogin () { thisObject.container = container thisObject.container.frame.width = 200 - thisObject.container.frame.height = BOTTOM_SPACE_HEIGHT + thisObject.container.frame.height = COCKPIT_SPACE_HEIGHT container.frame.position.x = viewPort.visibleArea.topRight.x - thisObject.container.frame.width * 1 container.frame.position.y = viewPort.visibleArea.bottomLeft.y + BREAKPOINT_HEIGHT diff --git a/UIControl.js b/UIControl.js deleted file mode 100644 index ab8a9de48..000000000 --- a/UIControl.js +++ /dev/null @@ -1,55 +0,0 @@ -function newUIControl () { - let thisObject = { - drawFunction: undefined, - paramsArray: undefined, - container: undefined, - draw: draw, - parentContainer: undefined, - getContainer: getContainer, // returns the inner most container that holds the point received by parameter. - initialize: initialize - } - - let isInitialized = false - /* Cointainer stuff */ - - let container = newContainer() - - container.name = 'UI Control' - container.initialize() - - container.isClickeable = true - - thisObject.container = container - thisObject.container.frame.containerName = 'Panel Tab Button' - - return thisObject - - function initialize () { - isInitialized = true - } - - function draw () { - if (isInitialized === false) { return } - - if (thisObject.drawFunction !== undefined && thisObject.paramsArray !== undefined) { - thisObject.drawFunction(thisObject.paramsArray) - } - } - - function getContainer (point) { - var container - - /* First we check if thisObject point is inside thisObject space. */ - - if (thisObject.container.frame.isThisPointHere(point, true) === true) { - /* Now we see which is the inner most container that has it */ - - return thisObject.container - } else { - /* This point does not belong to thisObject space. */ - - return undefined - } - } -} - diff --git a/Utilities.js b/Utilities.js index 8bc732ab9..a72310054 100644 --- a/Utilities.js +++ b/Utilities.js @@ -154,25 +154,10 @@ function removeTime (datetime) { return dateOnly } -function loadEmoji (pPath) { - let newImage - - newImage = new Image() - newImage.onload = onImageLoaded - - function onImageLoaded () { - newImage.isLoaded = true - } - - newImage.src = window.canvasApp.urlPrefix + 'Images/Emoji/' + pPath - - return newImage -} - function printLabel (labelToPrint, x, y, opacity, fontSize) { let labelPoint - browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY + ' Saira' + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.PRIMARY let label = '' + labelToPrint @@ -181,3 +166,10 @@ function printLabel (labelToPrint, x, y, opacity, fontSize) { browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', ' + 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) + }) +} diff --git a/Utilities/RoundedCornersBackground.js b/Utilities/RoundedCornersBackground.js index 76863de02..a940c81c8 100644 --- a/Utilities/RoundedCornersBackground.js +++ b/Utilities/RoundedCornersBackground.js @@ -1,30 +1,51 @@ function roundedCornersBackground (params) { borderPoint1 = { - x: params.cornerRadious, - y: params.cornerRadious + x: params.cornerRadius, + y: params.cornerRadius } borderPoint2 = { - x: params.container.frame.width - params.cornerRadious, - y: params.cornerRadious + x: params.container.frame.width - params.cornerRadius, + y: params.cornerRadius } borderPoint3 = { - x: params.container.frame.width - params.cornerRadious, - y: params.container.frame.height - params.cornerRadious + x: params.container.frame.width - params.cornerRadius, + y: params.container.frame.height - params.cornerRadius } borderPoint4 = { - x: params.cornerRadious, - y: params.container.frame.height - params.cornerRadious + x: params.cornerRadius, + y: params.container.frame.height - params.cornerRadius } /* Now the transformations. */ - 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.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]) @@ -35,14 +56,14 @@ function roundedCornersBackground (params) { browserCanvasContext.beginPath() - browserCanvasContext.arc(borderPoint1.x + SHADOW_OFFSET, borderPoint1.y + SHADOW_OFFSET, params.cornerRadious, 1.0 * Math.PI, 1.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint2.x + SHADOW_OFFSET, borderPoint2.y - params.cornerRadious + SHADOW_OFFSET) - browserCanvasContext.arc(borderPoint2.x + SHADOW_OFFSET, borderPoint2.y + SHADOW_OFFSET, params.cornerRadious, 1.5 * Math.PI, 2.0 * Math.PI) - browserCanvasContext.lineTo(borderPoint3.x + params.cornerRadious + SHADOW_OFFSET, borderPoint3.y + SHADOW_OFFSET) - browserCanvasContext.arc(borderPoint3.x + SHADOW_OFFSET, borderPoint3.y + SHADOW_OFFSET, params.cornerRadious, 0 * Math.PI, 0.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint4.x + SHADOW_OFFSET, borderPoint4.y + params.cornerRadious + SHADOW_OFFSET) - browserCanvasContext.arc(borderPoint4.x + SHADOW_OFFSET, borderPoint4.y + SHADOW_OFFSET, params.cornerRadious, 0.5 * Math.PI, 1.0 * Math.PI) - browserCanvasContext.lineTo(borderPoint1.x - params.cornerRadious + SHADOW_OFFSET, borderPoint1.y + SHADOW_OFFSET) + 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() @@ -63,14 +84,14 @@ function roundedCornersBackground (params) { browserCanvasContext.beginPath() - browserCanvasContext.arc(borderPoint1.x, borderPoint1.y, params.cornerRadious, 1.0 * Math.PI, 1.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint2.x, borderPoint2.y - params.cornerRadious) - browserCanvasContext.arc(borderPoint2.x, borderPoint2.y, params.cornerRadious, 1.5 * Math.PI, 2.0 * Math.PI) - browserCanvasContext.lineTo(borderPoint3.x + params.cornerRadious, borderPoint3.y) - browserCanvasContext.arc(borderPoint3.x, borderPoint3.y, params.cornerRadious, 0 * Math.PI, 0.5 * Math.PI) - browserCanvasContext.lineTo(borderPoint4.x, borderPoint4.y + params.cornerRadious) - browserCanvasContext.arc(borderPoint4.x, borderPoint4.y, params.cornerRadious, 0.5 * Math.PI, 1.0 * Math.PI) - browserCanvasContext.lineTo(borderPoint1.x - params.cornerRadious, borderPoint1.y) + 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() @@ -82,4 +103,3 @@ function roundedCornersBackground (params) { browserCanvasContext.strokeStyle = 'rgba(' + params.borderColor + ', ' + params.opacity + ')' browserCanvasContext.stroke() } -