<commit_before>(function( window, document, undefined ) {
  'use strict';

  var body = document.getElementsByClassName( 'body' )[0],
      bodyTransition = window.getComputedStyle( body ).transition;

  // Offset the transform origin so rotateY revolves around
  // an axis outside of the body.
  var transformOrigin = '50% 50% 0';
  body.style.webkitTransformOrigin = transformOrigin;
  body.style.transformOrigin = transformOrigin;

  function onMouseMove( event ) {
    var rx =   ( 0.5 - ( event.clientY / window.innerHeight ) ) * 180,
        ry =  -( 0.5 - ( event.clientX / window.innerWidth  ) ) * 180;

    var transform = 'rotateX( ' + rx + 'deg) rotateY( ' + ry + 'deg)';
    body.style.webkitTransform = transform;
    body.style.transform = transform;
  }

  onMouseMove({
    pageX: 0.5 * window.innerWidth,
    pageY: 0.5 * window.inenrHeight
  });

  // Toggle on/off the mouse-controlled rotating camera.
  document.addEventListener( 'keydown', function( event ) {
    // Space.
    if ( event.which === 32 ) {
      if ( window.getComputedStyle( body ).transitionProperty !== 'none' ) {
        body.style.transition = 'none';

        transformOrigin = '0 0 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.addEventListener( 'mousemove', onMouseMove );
      } else {
        body.style.transition = bodyTransition;

        // Reset transform and transform origin.
        body.style.webkitTransform = '';
        body.style.transform = '';

        transformOrigin = '50% 50% 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.removeEventListener( 'mousemove', onMouseMove );
      }
    }
  });

  /**
   * Need to handle the nested skeleton structure.
   *
   * Each of these needs to be able to take a number of transform functions.
   *  matrix()
   *  matrix3d()
   *  rotate()
   *  rotate3d()
   *  rotateX()
   *  rotateY()
   *  rotateZ()
   *  scale()
   *  scale3d()
   *  scaleX()
   *  scaleY()
   *  scaleZ()
   *  skewX()
   *  skewY()
   *  translate()
   *  translate3d()
   *  translateX()
   *  translateY()
   *  translateZ()
   */

  function Dimension( value, units ) {
    this.value = value || 0;
    this.units = units || '';
  }

  Dimension.prototype.toString = function() {
    return this.value + this.units;
  };

  function Angle( value, units ) {
    Dimension.call( this, value, units );
  }

  Angle.prototype = new Dimension();
  Angle.prototype.constructor = Angle;

  function Length( value, units ) {
    Dimension.call( this, value, units );
  }

  Length.prototype = new Dimension();
  Length.prototype.constructor = Length;

  function Transform() {}

  Transform.prototype.toString = function() { return ''; };

  function Matrix( a, b, c, d, tx, ty ) {
    this.a = a || 0;
    this.b = b || 0;
    this.c = c || 0;
    this.d = d || 0;
    this.tx = typeof tx !== 'undefined' ? tx : new Length();
    this.ty = typeof ty !== 'undefined' ? ty : new Length();
  }

  Matrix.prototype = new Transform();
  Matrix.prototype.constructor = Matrix;

  Matrix.prototype.toString = function() {
    return 'matrix(' +
      this.a + ', ' +
      this.b + ', ' +
      this.c + ', ' +
      this.d + ', ' +
      this.tx + ', ' +
      this.ty + ')';
  };

  function Matrix3D() {
    this.a0 = arguments[ 0] || 0;
    this.b0 = arguments[ 1] || 0;
    this.c0 = arguments[ 2] || 0;
    this.d0 = arguments[ 3] || 0;
    this.a1 = arguments[ 4] || 0;
    this.b1 = arguments[ 5] || 0;
    this.c1 = arguments[ 6] || 0;
    this.d1 = arguments[ 7] || 0;
    this.a2 = arguments[ 8] || 0;
    this.b2 = arguments[ 9] || 0;
    this.c2 = arguments[10] || 0;
    this.d2 = arguments[11] || 0;
    this.a3 = typeof arguments[12] !== 'undefined' ? arguments[12] : new Length();
    this.b3 = typeof arguments[13] !== 'undefined' ? arguments[13] : new Length();
    this.c3 = typeof arguments[14] !== 'undefined' ? arguments[14] : new Length();
    this.d3 = arguments[15] || 0;
  }

  Matrix3D.prototype = new Transform();
  Matrix3D.prototype.constructor = Matrix3D;

  Matrix3D.prototype.toString = function() {
    return 'matrix3d(' +
      this.a0 + ', ' + this.b0 + ', ' + this.c0 + ', ' + this.d0 + ', ' +
      this.a1 + ', ' + this.b1 + ', ' + this.c1 + ', ' + this.d1 + ', ' +
      this.a2 + ', ' + this.b2 + ', ' + this.c2 + ', ' + this.d2 + ', ' +
      this.a3 + ', ' + this.b3 + ', ' + this.c3 + ', ' + this.d3 + ')';
  };

  function Rotate( a ) {
    this.a = typeof a !== 'undefined' ? a : new Angle();
  }

  Rotate.prototype = new Transform();
  Rotate.prototype.constructor = Rotate;

  Rotate.prototype.toString = function() {
    return 'rotate(' + this.a + ')';
  };

  function RotateX( a ) {
    Rotate.call( this, a );
  }

  RotateX.prototype = new Transform();
  RotateX.prototype.constructor = RotateX;

  RotateX.prototype.toString = function() {
    return 'rotateX(' + this.a + ')';
  };

  function RotateY( a ) {
    Rotate.call( this, a );
  }

  RotateY.prototype = new Transform();
  RotateY.prototype.constructor = RotateY;

  RotateY.prototype.toString = function() {
    return 'rotateY(' + this.a + ')';
  };

  function RotateZ( a ) {
    Rotate.call( this, a );
  }

  RotateZ.prototype = new Transform();
  RotateZ.prototype.constructor = RotateZ;

  RotateZ.prototype.toString = function() {
    return 'rotateZ(' + this.a + ')';
  };

  function Rotate3D( x, y, z, a ) {
    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;
    Rotate.call( this, a );
  }

  Rotate3D.prototype = new Transform();
  Rotate3D.prototype.constructor = Rotate3D;

  Rotate3D.prototype.toString = function() {
    return 'rotate3d(' +
      this.x + ', ' +
      this.y + ', ' +
      this.z + ', ' +
      this.a + ')';
  };

  function Scale( sx, sy ) {
    this.sx = typeof sx !== 'undefined' ? sx : 1;
    this.sy = typeof sy !== 'undefined' ? sy : 1;
  }

  Scale.prototype = new Transform();
  Scale.prototype.cosntructor = Scale;

  Scale.prototype.toString = function() {
    return 'scale(' +
      this.sx + ', ' +
      this.sy + ')';
  };

  function Scale3D( sx, sy, sz ) {
    Scale.call( this, sx, sy );
    this.sz = typeof sz !== 'undefined' ? sz : 1;
  }

  Scale3D.prototype = new Transform();
  Scale3D.prototype.constructor = Scale3D;

  Scale3D.prototype.toString = function() {
    return 'scale3d(' +
      this.sx + ', ' +
      this.sy + ', ' +
      this.sz + ')';
  };

  function ScaleX( s ) {
    this.s = typeof s !== 'undefined' ? s : 1;
  }

  ScaleX.prototype = new Transform();
  ScaleX.prototype.constructor = ScaleX;

  ScaleX.prototype.toString = function() {
    return 'scaleX(' + this.s + ')';
  };

  function ScaleY( s ) {
    ScaleX.call( this, s );
  }

  ScaleY.prototype = new Transform();
  ScaleY.prototype.constructor = ScaleY;

  ScaleY.prototype.toString = function() {
    return 'scaleY(' + this.s + ')';
  };

  function ScaleZ( s ) {
    ScaleX.call( this, s );
  }

  ScaleZ.prototype = new Transform();
  ScaleZ.prototype.constructor = ScaleZ;

  ScaleZ.prototype.toString = function() {
    return 'scaleZ(' + this.s + ')';
  };

  function SkewX( a ) {
    this.a = typeof a !== 'undefined' ? a : new Angle();
  }

  SkewX.prototype = new Transform();
  SkewX.prototype.cosntructor = SkewX;

  SkewX.prototype.toString = function() {
    return 'skewX(' + this.a + ')';
  };

  function SkewY( a ) {
    SkewX.call( this, a );
  }

  SkewY.prototype = new Transform();
  SkewY.prototype.cosntructor = SkewY;

  SkewY.prototype.toString = function() {
    return 'skewY(' + this.a + ')';
  };

  function Translate( tx, ty ) {
    this.tx = typeof tx !== 'undefined' ? tx : new Length();
    this.ty = typeof ty !== 'undefined' ? ty : new Length();
  }

  Translate.prototype = new Transform();
  Translate.prototype.constructor = Translate;

  function Translate3D( tx, ty, tz ) {
    Translate.call( this, tx, ty, tz );
  }

  Translate3D.prototype = new Transform();
  Translate3D.prototype.constructor = Translate3D;

  Translate3D.prototype.toString = function() {
    return 'translate3d(' +
      this.tx + ', ' +
      this.ty + ', ' +
      this.tz + ')';
  };

  function TranslateX( t ) {
    this.t = typeof t !== 'undefined' ? t : new Length();
  }

  TranslateX.prototype = new Transform();
  TranslateX.prototype.constructor = TranslateX;

  TranslateX.prototype.toString = function() {
    return 'translateX(' + this.t  + ')';
  };

  function TranslateY( t ) {
    TranslateX.call( this, t );
  }

  TranslateY.prototype = new Transform();
  TranslateY.prototype.constructor = TranslateY;

  TranslateY.prototype.toString = function() {
    return 'translateY(' + this.t + ')';
  };

  function TranslateZ( t ) {
    TranslateX.call( this, t );
  }

  TranslateZ.prototype = new Transform();
  TranslateZ.prototype.constructor = TranslateZ;

  TranslateZ.prototype.toString = function() {
    return 'translateZ(' + this.t + ')';
  };

  function TransformView( options ) {
    this.el = options.el;
    this.model = options.model;
  }

  TransformView.prototype.render = function() {};
}) ( window, document );
<commit_msg>illustrations[robot-3d]: Last changes and tests before converting into a Backbone app.<commit_after>(function( window, document, undefined ) {
  'use strict';

  var body = document.getElementsByClassName( 'body' )[0],
      bodyTransition = window.getComputedStyle( body ).transition;

  // Offset the transform origin so rotateY revolves around
  // an axis outside of the body.
  var transformOrigin = '50% 50% 0';
  body.style.webkitTransformOrigin = transformOrigin;
  body.style.transformOrigin = transformOrigin;

  function onMouseMove( event ) {
    var rx =   ( 0.5 - ( event.clientY / window.innerHeight ) ) * 180,
        ry =  -( 0.5 - ( event.clientX / window.innerWidth  ) ) * 180;

    var transform = 'rotateX( ' + rx + 'deg) rotateY( ' + ry + 'deg)';
    body.style.webkitTransform = transform;
    body.style.transform = transform;
  }

  onMouseMove({
    pageX: 0.5 * window.innerWidth,
    pageY: 0.5 * window.inenrHeight
  });

  // Toggle on/off the mouse-controlled rotating camera.
  document.addEventListener( 'keydown', function( event ) {
    // Space.
    if ( event.which === 32 ) {
      if ( window.getComputedStyle( body ).transitionProperty !== 'none' ) {
        body.style.transition = 'none';

        transformOrigin = '0 0 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.addEventListener( 'mousemove', onMouseMove );
      } else {
        body.style.transition = bodyTransition;

        // Reset transform and transform origin.
        body.style.webkitTransform = '';
        body.style.transform = '';

        transformOrigin = '50% 50% 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.removeEventListener( 'mousemove', onMouseMove );
      }
    }
  });

  /**
   * Need to handle the nested skeleton structure.
   *
   * Each of these needs to be able to take a number of transform functions.
   *  matrix()
   *  matrix3d()
   *  rotate()
   *  rotate3d()
   *  rotateX()
   *  rotateY()
   *  rotateZ()
   *  scale()
   *  scale3d()
   *  scaleX()
   *  scaleY()
   *  scaleZ()
   *  skewX()
   *  skewY()
   *  translate()
   *  translate3d()
   *  translateX()
   *  translateY()
   *  translateZ()
   */

  // Utilities.
  /**
   * Used in a reduce() call to convert an array into an enum object.
   *
   * For example:
   *   [ 'a', 'b', 'c' ] => { 'a': 0, 'b': 1, 'c': 2 }
   */
  function reduceEnum( previousValue, currentValue, index ) {
    previousValue[ currentValue ] = index;
    return previousValue;
  }

  // CSS classes.
  function Dimension( value, units ) {
    this.value = value || 0;
    this.units = units || '';
  }

  Dimension.prototype.toString = function() {
    return this.value + this.units;
  };

  function Angle( value, units ) {
    Dimension.call( this, value, units );
  }

  Angle.Units = [ 'deg', 'rad', 'grad', 'turn' ].reduce( reduceEnum, {} );

  console.log( Angle.Units );

  Angle.prototype = new Dimension();
  Angle.prototype.constructor = Angle;

  function Length( value, units ) {
    Dimension.call( this, value, units );
  }

  Length.Units = [
    // Common units.
    'px', 'rem', 'em', 'pt',
    // Viewport-percentage units.
    'vw', 'vh', 'vmin', 'vmax',
    // Rest of the absolutes.
    'cm', 'mm', 'in', 'pc',
    // Rest of the font-relatives.
    'ex', 'ch'
  ].reduce( reduceEnum, {} );

  Length.prototype = new Dimension();
  Length.prototype.constructor = Length;

  function Transform() {}

  Transform.prototype.toString = function() { return ''; };

  function Matrix( a, b, c, d, tx, ty ) {
    this.a = a || 0;
    this.b = b || 0;
    this.c = c || 0;
    this.d = d || 0;
    this.tx = typeof tx !== 'undefined' ? tx : new Length();
    this.ty = typeof ty !== 'undefined' ? ty : new Length();
  }

  Matrix.prototype = new Transform();
  Matrix.prototype.constructor = Matrix;

  Matrix.prototype.toString = function() {
    return 'matrix(' +
      this.a + ', ' +
      this.b + ', ' +
      this.c + ', ' +
      this.d + ', ' +
      this.tx + ', ' +
      this.ty + ')';
  };

  function Matrix3D() {
    this.a0 = arguments[ 0] || 0;
    this.b0 = arguments[ 1] || 0;
    this.c0 = arguments[ 2] || 0;
    this.d0 = arguments[ 3] || 0;
    this.a1 = arguments[ 4] || 0;
    this.b1 = arguments[ 5] || 0;
    this.c1 = arguments[ 6] || 0;
    this.d1 = arguments[ 7] || 0;
    this.a2 = arguments[ 8] || 0;
    this.b2 = arguments[ 9] || 0;
    this.c2 = arguments[10] || 0;
    this.d2 = arguments[11] || 0;
    this.a3 = typeof arguments[12] !== 'undefined' ? arguments[12] : new Length();
    this.b3 = typeof arguments[13] !== 'undefined' ? arguments[13] : new Length();
    this.c3 = typeof arguments[14] !== 'undefined' ? arguments[14] : new Length();
    this.d3 = arguments[15] || 0;
  }

  Matrix3D.prototype = new Transform();
  Matrix3D.prototype.constructor = Matrix3D;

  Matrix3D.prototype.toString = function() {
    return 'matrix3d(' +
      this.a0 + ', ' + this.b0 + ', ' + this.c0 + ', ' + this.d0 + ', ' +
      this.a1 + ', ' + this.b1 + ', ' + this.c1 + ', ' + this.d1 + ', ' +
      this.a2 + ', ' + this.b2 + ', ' + this.c2 + ', ' + this.d2 + ', ' +
      this.a3 + ', ' + this.b3 + ', ' + this.c3 + ', ' + this.d3 + ')';
  };

  function Rotate( a ) {
    this.a = typeof a !== 'undefined' ? a : new Angle();
  }

  Rotate.prototype = new Transform();
  Rotate.prototype.constructor = Rotate;

  Rotate.prototype.toString = function() {
    return 'rotate(' + this.a + ')';
  };

  function RotateX( a ) {
    Rotate.call( this, a );
  }

  RotateX.prototype = new Transform();
  RotateX.prototype.constructor = RotateX;

  RotateX.prototype.toString = function() {
    return 'rotateX(' + this.a + ')';
  };

  function RotateY( a ) {
    Rotate.call( this, a );
  }

  RotateY.prototype = new Transform();
  RotateY.prototype.constructor = RotateY;

  RotateY.prototype.toString = function() {
    return 'rotateY(' + this.a + ')';
  };

  function RotateZ( a ) {
    Rotate.call( this, a );
  }

  RotateZ.prototype = new Transform();
  RotateZ.prototype.constructor = RotateZ;

  RotateZ.prototype.toString = function() {
    return 'rotateZ(' + this.a + ')';
  };

  function Rotate3D( x, y, z, a ) {
    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;
    Rotate.call( this, a );
  }

  Rotate3D.prototype = new Transform();
  Rotate3D.prototype.constructor = Rotate3D;

  Rotate3D.prototype.toString = function() {
    return 'rotate3d(' +
      this.x + ', ' +
      this.y + ', ' +
      this.z + ', ' +
      this.a + ')';
  };

  function Scale( sx, sy ) {
    this.sx = typeof sx !== 'undefined' ? sx : 1;
    this.sy = typeof sy !== 'undefined' ? sy : 1;
  }

  Scale.prototype = new Transform();
  Scale.prototype.cosntructor = Scale;

  Scale.prototype.toString = function() {
    return 'scale(' +
      this.sx + ', ' +
      this.sy + ')';
  };

  function Scale3D( sx, sy, sz ) {
    Scale.call( this, sx, sy );
    this.sz = typeof sz !== 'undefined' ? sz : 1;
  }

  Scale3D.prototype = new Transform();
  Scale3D.prototype.constructor = Scale3D;

  Scale3D.prototype.toString = function() {
    return 'scale3d(' +
      this.sx + ', ' +
      this.sy + ', ' +
      this.sz + ')';
  };

  function ScaleX( s ) {
    this.s = typeof s !== 'undefined' ? s : 1;
  }

  ScaleX.prototype = new Transform();
  ScaleX.prototype.constructor = ScaleX;

  ScaleX.prototype.toString = function() {
    return 'scaleX(' + this.s + ')';
  };

  function ScaleY( s ) {
    ScaleX.call( this, s );
  }

  ScaleY.prototype = new Transform();
  ScaleY.prototype.constructor = ScaleY;

  ScaleY.prototype.toString = function() {
    return 'scaleY(' + this.s + ')';
  };

  function ScaleZ( s ) {
    ScaleX.call( this, s );
  }

  ScaleZ.prototype = new Transform();
  ScaleZ.prototype.constructor = ScaleZ;

  ScaleZ.prototype.toString = function() {
    return 'scaleZ(' + this.s + ')';
  };

  function SkewX( a ) {
    this.a = typeof a !== 'undefined' ? a : new Angle();
  }

  SkewX.prototype = new Transform();
  SkewX.prototype.cosntructor = SkewX;

  SkewX.prototype.toString = function() {
    return 'skewX(' + this.a + ')';
  };

  function SkewY( a ) {
    SkewX.call( this, a );
  }

  SkewY.prototype = new Transform();
  SkewY.prototype.cosntructor = SkewY;

  SkewY.prototype.toString = function() {
    return 'skewY(' + this.a + ')';
  };

  function Translate( tx, ty ) {
    this.tx = typeof tx !== 'undefined' ? tx : new Length();
    this.ty = typeof ty !== 'undefined' ? ty : new Length();
  }

  Translate.prototype = new Transform();
  Translate.prototype.constructor = Translate;

  function Translate3D( tx, ty, tz ) {
    Translate.call( this, tx, ty, tz );
  }

  Translate3D.prototype = new Transform();
  Translate3D.prototype.constructor = Translate3D;

  Translate3D.prototype.toString = function() {
    return 'translate3d(' +
      this.tx + ', ' +
      this.ty + ', ' +
      this.tz + ')';
  };

  function TranslateX( t ) {
    this.t = typeof t !== 'undefined' ? t : new Length();
  }

  TranslateX.prototype = new Transform();
  TranslateX.prototype.constructor = TranslateX;

  TranslateX.prototype.toString = function() {
    return 'translateX(' + this.t  + ')';
  };

  function TranslateY( t ) {
    TranslateX.call( this, t );
  }

  TranslateY.prototype = new Transform();
  TranslateY.prototype.constructor = TranslateY;

  TranslateY.prototype.toString = function() {
    return 'translateY(' + this.t + ')';
  };

  function TranslateZ( t ) {
    TranslateX.call( this, t );
  }

  TranslateZ.prototype = new Transform();
  TranslateZ.prototype.constructor = TranslateZ;

  TranslateZ.prototype.toString = function() {
    return 'translateZ(' + this.t + ')';
  };

  // TODO: Convert into Backbone Views.
  function TransformView( options ) {
    this.el = options.el;
    this.model = options.model;
  }

  TransformView.prototype.initialize = function() {
    var model = this.model;
    for ( var key in model ) {
      if ( model.hasOwnProperty( key ) ) {
        if ( model[ key ] instanceof Dimension ) {
          console.log( key );
        }
      }
    }
  };

  var matrix = new Matrix();
  var view = new TransformView({
    model: matrix
  });

  view.initialize();

  TransformView.prototype.render = function() {};

  function DimensionView( options ) {
    this.el = options.el;
    this.model = options.model;
  }

  DimensionView.prototype.initialize = function() {};
  DimensionView.prototype.render = function() {};
}) ( window, document );
<|endoftext|>


