File size: 4,142 Bytes
8a37e0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import type { Logger } from 'roarr';
import type { JsonObject } from 'type-fest';

/**
 * Base class for all canvas modules.
 */
export abstract class CanvasModuleBase {
  /**
   * The type of the module.
   */
  abstract readonly type: string;
  /**
   * The unique identifier of the module.
   *
   * If the module is associated with an entity, this should be the entity's id. Otherwise, the id should be based on
   * the module's type. The `getPrefixedId` utility should be used for generating ids.
   *
   * @example
   * ```ts
   * this.id = getPrefixedId(this.type);
   * // this.id -> "raster_layer:aS2NREsrlz"
   * ```
   */
  abstract readonly id: string;
  /**
   * The path of the module in the canvas module tree.
   *
   * Modules should use the manager's `buildPath` method to set this value.
   *
   * @example
   * ```ts
   * this.path = this.manager.buildPath(this);
   * // this.path -> ["manager:3PWJWmHbou", "raster_layer:aS2NREsrlz", "entity_renderer:sfLO4j1B0n", "brush_line:Zrsu8gpZMd"]
   * ```
   */
  abstract readonly path: string[];
  /**
   * The parent module. This may be the canvas manager or another module.
   */
  abstract readonly parent: CanvasModuleBase;
  /**
   * The canvas manager.
   */
  abstract readonly manager: CanvasManager;
  /**
   * The logger for the module. The logger must be a `ROARR` logger.
   *
   * Modules should use the manager's `buildLogger` method to set this value.
   *
   * @example
   * ```ts
   * this.log = this.manager.buildLogger(this);
   * ```
   */
  abstract readonly log: Logger;

  /**
   * An optional method that initializes the module. This method is called after all modules have been created.
   *
   * Use this method to perform any setup that requires all modules to be created. For example, setting some initial
   * state or doing an initial render.
   */
  initialize?: () => void = undefined;

  /**
   * Returns a logging context object that includes relevant information about the module.
   * Canvas modules may override this method to include additional information in the logging context, but should
   * always include the parent's logging context.
   *
   * The default implementation includes the parent context and the module's path as a string.
   *
   * @example
   * ```ts
   * getLoggingContext = () => {
   *   return {
   *     ...this.parent.getLoggingContext(),
   *     path: this.path.join(' > '),
   *     someImportantValue: this.someImportantValue,
   *   };
   * };
   * ```
   */
  getLoggingContext: () => JsonObject = () => {
    return {
      ...this.parent.getLoggingContext(),
      path: this.path.join(' > '),
    };
  };

  /**
   * Cleans up the module when it is disposed.
   *
   * Canvas modules may override this method to clean up any loose ends. For example:
   * - Destroy Konva nodes
   * - Unsubscribe from any subscriptions
   * - Abort async operations
   * - Close websockets
   * - Terminate workers
   *
   * This method is called when the module is disposed. For example:
   * - When an entity is deleted and its module is destroyed
   * - When the canvas manager is destroyed
   *
   * The default implementation only logs a message.
   *
   * @example
   * ```ts
   * destroy = () => {
   *  this.log('Destroying module');
   *  this.subscriptions.forEach((unsubscribe) => unsubscribe());
   *  this.subscriptions.clear();
   *  this.konva.group.destroy();
   * };
   * ```
   */
  destroy: () => void = () => {
    this.log('Destroying module');
  };

  /**
   * Returns a serializable representation of the module.
   * Canvas modules may override this method to include additional information in the representation.
   * The default implementation includes id, type, and path.
   *
   * @example
   * ```ts
   * repr = () => {
   *   return {
   *     id: this.id,
   *     type: this.type,
   *     path: this.path,
   *     state: deepClone(this.state),
   *   };
   * };
   * ```
   */
  repr: () => JsonObject = () => {
    return {
      id: this.id,
      type: this.type,
      path: this.path,
    };
  };
}