fix(B06): 횡단 세월교 · BOX 본체 클릭 = 좌측 본체 상자 고름 · 강조(PLAN 66-1)
- 세월교 바닥판 · 관 판정면 추가 → 「세월교」 상자 강조 · 스크롤 · 그림 바닥판 · 관 붉게 - BOX 구체 가운데 1/3 = 본체 · 양쪽 = 그 끝(유입 · 유출 상자 그대로) - 고름 값에 body 추가(FordPick · BoxPick) · 조정창은 본체에서 안 뜸 - B05 넘김 키 body 도 같은 길 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
This commit is contained in:
@@ -27,8 +27,11 @@ export type {
|
||||
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
/** 고르는 부재 — 좌 · 우 끝 또는 본체(구체 가운데 1/3 · 좌측 「본체」 상자 · 66-1). */
|
||||
export type BoxPick = BoxSideRole | "body";
|
||||
|
||||
/** 선택 강조를 카드 재생성 없이 갈아 끼우는 setter. */
|
||||
export type BoxHighlightSetter = (role: BoxSideRole | null) => void;
|
||||
export type BoxHighlightSetter = (role: BoxPick | null) => void;
|
||||
|
||||
/**
|
||||
* BOX암거 구체 오버레이 — computeBoxLayout 결과를 그린다.
|
||||
@@ -39,7 +42,7 @@ export function appendBoxOverlay(
|
||||
layout: BoxLayout,
|
||||
x: (offset: number) => number,
|
||||
toDisplayY: (elevation: number) => number,
|
||||
onSelectSide?: (role: BoxSideRole) => void,
|
||||
onSelectSide?: (role: BoxPick) => void,
|
||||
): BoxHighlightSetter {
|
||||
const { box } = layout;
|
||||
const toXY = (point: OffsetPoint): [number, number] => [
|
||||
@@ -133,21 +136,30 @@ export function appendBoxOverlay(
|
||||
label.textContent = layout.label.text;
|
||||
layer.append(label);
|
||||
|
||||
// 좌·우 절반을 덮는 투명 겹면 — 어느 끝을 조정할지 클릭으로 고른다.
|
||||
const hits = new Map<BoxSideRole, SVGPolygonElement>();
|
||||
// 투명 겹면 — 구체 가운데 1/3 = 본체, 그 바깥 양쪽 = 그 끝(66-1). 어느 것을 조정할지 클릭으로 고른다.
|
||||
const hits = new Map<BoxPick, SVGPolygonElement>();
|
||||
if (onSelectSide) {
|
||||
const midOffset = (layout.sides[0].offset + layout.sides[1].offset) / 2;
|
||||
const third = (layout.sides[0].offset - layout.sides[1].offset) / 6;
|
||||
const top = Math.max(...layout.topSlab.map((point) => point.elevation));
|
||||
const bottom = Math.min(...layout.bottomSlab.map((point) => point.elevation));
|
||||
for (const side of layout.sides) {
|
||||
const outer = side.apron.length ? side.apron[1].offset : side.offset;
|
||||
const band = (from: number, to: number): OffsetPoint[] => [
|
||||
{ offset: from, elevation: top },
|
||||
{ offset: to, elevation: top },
|
||||
{ offset: to, elevation: bottom },
|
||||
{ offset: from, elevation: bottom },
|
||||
];
|
||||
const parts: Array<[BoxPick, OffsetPoint[]]> = [
|
||||
["body", band(midOffset - third, midOffset + third)],
|
||||
...layout.sides.map((side): [BoxPick, OffsetPoint[]] => {
|
||||
const outer = side.apron.length ? side.apron[1].offset : side.offset;
|
||||
const inner = midOffset + Math.sign(side.offset - midOffset) * Math.abs(third);
|
||||
return [side.role, band(inner, outer)];
|
||||
}),
|
||||
];
|
||||
for (const [role, points] of parts) {
|
||||
const hit = polygon(
|
||||
[
|
||||
{ offset: midOffset, elevation: top },
|
||||
{ offset: outer, elevation: top },
|
||||
{ offset: outer, elevation: bottom },
|
||||
{ offset: midOffset, elevation: bottom },
|
||||
],
|
||||
points,
|
||||
// 강조용 클래스를 하나 더 단다 — 고른 끝을 옅게 칠한다(2026-08-30 사용자:
|
||||
// BOX암거는 선택해도 아무 표시가 없었다). 구체 부재는 좌·우가 한 몸이라
|
||||
// 그쪽을 칠하면 어느 끝을 고른 것인지 되레 흐려진다.
|
||||
@@ -156,14 +168,14 @@ export function appendBoxOverlay(
|
||||
);
|
||||
hit.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
onSelectSide(side.role);
|
||||
onSelectSide(role);
|
||||
});
|
||||
hits.set(side.role, hit);
|
||||
hits.set(role, hit);
|
||||
layer.append(hit);
|
||||
}
|
||||
}
|
||||
|
||||
return (role: BoxSideRole | null): void => {
|
||||
return (role: BoxPick | null): void => {
|
||||
for (const [side, hit] of hits) hit.classList.toggle("is-active", side === role);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user