Skip to content

차트(OLE/OOXML) 지원 트래킹 이슈 #1431

Description

@johndoekim

개요

차트는 현재 읽기(렌더)·보존까지만 구현돼 있고 상호작용(선택/이동/속성)·내용 편집은 미구현이다. 본 트래킹은 차트 지원을 렌더 커버리지(C) → 개체 1급화(A) → 내용 편집(B) 순으로 단계화한다. C-first 이유: rhwp는 본질이 뷰어이고 "차트 (미지원)" 빈 박스가 가장 가시적 결함이며, 로드맵("기본 차트 렌더")·기존 정책(#1251 "parity 아니라 객체 손실 방지")과 일치하고, 정답지 PDF로 검증 가능하기 때문.

픽셀 단위 한컴 parity는 1차 목표 아님(아래 Non-goals). 실행은 트랙별 서브이슈로 분기(#536 형식).

현황 (측정값)

  • 모던(2018+) 차트는 OOXMLChartContents(DrawingML) + 레거시 Contents 둘 다 보유(검증 코퍼스 27/27). HWP=HWPX 렌더 동일.

  • 렌더 커버리지: 13/27 렌더, 14/27 "차트 (미지원)" 빈 박스. 렌더되는 13종은 한컴 PDF 대비 데이터·기하는 정확, 스타일 4갭(① 제목 누락 ② 팔레트 초록-우선 vs 한컴 파랑-우선 ③ 범례 하단 vs 우측 ④ Y축 max vs nice-scale). (스타일 갭은 막대/원/선 표본 관찰 → 13종 일반화 가정.)

    • ⚠️ 정정(2026-06-21, C1a 시각판정 발견): "13종 데이터·기하 정확"은 누적(stacked/percentStacked) 차트에 대해 과대평가였다. 누적은 4갭에 없는 기하 갭인데 누락 — 2D 누적/백프로 막대 4종은 grouped로, 누적 라인 3종은 독립 선으로 오렌더 중. 막대 누적 = C1a 편입(C1a: 3D막대·3D원형·ofPie 차트 라우팅 (#1431 Track C) #1453), 라인 누적 = C1d.
  • 미지원 14종 분해 (OoxmlChart::parse 직접 실행으로 확정):

    버킷 종류 파서 상태 막힌 이유
    데이터 OK · 라우팅만 3D막대·3D원형·ofPie 7 series·값·cats 완전 추출됨 chart_type=Unknown이라 renderer가 bail (src/ooxml_chart/renderer.rs:64)
    데이터 OK · HLC 렌더 필요 stock(고가저가종가·시가고가저가종가) 2 series(고/저/종) 값 추출됨 HLC 표현 미구현(선 근사는 오해 유발)
    데이터 미추출 scatter 5종 5 c:xVal/c:yVal 미파싱 → values 빈 배열 파서가 c:val만 읽음

Non-goals / 가드레일

  • 렌더는 Rust SVG→RawSvg / OOXML→네이티브 SVG 경로 유지. charming/ECharts 도입 금지(재지시 전까지).
  • 저장은 OLE blob 보존 계약 유지(트랙 B 승인 전 재생성 금지).
  • 픽셀 단위 한컴 parity는 1차 목표 아님(HWP OLE/차트 객체 정합성 개선: 143E433F503322BD33.hwp #1251 정책). 커버리지 + 합리적 스타일까지가 1차.
  • HWP3 전용 분기 금지(공통 모듈 규칙).

선행 작업

  • P-1 코퍼스 fixture 승격: 차트 샘플 27종을 samples/chart/(hwp+hwpx) + pdf/chart/(한컴2022 정답지)로 추가·커밋. (직접 제작본·전부 <50MB → 일반 git.) C/A 회귀 가드의 전제.

트랙

🟡 Track C — 렌더 정합 (FIRST). 검증 = 정답지 PDF

완료기준: 코퍼스 27종 export-svg에 "차트 (미지원)" placeholder 0건 + 시각 판정 통과(스타일 4갭 포함 합리적 수준).

  • C1a (C1a: 3D막대·3D원형·ofPie 차트 라우팅 (#1431 Track C) #1453) ✅ 구현완료·local/devel 통합 (2026-06-21) 3D막대·3D원형·ofPie 라우팅 (7): 파서 handle_start에 요소명 인식(bar3DChart→Column, pie3DChart/ofPieChart→Pie) → 기존 렌더러로 그림. 근거: 파서가 값 이미 추출함(스파이크 확정). + 막대 누적 보정 편입(C1a: 3D막대·3D원형·ofPie 차트 라우팅 (#1431 Track C) #1453, 2026-06-21): 시각판정에서 render_barsc:grouping 무시(항상 grouped) 발견 → stacked/percentStacked 렌더 구현. 대상 6종 = 3D 누적세로/가로(2) + 2D 누적세로/가로(2) + 2D 백프로기준누적세로/가로(2). (트리거가 C1a의 3D 누적막대라 C1a에 편입; 막대만, 라인은 C1d.)
  • C1b (C1b: 분산형(scatter) 차트 렌더링 (#1431 Track C) #1660) ✅ 구현완료·devel merge (PR C1b: 분산형(scatter) 차트 렌더링 (#1431 Track C) #1662, 2026-06-29) scatter (5): c:xVal/c:yVal 파싱 + OoxmlSeries.x_values 확장(신규 타입 분리 안 함 — C2에서 SeriesData 합타입 재평가) + render_scatter(2 수치축, 점/직선/Catmull-Rom 곡선/표식, c:scatterStyle 단독 구분) + 소수 축 라벨 + 축 분류 가드(scatter 두 valAx의 보조축 오분류 차단). 0-baseline 편입(한컴 PDF 확인, 막대/선 value_range_for와 일관). gap④(Y축 max nice-scale headroom)는 작업지시자 결정(2026-06-29)으로 C1c 이관 — 공용 nice_range 정책 갭이라 전 차트 일괄 보정. 전체 테스트·clippy green, 시각판정 정합.
  • C1c (C1c: 차트 스타일 4갭 보정 (#1431 Track C) #1882) 스타일 4갭 보정(제목·팔레트·범례 위치·Y축 nice-scale headroom). (2026-07-04 착수.)
  • C1d 라인 누적 렌더: render_linec:grouping 미인식 → 누적꺽은선·표식이있는누적꺽은선·백프로기준누적꺽은선(3종)이 독립 선으로 오렌더. 누적/백프로 라인 렌더 구현. 막대 누적(C1a 편입)과 대칭. (차트(OLE/OOXML) 지원 트래킹 이슈 #1431, 2026-06-21 등록.)
  • C2 stock HLC 렌더(2) + per-type fidelity 정밀화(3D 입체, ofPie 보조플롯 등) — 후속.

🟢 Track A — 개체 1급화 (그림 개체 cascade 미러). 검증 = rhwp 내부 UX

완료기준: 차트가 그림 개체와 동일하게 선택/이동/리사이즈/속성/복붙 가능 + 저장 라운드트립 무결.

  • P0 RawSvgNode(현재 svg:String만)에 secIdx/paraIdx/controlIdx+bbox 부여 → collect_controls OLE 케이스 + ControlLayoutItem 'ole'. Track C가 동일 노드 생성부(shape_layout)를 손대므로 C와 조율(coordinated), 순수 병렬 아님.
  • P1 클릭 hit-test/선택. P2 속성 다이얼로그. P3 이동/리사이즈/회전. P4 복사/붙여넣기/삭제+undo. P5 z-order/겹침.
  • P6 HWP/HWPX 저장 라운드트립 가드. (바이트 보존은 로컬 확인, "한컴이 제대로 연다"는 원격 Windows+한컴으로 확인.)

🔵 Track B — 내용 편집 (메인테이너 go/no-go 필요)

상태: 결정 전무(백지) — "보류"된 게 아니라 아직 묻지 않은 것. roadmap/vision에 없는 새 방향이고 blob 보존 계약을 바꾸는 일이라, 착수 전 메인테이너 go/no-go가 필요(A·C의 일반 승인보다 무거운 제품 결정).

  • 의존: A (선택 = 편집 진입점). 검증: 원격 Windows+한컴으로 가능(오라클 확보됨).
  • go/no-go: 차트 데이터 편집을 프로젝트 방향으로 채택할지 결정 요청.
  • (go 시) B1 숫자 데이터 편집(모던=OOXML c:val/c:cat 편집→중첩 OLE CFB 스트림 재기록 / HWPX는 zip 엔트리 교체; 레거시=Contents f64 in-place 패치, 실현성 별도 스파이크 검증). B2 행·열·라벨. B3 종류 변환.

순서·의존·검증

트랙 순서 의존 검증 환경
P-1 0 로컬
C 1st P-1 정답지 PDF 로컬
A C와 조율 P-1 (B의 선행) rhwp 내부 UX; P6 저장은 한컴(원격) 로컬 / P6 한컴 원격
B 마지막 A + go/no-go 원격 Windows+한컴 원격 가능

리스크 / 오픈 질문

  • C1a 2D 근사(3D→평면, ofPie→단일 원형)가 한컴과 얼마나 다른지 → 시각 판정으로 수용선 확정.
  • scatter (x,y) 모델: OoxmlSeries 확장 vs 신규 타입 (C1b 설계).
  • stock HLC 렌더 정책(고/저 막대 + 종가 마커, C2).
  • A P0 ↔ C 노드 재작업 충돌 방지(같은 파일) — 작업 순서 조율.
  • 픽셀 fidelity 천장: 어디까지가 1차 vs 후속(HWP OLE/차트 객체 정합성 개선: 143E433F503322BD33.hwp #1251 정책 준수).

근거 자료

스펙 mydocs/tech/한글문서파일형식_차트_revision1.2.pdf(레거시) / ECMA-376 DrawingML(외부). 결정·분석 mydocs/tech/hwp_ole_chart_renderer_architecture_decision_1251.md(ADR), hwp_ole_chart_visual_diff_against_hancom_pdf_1251.md, mydocs/pr/archives/pr_1268_review.md. 기존 이슈 #195/#221·#1251/#1268·#1283·#1156, 트래킹 #536.

서브이슈 인덱스 (생성 시 갱신)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions