Files
Aislo/common_util/common_util_mass_haul_badge.ts
eomsangdonandClaude Opus 5 818042e45c feat(B05,B06): 최종 누가토량 배지 + B06 유토곡선 그래프 제거
사용자 지시(2026-09-06): 유토곡선은 자리를 많이 먹는데 정작 늘 봐야 하는 값은 마지막
지점 누가토량 하나임. 기준은 횡단으로 고정(종단 기준 곡선은 뒤에 삭제 예정).

- 총괄값 계열을 범례 선택과 무관하게 **횡단 기준**으로 뽑음
- 공용 배지 `common_util_mass_haul_badge.ts` — 종단 그래프 좌측 상단 오버레이,
  세부 내역은 툴팁
- B05: 상단줄의 「누가토량」 항목을 배지로 옮김(유토곡선 패널은 그대로 유지)
- B06: 유토곡선 그래프·범례·요약줄 삭제, 그 높이를 종단면도가 전부 사용

검증: B06 배지 −5,595.5㎥·범례 없음·종단 228px, B05 배지 −6,842.6㎥·상단줄에서 제거.
테스트 390 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 19:44:59 +09:00

87 lines
3.5 KiB
TypeScript

/* =============================================================================
* common_util_mass_haul_badge.ts
* 「최종 누가토량」 배지 — 종단 그래프 **좌측 상단에 겹쳐** 띄우는 한 줄.
*
* 왜 배지인가(2026-09-06 사용자 지시) — 유토곡선 그래프는 자리를 많이 먹는데, 계획선을
* 만지며 늘 봐야 하는 값은 **마지막 지점의 누가토량 하나**다. 그래서 그 값만 그래프 위에
* 겹쳐 두고, 곡선 자체는 B05 의 유토곡선 패널에서만 펼쳐 본다(B06 에서는 곡선을 뺐다).
*
* 기준은 **횡단**이다 — 종단 기준 곡선은 계획선만 보는 개략값이라 뒤에 없앨 예정이다
* (2026-09-06 사용자). 값을 넣는 쪽에서 횡단 기준 계열을 골라 넘긴다.
* ========================================================================== */
/** 배지에 실리는 값 한 벌 — 유토곡선 계산 결과에서 뽑는다. */
export interface MassHaulBadgeValues {
/** 마지막 측점의 누계 토량(㎥). 음수면 부족(토취). */
finalM3: number;
cutNaturalM3: number;
cutCompactedM3: number;
fillCompactedM3: number;
surplusM3: number;
shortageM3: number;
}
/** 누가토량 표기 — 천 단위 구분 + 소수점 1자리(유토곡선 요약과 같은 규칙). */
function volume(value: number): string {
return `${value.toLocaleString("ko-KR", { maximumFractionDigits: 1 })}㎥`;
}
export interface MassHaulBadge {
/** 그래프 컨테이너(`position: relative`)에 붙일 요소. */
root: HTMLElement;
/** 값을 갈아 끼운다. null 이면 배지를 숨긴다(아직 계산 못 한 상태). */
set: (values: MassHaulBadgeValues | null) => void;
}
/** 유토곡선 계산 결과 한 벌에서 배지 값을 뽑는다 — B05·B06 이 같은 규칙을 쓴다. */
export function badgeValuesFrom(result: {
points: ReadonlyArray<{ cumulative_volume_m3: number }>;
cut_natural_m3: { soil: number; ripping_rock: number; blasting_rock: number };
cut_compacted_m3: number;
fill_compacted_m3: number;
surplus_m3: number;
shortage_m3: number;
}): MassHaulBadgeValues {
const cut = result.cut_natural_m3;
const points = result.points;
return {
finalM3: points.length ? points[points.length - 1].cumulative_volume_m3 : 0,
cutNaturalM3: cut.soil + cut.ripping_rock + cut.blasting_rock,
cutCompactedM3: result.cut_compacted_m3,
fillCompactedM3: result.fill_compacted_m3,
surplusM3: result.surplus_m3,
shortageM3: result.shortage_m3,
};
}
/** 배지를 만든다. 붙이는 것은 부르는 쪽 몫이다(그래프 컨테이너 첫 자식). */
export function createMassHaulBadge(): MassHaulBadge {
const root = document.createElement("span");
root.className = "mass-haul-badge";
root.hidden = true;
const caption = document.createElement("em");
caption.textContent = "누가토량";
const value = document.createElement("strong");
root.append(caption, value);
return {
root,
set(values) {
if (!values) {
root.hidden = true;
return;
}
root.hidden = false;
root.classList.toggle("is-over", values.finalM3 < 0);
value.textContent = volume(values.finalM3);
root.title = [
`절토(자연) ${volume(values.cutNaturalM3)} · 절토(다짐) ${volume(values.cutCompactedM3)}`,
`성토(다짐) ${volume(values.fillCompactedM3)}`,
values.shortageM3 > 0
? `부족 ${volume(values.shortageM3)}`
: `잉여 ${volume(values.surplusM3)}`,
"기준: 횡단",
].join("\n");
},
};
}