<commit_before>import React from 'react'
import d3 from 'd3'

import { Chart, Heatmap } from '../src'

// import exampleData from './data/heatmap.json'
import { ordinalHeatmapData, linearHeatmapData } from './data/exampleData'

const toolTipFunction = (d) => {
  let toolTip = ' No Data '

  if (d.value > 0) {
    toolTip =
      '' + d.key + '' +
      d3.format('n')(d.value)
  }

  return toolTip
}

const chartProps1 = {
  className: 'col-lg-3',
  margin: {top: 15, right: 15, bottom: 50, left: 110},
  width: 800,
  height: 300,
  data: ordinalHeatmapData,
  xScaleType: 'linear',
  yScaleType: 'ordinalBand',
  yAxis: {
    type: 'y',
    orient: 'left'
  },
  xAxis: {
    type: 'x',
    tickCount: ordinalHeatmapData[0].bins.length,
    orient: 'bottom'
  },
  legend: true
}

const heatmapProps1 = {
  labelField: 'key',
  numColorCat: 17
}

// Setup custom tick values to be used
// let yTickValues = []
// linearHeatmapData.forEach((d) => {
//   yTickValues.push(d.key)
// })

// NOTE: Padding wlinearHeatmapDataith empty data to keep heatmap more generic
// let numBins = 10
// if (linearHeatmapData.length < numBins) {
//   let n = linearHeatmapData.length
//   for (let i = n; i < numBins; i++) {
//     linearHeatmapData.push({
//       bins: [],
//       key: ' '.repeat(i),
//       value: 0
//     })
//   }
// }

const chartProps2 = {
  className: 'col-lg-3',
  margin: {top: 15, right: 15, bottom: 50, left: 110},
  width: 800,
  height: 300,
  data: linearHeatmapData,
  xScaleType: 'temporal',
  yScaleType: 'linear',
  yAxis: {
    type: 'y',
    tickCount: linearHeatmapData[0].bins.length,
    orient: 'left'
  },
  xAxis: {
    type: 'x',
    tickCount: linearHeatmapData[0].bins.length,
    orient: 'bottom'
  },
  legend: true
}

const heatmapProps2 = {
  labelField: 'key',
  yAccessor: {
    key: 'key',
    value: 'key'
  },
  numColorCat: 17,
  maxColor: '#7C9B27',
  minColor: '#F1F5E9'
}

