@vpmedia/phaser 1.75.0 → 1.77.0

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 (93) hide show
  1. package/README.md +1 -1
  2. package/coverage/clover.xml +1089 -3
  3. package/coverage/coverage-final.json +19 -1
  4. package/coverage/lcov-report/core/const.js.html +901 -0
  5. package/coverage/lcov-report/core/index.html +116 -0
  6. package/coverage/lcov-report/geom/circle.js.html +1003 -0
  7. package/coverage/lcov-report/geom/ellipse.js.html +388 -0
  8. package/coverage/lcov-report/geom/index.html +221 -0
  9. package/coverage/lcov-report/geom/line.js.html +1102 -0
  10. package/coverage/lcov-report/geom/matrix.js.html +751 -0
  11. package/coverage/lcov-report/geom/point.js.html +1027 -0
  12. package/coverage/lcov-report/geom/polygon.js.html +604 -0
  13. package/coverage/lcov-report/geom/rectangle.js.html +1774 -0
  14. package/coverage/lcov-report/geom/rounded_rectangle.js.html +226 -0
  15. package/coverage/lcov-report/geom/util/circle.js.html +436 -0
  16. package/coverage/lcov-report/geom/util/ellipse.js.html +139 -0
  17. package/coverage/lcov-report/geom/util/index.html +221 -0
  18. package/coverage/lcov-report/geom/util/line.js.html +475 -0
  19. package/coverage/lcov-report/geom/util/matrix.js.html +223 -0
  20. package/coverage/lcov-report/geom/util/point.js.html +961 -0
  21. package/coverage/lcov-report/geom/util/polygon.js.html +124 -0
  22. package/coverage/lcov-report/geom/util/rectangle.js.html +784 -0
  23. package/coverage/lcov-report/geom/util/rounded_rectangle.js.html +136 -0
  24. package/coverage/lcov-report/index.html +70 -10
  25. package/coverage/lcov-report/util/index.html +116 -0
  26. package/coverage/lcov-report/util/math.js.html +958 -0
  27. package/coverage/lcov.info +2179 -0
  28. package/lefthook.yml +0 -4
  29. package/package.json +13 -15
  30. package/src/phaser/core/device_util.js +1 -0
  31. package/src/phaser/core/dom.js +1 -0
  32. package/src/phaser/core/game.js +4 -1
  33. package/src/phaser/core/input_handler.js +2 -2
  34. package/src/phaser/core/scene.js +3 -1
  35. package/src/phaser/core/signal.js +1 -1
  36. package/src/phaser/core/timer.js +1 -1
  37. package/src/phaser/display/canvas/util.js +1 -0
  38. package/src/phaser/display/display_object.js +2 -0
  39. package/src/phaser/display/text.js +34 -4
  40. package/src/phaser/display/webgl/render_texture.js +5 -4
  41. package/src/phaser/display/webgl/shader/complex.js +1 -0
  42. package/src/phaser/display/webgl/shader/fast.js +1 -0
  43. package/src/phaser/display/webgl/shader/normal.js +3 -0
  44. package/src/phaser/display/webgl/shader/primitive.js +1 -0
  45. package/src/phaser/display/webgl/shader/strip.js +1 -0
  46. package/src/phaser/display/webgl/shader_manager.js +1 -1
  47. package/src/phaser/display/webgl/texture.js +1 -1
  48. package/src/phaser/geom/circle.test.js +198 -0
  49. package/src/phaser/geom/ellipse.test.js +83 -0
  50. package/src/phaser/geom/line.test.js +112 -0
  51. package/src/phaser/geom/matrix.test.js +242 -0
  52. package/src/phaser/geom/point.test.js +209 -0
  53. package/src/phaser/geom/rectangle.test.js +460 -0
  54. package/src/phaser/geom/rounded_rectangle.test.js +63 -0
  55. package/src/phaser/geom/util/circle.test.js +29 -0
  56. package/src/phaser/geom/util/ellipse.js +1 -1
  57. package/src/phaser/geom/util/ellipse.test.js +8 -0
  58. package/src/phaser/geom/util/line.js +1 -1
  59. package/src/phaser/geom/util/line.test.js +11 -0
  60. package/src/phaser/geom/util/matrix.test.js +23 -0
  61. package/src/phaser/geom/util/point.js +1 -1
  62. package/src/phaser/geom/util/point.test.js +9 -0
  63. package/src/phaser/geom/util/polygon.test.js +13 -0
  64. package/src/phaser/geom/util/rectangle.test.js +11 -0
  65. package/src/phaser/geom/util/rounded_rectangle.test.js +12 -0
  66. package/src/phaser/util/math.test.js +187 -0
  67. package/types/phaser/core/device_util.d.ts.map +1 -1
  68. package/types/phaser/core/dom.d.ts.map +1 -1
  69. package/types/phaser/core/game.d.ts.map +1 -1
  70. package/types/phaser/core/scene.d.ts +3 -1
  71. package/types/phaser/core/scene.d.ts.map +1 -1
  72. package/types/phaser/core/signal.d.ts +1 -1
  73. package/types/phaser/core/signal.d.ts.map +1 -1
  74. package/types/phaser/core/timer.d.ts +1 -1
  75. package/types/phaser/core/timer.d.ts.map +1 -1
  76. package/types/phaser/display/canvas/util.d.ts.map +1 -1
  77. package/types/phaser/display/display_object.d.ts +2 -0
  78. package/types/phaser/display/display_object.d.ts.map +1 -1
  79. package/types/phaser/display/webgl/render_texture.d.ts.map +1 -1
  80. package/types/phaser/display/webgl/shader/complex.d.ts +1 -0
  81. package/types/phaser/display/webgl/shader/complex.d.ts.map +1 -1
  82. package/types/phaser/display/webgl/shader/fast.d.ts +1 -0
  83. package/types/phaser/display/webgl/shader/fast.d.ts.map +1 -1
  84. package/types/phaser/display/webgl/shader/normal.d.ts +3 -0
  85. package/types/phaser/display/webgl/shader/normal.d.ts.map +1 -1
  86. package/types/phaser/display/webgl/shader/primitive.d.ts +1 -0
  87. package/types/phaser/display/webgl/shader/primitive.d.ts.map +1 -1
  88. package/types/phaser/display/webgl/shader/strip.d.ts +1 -0
  89. package/types/phaser/display/webgl/shader/strip.d.ts.map +1 -1
  90. package/types/phaser/display/webgl/shader_manager.d.ts +7 -3
  91. package/types/phaser/display/webgl/shader_manager.d.ts.map +1 -1
  92. package/types/phaser/geom/util/ellipse.d.ts +1 -1
  93. package/types/phaser/geom/util/ellipse.d.ts.map +1 -1
