server/ServerView.js

'use strict';

const { EventEmitter } = require('node:events');
const { IdStamper, Message, View } = require('../shared.js');
const { Interactable, Locker } = require('../mixins.js');

const SERVER_VIEW_IDS = new IdStamper();

/**
 * HACK to get around jsdoc bug that causes mixed methods and properties to be
 * duplicated.
 *
 * @class __ServerView
 * @private
 * @mixes module:mixins.Interactable
 * @mixes module:mixins.Locker
 */

/**
 * The ServerView models an attached client view in the browser.
 * rescale views.
 *
 * @memberof module:server
 * @extends module:shared.View
 * @extends __ServerView
 *
 * @param {Namespace} socket - Socket.io socket for publishing changes.
 * @param {Object} [ values ] - Object with user supplied values describing the
 * view.
 */
class ServerView extends Locker(Interactable(View)) {
  constructor(socket, values = {}) {
    super(values);

    /**
     * Socket.io socket for publishing changes.
     *
     * @type {Socket}
     */
    this.socket = socket;

    /**
     * The group that this view belongs to.
     *
     * @type {module:server.ServerViewGroup}
     * @default null
     */
    this.group = null;

    /**
     * The device corresponding to the client's device's physical orientation.
     *
     * @type {module:server.Device}
     */
    this.device = null;

    /**
     * A place for user to store view state.
     */
    this.state = {};

    /**
     * Id to make the views uniquely identifiable.
     *
     * @name id
     * @type {number}
     * @constant
     * @instance
     * @memberof module:server.ServerView
     */
    SERVER_VIEW_IDS.stampNewId(this);
  }

  /**
   * Get the position of the bottom left corner of this view.
   *
   * @type {module:shared.Point2D}
   */
  get bottomLeft() {
    return this.transformPoint(0, this.height);
  }

  /**
   * Get the position of the bottom right corner of this view.
   *
   * @type {module:shared.Point2D}
   */
  get bottomRight() {
    return this.transformPoint(this.width, this.height);
  }

  /**
   * Get the position of the top left corner of this view.
   *
   * @type {module:shared.Point2D}
   */
  get topLeft() {
    return this.transformPoint(0, 0);
  }

  /**
   * Get the position of the top right corner of this view.
   *
   * @type {module:shared.Point2D}
   */
  get topRight() {
    return this.transformPoint(this.width, 0);
  }

  /*
   * Publish the view, bringing subscribers up to date.
   *
   * @override
   */
  _emitPublication() {
    this.socket.broadcast.emit(Message.UD_SHADOW, this);
    this.socket.emit(Message.UD_VIEW, this);
  }

  /**
   * Send Message to this view to dispatch a user-defined event.
   *
   * @param {string} event name of the user-defined event.
   * @param {object} payload argument to pass to the event handler.
   */
  dispatch(action, payload) {
    console.debug(`dispatch: ${action} to View ${this.id}`);
    this.socket.emit(Message.DISPATCH, { action, payload });
  }

  /*
   * Scale the view by the given amount.
   *
   * @override
   */
  scaleBy(ds = 1, mx, my) {
    super.scaleBy(ds, mx, my, 'divideBy');
  }
}

Object.assign(ServerView.prototype, EventEmitter.prototype);

module.exports = ServerView;