text: /**
   * The stars in our starfield!
   * Stars coordinate system is relative to the CENTER of the canvas
   * @param  {number} x
   * @param  {number} y
   */
  var Star = function (x, y, maxSpeed) {
    this.x = x
    this.y = y
    this.slope = y / x // This only works because our origin is always (0,0)
    this.opacity = 0
    this.speed = Math.max(Math.random() * maxSpeed, 1)
  }
  
  /**
   * Compute the distance of this star relative to any other point in space.
   *
   * @param  {int} originX
   * @param  {int} originY
   *
   * @return {float} The distance of this star to the given origin
   */
  Star.prototype.distanceTo = function (originX, originY) {
    return Math.sqrt(
      Math.pow(originX - this.x, 2) + Math.pow(originY - this.y, 2)
    )
  }
  
  /**
   * Reinitializes this star's attributes, without re-creating it
   *
   * @param  {number} x
   * @param  {number} y
   *
   * @return {Star} this star
   */
  Star.prototype.resetPosition = function (x, y, maxSpeed) {
    Star.apply(this, arguments)
    return this
  }
  
  /**
   * The BigBang factory creates stars (Should be called StarFactory, but that is
   * a WAY LESS COOL NAME!
   * @type {Object}
   */
  var BigBang = {
    /**
     * Returns a random star within a region of the space.
     *
     * @param  {number} minX minimum X coordinate of the region
     * @param  {number} minY minimum Y coordinate of the region
     * @param  {number} maxX maximum X coordinate of the region
     * @param  {number} maxY maximum Y coordinate of the region
     *
     * @return {Star} The random star
     */
    getRandomStar: function (minX, minY, maxX, maxY, maxSpeed) {
      var coords = BigBang.getRandomPosition(minX, minY, maxX, maxY)
      return new Star(coords.x, coords.y, maxSpeed)
    },
  
    /**
     * Gets a random (x,y) position within a bounding box
     *
     *
     * @param  {number} minX minimum X coordinate of the region
     * @param  {number} minY minimum Y coordinate of the region
     * @param  {number} maxX maximum X coordinate of the region
     * @param  {number} maxY maximum Y coordinate of the region
     *
     * @return {Object} An object with random {x, y} positions
     */
    getRandomPosition: function (minX, minY, maxX, maxY) {
      return {
        x: Math.floor(Math.random() * maxX + minX),
        y: Math.floor(Math.random() * maxY + minY)
      }
    }
  }
  
  /**
   * Constructor function of our starfield. This just prepares the DOM nodes where
   * the scene will be rendered.
   *
   * @param {string} canvasId The DOM Id of the <div> containing a <canvas> tag
   */
  var StarField = function (containerId) {
    this.container = document.getElementById(containerId)
    this.canvasElem = this.container.getElementsByTagName('canvas')[0]
    this.canvas = this.canvasElem.getContext('2d')
  
    this.width = this.container.offsetWidth
    this.height = this.container.offsetHeight
  
    this.starField = []
  }
  
  /**
   * Updates the properties for every star for the next frame to be rendered
   */
  StarField.prototype._updateStarField = function () {
    var i, star, randomLoc, increment
  
    for (i = 0; i < this.numStars; i++) {
      star = this.starField[i]
  
      increment = Math.min(star.speed, Math.abs(star.speed / star.slope))
      star.x += star.x > 0 ? increment : -increment
      star.y = star.slope * star.x
  
      star.opacity += star.speed / 100
  
      // Recycle star obj if it goes out of the frame
      if (
        Math.abs(star.x) > this.width / 2 ||
        Math.abs(star.y) > this.height / 2
      ) {
        // randomLoc = BigBang.getRandomPosition(
        //    -this.width / 2, -this.height / 2,
        //       this.width, this.height
        // );
        randomLoc = BigBang.getRandomPosition(
          -this.width / 10,
          -this.height / 10,
          this.width / 5,
          this.height / 5
        )
        star.resetPosition(randomLoc.x, randomLoc.y, this.maxStarSpeed)
      }
    }
  }
  
  /**
   * Renders the whole starfield (background + stars)
   * This method could be made more efficient by just blipping each star,
   * and not redrawing the whole frame
   */
  StarField.prototype._renderStarField = function () {
    var i, star
    // Background
    this.canvas.fillStyle = 'rgba(0, 0, 0, .5)'
    this.canvas.fillRect(0, 0, this.width, this.height)
    // Stars
    for (i = 0; i < this.numStars; i++) {
      star = this.starField[i]
      this.canvas.fillStyle = 'rgba(188, 213, 236, ' + star.opacity + ')'
      this.canvas.fillRect(
        star.x + this.width / 2,
        star.y + this.height / 2,
        2,
        2
      )
    }
  }
  
  /**
   * Function that handles the animation of each frame. Update the starfield
   * positions and re-render
   */
  StarField.prototype._renderFrame = function (elapsedTime) {
    var timeSinceLastFrame = elapsedTime - (this.prevFrameTime || 0)
  
    window.requestAnimationFrame(this._renderFrame.bind(this))
  
    // Skip frames unless at least 30ms have passed since the last one
    // (Cap to ~30fps)
    if (timeSinceLastFrame >= 30 || !this.prevFrameTime) {
      this.prevFrameTime = elapsedTime
      this._updateStarField()
      this._renderStarField()
    }
  }
  
  /**
   * Makes sure that the canvas size fits the size of its container
   */
  StarField.prototype._adjustCanvasSize = function (width, height) {
    // Set the canvas size to match the container ID (and cache values)
    this.width = this.canvasElem.width = width || this.container.offsetWidth
    this.height = this.canvasElem.height = height || this.container.offsetHeight
  }
  
  /**
   * This listener compares the old container size with the new one, and caches
   * the new values.
   */
  StarField.prototype._watchCanvasSize = function (elapsedTime) {
    // eslint-disable-next-line one-var
    var timeSinceLastCheck = elapsedTime - (this.prevCheckTime || 0),
      width,
      height
  
    window.requestAnimationFrame(this._watchCanvasSize.bind(this))
  
    // Skip frames unless at least 333ms have passed since the last check
    // (Cap to ~3fps)
    if (timeSinceLastCheck >= 333 || !this.prevCheckTime) {
      this.prevCheckTime = elapsedTime
      width = this.container.offsetWidth
      height = this.container.offsetHeight
      if (this.oldWidth !== width || this.oldHeight !== height) {
        this.oldWidth = width
        this.oldHeight = height
        this._adjustCanvasSize(width, height)
      }
    }
  }
  
  /**
   * Initializes the scene by resizing the canvas to the appropiate value, and
   * sets up the main loop.
   * @param {int} numStars Number of stars in our starfield
   */
  StarField.prototype._initScene = function (numStars) {
    var i
    for (i = 0; i < this.numStars; i++) {
      this.starField.push(
        BigBang.getRandomStar(
          -this.width / 2,
          -this.height / 2,
          this.width,
          this.height,
          this.maxStarSpeed
        )
      )
    }
  
    // Intervals not stored because I don't plan to detach them later...
    window.requestAnimationFrame(this._renderFrame.bind(this))
    window.requestAnimationFrame(this._watchCanvasSize.bind(this))
  }
  
  /**
   * Kicks off everything!
   * @param {int} numStars The number of stars to render
   * @param {int} maxStarSpeed Maximum speed of the stars (pixels / frame)
   */
  StarField.prototype.render = function (numStars, maxStarSpeed) {
    this.numStars = numStars || 100
    this.maxStarSpeed = maxStarSpeed || 3
  
    this._initScene(this.numStars)
  }
  
  /**
   * requestAnimationFrame shim layer with setTimeout fallback
   * @see http://paulirish.com/2011/requestanimationframe-for-smart-animating
   */
  ;(function () {
    var lastTime = 0
    var vendors = ['ms', 'moz', 'webkit', 'o']
    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
      window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']
      window.cancelAnimationFrame =
        window[vendors[x] + 'CancelAnimationFrame'] ||
        window[vendors[x] + 'CancelRequestAnimationFrame']
    }
  
    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = function (callback, element) {
        var currTime = new Date().getTime()
        var timeToCall = Math.max(0, 16 - (currTime - lastTime))
        var id = window.setTimeout(function () {
          // eslint-disable-next-line standard/no-callback-literal
          callback(currTime + timeToCall)
        }, timeToCall)
        lastTime = currTime + timeToCall
        return id
      }
    }
  
    if (!window.cancelAnimationFrame) {
      window.cancelAnimationFrame = function (id) {
        clearTimeout(id)
      }
    }
  })()
  
  // Kick off!
  // var starField = new StarField('fullScreen').render(333, 3);
  
  export { StarField }
  