feat(abut-rebar): ③ 교대 부재 목록 단순화 · 철근표 선택 / 전체 선택 / 선택만 보기
- 부재 목록: 교각처럼 이름 + 경고 수 배지만. 배근 타입 · 번호 · 다음 단계는 툴팁과 카드 설명 줄로 - 철근표: 선택 칸, 행 클릭 단독 선택, 전체 선택/해제, 선택만 보기 (교각과 같은 rebarSelection · rebarIsolate) - 삽도: 여러 철근 강조, 선택만 보기면 나머지 숨김. B10 풍선은 B10-1 · B10-2를 함께 선택 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f4311d7f95
commit
d7714f7ef2
3 files changed
+63
-41
No files matched your search
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 교대 저판 배근 삽도 (2026-11-04, 시안 ③ 확대기초 카드, 교대확대기초철근.md §10): 교대축 직각 단면 (폭 W), 교대축 단면 (길이 L),
|
||||
* 상면 평면. 순수 문자열 함수. 번호 풍선(data-pick)을 누르면 그 철근만 강조한다; 강조할 번호는 `pick`으로 받는다.
|
||||
* 상면 평면. 순수 문자열 함수. 번호 풍선(data-pick)을 누르면 그 철근만 강조한다; 선택한 번호는 `pick`(철근표 번호 집합)으로, 선택만 보기는 `only`로 받는다.
|
||||
* 색은 역할 기준: 주철근 B1–B4 #0F5C66, 보조 B5–B8 #B4531F, 측면 B10 #2E7D32 점선, 전단 B9 #6B3FA0.
|
||||
*/
|
||||
import type { AbutFootingGeom, AbutFootingRebar } from '../core/abut/rebar/footing';
|
||||
@@ -14,21 +14,26 @@ const WALL = '#d9dee4';
|
||||
const text = (x: number, y: number, s: string, anchor = 'middle', fill = INK, size = 11) =>
|
||||
`<text x="${x.toFixed(1)}" y="${y.toFixed(1)}" text-anchor="${anchor}" font-size="${size}" fill="${fill}" font-family="JetBrains Mono, monospace">${s}</text>`;
|
||||
|
||||
/** Opacity of one bar group: dimmed when another bar is picked. B10 picks cover B10-1 and B10-2. */
|
||||
function opacity(pick: string | null, marks: string[]): number {
|
||||
if (!pick) return 1;
|
||||
return marks.some((m) => m === pick || (pick === 'B10' && m.startsWith('B10'))) ? 1 : 0.15;
|
||||
/** Selected bars (철근표 번호) and 선택만 보기. An empty selection shows every bar. */
|
||||
export type AbutRebarPick = { marks: ReadonlySet<string>; only: boolean };
|
||||
const NO_PICK: AbutRebarPick = { marks: new Set(), only: false };
|
||||
|
||||
/** Opacity of one bar group: dimmed (or hidden with 선택만 보기) when other bars are selected. */
|
||||
function opacity(pick: AbutRebarPick, marks: string[]): number {
|
||||
if (pick.marks.size === 0) return 1;
|
||||
return marks.some((m) => pick.marks.has(m)) ? 1 : pick.only ? 0 : 0.15;
|
||||
}
|
||||
|
||||
/** A clickable 번호 풍선. */
|
||||
function balloon(x: number, y: number, mark: string, color: string, pick: string | null): string {
|
||||
const on = pick === mark;
|
||||
function balloon(x: number, y: number, mark: string, color: string, pick: AbutRebarPick): string {
|
||||
// The B10 풍선 stands for B10-1 and B10-2.
|
||||
const on = [...pick.marks].some((m) => m === mark || (mark === 'B10' && m.startsWith('B10')));
|
||||
const r = mark.length > 3 ? 15 : 12;
|
||||
return `<g data-pick="${mark}" style="cursor:pointer" role="button" tabindex="0" aria-label="${mark} 강조"><circle cx="${x.toFixed(1)}" cy="${y.toFixed(1)}" r="${r}" fill="${on ? color : '#fff'}" stroke="${color}" stroke-width="1.4"/>${text(x, y + 4, mark, 'middle', on ? '#fff' : color, 10)}</g>`;
|
||||
}
|
||||
|
||||
/** 교대축 직각 단면 (폭 W): 왼쪽 배면(뒷굽) → 오른쪽 전면(앞굽). B1–B4 선, B5–B8 점, B10-1 점, B9 연직선. */
|
||||
export function abutFootingSectionWSvg(g: AbutFootingGeom, r: AbutFootingRebar, pick: string | null = null): string {
|
||||
export function abutFootingSectionWSvg(g: AbutFootingGeom, r: AbutFootingRebar, pick: AbutRebarPick = NO_PICK): string {
|
||||
const k = 0.12;
|
||||
const x0 = 60;
|
||||
const y0 = 46;
|
||||
@@ -82,7 +87,7 @@ export function abutFootingSectionWSvg(g: AbutFootingGeom, r: AbutFootingRebar,
|
||||
}
|
||||
|
||||
/** 교대축 단면 (길이 L, 가로 축척 0.4배): B5–B8 선(이음 위치), B1–B4 점, B10-2 점. 왼쪽 IP3 쪽. */
|
||||
export function abutFootingSectionLSvg(g: AbutFootingGeom, r: AbutFootingRebar, pick: string | null = null): string {
|
||||
export function abutFootingSectionLSvg(g: AbutFootingGeom, r: AbutFootingRebar, pick: AbutRebarPick = NO_PICK): string {
|
||||
const kx = 0.045;
|
||||
const kz = 0.12;
|
||||
const x0 = 50;
|
||||
@@ -132,7 +137,7 @@ export function abutFootingSectionLSvg(g: AbutFootingGeom, r: AbutFootingRebar,
|
||||
* 상면 평면: skew 평행사변형, 상면 B1·B3 (옵션에 따라 skew 선과 나란히 / 교대축 직각, 옵션 ② B1-S), B5·B7, B9, 벽체 밑 띠.
|
||||
* `skewK` = 날개벽 방향의 s / t 비 (장면의 abutSkewK): s(x) = s + skewK · x. 위 = 전면, 왼쪽 = IP3 끝 (s = L).
|
||||
*/
|
||||
export function abutFootingRebarPlanSvg(g: AbutFootingGeom, r: AbutFootingRebar, skewK: number, pick: string | null = null): string {
|
||||
export function abutFootingRebarPlanSvg(g: AbutFootingGeom, r: AbutFootingRebar, skewK: number, pick: AbutRebarPick = NO_PICK): string {
|
||||
const k = 0.045;
|
||||
const shiftMax = Math.abs(skewK) * g.W;
|
||||
const sMin = Math.min(0, skewK * g.W);
|
||||
|
||||
Reference in new issue
Block a user