diff --git a/Conditions.js b/Conditions.js new file mode 100644 index 000000000..be5e1e429 --- /dev/null +++ b/Conditions.js @@ -0,0 +1,578 @@ +function newAAMastersPlottersTradingSimulationConditions() { + + const MODULE_NAME = "Conditions Plotter"; + const INFO_LOG = false; + const ERROR_LOG = true; + const INTENSIVE_LOG = false; + const logger = newWebDebugLog(); + logger.fileName = MODULE_NAME; + + let thisObject = { + + // Main functions and properties. + + initialize: initialize, + container: undefined, + getContainer: getContainer, + setTimePeriod: setTimePeriod, + setDatetime: setDatetime, + draw: draw, + recalculateScale: recalculateScale, + + /* Events declared outside the plotter. */ + + onDailyFileLoaded: onDailyFileLoaded, + + // Secondary functions and properties. + + currentRecord: undefined + }; + + /* this is part of the module template */ + + let container = newContainer(); // Do not touch this 3 lines, they are just needed. + container.initialize(); + thisObject.container = container; + + let timeLineCoordinateSystem = newTimeLineCoordinateSystem(); // Needed to be able to plot on the timeline, otherwise not. + + let timePeriod; // This will hold the current Time Period the user is at. + let datetime; // This will hold the current Datetime the user is at. + + let marketFile; // This is the current Market File being plotted. + let fileCursor; // This is the current File Cursor being used to retrieve Daily Files. + + let marketFiles; // This object will provide the different Market Files at different Time Periods. + let dailyFiles; // This object will provide the different File Cursors at different Time Periods. + + /* these are module specific variables: */ + + let conditions = []; + + let smileyHappy; + let smileySad; + let smileyGhost; + let smileyMonkeyEyes; + let smileyMonkeyEars; + let imageStrategy; + let imageStrategyPhase; + let imageStopLossPhase; + let imageBuyOrderPhase; + + return thisObject; + + function initialize(pStorage, pExchange, pMarket, pDatetime, pTimePeriod, callBackFunction) { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] initialize -> Entering function."); } + + /* Store the information received. */ + + marketFiles = pStorage.marketFiles[0]; + dailyFiles = pStorage.dailyFiles[0]; + + datetime = pDatetime; + timePeriod = pTimePeriod; + + /* We need a Market File in order to calculate the Y scale, since this scale depends on actual data. */ + + marketFile = marketFiles.getFile(ONE_DAY_IN_MILISECONDS); // This file is the one processed faster. + + recalculateScale(); + + /* Now we set the right files according to current Period. */ + + marketFile = marketFiles.getFile(pTimePeriod); + fileCursor = dailyFiles.getFileCursor(pTimePeriod); + + /* Listen to the necesary events. */ + + viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged); + viewPort.eventHandler.listenToEvent("Offset Changed", onOffsetChanged); + marketFiles.eventHandler.listenToEvent("Files Updated", onFilesUpdated); + canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished); + + /* Get ready for plotting. */ + + recalculate(); + + /* Loading a few icons */ + + smileyHappy = loadEmoji("Smiley/Emoji Smiley-51.png"); + smileySad = loadEmoji("Smiley/Emoji Smiley-26.png"); + smileyGhost = loadEmoji("Objects/Emoji Objects-12.png"); + smileyMonkeyEyes = loadEmoji("Smiley/Emoji Smiley-85.png"); + smileyMonkeyEars = loadEmoji("Smiley/Emoji Smiley-86.png"); + imageStrategy = loadEmoji("Places/Emoji Orte-90.png"); + imageStrategyPhase = loadEmoji("Places/Emoji Orte-91.png"); + imageStopLossPhase = loadEmoji("Objects/Emoji Objects-55.png"); + imageBuyOrderPhase = loadEmoji("Objects/Emoji Objects-114.png"); + + 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; + } + + callBackFunction(); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] initialize -> err.message = " + err.message); } + } + } + + function getContainer(point) { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] getContainer -> Entering function."); } + + let container; + + /* First we check if this point is inside this space. */ + + if (this.container.frame.isThisPointHere(point) === true) { + + return this.container; + + } else { + + /* This point does not belong to this space. */ + + return undefined; + } + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] getContainer -> err.message = " + err.message); } + } + } + + function onFilesUpdated() { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] onFilesUpdated -> Entering function."); } + + let newMarketFile = marketFiles.getFile(timePeriod); + + if (newMarketFile !== undefined) { + + marketFile = newMarketFile; + recalculate(); + } + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] onFilesUpdated -> err.message = " + err.message); } + } + } + + function setTimePeriod(pTimePeriod) { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] setTimePeriod -> Entering function."); } + + if (timePeriod !== pTimePeriod) { + + timePeriod = pTimePeriod; + + if (timePeriod >= _1_HOUR_IN_MILISECONDS) { + + let newMarketFile = marketFiles.getFile(pTimePeriod); + + if (newMarketFile !== undefined) { + + marketFile = newMarketFile; + recalculate(); + } + + } else { + + let newFileCursor = dailyFiles.getFileCursor(pTimePeriod); + + if (newFileCursor !== undefined) { + + fileCursor = newFileCursor; + recalculate(); + } + } + } + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] setTimePeriod -> err.message = " + err.message); } + } + } + + function setDatetime(pDatetime) { + + if (INFO_LOG === true) { logger.write("[INFO] setDatetime -> Entering function."); } + + datetime = pDatetime; + + } + + function onDailyFileLoaded(event) { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] onDailyFileLoaded -> Entering function."); } + + if (event.currentValue === event.totalValue) { + + /* This happens only when all of the files in the cursor have been loaded. */ + + recalculate(); + + } + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] onDailyFileLoaded -> err.message = " + err.message); } + } + } + + function draw() { + + try { + + if (INTENSIVE_LOG === true) { logger.write("[INFO] draw -> Entering function."); } + + this.container.frame.draw(); + + plotChart(); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] draw -> err.message = " + err.message); } + } + } + + function recalculate() { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] recalculate -> Entering function."); } + + if (timePeriod >= _1_HOUR_IN_MILISECONDS) { + + recalculateUsingMarketFiles(); + + } else { + + recalculateUsingDailyFiles(); + + } + + thisObject.container.eventHandler.raiseEvent("Conditions Changed", conditions); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] recalculate -> err.message = " + err.message); } + } + } + + function recalculateUsingDailyFiles() { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] recalculateUsingDailyFiles -> Entering function."); } + + if (fileCursor === undefined) { return; } // We need to wait + + if (fileCursor.files.size === 0) { return; } // We need to wait until there are files in the cursor + + let daysOnSides = getSideDays(timePeriod); + + let leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, timeLineCoordinateSystem); + let rightDate = getDateFromPoint(viewPort.visibleArea.topRight, thisObject.container, timeLineCoordinateSystem); + + let dateDiff = rightDate.valueOf() - leftDate.valueOf(); + + let farLeftDate = new Date(leftDate.valueOf() - dateDiff * 1.5); + let farRightDate = new Date(rightDate.valueOf() + dateDiff * 1.5); + + let currentDate = new Date(farLeftDate.valueOf()); + + conditions = []; + + while (currentDate.valueOf() <= farRightDate.valueOf() + ONE_DAY_IN_MILISECONDS) { + + let stringDate = currentDate.getFullYear() + '-' + pad(currentDate.getMonth() + 1, 2) + '-' + pad(currentDate.getDate(), 2); + + let dailyFile = fileCursor.files.get(stringDate); + + if (dailyFile !== undefined) { + + for (let i = 0; i < dailyFile.length; i++) { + + let record = { + begin: undefined, + end: undefined, + conditions: undefined + }; + + record.begin = dailyFile[i][0]; + record.end = dailyFile[i][1]; + record.conditions = dailyFile[i]; + + if (record.begin >= farLeftDate.valueOf() && record.end <= farRightDate.valueOf()) { + + conditions.push(record); + + if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) { + + thisObject.currentRecord = record; + thisObject.container.eventHandler.raiseEvent("Current Condition Changed", thisObject.currentRecord); + + } + } + } + } + + currentDate = new Date(currentDate.valueOf() + ONE_DAY_IN_MILISECONDS); + } + + /* Lests check if all the visible screen is going to be covered by conditions. */ + + let lowerEnd = leftDate.valueOf(); + let upperEnd = rightDate.valueOf(); + + if (conditions.length > 0) { + + if (conditions[0].begin > lowerEnd || conditions[conditions.length - 1].end < upperEnd) { + + setTimeout(recalculate, 2000); + + //console.log("File missing while calculating conditions, scheduling a recalculation in 2 seconds."); + + } + } + + //console.log("Olivia > recalculateUsingDailyFiles > total conditions generated : " + conditions.length); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingDailyFiles -> err.message = " + err.message); } + } + } + + function recalculateUsingMarketFiles() { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] recalculateUsingMarketFiles -> Entering function."); } + + if (marketFile === undefined) { return; } // Initialization not complete yet. + + let daysOnSides = getSideDays(timePeriod); + + let leftDate = getDateFromPoint(viewPort.visibleArea.topLeft, thisObject.container, timeLineCoordinateSystem); + let rightDate = getDateFromPoint(viewPort.visibleArea.topRight, thisObject.container, timeLineCoordinateSystem); + + let dateDiff = rightDate.valueOf() - leftDate.valueOf(); + + leftDate = new Date(leftDate.valueOf() - dateDiff * 1.5); + rightDate = new Date(rightDate.valueOf() + dateDiff * 1.5); + + conditions = []; + + for (let i = 0; i < marketFile.length; i++) { + + let record = { + begin: undefined, + end: undefined, + conditions: undefined + }; + + record.begin = marketFile[i][0]; + record.end = marketFile[i][1]; + record.conditions = marketFile[i]; + + if (i === 0) { // The first record contains headers needed to be printed. + conditions.push(record); + } + + if (record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) { + + conditions.push(record); + + if (datetime.valueOf() >= record.begin && datetime.valueOf() <= record.end) { + + thisObject.currentRecord = record; + thisObject.container.eventHandler.raiseEvent("Current Condition Changed", thisObject.currentRecord); + + } + } + } + + //console.log("Olivia > recalculateUsingMarketFiles > total conditions generated : " + conditions.length); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] recalculateUsingMarketFiles -> err.message = " + err.message); } + } + } + + function recalculateScale() { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] recalculateScale -> Entering function."); } + + if (marketFile === undefined) { return; } // We need the market file to be loaded to make the calculation. + + if (timeLineCoordinateSystem.maxValue > 0) { return; } // Already calculated. + + let minValue = { + x: EARLIEST_DATE.valueOf(), + y: 0 + }; + + let maxValue = { + x: MAX_PLOTABLE_DATE.valueOf(), + y: nextPorwerOf10(getMaxRate()) / 4 // TODO: This 4 is temporary + }; + + + timeLineCoordinateSystem.initialize( + minValue, + maxValue, + thisObject.container.frame.width, + thisObject.container.frame.height + ); + + function getMaxRate() { + + if (INFO_LOG === true) { logger.write("[INFO] recalculateScale -> getMaxRate -> Entering function."); } + + let maxValue = 0; + + for (let i = 0; i < marketFile.length; i++) { + + let currentMax = 25000; // TODO Fix this, since when there are not records above 10k the scales is dissincronized with the scale of the candles. marketFile[i][3]; // 3 = rate. + + if (maxValue < currentMax) { + maxValue = currentMax; + } + } + + return maxValue; + + } + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] recalculateScale -> err.message = " + err.message); } + } + } + + function plotChart() { + + try { + + if (INTENSIVE_LOG === true) { logger.write("[INFO] plotChart -> Entering function."); } + + let conditionRecord; + + for (let i = 1; i < conditions.length; i++) { // We do not start in 0 because there we have the headers. + + conditionRecord = conditions[i]; + + /* Send the current record to the panel */ + + if (datetime !== undefined) { + let dateValue = datetime.valueOf(); + if (dateValue >= conditionRecord.begin && dateValue <= conditionRecord.end) { + + let currentRecord = { + conditionsNames: conditions[0].conditions, + conditionsValues: conditionRecord.conditions + }; + thisObject.container.eventHandler.raiseEvent("Current Condition Record Changed", currentRecord); + } + } + } + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] plotChart -> err.message = " + err.message); } + } + } + + + function onZoomChanged(event) { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] onZoomChanged -> Entering function."); } + + recalculate(); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] onZoomChanged -> err.message = " + err.message); } + } + } + + function onOffsetChanged() { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] onOffsetChanged -> Entering function."); } + + if (Math.random() * 100 > 95) { + + recalculate() + }; + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] onOffsetChanged -> err.message = " + err.message); } + } + } + + function onDragFinished() { + + try { + + if (INFO_LOG === true) { logger.write("[INFO] onDragFinished -> Entering function."); } + + recalculate(); + + } catch (err) { + + if (ERROR_LOG === true) { logger.write("[ERROR] onDragFinished -> err.message = " + err.message); } + } + } +} + + + + + + + + + + + + + + + + diff --git a/ConditionsPanel.js b/ConditionsPanel.js new file mode 100644 index 000000000..55e820318 --- /dev/null +++ b/ConditionsPanel.js @@ -0,0 +1,130 @@ + +function newAAMastersPlottersTradingSimulationConditionsConditionsPanel() { + + var thisObject = { + onEventRaised: onEventRaised, + container: undefined, + draw: draw, + getContainer: getContainer, + initialize: initialize + }; + + var container = newContainer(); + container.initialize(); + thisObject.container = container; + + container.displacement.containerName = "Conditions Panel"; + container.frame.containerName = "Conditions Panel"; + + let currentRecord; + + return thisObject; + + function initialize() { + + thisObject.container.frame.width = UI_PANEL.WIDTH.NORMAL; + thisObject.container.frame.height = UI_PANEL.HEIGHT.NORMAL * 1; + + thisObject.container.frame.position.x = viewPort.visibleArea.topRight.x - thisObject.container.frame.width * 2; + thisObject.container.frame.position.y = viewPort.visibleArea.topRight.y; + + } + + function getContainer(point) { + + var container; + + /* First we check if this point is inside this space. */ + + if (this.container.frame.isThisPointHere(point, true) === true) { + + return this.container; + + } else { + + /* This point does not belong to this space. */ + + return undefined; + } + + } + + + function onEventRaised(lastCurrentRecord) { + + currentRecord = lastCurrentRecord; + + } + + + function draw() { + + this.container.frame.draw(false, false, true); + + plotCurrentRecordInfo(); + + } + + + function plotCurrentRecordInfo() { + + if (currentRecord === undefined) { return; } + if (currentRecord.conditionsNames === undefined) { return; } + + const frameBodyHeight = thisObject.container.frame.getBodyHeight(); + const frameTitleHeight = thisObject.container.frame.height - frameBodyHeight; + + const X_AXIS = thisObject.container.frame.width / 2; + const Y_AXIS = frameTitleHeight + frameBodyHeight / 2; + + let y = 0; + let increment = 0.06; + + browserCanvasContext.beginPath(); + + for (let i = 2; i < currentRecord.conditionsNames.length; i++) { // Jump the first 2 items since they are the .begin and the .end of the record. + y = y + increment; + let opacity; + if (currentRecord.conditionsValues[i] === 1) { + opacity = '1.00' + } else { + opacity = '0.50'; + } + printLabel(currentRecord.conditionsNames[i], X_AXIS, frameTitleHeight + frameBodyHeight * y, opacity); + } + + function printLabel(labelToPrint, x, y, opacity) { + + let labelPoint; + let fontSize = 10; + + browserCanvasContext.font = fontSize + 'px ' + UI_FONT.SECONDARY; + + let label = '' + labelToPrint; + if (isNaN(label) === false) { + label = Number(label).toLocaleString(); + } + let xOffset = label.length / 2 * fontSize * FONT_ASPECT_RATIO; + + labelPoint = { + x: x - xOffset, + y: y + }; + + labelPoint = thisObject.container.frame.frameThisPoint(labelPoint); + + browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.DARK + ', ' + opacity + ')'; + browserCanvasContext.fillText(label, labelPoint.x, labelPoint.y); + + } + + browserCanvasContext.closePath(); + browserCanvasContext.fill(); + + } + + +} + + + diff --git a/Project.njsproj b/Project.njsproj index 2e95d5370..22f4dcca1 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -17,6 +17,12 @@ + + Code + + + Code + diff --git a/TradingSimulation.js b/TradingSimulation.js index f7b465f0c..c9bd8e390 100644 --- a/TradingSimulation.js +++ b/TradingSimulation.js @@ -426,8 +426,7 @@ strategyPhase: undefined, buyOrder: undefined, stopLossPhase: undefined, - buyOrderPhase: undefined, - conditions: undefined + buyOrderPhase: undefined }; record.begin = marketFile[i][0]; @@ -455,11 +454,6 @@ record.buyOrder = marketFile[i][22]; record.stopLossPhase = marketFile[i][23]; record.buyOrderPhase = marketFile[i][24]; - record.conditions = marketFile[i][25]; - - if (i === 0) { // The first record contains headers needed to be printed. - records.push(record); - } if (record.begin >= leftDate.valueOf() && record.end <= rightDate.valueOf()) { @@ -1033,8 +1027,6 @@ if (dateValue >= record.begin && dateValue <= record.end) { let currentRecord = { - conditionsNames: records[0].conditions, - conditionsValues: record.conditions, innerRecord: record }; thisObject.container.eventHandler.raiseEvent("Current Record Changed", currentRecord); diff --git a/TradingSimulationPanel.js b/TradingSimulationPanel.js index bbc814680..d9884e73a 100644 --- a/TradingSimulationPanel.js +++ b/TradingSimulationPanel.js @@ -77,93 +77,10 @@ function newAAMastersPlottersTradingSimulationTradingSimulationTradingSimulation const X_AXIS = thisObject.container.frame.width / 2; const Y_AXIS = frameTitleHeight + frameBodyHeight / 2; - var recordPoint1 = { - x: X_AXIS - currentRecord.bodyWidth / 2, - y: Y_AXIS - currentRecord.leftBodyHeight / 2 - currentRecord.bottomDelta / 4 - }; - - var recordPoint2 = { - x: X_AXIS - currentRecord.bodyWidth / 2, - y: Y_AXIS + currentRecord.leftBodyHeight / 2 - currentRecord.topDelta / 4 - }; - - var recordPoint3 = { - x: X_AXIS + currentRecord.bodyWidth / 2, - y: Y_AXIS + currentRecord.rightBodyHeight / 2 + currentRecord.topDelta / 4 - }; - - var recordPoint4 = { - x: X_AXIS + currentRecord.bodyWidth / 2, - y: Y_AXIS - currentRecord.rightBodyHeight / 2 + currentRecord.bottomDelta / 4 - }; - - - - /* Extra bounderies due to constrained space */ - - const upperLimit = frameTitleHeight + frameBodyHeight * 0.15; - const downLimit = frameTitleHeight + frameBodyHeight * 0.85; - - if (recordPoint1.y > downLimit) { recordPoint1.y = downLimit; } - if (recordPoint4.y > downLimit) { recordPoint4.y = downLimit; } - - if (recordPoint2.y < upperLimit) { recordPoint2.y = upperLimit; } - if (recordPoint3.y < upperLimit) { recordPoint3.y = upperLimit; } - - recordPoint1 = thisObject.container.frame.frameThisPoint(recordPoint1); - recordPoint2 = thisObject.container.frame.frameThisPoint(recordPoint2); - recordPoint3 = thisObject.container.frame.frameThisPoint(recordPoint3); - recordPoint4 = thisObject.container.frame.frameThisPoint(recordPoint4); - - browserCanvasContext.beginPath(); - - browserCanvasContext.moveTo(recordPoint1.x, recordPoint1.y); - browserCanvasContext.lineTo(recordPoint2.x, recordPoint2.y); - browserCanvasContext.lineTo(recordPoint3.x, recordPoint3.y); - browserCanvasContext.lineTo(recordPoint4.x, recordPoint4.y); - - browserCanvasContext.closePath(); - - const OPACITY = '0.1'; - - browserCanvasContext.fillStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', ' + OPACITY + ')'; - - browserCanvasContext.fill(); - - browserCanvasContext.beginPath(); - - browserCanvasContext.moveTo(recordPoint1.x, recordPoint1.y); - browserCanvasContext.lineTo(recordPoint4.x, recordPoint4.y); - browserCanvasContext.moveTo(recordPoint2.x, recordPoint2.y); - browserCanvasContext.lineTo(recordPoint3.x, recordPoint3.y); - - browserCanvasContext.closePath(); - - browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.PATINATED_TURQUOISE + ', 1)'; - - browserCanvasContext.lineWidth = 0.2; - browserCanvasContext.stroke(); - - browserCanvasContext.beginPath(); - - browserCanvasContext.moveTo(recordPoint1.x, recordPoint1.y + (recordPoint2.y - recordPoint1.y) / 2); - browserCanvasContext.lineTo(recordPoint4.x, recordPoint4.y - (recordPoint4.y - recordPoint3.y) / 2); - - - browserCanvasContext.closePath(); - - browserCanvasContext.strokeStyle = 'rgba(' + UI_COLOR.RUSTED_RED + ', 1)'; - - browserCanvasContext.lineWidth = 0.2; - browserCanvasContext.stroke(); - - - browserCanvasContext.beginPath(); /* put the labels with the records values */ - - + browserCanvasContext.beginPath(); let y = 0; let increment = 0.025; @@ -247,21 +164,7 @@ function newAAMastersPlottersTradingSimulationTradingSimulationTradingSimulation printLabel('Anualized Rate of Return', X_AXIS, frameTitleHeight + frameBodyHeight * y, '1'); y = y + increment; printLabel((currentRecord.innerRecord.anualizedRateOfReturn * 100).toFixed(2) + ' %', X_AXIS, frameTitleHeight + frameBodyHeight * y, '0.50'); - - y = y + increment; - y = y + increment; - - for (let i = 0; i < currentRecord.conditionsNames.length; i++) { - y = y + increment; - let opacity; - if (currentRecord.conditionsValues[i] === 1) { - opacity = '1.00' - } else { - opacity = '0.50'; - } - printLabel(currentRecord.conditionsNames[i], X_AXIS, frameTitleHeight + frameBodyHeight * y, opacity); - } - + function printLabel(labelToPrint, x, y, opacity) { let labelPoint; diff --git a/this.plotter.config.json b/this.plotter.config.json index 488a19e4e..1976dcda4 100644 --- a/this.plotter.config.json +++ b/this.plotter.config.json @@ -15,6 +15,19 @@ "event": "Current Record Changed" } ] + }, + { + "codeName": "Conditions", + "moduleName": "Conditions", + "description": "Plots Simulation Conditions.", + "profilePicture": "Conditions.png", + "panels": [ + { + "codeName": "ConditionsPanel", + "moduleName": "ConditionsPanel", + "event": "Current Condition Record Changed" + } + ] } ] } \ No newline at end of file