@tanstack/charts
Version:
<div align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/api/readme/charts.png?theme=dark" /> <source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/
136 lines (111 loc) • 4.33 kB
Markdown
---
title: Dodge Layouts
description: Reference for responsive dodgeX and dodgeY dot collision layouts, anchors, padding, radii, identity, and scale ownership.
---
`dodgeY` preserves each dot's scaled x position and derives a collision-free y
position in final plot pixels. `dodgeX` transposes the layout: y is preserved
and x is derived.
```ts
import { dodgeY } from '@tanstack/charts/dodge'
import { dot } from '@tanstack/charts/dot'
dot(rows, {
x: 'value',
key: 'id',
r: 4,
layout: dodgeY({
anchor: 'middle',
padding: 1,
}),
})
```
The layouts and `createDotLayout` are also exported from `/charts` and
`/charts/universal`.
## Signatures
```ts
function dodgeY(options?: {
anchor?: 'top' | 'middle' | 'bottom'
padding?: number
fit?: 'overflow' | 'compress'
}): DodgeYLayout
function dodgeX(options?: {
anchor?: 'left' | 'middle' | 'right'
padding?: number
fit?: 'overflow' | 'compress'
}): DodgeXLayout
function createDotLayout(options: {
axis: 'x' | 'y'
anchor: ChartValue
resolve(context: {
chart: ChartBounds
measuredPositions: readonly number[]
radii: readonly number[]
}): readonly number[]
}): DotLayout
```
`dodgeY` defaults to `bottom`; `dodgeX` defaults to `left`. `padding` is the
empty pixel distance between neighboring circle edges and defaults to `1`.
It must be finite and nonnegative.
`fit` defaults to `overflow`, preserving collision-free placement even when
the swarm extends beyond the plot. Use `fit: 'compress'` to fit crowded
offsets inside the plot without changing the measured coordinate or radii.
Compression can make circles overlap. Layouts that already fit are unchanged.
If a circle's diameter exceeds the available plot dimension, compression
throws a `RangeError`; reduce `r` or provide more space. Clipping an overflowing
swarm does not remove its points from keyboard or pointer interaction.
The public type surface also includes `CreateDotLayoutOptions`, `DotLayout`,
`DotLayoutResolveContext`, `DodgeOptions`, `DodgeXAnchor`, `DodgeYAnchor`,
`DodgeXOptions`, and `DodgeYOptions`.
## Custom layouts
Use `createDotLayout` when placement depends on final plot bounds but is not a
dodge. The resolver receives the preserved channel's scaled pixel positions
and the final radii in materialized valid-row order. Return one finite
cross-axis pixel position per materialized row. `dot` validates the result and
retains the authored `anchor` as the derived interaction-point value.
```ts
const rowLayout = createDotLayout({
axis: 'y',
anchor: 'rows',
resolve: ({ chart, measuredPositions, radii }) =>
measuredPositions.map(
(_position, index) => chart.y + radii[index] + index * 12,
),
})
```
## Scale ownership
The measured channel remains an ordinary semantic chart value. A `dodgeY`
dot contributes only x scale values, so its chart definition needs an x scale
but no y scale. A `dodgeX` dot needs only a y scale.
```ts
defineChart({
marks: [
dot(rows, {
x: 'economy',
layout: dodgeY({ anchor: 'middle' }),
}),
],
scales: {
x: { scale: scaleLinear().domain([5, 50]) },
y: null,
},
})
```
Do not configure the generated channel: `y` with `dodgeY`, or `x` with
`dodgeX`. The generated interaction-point value is the logical anchor while
its `x` and `y` fields contain the actual laid-out pixel center.
## Collision and radius
Collision distance is the sum of both final dot radii and `padding`. Configure
`r` and `rScale` once on `dot`; the layout receives the same resolved radii
used for rendering.
Placement is synchronous and deterministic. Edge anchors choose the nearest
valid inward position. Middle anchors choose the valid position with the
smallest absolute displacement. Fixed-radius rows retain source order;
variable-radius rows are placed largest first with source order as the stable
tie-breaker.
## Identity, facets, and grouping
Every rendered point retains its source datum, source index, key, group,
state, and motion policy. Supply `key` when the measured channel contains
duplicates.
Each facet resolves its child dodge layout against that cell's final scales
and bounds. `z` and `color` affect ordinary dot grouping and paint; they do not
create separate collision lanes. Use facets when groups need independent
swarm bounds.