You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
9.8 KiB
223 lines
9.8 KiB
<script lang="ts">
|
|
import { RadarChart } from '$uix/eidos/components/chart';
|
|
import { compileMorfo } from '$uix/morfo';
|
|
import { chartMorfo } from '@/uix/morfo/components/chart';
|
|
|
|
type Tab = 'live' | 'examples' | 'api' | 'morfo' | 'recipe' | 'a11y';
|
|
let tab = $state<Tab>('live');
|
|
|
|
const data = [
|
|
{ axis: 'Speed', current: 80, target: 90 },
|
|
{ axis: 'Reliability', current: 70, target: 85 },
|
|
{ axis: 'Comfort', current: 60, target: 78 },
|
|
{ axis: 'Safety', current: 90, target: 95 },
|
|
{ axis: 'Economy', current: 65, target: 72 },
|
|
{ axis: 'Design', current: 75, target: 82 }
|
|
];
|
|
|
|
let multi = $state(true);
|
|
let levels = $state(4);
|
|
let legend = $state(true);
|
|
let showTooltip = $state(true);
|
|
let animate = $state(false);
|
|
let size = $state(300);
|
|
|
|
const levelChoices = [3, 4, 5];
|
|
const sizes = [260, 300, 340];
|
|
const seriesKeys = $derived(multi ? ['current', 'target'] : 'current');
|
|
|
|
const compiled = compileMorfo(chartMorfo);
|
|
const partsList = $derived([...compiled.parts.byKebab.values()]);
|
|
|
|
const snippet = $derived(
|
|
[
|
|
"<script lang='ts'>",
|
|
" import { RadarChart } from '$uix/eidos/components/chart';",
|
|
'',
|
|
' // one row per axis (category) + one column per series',
|
|
' const data = [',
|
|
" { axis: 'Speed', current: 80, target: 90 },",
|
|
" { axis: 'Safety', current: 90, target: 95 }",
|
|
' // …',
|
|
' ];',
|
|
'</' + 'script>',
|
|
'',
|
|
'<RadarChart',
|
|
' {data}',
|
|
' axis="axis"',
|
|
multi ? " series={['current', 'target']}" : ' series="current"',
|
|
levels !== 4 && ` levels={${levels}}`,
|
|
!legend && ' legend={false}',
|
|
!showTooltip && ' tooltip={false}',
|
|
'/>'
|
|
]
|
|
.filter(Boolean)
|
|
.join('\n')
|
|
);
|
|
</script>
|
|
|
|
<div data-uix-canvas-inner>
|
|
<header>
|
|
<div data-uix-eyebrow>Charts · Radar</div>
|
|
<h1 data-uix-page-title>Radar chart</h1>
|
|
<p data-uix-page-lede>
|
|
A radar / spider chart — categories around a circle, each series a polygon whose vertices are the
|
|
value at each axis (placed by a radial <code>scaleLinear</code> from the zero-dependency
|
|
<code>$libs/plots</code> engine). N-gon grid rings + spokes; hover a sector for the values.
|
|
</p>
|
|
<div data-uix-page-meta>
|
|
<span data-uix-meta-pill><span data-uix-meta-key>render</span>svg · 0-dep</span>
|
|
<span data-uix-meta-pill><span data-uix-meta-key>axes</span>{data.length}</span>
|
|
<span data-uix-meta-pill><span data-uix-meta-key>series</span>{multi ? 2 : 1}</span>
|
|
<span data-uix-meta-pill><span data-uix-meta-key>rings</span>{levels}</span>
|
|
</div>
|
|
</header>
|
|
|
|
<div data-uix-stage>
|
|
<div data-uix-stage-area style="justify-content: center;">
|
|
<RadarChart {data} axis="axis" series={seriesKeys} {levels} {legend} {size} {animate} tooltip={showTooltip} ariaLabel="Vehicle ratings" />
|
|
</div>
|
|
<div data-uix-stage-trace>
|
|
<span data-uix-stage-trace-key>renders</span>
|
|
<span><span data-uix-stage-trace-event>{data.length} axes</span> · {multi ? 2 : 1} series · {levels} rings</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div data-uix-tabs role="tablist">
|
|
<button data-uix-tab data-active={tab === 'live'} onclick={() => (tab = 'live')}>Live</button>
|
|
<button data-uix-tab data-active={tab === 'examples'} onclick={() => (tab = 'examples')}>Examples</button>
|
|
<button data-uix-tab data-active={tab === 'api'} onclick={() => (tab = 'api')}>API</button>
|
|
<button data-uix-tab data-active={tab === 'morfo'} onclick={() => (tab = 'morfo')}>
|
|
<span data-uix-layer-badge="morfo">morfo</span>
|
|
<span data-uix-tab-count>{partsList.length}p</span>
|
|
</button>
|
|
<button data-uix-tab data-active={tab === 'recipe'} onclick={() => (tab = 'recipe')}>Recipe</button>
|
|
<button data-uix-tab data-active={tab === 'a11y'} onclick={() => (tab = 'a11y')}>A11y</button>
|
|
</div>
|
|
|
|
{#if tab === 'live'}
|
|
<section data-uix-section>
|
|
<h2 data-uix-section-title>Controls</h2>
|
|
<p data-uix-section-desc>Pass <code>data</code> as rows of <code>{`{ axis, ...series }`}</code>, with <code>axis</code> + <code>series</code> naming the keys. Every control changes the live chart.</p>
|
|
<div data-uix-controls>
|
|
<label data-uix-control>
|
|
<span data-uix-control-label>rings (levels)</span>
|
|
<span data-uix-chips role="radiogroup">
|
|
{#each levelChoices as l}<button data-uix-chip data-active={levels === l} onclick={() => (levels = l)}>{l}</button>{/each}
|
|
</span>
|
|
</label>
|
|
<label data-uix-control>
|
|
<span data-uix-control-label>size</span>
|
|
<span data-uix-chips role="radiogroup">
|
|
{#each sizes as s}<button data-uix-chip data-active={size === s} onclick={() => (size = s)}>{s}</button>{/each}
|
|
</span>
|
|
</label>
|
|
<label data-uix-control>
|
|
<span data-uix-control-label>series</span>
|
|
<span data-uix-switch><input type="checkbox" bind:checked={multi} /><span data-uix-switch-label>{multi ? 'current + target' : 'current only'}</span></span>
|
|
</label>
|
|
<label data-uix-control>
|
|
<span data-uix-control-label>legend</span>
|
|
<span data-uix-switch><input type="checkbox" bind:checked={legend} /><span data-uix-switch-label>{legend ? 'on' : 'off'}</span></span>
|
|
</label>
|
|
<label data-uix-control>
|
|
<span data-uix-control-label>tooltip</span>
|
|
<span data-uix-switch><input type="checkbox" bind:checked={showTooltip} /><span data-uix-switch-label>{showTooltip ? 'on' : 'off'}</span></span>
|
|
</label>
|
|
<label data-uix-control>
|
|
<span data-uix-control-label>animate</span>
|
|
<span data-uix-switch><input type="checkbox" bind:checked={animate} /><span data-uix-switch-label>{animate ? 'bloom' : 'off'}</span></span>
|
|
</label>
|
|
</div>
|
|
<div data-uix-code>
|
|
<div data-uix-code-head>
|
|
<span data-uix-layer-badge="eidos">eidos</span>
|
|
<span>RadarChart</span>
|
|
<span data-uix-code-lang>svelte</span>
|
|
</div>
|
|
<pre><code>{snippet}</code></pre>
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
|
|
{#if tab === 'examples'}
|
|
<section data-uix-section>
|
|
<h2 data-uix-section-title>Examples</h2>
|
|
<div data-uix-stage-area style="display: flex; gap: 1.5rem; flex-wrap: wrap; justify-content: center;">
|
|
<RadarChart {data} axis="axis" series="current" size={240} levels={3} ariaLabel="Single series" />
|
|
<RadarChart {data} axis="axis" series={['current', 'target']} size={240} ariaLabel="Two series" />
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
|
|
{#if tab === 'api'}
|
|
<section data-uix-section>
|
|
<h2 data-uix-section-title>API reference</h2>
|
|
<div data-uix-table-wrap>
|
|
<table data-uix-table>
|
|
<thead><tr><th>Prop</th><th>Type</th><th>Default</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="name">data</td><td class="type">{`Record<string, unknown>[]`}</td><td class="default empty">—</td><td>One row per axis/category.</td></tr>
|
|
<tr><td class="name">axis</td><td class="type">string</td><td class="default empty">—</td><td>Key of the axis (category) label.</td></tr>
|
|
<tr><td class="name">series</td><td class="type">{`string | string[]`}</td><td class="default empty">—</td><td>Series key(s) — one polygon each.</td></tr>
|
|
<tr><td class="name">max</td><td class="type">number</td><td class="default">niced</td><td>Radial domain max.</td></tr>
|
|
<tr><td class="name">levels</td><td class="type">number</td><td class="default">4</td><td>Concentric grid rings.</td></tr>
|
|
<tr><td class="name">size</td><td class="type">number</td><td class="default">300</td><td>Diameter in pixels.</td></tr>
|
|
<tr><td class="name">legend / tooltip</td><td class="type">boolean</td><td class="default">true</td><td>Chrome toggles.</td></tr>
|
|
<tr><td class="name">format</td><td class="type">{`(v: number) => string`}</td><td class="default empty">—</td><td>Tooltip value formatter (locale-aware default).</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
|
|
{#if tab === 'morfo'}
|
|
<section data-uix-section>
|
|
<h2 data-uix-section-title><span data-uix-layer-badge="morfo">morfo</span> · chart family contract</h2>
|
|
<p data-uix-section-desc>Radar is part of the <code>chart</code> family (<code>scope:['eidos']</code>, 0 events): the root is the <code>provider</code> SVG (<code>role="img"</code>); it adds radar-specific <code>data-chart-radar-*</code> surfaces. The shared contract:</p>
|
|
<div data-uix-table-wrap>
|
|
<table data-uix-table>
|
|
<thead><tr><th>Part</th><th>Marker</th><th>Element</th><th>Role</th><th>Optional</th></tr></thead>
|
|
<tbody>
|
|
{#each partsList as part}
|
|
<tr><td class="name">{part.kebab}</td><td><code data-uix-part-marker>[{part.marker}]</code></td><td class="type"><{part.defaultElement}></td><td class="type">{part.role ?? '—'}</td><td class="default">{part.optional ? 'yes' : 'no'}</td></tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
|
|
{#if tab === 'recipe'}
|
|
<section data-uix-section>
|
|
<h2 data-uix-section-title>Eidos recipe</h2>
|
|
<div data-uix-table-wrap>
|
|
<table data-uix-table>
|
|
<thead><tr><th>Surface</th><th>Token</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="name">series polygon</td><td class="type">var(--color-{'{'}role{'}'}-solid) + fill-opacity var(--chart-area-opacity)</td></tr>
|
|
<tr><td class="name">rings / spokes</td><td class="type">var(--color-border-subtle) · var(--chart-grid-width)</td></tr>
|
|
<tr><td class="name">labels</td><td class="type">var(--color-content-secondary)</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
|
|
{#if tab === 'a11y'}
|
|
<section data-uix-section>
|
|
<h2 data-uix-section-title>Accessibility</h2>
|
|
<div data-uix-table-wrap>
|
|
<table data-uix-table>
|
|
<thead><tr><th>Part</th><th>Attribute</th><th>Value</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="name">provider (svg)</td><td>role / aria-label</td><td class="type">"img" / ariaLabel</td></tr>
|
|
<tr><td class="name">rings / spokes</td><td>decorative</td><td class="type">visual grid only</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<p data-uix-section-desc style="margin-top: 0.75rem;">Pass <code>ariaLabel</code> summarising the comparison (e.g. "Vehicle ratings: current vs target").</p>
|
|
</div>
|
|
</section>
|
|
{/if}
|
|
</div>
|