Files
Superalgos/TimeMachine.js
T

264 lines
9.0 KiB
JavaScript

/*
Markets are a function of time. When watching them, end users must be positioned at one particular point in time. The system currently allows users
to position themselves at any time they like.
In the future, it will be usefull to explore markets and compare them at different times simultaneously. Anticipating that future this module exists.
All the charts that depand on a datetime are children of this object Time Machine. In the future we will allow users to have more than one Time Machine,
each one with it own charts, and each one positioned at an especific point in titme.
*/
function newTimeMachine () {
const MODULE_NAME = 'Time Machine'
const INFO_LOG = false
const logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let thisObject = {
container: undefined,
drawBackground: drawBackground,
draw: draw,
charts: [],
getContainer: getContainer, // returns the inner most container that holds the point received by parameter.
initialize: initialize,
finalize: finalize
}
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.isDraggeable = false
thisObject.container.detectMouseOver = true
thisObject.container.frame.width = TIME_MACHINE_WIDTH
thisObject.container.frame.height = TIME_MACHINE_HEIGHT
thisObject.container.frame.position.x = browserCanvas.width / 2 - TIME_MACHINE_WIDTH / 2
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.
const SEPARATION_BETWEEN_TIMELINE_CHARTS = 1.5
let timeScale
let rigthScale
let timeLineCoordinateSystem = newTimeLineCoordinateSystem()
return thisObject
function finalize () {
try {
if (INFO_LOG === true) { logger.write('[INFO] finalize -> Entering function.') }
for (let i = 0; i < thisObject.charts.length; i++) {
let chart = thisObject.charts[i]
chart.finalize()
}
} catch (err) {
if (ERROR_LOG === true) { logger.write('[ERROR] finalize -> err = ' + err.stack) }
}
}
function initialize (callBackFunction) {
if (INFO_LOG === true) { logger.write('[INFO] initialize -> Entering function.') }
/* Each Time Machine has a Control Panel. */
let panelOwner = 'Global'
controlPanelHandle = canvas.panelsSpace.createNewPanel('Time Control Panel', undefined, panelOwner)
let controlPanel = canvas.panelsSpace.getPanel(controlPanelHandle, panelOwner)
recalculateScale()
thisObject.container.eventHandler.listenToEvent('Dimmensions Changed', function (event) {
recalculateScale()
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. */
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.frame.height = thisObject.container.frame.height
timelineChart.container.frame.position.x = thisObject.container.frame.width / 2 - timelineChart.container.frame.width / 2
timelineChart.container.frame.position.y = timelineChart.container.frame.height * SEPARATION_BETWEEN_TIMELINE_CHARTS * position
position++
timelineChart.initialize(DEFAULT_EXCHANGE, DEFAULT_MARKET, timeLineCoordinateSystem, onDefaultInitialized)
function onDefaultInitialized (err) {
if (err.result !== GLOBAL.DEFAULT_OK_RESPONSE.result) {
callBackFunction(err)
return
}
thisObject.charts.push(timelineChart)
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. */
timeScale = newTimeScale()
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)
})
timeScale.initialize()
rigthScale = newRigthScale()
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)
})
rigthScale.initialize()
initializeTheRest()
}
function initializeTheRest () {
if (INFO_LOG === true) { logger.write('[INFO] initialize -> initializeTheRest -> Entering function.') }
let leftToInitialize = SUPPORTED_EXCHANGES.length * SUPPORTED_MARKETS.length - 1 // The default exchange and market was already initialized.
let alreadyInitialized = 0
if (alreadyInitialized === leftToInitialize) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE)
return
}
for (let i = 0; i < SUPPORTED_EXCHANGES.length; i++) {
for (let j = 0; j < SUPPORTED_MARKETS.length; j++) {
let exchange = SUPPORTED_EXCHANGES[i]
let market = SUPPORTED_MARKETS[j]
if (
exchange === DEFAULT_EXCHANGE &&
market.assetA === DEFAULT_MARKET.assetA &&
market.assetB === DEFAULT_MARKET.assetB
) { continue }
initializeTimelineChart(exchange, market)
}
}
function initializeTimelineChart (exchange, market) {
if (INFO_LOG === true) { logger.write('[INFO] initialize -> initializeTheRest -> initializeTimelineChart -> Entering function.') }
let timelineChart = newTimelineChart()
timelineChart.container.connectToParent(thisObject.container, 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
timelineChart.container.frame.position.y = timelineChart.container.frame.height * SEPARATION_BETWEEN_TIMELINE_CHARTS * position
position++
timelineChart.initialize(exchange, market, timeLineCoordinateSystem, finalSteps)
function finalSteps () {
if (INFO_LOG === true) { logger.write('[INFO] initialize -> initializeTheRest -> initializeTimelineChart -> finalSteps -> Entering function.') }
thisObject.charts.push(timelineChart)
controlPanel.container.eventHandler.listenToEvent('Datetime Changed', timelineChart.setDatetime, undefined)
timelineChart.container.eventHandler.listenToEvent('Datetime Changed', controlPanel.setDatetime)
alreadyInitialized++
if (alreadyInitialized === leftToInitialize) {
callBackFunction(GLOBAL.DEFAULT_OK_RESPONSE)
}
}
}
}
}
function drawBackground () {
for (let i = 0; i < this.charts.length; i++) {
let chart = this.charts[i]
chart.drawBackground()
}
}
function draw () {
// this.container.frame.draw(false, false)
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
if (timeScale !== undefined) {
container = timeScale.getContainer(point)
if (container !== undefined) {
if (container.isForThisPurpose(purpose)) {
return container
}
}
}
if (rigthScale !== undefined) {
container = rigthScale.getContainer(point)
if (container !== undefined) {
if (container.isForThisPurpose(purpose)) {
return container
}
}
}
for (let i = 0; i < this.charts.length; i++) {
container = this.charts[i].getContainer(point)
if (container !== undefined) {
if (container.isForThisPurpose(purpose)) {
return container
}
}
}
return this.container
}
function recalculateScale () {
if (INFO_LOG === true) { logger.write('[INFO] recalculateScale -> Entering function.') }
let minValue = {
x: MIN_PLOTABLE_DATE.valueOf(),
y: 0
}
let maxValue = {
x: MAX_PLOTABLE_DATE.valueOf(),
y: nextPorwerOf10(USDT_BTC_HTH) / 4
}
timeLineCoordinateSystem.initialize(
minValue,
maxValue,
thisObject.container.frame.width,
thisObject.container.frame.height
)
}
}