Files
Genarrative/apps/ai-game-creator-shell/tests/resourceCanvasGenerationVisibility.test.ts
T
suzmii e0f9f811b7 生成浮层居中定位与画布安全带高度
补回 transform translateX(-50%):锚点给的是占位卡中心,少了它浮层整体右偏半个面板宽
高度只按画布安全带分配:装得下时挂在卡下面,装不下时与卡顶边对齐盖住占位,不再压成一百多像素
reveal 的面板高度按当前缩放从屏幕 px 折回世界坐标,占位与浮层并集参与可见性
浮层宽度并入可见性并集,靠边卡片不再把浮层切掉一半
新增真实矩形模拟用例(画布高 568)核对浮层高度与落点不越出安全带
2026-09-17 19:35:41 +08:00

153 lines
5.1 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import { revealResourceCanvasGenerationContent } from '../src/features/resource-canvas/resourceCanvasGenerationVisibilityModel';
import { resolveResourceCanvasGenerationPanelPlacement } from '../src/features/resource-canvas/resourceCanvasGenerationVisibilityModel';
const canvasSize = { width: 800, height: 600 };
const insets = { top: 60, bottom: 90 };
describe('生成浮层与占位的可见性', () => {
test('内容已经在安全区内时坐标不变(宿主据此跳过写回)', () => {
const viewport = { x: 0, y: 0, scale: 1 };
const next = revealResourceCanvasGenerationContent({
viewport,
content: { x: 40, y: 80, width: 180, height: 200 },
canvasSize,
insets,
});
expect(next).toEqual(viewport);
});
test('内容落到视口下方时做最小上移,底边贴住底栏安全区', () => {
const viewport = { x: 0, y: 0, scale: 1 };
// 占位在 y=550、加上浮层后整块落到视口外——真实浏览器上复现过的那一档。
const next = revealResourceCanvasGenerationContent({
viewport,
content: { x: 40, y: 550, width: 180, height: 320 },
canvasSize,
insets,
});
const safeBottom = canvasSize.height - insets.bottom;
expect(viewport.y + (550 + 320)).toBeGreaterThan(safeBottom);
expect(next.y + 550 + 320).toBe(safeBottom);
expect(next.x).toBe(0);
expect(next.scale).toBe(1);
});
test('内容顶出顶栏时下移,内容越出左右边时做最小横移', () => {
const next = revealResourceCanvasGenerationContent({
viewport: { x: 0, y: 0, scale: 1 },
content: { x: -300, y: -40, width: 180, height: 120 },
canvasSize,
insets,
});
expect(next.y).toBe(insets.top + 40);
expect(next.x).toBe(12 + 300);
});
test('缩放参与换算:缩小后的越界按同一口径平移,比例保持不变', () => {
const next = revealResourceCanvasGenerationContent({
viewport: { x: 0, y: 0, scale: 0.5 },
content: { x: 40, y: 900, width: 180, height: 320 },
canvasSize,
insets,
});
expect(next.scale).toBe(0.5);
const safeBottom = canvasSize.height - insets.bottom;
expect(next.y + (900 + 320) * 0.5).toBe(safeBottom);
});
test('内容比安全区还大时以顶边 / 左边对齐,不来回抖', () => {
const next = revealResourceCanvasGenerationContent({
viewport: { x: 0, y: 0, scale: 1 },
content: { x: 0, y: 0, width: 2000, height: 1200 },
canvasSize,
insets,
});
expect(next).toEqual({ scale: 1, x: 12, y: insets.top });
});
test('尺寸非法或画布未就绪时原样返回', () => {
const viewport = { x: 5, y: 6, scale: 1 };
expect(
revealResourceCanvasGenerationContent({
viewport,
content: { x: 0, y: 0, width: 0, height: 0 },
canvasSize,
insets,
}),
).toEqual(viewport);
expect(
revealResourceCanvasGenerationContent({
viewport,
content: { x: 0, y: 0, width: 10, height: 10 },
canvasSize: { width: 0, height: 0 },
insets,
}),
).toEqual(viewport);
});
});
describe('浮层高度与「盖住占位」判定按画布安全带算', () => {
const placement = (input: {
canvasHeight: number;
topInset: number;
bottomInset: number;
anchorHeight: number;
}) => resolveResourceCanvasGenerationPanelPlacement(input);
test('空间够时挂在卡下面,高度 = 安全带 - 卡 - 间隙', () => {
const result = placement({
canvasHeight: 568,
topInset: 54,
bottomInset: 84,
anchorHeight: 128,
});
expect(result.overlaysAnchor).toBe(false);
// 安全带 430 - 卡 128 - 间隙 12 = 290:落在「至少 260 可编辑」的区间里。
expect(result.availableHeight).toBe(290);
});
test('安全带给不出可编辑高度时改为盖住占位,拿整条安全带', () => {
// 缩放 1.5:占位卡视觉 192px,卡下面只剩 224 (< 280) → 盖住占位。
const result = placement({
canvasHeight: 568,
topInset: 58,
bottomInset: 72,
anchorHeight: 192,
});
expect(result.overlaysAnchor).toBe(true);
// 安全带 438 - 间隙 12 = 426:远大于「一百多像素」的旧表现。
expect(result.availableHeight).toBe(426);
expect(result.availableHeight).toBeGreaterThanOrEqual(260);
});
test('空间充足时收到上限,几何非法时回退到最小编辑高度', () => {
expect(
placement({
canvasHeight: 1400,
topInset: 54,
bottomInset: 84,
anchorHeight: 128,
}).availableHeight,
).toBe(520);
expect(
placement({
canvasHeight: 0,
topInset: 54,
bottomInset: 84,
anchorHeight: 128,
}),
).toEqual({ overlaysAnchor: false, availableHeight: 280 });
// 画布小到连安全带都装不下:退到安全带能给的量,但仍有可编辑高度。
const tiny = placement({
canvasHeight: 240,
topInset: 40,
bottomInset: 40,
anchorHeight: 128,
});
expect(tiny.overlaysAnchor).toBe(true);
expect(tiny.availableHeight).toBe(160);
});
});