packages feed

hgg-core-0.2.0.0: src/Graphics/Hgg/Spec/Bake.hs

-- |
-- Module      : Graphics.Hgg.Spec.Bake
-- Description : Baking the Resolver in (resolving ColByName references to inline data)
-- Copyright   : (c) 2026 Aelysce Project (Toshiaki Honda)
-- License     : BSD-3-Clause
--
-- [日本語]: 'Graphics.Hgg.Spec' の module 分割で切り出し。 spec 内の全
-- 'ColByName' を 'Resolver' で inline ('ColNum' / 'ColTxt') 化する 'bakeSpec'
-- を持つ。 'VisualSpec' / 'Layer' 全体を走査する sink (被参照ゼロ) ゆえ分割
-- module 群の最後段。 公開 API は従来どおり 'Graphics.Hgg.Spec' (facade) が
-- re-export する。 挙動・出力は完全に不変。
--
-- [English]: A module split out of 'Graphics.Hgg.Spec'. Provides
-- 'bakeSpec', which inlines every 'ColByName' in the spec via the
-- 'Resolver' (into 'ColNum' / 'ColTxt'). Since it is a sink that walks the
-- whole 'VisualSpec' / 'Layer' tree (nothing else references it), it sits
-- last among the split modules. The public API is still re-exported by the
-- 'Graphics.Hgg.Spec' facade as before; behavior and output are completely
-- unchanged.
{-# LANGUAGE OverloadedStrings #-}
module Graphics.Hgg.Spec.Bake
  ( bakeSpec
  ) where

import           Graphics.Hgg.Spec.Column
import           Graphics.Hgg.Spec.Layer (Layer (..))
import           Graphics.Hgg.Spec.Mark (ColorEnc (..))
import           Graphics.Hgg.Spec.Visual (VisualSpec (..))

-- ===========================================================================
-- Resolver の焼き込み (Phase 8 B16): ColByName を inline (ColNum/ColTxt) に解決
-- ===========================================================================
-- PS canvas backend は Resolver を持たず spec JSON だけ受け取るため、 ColByName
-- (列名参照) のままだと PS で解決できず描画されない (= pairs/facet/legend が空)。
-- JSON 出力前に bakeSpec で全 ColRef を inline 化すると PS でも描ける。

-- | [日本語]: ColByName を Resolver で解決し ColNum/ColTxt に置換 (解決不能なら
--   元のまま)。
--   [English]: Resolves a ColByName via the Resolver and replaces it with
--   ColNum/ColTxt (left unchanged if it cannot be resolved).
bakeColRef :: Resolver -> ColRef -> ColRef
bakeColRef r cr@(ColByName n) = case r n of
  Just (NumData v) -> ColNum v
  Just (TxtData v) -> ColTxt v
  Nothing          -> cr
bakeColRef _ cr = cr

bakeColorEnc :: Resolver -> ColorEnc -> ColorEnc
bakeColorEnc r (ColorByCol cr)        = ColorByCol (bakeColRef r cr)
-- Phase 9 A-5 fix: ColorByContinuous も inline 化しないと PS (emptyResolver) で色も
-- legend も出ない (= legend-continuous で発覚)。
bakeColorEnc r (ColorByContinuous cr) = ColorByContinuous (bakeColRef r cr)
bakeColorEnc _ ce                     = ce

bakeLayer :: Resolver -> Layer -> Layer
bakeLayer r l = l
  { lyEncX    = bakeColRef r <$> lyEncX l
  , lyEncY    = bakeColRef r <$> lyEncY l
  , lyEncZ    = bakeColRef r <$> lyEncZ l   -- ★ Phase 64 A11: ternary 第 3 成分列
  , lyEncY2   = bakeColRef r <$> lyEncY2 l
  , lyErrorX  = bakeColRef r <$> lyErrorX l
  , lyErrorY  = bakeColRef r <$> lyErrorY l
  , lyChain   = bakeColRef r <$> lyChain l
  , lyShapeBy = bakeColRef r <$> lyShapeBy l
  , lySizeBy  = bakeColRef r <$> lySizeBy l
  , lyAlphaBy = bakeColRef r <$> lyAlphaBy l
  , lyLinetypeBy = bakeColRef r <$> lyLinetypeBy l
  , lyLabel   = bakeColRef r <$> lyLabel l
  , lyColor   = bakeColorEnc r <$> lyColor l
  , lyOverlay = map (bakeLayer r) (lyOverlay l)   -- ★ Phase 36 D2: sub-mark の inline 列も bake
  }

-- | [日本語]: spec 内の全 ColByName を Resolver で inline 化 (layers + facet +
--   subplots 再帰)。 JSON 出力前に呼ぶと PS でも Resolver 不要で描ける。
--   [English]: Inlines every ColByName in the spec via the Resolver
--   (recursing through layers + facet + subplots). Calling this before
--   JSON output lets PS draw without needing a Resolver.
bakeSpec :: Resolver -> VisualSpec -> VisualSpec
bakeSpec r spec = spec
  { vsLayers   = map (bakeLayer r) (vsLayers spec)
  , vsFacet    = bakeColRef r <$> vsFacet spec
  , vsFacetRow = bakeColRef r <$> vsFacetRow spec
  , vsFacetCol = bakeColRef r <$> vsFacetCol spec
  , vsSubplots = map (bakeSpec r) (vsSubplots spec)
  }