Files
Superalgos/TimelineChart.js
T
2018-02-14 13:00:19 +01:00

614 lines
24 KiB
JavaScript

function newTimelineChart() {
let layers = [];
let plotArea = newPlotArea();
let timePeriod = INITIAL_TIME_PERIOD;
var datetime;
var timelineChart = {
layers: layers,
setDatetime: setDatetime,
container: undefined,
draw: draw,
getContainer: getContainer,
initialize: initialize
};
var container = newContainer();
container.initialize();
timelineChart.container = container;
container.displacement.containerName = "Time Period Chart";
container.zoom.containerName = "Time Period Chart";
container.frame.containerName = "Time Period Chart";
let marketId;
let exchangeId;
let marketIndex;
let dailyFilesCursor;
let level;
let chartGrid;
let targetLabelFontSize = 150;
let fontSizeIncrement = 12.5;
let currentFontSize = 150;
let initializationReady = false;
let currentCandlePanel;
let currentVolumePanel;
let chartLayersPanel;
let botsLayersPanel;
let orderBookPanel;
return timelineChart;
function initialize(exchange, market, currentCandlePanelToUse, currentVolumePanelToUse, chartLayersPanelToUse, botsLayersPanelToUse, orderBookPanelToUse, callBackFunction) {
currentCandlePanel = currentCandlePanelToUse;
currentVolumePanel = currentVolumePanelToUse;
chartLayersPanel = chartLayersPanelToUse;
botsLayersPanel = botsLayersPanelToUse;
orderBookPanel = orderBookPanelToUse;
marketId = market;
exchangeId = exchange;
chartGrid = newChartGrid();
marketIndex = newMarketIndex();
marketIndex.initialize(exchangeId, marketId, continueInitialization);
function continueInitialization() {
recalculateScale();
dailyFilesCursor = newDailyFilesCursor();
dailyFilesCursor.initialize(exchangeId, marketId, finalSteps);
function finalSteps() {
/* Event Subscriptions - we need this events to be fired first here and then in layers. */
viewPort.eventHandler.listenToEvent("Offset Changed", onOffsetChanged);
viewPort.eventHandler.listenToEvent("Zoom Changed", onZoomChanged);
canvas.eventHandler.listenToEvent("Drag Finished", onDragFinished);
initializeLayers();
callBackFunction();
initializationReady = true;
marketInitializationCounter++;
}
}
}
function initializeLayers() {
/* All Time Layer */
var allTimeChartLayer = newAllTimeChartLayer();
allTimeChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
allTimeChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
allTimeChartLayer.container.frame.parentFrame = timelineChart.container.frame;
allTimeChartLayer.container.parentContainer = timelineChart.container;
allTimeChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
allTimeChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
allTimeChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - allTimeChartLayer.container.frame.width / 2;
allTimeChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - allTimeChartLayer.container.frame.height / 2;
allTimeChartLayer.initialize(exchangeId, marketId, marketIndex, chartLayersPanel);
/* Orderbook Resistances Layer */
var orderBooksChartLayer = newOrderBooksChartLayer();
orderBooksChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
orderBooksChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
orderBooksChartLayer.container.frame.parentFrame = timelineChart.container.frame;
orderBooksChartLayer.container.parentContainer = timelineChart.container;
orderBooksChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
orderBooksChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
orderBooksChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - orderBooksChartLayer.container.frame.width / 2;
orderBooksChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - orderBooksChartLayer.container.frame.height / 2;
orderBooksChartLayer.initialize(exchangeId, marketId, marketIndex, chartLayersPanel);
/* Candle Technical Analisys Layer */
var candleTechnicalAnalisysChartLayer = newCandleTechnicalAnalisysChartLayer();
candleTechnicalAnalisysChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
candleTechnicalAnalisysChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
candleTechnicalAnalisysChartLayer.container.frame.parentFrame = timelineChart.container.frame;
candleTechnicalAnalisysChartLayer.container.parentContainer = timelineChart.container;
candleTechnicalAnalisysChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
candleTechnicalAnalisysChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
candleTechnicalAnalisysChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - candleTechnicalAnalisysChartLayer.container.frame.width / 2;
candleTechnicalAnalisysChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - candleTechnicalAnalisysChartLayer.container.frame.height / 2;
candleTechnicalAnalisysChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel);
/* Volume Technical Analisys Layer */
var volumeTechnicalAnalisysChartLayer = newVolumeTechnicalAnalisysChartLayer();
volumeTechnicalAnalisysChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
volumeTechnicalAnalisysChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
volumeTechnicalAnalisysChartLayer.container.frame.parentFrame = timelineChart.container.frame;
volumeTechnicalAnalisysChartLayer.container.parentContainer = timelineChart.container;
volumeTechnicalAnalisysChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
volumeTechnicalAnalisysChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
volumeTechnicalAnalisysChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - volumeTechnicalAnalisysChartLayer.container.frame.width / 2;
volumeTechnicalAnalisysChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - volumeTechnicalAnalisysChartLayer.container.frame.height / 2;
volumeTechnicalAnalisysChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel);
/* Sopport Resistance Layer */
var supportResistanceChartLayer = newSupportResistanceChartLayer();
supportResistanceChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
supportResistanceChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
supportResistanceChartLayer.container.frame.parentFrame = timelineChart.container.frame;
supportResistanceChartLayer.container.parentContainer = timelineChart.container;
supportResistanceChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
supportResistanceChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
supportResistanceChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - supportResistanceChartLayer.container.frame.width / 2;
supportResistanceChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - supportResistanceChartLayer.container.frame.height / 2;
supportResistanceChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel);
/* High Low Layer */
var highLowChartLayer = newHighLowChartLayer();
highLowChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
highLowChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
highLowChartLayer.container.frame.parentFrame = timelineChart.container.frame;
highLowChartLayer.container.parentContainer = timelineChart.container;
highLowChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
highLowChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
highLowChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - highLowChartLayer.container.frame.width / 2;
highLowChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - highLowChartLayer.container.frame.height / 2;
highLowChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel);
/* Candles Layer */
var candleStickChartLayer = newCandleStickChartLayer();
candleStickChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
candleStickChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
candleStickChartLayer.container.frame.parentFrame = timelineChart.container.frame;
candleStickChartLayer.container.parentContainer = timelineChart.container;
candleStickChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
candleStickChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
candleStickChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - candleStickChartLayer.container.frame.width / 2;
candleStickChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - candleStickChartLayer.container.frame.height / 2;
candleStickChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel, chartLayersPanel);
/* Volume Layer */
var volumeChartLayer = newVolumeChartLayer();
volumeChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
volumeChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
volumeChartLayer.container.frame.parentFrame = timelineChart.container.frame;
volumeChartLayer.container.parentContainer = timelineChart.container;
volumeChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
volumeChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
volumeChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - volumeChartLayer.container.frame.width / 2;
volumeChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - volumeChartLayer.container.frame.height / 2;
volumeChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel, chartLayersPanel);
/* Accumulated Volume Volume Layer */
var accumulatedVolumeChartLayer = newAccumulatedVolumeChartLayer();
accumulatedVolumeChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
accumulatedVolumeChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
accumulatedVolumeChartLayer.container.frame.parentFrame = timelineChart.container.frame;
accumulatedVolumeChartLayer.container.parentContainer = timelineChart.container;
accumulatedVolumeChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
accumulatedVolumeChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
accumulatedVolumeChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - accumulatedVolumeChartLayer.container.frame.width / 2;
accumulatedVolumeChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - accumulatedVolumeChartLayer.container.frame.height / 2;
accumulatedVolumeChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel);
/* Forecast Layer */
var forecastChartLayer = newForecastChartLayer();
forecastChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
forecastChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
forecastChartLayer.container.frame.parentFrame = timelineChart.container.frame;
forecastChartLayer.container.parentContainer = timelineChart.container;
forecastChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
forecastChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
forecastChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - forecastChartLayer.container.frame.width / 2;
forecastChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - forecastChartLayer.container.frame.height / 2;
forecastChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel);
candleStickChartLayer.container.eventHandler.listenToEvent("Current Candle Changed", forecastChartLayer.setCurrentCandle);
forecastChartLayer.setCurrentCandle(candleStickChartLayer.currentCandle);
/* Linear Regression Curve Layer */
var linearRegressionCurveChartLayer = newLinearRegressionCurve();
linearRegressionCurveChartLayer.container.displacement.parentDisplacement = timelineChart.container.displacement;
linearRegressionCurveChartLayer.container.zoom.parentZoom = timelineChart.container.zoom;
linearRegressionCurveChartLayer.container.frame.parentFrame = timelineChart.container.frame;
linearRegressionCurveChartLayer.container.parentContainer = timelineChart.container;
linearRegressionCurveChartLayer.container.frame.width = timelineChart.container.frame.width * 1;
linearRegressionCurveChartLayer.container.frame.height = timelineChart.container.frame.height * 1;
linearRegressionCurveChartLayer.container.frame.position.x = timelineChart.container.frame.width / 2 - candleTechnicalAnalisysChartLayer.container.frame.width / 2;
linearRegressionCurveChartLayer.container.frame.position.y = timelineChart.container.frame.height / 2 - candleTechnicalAnalisysChartLayer.container.frame.height / 2;
linearRegressionCurveChartLayer.initialize(exchangeId, marketId, marketIndex, dailyFilesCursor, chartLayersPanel);
/* Add all layers to the internal array */
timelineChart.layers.push(allTimeChartLayer);
timelineChart.layers.push(orderBooksChartLayer);
timelineChart.layers.push(forecastChartLayer);
//timelineChart.layers.push(supportResistanceChartLayer);
timelineChart.layers.push(highLowChartLayer);
timelineChart.layers.push(candleTechnicalAnalisysChartLayer);
timelineChart.layers.push(volumeTechnicalAnalisysChartLayer);
timelineChart.layers.push(candleStickChartLayer);
timelineChart.layers.push(volumeChartLayer);
timelineChart.layers.push(accumulatedVolumeChartLayer);
timelineChart.layers.push(linearRegressionCurveChartLayer);
/* Wiring some charts with others using events */
candleStickChartLayer.container.eventHandler.listenToEvent("Candles Changed", candleTechnicalAnalisysChartLayer.onCandlesChanged);
candleStickChartLayer.container.eventHandler.listenToEvent("Candles Changed", highLowChartLayer.onCandlesChanged);
candleStickChartLayer.container.eventHandler.listenToEvent("Candles Changed", supportResistanceChartLayer.onCandlesChanged);
candleStickChartLayer.container.eventHandler.listenToEvent("Current Candle Info Changed", currentCandlePanel.onCurrentCandleChanged);
candleStickChartLayer.container.eventHandler.listenToEvent("Candles Changed", linearRegressionCurveChartLayer.onCandlesChanged);
volumeChartLayer.container.eventHandler.listenToEvent("Current Volume Info Changed", currentVolumePanel.onCurrentVolumeChanged);
volumeChartLayer.container.eventHandler.listenToEvent("Volumes Changed", volumeTechnicalAnalisysChartLayer.onVolumesChanged);
orderBooksChartLayer.container.eventHandler.listenToEvent("Current Order Book Changed", orderBookPanel.onCurrentOrderBookChanged);
/* Connecting all layers to the panel that provides a user interface to turn them on - visible - off */
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", accumulatedVolumeChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", candleStickChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", candleTechnicalAnalisysChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", highLowChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", volumeChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", volumeTechnicalAnalisysChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", allTimeChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", forecastChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", orderBooksChartLayer.onLayerStatusChanged);
chartLayersPanel.container.eventHandler.listenToEvent("Layer Status Changed", linearRegressionCurveChartLayer.onLayerStatusChanged);
}
function onZoomChanged(event) {
if (initializationReady === true) {
level = event.newLevel; // for debugging purposes only
let currentTimePeriod = timePeriod;
timePeriod = recalculatePeriod(event.newLevel);
if (timePeriod !== currentTimePeriod) {
for (var i = 0; i < timelineChart.layers.length; i++) {
let layer = timelineChart.layers[i];
layer.setTimePeriod(timePeriod);
}
}
recalculateCurrentDatetime();
if (timelineChart.container.frame.isInViewPort() && tooSmall() === false) {
dailyFilesCursor.setDatetime(datetime);
}
}
}
function onDragFinished() {
if (initializationReady === true) {
if (timelineChart.container.frame.isInViewPort() && tooSmall() === false) {
dailyFilesCursor.setDatetime(datetime);
}
}
}
function onOffsetChanged() {
if (initializationReady === true) {
if (timelineChart.container.frame.isInViewPort()) {
recalculateCurrentDatetime();
}
}
}
function recalculateCurrentDatetime() {
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, timelineChart.container);
center = plotArea.unInverseTransform(center, timelineChart.container.frame.height);
let newDate = new Date(0);
newDate.setUTCSeconds(center.x / 1000);
datetime = newDate;
for (var i = 0; i < timelineChart.layers.length; i++) {
let layer = timelineChart.layers[i];
layer.setDatetime(datetime);
}
timelineChart.container.eventHandler.raiseEvent("Datetime Changed", datetime);
}
function getContainer(point) {
var 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;
}
}
function setDatetime(newDatetime) {
if (timelineChart.container.frame.isInViewPort()) {
for (var i = 0; i < timelineChart.layers.length; i++) {
let layer = timelineChart.layers[i];
layer.setDatetime(newDatetime);
if (layer.positionAtDatetime !== undefined) {
layer.positionAtDatetime(newDatetime);
}
}
}
}
function draw() {
if (timelineChart.container.frame.isInViewPort()) {
this.container.frame.draw();
drawBackground();
chartGrid.draw(timelineChart.container, plotArea);
for (var i = 0; i < this.layers.length; i++) {
let layer = this.layers[i];
layer.draw();
}
}
}
function recalculateScale() {
var minValue = {
x: EARLIEST_DATE.valueOf(),
y: 0
};
var maxValue = {
x: MAX_PLOTABLE_DATE.valueOf(),
y: nextPorwerOf10(marketIndex.maxRate())
};
plotArea.initialize(
minValue,
maxValue,
timelineChart.container.frame.width,
timelineChart.container.frame.height
);
}
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() {
var market = markets.get(marketId);
var label = market.assetA + " " + market.assetB;
//label = '' + level; // Math.trunc(timePeriod / 1000 / 60);
if (tooTiny() === true ) {
return;
}
let topPoint = {
x: 0,
y: 0
};
let bottomPoint = {
x: 0,
y: timelineChart.container.frame.height
};
topPoint = transformThisPoint(topPoint, timelineChart.container);
bottomPoint = transformThisPoint(bottomPoint, timelineChart.container);
/* We want the label of the market to be always centered in the middle of the screen, unless the upper or lower border of the frame is visible on the screen */
let point;
if (targetLabelFontSize !== currentFontSize) {
if (targetLabelFontSize > currentFontSize) {
currentFontSize = currentFontSize + fontSizeIncrement;
} else {
currentFontSize = currentFontSize - fontSizeIncrement;
}
}
if (topPoint.y > viewPort.visibleArea.topLeft.y || bottomPoint.y < viewPort.visibleArea.bottomRight.y) {
targetLabelFontSize = 150 / 2;
point = {
x: 0,
y: timelineChart.container.frame.height / 2
};
point = transformThisPoint(point, timelineChart.container);
point = {
x: (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.bottomLeft.x) / 2 - label.length / 2 * currentFontSize * 0.60,
y: point.y + currentFontSize * 0.60 / 2
};
} else {
targetLabelFontSize = 150;
point = {
x: (viewPort.visibleArea.bottomRight.x - viewPort.visibleArea.bottomLeft.x) / 2 - label.length / 2 * currentFontSize * 0.60,
y: (viewPort.visibleArea.bottomLeft.y - viewPort.visibleArea.topLeft.y) / 2 + currentFontSize * 0.60 / 2
};
}
browserCanvasContext.font = currentFontSize + 'px Courier New';
browserCanvasContext.fillStyle = 'rgba(75, 86, 235, 0.07)';
browserCanvasContext.fillText(label, point.x, point.y);
}
}