class HeatmapExample extends React.Component {
  render () {
    return (

        <Chart {...chartProps1} tipFunction={toolTipFunction}>
          <Heatmap {...heatmapProps1} />
        </Chart>
        <Chart {...chartProps2} tipFunction={toolTipFunction}>
          <Heatmap {...heatmapProps2} />
        </Chart>

    )
  }
}

export default HeatmapExample
<commit_msg>Fixed tooltip for heatmap example<commit_after>import React from 'react'
import d3 from 'd3'

import { Chart, Heatmap } from '../src'

// import exampleData from './data/heatmap.json'
import { ordinalHeatmapData, linearHeatmapData } from './data/exampleData'

const toolTipFunction1 = (d) => {
  let toolTip = ' No Data '

  if (d.value > 0) {
    toolTip =
      '' + d.key + '' +
      d3.format('n')(d.value)
  }

  return toolTip
}

const chartProps1 = {
  className: 'col-lg-3',
  margin: {top: 15, right: 15, bottom: 50, left: 110},
  width: 800,
  height: 300,
  data: ordinalHeatmapData,
  xScaleType: 'linear',
  yScaleType: 'ordinalBand',
  yAxis: {
    type: 'y',
    orient: 'left'
  },
  xAxis: {
    type: 'x',
    tickCount: ordinalHeatmapData[0].bins.length,
    orient: 'bottom'
  },
  legend: true
}

const heatmapProps1 = {
  labelField: 'key',
  numColorCat: 17
}

// Setup custom tick values to be used
// let yTickValues = []
// linearHeatmapData.forEach((d) => {
//   yTickValues.push(d.key)
// })

// NOTE: Padding wlinearHeatmapDataith empty data to keep heatmap more generic
// let numBins = 10
// if (linearHeatmapData.length < numBins) {
//   let n = linearHeatmapData.length
//   for (let i = n; i < numBins; i++) {
//     linearHeatmapData.push({
//       bins: [],
//       key: ' '.repeat(i),
//       value: 0
//     })
//   }
// }

const toolTipFunction2 = (d) => {
  let toolTip = ' No Data '

  if (d.value > 0) {
    toolTip =
      '' + new Date(+d.key) + '' +
      d3.format('n')(d.value)
  }

  return toolTip
}

const chartProps2 = {
  className: 'col-lg-3',
  margin: {top: 15, right: 15, bottom: 50, left: 110},
  width: 800,
  height: 300,
  data: linearHeatmapData,
  xScaleType: 'temporal',
  yScaleType: 'linear',
  yAxis: {
    type: 'y',
    tickCount: linearHeatmapData[0].bins.length,
    orient: 'left'
  },
  xAxis: {
    type: 'x',
    tickCount: linearHeatmapData[0].bins.length,
    orient: 'bottom'
  },
  legend: true
}

const heatmapProps2 = {
  labelField: 'key',
  yAccessor: {
    key: 'key',
    value: 'key'
  },
  numColorCat: 17,
  maxColor: '#7C9B27',
  minColor: '#F1F5E9'
}

class HeatmapExample extends React.Component {
  render () {
    return (

        <Chart {...chartProps1} tipFunction={toolTipFunction1}>
          <Heatmap {...heatmapProps1} />
        </Chart>
        <Chart {...chartProps2} tipFunction={toolTipFunction2}>
          <Heatmap {...heatmapProps2} />
        </Chart>

    )
  }
}

export default HeatmapExample
<|endoftext|>


<commit_before>var del = require('del');
var _ = require('lodash');

function clean(target, done) {
	var dir = './' + target;
	var deleteList = [dir + '/*'];
	deleteList = deleteList.concat(getPreservedFiles(dir));
	return del(deleteList, done);
}

var preservedFiles = [
	'web.config',
	'bower.json',
];

function getPreservedFiles(directory) {
	return _.map(preservedFiles, function(file) {
		return '!' + directory + '/' + file;
	});
}

module.exports = clean;

var defaults = require('./defaults');

module.exports.config = function(gulp) {
	gulp.task('clean', ['clean.debug']);

	gulp.task('clean.debug', function (done) {
		return clean(defaults.debugFolder, done);
	});

	gulp.task('clean.release', function (done) {
		return clean(defaults.releaseFolder, done);
	});
};
<commit_msg>Clean bower js files now since we will be copying these from the main repo<commit_after>var del = require('del');
var _ = require('lodash');

function clean(target, done) {
	var dir = './' + target;
	var deleteList = [dir + '/*'];
	deleteList = deleteList.concat(getPreservedFiles(dir));
	return del(deleteList, done);
}

var preservedFiles = [
	'web.config',
];

function getPreservedFiles(directory) {
	return _.map(preservedFiles, function(file) {
		return '!' + directory + '/' + file;
	});
}

module.exports = clean;

var defaults = require('./defaults');

module.exports.config = function(gulp) {
	gulp.task('clean', ['clean.debug']);

	gulp.task('clean.debug', function (done) {
		return clean(defaults.debugFolder, done);
	});

	gulp.task('clean.release', function (done) {
		return clean(defaults.releaseFolder, done);
	});
};
<|endoftext|>


<commit_before>var _ = require('underscore');
var util = require('util');
var utils = require('../../utils').common;
var async = require('async');
var url = require('url');

/**
 *
 * @param devops_github
 * @param is_closed
 * @returns
 */
var make_github_options = function(api_spec, is_closed) {
  var path = [
    '/pulls'
  ];

  if (is_closed) {
    path.push("?state=closed");
  }else{
    path.push('?state=open');
  }
  path.push('&per_page=150&page=1');

  return utils.github_options(api_spec, path);
};
/** Adds github field to devops if github related api is present
 * @param {object} devops devops object
 */
module.exports = function github(payload) {
  var api_config = payload.get_config();
  var open_options = make_github_options(api_config);
  var closed_options = make_github_options(api_config, true);

  var pulls;

  async.parallel({
    open_pull_requests: function(cb){
      utils.request_maker(open_options, cb);
    },
    closed_pull_requests: function(cb){
      utils.request_maker(closed_options, cb);
    }
  },function(err, results){
    var data = [];

    if (err) {
      payload.set_data(err);
      return;
    }

    try{
       // open_pull_requests: github response string
      _.each(results, function(val, key) {
        val = JSON.parse(val.data);
        data = data.concat(val);
      });
      data = parse_github_response(data);
    } catch (e){
      payload.set_data(e);
      return;
    }
    payload.set_data(null, data);
  });
};

/**
 * Parses
 * @param data List of pull requests
 * @returns
 */
var parse_github_response = function(data){
  var username, user_data = {};
  var avg_merge_age_metric, avg_staleness_metric, number_metric;
  var metrics = [];

  avg_merge_age_metric = new MergeMetric("Merged Pull Request Average Age", "Days");
  avg_staleness_metric = new StaleMetric("Stale Pull Request Average Age", "Days");
  number_metric = new NumberMetric("Pull Requests", "Count");
  metrics.push(avg_merge_age_metric);
  metrics.push(avg_staleness_metric);
  metrics.push(number_metric);

  _.each(data, function(pull) {
    _.each(metrics, function(metric) {
      metric.handle_pull(pull);
    });

    username = pull.user.login;
    if (!(username in user_data)) {
      user_data[username] = [];
    }
    user_data[username].push(pull);
  });

  _.each(metrics, function(metric) {
    var usernames = Object.getOwnPropertyNames(user_data);
    _.each(usernames, function(username) {
      metric.handle_user_pulls(username, user_data[username]);
    });
  });

  var formatted_metrics = [];
  _.each(metrics, function(metric) {
    formatted_metrics.push(metric.get_stats());
  });

  return formatted_metrics;
};

/**
 * Pulls out metric information for a set of Github pull request objects.
 * @todo The "user" part of the name "user_stats" is an assumption not a requirement.
 * @param {list} pull List of Github pull request objects
 * @returns {object} like so:
 * {
    number_pull_requests: total number
    number_merged: number merged
    number_stale: number still open
    number_tested: 0
    number_commits: 0
    avg_merged_life_span: number (days)
    avg_total_life_span: number (days)
    avg_stale_life_span: number (days)
    };
 */
var user_stats = function(pulls) {
  // pull request counts
  var number_pull_requests = pulls.length;
  var number_merged = 0;
  var number_stale = 0;
  var number_tested = 0;
  // commit counts
  var number_commits = 0;
  // avg times
  var merged_life_span_time = 0; // against number_merged
  var total_life_span_time = 0; // against number_pull_requests
  var stale_time = 0; // against number_stale

  var now = Date.now();
  for(var i = 0; i < pulls.length; i++) {
    var pull = pulls[i];
    var created_at = Date.parse(pull.created_at);
    var updated_at = Date.parse(pull.updated_at);
    var merged_at = pull.merged_at;
    var closed_at = pull.closed_at;
    if (merged_at) { merged_at = Date.parse(merged_at); }
    if (closed_at) { closed_at = Date.parse(closed_at); }

    // get total merged stats
    if (merged_at) {
      number_merged++;
      merged_life_span_time += (merged_at - created_at);
    }

    var is_stale =  (!merged_at && !closed_at);
    // this is tricky, all pulls have been stale for some time
    if (is_stale){
      // number_stale refers to pulls that are currently stale
      number_stale++;
      // stale time for closed tickets
      stale_time += (now - updated_at);
    }

    if (closed_at) {
      total_life_span_time += (closed_at - created_at);
    } else {
      total_life_span_time += (now - created_at);
    }
  }
  return {
    number_pull_requests: number_pull_requests,
    number_merged: number_merged,
    number_stale: number_stale,
    number_tested: number_tested,
    number_commits: number_commits,
    avg_merged_life_span: avg_days(merged_life_span_time, number_merged),
    avg_total_life_span: avg_days(total_life_span_time, number_pull_requests),
    avg_stale_life_span: avg_days(stale_time, number_stale)
    };
};

/**
 * Abstract parent class for metric data.
 * Subclasses should implement get_stats and at least one of handle_pull and handle_user_pulls.
 *
 * @param name {string} Human readable name for what this metric is
 * @param unit {string} Human readable units of metric
 */
var Metric = function(name, unit) {
  // {string} Human readable name for what this metric is
  this._name = name;
  // {string} Human readable units of metric
  this._unit = unit;
  // {int} Total number or 100% or whatever makes sense based on units and data
  this._aggregate = 0;
  // {array} List of mappings between Github username and metric value
  this._stats = [];
};

/**
 * @param pull {object} A pull request object from Github @TODO give example
 * @side-effecting and likely NOT idempotent
 */
Metric.prototype.handle_pull = function(pull) {
  // implement this
};

/**
 * @param username {string} A Github username
 * @param pulls {array} pulls List of Github pull request objects.
 * @side-effecting and likely NOT idempotent
 */
Metric.prototype.handle_user_pulls = function(username, pulls) {
  // implement this
};

Metric.prototype.get_stats = function() {
  // implement this
};

/**
 * Total number of pull requests
 */
var NumberMetric = function(name, unit) {
  this._name = name;
  this._unit = unit;
  this._aggregate = 0;
  this._stats = [];
  this._obj_stats = {};
};
// @TODO are we using this correctly? Seems lame to have to redefine the parent methods if not
// overwriting them.
util.inherits(NumberMetric, Metric);

NumberMetric.prototype.handle_pull = function(pull) {
  this._aggregate++;
  if (!this._obj_stats[pull.user.login]) {
    this._obj_stats[pull.user.login] = 0;
  }
  this._obj_stats[pull.user.login]++;
};

NumberMetric.prototype.handle_user_pulls = function(username, pulls) {
  // implement this
};

NumberMetric.prototype.get_stats = function() {
  var self = this;
  var stats =  _.map(
      Object.getOwnPropertyNames(self._obj_stats),
      function(x) {
        var m = {};
        m[x] = self._obj_stats[x];
        return m;
      });
  return {
    name: self._name,
    unit: self._unit,
    aggregate: self._aggregate,
    stats: stats};
};

/**
 * Average time to merge pull requests
 */
