Files
XRLib/Assets/work.md
2025-11-17 19:30:05 +09:00

8.1 KiB

간트 차트 구현 작업 지시서 (개선판 v1.3)

##1. 목표 (Overview)

  • StreamingAssets/isop_chart.json 로드 후 UI Toolkit 기반 간트 차트 생성.
  • 좌측 계층 컬럼(L1~L8) 표시, 우측 월/주/일3단 헤더 + 막대(기간) / 마커(단일일) 렌더.
  • 막대/마커 클릭 시 OnRowClickedByKey 호출.
  • 외부 선택 API(SelectByItemKey)로 행 하이라이트.
  • 수평/수직 스크롤 및 향후 줌(dayWidth) 지원.

##1.1 프로젝트 개요

항목 내용
프로젝트명 SN2662 블록 B11GP 생산 계획 시각화 시스템
목적 블록 생산 일정 실시간 모니터링 / 지연 즉시 파악 / 현장 의사결정 지원
주요 사용자 생산 관리자, 현장 반장, 설계/자재 담당자
사용 환경 태블릿(터치) + PC(마우스)

##2. 용어 & 기본 파라미터

항목 의미 기본값 조정 범위
dayWidth 1일당 픽셀 폭 16px 8~32px (줌)
rowHeight 1행 높이 28px 24~40px
MinDate/MaxDate 전체 데이터 기간 경계 파싱 계산 -
Periods 코드별 기간/마커 딕셔너리 각 Row별 -

##3. 데이터 구조 (Model)

class GanttChartData { List<BlockScheduleRow> Rows; DateTime? MinDate, MaxDate; }
class BlockScheduleRow { string? ProjNo, BlockNo, L1,L2,L3,L4,L5,L6,L7,L8; Dictionary<string,DateRange> Periods; }
class DateRange { DateTime? Start, End; int? Duration; bool IsMarker => Start.HasValue && !End.HasValue; }
  • JSON 필드 패턴: STDTxx = 시작일(Start), FNDTxx = 종료일(End), DURxx = 기간(일수).
  • 날짜 문자열 형식: yyyyMMdd.

##3.1 계획/실적 분리 확대 (미래 확장) 현재 JSON은 계획(Plan)만 제공. 실적(Actual) 데이터 추가 시 권장 구조:

class ExtendedScheduleItem {
 public string Code;
 public DateTime? PlannedStart, PlannedEnd;
 public DateTime? ActualStart, ActualEnd;
 public int? PlannedDuration, ActualDuration;
 public float Progress; //0..1
 public bool IsCritical; // 임계경로
 public int DelayDays => (ActualEnd.HasValue && PlannedEnd.HasValue) ? (int)(ActualEnd.Value - PlannedEnd.Value).TotalDays :0; // 음수면 조기 완료
 public int EarlyFinishDays => (DelayDays <0) ? -DelayDays :0;
 public bool IsDelayed => DelayDays >0;
}
  • DelayDays 음수일 경우 조기 완료(EarlyFinish) 표시 가능.

##4. 파싱 규칙

^STDT([0-9A-FM]{2})$ // 시작일
^FNDT([0-9A-FM]{2})$ // 종료일
^DUR([0-9A-FM]{2})$ // 일수
  • 시작만 있고 종료 없음 → 마커(단일 이벤트).
  • 시작/종료 모두 존재 → 기간 막대.
  • Duration 없으면 캘린더 일수로 자동 계산.

##5. Duration 계산 정책 (확정)

  • 기본: 캘린더 일수 (End - Start).Days +1.
  • 옵션: 근무일(월~금) 필요 시 별도 플래그 useBusinessDays → 계산 시 주말 제외.

##6. 레이아웃 & 타임라인 렌더링

  • left(px) = (Start - MinDate).TotalDays * dayWidth
  • width(px) = ((End - Start).TotalDays +1) * dayWidth
  • 헤더3단: Month / ISO Week / Day.
  • Span cell width = 구간 일수 * dayWidth.

##7. UI 계층 구조

Root
 ├─ HeaderContainer (MonthRow, WeekRow, DayRow)
 └─ BodyScroll
 └─ RowsContainer
 └─ Row
 ├─ HierarchyContainer (L1~L8)
 └─ SegmentsLayer (절대 위치 막대/마커)

##8. 스타일 전략

  • 코드별 USS 클래스: seg-code-XX, marker-code-XX.
  • 선택 상태: row-selected, segment-selected.
  • 외부 스타일 매핑 가능: GanttStyleConfig.json or ScriptableObject.

##9. 상호작용 & 이벤트

  • Segment/Marker 클릭 → OnRowClickedByKey(BlockNo).
  • 세그먼트 식별 확장: BlockNo|Code 문자열 전달 고려.
  • 터치 vs 마우스:
private void OnSegmentPointerDown(PointerDownEvent evt, BlockScheduleRow row, string code){
 if(evt.pointerType=="touch") ShowTouchPopup(row, code, evt.position);
 else ShowTooltip(row, code, evt.position);
}

##10. 아키텍처 & 모듈 분리

모듈 책임
GanttJsonParser JSON → 모델 변환
GanttBuilder UI 생성/레이아웃
GanttInteraction 이벤트/툴팁/선택
GanttVirtualizer 대량 행 가상화
GanttZoomController 줌/재계산/캐시 무효화
CriticalPathAnalyzer 선후관계 기반 임계경로 계산

##11. 에러 처리 & 로깅 (정책 확정)

케이스 처리 로그
파일 없음 더미 데이터 로드 후 경고 Error
날짜 파싱 실패 해당 코드 Skip Warning
Start > End 무효 처리 (Skip) Warning
중복 Start/End 마지막 값 채택 Info
파일 >5MB 경고 + 스트리밍 파서 권고 Info

