// 확대 상태의 팬 한계가 캐시 보유 범위까지 늘어나는지 — Cross_View_Zoom.clampPan 로직 복제. // 실행: node tmp/tests/test_cross_pan_bounds.mjs import assert from "node:assert/strict"; const plot = { x: 58, y: 10, width: 552, height: 188 }; // 표시 반폭 12m(=플롯 폭)보다 넓은 캐시 20m — 좌우로 각각 플롯 폭의 2/3만큼 더 있다. const content = { x: plot.x - 368, y: plot.y - 100, width: plot.width + 736, height: plot.height + 200 }; function clampAxis(value, scale, start, size, from, to) { const lo = start + size - scale * to; const hi = start - scale * from; return Math.min(Math.max(value, Math.min(lo, hi)), Math.max(lo, hi)); } function clampPan(tx, ty, scale, useContent = true) { const bounds = useContent && scale > 1 + 1e-6 ? { x: Math.min(content.x, plot.x), y: Math.min(content.y, plot.y), right: Math.max(content.x + content.width, plot.x + plot.width), bottom: Math.max(content.y + content.height, plot.y + plot.height), } : { x: plot.x, y: plot.y, right: plot.x + plot.width, bottom: plot.y + plot.height }; return { tx: clampAxis(tx, scale, plot.x, plot.width, bounds.x, bounds.right), ty: clampAxis(ty, scale, plot.y, plot.height, bounds.y, bounds.bottom), }; } // 화면 창이 보는 원배율 좌표 구간. const windowSpan = (tx, scale) => [(plot.x - tx) / scale, (plot.x + plot.width - tx) / scale]; // 원배율: 이동 없음(기존 규칙 유지). assert.deepEqual(clampPan(200, 200, 1), { tx: 0, ty: 0 }); // 2배 확대: 캐시 왼쪽 끝까지 끌 수 있고, 창이 캐시 범위를 벗어나지 않는다. const scale = 2; const far = clampPan(100000, 100000, scale); const [leftFrom] = windowSpan(far.tx, scale); assert.ok(Math.abs(leftFrom - content.x) < 1e-6, `왼쪽 한계가 캐시 끝이 아님: ${leftFrom}`); const farNeg = clampPan(-100000, -100000, scale); const [, rightTo] = windowSpan(farNeg.tx, scale); assert.ok( Math.abs(rightTo - (content.x + content.width)) < 1e-6, `오른쪽 한계가 캐시 끝이 아님: ${rightTo}`, ); // 캐시 범위 밖으로는 못 나간다. for (const raw of [-5000, -800, -100, 0, 100, 800, 5000]) { const { tx } = clampPan(raw, 0, scale); const [from, to] = windowSpan(tx, scale); assert.ok(from >= content.x - 1e-6, `왼쪽 이탈 ${from}`); assert.ok(to <= content.x + content.width + 1e-6, `오른쪽 이탈 ${to}`); } // content가 없으면(옛 규칙) 확대해도 플롯 영역 안으로만 움직인다. const noContent = clampPan(100000, 0, scale, false); const [fitFrom] = windowSpan(noContent.tx, scale); assert.ok(Math.abs(fitFrom - plot.x) < 1e-6, `기본 한계 어긋남 ${fitFrom}`); console.log("ok");