チャート
チャートレシピは、サーバレンダリングされたデータテーブルを
Observable Plot の SVG チャートに
変えます。テーブルはデータソースであり、非 JavaScript のフォールバック
であり、スクリーンリーダー用のデータです — installChart() がそれを
読んでチャートを描きます。チャートごとの JavaScript はありません:
チャートの種類と系列ごとのマークはマークアップで宣言します。
このレシピはビヘイビアを必要とします —
installChart —
そして Observable Plot、自分で読み込む任意のピア依存です。Plot は
決して @hypermedia-components/core にバンドルされないため、
installChart は自動初期化の behaviors エントリには含まれません。
Plot がなければビヘイビアは no-op で、テーブルが見えたままになります。
別名: グラフ、可視化。
リージョンを切り替えてみてください — 各ボタンが
<figure class="hc-chart"> フラグメント(セマンティックなデータ
テーブル)を api/recipes/chart/ 配下の実エンドポイントから再取得し、
installChart が htmx:load で再描画します。JavaScript がなければ
同じエンドポイントがテーブルを読めるページとして返します —
テーブルこそがフォールバックそのものです。
| Month | Sales |
|---|---|
| Jan | 120 |
| Feb | 200 |
| Mar | 150 |
<figure class="hc-chart" data-hc-chart="bar" data-y-label="Sales ($k)"> <table class="hc-table"> <caption>Monthly sales</caption> <thead><tr><th>Month</th><th>Sales</th></tr></thead> <tbody> <tr><td>Jan</td><td>120</td></tr> <tr><td>Feb</td><td>200</td></tr> <tr><td>Mar</td><td>150</td></tr> </tbody> </table></figure>ビヘイビアのインストール
Section titled “ビヘイビアのインストール”Plot(ここでは CDN の UMD グローバル)を読み込み、ページごとに一度 インストールします:
<script src="https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/dist/plot.umd.min.js"></script><script type="module"> import { installChart } from '@hypermedia-components/core'; installChart(document, { plot: window.Plot });</script>installChart は window.Plot を自動で拾うため、CDN スクリプトの実行
後なら installChart() 単体でも動きます。plot を明示的に渡すほうが
明快で、グローバルの代わりにバンドルされたインポートも使えます。
テーブル契約
Section titled “テーブル契約”カテゴリカルなチャートでは、テーブルはこう読まれます:
- 1 列目 — x のカテゴリ。
- 2〜N 列目 — 各列が 1 系列。
<thead>のセルが系列名です。 - 各
<td>は数値に変換されます(1,200→1200。通貨記号や%は 取り除かれます)。 - 任意の
<caption>はチャートのタイトルになります。
チャートの種類
Section titled “チャートの種類”figure に data-hc-chart を設定します:
| 値 | 描画 |
|---|---|
bar | 縦棒。複数系列は積み上げ。 |
line | ノードの点つきの折れ線。系列ごとに 1 本。 |
area | 線の縁つきの塗りつぶし面。系列ごとに 1 つ。 |
combo | 列ごとのマーク — <th data-mark="bar|line|area"> を設定。 |
data-hc-chart は、自身の data-mark を持たない列のデフォルト
マークです。bar / line / area は、すべての列が 1 つのマークを
共有する場合にすぎません。
折れ線(line)
Section titled “折れ線(line)”| Week | Web | Mobile |
|---|---|---|
| W1 | 42 | 18 |
| W2 | 48 | 24 |
| W3 | 39 | 31 |
| W4 | 55 | 36 |
| W5 | 61 | 33 |
<figure class="hc-chart" data-hc-chart="line" data-y-label="Sessions (k)"> <table class="hc-table"> <caption>Weekly sessions</caption> <thead> <tr><th>Week</th><th>Web</th><th>Mobile</th></tr> </thead> <tbody> <tr><td>W1</td><td>42</td><td>18</td></tr> <tr><td>W2</td><td>48</td><td>24</td></tr> <tr><td>W3</td><td>39</td><td>31</td></tr> <tr><td>W4</td><td>55</td><td>36</td></tr> <tr><td>W5</td><td>61</td><td>33</td></tr> </tbody> </table></figure>面(area)
Section titled “面(area)”| Month | Used |
|---|---|
| Jan | 120 |
| Feb | 135 |
| Mar | 170 |
| Apr | 165 |
| May | 210 |
<figure class="hc-chart" data-hc-chart="area" data-y-label="Storage (GB)"> <table class="hc-table"> <caption>Storage used</caption> <thead> <tr><th>Month</th><th>Used</th></tr> </thead> <tbody> <tr><td>Jan</td><td>120</td></tr> <tr><td>Feb</td><td>135</td></tr> <tr><td>Mar</td><td>170</td></tr> <tr><td>Apr</td><td>165</td></tr> <tr><td>May</td><td>210</td></tr> </tbody> </table></figure>コンボチャート(棒 + 線)
Section titled “コンボチャート(棒 + 線)”data-mark で列ごとにマークを宣言します。combo の下で無印の列の
デフォルトは bar です。
| Month | Sales | Target |
|---|---|---|
| Jan | 120 | 150 |
| Feb | 200 | 160 |
| Mar | 150 | 170 |
<figure class="hc-chart" data-hc-chart="combo" data-y-label="Sales ($k)"> <table class="hc-table"> <caption>Monthly sales vs target</caption> <thead> <tr> <th>Month</th> <th data-mark="bar">Sales</th> <th data-mark="line">Target</th> </tr> </thead> <tbody> <tr><td>Jan</td><td>120</td><td>150</td></tr> <tr><td>Feb</td><td>200</td><td>160</td></tr> <tr><td>Mar</td><td>150</td><td>170</td></tr> </tbody> </table></figure>Plot は線を棒のバンドスケールに自動で載せるため、点は棒の中心に揃い ます。系列が y の範囲を共有していれば追加の設定は不要です。本物の 第 2 y 軸はこのレシピのスコープ外です。
積み上げ、グループ、横棒、散布図、スパークライン
Section titled “積み上げ、グループ、横棒、散布図、スパークライン”同じテーブル契約を、figure 全体の 6 つのプリセットが拡張します
(列ごとの data-mark コンボはこれらには適用されません)。
積み上げ棒(bar-stacked)
Section titled “積み上げ棒(bar-stacked)”複数系列が積み上がります(複数系列の bar がすでにやることの
明示形)。
| Quarter | Store | Online |
|---|---|---|
| Q1 | 80 | 45 |
| Q2 | 95 | 70 |
| Q3 | 60 | 98 |
<figure class="hc-chart" data-hc-chart="bar-stacked" data-y-label="Orders"> <table class="hc-table"> <caption>Orders by channel</caption> <thead> <tr><th>Quarter</th><th>Store</th><th>Online</th></tr> </thead> <tbody> <tr><td>Q1</td><td>80</td><td>45</td></tr> <tr><td>Q2</td><td>95</td><td>70</td></tr> <tr><td>Q3</td><td>60</td><td>98</td></tr> </tbody> </table></figure>グループ棒(bar-grouped)
Section titled “グループ棒(bar-grouped)”系列が各カテゴリ内で横並びに描画されます。カテゴリ軸がラベルを運び、 凡例が系列名を示します。
| Quarter | Store | Online |
|---|---|---|
| Q1 | 80 | 45 |
| Q2 | 95 | 70 |
| Q3 | 60 | 98 |
<figure class="hc-chart" data-hc-chart="bar-grouped" data-y-label="Orders"> <table class="hc-table"> <caption>Orders by channel</caption> <thead> <tr><th>Quarter</th><th>Store</th><th>Online</th></tr> </thead> <tbody> <tr><td>Q1</td><td>80</td><td>45</td></tr> <tr><td>Q2</td><td>95</td><td>70</td></tr> <tr><td>Q3</td><td>60</td><td>98</td></tr> </tbody> </table></figure>横棒(bar-x)
Section titled “横棒(bar-x)”ランキングの形です: カテゴリが y に載るため長いラベルが読みやすく、
値は x に載ります。複数系列は積み上がります。data-y-label、
data-y-min / data-y-max、data-y-format は値軸(ここでは x)を
設定し、値なしの data-tip はカテゴリ軸に沿ってスナップします。
| Product | Sales |
|---|---|
| Wireless headphones | 320 |
| Mechanical keyboard | 260 |
| USB-C dock | 210 |
| Laptop stand | 150 |
| Webcam | 90 |
<figure class="hc-chart" data-hc-chart="bar-x" data-tip data-y-label="Sales ($k)"> <table class="hc-table"> <caption>Top products</caption> <thead> <tr><th>Product</th><th>Sales</th></tr> </thead> <tbody> <tr><td>Wireless headphones</td><td>320</td></tr> <tr><td>Mechanical keyboard</td><td>260</td></tr> <tr><td>USB-C dock</td><td>210</td></tr> <tr><td>Laptop stand</td><td>150</td></tr> <tr><td>Webcam</td><td>90</td></tr> </tbody> </table></figure>横棒グループ(bar-x-grouped)
Section titled “横棒グループ(bar-x-grouped)”各カテゴリの中で系列が横方向に並びます(行軸でファセット)。
| Quarter | Store | Online |
|---|---|---|
| Q1 | 80 | 45 |
| Q2 | 95 | 70 |
| Q3 | 60 | 98 |
<figure class="hc-chart" data-hc-chart="bar-x-grouped" data-y-label="Orders"> <table class="hc-table"> <caption>Orders by channel</caption> <thead> <tr><th>Quarter</th><th>Store</th><th>Online</th></tr> </thead> <tbody> <tr><td>Q1</td><td>80</td><td>45</td></tr> <tr><td>Q2</td><td>95</td><td>70</td></tr> <tr><td>Q3</td><td>60</td><td>98</td></tr> </tbody> </table></figure>散布図(scatter)
Section titled “散布図(scatter)”数値軸 2 本: 1 列目が数値の x(data-x-type のデフォルトは
number)、各系列列が 1 つの点集合、任意の <th data-role="r"> 列が
点の半径を駆動します。
| Height | Weight | Count |
|---|---|---|
| 150 | 52 | 3 |
| 158 | 58 | 6 |
| 165 | 63 | 12 |
| 172 | 70 | 9 |
| 180 | 78 | 4 |
<figure class="hc-chart" data-hc-chart="scatter" data-y-label="Weight (kg)"> <table class="hc-table"> <caption>Height vs weight</caption> <thead> <tr><th>Height</th><th>Weight</th><th data-role="r">Count</th></tr> </thead> <tbody> <tr><td>150</td><td>52</td><td>3</td></tr> <tr><td>158</td><td>58</td><td>6</td></tr> <tr><td>165</td><td>63</td><td>12</td></tr> <tr><td>172</td><td>70</td><td>9</td></tr> <tr><td>180</td><td>78</td><td>4</td></tr> </tbody> </table></figure>スパークライン(sparkline)
Section titled “スパークライン(sparkline)”コンパクトな Plot スタイルのトレンド: 軸・グリッド・凡例はオフ、
data-height の指定がなければ高さ 48 px。依存なしのインライン
トレンドには、単体の
スパークラインコンポーネントの
ほうがたいてい適しています — このプリセットは Plot で統一された
ダッシュボードのためにあります。
| Day | Value |
|---|---|
| 1 | 12 |
| 2 | 18 |
| 3 | 9 |
| 4 | 22 |
| 5 | 17 |
| 6 | 28 |
| 7 | 25 |
<figure class="hc-chart" data-hc-chart="sparkline"> <table class="hc-table"> <caption>30-day trend</caption> <thead> <tr><th>Day</th><th>Value</th></tr> </thead> <tbody> <tr><td>1</td><td>12</td></tr> <tr><td>2</td><td>18</td></tr> <tr><td>3</td><td>9</td></tr> <tr><td>4</td><td>22</td></tr> <tr><td>5</td><td>17</td></tr> <tr><td>6</td><td>28</td></tr> <tr><td>7</td><td>25</td></tr> </tbody> </table></figure>ヒストグラムとヒートマップ
Section titled “ヒストグラムとヒートマップ”ヒストグラム(histogram)
Section titled “ヒストグラム(histogram)”1 本の数値列をカウントの棒にビニングします(data-x-type の
デフォルトは number。余分な列は無視。data-bins がビン数の上限)。
| ms |
|---|
| 90 |
| 95 |
| 110 |
| 120 |
| 125 |
| 140 |
| 160 |
| 180 |
| 210 |
| 260 |
| 340 |
| 520 |
<figure class="hc-chart" data-hc-chart="histogram" data-bins="6" data-y-label="Requests"> <table class="hc-table"> <caption>Response times (ms)</caption> <thead> <tr><th>ms</th></tr> </thead> <tbody> <tr><td>90</td></tr> <tr><td>95</td></tr> <tr><td>110</td></tr> <tr><td>120</td></tr> <tr><td>125</td></tr> <tr><td>140</td></tr> <tr><td>160</td></tr> <tr><td>180</td></tr> <tr><td>210</td></tr> <tr><td>260</td></tr> <tr><td>340</td></tr> <tr><td>520</td></tr> </tbody> </table></figure>ヒートマップ(heatmap)
Section titled “ヒートマップ(heatmap)”行カテゴリが y、列ヘッダーが x、セル値が連続の塗りをカラー凡例
つきで駆動するマトリクス形(data-scheme が Plot のスキームを選び
ます。カテゴリカルな系列パレットは適用されません)。行 / 列の順序は
書かれたとおりに保たれます。
| Slot | Mon | Tue | Wed | Thu | Fri |
|---|---|---|---|---|---|
| Morning | 3 | 7 | 5 | 8 | 4 |
| Afternoon | 6 | 4 | 9 | 5 | 7 |
| Evening | 9 | 2 | 6 | 3 | 10 |
<figure class="hc-chart" data-hc-chart="heatmap" data-y-label="Visits"> <table class="hc-table"> <caption>Visits by slot</caption> <thead> <tr><th>Slot</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th></tr> </thead> <tbody> <tr><td>Morning</td><td>3</td><td>7</td><td>5</td><td>8</td><td>4</td></tr> <tr><td>Afternoon</td><td>6</td><td>4</td><td>9</td><td>5</td><td>7</td></tr> <tr><td>Evening</td><td>9</td><td>2</td><td>6</td><td>3</td><td>10</td></tr> </tbody> </table></figure>ウォーターフォール(waterfall)
Section titled “ウォーターフォール(waterfall)”財務ブリッジ図です: 符号付きの増減を 1 列だけ読み、直前までの
累計から増減後の累計まで棒が浮いて描かれます。<tr data-total> を
付けた行は絶対値のアンカーです — セルには実際の合計値を入れます
(非 JavaScript のテーブルが正しいままになります)。その棒は 0 から
その値まで描かれ、累計はその値にリセットされます。増加 / 減少 / 合計の
棒はそれぞれ --hc-chart-waterfall-increase / -decrease / -total
で着色されます(デフォルトは success / error / muted)。
| Step | Amount |
|---|---|
| Opening | 100 |
| Sales | +80 |
| Refunds | -15 |
| Costs | -30 |
| Closing | 135 |
<figure class="hc-chart" data-hc-chart="waterfall" data-tip data-y-label="Cash ($k)"> <table class="hc-table"> <caption>Cash bridge</caption> <thead> <tr><th>Step</th><th>Amount</th></tr> </thead> <tbody> <tr data-total><td>Opening</td><td>100</td></tr> <tr><td>Sales</td><td>+80</td></tr> <tr><td>Refunds</td><td>-15</td></tr> <tr><td>Costs</td><td>-30</td></tr> <tr data-total><td>Closing</td><td>135</td></tr> </tbody> </table></figure>data-tip を付けると、ツールチップにステップ・累計・増減が表示され
ます。凡例(increase / decrease / total)はデフォルトで表示され、
data-legend="false" で非表示にできます。
ツールチップ(data-tip)
Section titled “ツールチップ(data-tip)”data-tip を付けると、ホバーでツールチップが表示されます — x 値、
y 値、そして(複数系列なら)系列名。コンボチャートでも同時に表示される
ツールチップは常に 1 つだけです。値なしの data-tip は x 方向に
スナップします(棒・折れ線・時系列に最適)。scatter は最近傍点
(xy)がデフォルトです。data-tip="x" / "y" / "xy" で明示指定
できます。histogram のツールチップはビンの範囲と件数を、heatmap は
行 × 列 + 値を表示します。デモをホバーしてみてください:
| Week | Web | Mobile |
|---|---|---|
| W1 | 42 | 18 |
| W2 | 48 | 24 |
| W3 | 39 | 31 |
| W4 | 55 | 36 |
| W5 | 61 | 33 |
<figure class="hc-chart" data-hc-chart="line" data-tip data-y-label="Sessions (k)"> <table class="hc-table"> <caption>Weekly sessions</caption> <thead> <tr><th>Week</th><th>Web</th><th>Mobile</th></tr> </thead> <tbody> <tr><td>W1</td><td>42</td><td>18</td></tr> <tr><td>W2</td><td>48</td><td>24</td></tr> <tr><td>W3</td><td>39</td><td>31</td></tr> <tr><td>W4</td><td>55</td><td>36</td></tr> <tr><td>W5</td><td>61</td><td>33</td></tr> </tbody> </table></figure>ツールチップはクライアント側のインタラクションです — サーバサイドレンダリングのパスには 適用されません。
クリックで遷移(data-link)
Section titled “クリックで遷移(data-link)”1列目のセルを本物のリンクにして figure に data-link を付けると、
棒・点・セルのクリックがその行のアンカーへ転送されます。チャートは
URL もリクエストも一切持ちません: 素の href ならページ遷移、
アンカーに htmx 属性(data-hx-get、data-hx-target、
data-hx-push-url など)があれば書いたとおりに swap されます。同じ
リンクが非 JavaScript・キーボード・スクリーンリーダーの操作経路にも
なります(テーブルがアクセシブルな操作面であり続けます)。
<figure class="hc-chart" data-hc-chart="bar" data-link data-tip data-y-label="Sales ($k)"> <table class="hc-table"> <caption>Sales by product</caption> <thead> <tr><th>Product</th><th>Sales</th></tr> </thead> <tbody> <tr><td><a href="/products/alpha" data-hx-get="/products/alpha/panel" data-hx-target="#detail">Alpha</a></td><td>320</td></tr> <tr><td><a href="/products/beta" data-hx-get="/products/beta/panel" data-hx-target="#detail">Beta</a></td><td>180</td></tr> </tbody> </table></figure>アンカーのない行は単に遷移しません。フォーカス追跡はツールチップの
pointer を再利用します(data-tip なしの場合は不可視のプローブ)。
pointer の半径 40px を超えた余白のクリックは何もせず、カーソルは
クリック可能なデータにフォーカスしている間だけポインターになります。
クライアント側限定で、histogram は対象外です(ビンが複数行を集約
するため)。
figure 共通のフォームモード(カテゴリ × 系列)
Section titled “figure 共通のフォームモード(カテゴリ × 系列)”行アンカーの粒度は行単位です。「クリックの意味はサーバが決める」
形にしたい場合や、複数系列チャートでどの系列がクリックされたかまで
必要な場合は、figure の中に <form> を置きます。クリック時に、データの
キー(x、series、value など)と一致する name を持つフィールドが
フォーカス中のデータで埋められ、フォームが送信されます — リクエストは
フォーム上の htmx が所有します:
<figure class="hc-chart" data-hc-chart="bar-grouped" data-link data-tip> <form data-hx-get="/reports/drill" data-hx-target="#detail"> <input type="hidden" name="x"> <input type="hidden" name="series"> </form> <table class="hc-table">…</table></figure><!-- Feb × Osaka をクリック → GET /reports/drill?x=Feb&series=Osaka --><form> は行アンカーより優先され、すべてのデータがクリック可能に
なります。非 JavaScript でもドリルダウンできる経路が必要なら、hidden の
代わりに可視のフィールド(<select name="x"> + 送信ボタン)にして
ください — 同じエンドポイントが両方に応えます。
y 軸: 範囲と表示形式
Section titled “y 軸: 範囲と表示形式”data-y-min / data-y-max は y のドメインを固定します —
パーセントを 0–100 に固定する、ダッシュボード内の複数チャートで軸を
揃える、折れ線をゼロ始まり以外にする、といった用途です(0 がドメイン外
になるとゼロ基準線は自動で省かれます)。data-y-format は
d3-format 文字列で目盛りを整形します
("s" → 1.2k、".0%"、",.0f")。
| Month | Revenue |
|---|---|
| Jan | 4,200 |
| Feb | 4,650 |
| Mar | 4,400 |
| Apr | 5,100 |
| May | 5,600 |
<figure class="hc-chart" data-hc-chart="line" data-tip data-y-min="3000" data-y-max="6000" data-y-format="s" data-y-label="Revenue (¥)"> <table class="hc-table"> <caption>Monthly revenue</caption> <thead> <tr><th>Month</th><th>Revenue</th></tr> </thead> <tbody> <tr><td>Jan</td><td>4,200</td></tr> <tr><td>Feb</td><td>4,650</td></tr> <tr><td>Mar</td><td>4,400</td></tr> <tr><td>Apr</td><td>5,100</td></tr> <tr><td>May</td><td>5,600</td></tr> </tbody> </table></figure>積み上げ棒では両端を明示的に指定してください — フォールバックの データ範囲は生のセル値を読むため、積み上げを考慮しません。
| 属性 | デフォルト | 効果 |
|---|---|---|
data-y-label | (なし) | y 軸ラベル。 |
data-title | <caption> | チャートタイトル。 |
data-x-type | category | category | number | date。 |
data-width | コンテナ幅 | Plot の幅(px)。 |
data-height | --hc-chart-height(320px) | Plot の高さ(px)。 |
data-legend | 自動(系列 ≥2 でオン) | false でカラー凡例を非表示。 |
data-tip | オフ | ホバーツールチップ。値なし、または x | y | xy。 |
data-y-min / data-y-max | データ範囲 | y ドメインを固定。 |
data-y-format | Plot 既定 | y 目盛りの表示形式(d3-format 文字列)。 |
data-link | オフ | クリックを行の1列目アンカーへ転送。 |
棒は category の x を期待します。number / date の x は
line / area に向きます。
それ以外はすべて: buildOptions フック
Section titled “それ以外はすべて: buildOptions フック”属性は高頻度のニーズをカバーします。それ以外は installChart に
buildOptions を渡してください — 描画直前に最終的な Plot スペックと
figure を受け取り、返したものがそのまま Plot に描画されます:
installChart(document, { plot: window.Plot, buildOptions: (spec, figure) => ({ ...spec, marginLeft: 60, y: { ...spec.y, ticks: 4 }, }),});何も返さなければ構築済みのスペックが使われるため、フックは観察だけに 使うこともできます。
チャートのクローム(目盛り、軸ラベル、グリッド)は
--hc-chart-axis と --hc-chart-grid を通じてテーマに従います。
系列色は固定のカテゴリカルパレット
--hc-chart-series-1 … --hc-chart-series-6 から来ます。描画時に解決
され、Plot のカラースケールへ渡されます。パレットは意図的に
テーマ非依存です — チャートの系列はブランドのアクセントに追従する
より、相互に区別可能であり続けるべきだからです。
:root { --hc-chart-series-1: #2563eb; /* override per series */}installChart は htmx:load を待ち受けるため、ページへスワップされた
チャートは自動で描画されます — スワップごとの JavaScript は不要です。
<div data-hx-get="/reports/sales" data-hx-trigger="load" data-hx-swap="innerHTML"> <!-- The server returns the <figure class="hc-chart">…</figure> fragment. --></div>非 htmx リクエスト(フルページロード)にも同じ読めるテーブルを返し、
非 JavaScript パスを機能させてください。フラグメントをレイアウトで包む
場合は HX-Request: true ヘッダーで htmx を検知します。
アクセシビリティ
Section titled “アクセシビリティ”- ソーステーブルは保持されます — 取り除かれるのではなく
.hc-sr-onlyでアクセシビリティツリーへ移されるため、支援技術は 完全なデータを読めます。 - 描画された
<svg>はaria-hidden="true"です: テーブルの装飾的な 複製なので、二重に読み上げられません。 - テーブルには常にチャートを説明する
<caption>を与えてください。
プログレッシブエンハンスメント
Section titled “プログレッシブエンハンスメント”- JavaScript なし →
<table class="hc-table">が普通の読める テーブルとして描画されます。 - JavaScript あり、Plot なし → 同じ: Plot なしの
installChartは no-op です。 - JavaScript + Plot → テーブルはアクセシビリティツリーへ移り、 SVG チャートが表示されます。
サーバサイドレンダリング
Section titled “サーバサイドレンダリング”チャートは、DOM シム(linkedom)の
下の Plot でサーバ上でも SVG に描画し、インラインで返せます —
クライアント側の Plot は不要になります。その場合は明示的な
marginLeft / marginBottom を設定してください — サーバの DOM シムは
自動軸マージンのためのテキスト計測をしません。figure は
data-state="rendered"(+ hc-sr-only のテーブルと aria-hidden の
SVG)つきで出力します: installChart() は描画済みの figure を認識して
放っておくため、SSR とクライアント描画のチャートは共存します。
トークンはクライアント側 CSS です — SSR では明示的な色を渡して
ください。動くスニペットは
契約に
あります。