var MergeMetric = function(name, unit) {
  this._name = name;
  this._unit = unit;
  this._aggregate = 0;
  this._stats = [];
};
util.inherits(MergeMetric, Metric);

MergeMetric.prototype.handle_pull = function(pull) {
  // implement this
};

MergeMetric.prototype.handle_user_pulls = function(username, pulls) {
  var userstats = user_stats(pulls);
  var m = {};
  m[username] = userstats.avg_total_life_span;
  this._stats.push(m);
  this._aggregate += parseFloat(userstats.avg_total_life_span);
};

MergeMetric.prototype.get_stats = function() {
  return {
    name: this._name,
    unit: this._unit,
    aggregate: (this._aggregate / _.keys(this._stats).length).toFixed(1),
    stats: this._stats
  };
};

/**
 * Average time stale pull requests have lain open
 */
var StaleMetric = function(name, unit) {
  this._name = name;
  this._unit = unit;
  this._aggregate = 0;
  this._stats = [];
};
util.inherits(StaleMetric, Metric);

StaleMetric.prototype.handle_pull = function(pull) {
  // implement this
};

StaleMetric.prototype.handle_user_pulls = function(username, pulls) {
  var userstats = user_stats(pulls);
  var m = {};
  m[username] = userstats.avg_stale_life_span;
  this._stats.push(m);
  this._aggregate += parseFloat(userstats.avg_stale_life_span);
};

StaleMetric.prototype.get_stats = function() {
  return {
    name: this._name,
    unit: this._unit,
    aggregate: (this._aggregate / _.keys(this._stats).length).toFixed(1),
    stats: this._stats
  };
};

/**
 * Parses
 * @param data List of pull requests
 * @returns
 */
var parse_github_response = function(data){
  var username, user_data = {};
  var avg_merge_age_metric, avg_staleness_metric, number_metric;
  var metrics = [];

  avg_merge_age_metric = new MergeMetric("Merged Pull Request Average Age", "Days");
  avg_staleness_metric = new StaleMetric("Stale Pull Request Average Age", "Days");
  number_metric = new NumberMetric("Pull Requests", "Count");
  metrics.push(avg_merge_age_metric);
  metrics.push(avg_staleness_metric);
  metrics.push(number_metric);

  _.each(data, function(pull) {
    _.each(metrics, function(metric) {
      metric.handle_pull(pull);
    });

    username = pull.user.login;
    if (!(username in user_data)) {
      user_data[username] = [];
    }
    user_data[username].push(pull);
  });

  _.each(metrics, function(metric) {
    var usernames = Object.getOwnPropertyNames(user_data);
    _.each(usernames, function(username) {
      metric.handle_user_pulls(username, user_data[username]);
    });
  });

  var formatted_metrics = [];
  _.each(metrics, function(metric) {
    formatted_metrics.push(metric.get_stats());
  });

  return formatted_metrics;
};

/** Adds github field to devops if github related api is present
 * @param {object} devops devops object
 */
module.exports = function github(payload) {
  var api_config = payload.get_config();
  var open_options = make_github_options(api_config);
  var closed_options = make_github_options(api_config, true);

  var pulls;

  async.parallel({
    open_pull_requests: function(cb){
      utils.request_maker(open_options, cb);
    },
    closed_pull_requests: function(cb){
      utils.request_maker(closed_options, cb);
    }
  },function(err, results){
    var data = [];

    if (err) {
      payload.set_data(err);
      return;
    }

    try{
       // open_pull_requests: github response string
      _.each(results, function(val, key) {
        val = JSON.parse(val.data);
        data = data.concat(val);
      });
      data = parse_github_response(data);
    } catch (e){
      payload.set_data(e);
      return;
    }
    payload.set_data(null, data);
  });
};
<commit_msg>Fix github poller. The merge was messed up<commit_after>var _ = require('underscore');
var util = require('util');
var utils = require('../../utils').common;
var async = require('async');
var url = require('url');

/**
 *
 * @param devops_github
 * @param is_closed
 * @returns
 */
var make_github_options = function(api_spec, is_closed) {
  var path = [
    '/pulls'
  ];

  if (is_closed) {
    path.push("?state=closed");
  }else{
    path.push('?state=open');
  }
  path.push('&per_page=150&page=1');

  return utils.github_options(api_spec, path);
};
/** Adds github field to devops if github related api is present
 * @param {object} devops devops object
 */
module.exports = function github(payload) {
  var api_config = payload.get_config();
  var open_options = make_github_options(api_config);
  var closed_options = make_github_options(api_config, true);

  var pulls;

  async.parallel({
    open_pull_requests: function(cb){
      utils.request_maker(open_options, cb);
    },
    closed_pull_requests: function(cb){
      utils.request_maker(closed_options, cb);
    }
  },function(err, results){
    var data = [];

    if (err) {
      payload.set_data(err);
      return;
    }

    try{
       // open_pull_requests: github response string
      _.each(results, function(val, key) {
        val = JSON.parse(val.data);
        data = data.concat(val);
      });
      data = parse_github_response(data);
    } catch (e){
      payload.set_data(e);
      return;
    }
    payload.set_data(null, data);
  });
};

/**
 * Parses
 * @param data List of pull requests
 * @returns
 */
var parse_github_response = function(data){
  var username, user_data = {};
  var avg_merge_age_metric, avg_staleness_metric, number_metric;
  var metrics = [];

  avg_merge_age_metric = new MergeMetric("Merged Pull Request Average Age", "Days");
  avg_staleness_metric = new StaleMetric("Stale Pull Request Average Age", "Days");
  number_metric = new NumberMetric("Pull Requests", "Count");
  metrics.push(avg_merge_age_metric);
  metrics.push(avg_staleness_metric);
  metrics.push(number_metric);

  _.each(data, function(pull) {
    _.each(metrics, function(metric) {
      metric.handle_pull(pull);
    });

    username = pull.user.login;
    if (!(username in user_data)) {
      user_data[username] = [];
    }
    user_data[username].push(pull);
  });

  _.each(metrics, function(metric) {
    var usernames = Object.getOwnPropertyNames(user_data);
    _.each(usernames, function(username) {
      metric.handle_user_pulls(username, user_data[username]);
    });
  });

  var formatted_metrics = [];
  _.each(metrics, function(metric) {
    formatted_metrics.push(metric.get_stats());
  });

  return formatted_metrics;
};

/**
 * Pulls out metric information for a set of Github pull request objects.
 * @todo The "user" part of the name "user_stats" is an assumption not a requirement.
 * @param {list} pull List of Github pull request objects
 * @returns {object} like so:
 * {
    number_pull_requests: total number
    number_merged: number merged
    number_stale: number still open
    number_tested: 0
    number_commits: 0
    avg_merged_life_span: number (days)
    avg_total_life_span: number (days)
    avg_stale_life_span: number (days)
    };
 */
var user_stats = function(pulls) {

  // pull request counts
  var number_pull_requests = pulls.length;
  var number_merged = 0;
  var number_stale = 0;
  var number_tested = 0;
  // commit counts
  var number_commits = 0;
  // avg times
  var merged_life_span_time = 0; // against number_merged
  var total_life_span_time = 0; // against number_pull_requests
  var stale_time = 0; // against number_stale

  var now = Date.now();
  for(var i = 0; i < pulls.length; i++) {
    var pull = pulls[i];
    var created_at = Date.parse(pull.created_at);
    var updated_at = Date.parse(pull.updated_at);
    var merged_at = pull.merged_at;
    var closed_at = pull.closed_at;
    if (merged_at) { merged_at = Date.parse(merged_at); }
    if (closed_at) { closed_at = Date.parse(closed_at); }

    // get total merged stats
    if (merged_at) {
      number_merged++;
      merged_life_span_time += (merged_at - created_at);
    }

    var is_stale =  (!merged_at && !closed_at);
    // this is tricky, all pulls have been stale for some time
    if (is_stale){
      // number_stale refers to pulls that are currently stale
      number_stale++;
      // stale time for closed tickets
      stale_time += (now - updated_at);
    }

    if (closed_at) {
      total_life_span_time += (closed_at - created_at);
    } else {
      total_life_span_time += (now - created_at);
    }
  }
  return {
    number_pull_requests: number_pull_requests,
    number_merged: number_merged,
    number_stale: number_stale,
    number_tested: number_tested,
    number_commits: number_commits,
    avg_merged_life_span: avg_days(merged_life_span_time, number_merged),
    avg_total_life_span: avg_days(total_life_span_time, number_pull_requests),
    avg_stale_life_span: avg_days(stale_time, number_stale)
    };
};

/**
 * @param {number} total_seconds Total number of seconds
 * @param {number} number Total number of (probably) pull requests
 * @return {number} The average number of days
 */
var avg_days = function(total_seconds, number) {
  var avg_seconds = 0;
  if (number) {
    avg_seconds = total_seconds / number;
    return (avg_seconds / 1000 / 60 / 60 / 24).toFixed(1);
  } else {
    return avg_seconds;
  }
};

/**
 * Abstract parent class for metric data.
 * Subclasses should implement get_stats and at least one of handle_pull and handle_user_pulls.
 *
 * @param name {string} Human readable name for what this metric is
 * @param unit {string} Human readable units of metric
 */
var Metric = function(name, unit) {
  // {string} Human readable name for what this metric is
  this._name = name;
  // {string} Human readable units of metric
  this._unit = unit;
  // {int} Total number or 100% or whatever makes sense based on units and data
  this._aggregate = 0;
  // {array} List of mappings between Github username and metric value
  this._stats = [];
};

/**
 * @param pull {object} A pull request object from Github @TODO give example
 * @side-effecting and likely NOT idempotent
 */
Metric.prototype.handle_pull = function(pull) {
  // implement this
};

/**
 * @param username {string} A Github username
 * @param pulls {array} pulls List of Github pull request objects.
 * @side-effecting and likely NOT idempotent
 */
Metric.prototype.handle_user_pulls = function(username, pulls) {
  // implement this
};

Metric.prototype.get_stats = function() {
  // implement this
};

/**
 * Total number of pull requests
 */
var NumberMetric = function(name, unit) {
  this._name = name;
  this._unit = unit;
  this._aggregate = 0;
  this._stats = [];
  this._obj_stats = {};
};
// @TODO are we using this correctly? Seems lame to have to redefine the parent methods if not
// overwriting them.
util.inherits(NumberMetric, Metric);

NumberMetric.prototype.handle_pull = function(pull) {
  this._aggregate++;
  if (!this._obj_stats[pull.user.login]) {
    this._obj_stats[pull.user.login] = 0;
  }
  this._obj_stats[pull.user.login]++;
};

NumberMetric.prototype.handle_user_pulls = function(username, pulls) {
  // implement this
};

NumberMetric.prototype.get_stats = function() {
  var self = this;
  var stats =  _.map(
      Object.getOwnPropertyNames(self._obj_stats),
      function(x) {
        var m = {};
        m[x] = self._obj_stats[x];
        return m;
      });
  return {
    name: self._name,
    unit: self._unit,
    aggregate: self._aggregate,
    stats: stats};
};

/**
 * Average time to merge pull requests
 */
var MergeMetric = function(name, unit) {
  this._name = name;
  this._unit = unit;
  this._aggregate = 0;
  this._stats = [];
};
util.inherits(MergeMetric, Metric);

MergeMetric.prototype.handle_pull = function(pull) {
  // implement this
};

MergeMetric.prototype.handle_user_pulls = function(username, pulls) {
  var userstats = user_stats(pulls);
  var m = {};
  m[username] = userstats.avg_total_life_span;
  this._stats.push(m);
  this._aggregate += parseFloat(userstats.avg_total_life_span);
};

MergeMetric.prototype.get_stats = function() {
  return {
    name: this._name,
    unit: this._unit,
    aggregate: (this._aggregate / _.keys(this._stats).length).toFixed(1),
    stats: this._stats
  };
};

/**
 * Average time stale pull requests have lain open
 */
var StaleMetric = function(name, unit) {
  this._name = name;
  this._unit = unit;
  this._aggregate = 0;
  this._stats = [];
};
util.inherits(StaleMetric, Metric);

StaleMetric.prototype.handle_pull = function(pull) {
  // implement this
};

