ChartDonut
Num cartão de painel
Por natureza
Agosto de 2026.
- ServiçoR$ 148,2K
- ProdutoR$ 62,4K
- LocaçãoR$ 24,6K
- FreteR$ 11,5K
Sem a lista embaixo
Anel fino
- ServiçoR$ 148,2K
- ProdutoR$ 62,4K
- LocaçãoR$ 24,6K
- FreteR$ 11,5K
import { ChartDonut } from '@rivocode/ui/chart'Quando usar
Rosca com o total no meio.
<ChartDonut
data={porNatureza}
valueKey="total"
nameKey="natureza"
centerValue={compact(246700)}
centerLabel="no mês"
/>
A pizza responde "qual é a maior fatia" e nada mais. A rosca responde a mesma coisa e ainda usa o buraco para dizer o total, que é o número que a pessoa veio buscar. Um painel que mostra a divisão sem mostrar o total obriga a somar de cabeça.
O anel
thickness é a espessura, em fração do raio: quanto mais fino o anel, maior o
buraco, e é ali que o total precisa caber. Em 1 ela fecha e vira pizza.
O número do meio fica preso à largura do buraco. Total comprido escapando por cima do anel é o defeito clássico dessa peça.
O miolo apaga enquanto o ponteiro lê uma fatia, e isso é de propósito. A dica que aparece já traz o número daquela fatia; manter o total no centro ao mesmo tempo deixaria dois números na tela sem dizer qual é qual, e o de baixo do dedo é o que a pessoa foi buscar. O centro volta sozinho quando o ponteiro sai — não há prop para desligar, e nada se perde, porque o total está a um movimento de distância.
Se você precisa dos dois ao mesmo tempo na tela, o lugar do total é fora da
peça: um Stat ao lado, ou o título do cartão.
Movimento
Na primeira vez que aparece, a rosca varre do zero: as fatias saem juntas do
topo e cada uma se abre até o seu ângulo. Quando os dados mudam, cada fatia anda
do ângulo velho ao novo. Nos dois casos, com a duração e a curva dos tokens
(--rc-duration-slow, --rc-ease), pela mesma decisão do ChartContainer.
Com "reduzir movimento", a rosca nasce pronta e a troca é seca.
As cores
Sem config, cada fatia pega uma cor da paleta do tema, na ordem. Com config,
vale a color que você escreveu ali.
O que não funciona é var(--color-<nome>): essas variáveis são escritas pelo
ChartContainer, e a rosca desenha sozinha, fora dele.
Quando não usar
Acima de seis fatias ela para de informar: as menores viram tiras finas e a legenda vira uma lista que a pessoa lê em vez de olhar. Nesse caso, barra deitada lê melhor, e ainda cabe o rótulo por extenso.
No React Native
Traduz, em @rivocode/ui-native/chart, com as mesmas props: valueKey, nameKey, config, thickness, legend, centerValue, centerLabel. Duas mudanças de tipo: o miolo é string e não ReactNode, e o format só aceita função, que é a decisão que o Meter nativo já tinha tomado. Resolver nome de formatador arrasta o Intl inteiro para o bundle do celular.
O que muda de verdade é como se lê uma fatia. No web o ponteiro pousa no anel, a dica diz nome e valor, e o total sai de cena para os dois números não se empilharem. No toque não existe pousar, e o gesto equivalente mora na legenda, não na fatia: tocar a linha acende a fatia dela e manda nome e valor para o meio, no lugar exato onde o web põe a dica; tocar de novo devolve o total.
A fatia não é o alvo, e a razão é aritmética: um anel de 190px tem cerca de 600px de contorno para dividir entre até seis fatias, e a de 2% fica com doze (a mesma conta que tirou a dica por quadrado do Tracker). A linha da legenda tem 44px e a largura da tela.
E a leitura de tela não usa o truque do Tracker. Lá os 90 períodos viraram uma parada adjustable só, porque 90 paradas dentro de um cartão são um obstáculo. Aqui são no máximo seis fatias (acima disso a rosca para de informar e barra deitada lê melhor), e seis paradas com nome e valor são melhores que uma ajustável, porque cada uma é também o botão que acende a fatia. Contagem diferente, saída diferente. Com legend={false} o desenho vira imagem cujo nome carrega as fatias e os valores: sem legenda e sem dica, o dado ficaria inalcançável.
Uma diferença de desenho, e ela é medida: as pontas das fatias saem retas. O cornerRadius do web vem da Recharts, que recorta o canto de uma fatia preenchida; aqui a fatia é um arco traçado, e a ponta redonda que o SVG oferece estende o traço em quase doze graus para cada lado na espessura padrão: uma fatia de 5% apareceria como 11%.
O movimento é o do web: a rosca nasce pronta e, quando os dados mudam, cada fatia anda do ângulo velho ao novo com a duração e a curva dos tokens, pelo Reanimated. Com "reduzir movimento", a troca é seca.
API
| Prop | Tipo |
|---|---|
dataobrigatória0.4.0 | Slice[] |
nameKeyobrigatória0.4.0De onde sai o nome de cada fatia. | keyof Slice & string |
valueKeyobrigatória0.4.0De onde sai o numero de cada fatia. | keyof Slice & string |
centerLabel0.4.0A linha pequena embaixo do numero. | ReactNode |
centerValue0.4.0O numero grande no meio, que apaga enquanto o ponteiro le uma fatia. | ReactNode |
config0.4.0 | ChartConfig |
format0.4.0Como o numero e escrito: nome de formatador da casa (`currencyShort`, `percent`, `integer`...) ou funcao propria. | Format |
labelO que o leitor de tela ouve no lugar do desenho. | string |
legend0.4.0A lista de fatias embaixo, com nome e valor. | boolean |
thickness0.4.0Espessura do anel, em fracao do raio. | number |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.