feat(b06): 맹암거 형상 누름 = 그 구조물 고름 — 물넘이와 같은 판정면 · 보라 손잡이 아래 · 끌기는 고름 아님 (288-2)
- 맹암거 둘레에 고름 표식(data-structure-id) · 287-5 판정면을 같이 탐(손잡이 아래 · 3 px 끌기 = 고름 아님) - 형상 누름 창구 shapePickRoute — 관 지점(물넘이) = 그 카드 시설 고름 · 맹암거 = id 알림 → 구조물 목록이 id 로 고름(알약 · 폼 · 측점선 따라옴 · 노면공 포장 범위 고름과 따로) - 목록 · 알약 고름 → 형상 강조(287-5 highlightShapes) - 시험 test_288 · 287 대조 글 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
* ========================================================================== */
|
||||
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
/** 관 지점이 아닌 구조물(맹암거) 형상 누름 — 카드 밖(구조물 목록)이 id 로 고름(288-2). */
|
||||
export const SHAPE_PICK_EVENT = "b06-structure-shape-pick";
|
||||
/** 끌기로 볼 움직임(px) — 이보다 크면 고름 아님. */
|
||||
export const SHAPE_DRAG_PX = 3;
|
||||
|
||||
@@ -49,6 +51,15 @@ export function attachShapePick(
|
||||
return (active) => shapes.forEach((shape) => shape.classList.toggle("is-active", active));
|
||||
}
|
||||
|
||||
/** 형상 누름 창구(287-5 · 288-2) — 관 지점(`pipe-…` · 물넘이포장) = 그 카드 시설 고름 · 그 밖(맹암거) = id 를
|
||||
* 실은 알림을 위로 띄움(구조물 목록이 받음). */
|
||||
export function shapePickRoute(from: Element, pickPipe: () => void): (structureId: string) => void {
|
||||
return (structureId) => {
|
||||
if (structureId.startsWith("pipe-")) return pickPipe();
|
||||
from.dispatchEvent(new CustomEvent(SHAPE_PICK_EVENT, { bubbles: true, detail: structureId }));
|
||||
};
|
||||
}
|
||||
|
||||
/** 카드 안 형상 강조 — 고른 구조물 id 와 같은 형상만(목록 · 알약 · 폼 고름이 따라옴). */
|
||||
export function highlightShapes(root: ParentNode, structureId: string | null): void {
|
||||
for (const shape of root.querySelectorAll<SVGElement>("[data-structure-id]")) {
|
||||
|
||||
@@ -98,6 +98,7 @@ export function appendUnderdrainOverlay(
|
||||
const body = document.createElementNS(SVG_NS, "polygon");
|
||||
body.setAttribute("points", points);
|
||||
body.setAttribute("class", "b06-chart__underdrain-body");
|
||||
if (spec.structure_id) body.setAttribute("data-structure-id", spec.structure_id);
|
||||
clipSeq += 1;
|
||||
const clipId = `b06-underdrain-clip-${clipSeq}`;
|
||||
const clip = document.createElementNS(SVG_NS, "clipPath");
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
appendFordSurfaceDropPlan,
|
||||
} from "./B06_Section_UI_Cross_Ford_Pavement";
|
||||
import { ownWallsDrawAt } from "./B06_Section_UI_Cross_Culvert_Wire";
|
||||
import { attachShapePick } from "./B06_Section_UI_Cross_Shape_Pick";
|
||||
import { attachShapePick, shapePickRoute } from "./B06_Section_UI_Cross_Shape_Pick";
|
||||
import { appendUnderdrainOverlay } from "./B06_Section_UI_Cross_Underdrain";
|
||||
import { raiseWalls } from "./B06_Section_UI_Cross_Wall";
|
||||
import { attachChuteBandPick } from "./B06_Section_UI_Cross_Wall_Hatch";
|
||||
@@ -579,7 +579,10 @@ export function createCrossSectionCard(
|
||||
setChuteActive(highlightRevet === "chute");
|
||||
}
|
||||
// 물넘이포장 · 맹암거 형상 고름(287-5 · 288-2) — 다른 시설과 같은 창구 · 보라 손잡이 아래 · 누름만
|
||||
const setShapeActive = attachShapePick(plotLayer, revetOffset && (() => toggleRevet("pipe")));
|
||||
const setShapeActive = attachShapePick(
|
||||
plotLayer,
|
||||
revetOffset && shapePickRoute(svg, () => toggleRevet("pipe")),
|
||||
);
|
||||
if (setShapeActive) {
|
||||
const baseSetActive = setRevetActive;
|
||||
setRevetActive = (key) => {
|
||||
|
||||
@@ -69,7 +69,7 @@ import {
|
||||
import type { SectionViewController } from "./B06_Section_UI_Section_View_Types";
|
||||
import { createFillSlopeNotice } from "./B06_Section_UI_Cross_FillSlope_Notice";
|
||||
import { highlightPavement, pavementAt } from "./B06_Section_UI_Cross_Design_Surface";
|
||||
import { highlightShapes } from "./B06_Section_UI_Cross_Shape_Pick";
|
||||
import { highlightShapes, SHAPE_PICK_EVENT } from "./B06_Section_UI_Cross_Shape_Pick";
|
||||
import { createSectionProfile } from "./B06_Section_UI_Section_View_Profile";
|
||||
import type { DesignPageShared } from "../A00_Common/design/design_shared";
|
||||
|
||||
@@ -440,6 +440,11 @@ export function createSectionView(
|
||||
// 렌더 행과 달라져 카드 내부가 뒤죽박죽된다(N-2-6). 열 수 · 폭을 JS가 명시해 일치시킨다.
|
||||
grid.style.gridTemplateColumns = `repeat(${columnCount}, ${cachedCardWidth}px)`;
|
||||
grid.dataset.columns = String(columnCount); // 4열부터 면적표 「계」만(173-3 · CSS)
|
||||
// 맹암거 형상 누름 = 그 구조물 id 고름(288-2 · 노면공 포장 범위 표식과 따로 · 같은 id 고름 창구)
|
||||
grid.addEventListener(SHAPE_PICK_EVENT, (event) => {
|
||||
const id = (event as CustomEvent<string>).detail;
|
||||
if (id) pavementSelectListener?.(id);
|
||||
});
|
||||
cachedRowHeight.clear();
|
||||
if (detail.cross_sections.length) {
|
||||
// 1차: 각 카드의 자연 높이(250px 바닥 적용) 측정 → 같은 행(columnCount 단위) 최댓값을 행 높이로.
|
||||
|
||||
@@ -73,6 +73,21 @@ const group = draw.appendUnderdrainOverlay(
|
||||
);
|
||||
const body = group?.children.find((k) => k.attrs.class === "b06-chart__underdrain-body");
|
||||
|
||||
// 288-2 형상 누름 창구 — 물넘이(pipe-…) = 시설 고름 · 맹암거 = id 알림(목록이 고름)
|
||||
globalThis.CustomEvent = class {
|
||||
constructor(type, init) {
|
||||
this.type = type;
|
||||
this.detail = init?.detail;
|
||||
this.bubbles = init?.bubbles;
|
||||
}
|
||||
};
|
||||
const shapePick = load(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Shape_Pick.ts"));
|
||||
const routed = [];
|
||||
const from = { dispatchEvent: (event) => routed.push([event.type, event.detail, event.bubbles]) };
|
||||
const route = shapePick.shapePickRoute(from, () => routed.push(["pipe"]));
|
||||
route("pipe-230.00");
|
||||
route("ud-1");
|
||||
|
||||
process.stdout.write(
|
||||
JSON.stringify({
|
||||
specs,
|
||||
@@ -82,6 +97,8 @@ process.stdout.write(
|
||||
noHeight: draw.underdrainOutline(design, null),
|
||||
drew: !!group,
|
||||
bodyId: body?.attrs["data-structure-id"] ?? null,
|
||||
routed,
|
||||
eventName: shapePick.SHAPE_PICK_EVENT,
|
||||
stones: group?.children.filter((k) => k.tag === "g").flatMap((g) => g.children).length ?? 0,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -121,8 +121,8 @@ def test_형상_강조와_표식(ts):
|
||||
def test_보라_손잡이는_계획고만_형상_누름은_고름만():
|
||||
view = _read("B06_Section", "B06_Section_UI_Cross_View.ts")
|
||||
# 형상 누름 = 시설 고름 창구만(설계 · 계획고를 안 건드림) · 보라 선 고름보다 먼저 꽂음(손잡이가 위)
|
||||
assert 'attachShapePick(plotLayer, revetOffset && (() => toggleRevet("pipe")))' in view
|
||||
assert view.index("attachShapePick(plotLayer") < view.index("attachDesignLinePick({")
|
||||
assert 'shapePickRoute(svg, () => toggleRevet("pipe"))' in view
|
||||
assert view.index("attachShapePick(") < view.index("attachDesignLinePick({")
|
||||
pick = _read("B06_Section", "B06_Section_UI_Cross_Shape_Pick.ts")
|
||||
assert "onDesignChange" not in pick and "design_elevation" not in pick
|
||||
assert '"b06-chart__culvert-revet-hit"' in pick # 구조물 판정면 앞(아래)에 꽂을 기준만
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
서버 `tilt_ranges` · `tilt_args` · TS 짝 `tilted`) · 제원 얹기 서버 `attach_underdrains` ↔ TS
|
||||
`attachUnderdrainSpecs` 같은 값 · 형상 = 노면을 암거 높이만큼 아래로 옵셋 → 성토 쪽은 성토 사면과
|
||||
만남 · 절토 쪽은 절토 사면을 늘여 만남 · 그 안 돌 무늬 · 높이 비면 안 그림.
|
||||
- 288-2 맹암거 형상 누름 = 그 구조물 id 고름(구조물 목록 창구 · 알약 · 폼 · 측점선 따라옴) · 물넘이와 같은
|
||||
판정면(보라 손잡이 아래 · 끌기 = 고름 아님 · 287-5) · 노면공 포장 범위 고름과 따로.
|
||||
|
||||
진짜 TS 는 `helper_288_underdrain.cjs` 가 Node 로 돌림. 화면은 사용자 확인.
|
||||
"""
|
||||
@@ -141,3 +143,13 @@ def test_횡단도_B07_이_맹암거를_그림():
|
||||
assert "appendUnderdrainOverlay(svg, section.underdrain, design, x, y);" in b07
|
||||
refresh = (ROOT / "B06_Section" / "B06_Section_Cross_Refresh.ts").read_text(encoding="utf-8")
|
||||
assert "tilted: Boolean(section.ford_pavement || section.underdrain)," in refresh
|
||||
|
||||
|
||||
def test_맹암거_형상_누름은_그_구조물_고름(ts):
|
||||
assert ts["bodyId"] == "ud-1" # 둘레 = 형상 고름 표식
|
||||
assert ts["routed"] == [["pipe"], [ts["eventName"], "ud-1", True]]
|
||||
view = (ROOT / "B06_Section" / "B06_Section_UI_Section_View.ts").read_text(encoding="utf-8")
|
||||
assert "grid.addEventListener(SHAPE_PICK_EVENT, (event) => {" in view
|
||||
assert "if (id) pavementSelectListener?.(id);" in view # = structuresPanel.selectStructure(id)
|
||||
cross = (ROOT / "B06_Section" / "B06_Section_UI_Cross_View.ts").read_text(encoding="utf-8")
|
||||
assert 'revetOffset && shapePickRoute(svg, () => toggleRevet("pipe")),' in cross
|
||||
|
||||
Reference in New Issue
Block a user