canvasengine 2.0.0-beta.2 → 2.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/index.d.ts +1285 -0
  2. package/dist/index.js +4150 -0
  3. package/dist/index.js.map +1 -0
  4. package/index.d.ts +4 -0
  5. package/package.json +5 -12
  6. package/src/components/Canvas.ts +53 -45
  7. package/src/components/Container.ts +2 -2
  8. package/src/components/DOMContainer.ts +229 -0
  9. package/src/components/DisplayObject.ts +263 -189
  10. package/src/components/Graphic.ts +213 -36
  11. package/src/components/Mesh.ts +222 -0
  12. package/src/components/NineSliceSprite.ts +4 -1
  13. package/src/components/ParticleEmitter.ts +12 -8
  14. package/src/components/Sprite.ts +77 -14
  15. package/src/components/Text.ts +34 -14
  16. package/src/components/Video.ts +110 -0
  17. package/src/components/Viewport.ts +59 -43
  18. package/src/components/index.ts +5 -4
  19. package/src/components/types/DisplayObject.ts +30 -0
  20. package/src/directives/Drag.ts +357 -52
  21. package/src/directives/KeyboardControls.ts +3 -1
  22. package/src/directives/Sound.ts +94 -31
  23. package/src/directives/ViewportFollow.ts +35 -7
  24. package/src/engine/animation.ts +41 -5
  25. package/src/engine/bootstrap.ts +13 -2
  26. package/src/engine/directive.ts +2 -2
  27. package/src/engine/reactive.ts +336 -168
  28. package/src/engine/trigger.ts +65 -9
  29. package/src/engine/utils.ts +92 -9
  30. package/src/hooks/useProps.ts +1 -1
  31. package/src/index.ts +5 -1
  32. package/src/utils/RadialGradient.ts +29 -0
  33. package/src/utils/functions.ts +7 -0
  34. package/testing/index.ts +12 -0
  35. package/src/components/DrawMap/index.ts +0 -65
  36. package/src/components/Tilemap/Tile.ts +0 -79
  37. package/src/components/Tilemap/TileGroup.ts +0 -207
  38. package/src/components/Tilemap/TileLayer.ts +0 -163
  39. package/src/components/Tilemap/TileSet.ts +0 -41
  40. package/src/components/Tilemap/index.ts +0 -80
@@ -1,22 +1,25 @@
1
- import { Node } from "yoga-layout";
2
1
  import { Element, isElement, Props } from "../engine/reactive";
3
2
  import { setObservablePoint } from "../engine/utils";
4
3
  import type {
5
4
  AlignContent,
6
5
  EdgeSize,
7
6
  FlexDirection,
8
- Size,
7
+ ObjectFit,
8
+ ObjectPosition,
9
+ TransformOrigin,
9
10
  } from "./types/DisplayObject";
10
- import { effect, Signal, signal } from "@signe/reactive";
11
- import { DropShadowFilter } from "pixi-filters";
11
+ import { signal } from "@signe/reactive";
12
12
  import { BlurFilter, ObservablePoint } from "pixi.js";
13
+ import * as FILTERS from "pixi-filters";
14
+ import { isPercent } from "../utils/functions";
15
+ import { BehaviorSubject, filter, Subject } from "rxjs";
13
16
 