package/lefthook.yml CHANGED
@@ -1,7 +1,3 @@
1
- # Copyright (c) Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
2
- # author: Andras Csizmadia <andras@vpmedia.hu>
3
- # see: https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md
4
-
5
1
  pre-commit:
6
2
  parallel: false
7
3
  commands:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vpmedia/phaser",
3
- "version": "1.75.0",
3
+ "version": "1.77.0",
4
4
  "description": "@vpmedia/phaser is the modern ECMAScript port of the popular Phaser game engine v2.6.2",
5
5
  "author": "Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)",
6
6
  "license": "MIT",
@@ -23,34 +23,32 @@
23
23
  "types": "./types/index.d.ts",
24
24
  "type": "module",
25
25
  "dependencies": {
26
- "@vpmedia/simplify": "^1.16.0",
27
- "uuid": "^11.0.3"
26
+ "@vpmedia/simplify": "^1.17.0",
27
+ "uuid": "^11.1.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@eslint/js": "^9.16.0",
30
+ "@eslint/js": "^9.21.0",
31
31
  "@jest/globals": "^29.7.0",
32
32
  "@types/jest": "^29.5.14",
33
- "eslint": "^9.16.0",
34
- "eslint-plugin-jsdoc": "^50.6.0",
35
- "eslint-plugin-unicorn": "^56.0.1",
36
- "globals": "^15.13.0",
33
+ "eslint": "^9.23.0",
34
+ "eslint-plugin-jsdoc": "^50.6.8",
35
+ "eslint-plugin-unicorn": "^57.0.0",
36
+ "globals": "^16.0.0",
37
37
  "jest": "^29.7.0",
38
38
  "jest-environment-jsdom": "^29.7.0",
39
- "lefthook": "^1.8.5",
40
- "prettier": "^3.4.1",
41
- "typescript": "^5.7.2"
39
+ "prettier": "^3.5.3",
40
+ "typescript": "^5.8.2"
42
41
  },
