Files
Superalgos/ChartsSpace/TimelineChart.js
T

459 lines
15 KiB
JavaScript

function newTimelineChart () {
const MODULE_NAME = 'Timeline Chart'
const INFO_LOG = false
const INTENSIVE_LOG = false
const ERROR_LOG = true
let logger = newWebDebugLog()
logger.fileName = MODULE_NAME
let timeFrame = INITIAL_TIME_PERIOD
let datetime = NEW_SESSION_INITIAL_DATE
let thisObject = {
container: undefined,
fitFunction: undefined,
rateScale: undefined,
timeFrameScale: undefined,
payload: undefined,
layersManager: undefined,
plotterManager: undefined,
upstreamTimeFrame: undefined,
setTimeFrame: setTimeFrame,
physics: physics,
draw: draw,
drawBackground: drawBackground,
drawForeground: drawForeground,
getContainer: getContainer,
initialize: initialize,
finalize: finalize
}
let timeMachineCoordinateSystem
let timelineChartCoordinateSystem = newCoordinateSystem()
let layersPanel
let layersPanelHandle
let onViewportPositionChangedEventSuscriptionId
let onViewportZoomChangedEventSuscriptionId
let onMouseOverEventSuscriptionId
let onMouseNotOverEventSuscriptionId
let rateScaleValueEventSuscriptionId
let rateScaleUpstreamEventSuscriptionId
let rateScaleMouseOverEventSuscriptionId
let rateScaleOffsetEventSuscriptionId
let timeFrameScaleEventSuscriptionId
let timeFrameScaleMouseOverEventSuscriptionId
let drawScales = false
let mouse = {
position: {
x: 0,
y: 0
}
}
setupContainer()
return thisObject
function setupContainer () {
thisObject.container = newContainer()
thisObject.container.initialize(MODULE_NAME)
thisObject.container.detectMouseOver = true
}
function finalize () {
if (thisObject.layersManager !== undefined) {
finalizeLayersManager()
}
if (thisObject.rateScale !== undefined) {
finalizeRateScale()
}
if (thisObject.timeFrameScale !== undefined) {
finalizeTimeFrameScale()
}
canvas.chartSpace.viewport.eventHandler.stopListening(onViewportPositionChangedEventSuscriptionId)
canvas.chartSpace.viewport.eventHandler.stopListening(onViewportZoomChangedEventSuscriptionId)
thisObject.container.eventHandler.stopListening(onMouseOverEventSuscriptionId)
thisObject.container.eventHandler.stopListening(onMouseNotOverEventSuscriptionId)
thisObject.container.finalize()
thisObject.container = undefined
thisObject.payload = undefined
mouse = undefined
logger = undefined
}
function finalizeLayersManager () {
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.finalize()
}
thisObject.plotterManager = undefined
thisObject.layersManager = undefined
canvas.panelsSpace.destroyPanel(layersPanelHandle)
}
function finalizeTimeFrameScale () {
if (thisObject.timeFrameScale === undefined) { return }
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleEventSuscriptionId)
thisObject.timeFrameScale.container.eventHandler.stopListening(timeFrameScaleMouseOverEventSuscriptionId)
thisObject.timeFrameScale.finalize()
thisObject.timeFrameScale = undefined
if (thisObject.upstreamTimeFrame !== undefined) {
timeFrame = thisObject.upstreamTimeFrame
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setTimeFrame(timeFrame)
}
}
}
function finalizeRateScale () {
if (thisObject.rateScale === undefined) { return }
thisObject.rateScale.container.eventHandler.stopListening(rateScaleOffsetEventSuscriptionId)
thisObject.rateScale.container.eventHandler.stopListening(rateScaleValueEventSuscriptionId)
thisObject.rateScale.container.eventHandler.stopListening(rateScaleMouseOverEventSuscriptionId)
thisObject.container.parentContainer.eventHandler.stopListening(rateScaleUpstreamEventSuscriptionId)
thisObject.rateScale.finalize()
thisObject.rateScale = undefined
/* Resets the local container with the dimessions of its parent, the Time Machine */
thisObject.container.frame.position.x = 0
thisObject.container.frame.position.y = 0
thisObject.container.frame.height = TIME_MACHINE_HEIGHT
thisObject.container.frame.width = TIME_MACHINE_WIDTH
}
function initialize (pTimeMachineCoordinateSystem) {
/* We load the logow we will need for the background. */
timeMachineCoordinateSystem = pTimeMachineCoordinateSystem
timeFrame = INITIAL_TIME_PERIOD
datetime = NEW_SESSION_INITIAL_DATE
/* Event Subscriptions - we need this events to be fired first here and then in active Plotters. */
onViewportPositionChangedEventSuscriptionId = canvas.chartSpace.viewport.eventHandler.listenToEvent('Position Changed', onViewportPositionChanged)
onViewportZoomChangedEventSuscriptionId = canvas.chartSpace.viewport.eventHandler.listenToEvent('Zoom Changed', onViewportZoomChanged)
onMouseOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseOver', onMouseOver)
onMouseNotOverEventSuscriptionId = thisObject.container.eventHandler.listenToEvent('onMouseNotOver', onMouseNotOver)
}
function initializeLayersManager () {
let owner = thisObject.payload.node.payload.parentNode.id // The real owner is the Time Machine
layersPanelHandle = canvas.panelsSpace.createNewPanel('Layers Panel', undefined, owner)
thisObject.layersManager = canvas.panelsSpace.getPanel(layersPanelHandle)
thisObject.layersManager.payload = thisObject.payload.node.layersManager.payload
thisObject.layersManager.initialize()
/* Initialize the Plotter Manager */
thisObject.plotterManager = newPlottersManager()
thisObject.plotterManager.container.connectToParent(thisObject.container, true, true, false, true, true, true, false, false, true)
thisObject.plotterManager.container.frame.position.x = 0
thisObject.plotterManager.container.frame.position.y = 0
thisObject.plotterManager.fitFunction = thisObject.fitFunction
thisObject.plotterManager.payload = thisObject.payload
thisObject.plotterManager.initialize(thisObject.layersManager, DEFAULT_EXCHANGE, DEFAULT_MARKET)
thisObject.plotterManager.setTimeFrame(timeFrame)
}
function initializeRateScale () {
thisObject.rateScale = newRateScale()
thisObject.rateScale.fitFunction = thisObject.fitFunction
thisObject.rateScale.payload = thisObject.payload.node.rateScale.payload
rateScaleOffsetEventSuscriptionId = thisObject.rateScale.container.eventHandler.listenToEvent('Rate Scale Offset Changed', rateScaleOffsetChanged)
rateScaleValueEventSuscriptionId = thisObject.rateScale.container.eventHandler.listenToEvent('Rate Scale Value Changed', rateScaleValueChanged)
rateScaleMouseOverEventSuscriptionId = thisObject.rateScale.container.eventHandler.listenToEvent('onMouseOverScale', rateScaleMouseOver)
rateScaleUpstreamEventSuscriptionId = thisObject.container.parentContainer.eventHandler.listenToEvent('Upstream Rate Scale Value Changed', rateScaleUpstreamChanged)
thisObject.rateScale.initialize(timelineChartCoordinateSystem, thisObject.container.parentContainer)
function rateScaleUpstreamChanged (event) {
thisObject.rateScale.setScale(event.scale)
}
function rateScaleOffsetChanged (event) {
thisObject.container.frame.offset.y = event.offset
}
function rateScaleValueChanged (event) {
thisObject.container.frame.height = TIME_MACHINE_HEIGHT * event.scale
recalculateCoordinateSystem()
thisObject.container.eventHandler.raiseEvent('Dimmensions Changed', event)
}
function rateScaleMouseOver (event) {
thisObject.container.eventHandler.raiseEvent('onChildrenMouseOver', event)
}
}
function initializeTimeFrameScale () {
thisObject.timeFrameScale = newTimeFrameScale()
thisObject.timeFrameScale.fitFunction = thisObject.fitFunction
thisObject.timeFrameScale.payload = thisObject.payload.node.timeFrameScale.payload
timeFrameScaleEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('Time Frame Value Changed', timeFrameScaleValueChanged)
timeFrameScaleMouseOverEventSuscriptionId = thisObject.timeFrameScale.container.eventHandler.listenToEvent('onMouseOverScale', timeFrameScaleMouseOver)
thisObject.timeFrameScale.initialize(timeMachineCoordinateSystem, thisObject.container.parentContainer)
function timeFrameScaleValueChanged (event) {
let currentTimeFrame = timeFrame
timeFrame = event.timeFrame
if (timeFrame !== currentTimeFrame) {
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setTimeFrame(timeFrame)
}
}
}
function timeFrameScaleMouseOver (event) {
thisObject.container.eventHandler.raiseEvent('onChildrenMouseOver', event)
saveUserPosition(thisObject.container, timeMachineCoordinateSystem, event)
}
}
function setTimeFrame (pTimeFrame) {
timeFrame = pTimeFrame
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setTimeFrame(timeFrame)
}
}
function onMouseOver (event) {
/* This event gets to the timelinechart container because it inherits it from the time machine container, which is the one raising Mouse Over and Mouse not Over Events to its children. */
drawScales = true
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.onMouseOverSomeTimeMachineContainer(event)
}
if (thisObject.timeFrameScale !== undefined) {
thisObject.timeFrameScale.onMouseOverSomeTimeMachineContainer(event)
}
mouse.position.x = event.x
mouse.position.y = event.y
saveUserPosition(thisObject.container, timeMachineCoordinateSystem, event)
}
function onMouseNotOver (event) {
/* This event is inherited from the Time Machine */
drawScales = false
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.visible = false
}
if (thisObject.timeFrameScale !== undefined) {
thisObject.timeFrameScale.visible = false
}
}
function onViewportZoomChanged (event) {
if (thisObject.container.frame.isInViewPort()) {
recalculateCurrentDatetime()
}
}
function onViewportPositionChanged () {
if (thisObject.container.frame.isInViewPort()) {
recalculateCurrentDatetime()
}
}
function recalculateCurrentDatetime () {
/*
The view port was moved or the view port zoom level was changed and the center of the screen points to a different datetime that we
must calculate.
*/
let center = {
x: (canvas.chartSpace.viewport.visibleArea.bottomRight.x - canvas.chartSpace.viewport.visibleArea.bottomLeft.x) / 2,
y: (canvas.chartSpace.viewport.visibleArea.bottomRight.y - canvas.chartSpace.viewport.visibleArea.topRight.y) / 2
}
center = unTransformThisPoint(center, thisObject.container)
if (thisObject.rateScale === undefined) {
center = timeMachineCoordinateSystem.unInverseTransform(center, thisObject.container.frame.height)
} else {
center = timelineChartCoordinateSystem.unInverseTransform(center, thisObject.container.frame.height)
}
let newDate = new Date(center.x)
datetime = newDate
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.setDatetime(datetime)
}
}
function getContainer (point, purpose) {
let container
if (thisObject.rateScale !== undefined) {
container = thisObject.rateScale.getContainer(point)
if (container !== undefined) {
if (container.isForThisPurpose(purpose)) {
return container
}
}
}
if (thisObject.timeFrameScale !== undefined) {
container = thisObject.timeFrameScale.getContainer(point)
if (container !== undefined) {
if (container.isForThisPurpose(purpose)) {
return container
}
}
}
return container
}
function physics () {
thisObjectPhysics()
childrenPhysics()
syncWithDesignerScales()
syncWithDesignerLayersManager()
}
function thisObjectPhysics () {
}
function syncWithDesignerLayersManager () {
if (thisObject.payload.node === undefined) {
finalizeLayersManager()
return
}
if (thisObject.payload.node.layersManager === undefined && thisObject.layersManager !== undefined) {
finalizeLayersManager()
}
if (thisObject.payload.node.layersManager !== undefined && thisObject.layersManager === undefined) {
initializeLayersManager()
}
}
function syncWithDesignerScales () {
if (thisObject.payload.node === undefined) {
finalizeRateScale()
finalizeTimeFrameScale()
return
}
if (thisObject.payload.node.rateScale === undefined && thisObject.rateScale !== undefined) {
finalizeRateScale()
}
if (thisObject.payload.node.rateScale !== undefined && thisObject.rateScale === undefined) {
initializeRateScale()
}
if (thisObject.payload.node.timeFrameScale === undefined && thisObject.timeFrameScale !== undefined) {
finalizeTimeFrameScale()
}
if (thisObject.payload.node.timeFrameScale !== undefined && thisObject.timeFrameScale === undefined) {
initializeTimeFrameScale()
}
}
function childrenPhysics () {
if (thisObject.rateScale !== undefined) {
thisObject.rateScale.physics()
}
if (thisObject.timeFrameScale !== undefined) {
thisObject.timeFrameScale.physics()
}
}
function drawBackground () {
if (thisObject.container.frame.isInViewPort()) {
drawChartsBackground()
if (thisObject.plotterManager !== undefined) {
thisObject.plotterManager.draw()
}
}
}
function draw () {
if (thisObject.container.frame.isInViewPort()) {
if (drawScales === true) {
if (thisObject.timeFrameScale !== undefined) { thisObject.timeFrameScale.draw() }
if (thisObject.rateScale !== undefined) { thisObject.rateScale.draw() }
}
}
}
function drawForeground () {
if (thisObject.container.frame.isInViewPort()) {
if (drawScales === true) {
if (thisObject.timeFrameScale !== undefined) { thisObject.timeFrameScale.drawForeground() }
if (thisObject.rateScale !== undefined) { thisObject.rateScale.drawForeground() }
}
}
}
function drawChartsBackground () {
/* We will paint some transparent background here. */
let opacity = '0.1'
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 = thisObject.fitFunction(fromPoint)
toPoint = thisObject.fitFunction(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 recalculateCoordinateSystem () {
let minValue = {
x: MIN_PLOTABLE_DATE.valueOf(),
y: 0
}
let maxValue = {
x: MAX_PLOTABLE_DATE.valueOf(),
y: nextPorwerOf10(USDT_BTC_HTH) / 4
}
timelineChartCoordinateSystem.initialize(
minValue,
maxValue,
thisObject.container.frame.width,
thisObject.container.frame.height
)
}
}