feat(B05 평면 구조물 마커): 구조물 측점 마커 · 고름 정보 창 · 20 m 법선 · 끌기 · 방향키 1 m (399)
- 마커 = 종단 알약과 같은 목록(laneStructures) · 노선 위 알약 꼴(종류 색) · 스냅 · 간격과 무관 - 고름 = 알약 고름과 같은 길(onStructureSelect · 공용 고름) · 알약 벌룬 그대로 · 좌우 20 m 법선 - 끌기 · 방향키 = 노선 따라 정수 m 1 m 씩 · 시점 · 종점 밖 안 감 · 놓을 때 알약 끌기와 같은 길로 한 번 - 집기 차례 = 교각점 · 곡선 손잡이 다음 · 옛 마름모 지움 - 시험 test_399_plan_structure_marks · test_391 마름모 줄 고침 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
This commit is contained in:
@@ -78,7 +78,7 @@ export interface StructureMarksOptions {
|
||||
}
|
||||
|
||||
/** 위치 표기 — 측점번호+잔여거리(예: 3+18.0). 누가거리 표기는 쓰지 않는다(2026-08-17). */
|
||||
function positionText(structure: StructureInstance, intervalM: number): string {
|
||||
export function positionText(structure: StructureInstance, intervalM: number): string {
|
||||
return structure.placement === "interval"
|
||||
? `${formatStation(structure.start_m ?? 0, intervalM)} ~ ${formatStation(structure.end_m ?? 0, intervalM)}`
|
||||
: formatStation(structure.chainage_m ?? 0, intervalM);
|
||||
@@ -141,6 +141,16 @@ export function structurePillTexts(
|
||||
);
|
||||
}
|
||||
|
||||
/** 알약 자리 목록 — 노선 초안 동안은 묶음 follow 뒤 자리(평면 구조물 마커 399 도 이 목록). */
|
||||
export function laneStructures(
|
||||
structures: ReadonlyArray<StructureInstance>,
|
||||
): ReadonlyArray<StructureInstance> {
|
||||
const pipe = pagePipeline(draftProjectId());
|
||||
return pipe?.input("route")
|
||||
? followedMarks(structures, pipe.input("structures"), pipe.input("pipes"))
|
||||
: structures;
|
||||
}
|
||||
|
||||
/**
|
||||
* 그래프 아래에 구조물 알약 레인을 만들어 돌려준다(호출부가 원하는 위치에 붙인다).
|
||||
*/
|
||||
@@ -151,10 +161,7 @@ export function buildStructureLane(options: StructureMarksOptions): HTMLElement
|
||||
lane.style.height = `${STRUCTURE_LANE_HEIGHT_PX}px`;
|
||||
|
||||
const typeMap = new Map(options.types.map((type) => [type.type_id, type]));
|
||||
const pipe = pagePipeline(draftProjectId());
|
||||
const structures = pipe?.input("route")
|
||||
? followedMarks(options.structures, pipe.input("structures"), pipe.input("pipes"))
|
||||
: options.structures;
|
||||
const structures = laneStructures(options.structures);
|
||||
// 좌측 목록과 같은 중복 이름 번호(2026-08-19 사용자 지시) — 알약 글·툴팁·벌룬 제목이
|
||||
// 모두 이 번호를 따른다.
|
||||
const texts = structurePillTexts(structures, typeMap);
|
||||
@@ -266,13 +273,20 @@ function buildBalloon(
|
||||
anchorPx: number,
|
||||
row: number | null,
|
||||
): HTMLElement {
|
||||
const balloon = document.createElement("div");
|
||||
balloon.className = "b05-structure__balloon";
|
||||
const balloon = balloonElement(lines, type);
|
||||
balloon.classList.add(row === 0 ? "is-left" : row === 1 ? "is-right" : "is-center");
|
||||
balloon.style.left = `${anchorPx}px`;
|
||||
balloon.style.bottom = `${STRUCTURE_LANE_HEIGHT_PX + ROW_GAP_PX + EDIT_BUTTON_CLEARANCE_PX}px`;
|
||||
balloon.style.borderColor = type?.style?.color ?? "#888";
|
||||
// 붙은 뒤 그 창의 틀에서 잼 — 만들 때는 아직 메인 문서 소속이라 새 창 최대화 때 멈춤(230-2).
|
||||
queueMicrotask(() => frameOf(balloon, () => flipIfClipped(balloon)));
|
||||
return balloon;
|
||||
}
|
||||
|
||||
/** 벌룬 몸(제목 + 줄 · 테 색) — 자리는 부르는 쪽(알약 레인 · 평면 구조물 마커 399). */
|
||||
export function balloonElement(lines: string[], type: StructureType | undefined): HTMLElement {
|
||||
const balloon = document.createElement("div");
|
||||
balloon.className = "b05-structure__balloon";
|
||||
balloon.style.borderColor = type?.style?.color ?? "#888";
|
||||
const [name, ...rest] = lines;
|
||||
const title = document.createElement("strong");
|
||||
title.textContent = name;
|
||||
@@ -284,8 +298,6 @@ function buildBalloon(
|
||||
return span;
|
||||
}),
|
||||
);
|
||||
// 붙은 뒤 그 창의 틀에서 잼 — 만들 때는 아직 메인 문서 소속이라 새 창 최대화 때 멈춤(230-2).
|
||||
queueMicrotask(() => frameOf(balloon, () => flipIfClipped(balloon)));
|
||||
return balloon;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user