43
42
  "scripts": {
44
43
  "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests",
45
44
  "lint": "eslint \"**/*.{js,jsx}\"",
46
45
  "typecheck": "tsc",
47
- "format": "prettier --write \"./**/*.{js,jsx,mjs,cjs,ts,tsx,json,md,css}\"",
48
- "lefthook:install": "lefthook install",
49
- "lefthook:uninstall": "lefthook uninstall"
46
+ "format": "prettier --write \"./**/*.{js,jsx,mjs,cjs,ts,tsx,json,md,css}\""
50
47
  },
51
48
  "browserslist": [
52
49
  "> 0.5%",
53
50
  "not dead",
54
- "not op_mini all"
51
+ "not op_mini all",
52
+ "iOS >= 14"
55
53
  ]
56
54
  }
@@ -110,6 +110,7 @@ export const checkFullScreenSupport = (device) => {
110
110
  break;
111
111
  }
112
112
  }
113
+ // @ts-ignore
113
114
  if (window.Element && Element.ALLOW_KEYBOARD_INPUT) {
114
115
  device.fullscreenKeyboard = true;
115
116
  }
@@ -257,6 +257,7 @@ export class DOM {
257
257
  */
258
258
  getScreenOrientation(primaryFallback) {
259
259
  const screen = window.screen;
260
+ // @ts-ignore
260
261
  const orientation = screen.orientation || screen.mozOrientation || screen.msOrientation;
261
262
  if (orientation && typeof orientation.type === 'string') {
262
263
  // Screen Orientation API specification
@@ -126,7 +126,10 @@ export class Game {
126
126
  this.canvas = create(this, this.width, this.height, this.config.canvasID, true);
127
127
  }
128
128
  if (this.config.canvasStyle) {
129
- this.canvas.style = this.config.canvasStyle;
129
+ const properties = Object.keys(this.config.canvasStyle);
130
+ for (const property of properties) {
131
+ this.canvas.style[property] = this.config.canvasStyle[property];
132
+ }
130
133
  } else {
131
134
  this.canvas.style['-webkit-full-screen'] = 'width: 100%; height: 100%';
132
135
  }
@@ -284,7 +284,7 @@ export class InputHandler {
284
284
  if (!this.enabled) {
285
285
  return false;
286
286
  }
287
- if (pointerId === undefined) {
287
+ if (pointerId === undefined || pointerId === null) {
288
288
  for (let i = 0; i < 10; i += 1) {
289
289
  if (this._pointerData[i].isOver) {
290
290
  return true;
@@ -304,7 +304,7 @@ export class InputHandler {
304
304
  if (!this.enabled) {
305
305
  return false;
306
306
  }
307
- if (pointerId === undefined) {
307
+ if (pointerId === undefined || pointerId === null) {
308
308
  for (let i = 0; i < 10; i += 1) {
309
309
  if (this._pointerData[i].isOut) {
310
310
  return true;
@@ -37,8 +37,10 @@ export class Scene {
37
37
 
38
38
  /**
39
39
  * TBD.
40
+ * @param {number} width - TBD.
41
+ * @param {number} height - TBD.
40
42
  */
41
- resize() {
43
+ resize(width, height) {
42
44
  // inherit
43
45
  }
44
46
 
@@ -10,7 +10,7 @@ export class Signal {
10
10
  this.memorize = false;
11
11
  this._shouldPropagate = true;
12
12
  this.active = true;
13
- this._boundDispatch = false;
13
+ this._boundDispatch = null;
14
14
  }
15
15
 
16
16
  /**
@@ -96,7 +96,7 @@ export class Timer {
96
96
  * TBD.
97
97
  * @param {number} delay - TBD.
98
98
  */
99
- start(delay) {
99
+ start(delay = 0) {
100
100
  if (this.running) {
101
101
  return;
102
102
  }
@@ -42,6 +42,7 @@ export const setBackgroundColor = (canvas, color) => {
42
42
  */
43
43
  export const setTouchAction = (canvas, value = 'none') => {
44
44
  value = value || 'none';
45
+ // @ts-ignore
45
46
  canvas.style.msTouchAction = value;
46
47
  canvas.style['ms-touch-action'] = value;
47
48
  canvas.style['touch-action'] = value;
@@ -32,6 +32,8 @@ export class DisplayObject {
32
32
  this.cachedBounds = new Rectangle(0, 0, 0, 0);
33
33
  this.currentBounds = null;
34
34
  this._mask = null;
35
+ this._filters = null;
36
+ this._filterBlock = null;
35
37
  this.children = [];
36
38
  this.ignoreChildInput = false;
37
39
  }
@@ -153,7 +153,10 @@ export class Text extends Image {
153
153
  const lineWidths = [];
154
154
  let lineWidth = 0;
155
155
  let maxLineWidth = 0;
156
- const fontProperties = this.determineFontProperties(this.style.font);
156
+ let fontProperties = this.determineFontProperties(this.style.font);
157
+ if (!fontProperties.fontSize) {
158
+ fontProperties = this.determineFontPropertiesFallback(this.style.font);
159
+ }
157
160
  let drawnLines = lines.length;
158
161
  if (this.style.maxLines > 0 && this.style.maxLines < lines.length) {
159
162
  drawnLines = this.style.maxLines;
@@ -894,12 +897,37 @@ export class Text extends Image {
894
897
  return window.PhaserRegistry.fontPropertiesContext;
895
898
  }
896
899
 
900
+ /**
901
+ * TBD.
902
+ * @param {string} font - TBD.
903
+ * @returns {object} TBD.
904
+ */
905
+ determineFontProperties(font) {
906
+ const fontPropertiesCache = this.getFontPropertiesCache();
907
+ let properties = fontPropertiesCache[font];
908
+ if (properties) {
909
+ return properties;
910
+ }
911
+ const METRICS_STRING = '|ÉqÅ';
912
+ const BASELINE_SYMBOL = 'M';
913
+ /** @type {CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D} */
914
+ const context = this.getFontPropertiesContext();
915
+ context.font = font;
916
+ const metrics = context.measureText(METRICS_STRING + BASELINE_SYMBOL);
917
+ properties = {
918
+ ascent: Math.ceil(metrics.actualBoundingBoxAscent),
919
+ descent: Math.ceil(metrics.actualBoundingBoxDescent),
920
+ fontSize: Math.ceil(metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent),
921
+ };
922
+ return properties;
923
+ }
924
+
897
925
  /**
898
926
  * TBD.
899
927
  * @param {string} fontStyle - TBD.
900
928
  * @returns {object} TBD.
901
929
  */
902
- determineFontProperties(fontStyle) {
930
+ determineFontPropertiesFallback(fontStyle) {
903
931
  const fontPropertiesCache = this.getFontPropertiesCache();
904
932
  let properties = fontPropertiesCache[fontStyle];
905
933
  if (!properties) {
@@ -936,7 +964,8 @@ export class Text extends Image {
936
964
  // ascent. scan from top to bottom until we find a non red pixel
937
965
  for (i = 0; i < baseline; i += 1) {
938
966
  for (j = 0; j < line; j += 4) {
939
- if (imagedata[idx + j] !== 255) {
967
+ // firefox returns 253 for red pixel
968
+ if (imagedata[idx + j] < 253) {
940
969
  stop = true;
941
970
  break;
942
971
  }
@@ -953,7 +982,8 @@ export class Text extends Image {
953
982
  // descent. scan from bottom to top until we find a non red pixel
954
983
  for (i = height; i > baseline; i -= 1) {
955
984
  for (j = 0; j < line; j += 4) {
956
- if (imagedata[idx + j] !== 255) {
985
+ // firefox returns 253 for red pixel
986
+ if (imagedata[idx + j] < 253) {
957
987
  stop = true;
958
988
  break;
959
989
  }
@@ -1,10 +1,10 @@
1
- import { Rectangle } from '../../geom/rectangle.js';
1
+ import { RENDER_WEBGL } from '../../core/const.js';
2
2
  import { Point } from '../../geom/point.js';
3
- import { Texture } from './texture.js';
3
+ import { Rectangle } from '../../geom/rectangle.js';
4
+ import { CanvasBuffer } from '../canvas/buffer.js';
4
5
  import { BaseTexture } from './base_texture.js';
5
6
  import { FilterTexture } from './filter_texture.js';
6
- import { CanvasBuffer } from '../canvas/buffer.js';
7
- import { RENDER_WEBGL } from '../../core/const.js';
7
+ import { Texture } from './texture.js';
8
8
 
9
9
  export class RenderTexture extends Texture {
10
10
  /**
@@ -34,6 +34,7 @@ export class RenderTexture extends Texture {
34
34
  this.crop = new Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution);
35
35
  this.renderer = renderer;
36
36
  if (this.renderer.type === RENDER_WEBGL) {
37
+ // @ts-ignore
37
38
  const gl = this.renderer.gl;
38
39
  this.baseTexture._dirty[gl.id] = false;
39
40
  this.textureBuffer = new FilterTexture(gl, this.width, this.height, this.baseTexture.scaleMode);
@@ -11,6 +11,7 @@ export class ComplexPrimitiveShader {
11
11
  constructor(gl) {
12
12
  this.gl = gl;
13
13
  this._UID = uuidv4();
14
+ /** @type {WebGLProgram} */
14
15
  this.program = null;
15
16
  this.fragmentSrc = [
16
17
  'precision mediump float;',
@@ -11,6 +11,7 @@ export class FastShader {
11
11
  constructor(gl) {
12
12
  this.gl = gl;
13
13
  this._UID = uuidv4();
14
+ /** @type {WebGLProgram} */
14
15
  this.program = null;
15
16
  this.textureCount = 0;
16
17
  this.fragmentSrc = [
@@ -31,6 +31,7 @@ export class NormalShader {
31
31
  constructor(gl) {
32
32
  this.gl = gl;
33
33
  this._UID = uuidv4();
34
+ /** @type {WebGLProgram} */
34
35
  this.program = null;
35
36
  this.fragmentSrc = [
36
37
  'precision lowp float;',
@@ -41,6 +42,8 @@ export class NormalShader {
41
42
  ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
42
43
  '}',
43
44
  ];
45
+ /** @type {string[]} */
46
+ this.vertexSrc = null;
44
47
  this.textureCount = 0;
45
48
  this.firstRun = true;
46
49
  this.dirty = true;
@@ -11,6 +11,7 @@ export class PrimitiveShader {
11
11
  constructor(gl) {
12
12
  this.gl = gl;
13
13
  this._UID = uuidv4();
14
+ /** @type {WebGLProgram} */
14
15
  this.program = null;
15
16
  this.fragmentSrc = [
16
17
  'precision mediump float;',
@@ -11,6 +11,7 @@ export class StripShader {
11
11
  constructor(gl) {
12
12
  this.gl = gl;
13
13
  this._UID = uuidv4();
14
+ /** @type {WebGLProgram} */
14
15
  this.program = null;
15
16
  this.fragmentSrc = [
16
17
  'precision mediump float;',
@@ -26,7 +26,7 @@ export class WebGLShaderManager {
26
26
 
27
27
  /**
28
28
  * TBD.
29
- * @param {WebGLRenderingContext} gl - TBD.
29
+ * @param {WebGLRenderingContext & { id: number }} gl - TBD.
30
30
  */
31
31
  setContext(gl) {
32
32
  this.gl = gl;
@@ -30,7 +30,7 @@ export class Texture {
30
30
  this.noFrame = true;
31
31
  frame = new Rectangle(0, 0, 1, 1);
32
32
  }
33
- if (baseTexture && baseTexture.baseTexture) {
33
+ if (baseTexture instanceof Texture) {
34
34
  baseTexture = baseTexture.baseTexture;
35
35
  }
36
36
  this.baseTexture = baseTexture;
@@ -0,0 +1,198 @@
1
+ import { Circle } from './circle.js';
2
+ import { Point } from './point.js';
3
+
4
+ describe('Circle', () => {
5
+ describe('constructor', () => {
6
+ it('should initialize properties correctly when no arguments are provided', () => {
7
+ const circle = new Circle();
8
+ expect(circle.x).toBe(0);
9
+ expect(circle.y).toBe(0);
10
+ expect(circle.diameter).toBe(0);
11
+ });
12
+
13
+ it('should initialize properties correctly when x, y, and diameter are provided', () => {
14
+ const circle = new Circle(10, 20, 30);
15
+ expect(circle.x).toBe(10);
16
+ expect(circle.y).toBe(20);
17
+ expect(circle.diameter).toBe(30);
18
+ });
19
+ });
20
+
21
+ describe('circumference', () => {
22
+ it('should calculate the circumference correctly when diameter is provided', () => {
23
+ const circle = new Circle(0, 0, 1);
24
+ expect(circle.circumference()).toBeCloseTo(Math.PI);
25
+ });
26
+
27
+ it('should return Infinity when diameter is 0', () => {
28
+ const circle = new Circle();
29
+ circle.diameter = 0;
30
+ expect(circle.circumference()).toBe(0);
31
+ });
32
+ });
33
+
34
+ describe('random', () => {
35
+ it('should generate a random point within the circle correctly', () => {
36
+ const circle = new Circle();
37
+ const output = new Point();
38
+ circle.random(output);
39
+ expect(output.x).toBeGreaterThan(-1);
40
+ expect(output.y).toBeGreaterThan(-1);
41
+ expect(Math.hypot(output.x, output.y)).toBe(0);
42
+ });
43
+
44
+ it('should generate a random point within the circle correctly when output is not provided', () => {
45
+ const circle = new Circle();
46
+ const output = new Point();
47
+ circle.random(output);
48
+ expect(output.x).toBeGreaterThan(-1);
49
+ expect(output.y).toBeGreaterThan(-1);
50
+ expect(Math.hypot(output.x, output.y)).toBe(0);
51
+ });
52
+ });
53
+
54
+ describe('getBounds', () => {
55
+ it('should calculate the bounds correctly when diameter is provided', () => {
56
+ const circle = new Circle(0, 0, 1);
57
+ const bounds = circle.getBounds();
58
+ expect(bounds.x).toBe(-0.5);
59
+ expect(bounds.y).toBe(-0.5);
60
+ expect(bounds.width).toBe(1);
61
+ expect(bounds.height).toBe(1);
62
+ });
63
+
64
+ it('should return empty rectangle when diameter is 0', () => {
65
+ const circle = new Circle();
66
+ circle.diameter = 0;
67
+ const bounds = circle.getBounds();
68
+ expect(bounds.x).toBe(0);
69
+ expect(bounds.y).toBe(0);
70
+ expect(bounds.width).toBe(0);
71
+ expect(bounds.height).toBe(0);
72
+ });
73
+ });
74
+
75
+ describe('setTo', () => {
76
+ it('should set properties correctly when x, y, and diameter are provided', () => {
77
+ const circle = new Circle();
78
+ circle.setTo(10, 20, 30);
79
+ expect(circle.x).toBe(10);
80
+ expect(circle.y).toBe(20);
81
+ expect(circle.diameter).toBe(30);
82
+ });
83
+
84
+ it('should set radius property correctly when diameter is changed', () => {
85
+ const circle = new Circle();
86
+ circle.diameter = 1;
87
+ expect(circle.radius).toBe(0.5);
88
+ });
89
+ });
90
+
91
+ describe('copyFrom', () => {
92
+ it('should copy properties correctly from another Circle instance', () => {
93
+ const source = new Circle(10, 20, 30);
94
+ const dest = new Circle();
95
+ dest.copyFrom(source);
96
+ expect(dest.x).toBe(source.x);
97
+ expect(dest.y).toBe(source.y);
98
+ expect(dest.diameter).toBe(source.diameter);
99
+ });
100
+ });
101
+
102
+ describe('copyTo', () => {
103
+ it('should copy properties correctly to another Circle instance', () => {
104
+ const source = new Circle(10, 20, 30);
105
+ const dest = new Circle();
106
+ source.copyTo(dest);
107
+ expect(dest.x).toBe(source.x);
108
+ expect(dest.y).toBe(source.y);
109
+ expect(dest.diameter).toBe(source.diameter);
110
+ });
111
+ });
112
+
113
+ describe('distance', () => {
114
+ it('should calculate the distance correctly between two points within a circle', () => {
115
+ const circle = new Circle();
116
+ const point = new Point(1, 1);
117
+ expect(circle.distance(point)).toBeCloseTo(Math.hypot(point.x, point.y));
118
+ });
119
+
120
+ it('should return Infinity when diameter is 0', () => {
121
+ const circle = new Circle();
122
+ circle.diameter = 0;
123
+ expect(circle.distance(new Point(1, 1))).toBeCloseTo(1.4142);
124
+ });
125
+ });
126
+
127
+ describe('clone', () => {
128
+ it('should create a deep copy of the Circle instance correctly', () => {
129
+ const source = new Circle(10, 20, 30);
130
+ const clone = source.clone();
131
+ expect(clone.x).toBe(source.x);
132
+ expect(clone.y).toBe(source.y);
133
+ expect(clone.diameter).toBe(source.diameter);
134
+ });
135
+ });
136
+
137
+ describe('contains', () => {
138
+ it('should determine if a point is within the circle correctly', () => {
139
+ const circle = new Circle();
140
+ const point = new Point(1, 1);
141
+ expect(circle.contains(point.x, point.y)).toBe(false);
142
+ });
143
+
144
+ it('should return false when diameter is 0', () => {
145
+ const circle = new Circle();
146
+ circle.diameter = 0;
147
+ expect(circle.contains(1, 1)).toBe(false);
148
+ });
149
+ });
150
+
151
+ describe('circumferencePoint', () => {
152
+ it('should generate a point on the circumference correctly', () => {
153
+ const circle = new Circle();
154
+ const output = new Point();
155
+ expect(circle.circumferencePoint(Math.PI / 2).x).toBeCloseTo(0.5 * circle.radius);
156
+ });
157
+
158
+ it('should return null when diameter is 0', () => {
159
+ const circle = new Circle();
160
+ circle.diameter = 0;
161
+ expect(circle.circumferencePoint(Math.PI / 2).type).toBe(25);
162
+ });
163
+ });
164
+
165
+ describe('offset', () => {
166
+ it('should offset the circle correctly by a point', () => {
167
+ const circle = new Circle();
168
+ const point = new Point(1, 1);
169
+ circle.offset(point.x, point.y);
170
+ expect(circle.x).toBeGreaterThan(0);
171
+ expect(circle.y).toBeGreaterThan(0);
172
+ });
173
+
174
+ it('should return the Circle instance itself', () => {
175
+ const circle = new Circle();
176
+ const point = new Point(1, 1);
177
+ circle.offset(point.x, point.y);
178
+ expect(circle).toBe(circle);
179
+ });
180
+ });
181
+
182
+ describe('offsetPoint', () => {
183
+ it('should offset the circle correctly by a point', () => {
184
+ const circle = new Circle();
185
+ const point = new Point(1, 1);
186
+ circle.offsetPoint(point);
187
+ expect(circle.x).toBeGreaterThan(0);
188
+ expect(circle.y).toBeGreaterThan(0);
189
+ });
190
+ });
191
+
192
+ describe('toString', () => {
193
+ it('should generate the correct string representation of the Circle instance', () => {
194
+ const circle = new Circle();
195
+ expect(circle.toString()).toBe('[{Circle (x=0 y=0 diameter=0 radius=0)}]');
196
+ });
197
+ });
198
+ });
@@ -0,0 +1,83 @@
1
+ import { Ellipse } from './ellipse.js';
2
+
3
+ it('should create an ellipse with default values', () => {
4
+ const ellipse = new Ellipse();
5
+ expect(ellipse.x).toBe(0);
6
+ expect(ellipse.y).toBe(0);
7
+ expect(ellipse.width).toBe(0);
8
+ expect(ellipse.height).toBe(0);
9
+ });
10
+
11
+ it('should create an ellipse with custom x, y, width, height', () => {
12
+ const ellipse = new Ellipse(10, 20, 30, 40);
13
+ expect(ellipse.x).toBe(10);
14
+ expect(ellipse.y).toBe(20);
15
+ expect(ellipse.width).toBe(30);
16
+ expect(ellipse.height).toBe(40);
17
+ });
18
+
19
+ it('should set the ellipse values to new x, y, width, height', () => {
20
+ const ellipse = new Ellipse();
21
+ ellipse.setTo(10, 20, 30, 40);
22
+ expect(ellipse.x).toBe(10);
23
+ expect(ellipse.y).toBe(20);
24
+ expect(ellipse.width).toBe(30);
25
+ expect(ellipse.height).toBe(40);
26
+ });
27
+
28
+ it('should return the ellipse instance', () => {
29
+ const ellipse = new Ellipse();
30
+ const result = ellipse.setTo(10, 20, 30, 40);
31
+ expect(result).toBe(ellipse);
32
+ });
33
+
34
+ it('should create a rectangle with correct bounds', () => {
35
+ const ellipse = new Ellipse(10, 20, 30, 40);
36
+ const bounds = ellipse.getBounds();
37
+ expect(bounds.x).toBe(10 - 30);
38
+ expect(bounds.y).toBe(20 - 40);
39
+ expect(bounds.width).toBe(30);
40
+ expect(bounds.height).toBe(40);
41
+ });
42
+
43
+ it('should copy the values from another ellipse', () => {
44
+ const source = new Ellipse(10, 20, 30, 40);
45
+ const target = new Ellipse();
46
+ target.copyFrom(source);
47
+ expect(target.x).toBe(source.x);
48
+ expect(target.y).toBe(source.y);
49
+ expect(target.width).toBe(source.width);
50
+ expect(target.height).toBe(source.height);
51
+ });
52
+
53
+ it('should copy the values to another ellipse', () => {
54
+ const source = new Ellipse(10, 20, 30, 40);
55
+ const target = new Ellipse();
56
+ source.copyTo(target);
57
+ expect(target.x).toBe(source.x);
58
+ expect(target.y).toBe(source.y);
59
+ expect(target.width).toBe(source.width);
60
+ expect(target.height).toBe(source.height);
61
+ });
62
+
63
+ it('should return true if point is inside the ellipse', () => {
64
+ const ellipse = new Ellipse(10, 20, 30, 40);
65
+ expect(ellipse.contains(20, 30)).toBe(true);
66
+ });
67
+
68
+ it('should return false if point is outside the ellipse', () => {
69
+ const ellipse = new Ellipse(10, 20, 30, 40);
70
+ expect(ellipse.contains(-5, -10)).toBe(false);
71
+ });
72
+
73
+ it('should generate a random point within the ellipse', () => {
74
+ const ellipse = new Ellipse(10, 20, 30, 40);
75
+ const point = ellipse.random();
76
+ expect(typeof point.x).toBe('number');
77
+ expect(typeof point.y).toBe('number');
78
+ });
79
+
80
+ it('should return a string representation of the ellipse', () => {
81
+ const ellipse = new Ellipse(10, 20, 30, 40);
82
+ expect(ellipse.toString()).toBe('[{Ellipse (x=10 y=20 width=30 height=40)}]');
83
+ });