Source: skymap_page/ConstellationStar.js

/**
 * This class is intended for interactable stars, it takes the x and y for
 * the foreground star along with radius and color. It will draw a star
 * there, and it reacts to click captures.
 */
export class ConstellationStar {
  /**
   * Takes the x y for the foreground star, along with the radius for the star.
   * The selected state enables or disables the selected swelling animation, and
   * the swell ratio tells how much to swell by.
   * @param {CanvasRenderingContext2D} ctx canvas rendering context
   * @param {Number} x coordinate
   * @param {Number} y coordinate
   * @param {Number} radius star radius
   * @param {Boolean} selected if is selected
   * @param {Number} swell_ratio animated swelling radius
   * @param {String} color default color
   * @param {String} selected_color selected color
   * @param {Number} ratio aspect ratio
   */
  constructor(
    ctx,
    x,
    y,
    radius,
    selected,
    swell_ratio,
    color,
    selected_color,
    ratio
  ) {
    this.ctx = ctx;
    this.x = x;
    this.y = y;
    this.default_radius = radius;
    this.radius = radius;
    this.selected = selected;
    this.max_swell = this.radius * swell_ratio;
    this.dswell = 0.05;
    this.color = color;
    this.selected_color = selected_color;
    this.done = false;
    this.ratio = ratio;
  }

  /**
   * Draws the star based on current values and user_x and user_y
   * @param {Number} user_x user view offset
   * @param {Number} user_y user view offset
   */
  draw(user_x, user_y) {
    if (!this.selected) {
      this.ctx.strokeStyle = this.color;
      this.ctx.fillStyle = this.color;
    } else {
      this.ctx.strokeStyle = this.selected_color;
      this.ctx.fillStyle = this.selected_color;
    }
    this.ctx.beginPath();
    this.ctx.arc(
      this.x + user_x,
      this.y + user_y,
      this.radius,
      0,
      Math.PI * 2,
      false
    );
    this.ctx.fill();
    this.ctx.stroke();
  }

  /**
   * Draw a line between this star and the input star
   * @param {Number} user_x user view offset x
   * @param {Number} user_y user view offset y
   * @param {ConstellationStar} star stars to connect
   */
  connect(user_x, user_y, star) {
    this.ctx.beginPath();
    this.ctx.strokeStyle = "#16BDE5";
    this.ctx.moveTo(this.x + user_x, this.y + user_y);
    this.ctx.lineTo(star.x + user_x, star.y + user_y);
    this.ctx.stroke();
  }

  /**
   * Call with animation loop, updates the swell amount if it is selected
   * else set the swell to 0
   * @param {Number} user_x user view offset
   * @param {Number} user_y user view offset
   */
  update(user_x, user_y) {
    if (this.selected) {
      this.radius += this.dswell;
      if (this.radius > this.default_radius + this.max_swell) {
        this.dswell = -0.05;
      } else if (this.radius < this.default_radius - this.max_swell) {
        this.dswell = 0.05;
      }
    } else {
      this.radius = this.default_radius;
    }
    this.draw(user_x, user_y);
  }

  /**
   * Click event handler, if the click fell within the region of the circle
   * change its selected mode
   * @param {Number} x clicked coordinate
   * @param {Number} y clicked coordinate
   */
  click(x, y) {
    const isOnStar =
      (this.x - x) ** 2 + (this.y - y) ** 2 < (2 * this.default_radius) ** 2;
    if (isOnStar && !this.done) this.selected = !this.selected;
  }

  /**
   * @Property {Function} Getter for is selected
   */
  get isSelected() {
    return this.selected;
  }

  updateRatio(ratio) {
    this.x *= ratio / this.ratio;
    this.y *= ratio / this.ratio;
  }
}