##12. 성능 & 가상화

  • 행 >300 → 가상화 고려.
  • 목표:1000행 로드 <500ms / 메모리 증가 <50MB.
  • CalculateBarRect 캐시: Key=(Start,End,dayWidth,MinDate) → 줌(dayWidth)·범위 변경 시 캐시 Flush.

##13. 줌 & 스크롤 동기화

  • 헤더/바디 스크롤 동기화: 바디 Scroll 이벤트에서 헤더 translateX 적용.
  • 줌 변경 순서: dayWidth 변경 → 좌표 재계산 → 캐시 Flush → Layout pass.

##14. 확장 로드맵

  • Tooltip / Today 라인 / 필터 API / PNG Export.
  • 임계경로 강조 / D-3 알림 아이콘 / 조기완료(EarlyFinish) 표시.

##15. 체크리스트

Mandatory

  • JSON 로드
  • 파싱 & Periods 구성
  • Min/Max 날짜 계산
  • 헤더 렌더
  • 행 + 막대/마커 렌더
  • 클릭 이벤트 연결
  • 선택 하이라이트
  • USS 기본 스타일

Optional

  • 근무일 Duration 옵션
  • 가상화
  • 줌 컨트롤
  • Tooltip
  • Today 라인
  • 외부 색상 매핑
  • 계획/실적 분리 모델
  • 임계경로 분석
  • D-3 알림 / 지연 깜빡임 / 조기완료 표시

##16. 구현 스켈레톤

public void LoadFromStreamingAssets() {
 var path = Path.Combine(Application.streamingAssetsPath, "isop_chart.json");
 if (!File.Exists(path)) {
 Debug.LogError($"File not found: {path}");
 _data = CreateDummyData(); // 더미 로드 정책
 BuildUI();
 return;
 }
 var json = File.ReadAllText(path);
 var raw = JsonHelper.FromJsonDictArray(json);
 var data = GanttJsonParser.Parse(raw);
 LoadData(data);
 BuildUI();
}

##17. 테스트 계획

분류 항목
단위 날짜 파싱 / Start>End Skip 검증
단위 Duration 자동 계산(캘린더) & 근무일 옵션
단위 마커 vs 기간 구분(IsMarker)
단위 캐시 Flush(zoom/minDate 변경)
통합 클릭 이벤트 전달(BlockNo
통합 선택 하이라이트 토글
성능 1000 /5000 행 로드 시간 & 메모리 측정
UX 터치 팝업 ≤300ms 반응
시각 줌 변경 후 헤더/세그먼트 정렬 유지

##18. 리스크 & 대응

리스크 대응
대용량 JSON 스트리밍/청크 파서
잦은 줌 변경 최소/최대 줌 제한 + 캐시 재사용
색상 유지보수 외부 매핑 파일화
계획/실적 혼동 확장 시 모델 전환 마이그레이션 문서
태블릿 성능 저하 가상화 + 스타일 최소화

##19. Pending 결정

  • 근무일 옵션 실제 사용 여부.
  • 색상/코드 매핑 저장 위치.
  • 임계경로 입력 포맷(선후관계) 정의.

##20. 사용 흐름

var chart = FindObjectOfType<ModelDetailChartView>();
chart.LoadFromStreamingAssets();
chart.SelectByItemKey("B11GP");

##21. 향후 API 예시

public void ApplyFilter(DateTime? from, DateTime? to, string? code = null, string? blockNo = null);
public void SetZoom(float newDayWidth); // Flush + 재계산
public void ToggleTodayLine(bool enabled);
public void SetActualDates(string blockNo, string code, DateTime? actualStart, DateTime? actualEnd);
public IReadOnlyList<string> GetCriticalPathCodes();

##22. USS 샘플

.chart-row { flex-direction: row; height:28px; position: relative; border-bottom:1px solid #3A3A3A; }
.hierarchy-container { width:240px; flex-wrap: wrap; }
.hierarchy-cell { font-size:11px; width:60px; padding-left:4px; }
.segments-layer { flex-grow:1; position: relative; }
.segment { border-radius:3px; height:22px; }
.seg-code-21 { background:#3A7BFF; }
.seg-code-23 { background:#7BD95A; }
.marker { color:#2AA3FF; font-size:12px; }
.row-selected { background:rgba(255,255,0,0.15); }
.span-cell { text-align:center; font-size:11px; border-right:1px solid #222; }
.day-cell { text-align:center; font-size:10px; border-right:1px solid #333; width:16px; }
.segment.delayed { background:#d0021b; animation: blink1s infinite; }
.today-line { position:absolute; width:1px; background:#ff6b00; top:0; bottom:0; }
@keyframes blink {0%,100% { opacity:1; }50% { opacity:.3; } }

##23. 데이터 누락 대응

  • 렌더 필터:4x 계열 우선 →3x/5x 존재 시 추가 →0x/Mx 전부 null이면 제외.
  • Null 날짜: 렌더 생략, Progress=0.
  • 파싱 실패: Skip + Warning.

##24. 최종 검수 체크리스트

항목 기준
날짜 정확성 STDT/FNDT UI 값 = JSON 원본
가독성 태블릿 폰트 ≥14px, 대비 확보
반응성 터치 팝업 ≤300ms
안정성 Null90% 상황 문제 없음
임계경로 지연/조기완료 시 색상/아이콘 반영
dayWidth 변경 후 좌표/헤더 싱크 정확

##25. 종료 위 내용으로 구현 진행. Pending 결정 완료 시 문서 재갱신. (문서 버전: v1.3)