Skip to content

Commit 2e8281d

Browse files
author
DavidQ
committed
Add mouse wheel zoom to Collision Inspector V2 - PR_26140_053-add-collision-mouse-wheel-zoom
1 parent 2a6639b commit 2e8281d

6 files changed

Lines changed: 96 additions & 11 deletions

File tree

games/Asteroids/game.manifest.json

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,20 +229,20 @@
229229
"geometry": {
230230
"points": [
231231
{
232-
"x": -1.5,
233-
"y": 1.5
232+
"x": -1,
233+
"y": -1
234234
},
235235
{
236-
"x": 0.5,
237-
"y": 1.5
236+
"x": 1,
237+
"y": -1
238238
},
239239
{
240-
"x": 0.5,
241-
"y": 3.5
240+
"x": 1,
241+
"y": 1
242242
},
243243
{
244-
"x": -1.5,
245-
"y": 3.5
244+
"x": -1,
245+
"y": 1
246246
}
247247
]
248248
},
@@ -251,7 +251,16 @@
251251
"stroke": "#FFFFFF",
252252
"strokeWidth": 2,
253253
"fillOpacity": 1,
254-
"strokeOpacity": 1
254+
"strokeOpacity": 1,
255+
"pointRounding": [
256+
false,
257+
false,
258+
false,
259+
false
260+
],
261+
"startPointStyle": "square",
262+
"endPointStyle": "square",
263+
"pointStyle": "square"
255264
},
256265
"transform": {
257266
"rotation": 0,
@@ -293,8 +302,8 @@
293302
"bullet"
294303
],
295304
"objectOrigin": {
296-
"x": -0.5,
297-
"y": 2.5
305+
"x": 0,
306+
"y": 0
298307
}
299308
},
300309
{

tests/playwright/tools/CollisionInspectorV2.spec.mjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,43 @@ test.describe("Collision Inspector V2", () => {
288288
await expect(page.locator("#collisionZoomInput")).toHaveAttribute("step", "10");
289289
await expect(page.locator("#collisionZoomInput")).toHaveValue("100");
290290
await expect(page.locator("#zoomState")).toHaveText("100%");
291+
const wheelZoomState = await page.locator("#collisionCanvas").evaluate((canvas) => {
292+
const app = window.__collisionInspectorV2App;
293+
const rect = canvas.getBoundingClientRect();
294+
const clientX = Math.round(rect.left + rect.width * 0.72);
295+
const clientY = Math.round(rect.top + rect.height * 0.44);
296+
const before = app.renderer.canvasPoint({ clientX, clientY });
297+
const event = new WheelEvent("wheel", {
298+
bubbles: true,
299+
cancelable: true,
300+
clientX,
301+
clientY,
302+
deltaY: -120
303+
});
304+
canvas.dispatchEvent(event);
305+
const after = app.renderer.canvasPoint({ clientX, clientY });
306+
return {
307+
after,
308+
before,
309+
defaultPrevented: event.defaultPrevented,
310+
pan: { ...app.renderer.viewportPan },
311+
zoom: app.zoom
312+
};
313+
});
314+
expect(wheelZoomState.defaultPrevented).toBe(true);
315+
expect(wheelZoomState.zoom).toBe(1.1);
316+
expect(Math.abs(wheelZoomState.after.x - wheelZoomState.before.x)).toBeLessThan(0.01);
317+
expect(Math.abs(wheelZoomState.after.y - wheelZoomState.before.y)).toBeLessThan(0.01);
318+
expect(Math.abs(wheelZoomState.pan.x) + Math.abs(wheelZoomState.pan.y)).toBeGreaterThan(0);
319+
await expect(page.locator("#zoomState")).toHaveText("110%");
320+
await expect(page.locator("#collisionSummary")).toContainText('"zoom": "110%"');
321+
await expect(page.locator("#collisionLog")).toHaveValue(/Canvas zoom set to 110%/);
322+
await page.evaluate(() => {
323+
window.__collisionInspectorV2App.setZoom(1);
324+
window.__collisionInspectorV2App.renderer.resetViewportPan();
325+
window.__collisionInspectorV2App.evaluateAndRender();
326+
});
327+
await expect(page.locator("#zoomState")).toHaveText("100%");
291328
const viewportPanState = await page.locator("#collisionCanvas").evaluate((canvas) => {
292329
const app = window.__collisionInspectorV2App;
293330
const rect = canvas.getBoundingClientRect();

tools/collision-inspector-v2/js/CollisionInspectorV2App.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { deepClone } from "../../../src/shared/utils/jsonUtils.js";
1111
import {
1212
clampCollisionZoom,
1313
COLLISION_ZOOM_DEFAULT,
14+
COLLISION_ZOOM_STEP,
15+
collisionZoomToPercent,
1416
OBJECT_LABELS,
1517
roundNumber
1618
} from "./constants.js";
@@ -58,6 +60,7 @@ export class CollisionInspectorV2App {
5860
this.shell.returnToWorkspace();
5961
},
6062
onRotationChange: (key, rotation) => this.setRotation(key, rotation),
63+
onCanvasWheel: (event) => this.handleCanvasWheel(event),
6164
onZoomChange: (zoom) => this.setZoom(zoom)
6265
});
6366
this.controls.setLaunchMode(this.isWorkspaceLaunch());
@@ -203,6 +206,27 @@ export class CollisionInspectorV2App {
203206
this.evaluateAndRender();
204207
}
205208

209+
handleCanvasWheel(event) {
210+
if (!this.hasRenderableManifest() || this.dragState) {
211+
return;
212+
}
213+
const deltaY = Number(event.deltaY) || 0;
214+
if (!deltaY) {
215+
return;
216+
}
217+
event.preventDefault();
218+
const direction = deltaY < 0 ? 1 : -1;
219+
const nextZoom = clampCollisionZoom(Number((this.zoom + direction * COLLISION_ZOOM_STEP).toFixed(3)));
220+
if (nextZoom === this.zoom) {
221+
return;
222+
}
223+
this.zoom = nextZoom;
224+
this.renderer.setZoomAtClientPoint(this.zoom, event);
225+
this.controls.setZoom(this.zoom);
226+
this.evaluateAndRender();
227+
this.logger.write(`INFO Canvas zoom set to ${collisionZoomToPercent(this.zoom)}%.`);
228+
}
229+
206230
resetSimulation({ silent = false } = {}) {
207231
if (!this.screen || !this.objects.length) {
208232
this.logger.write("FAIL Load a manifest with root.screen.width, root.screen.height, and Object Vector Studio V2 objects before resetting.");

tools/collision-inspector-v2/js/CollisionInspectorV2Controls.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ export class CollisionInspectorV2Controls {
4848
this.elements.resetButton.addEventListener("click", callbacks.onReset);
4949
this.elements.returnToWorkspaceButton.addEventListener("click", callbacks.onReturnToWorkspace);
5050
this.elements.canvas.addEventListener("pointerdown", callbacks.onPointerDown);
51+
this.elements.canvas.addEventListener("wheel", (event) => {
52+
callbacks.onCanvasWheel?.(event);
53+
}, { passive: false });
5154
this.window.addEventListener("pointermove", callbacks.onPointerMove);
5255
this.window.addEventListener("pointerup", callbacks.onPointerUp);
5356
}

tools/collision-inspector-v2/js/CollisionInspectorV2Renderer.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ export class CollisionInspectorV2Renderer {
3838
});
3939
}
4040

41+
setZoomAtClientPoint(zoom, event) {
42+
const before = this.canvasPoint(event);
43+
this.setZoom(zoom);
44+
const after = this.canvasPoint(event);
45+
this.viewportPan = {
46+
x: Number((this.viewportPan.x + before.x - after.x).toFixed(6)),
47+
y: Number((this.viewportPan.y + before.y - after.y).toFixed(6))
48+
};
49+
return { ...this.viewportPan };
50+
}
51+
4152
clear() {
4253
const ctx = this.ctx;
4354
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

tools/collision-inspector-v2/js/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const OBJECT_LABELS = Object.freeze({
88
export const COLLISION_ZOOM_DEFAULT = 1;
99
export const COLLISION_ZOOM_MAX = 10;
1010
export const COLLISION_ZOOM_MIN = 0.1;
11+
export const COLLISION_ZOOM_STEP = 0.1;
1112

1213
export function labelForObject(object) {
1314
return `${object?.name || "Object"} (${object?.id || "unknown"})`;

0 commit comments

Comments
 (0)