• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excaliburjs / Excalibur / 26011438031

18 May 2026 03:10AM UTC coverage: 88.074% (+0.01%) from 88.06%
26011438031

Pull #3747

github

web-flow
Merge d7c85637c into 326d08c95
Pull Request #3747: fix: Enhance pointer event handling by adding coordPlane check for graphics tracking, also added world to screen space conversion on pointer event check

5573 of 7711 branches covered (72.27%)

19 of 19 new or added lines in 3 files covered. (100.0%)

83 existing lines in 7 files now uncovered.

15235 of 17298 relevant lines covered (88.07%)

23989.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.89
/src/engine/entity-component-system/components/transform-component.ts
1
import type { Vector } from '../../math/vector';
2
import { CoordPlane } from '../../math/coord-plane';
3
import { Transform } from '../../math/transform';
4
import { Component } from '../component';
5
import type { Entity } from '../entity';
6
import { Observable } from '../../util/observable';
7
import { Logger } from '../../util/log';
8

9
// =============================================================
10
// Transform Component Serialization Data
11
// ============================================================
12

13
export interface TransformComponentData {
14
  type: string;
15
  pos: { x: number; y: number };
16
  rotation: number;
17
  scale: { x: number; y: number };
18
  z: number;
19
  coordPlane?: CoordPlane;
20
}
21

22
export class TransformComponent extends Component {
9,539✔
23
  // @ts-ignore
24
  private static _NAME = 'TransformComponent';
25
  private _logger = Logger.getInstance();
9,285✔
26
  private _parentComponent: TransformComponent | null = null;
9,285✔
27
  private _transform = new Transform();
9,285✔
28
  public get() {
29
    return this._transform;
16,148✔
30
  }
31

32
  private _addChildTransform = (child: Entity) => {
9,285✔
33
    const childTxComponent = child.get(TransformComponent);
2,925✔
34
    if (childTxComponent) {
2,925!
35
      childTxComponent._transform.parent = this._transform;
2,925✔
36
      childTxComponent._parentComponent = this;
2,925✔
37
    }
38
  };
39
  onAdd(owner: Entity): void {
40
    for (const child of owner.children) {
7,406✔
UNCOV
41
      this._addChildTransform(child);
×
42
    }
43
    owner.childrenAdded$.subscribe((child) => this._addChildTransform(child));
7,406✔
44
    owner.childrenRemoved$.subscribe((child) => {
7,406✔
45
      const childTxComponent = child.get(TransformComponent);
1✔
46
      if (childTxComponent) {
1!
47
        childTxComponent._transform.parent = null;
1✔
48
        childTxComponent._parentComponent = null;
1✔
49
      }
50
    });
51
  }
52
  onRemove(_previousOwner: Entity): void {
53
    this._transform.parent = null;
5✔
54
    this._parentComponent = null;
5✔
55
  }
56

57
  /**
58
   * Observable that emits when the z index changes on this component
59
   */
60
  public zIndexChanged$ = new Observable<number>();
9,285✔
61

62
  /**
63
   * The z-index ordering of the entity, a higher values are drawn on top of lower values.
64
   * For example z=99 would be drawn on top of z=0.
65
   */
66
  public get z(): number {
67
    return this._transform.z;
566✔
68
  }
69

70
  public set z(val: number) {
71
    const oldz = this._transform.z;
4,618✔
72
    this._transform.z = val;
4,618✔
73
    if (oldz !== val) {
4,618✔
74
      this.zIndexChanged$.notifyAll(val);
119✔
75
    }
76
  }
77

78
  public get globalZ() {
79
    return this._transform.globalZ;
5,306✔
80
  }
81

82
  public set globalZ(z: number) {
83
    this._transform.globalZ = z;
1✔
84
  }
85

86
  private _coordPlane = CoordPlane.World;
9,285✔
87
  /**
88
   * The {@apilink CoordPlane | `coordinate plane`} for this transform for the entity.
89
   */
90
  public get coordPlane() {
91
    if (this._parentComponent) {
17,876✔
92
      return this._parentComponent.coordPlane;
4,581✔
93
    }
94
    return this._coordPlane;
13,295✔
95
  }
96

97
  public set coordPlane(value: CoordPlane) {
98
    if (!this._parentComponent) {
944✔
99
      this._coordPlane = value;
943✔
100
    } else {
101
      this._logger.warn(
1✔
102
        `Cannot set coordinate plane on child entity ${this.owner?.name}, children inherit their coordinate plane from their parents.`
1!
103
      );
104
    }
105
  }
106

107
  get pos() {
108
    return this._transform.pos;
19,377✔
109
  }
110
  set pos(v: Vector) {
111
    this._transform.pos = v;
7,708✔
112
  }
113

114
  get globalPos() {
115
    return this._transform.globalPos;
5,461✔
116
  }
117
  set globalPos(v: Vector) {
118
    this._transform.globalPos = v;
110✔
119
  }
120

121
  get rotation() {
122
    return this._transform.rotation;
8,159✔
123
  }
124
  set rotation(rotation) {
125
    this._transform.rotation = rotation;
4,546✔
126
  }
127

128
  get globalRotation() {
129
    return this._transform.globalRotation;
451✔
130
  }
131
  set globalRotation(rotation) {
132
    this._transform.globalRotation = rotation;
105✔
133
  }
134

135
  get scale() {
136
    return this._transform.scale;
23,637✔
137
  }
138
  set scale(v: Vector) {
139
    this._transform.scale = v;
4,539✔
140
  }
141

142
  get globalScale() {
143
    return this._transform.globalScale;
1,226✔
144
  }
145
  set globalScale(v: Vector) {
146
    this._transform.globalScale = v;
2✔
147
  }
148

149
  applyInverse(v: Vector) {
150
    return this._transform.applyInverse(v);
72✔
151
  }
152

153
  apply(v: Vector) {
154
    return this._transform.apply(v);
324✔
155
  }
156

157
  clone(): TransformComponent {
158
    const component = new TransformComponent();
7✔
159
    component._transform = this._transform.clone();
7✔
160
    return component;
7✔
161
  }
162

163
  /**
164
   * Custom serialization - only store local transform values
165
   * Private fields (_transform, _parentComponent) are automatically excluded
166
   */
167
  public serialize(): TransformComponentData {
168
    const type = this.constructor.name;
3✔
169
    const data: TransformComponentData = {
3✔
170
      type,
171
      pos: { x: this.pos.x, y: this.pos.y },
172
      rotation: this.rotation,
173
      scale: { x: this.scale.x, y: this.scale.y },
174
      z: this.z
175
    };
176

177
    // Only serialize coordPlane if not inherited from parent
178
    if (!this._parentComponent) {
3!
179
      data.coordPlane = this._coordPlane;
3✔
180
    }
181

182
    return data;
3✔
183
  }
184

185
  /**
186
   * Restore state from serialized data
187
   */
188
  public deserialize(data: TransformComponentData): void {
189
    // Set local transform values
190
    this.pos = { x: data.pos.x, y: data.pos.y } as Vector;
×
191
    this.rotation = data.rotation;
×
UNCOV
192
    this.scale = { x: data.scale.x, y: data.scale.y } as Vector;
×
UNCOV
193
    this.z = data.z;
×
194

195
    // Only set coordPlane if provided (root entities only)
UNCOV
196
    if (data.coordPlane !== undefined && !this._parentComponent) {
×
UNCOV
197
      this._coordPlane = data.coordPlane;
×
198
    }
199
  }
200
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc