server/ServerItemGroup.js

  1. 'use strict';
  2. const { EventEmitter } = require('node:events');
  3. const { Message, Item } = require('../shared.js');
  4. const { Hittable, Identifiable } = require('../mixins.js');
  5. /**
  6. * HACK to get around jsdoc bug that causes mixed methods and properties to be
  7. * duplicated.
  8. *
  9. * @class __ServerItemGroup
  10. * @private
  11. * @mixes module:mixins.Hittable
  12. * @mixes module:mixins.Identifiable
  13. */
  14. /**
  15. * The ServerItemGroup provides operations for the server to locate and move
  16. * several different elements around.
  17. *
  18. * @memberof module:server
  19. * @extends module:shared.WamsElement
  20. * @extends __ServerItemGroup
  21. *
  22. * @param {Namespace} namespace - Socket.io namespace for publishing changes.
  23. * @param {Object} values - User-supplied data detailing the elements.
  24. * Properties on this object that line up with {@link module:shared.Element}
  25. * members will be stored. Any other properties will be ignored.
  26. */
  27. class ServerItemGroup extends Identifiable(Hittable(Item)) {
  28. constructor(namespace, values = {}) {
  29. super(values);
  30. /**
  31. * Socket.io namespace for publishing updates.
  32. *
  33. * @type {Namespace}
  34. */
  35. this.namespace = namespace;
  36. // Notify subscribers immediately.
  37. if (!this.items) throw Error('Items must be passed to ServerItemGroup.');
  38. // calculate based on elements positions;
  39. this.setMeasures();
  40. this.setParentForItems();
  41. }
  42. on(eventName, listener) {
  43. this.items.forEach((item) => {
  44. item.on(eventName, (event) => {
  45. event.target = this;
  46. return listener(event);
  47. });
  48. });
  49. }
  50. /*
  51. * Publish a general notification about the status of the group.
  52. */
  53. _emitPublication() {
  54. this.namespace.emit(Message.UD_ITEM, this);
  55. }
  56. moveTo(x, y) {
  57. const offsetX = x - this.x;
  58. const offsetY = y - this.y;
  59. this.x = x;
  60. this.y = y;
  61. this.items.forEach((item) => item.moveBy(offsetX, offsetY));
  62. }
  63. moveBy(dx, dy) {
  64. this.x = this.x + dx;
  65. this.y = this.y + dy;
  66. this.items.forEach((item) => item.moveBy(dx, dy));
  67. }
  68. /**
  69. * Update children items to have parent property.
  70. *
  71. */
  72. setParentForItems() {
  73. this.items.forEach((item) => {
  74. item.parent = this;
  75. this.namespace.emit(Message.SET_PARENT, { id: item.id, parent: this.id });
  76. });
  77. }
  78. setMeasures() {
  79. // calculate x, y, width and height
  80. // of the group
  81. let minX = Number.MAX_SAFE_INTEGER;
  82. let minY = Number.MAX_SAFE_INTEGER;
  83. let maxX = -Number.MAX_SAFE_INTEGER;
  84. let maxY = -Number.MAX_SAFE_INTEGER;
  85. this.items.forEach((el) => {
  86. minX = Math.min(minX, el.x);
  87. minY = Math.min(minY, el.y);
  88. maxX = Math.max(maxX, el.x + el.width);
  89. maxY = Math.max(maxY, el.y + el.height);
  90. });
  91. this.x = minX;
  92. this.y = minY;
  93. // this.width = maxX - minX;
  94. this.height = maxY - minY;
  95. }
  96. }
  97. Object.assign(ServerItemGroup.prototype, EventEmitter.prototype);
  98. module.exports = ServerItemGroup;