StaleMetric.prototype.handle_user_pulls = function(username, pulls) {
  var userstats = user_stats(pulls);
  var m = {};
  m[username] = userstats.avg_stale_life_span;
  this._stats.push(m);
  this._aggregate += parseFloat(userstats.avg_stale_life_span);
};

StaleMetric.prototype.get_stats = function() {
  return {
    name: this._name,
    unit: this._unit,
    aggregate: (this._aggregate / _.keys(this._stats).length).toFixed(1),
    stats: this._stats
  };
};
<|endoftext|>


<commit_before>/**
 * Created by Mihail on 8/15/2016.
 */
'use strict';

import ApiController from './api/api-controller';
import ViewManipulator from './utils/view-manipulator';
import CardGenerator from './card/card-generator';
import CardDrawer from './card/card-drawer';
import MarketCards from './market-place/market-cards';
import Blower from './blower/blower';
import Dauber from './dauber/dauber';
import Timer from './utils/timer';
import { EventsConsts } from './events/events-consts';
import WinningDialog from './winning/winning-dialog';
import 'es6-promise';
import 'isomorphic-fetch';
import { ApiConsts } from './api/api-consts';
import WinPatternsAnimModule from './winning/win-patterns-anim-module';

class App {
	constructor() {
		this.confUrl = ApiConsts.CONF;
		this.loadConfigs(App.init);
	}

	loadConfigs(callback) {
		fetch(this.confUrl)
			.then((response) => {
				if (response.status >= 400) {
					throw new Error("Bad response from server");
				}
				return response.json();
			}).then((config) => {
			callback(this, config);
		});
		return callback;
	}

	static init(context, conf) {
		context.start(conf);
	}

	initPlayingCards(conf, container) {
		if (conf.gameConf.playingCards) {
			this.cardGen = new CardGenerator(conf);
			const marketCards = new MarketCards(container);
			const purchasedCardsCount = MarketCards.getPurchasedCardsCount(marketCards.getRadioButtonsArray());
			const cardDrawer = new CardDrawer(
				this.cardGen.generateCards(purchasedCardsCount),
				document.querySelector('#leftGameScreen')
			);
			MarketCards.buyCards(purchasedCardsCount, conf.gameConf.cardPrice);
		}
	}

	start(conf) {
		this.title = conf.gameConf.appTitle;
		document.querySelector('title').innerText = conf.gameConf.appTitle;
		const elMarketPlace = document.querySelector('#marketPlace');

		// Create the components only if they are allowed in the config
		if (conf.gameConf.winningDialog) {
			const winningDialog = new WinningDialog('#winningDialogContainer');
		}

		if (!conf.gameConf.marketCards) {
			ViewManipulator.toggleVisibility(elMarketPlace, false);
		}
		MarketCards.setCardPrices(conf.gameConf.cardPrice, document.querySelectorAll('.cards'));

		let elWinPatternsAnimModule = null;
		if (conf.gameConf.winPatternsAnimModule) {
			elWinPatternsAnimModule = document.querySelector('#winPatternsAnimModule');
			const horPattern = new WinPatternsAnimModule(elWinPatternsAnimModule.querySelector('#horizontal'), 5, 5, 'horizontal');
			const verPattern = new WinPatternsAnimModule(elWinPatternsAnimModule.querySelector('#vertical'), 5, 5, 'vertical');
			const diagPattern = new WinPatternsAnimModule(elWinPatternsAnimModule.querySelector('#diagonal'), 5, 5, 'diagonal');
		}

		if (conf.gameConf.mainGame) {
			const timer = new Timer(
				document.querySelector('#timerContainer'),
				conf.gameConf.beforeStartGameSeconds,
				EventsConsts.START_GAME, true
			);

			document.addEventListener(EventsConsts.ENOUGH_BALANCE, () => {
				ViewManipulator.toggleVisibility(elMarketPlace, false);
				ViewManipulator.toggleVisibility(document.querySelector('#footer'), false);
				timer.pulsate();
			});

			const startBtn = document.querySelector('#startBtn');
			if (startBtn) {
				startBtn.addEventListener('click', (e) => {
					this.initPlayingCards(conf, elMarketPlace);
				});
			}
		}

		if (conf.gameConf.dauber) {
			const dauber = new Dauber(conf, document.querySelector('#tube'));
			const blower = new Blower(document.querySelector('#blower-balloon'));
		}

		const apiCtrl = new ApiController();
		const logoutBtn = document.querySelector('#logoutBtn');
		if (logoutBtn) {
			logoutBtn.addEventListener('click', (e) => {
				apiCtrl.logout();
			});
		}

		if (ApiController.isLogged()) {
			ViewManipulator.showUserInfo();
		}
	}
}

export default App;

(() => {
	const app = new App();
})();
<commit_msg>Fixed unit test for Timer component.<commit_after>/**
 * Created by Mihail on 8/15/2016.
 */
'use strict';

import ApiController from './api/api-controller';
import ViewManipulator from './utils/view-manipulator';
import CardGenerator from './card/card-generator';
import CardDrawer from './card/card-drawer';
import MarketCards from './market-place/market-cards';
import Blower from './blower/blower';
import Dauber from './dauber/dauber';
import Timer from './utils/timer';
import { EventsConsts } from './events/events-consts';
import WinningDialog from './winning/winning-dialog';
import 'es6-promise';
import 'isomorphic-fetch';
import { ApiConsts } from './api/api-consts';
import WinPatternsAnimModule from './winning/win-patterns-anim-module';

class App {
	constructor() {
		this.confUrl = ApiConsts.CONF;
		this.loadConfigs(App.init);
	}

	loadConfigs(callback) {
		fetch(this.confUrl).then((response) => {
				if (response.status >= 400) {
					throw new Error("Bad response from server");
				}
				return response.json();
			}).then((config) => {
			callback(this, config);
		});
		return callback;
	}

	static init(context, conf) {
		context.start(conf);
	}

	initPlayingCards(conf, container) {
		if (conf.gameConf.playingCards) {
			this.cardGen = new CardGenerator(conf);
			const marketCards = new MarketCards(container);
			const purchasedCardsCount = MarketCards.getPurchasedCardsCount(marketCards.getRadioButtonsArray());
			const cardDrawer = new CardDrawer(
				this.cardGen.generateCards(purchasedCardsCount),
				document.querySelector('#leftGameScreen')
			);
			MarketCards.buyCards(purchasedCardsCount, conf.gameConf.cardPrice);
		}
	}

	start(conf) {
		this.title = conf.gameConf.appTitle;
		document.querySelector('title').innerText = conf.gameConf.appTitle;
		const elMarketPlace = document.querySelector('#marketPlace');

		// Create the components only if they are allowed in the config
		if (conf.gameConf.winningDialog) {
			const winningDialog = new WinningDialog('#winningDialogContainer');
		}

		if (!conf.gameConf.marketCards) {
			ViewManipulator.toggleVisibility(elMarketPlace, false);
		}
		MarketCards.setCardPrices(conf.gameConf.cardPrice, document.querySelectorAll('.cards'));

		let elWinPatternsAnimModule = null;
		if (conf.gameConf.winPatternsAnimModule) {
			elWinPatternsAnimModule = document.querySelector('#winPatternsAnimModule');
			const horPattern = new WinPatternsAnimModule(elWinPatternsAnimModule.querySelector('#horizontal'), 5, 5, 'horizontal');
			const verPattern = new WinPatternsAnimModule(elWinPatternsAnimModule.querySelector('#vertical'), 5, 5, 'vertical');
			const diagPattern = new WinPatternsAnimModule(elWinPatternsAnimModule.querySelector('#diagonal'), 5, 5, 'diagonal');
		}

		if (conf.gameConf.mainGame) {
			const timer = new Timer(
				document.querySelector('#timerContainer'),
				conf.gameConf.beforeStartGameSeconds,
				EventsConsts.START_GAME, true
			);

			document.addEventListener(EventsConsts.ENOUGH_BALANCE, () => {
				ViewManipulator.toggleVisibility(elMarketPlace, false);
				ViewManipulator.toggleVisibility(document.querySelector('#footer'), false);
				timer.pulsate();
			});

			const startBtn = document.querySelector('#startBtn');
			if (startBtn) {
				startBtn.addEventListener('click', (e) => {
					this.initPlayingCards(conf, elMarketPlace);
				});
			}
		}

		if (conf.gameConf.dauber) {
			const dauber = new Dauber(conf, document.querySelector('#tube'));
			const blower = new Blower(document.querySelector('#blower-balloon'));
		}

		const apiCtrl = new ApiController();
		const logoutBtn = document.querySelector('#logoutBtn');
		if (logoutBtn) {
			logoutBtn.addEventListener('click', (e) => {
				apiCtrl.logout();
			});
		}

		if (ApiController.isLogged()) {
			ViewManipulator.showUserInfo();
		}
	}
}

export default App;

(() => {
	const app = new App();
})();
<|endoftext|>


<commit_before>import Event from './event';

