From 2261ea53fc019fac8986ab9b85d26f8812761fd6 Mon Sep 17 00:00:00 2001 From: ienaga Date: Fri, 14 Nov 2025 15:20:41 +0900 Subject: [PATCH 1/3] =?UTF-8?q?#227=20graphics=E3=81=8C=E5=AE=9A=E7=BE=A9?= =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=A6=E3=81=AA=E3=81=84=E5=A0=B4=E5=90=88?= =?UTF-8?q?=E3=81=AF=E3=80=81Bitmap=E3=81=AE=E3=83=AC=E3=82=AF=E3=82=BF?= =?UTF-8?q?=E3=83=B3=E3=82=B0=E3=83=AB=E3=81=A7HitTest=E3=82=92=E5=88=A4?= =?UTF-8?q?=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Shape/usecase/ShapeHitTestUseCase.test.ts | 243 ++++++++++++++++++ .../src/Shape/usecase/ShapeHitTestUseCase.ts | 22 +- 2 files changed, 262 insertions(+), 3 deletions(-) diff --git a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts index a5937d0a..c506f818 100644 --- a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts +++ b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts @@ -180,4 +180,247 @@ describe("ShapeHitTestUseCase.js test", () => expect(typeof result).toBe("boolean"); }); + + it("execute test case11 - hit inside shape without buffer (default rectangle path)", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case12 - hit outside shape without buffer", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 150, y: 150 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(result).toBe(false); + }); + + it("execute test case13 - hit on edge of shape without buffer", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 0, y: 0 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case14 - hit with shape transformation (rawMatrix)", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + shape.x = 50; + shape.y = 50; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 75, y: 75 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case15 - hit with scaled shape transformation", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + shape.scaleX = 2; + shape.scaleY = 2; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 75, y: 75 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case16 - hit with rotated shape", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + shape.rotation = 45; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case17 - hit with combined parent matrix and shape transformation", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + shape.x = 10; + shape.y = 10; + + const parentMatrix = new Float32Array([1, 0, 0, 1, 100, 100]); + const hitObject = { x: 125, y: 125 }; + + const result = execute(shape, context, parentMatrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case18 - hit with graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.beginFill(0xFF0000); + shape.graphics.drawRect(0, 0, 100, 100); + shape.graphics.endFill(); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case19 - hit outside with graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.beginFill(0xFF0000); + shape.graphics.drawRect(0, 0, 100, 100); + shape.graphics.endFill(); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 150, y: 150 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case20 - hit with line stroke graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.lineStyle(5, 0x000000); + shape.graphics.moveTo(0, 0); + shape.graphics.lineTo(100, 100); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case21 - hit with circle graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.beginFill(0x00FF00); + shape.graphics.drawCircle(50, 50, 50); + shape.graphics.endFill(); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case22 - handles negative coordinates", () => + { + const shape = new Shape(); + shape.graphics.xMin = -50; + shape.graphics.yMin = -50; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 0, y: 0 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case23 - handles fractional coordinates", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0.5; + shape.graphics.yMin = 0.5; + shape.graphics.xMax = 100.5; + shape.graphics.yMax = 100.5; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50.25, y: 50.25 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case24 - handles very small shape", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 1; + shape.graphics.yMax = 1; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 0.5, y: 0.5 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case25 - handles very large shape", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 10000; + shape.graphics.yMax = 10000; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 5000, y: 5000 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); }); diff --git a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts index 0d6c917d..49d4489a 100644 --- a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts +++ b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts @@ -42,9 +42,25 @@ export const execute = ( tMatrix[3], tMatrix[4], tMatrix[5] ); - const hit = graphicsHitTestService( - hit_context, graphics.buffer, hit_object - ); + let hit = false; + if (graphics.buffer.length) { + hit = graphicsHitTestService( + hit_context, graphics.buffer, hit_object + ); + } else { + hit_context.setTransform( + tMatrix[0], tMatrix[1], tMatrix[2], + tMatrix[3], tMatrix[4], tMatrix[5] + ); + hit_context.beginPath(); + hit_context.moveTo(0, 0); + hit_context.lineTo(width, 0); + hit_context.lineTo(width, height); + hit_context.lineTo(0, height); + hit_context.lineTo(0, 0); + + hit = hit_context.isPointInPath(hit_object.x, hit_object.y); + } if (tMatrix !== matrix) { Matrix.release(tMatrix); From 56e1642e1b74d687ea5ad1282d03ad64fa1fde71 Mon Sep 17 00:00:00 2001 From: ienaga Date: Fri, 14 Nov 2025 15:21:31 +0900 Subject: [PATCH 2/3] =?UTF-8?q?#227=20=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E6=83=85=E5=A0=B1=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index df343ea5..2a6e1ea7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@next2d/player", - "version": "2.7.0", + "version": "2.8.0", "description": "Experience the fast and beautiful anti-aliased rendering of WebGL. You can create rich, interactive graphics, cross-platform applications and games without worrying about browser or device compatibility.", "author": "Toshiyuki Ienaga (https://github.com/ienaga/)", "license": "MIT", diff --git a/src/index.ts b/src/index.ts index 42df8738..4e50c90e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import { Next2D } from "@next2d/core"; if (!("next2d" in window)) { - console.log("%c Next2D Player %c 2.7.0 %c https://next2d.app", + console.log("%c Next2D Player %c 2.8.0 %c https://next2d.app", "color: #fff; background: #5f5f5f", "color: #fff; background: #4bc729", ""); From fc2e6ca6b8373ca301757d1e78138c9642c5db8c Mon Sep 17 00:00:00 2001 From: ienaga Date: Fri, 14 Nov 2025 15:30:24 +0900 Subject: [PATCH 3/3] =?UTF-8?q?#227=20=E4=B8=8D=E8=A6=81=E3=81=AAcanvas?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts index 49d4489a..ea8d0320 100644 --- a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts +++ b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts @@ -48,11 +48,6 @@ export const execute = ( hit_context, graphics.buffer, hit_object ); } else { - hit_context.setTransform( - tMatrix[0], tMatrix[1], tMatrix[2], - tMatrix[3], tMatrix[4], tMatrix[5] - ); - hit_context.beginPath(); hit_context.moveTo(0, 0); hit_context.lineTo(width, 0); hit_context.lineTo(width, height);