# Legend

A presentational legend for maps and charts in one of five modes: threshold, continuous, diverging, categorical or proportional symbols.

**Category:** Components/Graphics/Legend

**Import:** `import { Legend } from '@reuters-graphics/graphics-components'`

## Props

| Prop | Type | Default | Required | Description |
|------|------|---------|:--------:|-------------|
| `title` | `string` | `''` |  | Optional legend heading displayed above the scale. |
| `subtitle` | `string` | `''` |  | Optional subtitle displayed beneath the title. |
| `mode` | `LegendMode` | `'threshold'` |  | Legend rendering mode. Options: `threshold`, `continuous`, `diverging`, `categorical`, `proportional-symbols` |
| `items` | `LegendItem[] \| LegendSymbolItem[]` | `[]` |  | Legend entries. Threshold/diverging modes use numeric bounds and colors; categorical mode uses label and color pairs; proportional-symbols mode uses numeric values and optional labels. |
| `stops` | `LegendStop[]` | `[]` |  | Ordered continuous color stops with numeric values. |
| `ticks` | `LegendTick[]` | `[]` |  | Optional tick values and labels for continuous mode. |
| `midpoint` | `LegendMidpoint \| null` | `null` |  | Diverging midpoint with a numeric value and optional label. |
| `formatter` | `LegendFormatter \| null` | `null` |  | Optional formatter applied to numeric values. |
| `noData` | `LegendNoData \| null` | `null` |  | Optional fallback swatch for missing values. |
| `width` | `ContainerWidth` | `'normal'` |  | Width of the legend within the text well. Options: `narrower`, `narrow`, `normal`, `wide`, `wider`, `widest`, `fluid` |

## Types

```typescript
export type LegendMode =
    | 'threshold'
    | 'continuous'
    | 'diverging'
    | 'categorical'
    | 'proportional-symbols';

export type LegendFormatter = (value: number) => string;

export interface LegendItem {
    /** CSS color for the bin or category swatch. */
    color: string;
    /** Lower bound of the bin (inclusive). Omit for an open-ended first bin. */
    from?: number | null;
    /** Upper bound of the bin (exclusive). Omit for an open-ended last bin. */
    to?: number | null;
    /** Optional explicit label. Generated from the bounds when omitted. */
    label?: string;
  }

export interface LegendStop {
    /** Numeric position of the stop along the domain. */
    value: number;
    /** CSS color at this stop. */
    color: string;
    /** Optional explicit label. */
    label?: string;
  }

export interface LegendTick {
    /** Numeric position of the tick along the domain. */
    value: number;
    /** Optional explicit label. Formatted from `value` when omitted. */
    label?: string;
  }

export interface LegendMidpoint {
    /** Numeric value of the midpoint within the legend domain. */
    value: number;
    /** Optional explicit label. Formatted from `value` when omitted. */
    label?: string;
  }

export interface LegendSymbolItem {
    /** Non-negative numeric value mapped to circle area. */
    value: number;
    /** Optional explicit label. Formatted from `value` when omitted. */
    label?: string;
  }

export interface LegendNoData {
    /** Label shown next to the fallback swatch. */
    label: string;
    /** Optional CSS color for the fallback swatch. */
    color?: string;
  }
```

## Examples

### Threshold

```svelte
<Legend
  title="Annual average PM2.5"
  subtitle="Micrograms per cubic meter"
  mode="threshold"
  items={[
    { to: 12, color: 'var(--tr-light-orange)' },
    { from: 12, to: 35, color: 'var(--tr-orange)' },
    { from: 35, to: 55, color: 'var(--tr-dark-orange)' },
    { from: 55, color: 'var(--tr-dark-red)' },
  ]}
  noData={{ label: 'Data not available' }}
/>
```

### Continuous Gradient

```svelte
<Legend
  title="Graduation rate"
  mode="continuous"
  stops={[
    { value: 0, color: 'var(--tr-superlight-blue)' },
    { value: 50, color: 'var(--tr-light-blue)' },
    { value: 100, color: 'var(--tr-dark-blue)' },
  ]}
  ticks={[
    { value: 0, label: '0%' },
    { value: 25, label: '25%' },
    { value: 50, label: '50%' },
    { value: 75, label: '75%' },
    { value: 100, label: '100%' },
  ]}
/>
```

### Diverging Midpoint

```svelte
<Legend
  title="Today's difference from the normal high of 1961-1990"
  mode="diverging"
  items={/* array — see Props/Types for full type */}
  midpoint={{ value: 0, label: '±0°' }}
  formatter={(value: number) => {
    if (value === 0) {
      return '0°';
    }

    return `${value > 0 ? '+' : '−'}${Math.abs(value)}°`;
  }}
/>
```

### Categorical

```svelte
<Legend
  title="Hurricanes since 1980"
  subtitle="By Saffir-Simpson category"
  mode="categorical"
  items={/* array — see Props/Types for full type */}
/>
```

### Proportional Symbols

```svelte
<Legend
  title="Population"
  subtitle="in millions"
  mode="proportional-symbols"
  items={[
    { value: 1400, label: '1,400' },
    { value: 600, label: '600' },
    { value: 150, label: '150' },
    { value: 0, label: '0' },
  ]}
/>
```

### Map Layout

```svelte
<TileMap
  id="legend-demo-map"
  center={[0, 20]}
  zoom={0}
  height="460px"
  onMapReady={addCycloneLayer}
>
  {#snippet legend()}
    <Legend
      title="Hurricanes since 1980"
      subtitle="By Saffir-Simpson category"
      mode="categorical"
      items={cycloneCategories}
    />
  {/snippet}
</TileMap>
```

## Documentation

# Legend

A legend or key for maps and data displays. Renders one of five
modes.

They are:

- **`threshold`** — discrete bins with color swatches and break ticks
- **`continuous`** — a continuous gradient with axis ticks
- **`diverging`** — threshold bins with a highlighted midpoint
- **`categorical`** — square swatches with labels in a horizontal row
- **`proportional-symbols`** — nested circles with leader lines and labels

The optional `noData` prop renders a separate fallback swatch for missing,
unknown, or unavailable values across every mode.

The legend sizes itself to the text well with the `width` prop, matching the
other graphics components.

## Threshold

Discrete bins, each with its own color. Labels are generated from the numeric
bounds unless you pass an explicit `label`.

## Continuous gradient

A smooth gradient built from ordered `stops`. Pass `ticks` to control the axis
labels.

## Diverging midpoint

Threshold bins centered on a highlighted `midpoint`. Use `formatter` to control
how numeric boundaries are displayed.

## Categorical

Square swatches with labels laid out in a wrapping row.

## Proportional symbols

Nested circles sized by area, with leader lines and labels.

## With a map

`Legend` is standalone and can be placed anywhere in the layout, including above
or below a `TileMap`.

## Props
