unageanu/jiji2

View on GitHub
sites/src/js/viewmodel/chart/graphs.js

Summary

Maintainability
B
5 hrs
Test Coverage
import ContainerJS               from "container-js"
import Observable                from "../../utils/observable"
import Numbers                   from "../../utils/numbers"
import Deferred                  from "../../utils/deferred"
import GraphCoordinateCalculator from "./graph-coordinate-calculator"

const defaultColor = "#999";


class Graph {
  constructor(src, coordinateCalculator) {
    this.id     = src.id;
    this.colors = src.colors || [];
    this.type   = src.type;
    this.axises = src.axises || [];

    this.coordinateCalculator =
      GraphCoordinateCalculator.create(this.type, coordinateCalculator);
  }
  resolveColor(index) {
    if ( this.colors.length <= index
      || !this.colors[index]) {
      return defaultColor;
    }
    return this.colors[index];
  }
}

class GraphDataConverter {

  constructor( graph, coordinateCalculator ) {
    this.lines = [];

    this.graph = graph;
    this.coordinateCalculator = coordinateCalculator;
  }
  prepare( allValues ) {
    this.graph.coordinateCalculator.calculateRange(allValues);
  }
  push(values, timestamp) {
    const x = this.coordinateCalculator.calculateX(timestamp);
    values.forEach((v, i) => {
      if (v === null || v === undefined) return;
      if (!this.lines[i]) this.lines[i] = [];
      this.lines[i].push({
        timestamp: timestamp,
        value: v,
        x: x,
        y: this.graph.coordinateCalculator.calculateY( v )
      });
    });
  }
  getLines() {
    return this.lines.map((line, index) => {
      return {
        type:  this.graph.type,
        color: this.graph.resolveColor(index),
        line:  line
      };
    });
  }
  getAxises() {
    return this.graph.coordinateCalculator.calculateAxises(this.graph.axises);
  }
}

export default class Graphs extends Observable {

  constructor( context,
    coordinateCalculator, preferences, pairSelector, graphService) {
    super();
    this.context = context;

    this.preferences          = preferences;
    this.pairSelector         = pairSelector;
    this.graphService         = graphService;
    this.coordinateCalculator = coordinateCalculator;

    this.registerObservers();
  }

  registerObservers() {
    this.pairSelector.addObserver("propertyChanged", (n, e) => {
      if (e.key === "selectedPair") {
        this.update();
      }
    }, this);
  }

  attach(slider) {
    this.slider = slider;
    this.slider.addObserver("propertyChanged", (n, e) => {
      if (e.key === "currentRange") {
        this.currentRange = e.newValue;
        this.update();
      }
    }, this);

    this.currentRange = slider.currentRange;
    this.update();
  }

  unregisterObservers() {
    this.pairSelector.removeAllObservers(this);
    this.slider.removeAllObservers(this);
    this.context.removeAllObservers(this);
  }

  update() {
    if (!this.currentRange) return;
    Deferred.when([
      this.fetchGraphs(this.currentRange),
      this.fetchGraphData(this.currentRange)
    ]).then( (results) => {
      this.updateGraphs(results[0]);
      this.coordinateCalculator.updateDeferred.then(
        () => this.updateGraphData(results[1]));
    });
  }
  fetchGraphs(range) {
    return this.graphService.fetchGraphs(
      range.start,
      range.end,
      this.context.backtestId
    );
  }
  fetchGraphData(range) {
    return this.graphService.fetchGraphData(
      range.start,
      range.end,
      this.preferences.chartInterval,
      this.context.backtestId
    );
  }

  get lines() {
    return this.getProperty("lines");
  }
  get axises() {
    return this.getProperty("axises");
  }
  updateGraphs( graphs ) {
    this.graphs = graphs.reduce(
      (p, c, i) => p.set(c.id, new Graph(c, this.coordinateCalculator)), new Map());
  }
  updateGraphData( data ) {
    var lines  = [];
    var axises = [];
    data.forEach((graphData) => {
      const graph = this.graphs.get(graphData.id);
      if (!this.checkEnabled(graph)) return;
      const converter = new GraphDataConverter(graph, this.coordinateCalculator );
      converter.prepare(graphData.data);

      graphData.data.map((data) =>
        converter.push(data.values, data.timestamp));

      lines  = lines.concat( converter.getLines() );
      axises = axises.concat( converter.getAxises() );
    });
    this.setProperty("lines", lines);
    this.setProperty("axises", axises);
  }
  checkEnabled(graph) {
    if (!graph) return false;
    if (!this.context.displaySubGraph
      && (graph.type !== "rate" && graph.type !== "balance" )) return false;
    return true;
  }
}