const Day = ({ events }) => {

  const DAY_NAMES = [ 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag', 'Søndag' ];
  const MONTH_NAMES = [ 'januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember' ];

  const DAY = events[ 0 ].start_time;
  const DAY_NAME = DAY_NAMES[ DAY.getDay() ];
  const DATE = DAY.getDate();
  const MONTH_NAME = MONTH_NAMES[ DAY.getMonth() ];

  return (

{`${DAY_NAME} ${DATE}. ${MONTH_NAME}`}

      { events.map((e, id) => {
        return <Event title={e.title} start_time={e.start_time} content={e.content} key={id}/>
      })}

  );
};

export default Day;
<commit_msg>Move constants outside of component as they didn't really need to be in there<commit_after>import Event from './event';

const DAY_NAMES = [ 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag', 'Søndag' ];
const MONTH_NAMES = [ 'januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember' ];

const Day = ({ events }) => {

  const DAY = events[ 0 ].start_time;
  const DAY_NAME = DAY_NAMES[ DAY.getDay() ];
  const DATE = DAY.getDate();
  const MONTH_NAME = MONTH_NAMES[ DAY.getMonth() ];

  return (

{`${DAY_NAME} ${DATE}. ${MONTH_NAME}`}

      { events.map((e, id) => {
        return <Event title={e.title} start_time={e.start_time} content={e.content} key={id}/>
      })}

  );
};

export default Day;
<|endoftext|>


<commit_before>/*
  data-display.js

  Montor data stuff, draw data stuff.
*/

var map;
var marker;
var firstFix = true;
var mapReady = false;

function initMap() {

  map = new google.maps.Map(document.getElementById('map-canvas'), {
    center : { lat : 37.444795, lng : -122.165146 },
    zoom : 4
  });

  // TODO: These listeners are a hack to get the map to initially display until I come
  // back to work on this. May have something to do with the fact that '#map-canvas' has
  // size (0,0) when initMap is called. Fix layout!
  //
  google.maps.event.addListenerOnce(map, 'idle', function() {
    google.maps.event.trigger(map, 'resize');
  });

  google.maps.event.addListenerOnce(map, 'projection_changed', function() {
    google.maps.event.trigger(map, 'resize');
  });

  google.maps.event.addListenerOnce(map, 'tilesloaded', function() {
    mapReady = true;
  });
}

function initCharts() {
  google.charts.load('current', {'packages':['gauge']});
  google.charts.setOnLoadCallback(drawCharts);

  (function pollSensors() {
    $.get(window.dataSourceUrl + '/sensors', function(data) {
      $.sensorData = data;

      drawCharts();

      if(map && google.maps && (_.get(data, 'GPS.lat') || _.get(data, 'GPS.lon'))) {

        var latlng = new google.maps.LatLng(data.GPS.lat, data.GPS.lon);

        // If this is our first good location, pan map to location. We'll do this only once
        // on first fix to allow the user to then pan/zoom as they desire.
        //
        if(mapReady && firstFix) {
          firstFix = false;
          map.setZoom(16);
          map.panTo(latlng);
        }

        // Position marker at the latest location
        //
        if(marker) {
          marker.setPosition(latlng);
        }
        else {
          marker = new google.maps.Marker({
            position : latlng,
            map : map,
            title : ''
          });
        }
      }

      $('#raw-data-json').text(JSON.stringify(data, null, 2));
      setTimeout(pollSensors, 1000);
    }).
    fail(function() {
      setTimeout(pollSensors, 1000);
    });
  })();
}

function drawCharts() {
  drawTemperatureChart();
  drawHumidityChart();
  drawPressureChart();
}

function drawTemperatureChart() {

  if(!_.has(google, 'visualization.arrayToDataTable') || !$.sensorData)
    return;

  var data = google.visualization.arrayToDataTable([
    ['Label', 'Value'],
    ['Temp F ', Number(_.get($.sensorData, 'DHT22.temperature_F', 0).toFixed(0))]
  ]);

  var options = {
    min         : 0,
    max         : 120,
    yellowFrom  : 70,
    yellowTo    : 90,
    redFrom     : 90,
    redTo       : 200,
    minorTicks  : 4,
    majorTicks  : ['0', '20', '40', '60', '80', '100', '120']
  };

  var chart = new google.visualization.Gauge(document.getElementById('chart_div1'));
  chart.draw(data, options);
}

function drawHumidityChart() {

  if(!_.has(google, 'visualization.arrayToDataTable') || !$.sensorData)
    return;

  var data = google.visualization.arrayToDataTable([
    ['Label', 'Value'],
    ['Humidity %', Number(_.get($.sensorData, 'DHT22.humidity', 0).toFixed(0))]
  ]);

  var options = {
    min         : 0,
    max         : 100,
    minorTicks  : 4,
    majorTicks  : ['0', '20', '40', '60', '80', '100']
  };

  var chart = new google.visualization.Gauge(document.getElementById('chart_div2'));
  chart.draw(data, options);
}

function drawPressureChart() {

  if(!_.has(google, 'visualization.arrayToDataTable') || !$.sensorData)
    return;

  var data = google.visualization.arrayToDataTable([
    ['Label', 'Value'],
    ['inHg', Number(_.get($.sensorData, 'BME280.pressure_inHg', 0).toFixed(2))]
  ]);

  var options = {
    min        : 27.8,
    max        : 31.2,
    minorTicks : 4,
    majorTicks : ['Stormy', 'Rain', 'Change', 'Fair', 'Dry']
  };

  var chart = new google.visualization.Gauge(document.getElementById('chart_div3'));
  chart.draw(data, options);
}

<commit_msg>Google Graphs slow to load, deal with it<commit_after>/*
  data-display.js

  Montor data stuff, draw data stuff.
*/

var map;
var marker;
var firstFix = true;
var mapReady = false;

function initMap() {

  map = new google.maps.Map(document.getElementById('map-canvas'), {
    center : { lat : 37.444795, lng : -122.165146 },
    zoom : 4
  });

  // TODO: These listeners are a hack to get the map to initially display until I come
  // back to work on this. May have something to do with the fact that '#map-canvas' has
  // size (0,0) when initMap is called. Fix layout!
  //
  google.maps.event.addListenerOnce(map, 'idle', function() {
    google.maps.event.trigger(map, 'resize');
  });

  google.maps.event.addListenerOnce(map, 'projection_changed', function() {
    google.maps.event.trigger(map, 'resize');
  });

  google.maps.event.addListenerOnce(map, 'tilesloaded', function() {
    mapReady = true;
  });
}

function initCharts() {
  google.charts.load('current', {'packages':['gauge']});
  google.charts.setOnLoadCallback(drawCharts);

  (function pollSensors() {
    $.get(window.dataSourceUrl + '/sensors', function(data) {
      $.sensorData = data;

      drawCharts();

      if(map && google.maps && (_.get(data, 'GPS.lat') || _.get(data, 'GPS.lon'))) {

        var latlng = new google.maps.LatLng(data.GPS.lat, data.GPS.lon);

        // If this is our first good location, pan map to location. We'll do this only once
        // on first fix to allow the user to then pan/zoom as they desire.
        //
        if(mapReady && firstFix) {
          firstFix = false;
          map.setZoom(16);
          map.panTo(latlng);
        }

        // Position marker at the latest location
        //
        if(marker) {
          marker.setPosition(latlng);
        }
        else {
          marker = new google.maps.Marker({
            position : latlng,
            map : map,
            title : ''
          });
        }
      }

      $('#raw-data-json').text(JSON.stringify(data, null, 2));
      setTimeout(pollSensors, 1000);
    }).
    fail(function() {
      setTimeout(pollSensors, 1000);
    });
  })();
}

function drawCharts() {
  drawTemperatureChart();
  drawHumidityChart();
  drawPressureChart();
}

function drawTemperatureChart() {

  if(!_.has(google, 'visualization.arrayToDataTable') || !_.has(google, 'visualization.Gauge') || !$.sensorData)
    return;

  var data = google.visualization.arrayToDataTable([
    ['Label', 'Value'],
    ['Temp F ', Number(_.get($.sensorData, 'DHT22.temperature_F', 0).toFixed(0))]
  ]);

  var options = {
    min         : 0,
    max         : 120,
    yellowFrom  : 70,
    yellowTo    : 90,
    redFrom     : 90,
    redTo       : 200,
    minorTicks  : 4,
    majorTicks  : ['0', '20', '40', '60', '80', '100', '120']
  };

  var chart = new google.visualization.Gauge(document.getElementById('chart_div1'));
  chart.draw(data, options);
}

function drawHumidityChart() {

  if(!_.has(google, 'visualization.arrayToDataTable') || !_.has(google, 'visualization.Gauge') || !$.sensorData)
    return;

  var data = google.visualization.arrayToDataTable([
    ['Label', 'Value'],
    ['Humidity %', Number(_.get($.sensorData, 'DHT22.humidity', 0).toFixed(0))]
  ]);

  var options = {
    min         : 0,
    max         : 100,
    minorTicks  : 4,
    majorTicks  : ['0', '20', '40', '60', '80', '100']
  };

  var chart = new google.visualization.Gauge(document.getElementById('chart_div2'));
  chart.draw(data, options);
}

function drawPressureChart() {

  if(!_.has(google, 'visualization.arrayToDataTable') || !_.has(google, 'visualization.Gauge') || !$.sensorData)
    return;

  var data = google.visualization.arrayToDataTable([
    ['Label', 'Value'],
    ['inHg', Number(_.get($.sensorData, 'BME280.pressure_inHg', 0).toFixed(2))]
  ]);

  var options = {
    min        : 27.8,
    max        : 31.2,
    minorTicks : 4,
    majorTicks : ['Stormy', 'Rain', 'Change', 'Fair', 'Dry']
  };

  var chart = new google.visualization.Gauge(document.getElementById('chart_div3'));
  chart.draw(data, options);
}

<|endoftext|>


<commit_before>import {Observable} from 'rx';
import {div} from '@cycle/dom';
import _ from 'lodash';
import $ from 'jquery';
import { Graph, astar } from 'javascript-astar';

import validateBoard from './validate-board';
import LetterBag from './letter-bag';
import distance from './distance';

const board = _.range(0, 15).map(() =>
  _.range(0, 15).map(() => Tile())
);

board[7][7] = Tile({letter: '*'});

const bag = LetterBag();

const maxBaseHealth = 100;

const initialState = {
  board,
  hand: _.range(0, 10).map(() => Tile({letter: randomLetter()})),
  selectedTile: null,
  enemies: [],
  score: 0,
  draggingTile: null,
  mousePosition: {x: 0, y: 0}
};

function Tile ({active = false, letter = '', health = 100} = {}) {
  return {active, letter, health};
}

function renderTile (tile, baseHealth, coordinate) {
  const tileIsBase = tile.letter === '*';
  const position = coordinateToPosition(coordinate);

  let style = {
    top: position.y + 'px',
    left: position.x + 'px'
  };

  if (tileIsBase) {
    Object.assign(style, {background: `rgba(0, 0, 240, ${baseHealth / maxBaseHealth})`});
  }

  return (
    div(
      `.tile ${tile.letter === '' ? '' : '.active'} ${tile.active ? '.valid' : ''} ${tileIsBase ? '.base' : ''}`,
      {style},
      tile.letter
    )
  );
}

function renderDraggingTile (tile, mousePosition) {
  if (tile === null) { return }

  let style = {
    top: mousePosition.y + 'px',
    left: mousePosition.x + 'px',
    position: 'absolute'
  };

  return (
    div(
      `.tile ${tile.letter === '' ? '' : '.active'}`,
      {style, key: 8796}, //TODO: setup keys properly
      tile.letter
    )
  );
}

function renderRow (row, rowIndex, baseHealth) {
  return (
    div('.row', row.map((tile, column) => renderTile(tile, baseHealth, {row: rowIndex, column})))
  );
}

function renderBoard (board, baseHealth) {
  return (
    div('.board', board.map((row, rowIndex) => renderRow(row, rowIndex, baseHealth)))
  );
}

function renderHand (hand) {
  return (
    div('.hand', hand.map(renderTile))
  );
}

function renderEnemy (enemy) {
  const style = {
    position: 'absolute',
    left: enemy.x + 'px',
    top: enemy.y + 'px'
  };

  return (
    div('.enemy', {style})
  );
}

function renderEnemies (enemies) {
  return (
    div('.enemies', enemies.map(renderEnemy))
  );
}

function makeSelectHandTileReducer (event) {
  return function selectHandTile (state) {
    const selectedTileIndex = $(event.target).index();
    const tile = state.hand[selectedTileIndex];

    state.hand.splice(selectedTileIndex, 1);

    return Object.assign(
      {},
      state,
      {
        selectedTile: {location: 'hand', position: selectedTileIndex},
        draggingTile: tile
      }
    );
  };
}

function randomLetter () {
  return bag.draw();
}

function makeDragBoardTileReducer (e) {
  const column = $(e.target).index();
  const row = $(e.target).parent().index();

  return function dragBoardTile (state) {
    state.draggingTile = state.board[row][column];
    state.board[row][column] = Tile();

    return state
  }
}

function makePlaceTileReducer (event) {
  return function placeTile (state) {
    const {column, row} = positionToCoordinate(state.mousePosition);

    if (state.draggingTile === null) {
      return state;
    }

    if (state.draggingTile !== null && state.board[row][column].letter !== '') {
      state.hand.push(state.draggingTile)
      state.draggingTile = null
      return state;
    }

    state.board[row][column] = state.draggingTile;

    if (state.hand.length < 10) { // TODO: constantize hand length
      state.hand.push(Tile({letter: randomLetter()}));
    }

    return Object.assign(
      {},
      state,
      {
        enemies: updateEnemyPaths(state),
        board: validateBoard(state.board),
        selectedTile: null,
        draggingTile: null
      }
    );
  };
}

function moveTowards (enemy, targetPosition, deltaTime) {
  const speed = enemy.speed * deltaTime;

  const angle = Math.atan2(
    targetPosition.y - enemy.y,
    targetPosition.x - enemy.x
  );

  enemy.x = enemy.x + Math.cos(angle) * speed;
  enemy.y = enemy.y + Math.sin(angle) * speed;

  return enemy;
}

function base (board) {
  return board[7][7];
}

function moveEnemies (state, deltaTime, basePosition) {
  state.enemies.forEach(enemy => {
    if (enemy.path.length === 0) {
      base(state.board).health -= 0.5;

      return state;
    }

    const coordinate = enemy.path[0];
    const nodePosition = coordinateToPosition(coordinate);
    const tileAtNode = state.board[coordinate.row][coordinate.column];

    if (tileAtNode.active) {
      tileAtNode.health -= enemy.damage * deltaTime;
      return;
    }

    if (distance(enemy, nodePosition) < 1) {
      enemy.path.shift();
    } else {
      moveTowards(enemy, nodePosition, deltaTime);
    }
  });

  return state;
}

// TODO - this probably belongs on the tile object
const TILE_RANGE = 100;
const TILE_DAMAGE = 0.5;
const TILE_WIDTH = 40;
const TILE_HEIGHT = 40;
const PADDING = 6;
const MARGIN = 30;

function coordinateToPosition ({row, column}) {
  return {
    x: column * (TILE_WIDTH + PADDING) + MARGIN,
    y: row * (TILE_HEIGHT + PADDING) + MARGIN
  };
}

function positionToCoordinate ({x, y}) {
  return {
    column: Math.floor((x - MARGIN) / (TILE_WIDTH + PADDING)),
    row: Math.floor((y - MARGIN) / (TILE_HEIGHT + PADDING))
  };
}

function targetAndShootEnemy (state, tile, coordinate) {
  if (!tile.active) {
    return;
  }

  const potentialTargets = state.enemies.filter(enemy => {
    const position = coordinateToPosition(coordinate);

    return distance(enemy, position) < TILE_RANGE;
  });

  if (potentialTargets.length > 0) {
    const enemy = potentialTargets[0];

    enemy.health -= TILE_DAMAGE;
  }
}

function shootAtEnemies (state, deltaTime, basePosition) {
  state.board.forEach((row, rowIndex) =>
    row.forEach((tile, column) =>
      targetAndShootEnemy(state, tile, {row: rowIndex, column})
    )
  );

  return state;
}

function removeDeadEnemies (state) {
  return Object.assign({}, state, {enemies: state.enemies.filter(enemy => enemy.health > 0)});
}

function removeDeadTiles (state) {
  let removedTileCount = 0;

  const board = state.board.map(row =>
    row.map(tile => {
      if (tile.active && tile.health < 0) {
        removedTileCount++;

        return Tile({health: 0});
      }

      return tile;
    })
  );

  if (removedTileCount > 0) {
    return Object.assign({}, state, {board: validateBoard(board), enemies: updateEnemyPaths(state)});
  }

  return Object.assign({}, state, {board});
}

function addScore (state, deltaTime) {
  if (base(state.board).health > 0) {
    state.score += deltaTime / 1000;
  }

  return state;
}

function makeUpdateReducer (deltaTime, basePosition) {
  return function update (startingState) {
    return [
      moveEnemies,
      shootAtEnemies,
      removeDeadEnemies,
      removeDeadTiles,
      addScore
    ].reduce((state, updater) => updater(state, deltaTime, basePosition), startingState);
  };
}

const POSITION_MIN = 0;
const POSITION_MAX = 14;

function enemySpawnCoordinate () {
  const randomPosition = _.random(POSITION_MIN, POSITION_MAX);

  const possibleSpawnPoints = [
    {column: randomPosition, row: POSITION_MIN},
    {column: randomPosition, row: POSITION_MAX},
    {column: POSITION_MIN, row: randomPosition},
    {column: POSITION_MAX, row: randomPosition}
  ];

  return _.sample(possibleSpawnPoints);
}

function calculateEnemyPath (position, state) {
  const graph = new Graph(state.board.map(row =>
      row.map(tile => tile.active ? 3 : 1)
    )
  );

  const start = graph.grid[position.row][position.column];
  // TODO constantize basePosition
  const end = graph.grid[7][7];

  let result;

  try {
    result = astar
      .search(graph, start, end)
      .map(node => ({row: node.x, column: node.y}));
  } catch (e) {
    console.error(e);
    debugger;
  }

  return result;
}

function updateEnemyPaths (state) {
  return state.enemies.map(enemy => {
    return Object.assign({}, enemy, {path: calculateEnemyPath(positionToCoordinate(enemy), state).slice(1)});
  });
}

function makeSpawnEnemiesReducer () {
  return function spawnEnemies (state) {
    const spawnCoordinate = enemySpawnCoordinate();
    const position = coordinateToPosition(spawnCoordinate);

    state.enemies.push({
      x: position.x,
      y: position.y,
      health: 30,
      damage: 0.1,
      speed: 0.03,
      path: calculateEnemyPath(spawnCoordinate, state)
    });

    return state;
  };
}

function makeUpdateMousePositionReducer (mousePosition) {
  return function updateMousePosition (state) {
    return Object.assign({}, state, {mousePosition})
  }
}

function mousePosition (e, gamePosition) {
  return {
    x: e.clientX - gamePosition.left,
    y: e.clientY - gamePosition.top
  }
}

export default function App ({DOM, animation}) {
  const selectHandTile$ = DOM
    .select('.hand .tile')
    .events('mousedown');

  const selectBoardTile$ = DOM
    .select('.board .tile')
    .events('mousedown');

  const dropTileOnBoard$ = DOM
    .select('.app *')
    .events('mouseup')

  const basePosition$ = DOM
    .select('.base')
    .observable
    .map(el => $(el).position())
    .take(1);

  const gamePosition$ = DOM
    .select('.game')
    .observable
    .map(el => $(el).position())
    .take(1);

  const mousePosition$ = DOM
    .select('.app *')
    .events('mousemove', true)
    .withLatestFrom(gamePosition$, mousePosition)

  const updateMousePosition$ = mousePosition$
    .map(position => makeUpdateMousePositionReducer(position))

  const placeTileReducer$ = dropTileOnBoard$
    .map(e => makePlaceTileReducer(e))

  const dragBoardTile$ = selectBoardTile$
    .map(e => makeDragBoardTileReducer(e));

  const selectHandTileReducer$ = selectHandTile$
    .map(e => makeSelectHandTileReducer(e));

  const update$ = animation.pluck('delta')
    .withLatestFrom(basePosition$, (deltaTime, basePosition) => makeUpdateReducer(deltaTime, basePosition));

  const spawnEnemyReducer$ = Observable.generateWithRelativeTime(
      1,
      () => true,
      (i) => i + 1,
      (i) => i,
      (i) => {
        console.log(i);
        const pauseFromWave = i % 2 !== 0;

        if (pauseFromWave) {
          console.log('pause duration', 10000 * (1 + i / 5));
          return 10000 * (1 + i / 7);
        }

        return 10000;
      }
    )
    .flatMapLatest(i => {
      const pauseFromWave = i % 2 === 0;

      console.log('starting wave', i, pauseFromWave ? 'pause' : 'attack!');

      if (pauseFromWave) {
        return Observable.empty();
      }

      console.log('attack freq', 10000 / Math.pow((Math.sin(i * 0.28) * 8 + i * 2), 1.3));
      return Observable.interval(10000 / Math.pow((Math.sin(i * 0.28) * 8 + i * 2), 1.3));
    })
    .startWith('go!')
    .map(e => makeSpawnEnemiesReducer());

  const reducer$ = Observable.merge(
    selectHandTileReducer$,
    placeTileReducer$,
    update$,
    spawnEnemyReducer$,
    updateMousePosition$,
    dragBoardTile$
  );

  const state$ = reducer$
    .startWith(initialState)
    .scan((state, reducer) => reducer(state))
    .distinctUntilChanged(JSON.stringify)

  return {
    DOM: state$.map(({board, hand, selectedTile, enemies, score, draggingTile, mousePosition}) => (
      div('.game', [
        renderHand(hand),
        div('.score', `Score: ${Math.round(score)}`),
        renderBoard(board, base(board).health),
        renderEnemies(enemies),
        div('.selected-tile-info',  JSON.stringify(selectedTile)),
        div('.game-over', base(board).health <= 0 ? 'Game over!' : ''),
        renderDraggingTile(draggingTile, mousePosition)
      ])
    ))
  };
}
<commit_msg>Display health for all tiles<commit_after>import {Observable} from 'rx';
import {div} from '@cycle/dom';
import _ from 'lodash';
import $ from 'jquery';
import { Graph, astar } from 'javascript-astar';

import validateBoard from './validate-board';
import LetterBag from './letter-bag';
import distance from './distance';

const board = _.range(0, 15).map(() =>
  _.range(0, 15).map(() => Tile())
);

board[7][7] = Tile({letter: '*'});

const bag = LetterBag();

const maxBaseHealth = 100;

const initialState = {
  board,
  hand: _.range(0, 10).map(() => Tile({letter: randomLetter()})),
  selectedTile: null,
  enemies: [],
  score: 0,
  draggingTile: null,
  mousePosition: {x: 0, y: 0}
};

function Tile ({active = false, letter = '', health = 100, maxHealth = 100} = {}) {
  return {active, letter, health, maxHealth};
}

function renderTile (tile, baseHealth, coordinate) {
  const tileIsBase = tile.letter === '*';
  const position = coordinateToPosition(coordinate);

  let style = {
    top: position.y + 'px',
    left: position.x + 'px'
  };

  if (tile.letter !== '') {
    style.opacity = tile.health / tile.maxHealth
  }

  if (tileIsBase) {
    Object.assign(style, {background: `rgb(0, 0, 240)`});
  }

  return (
    div(
      `.tile ${tile.letter === '' ? '' : '.active'} ${tile.active ? '.valid' : ''} ${tileIsBase ? '.base' : ''}`,
      {style},
      tile.letter
    )
  );
}

function renderDraggingTile (tile, mousePosition) {
  if (tile === null) { return }

  let style = {
    top: mousePosition.y + 'px',
    left: mousePosition.x + 'px',
    position: 'absolute'
  };

  if (tile.letter !== '') {
    style.opacity = tile.health / tile.maxHealth
  }

  return (
    div(
      `.tile ${tile.letter === '' ? '' : '.active'}`,
      {style, key: 8796}, //TODO: setup keys properly
      tile.letter
    )
  );
}

function renderRow (row, rowIndex, baseHealth) {
  return (
    div('.row', row.map((tile, column) => renderTile(tile, baseHealth, {row: rowIndex, column})))
  );
}

function renderBoard (board, baseHealth) {
  return (
    div('.board', board.map((row, rowIndex) => renderRow(row, rowIndex, baseHealth)))
  );
}

function renderHand (hand) {
  return (
    div('.hand', hand.map(renderTile))
  );
}

function renderEnemy (enemy) {
  const style = {
    position: 'absolute',
    left: enemy.x + 'px',
    top: enemy.y + 'px'
  };

  return (
    div('.enemy', {style})
  );
}

function renderEnemies (enemies) {
  return (
    div('.enemies', enemies.map(renderEnemy))
  );
}

function makeSelectHandTileReducer (event) {
  return function selectHandTile (state) {
    const selectedTileIndex = $(event.target).index();
    const tile = state.hand[selectedTileIndex];

    state.hand.splice(selectedTileIndex, 1);

    return Object.assign(
      {},
      state,
      {
        selectedTile: {location: 'hand', position: selectedTileIndex},
        draggingTile: tile
      }
    );
  };
}

function randomLetter () {
  return bag.draw();
}

function makeDragBoardTileReducer (e) {
  const column = $(e.target).index();
  const row = $(e.target).parent().index();

  return function dragBoardTile (state) {
    state.draggingTile = state.board[row][column];
    state.board[row][column] = Tile();

    return state
  }
}

function makePlaceTileReducer (event) {
  return function placeTile (state) {
    const {column, row} = positionToCoordinate(state.mousePosition);

    if (state.draggingTile === null) {
      return state;
    }

    if (state.draggingTile !== null && state.board[row][column].letter !== '') {
      state.hand.push(state.draggingTile)
      state.draggingTile = null
      return state;
    }

    state.board[row][column] = state.draggingTile;

    if (state.hand.length < 10) { // TODO: constantize hand length
      state.hand.push(Tile({letter: randomLetter()}));
    }

    return Object.assign(
      {},
      state,
      {
        enemies: updateEnemyPaths(state),
        board: validateBoard(state.board),
        selectedTile: null,
        draggingTile: null
      }
    );
  };
}

function moveTowards (enemy, targetPosition, deltaTime) {
  const speed = enemy.speed * deltaTime;

  const angle = Math.atan2(
    targetPosition.y - enemy.y,
    targetPosition.x - enemy.x
  );

  enemy.x = enemy.x + Math.cos(angle) * speed;
  enemy.y = enemy.y + Math.sin(angle) * speed;

  return enemy;
}

function base (board) {
  return board[7][7];
}

function moveEnemies (state, deltaTime, basePosition) {
  state.enemies.forEach(enemy => {
    if (enemy.path.length === 0) {
      base(state.board).health -= 0.5;

      return state;
    }

    const coordinate = enemy.path[0];
    const nodePosition = coordinateToPosition(coordinate);
    const tileAtNode = state.board[coordinate.row][coordinate.column];

    if (tileAtNode.active) {
      tileAtNode.health -= enemy.damage * deltaTime;
      return;
    }

    if (distance(enemy, nodePosition) < 1) {
      enemy.path.shift();
    } else {
      moveTowards(enemy, nodePosition, deltaTime);
    }
  });

  return state;
}

// TODO - this probably belongs on the tile object
const TILE_RANGE = 100;
const TILE_DAMAGE = 0.5;
const TILE_WIDTH = 40;
const TILE_HEIGHT = 40;
const PADDING = 6;
const MARGIN = 30;

function coordinateToPosition ({row, column}) {
  return {
    x: column * (TILE_WIDTH + PADDING) + MARGIN,
    y: row * (TILE_HEIGHT + PADDING) + MARGIN
  };
}

function positionToCoordinate ({x, y}) {
  return {
    column: Math.floor((x - MARGIN) / (TILE_WIDTH + PADDING)),
    row: Math.floor((y - MARGIN) / (TILE_HEIGHT + PADDING))
  };
}

function targetAndShootEnemy (state, tile, coordinate) {
  if (!tile.active) {
    return;
  }

  const potentialTargets = state.enemies.filter(enemy => {
    const position = coordinateToPosition(coordinate);

    return distance(enemy, position) < TILE_RANGE;
  });

  if (potentialTargets.length > 0) {
    const enemy = potentialTargets[0];

    enemy.health -= TILE_DAMAGE;
  }
}

function shootAtEnemies (state, deltaTime, basePosition) {
  state.board.forEach((row, rowIndex) =>
    row.forEach((tile, column) =>
      targetAndShootEnemy(state, tile, {row: rowIndex, column})
    )
  );

  return state;
}

function removeDeadEnemies (state) {
  return Object.assign({}, state, {enemies: state.enemies.filter(enemy => enemy.health > 0)});
}

function removeDeadTiles (state) {
  let removedTileCount = 0;

  const board = state.board.map(row =>
    row.map(tile => {
      if (tile.active && tile.health < 0) {
        removedTileCount++;

        return Tile({health: 0});
      }

      return tile;
    })
  );

  if (removedTileCount > 0) {
    return Object.assign({}, state, {board: validateBoard(board), enemies: updateEnemyPaths(state)});
  }

  return Object.assign({}, state, {board});
}

function addScore (state, deltaTime) {
  if (base(state.board).health > 0) {
    state.score += deltaTime / 1000;
  }

  return state;
}

function makeUpdateReducer (deltaTime, basePosition) {
  return function update (startingState) {
    return [
      moveEnemies,
      shootAtEnemies,
      removeDeadEnemies,
      removeDeadTiles,
      addScore
    ].reduce((state, updater) => updater(state, deltaTime, basePosition), startingState);
  };
}

const POSITION_MIN = 0;
const POSITION_MAX = 14;

function enemySpawnCoordinate () {
  const randomPosition = _.random(POSITION_MIN, POSITION_MAX);

  const possibleSpawnPoints = [
    {column: randomPosition, row: POSITION_MIN},
    {column: randomPosition, row: POSITION_MAX},
    {column: POSITION_MIN, row: randomPosition},
    {column: POSITION_MAX, row: randomPosition}
  ];

  return _.sample(possibleSpawnPoints);
}

function calculateEnemyPath (position, state) {
  const graph = new Graph(state.board.map(row =>
      row.map(tile => tile.active ? 3 : 1)
    )
  );

  const start = graph.grid[position.row][position.column];
  // TODO constantize basePosition
  const end = graph.grid[7][7];

  let result;

  try {
    result = astar
      .search(graph, start, end)
      .map(node => ({row: node.x, column: node.y}));
  } catch (e) {
    console.error(e);
    debugger;
  }

  return result;
}

function updateEnemyPaths (state) {
  return state.enemies.map(enemy => {
    return Object.assign({}, enemy, {path: calculateEnemyPath(positionToCoordinate(enemy), state).slice(1)});
  });
}

function makeSpawnEnemiesReducer () {
  return function spawnEnemies (state) {
    const spawnCoordinate = enemySpawnCoordinate();
    const position = coordinateToPosition(spawnCoordinate);

    state.enemies.push({
      x: position.x,
      y: position.y,
      health: 30,
      damage: 0.1,
      speed: 0.03,
      path: calculateEnemyPath(spawnCoordinate, state)
    });

    return state;
  };
}

function makeUpdateMousePositionReducer (mousePosition) {
  return function updateMousePosition (state) {
    return Object.assign({}, state, {mousePosition})
  }
}

function mousePosition (e, gamePosition) {
  return {
    x: e.clientX - gamePosition.left,
    y: e.clientY - gamePosition.top
  }
}

export default function App ({DOM, animation}) {
  const selectHandTile$ = DOM
    .select('.hand .tile')
    .events('mousedown');

  const selectBoardTile$ = DOM
    .select('.board .tile')
    .events('mousedown');

  const dropTileOnBoard$ = DOM
    .select('.app *')
    .events('mouseup')

  const basePosition$ = DOM
    .select('.base')
    .observable
    .map(el => $(el).position())
    .take(1);

  const gamePosition$ = DOM
    .select('.game')
    .observable
    .map(el => $(el).position())
    .take(1);

  const mousePosition$ = DOM
    .select('.app *')
    .events('mousemove', true)
    .withLatestFrom(gamePosition$, mousePosition)

  const updateMousePosition$ = mousePosition$
    .map(position => makeUpdateMousePositionReducer(position))

  const placeTileReducer$ = dropTileOnBoard$
    .map(e => makePlaceTileReducer(e))

  const dragBoardTile$ = selectBoardTile$
    .map(e => makeDragBoardTileReducer(e));

  const selectHandTileReducer$ = selectHandTile$
    .map(e => makeSelectHandTileReducer(e));

  const update$ = animation.pluck('delta')
    .withLatestFrom(basePosition$, (deltaTime, basePosition) => makeUpdateReducer(deltaTime, basePosition));

  const spawnEnemyReducer$ = Observable.generateWithRelativeTime(
      1,
      () => true,
      (i) => i + 1,
      (i) => i,
      (i) => {
        console.log(i);
        const pauseFromWave = i % 2 !== 0;

        if (pauseFromWave) {
          console.log('pause duration', 10000 * (1 + i / 5));
          return 10000 * (1 + i / 7);
        }

        return 10000;
      }
    )
    .flatMapLatest(i => {
      const pauseFromWave = i % 2 === 0;

      console.log('starting wave', i, pauseFromWave ? 'pause' : 'attack!');

      if (pauseFromWave) {
        return Observable.empty();
      }

      console.log('attack freq', 10000 / Math.pow((Math.sin(i * 0.28) * 8 + i * 2), 1.3));
      return Observable.interval(10000 / Math.pow((Math.sin(i * 0.28) * 8 + i * 2), 1.3));
    })
    .startWith('go!')
    .map(e => makeSpawnEnemiesReducer());

  const reducer$ = Observable.merge(
    selectHandTileReducer$,
    placeTileReducer$,
    update$,
    spawnEnemyReducer$,
    updateMousePosition$,
    dragBoardTile$
  );

  const state$ = reducer$
    .startWith(initialState)
    .scan((state, reducer) => reducer(state))
    .distinctUntilChanged(JSON.stringify)

  return {
    DOM: state$.map(({board, hand, selectedTile, enemies, score, draggingTile, mousePosition}) => (
      div('.game', [
        renderHand(hand),
        div('.score', `Score: ${Math.round(score)}`),
        renderBoard(board, base(board).health),
        renderEnemies(enemies),
        div('.selected-tile-info',  JSON.stringify(selectedTile)),
        div('.game-over', base(board).health <= 0 ? 'Game over!' : ''),
        renderDraggingTile(draggingTile, mousePosition)
      ])
    ))
  };
}
<|endoftext|>


<commit_before>var eviltransform = require('eviltransform');

function gll2ll(gll, gcj02) {
  var ll;
  if (!gll) {
    return;
  }
  ll = [gll.lng(), gll.lat()];
  if (!(gcj02 && this.isGCJ02(ll))) {
    return ll;
  }
  ll = eviltransform.gcj2wgs(ll[1], ll[0]);
  return [ll.lng, ll.lat];
}

function ll2gll(ll, gcj02) {
  var LatLng = gm().LatLng;
  if (!(gcj02 && this.isGCJ02(ll))) {
    return new LatLng(ll[1], ll[0]);
  }
  ll = eviltransform.wgs2gcj(ll[1], ll[0]);
  return new LatLng(ll.lat, ll.lng);
}

function bounds2gbounds(b, gcj02) {
  var LatLngBounds = gm().LatLngBounds;
  b = b.map(function (ll) {
    return ll2gll.call(this, ll, gcj02);
  }, this);
  return new LatLngBounds(b[0], b[1]);
}

function gbounds2bounds(gb, gcj02) {
  return gb && [
    gb.getSouthWest(),
    gb.getNorthEast()
  ].map(function (gll) {
    return gll2ll.call(this, gll, gcj02);
  }, this);
}

function decodePath(path) {
  return gm().geometry.encoding.decodePath(path);
}

function path2gpath(path, gcj02) {
  if (path.gmPath) {
    path = path.gmPath;
  }
  else if (Array.isArray(path)) {
    if (Array.isArray(path[0])) {
      path = path.gmPath = path.map(function (ll) {
        return ll2gll(ll, gcj02);
      });
    }
  }
  else if (typeof path === 'string') {
    path = decodePath(path);
  }
  return path;
}

function gm() {
  if (!window.google || !window.google.maps) {
    throw 'Google Maps not initialized properly: call maps.init()';
  }
  return window.google.maps;
}

module.exports = {
  decodePath: decodePath,
  gll2ll: gll2ll,
  ll2gll: ll2gll,
  bounds2gbounds: bounds2gbounds,
  gbounds2bounds: gbounds2bounds,
  path2gpath: path2gpath,
  gm: gm
};<commit_msg>fix checking coordinates in China<commit_after>var eviltransform = require('eviltransform');

function gll2ll(gll, gcj02) {
  var ll;
  if (!gll) {
    return;
  }
  ll = [gll.lng(), gll.lat()];
  if (!(gcj02 && this.isGCJ02(ll))) {
    return ll;
  }
  ll = eviltransform.gcj2wgs(ll[1], ll[0]);
  return [ll.lng, ll.lat];
}

function ll2gll(ll, gcj02) {
  var LatLng = gm().LatLng;
  if (!(gcj02 && this.isGCJ02(ll))) {
    return new LatLng(ll[1], ll[0]);
  }
  ll = eviltransform.wgs2gcj(ll[1], ll[0]);
  return new LatLng(ll.lat, ll.lng);
}

function bounds2gbounds(b, gcj02) {
  var LatLngBounds = gm().LatLngBounds;
  b = b.map(function (ll) {
    return ll2gll.call(this, ll, gcj02);
  }, this);
  return new LatLngBounds(b[0], b[1]);
}

function gbounds2bounds(gb, gcj02) {
  return gb && [
    gb.getSouthWest(),
    gb.getNorthEast()
  ].map(function (gll) {
    return gll2ll.call(this, gll, gcj02);
  }, this);
}

function decodePath(path) {
  return gm().geometry.encoding.decodePath(path);
}

function path2gpath(path, gcj02) {
  if (path.gmPath) {
    path = path.gmPath;
  }
  else if (Array.isArray(path)) {
    if (Array.isArray(path[0])) {
      path = path.gmPath = path.map(function (ll) {
        return ll2gll.call(this, ll, gcj02);
      }, this);
    }
  }
  else if (typeof path === 'string') {
    path = decodePath(path);
  }
  return path;
}

function gm() {
  if (!window.google || !window.google.maps) {
    throw 'Google Maps not initialized properly: call maps.init()';
  }
  return window.google.maps;
}

module.exports = {
  decodePath: decodePath,
  gll2ll: gll2ll,
  ll2gll: ll2gll,
  bounds2gbounds: bounds2gbounds,
  gbounds2bounds: gbounds2bounds,
  path2gpath: path2gpath,
  gm: gm
};<|endoftext|>