14
17
  export interface ComponentInstance extends PixiMixins.ContainerOptions {
15
18
  id?: string;
16
19
  children?: ComponentInstance[];
17
20
  onInit?(props: Props): void;
18
21
  onUpdate?(props: Props): void;
19
- onDestroy?(parent: Element): void;
22
+ onDestroy?(parent: Element, afterDestroy: () => void): void;
20
23
  onMount?(context: Element, index?: number): void;
21
24
  setWidth(width: number): void;
22
25
  setHeight(height: number): void;
@@ -93,6 +96,8 @@ export const EVENTS = [
93
96
  "wheelcapture",
94
97
  ];
95
98
 
99
+ type OnHook = (() => void) | (() => Promise<void> | void);
100
+
96
101
  export function DisplayObject(extendClass) {
97
102
  return class DisplayObject extends extendClass {
98
103
  #canvasContext: {
@@ -101,26 +106,27 @@ export function DisplayObject(extendClass) {
101
106
  isFlex: boolean = false;
102
107
  fullProps: Props = {};
103
108
  isMounted: boolean = false;
104
- _anchorPoints = new ObservablePoint(
105
- { _onUpdate: () => {} },
106
- 0,
107
- 0
108
- );
109
+ _anchorPoints = new ObservablePoint({ _onUpdate: () => {} }, 0, 0);
109
110
  isCustomAnchor: boolean = false;
110
111
  displayWidth = signal(0);
111
112
  displayHeight = signal(0);
112
113
  overrideProps: string[] = [];
113
- node: Node;
114
-
115
- get yoga() {
116
- return this.#canvasContext?.Yoga;
117
- }
114
+ layout = null;
115
+ onBeforeDestroy: OnHook | null = null;
116
+ onAfterMount: OnHook | null = null;
117
+ subjectInit = new BehaviorSubject(null);
118
+ disableLayout: boolean = false;
118
119
 
119
120
  get deltaRatio() {
120
121
  return this.#canvasContext?.scheduler?.tick.value.deltaRatio;
121
122
  }
122
123
 
123
- onInit(props) {
124
+ get parentIsFlex() {
125
+ if (this.disableLayout) return false;
126
+ return this.parent?.isFlex;
127
+ }
128
+
129
+ onInit(props: Props) {
124
130
  this._id = props.id;
125
131
  for (let event of EVENTS) {
126
132
  if (props[event] && !this.overrideProps.includes(event)) {
@@ -128,90 +134,62 @@ export function DisplayObject(extendClass) {
128
134
  this.on(event, props[event]);
129
135
  }
130
136
  }
137
+ if (props.onBeforeDestroy || props['on-before-destroy']) {
138
+ this.onBeforeDestroy = props.onBeforeDestroy || props['on-before-destroy'];
139
+ }
140
+ if (props.onAfterMount || props['on-after-mount']) {
141
+ this.onAfterMount = props.onAfterMount || props['on-after-mount'];
142
+ }
143
+ if (
144
+ props.justifyContent ||
145
+ props.alignItems ||
146
+ props.flexDirection ||
147
+ props.flexWrap ||
148
+ props.alignContent ||
149
+ props.display == "flex" ||
150
+ isPercent(props.width) ||
151
+ isPercent(props.height) ||
152
+ props.isRoot
153
+ ) {
154
+ this.layout = {};
155
+ this.isFlex = true;
156
+ }
157
+
158
+ this.subjectInit.next(this);
131
159
  }
132
160
 
133
- onMount({ parent, props }: Element<DisplayObject>, index?: number) {
161
+ async onMount({ parent, props }: Element<DisplayObject>, index?: number) {
134
162
  this.#canvasContext = props.context;
135
- this.node = this.yoga.Node.create();
136
163
  if (parent) {
137
164
  const instance = parent.componentInstance as DisplayObject;
165
+ if (instance.isFlex && !this.layout && !this.disableLayout) {
166
+ try {
167
+ this.layout = {};
168
+ } catch (error) {
169
+ console.warn('Failed to set layout:', error);
170
+ }
171
+ }
138
172
  if (index === undefined) {
139
173
  instance.addChild(this);
140
174
  } else {
141
175
  instance.addChildAt(this, index);
142
176
  }
143
- if (instance.layer) this.parentLayer = instance.layer;
144
177
  this.isMounted = true;
145
- this.effectSize(props.width, props.height);
146
178
  this.onUpdate(props);
147
- this.parent.node.insertChild(
148
- this.node,
149
- this.parent.node.getChildCount()
150
- );
151
- if (parent.props.flexDirection) {
152
- this.parent.node.calculateLayout();
153
- for (let child of this.parent.children) {
154
- const { left, top } = child.getComputedLayout();
155
- child.x = left;
156
- child.y = top;
157
- }
179
+ if (this.onAfterMount) {
180
+ await this.onAfterMount();
158
181
  }
159
-
160
- }
161
- }
162
-
163
- effectSize(width: Size, height: Size) {
164
- const handleSize = (
165
- size: Size,
166
- setter: (value: number) => void,
167
- parentSize: Signal<number>
168
- ) => {
169
- if (typeof size === "string" && size.endsWith("%")) {
170
- effect(() => {
171
- setter(parentSize() * (parseInt(size) / 100));
172
- if (this.isFlex) {
173
- this.#applyFlexLayout();
174
- }
175
- });
176
- } else {
177
- setter(+size);
178
- }
179
- };
180
-
181
- if (width != undefined)
182
- handleSize(width, this.setWidth.bind(this), this.parent.displayWidth);
183
- if (height != undefined)
184
- handleSize(
185
- height,
186
- this.setHeight.bind(this),
187
- this.parent.displayHeight
188
- );
189
- }
190
-
191
- #applyFlexLayout() {
192
- this.calculateLayout();
193
- for (let child of this.children) {
194
- const { left, top } = child.node.getComputedLayout();
195
- child.x = left;
196
- child.y = top;
197
- }
198
- }
199
-
200
- #flexRender(props) {
201
- if (!this.parent) return;
202
- if (props.flexDirection || props.justifyContent) {
203
- this.isFlex = true;
204
- this.#applyFlexLayout();
205
182
  }
206
183
  }
207
184
 
208
- onUpdate(props) {
185
+ onUpdate(props: Props) {
209
186
  this.fullProps = {
210
187
  ...this.fullProps,
211
188
  ...props,
212
189
  };
213
190
 
214
191
  if (!this.#canvasContext || !this.parent) return;
192
+
215
193
  if (props.x !== undefined) this.setX(props.x);
216
194
  if (props.y !== undefined) this.setY(props.y);
217
195
  if (props.scale !== undefined)
@@ -219,6 +197,28 @@ export function DisplayObject(extendClass) {
219
197
  if (props.anchor !== undefined && !this.isCustomAnchor) {
220
198
  setObservablePoint(this.anchor, props.anchor);
221
199
  }
200
+ if (props.width !== undefined) this.setWidth(props.width);
201
+ if (props.height !== undefined) this.setHeight(props.height);
202
+ if (props.minWidth !== undefined) this.setMinWidth(props.minWidth);
203
+ if (props.minHeight !== undefined) this.setMinHeight(props.minHeight);
204
+ if (props.maxWidth !== undefined) this.setMaxWidth(props.maxWidth);
205
+ if (props.maxHeight !== undefined) this.setMaxHeight(props.maxHeight);
206
+ if (props.aspectRatio !== undefined)
207
+ this.setAspectRatio(props.aspectRatio);
208
+ if (props.flexGrow !== undefined) this.setFlexGrow(props.flexGrow);
209
+ if (props.flexShrink !== undefined) this.setFlexShrink(props.flexShrink);
210
+ if (props.flexBasis !== undefined) this.setFlexBasis(props.flexBasis);
211
+ if (props.rowGap !== undefined) this.setRowGap(props.rowGap);
212
+ if (props.columnGap !== undefined) this.setColumnGap(props.columnGap);
213
+ if (props.top !== undefined) this.setTop(props.top);
214
+ if (props.left !== undefined) this.setLeft(props.left);
215
+ if (props.right !== undefined) this.setRight(props.right);
216
+ if (props.bottom !== undefined) this.setBottom(props.bottom);
217
+ if (props.objectFit !== undefined) this.setObjectFit(props.objectFit);
218
+ if (props.objectPosition !== undefined)
219
+ this.setObjectPosition(props.objectPosition);
220
+ if (props.transformOrigin !== undefined)
221
+ this.setTransformOrigin(props.transformOrigin);
222
222
  if (props.skew !== undefined) setObservablePoint(this.skew, props.skew);
223
223
  if (props.tint) this.tint = props.tint;
224
224
  if (props.rotation !== undefined) this.rotation = props.rotation;
@@ -243,23 +243,24 @@ export function DisplayObject(extendClass) {
243
243
  if (props.filters) this.filters = props.filters;
244
244
  if (props.maskOf) {
245
245
  if (isElement(props.maskOf)) {
246
- props.maskOf.componentInstance.mask = this;
246
+ props.maskOf.componentInstance.mask = this as any;
247
247
  }
248
248
  }
249
249
  if (props.blendMode) this.blendMode = props.blendMode;
250
250
  if (props.filterArea) this.filterArea = props.filterArea;
251
251
  const currentFilters = this.filters || [];
252
252
 
253
- if (props.shadow) {
254
- let dropShadowFilter = currentFilters.find(
255
- (filter) => filter instanceof DropShadowFilter
256
- );
257
- if (!dropShadowFilter) {
258
- dropShadowFilter = new DropShadowFilter();
259
- currentFilters.push(dropShadowFilter);
260
- }
261
- Object.assign(dropShadowFilter, props.shadow);
262
- }
253
+ // TODO: Fix DropShadowFilter import issue
254
+ // if (props.shadow) {
255
+ // let dropShadowFilter = currentFilters.find(
256
+ // (filter) => filter instanceof FILTERS.DropShadowFilter
257
+ // );
258
+ // if (!dropShadowFilter) {
259
+ // dropShadowFilter = new FILTERS.DropShadowFilter();
260
+ // currentFilters.push(dropShadowFilter);
261
+ // }
262
+ // Object.assign(dropShadowFilter, props.shadow);
263
+ // }
263
264
 
264
265
  if (props.blur) {
265
266
  let blurFilter = currentFilters.find(
@@ -279,73 +280,34 @@ export function DisplayObject(extendClass) {
279
280
  }
280
281
 
281
282
  this.filters = currentFilters;
282
-
283
- this.#flexRender(props);
284
283
  }
285
284
 
286
- onDestroy() {
285
+ async onDestroy(parent: Element, afterDestroy?: () => void) {
286
+ if (this.onBeforeDestroy) {
287
+ await this.onBeforeDestroy();
288
+ }
287
289
  super.destroy();
288
- this.node?.freeRecursive();
289
- }
290
-
291
- getComputedLayout() {
292
- return this.node.getComputedLayout();
293
- }
294
-
295
- applyComputedLayout() {
296
- const layout = this.getComputedLayout();
297
- this.x = layout.left;
298
- this.y = layout.top;
299
- }
300
-
301
- calculateLayout() {
302
- this.node.calculateLayout();
290
+ if (afterDestroy) afterDestroy();
303
291
  }
304
292
 
305
293
  setFlexDirection(direction: FlexDirection) {
306
- const mapping = {
307
- row: this.yoga.FLEX_DIRECTION_ROW,
308
- column: this.yoga.FLEX_DIRECTION_COLUMN,
309
- "row-reverse": this.yoga.FLEX_DIRECTION_ROW_REVERSE,
310
- "column-reverse": this.yoga.FLEX_DIRECTION_COLUMN_REVERSE,
311
- };
312
- this.node.setFlexDirection(mapping[direction]);
294
+ this.layout = { flexDirection: direction };
313
295
  }
314
296
 
315
297
  setFlexWrap(wrap: "wrap" | "nowrap" | "wrap-reverse") {
316
- const mapping = {
317
- wrap: this.yoga.WRAP_WRAP,
318
- nowrap: this.yoga.WRAP_NO_WRAP,
319
- "wrap-reverse": this.yoga.WRAP_WRAP_REVERSE,
320
- };
321
- this.node.setFlexWrap(mapping[wrap]);
322
- }
323
-
324
- #setAlign(methodName: string, align: AlignContent) {
325
- const mapping = {
326
- auto: this.yoga.ALIGN_AUTO,
327
- "flex-start": this.yoga.ALIGN_FLEX_START,
328
- "flex-end": this.yoga.ALIGN_FLEX_END,
329
- center: this.yoga.ALIGN_CENTER,
330
- stretch: this.yoga.ALIGN_STRETCH,
331
- baseline: this.yoga.ALIGN_BASELINE,
332
- "space-between": this.yoga.ALIGN_SPACE_BETWEEN,
333
- "space-around": this.yoga.ALIGN_SPACE_AROUND,
334
- };
335
- const method = (this.node as any)[methodName].bind(this.node);
336
- method(mapping[align]);
298
+ this.layout = { flexWrap: wrap };
337
299
  }
338
300
 
339
301
  setAlignContent(align: AlignContent) {
340
- this.#setAlign("setAlignContent", align);
302
+ this.layout = { alignContent: align };
341
303
  }
342
304
 
343
305
  setAlignSelf(align: AlignContent) {
344
- this.#setAlign("setAlignSelf", align);
306
+ this.layout = { alignSelf: align };
345
307
  }
346
308
 
347
309
  setAlignItems(align: AlignContent) {
348
- this.#setAlign("setAlignItems", align);
310
+ this.layout = { alignItems: align };
349
311
  }
350
312
 
351
313
  setJustifyContent(
@@ -356,95 +318,133 @@ export function DisplayObject(extendClass) {
356
318
  | "space-between"
357
319
  | "space-around"
358
320
  ) {
359
- const mapping = {
360
- "flex-start": this.yoga.JUSTIFY_FLEX_START,
361
- "flex-end": this.yoga.JUSTIFY_FLEX_END,
362
- center: this.yoga.JUSTIFY_CENTER,
363
- "space-between": this.yoga.JUSTIFY_SPACE_BETWEEN,
364
- "space-around": this.yoga.JUSTIFY_SPACE_AROUND,
365
- };
366
- this.node.setJustifyContent(mapping[justifyContent]);
367
- }
368
-
369
- #setEdgeSize(methodName: string, size: EdgeSize) {
370
- const method = (this.node as any)[methodName].bind(this.node);
371
- if (size instanceof Array) {
372
- if (size.length === 2) {
373
- method(this.yoga.EDGE_VERTICAL, size[0]);
374
- method(this.yoga.EDGE_HORIZONTAL, size[1]);
375
- } else if (size.length === 4) {
376
- method(this.yoga.EDGE_TOP, size[0]);
377
- method(this.yoga.EDGE_RIGHT, size[1]);
378
- method(this.yoga.EDGE_BOTTOM, size[2]);
379
- method(this.yoga.EDGE_LEFT, size[3]);
380
- }
381
- } else {
382
- method(this.yoga.EDGE_ALL, size);
383
- }
321
+ this.layout = { justifyContent };
384
322
  }
385
323
 
386
324
  setPosition(position: EdgeSize) {
387
- this.#setEdgeSize("setPosition", position);
325
+ if (position instanceof Array) {
326
+ if (position.length === 2) {
327
+ this.layout = {
328
+ positionY: position[0],
329
+ positionX: position[1],
330
+ };
331
+ } else if (position.length === 4) {
332
+ this.layout = {
333
+ positionTop: position[0],
334
+ positionRight: position[1],
335
+ positionBottom: position[2],
336
+ positionLeft: position[3],
337
+ };
338
+ }
339
+ } else {
340
+ this.layout = { position };
341
+ }
388
342
  }
389
343
 
390
344
  setX(x: number) {
391
345
  x = x + this.getWidth() * this._anchorPoints.x;
392
- if (!this.parent.isFlex) {
346
+ if (!this.parentIsFlex) {
347
+ this.x = x;
348
+ } else {
393
349
  this.x = x;
350
+ this.layout = { x };
394
351
  }
395
- this.node.setPosition(this.yoga.EDGE_LEFT, x);
396
352
  }
397
353
 
398
354
  setY(y: number) {
399
355
  y = y + this.getHeight() * this._anchorPoints.y;
400
- if (!this.parent.isFlex) {
356
+ if (!this.parentIsFlex) {
401
357
  this.y = y;
358
+ } else {
359
+ this.y = y;
360
+ this.layout = { y };
402
361
  }
403
- this.node.setPosition(this.yoga.EDGE_TOP, y);
404
362
  }
405
363
 
406
364
  setPadding(padding: EdgeSize) {
407
- this.#setEdgeSize("setPadding", padding);
365
+ if (padding instanceof Array) {
366
+ if (padding.length === 2) {
367
+ this.layout = {
368
+ paddingVertical: padding[0],
369
+ paddingHorizontal: padding[1],
370
+ };
371
+ } else if (padding.length === 4) {
372
+ this.layout = {
373
+ paddingTop: padding[0],
374
+ paddingRight: padding[1],
375
+ paddingBottom: padding[2],
376
+ paddingLeft: padding[3],
377
+ };
378
+ }
379
+ } else {
380
+ this.layout = { padding };
381
+ }
408
382
  }
409
383
 
410
384
  setMargin(margin: EdgeSize) {
411
- this.#setEdgeSize("setMargin", margin);
385
+ if (margin instanceof Array) {
386
+ if (margin.length === 2) {
387
+ this.layout = {
388
+ marginVertical: margin[0],
389
+ marginHorizontal: margin[1],
390
+ };
391
+ } else if (margin.length === 4) {
392
+ this.layout = {
393
+ marginTop: margin[0],
394
+ marginRight: margin[1],
395
+ marginBottom: margin[2],
396
+ marginLeft: margin[3],
397
+ };
398
+ }
399
+ } else {
400
+ this.layout = { margin };
401
+ }
412
402
  }
413
403
 
414
404
  setGap(gap: EdgeSize) {
415
- this.node.setGap(this.yoga.GAP_ALL, +gap);
405
+ this.layout = { gap };
416
406
  }
417
407
 
418
408
  setBorder(border: EdgeSize) {
419
- this.#setEdgeSize("setBorder", border);
409
+ if (border instanceof Array) {
410
+ if (border.length === 2) {
411
+ this.layout = {
412
+ borderVertical: border[0],
413
+ borderHorizontal: border[1],
414
+ };
415
+ } else if (border.length === 4) {
416
+ this.layout = {
417
+ borderTop: border[0],
418
+ borderRight: border[1],
419
+ borderBottom: border[2],
420
+ borderLeft: border[3],
421
+ };
422
+ }
423
+ } else {
424
+ this.layout = { border };
425
+ }
420
426
  }
421
427
 
422
428
  setPositionType(positionType: "relative" | "absolute") {
423
- const mapping = {
424
- relative: this.yoga.POSITION_TYPE_RELATIVE,
425
- absolute: this.yoga.POSITION_TYPE_ABSOLUTE,
426
- };
427
- this.node.setPositionType(mapping[positionType]);
428
- }
429
-
430
- calculateBounds() {
431
- super.calculateBounds();
432
- if (!this._geometry) return;
433
- const bounds = this._geometry.bounds;
434
- const width = Math.abs(bounds.minX - bounds.maxX);
435
- const height = Math.abs(bounds.minY - bounds.maxY);
436
- // this.node.setWidth(width);
437
- // this.node.setHeight(height);
429
+ this.layout = { position: positionType };
438
430
  }
439
431
 
440
432
  setWidth(width: number) {
441
433
  this.displayWidth.set(width);
442
- this.node?.setWidth(width);
434
+ if (!this.parentIsFlex) {
435
+ this.width = width;
436
+ } else {
437
+ this.layout = { width };
438
+ }
443
439
  }
444
440
 
445
441
  setHeight(height: number) {
446
442
  this.displayHeight.set(height);
447
- this.node?.setHeight(height);
443
+ if (!this.parentIsFlex) {
444
+ this.height = height;
445
+ } else {
446
+ this.layout = { height };
447
+ }
448
448
  }
449
449
 
450
450
  getWidth() {
@@ -454,5 +454,79 @@ export function DisplayObject(extendClass) {
454
454
  getHeight() {
455
455
  return this.displayHeight();
456
456
  }
457
+
458
+ // Min/Max constraints
459
+ setMinWidth(minWidth: number | string) {
460
+ this.layout = { minWidth };
461
+ }
462
+
463
+ setMinHeight(minHeight: number | string) {
464
+ this.layout = { minHeight };
465
+ }
466
+
467
+ setMaxWidth(maxWidth: number | string) {
468
+ this.layout = { maxWidth };
469
+ }
470
+
471
+ setMaxHeight(maxHeight: number | string) {
472
+ this.layout = { maxHeight };
473
+ }
474
+
475
+ // Aspect ratio
476
+ setAspectRatio(aspectRatio: number) {
477
+ this.layout = { aspectRatio };
478
+ }
479
+
480
+ // Flex properties
481
+ setFlexGrow(flexGrow: number) {
482
+ this.layout = { flexGrow };
483
+ }
484
+
485
+ setFlexShrink(flexShrink: number) {
486
+ this.layout = { flexShrink };
487
+ }
488
+
489
+ setFlexBasis(flexBasis: number | string) {
490
+ this.layout = { flexBasis };
491
+ }
492
+
493
+ // Gap properties
494
+ setRowGap(rowGap: number) {
495
+ this.layout = { rowGap };
496
+ }
497
+
498
+ setColumnGap(columnGap: number) {
499
+ this.layout = { columnGap };
500
+ }
501
+
502
+ // Position insets
503
+ setTop(top: number | string) {
504
+ this.layout = { top };
505
+ }
506
+
507
+ setLeft(left: number | string) {
508
+ this.layout = { left };
509
+ }
510
+
511
+ setRight(right: number | string) {
512
+ this.layout = { right };
513
+ }
514
+
515
+ setBottom(bottom: number | string) {
516
+ this.layout = { bottom };
517
+ }
518
+
519
+ // Object properties
520
+ setObjectFit(objectFit: ObjectFit) {
521
+ this.layout = { objectFit };
522
+ }
523
+
524
+ setObjectPosition(objectPosition: ObjectPosition) {
525
+ this.layout = { objectPosition };
526
+ }
527
+
528
+ setTransformOrigin(transformOrigin: TransformOrigin) {
529
+ this.layout = { transformOrigin };
530
+ }
457
531
  };
458
532
  }