fix(b08): 거리이정표 다이어그램 영역 스크롤 없앰 · 휠 = 줌만 (244-8)
- 틀 overflow hidden · max-height 없앰 — 그림 = 틀 안 맞춤(높이 48vh 넘으면 비율대로 좁힘) - 틀 wheel 듣개(passive false · preventDefault) — 그림 밖 여백 · 단추 줄 휠도 페이지 스크롤로 안 샘 - 새 시험 test_244_8 — 진짜 wheel 사건으로 줌 · 기본동작 막힘 판정 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
This commit is contained in:
@@ -51,10 +51,9 @@
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
/* 244-2 다이어그램 — 상자 · 선 · km 글(테마 변수) */
|
||||
/* 244-2 다이어그램 — 상자 · 선 · km 글(테마 변수) · 스크롤 없음(244-8 · 그림 = 틀 안 맞춤) */
|
||||
.b08-milestone__diagram {
|
||||
overflow: auto;
|
||||
max-height: 48vh;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
background: var(--color-surface);
|
||||
|
||||
@@ -104,6 +104,8 @@ export function createDiagram(
|
||||
): { root: HTMLElement; refresh: () => void } {
|
||||
const host = el("div", { className: "b08-milestone__diagram" });
|
||||
host.dataset.b08Milestone = "diagram";
|
||||
// 틀 위 휠 = 줌만(244-8) — 그림 밖 여백 · 단추 줄 휠도 페이지 스크롤로 새지 않음
|
||||
host.addEventListener("wheel", (e) => e.preventDefault(), { passive: false });
|
||||
let zoomState: ZoomPanState | undefined; // 다시 그려도 배율 그대로
|
||||
const INFO: Record<DiagramBox["kind"], (id: string) => void> = {
|
||||
route: (id) => openRouteInfo(projectId, id),
|
||||
@@ -147,7 +149,8 @@ export function createDiagram(
|
||||
"aria-label": "거리이정표 다이어그램",
|
||||
});
|
||||
// 틀 너비 = 아래 표 너비(244-6) · 높이는 비율대로(팬 · 줌 화면 px ↔ 그림 좌표가 어긋나지 않게)
|
||||
root.style.width = "100%";
|
||||
// 높이 48vh 넘으면 그만큼 좁혀 틀 안에 다 들어감(244-8 · 스크롤 없음)
|
||||
root.style.width = `min(100%, calc(48vh * ${vw / vh}))`;
|
||||
root.style.height = "auto";
|
||||
const layer = svg("g", {});
|
||||
const shift = svg("g", { transform: `translate(${-vx} ${-vy})` });
|
||||
|
||||
@@ -107,7 +107,7 @@ def test_표_폭_다이어그램_폭_좌측_카드_없음():
|
||||
assert "width: fit-content;" in block[: block.index("}")] # 틀 = 표 너비
|
||||
assert ".b08-milestone > .b08-milestone__diagram {\n contain: inline-size;" in css
|
||||
ui = _read("B08_Quantity/B08_Quantity_UI_Milestone_Diagram.ts")
|
||||
assert 'root.style.width = "100%";' in ui # 다이어그램 = 틀 너비
|
||||
assert "root.style.width = `min(100%, calc(48vh * ${vw / vh}))`;" in ui # 다이어그램 = 틀 너비
|
||||
page = _read("B08_Quantity/B08_Quantity_UI_Milestone.ts")
|
||||
assert "children: [diagram.root, none, table.root]" in page
|
||||
# 좌측 패널 카드 없음 · 공사지 · 기준점은 모달
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
"""244-8 B08 거리이정표 다이어그램 영역 스크롤 없앰(사용자 135번).
|
||||
|
||||
틀 = overflow hidden · 그림 = 틀 안 맞춤(높이 48vh 넘으면 좁힘) · 휠 = 줌만.
|
||||
휠은 공용 `A00_Common/b_svg_zoom_pan.ts` 와 다이어그램 틀 듣개를 node 로 돌려
|
||||
진짜 wheel 사건(cancelable)을 보내 기본동작(스크롤)이 막히는지 · 배율이 바뀌는지 잼.
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
IMPORTS = re.compile(r"^import[^;]*;\n", re.MULTILINE)
|
||||
DIAGRAM = "B08_Quantity/B08_Quantity_UI_Milestone_Diagram.ts"
|
||||
|
||||
|
||||
def _read(rel):
|
||||
return (ROOT / rel).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _node(script):
|
||||
src = IMPORTS.sub("", _read("A00_Common/b_svg_zoom_pan.ts"))
|
||||
result = subprocess.run(
|
||||
["node", "--experimental-strip-types", "--no-warnings",
|
||||
"--input-type=module-typescript", "-e", src + "\n" + script],
|
||||
capture_output=True, text=True, encoding="utf-8", timeout=60,
|
||||
) # fmt: skip
|
||||
assert result.returncode == 0, result.stderr
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def test_틀_스크롤_없음_그림_맞춤():
|
||||
css = _read("B08_Quantity/B08_Quantity_UI_Milestone.css")
|
||||
block = css[css.index("\n.b08-milestone__diagram {") :]
|
||||
block = block[: block.index("}")]
|
||||
assert "overflow: hidden;" in block and "overflow: auto" not in block
|
||||
assert "max-height" not in block # 높이는 그림이 맞춤 — 틀이 자르지 않음
|
||||
ui = _read(DIAGRAM)
|
||||
# 너비 = 틀 · 높이 48vh 넘으면 비율대로 좁힘(height auto 라 화면 px ↔ 그림 좌표 그대로)
|
||||
assert "root.style.width = `min(100%, calc(48vh * ${vw / vh}))`;" in ui
|
||||
assert 'root.style.height = "auto";' in ui
|
||||
|
||||
|
||||
def test_휠_진짜_사건_줌_스크롤_막음():
|
||||
ui = _read(DIAGRAM)
|
||||
line = next(ln.strip() for ln in ui.splitlines() if 'host.addEventListener("wheel"' in ln)
|
||||
got = _node(
|
||||
"""
|
||||
const W = 600, H = 400;
|
||||
class Svg extends EventTarget {
|
||||
classList = { add() {}, remove() {} };
|
||||
getBoundingClientRect() { return { left: 0, top: 0, width: W, height: H }; }
|
||||
}
|
||||
function wheel(target: EventTarget, deltaY: number) {
|
||||
const ev = new Event("wheel", { cancelable: true, bubbles: true });
|
||||
for (const [k, v] of Object.entries({ deltaY, clientX: 300, clientY: 200 }))
|
||||
Object.defineProperty(ev, k, { value: v });
|
||||
target.dispatchEvent(ev);
|
||||
return ev.defaultPrevented;
|
||||
}
|
||||
const svg = new Svg();
|
||||
const layer = { t: "", setAttribute(_k: string, v: string) { this.t = v; } };
|
||||
attachSvgZoomPan({ svg: svg as any, layer: layer as any, widthPx: W, heightPx: H,
|
||||
pad: { left: 0, right: 0, top: 0, bottom: 0 }, wheelZoom: true });
|
||||
const svgIn = wheel(svg, 100);
|
||||
const zoomIn = layer.t;
|
||||
const svgOut = wheel(svg, -100);
|
||||
const zoomOut = layer.t;
|
||||
// 틀 듣개(그림 밖 여백 · 단추 줄) — 소스 줄 그대로 돌림 · passive 면 preventDefault 무시됨
|
||||
const host = new EventTarget();
|
||||
let opts: unknown = null;
|
||||
const add = host.addEventListener.bind(host);
|
||||
host.addEventListener = (t: string, f: any, o: any) => { opts = o; add(t, f, o); };
|
||||
LINE
|
||||
const hostBlocked = wheel(host, 100);
|
||||
console.log(JSON.stringify({ svgIn, zoomIn, svgOut, zoomOut, hostBlocked, opts }));
|
||||
""".replace("LINE", line)
|
||||
)
|
||||
# 그림 위 휠 = 줌(커서 자리 붙잡음) · 기본동작(스크롤) 막힘 = 스크롤 위치 안 바뀜
|
||||
assert got["svgIn"] is True and got["zoomIn"].endswith(" scale(1.15)")
|
||||
assert got["zoomIn"].startswith("translate(-45 -29.99") # 커서(300, 200) 제자리
|
||||
assert got["svgOut"] is True and got["zoomOut"] != got["zoomIn"] # 밀면 축소
|
||||
# 그림 밖 틀 위 휠도 페이지 스크롤로 안 샘
|
||||
assert got["hostBlocked"] is True and got["opts"] == {"passive": False}
|
||||
Reference in New Issue
Block a user