#nullable enable using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; using UnityEngine.UIElements; using UVC.Util; namespace SHI.Modal.NW { /// /// 네트워크 다이어그램 노드의 드래그 모드를 정의합니다. /// public enum NodeDragMode { /// 드래그 불가 (고정 위치) None, /// 수평(X축) 이동만 가능 HorizontalOnly, /// 수직(Y축) 이동만 가능 (기본값) VerticalOnly, /// 자유롭게 이동 가능 Free } /// /// NW(네트워크 다이어그램) 차트를 표시하는 UI Toolkit 컴포넌트입니다. /// /// 개요: /// /// JSON 파일에서 작업 데이터를 로드하여 네트워크 다이어그램 형태로 시각화합니다. /// 각 작업은 노드로 표시되며, ERE_NW_NXT_ACTV_CD 필드를 통해 노드 간 연결선이 그려집니다. /// 노드를 드래그하여 위치를 조정할 수 있습니다. /// /// /// 주요 기능: /// /// JSON 데이터 로드 및 파싱 (NWChartDataTask) /// 노드 자동 배치 (겹침 방지 알고리즘) /// 노드 간 연결선 렌더링 (충돌 우회 경로) /// 노드 드래그 이동 (수직/수평/자유 모드) /// 타임라인 헤더 (날짜 기반) /// /// /// 네트워크 구조: /// /// ERE_NW_ACTV_CD - 현재 노드의 활동 코드 /// ERE_NW_NXT_ACTV_CD - 다음 노드로의 연결 (화살표) /// STDT - 시작일 (노드의 X 위치 결정) /// /// /// 사용 예시: /// /// var chart = root.Q<NWChart>(); /// chart.DragMode = NodeDragMode.VerticalOnly; /// chart.Load("path/to/nw_data.json"); /// chart.OnExpand += () => { /* 확장 처리 */ }; /// /// /// 관련 리소스: /// /// Resources/SHI/Modal/NW/NWChart.uxml - 메인 레이아웃 /// /// [UxmlElement] public partial class NWChart : VisualElement, IDisposable { #region IDisposable private bool _disposed = false; #endregion private const string UXML_PATH = "SHI/Modal/NW/NWChart"; public Action? OnExpand; /// /// 노드 드래그 모드 설정 /// public NodeDragMode DragMode { get; set; } = NodeDragMode.VerticalOnly; private Button? _expandBtn; // Network diagram settings private float pixelsPerDay = 18f; private float nodeWidth = 60f; private float nodeHeight = 30f; private Color nodeColor = new Color(0.2f, 0.6f, 0.9f, 1f); private Color nodeEndColor = new Color(0.9f, 0.8f, 0.2f, 1f); private Color lineColor = new Color(0.3f, 0.3f, 0.3f, 1f); private VisualElement? root; private VisualElement? headerTimeline; private VisualElement? monthsLayer; private VisualElement? daysLayer; private VisualElement? networkCanvas; private VisualElement? nodesLayer; private VisualElement? linesLayer; private ScrollView? contentScroll; private List? tasks; private Dictionary tasksByActivityCode = new(); private Dictionary nodeElements = new(); private Dictionary nodePositions = new(); // 연결선 캐싱 (fromCode_toCode -> ConnectionElements) private Dictionary connectionCache = new(); // 연결선 요소들을 묶어서 관리 private class ConnectionElements { public VisualElement[] Lines = Array.Empty(); public VisualElement? Arrow; public string FromCode = ""; public string ToCode = ""; public int Ptch; } // 노드 외곽 우회를 위한 여백 private float routingPadding = 8f; // 드래그 관련 변수 private VisualElement? draggingNode; private string? draggingActivityCode; private Vector2 dragStartMousePos; private Vector2 dragStartNodePos; private bool isDragging; private DateTime projectStartDate; public DateTime ProjectStartDate => projectStartDate; private DateTime projectEndDate; public DateTime ProjectEndDate => projectEndDate; private int totalDays; private float canvasHeight; public NWChart() { var visualTree = Resources.Load(UXML_PATH); if (visualTree != null) { visualTree.CloneTree(this); } else { Debug.LogError($"Failed to load UXML at path: {UXML_PATH}"); } _expandBtn = this.Q