BetaCharts

RadialChart

Several quantities, each as far round its own ring as it has got.

Overview

Several quantities, each as far round its own ring as it has got.

import { RadialChart } from '@xaui/native/radial-chart'

<RadialChart
  data={[
    { label: 'Calories', value: 1623, target: 2000 },
    { label: 'Pas', value: 5400, target: 10000 },
    { label: 'Exercice', value: 25, target: 120 },
  ]}
  labelKey="label"
  valueKey="value"
  maxKey="target"
/>

<RadialChart data={rows} labelKey="source" valueKey="kcal" maxValue={2000}>
  <Text>Calories</Text>
  <Text>700 kcal</Text>
</RadialChart>

The palette, the variants and the ink are the family's — chart.md. Like the PieChart and the RadarChart, it is square rather than framed, so it draws its own geometry rather than sitting in the shared plot.

First example

import { RadialChart } from '@xaui/native/radial-chart'
export function Example() {
return <RadialChart />
}

Anatomy

RadialChart is a standalone component with no public slots.

Usage

import { RadialChart } from '@xaui/native/radial-chart'

<RadialChart data={[ { label: 'Calories', value: 1623, target: 2000 }, { label: 'Pas', value: 5400, target: 10000 }, { label: 'Exercice', value: 25, target: 120 }, ]} labelKey="label" valueKey="value" maxKey="target" />

<RadialChart data={rows} labelKey="source" valueKey="kcal" maxValue={2000}> <Text>Calories</Text> <Text>700 kcal</Text> </RadialChart>

Root props

RadialChartProps

The node's inherited React Native props apply too, and so do its style props padding, margin, width and the rest.

PropTypeRequiredDescription
datareadonly Data[]YesThe rows. **The first is the outermost ring**, and the palette walks them in order.
labelKeyLKYesWhich key names each ring — what a legend would print.
valueKeyVKYesWhich key is the quantity.
maxKeyMK | undefinedNoWhich key holds that row's **own** target, for rings that are each a share of a different goal — 1 623 of 2 000 kcal beside 5 400 of 10 000 steps. It wins over `maxValue` wherever a row carries one, which is what lets a chart mix a per-row goal with a shared fallback.
maxValuenumber | undefinedNoOne target for every ring, for rings that are shares of the same thing. Unset and with no `maxKey`, it is the **largest value in the data**, so the biggest ring closes and the rest are read against it. That makes a figure honest about itself and says nothing about any other, exactly as the `RadarChart`'s `maxValue` does: a dashboard of radial charts should give all of them the same top.
variantChartVariant | undefinedNo
sizeChartSize | undefinedNoThe outermost ring's diameter.
colorstring | undefinedNoA raw tint (R7). The palette is walked out of it, a shade per ring.
thicknessnumber | undefinedNoHow thick every ring is, in points. A **raw value** that wins over `size`, the way `ProgressCircle`'s `strokeWidth` does — a figure that has to line up with something already on the screen is not a vocabulary question. Every ring shares it: rings of different weights read as different charts.
gapnumber | undefinedNoThe bare ground between two rings, in points.
hasTrackboolean | undefinedNoWhether the whole of each ring's distance is drawn behind it. Without it a ring at a fifth is an arc floating in space, with nothing saying how far it had to go.
childrenReactNodeNoWhat sits in the middle — a total, a label, an icon. It is **React Native laid over the canvas**, not SVG text, so it takes the theme's font and its scaling like any other `Text` on the screen, and it takes no touches.
isDisabledboolean | undefinedNo
styleStyleProp<ViewStyle>No

Slots

This component is standalone and exposes no public slot.

Variants, sizes and colour

This component adds no visual axis of its own. The values it does take are in the generated types above and in the live demo.

Accessibility

The source defines no extra rule. Keep the React Native labels, roles, states and focus order your case needs, then check the result with VoiceOver and TalkBack.

Migration from legacy

This component declares no rule of its own. The migration guide covers variants, colours and slots.

Implementation notes

A ring is not a slice

The PieChart splits one quantity into shares that add up to the whole. This draws several quantities that have nothing to do with each other, each against a target of its own.

Calories, steps and minutes do not sum to anything, and a donut of the three would be drawing a total nobody measured. That is the whole distinction, and it is the one to get right at the call site.

The first row is the outermost ring

And the palette walks the rows in that order, so the ring that catches the eye first is the row written first.

Each ring has its own target

what you havewhat you write
a goal per rowmaxKey="target"
one goal for all of themmaxValue={2000}
no goal at allneither — the largest value becomes the top

maxKey wins wherever a row carries one, so a chart can mix a per-row goal with a shared fallback.

With neither, the biggest ring closes and the rest are read against it. That makes a figure honest about itself and says nothing about any other — the RadarChart's maxValue rule, for the same reason: a dashboard of radial charts should give all of them the same top.

A reading of zero or below draws no arc: a ring runs from nothing to its target, and a negative value would ask for a dash offset longer than the path.

The track is the rest of the distance

Without it a ring at a fifth is an arc floating in space, with nothing saying how far it had to go — which is the one thing this figure exists to say. hasTrack={false} gives it up for a figure that is a glyph rather than a chart.

Every track is drawn before every ring, so a ring's rounded cap is never cut by the ground of the one inside it.

The rings thin rather than disappear

The stroke is centred on the path, so a ring drawn at the box's own radius loses its outer half to the canvas edge — and six series at the default thickness ask for more room than a phone-sized figure has.

So the geometry is clamped to the room there actually is: the gap takes at most half of it, and the thickness takes what is left, divided evenly. What gives is the thickness, because the alternative is a chart that silently drops its innermost rings.

Every ring shares one thickness. Rings of different weights read as different charts.

The middle is React Native

The PieChart's arrangement, for the PieChart's reason: what sits in the middle is children in a View laid over the canvas — a Text, a total, an icon — so it takes the theme's font and its scaling like everything else on the screen. It takes no touches.

The canvas is turned a quarter turn on its wrapper rather than on each circle, which is ProgressCircle's arrangement and its reason: Circle's own rotation prop emits an invalid DOM property on web. It also leaves the middle upright, since that is the wrapper's sibling rather than its child.

Its own props

PropTypeDefaultNotes
dataData[]One row per ring, the first outermost
labelKeykeyof DataWhat names each ring
valueKeykeyof DataThe quantity
maxKeykeyof DataThat row's own target
maxValuenumberthe largest valueOne target for every ring
thicknessnumberthe size's ownPoints, raw — it wins over size
gapnumberhalf the thicknessPoints of bare ground between two rings
hasTrackbooleantrueThe whole of each ring's distance, behind it
childrenReactNodeWhat sits in the middle

In a `Chart`

The frame carries the words and the legend, and its seriesCount is what walks the legend's dots to the same length as the rings:

<Chart seriesCount={3}>
  <Chart.Header>
    <Chart.Heading>
      <Chart.Title>Activité du jour</Chart.Title>
    </Chart.Heading>
    <Chart.Legend labels={['Calories', 'Pas', 'Exercice']} />
  </Chart.Header>
  <RadialChart data={rows} labelKey="label" valueKey="value" maxKey="target" />
</Chart>