unageanu/jiji2

View on GitHub
sites/src/js/view/components/chart/chart.js

Summary

Maintainability
A
3 hrs
Test Coverage
import React                from "react"
import ReactDOM             from "react-dom"

import CreateJS             from "easeljs"
import CandleSticks         from "./candle-sticks"
import Background           from "./background"
import Axises               from "./axises"
import Slider               from "./slider"
import GraphView            from "./graph-view"
import PositionsView        from "./positions-view"
import Pointer              from "./pointer"
import CoordinateCalculator from "../../../viewmodel/chart/coordinate-calculator"
import Theme                from "../../theme"
import StageUpdater         from "./stage-updater"

const padding = CoordinateCalculator.padding();

export default class Chart extends React.Component {

  constructor(props) {
    super(props);
    this.state = {};
  }

  componentWillMount() {
  }

  componentDidMount() {
    this.props.model.reset();
    this.props.model.stageSize = this.props.size;
    const canvas = ReactDOM.findDOMNode(this.refs.canvas);

    this.buildStage(canvas, this.props.devicePixelRatio);
    this.buildViewComponents();

    this.registerSlideAction();
    this.initViewComponents();
    this.props.model.initialize();
  }

  componentWillUnmount() {
    this.axises.unregisterObservers();
    this.candleSticks.unregisterObservers();
    this.graphView.unregisterObservers();
    this.positionsView.unregisterObservers();
    this.pointer.unregisterObservers();
  }

  render() {
    const r = this.props.devicePixelRatio;
    return (
      <div>
        <canvas ref="canvas"
          width={this.props.size.w*r}
          height={this.props.size.h*r}
          style={{
            width: this.props.size.w+"px",
            height: this.props.size.h+"px"
        }}>
        </canvas>
      </div>
    );
  }

  buildStage(canvas, scale) {
    this.stage = new CreateJS.Stage(canvas);
    this.stage.scaleX = scale;
    this.stage.scaleY = scale;
    CreateJS.Touch.enable(this.stage, true, true);
    this.stage.preventSelection = false;

    this.stageUpdater = new StageUpdater(this.stage);
  }

  buildViewComponents() {
    this.slidableMask = this.createSlidableMask();
    this.slidable     = this.createSlidableMask(
      Theme.palette.backgroundColorDark);
    const model = this.props.model;

    const dpr = this.props.devicePixelRatio;
    this.background    = new Background( model, dpr );
    this.axises        = new Axises( model, this.slidableMask, dpr );
    this.candleSticks  = new CandleSticks( model, this.slidableMask, dpr );
    this.graphView     = new GraphView( model, this.slidableMask, dpr );
    this.positionsView = new PositionsView( model, this.slidableMask, dpr );
    this.pointer       = new Pointer( model, this.slidableMask, dpr );
  }
  initViewComponents() {
    this.background.attach( this.stage, this.stageUpdater );
    this.stage.addChild(this.slidable);

    this.axises.attach( this.stage, this.stageUpdater );
    this.pointer.attach( this.stage, this.stageUpdater );
    this.candleSticks.attach( this.stage, this.stageUpdater );
    this.graphView.attach( this.stage, this.stageUpdater );
    this.positionsView.attach( this.stage, this.stageUpdater );
  }

  registerSlideAction() {
    this.slidable.addEventListener("mousedown", (event) => {
      if (this.pointer.slideXStart != null
       || this.pointer.slideYStart != null) {
        return;
      }
      this.slideStart = event.stageX;
      this.props.model.slider.slideStart();
      event.preventDefault();
      event.nativeEvent.preventDefault();
    });
    this.slidable.addEventListener("pressmove", (event) => {
      if (!this.slideStart) return;
      this.doSlide( event.stageX );
      event.preventDefault();
      event.nativeEvent.preventDefault();
    });
    this.slidable.addEventListener("pressup", (event) => {
      if (!this.slideStart) return;
      this.props.model.slider.slideEnd();
      this.slideStart = null;
      event.preventDefault();
      event.nativeEvent.preventDefault();
    });
  }

  doSlide(x) {
    x = Math.ceil((this.slideStart - x) / (6*this.props.devicePixelRatio)) * -6;
    this.props.model.slider.slideByChart(x/6);
  }

  createSlidableMask(color="#000") {
    const stageSize    = this.props.model.candleSticks.stageSize;
    const axisPosition = this.props.model.candleSticks.axisPosition;
    const mask         = new CreateJS.Shape();
    mask.graphics.beginFill(color)
      .drawRect( padding, padding, axisPosition.horizontal - padding, stageSize.h )
      .endFill();
    return mask;
  }
}
Chart.propTypes = {
  devicePixelRatio: React.PropTypes.number.isRequired,
  size: React.PropTypes.object.isRequired,
  model: React.PropTypes.object.isRequired
};
Chart.defaultProps = {
  devicePixelRatio: window.devicePixelRatio || 1,
  size: {w:600, h:500}
};