refactor(plan): 형상계획 ②의 교대 기본 정보 입력칸 제거, 삽도에 EL 표시
- ②의 교대 편집 영역에서 기본 정보 6칸과 기본값 복원 버튼을 뺌. 기본 정보 편집과 복원은 ①에만 남김 - ②의 삽도에 교좌면·기초 하단·지반고 값을 읽기 전용 라벨로 표시 (abut-section-svg.ts의 AbutLevels) - 날개벽 형식은 ②의 날개벽 카드에 그대로 둠 - 테스트 631건 통과, 타입 검사·빌드 통과. 브라우저 시각 확인은 미실시 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
18524460e8
commit
789f62adf0
3 files changed
+25
-6
No files matched your search
+10
-4
@@ -693,13 +693,19 @@ function fillAbutSlot(slot: (typeof ABUT_SLOTS)[keyof typeof ABUT_SLOTS], rec: A
|
||||
const msg = $<HTMLParagraphElement>(slot.msg);
|
||||
basic.replaceChildren();
|
||||
// ② puts the wing forms in their own card; ① keeps them in the basic items.
|
||||
const wingBox = 'wing' in slot ? $<HTMLDivElement>(slot.wing) : basic;
|
||||
// ② (plan card) shows no basic items: they are edited in ① only, and ② reads them off the 삽도 labels (2026-11-03).
|
||||
const planCard = 'wing' in slot;
|
||||
const wingBox = planCard ? $<HTMLDivElement>(slot.wing) : basic;
|
||||
wingBox.replaceChildren();
|
||||
bearings.replaceChildren();
|
||||
shape.replaceChildren();
|
||||
// 삽도 (벽체·흉벽 개략 단면): the values it names are the card's values, so the drawing follows each change.
|
||||
const drawing = el('div', undefined, 'abut-section');
|
||||
drawing.innerHTML = abutSectionSvg(resolveShape(rec.shape), { ...ABUT_SHAPE_DEFAULT, ...(rec.shape ?? {}) });
|
||||
drawing.innerHTML = abutSectionSvg(
|
||||
resolveShape(rec.shape),
|
||||
{ ...ABUT_SHAPE_DEFAULT, ...(rec.shape ?? {}) },
|
||||
{ seatEl: rec.seatEl, footingBottomEl: rec.foundationBottomEl, groundEl: rec.groundEl },
|
||||
);
|
||||
shape.append(drawing);
|
||||
msg.textContent = '';
|
||||
const apply = (next: AbutRecord) => {
|
||||
@@ -721,7 +727,7 @@ function fillAbutSlot(slot: (typeof ABUT_SLOTS)[keyof typeof ABUT_SLOTS], rec: A
|
||||
};
|
||||
const idOf = (suffix: string) => `${slot.prefix}-${rec.name}-${suffix}`;
|
||||
|
||||
for (const f of ABUT_EDIT_FIELDS) {
|
||||
for (const f of planCard ? [] : ABUT_EDIT_FIELDS) {
|
||||
const id = idOf(f.key);
|
||||
const lab = el('label', `${f.label}${f.unit ? ` (${f.unit})` : ''}`);
|
||||
lab.htmlFor = id;
|
||||
@@ -752,7 +758,7 @@ function fillAbutSlot(slot: (typeof ABUT_SLOTS)[keyof typeof ABUT_SLOTS], rec: A
|
||||
const def = state.abutDefaults.find((a) => a.name === rec.name);
|
||||
if (def) apply(restoreAbutDefault(def));
|
||||
});
|
||||
basic.appendChild(restore);
|
||||
if (!planCard) basic.appendChild(restore);
|
||||
|
||||
for (const b of rec.bearings) {
|
||||
const zId = idOf(`bz-${b.no}`);
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
import { type AbutShape, type ResolvedShape } from '../core/abut/shape';
|
||||
|
||||
/** EL values (m) the drawing names as read-only labels; they come from the record, not from this card. */
|
||||
export interface AbutLevels {
|
||||
seatEl: number;
|
||||
footingBottomEl: number;
|
||||
groundEl: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 벽체·흉벽 개략 단면 (시안 ② 삽도). Not to scale: the heights are fixed for legibility,
|
||||
* and the labels show the card's values in mm, so the numbers the user types are what the drawing names.
|
||||
* t runs along the 교대 직각 방향 (배면 −, 전면 +); the 교대축 is t = 0.
|
||||
*/
|
||||
export function abutSectionSvg(r: ResolvedShape, v: AbutShape): string {
|
||||
export function abutSectionSvg(r: ResolvedShape, v: AbutShape, levels?: AbutLevels): string {
|
||||
const S = 100; // px per m
|
||||
const YMAX = 4.6; // highest drawn height (m above the footing bottom)
|
||||
const tMin = r.footingBackM - 0.4;
|
||||
const tMax = r.footingFrontM + 0.6;
|
||||
const W = (tMax - tMin) * S;
|
||||
const H = (YMAX + 0.5) * S;
|
||||
const H = (YMAX + 0.8) * S;
|
||||
const X = (t: number) => (t - tMin) * S;
|
||||
const Y = (h: number) => (YMAX - h) * S;
|
||||
const fT = r.footingThicknessM;
|
||||
@@ -36,6 +43,7 @@ export function abutSectionSvg(r: ResolvedShape, v: AbutShape): string {
|
||||
text(4, Y(fT / 2) + 4, `저판 두께 ${v.footingThicknessMm}`),
|
||||
text(X(r.footingBackM), Y(0) + 18, `저판 뒷굽 ${v.footingBackMm}`),
|
||||
text(X(r.footingFrontM), Y(0) + 18, `저판 앞굽 ${v.footingFrontMm}`, 'end'),
|
||||
levels ? text(4, H - 44, `교좌면 ${levels.seatEl.toFixed(3)} · 기초 하단 ${levels.footingBottomEl.toFixed(3)} · 지반고 ${levels.groundEl.toFixed(3)} m`, 'start') : '',
|
||||
text(4, H - 22, '개략 도시 · 축척 아님', 'start'),
|
||||
text(4, H - 6, `흉벽 상단 Level 좌 ${v.parapetLevelLeftMm} · 우 ${v.parapetLevelRightMm} (계산 미사용, QA-4)`, 'start'),
|
||||
'</svg>',
|
||||
|
||||
@@ -20,6 +20,11 @@ describe('교대 삽도 (벽체·흉벽 개략 단면, 시안 ②)', () => {
|
||||
expect(svg).toContain('축척 아님');
|
||||
});
|
||||
|
||||
it('names the 교좌면, 기초 하단 and 지반고 EL as read-only labels when given', () => {
|
||||
const svg = abutSectionSvg(resolveShape(), ABUT_SHAPE_DEFAULT, { seatEl: 44.367, footingBottomEl: 40.895, groundEl: 33.984 });
|
||||
expect(svg).toContain('교좌면 44.367 · 기초 하단 40.895 · 지반고 33.984 m');
|
||||
});
|
||||
|
||||
it('draws the footing, wall and parapet as separate shapes', () => {
|
||||
const svg = abutSectionSvg(resolveShape(), ABUT_SHAPE_DEFAULT);
|
||||
expect(svg.match(/<rect /g)).toHaveLength(3);
|
||||
|
||||
Reference in new issue
Block a user