Tutorial: Tabela Pivot com dados inline#
Neste tutorial você criará o relatório Arrecadação de ICMS por Estado — 2025: registros planos
{estado, mes, icms} são transformados automaticamente em uma matriz Estado × Mês com totais por linha e coluna, usando o
pivot mode do TableElement.
O que você vai aprender:
- Estruturar dados flat para consumo pivot
-
Configurar
TablePivotConfigcomrowFields,columnField,valueFielde verb - Usar
height: 0emSummaryBandpara altura dinâmica (PDF) - Ativar totais por linha (
showRowTotals) e por coluna (showColumnTotals) - Configurar o pivot no Studio via editor de tabela
O código completo deste exemplo está em example/lib/examples/icms_pivot_report.dart.
Pré-requisitos#
- Sulfite instalado (Instalação →)
- Familiaridade com data sources e bands
Passo 1 — Entender o modelo de dados#
O pivot mode espera registros planos: um registro por célula da matriz final.
// 8 estados × 12 meses = 96 registros
[
{'estado': 'SP', 'mes': 'Jan', 'icms': 180.0},
{'estado': 'SP', 'mes': 'Fev', 'icms': 162.0},
// ...
{'estado': 'GO', 'mes': 'Dez', 'icms': 47.0},
]
O renderer agrupa, pivota e agrega esses registros em tempo de renderização — o JSON do relatório não muda conforme os dados crescem.
Declare o data source normalmente:
{
"dataSources": [
{
"id": "arrecadacao",
"type": "list",
"schema": {
"estado": "string",
"mes": "string",
"icms": "number"
}
}
]
}
Passo 2 — Configurar o pivot#
No elemento table, adicione o campo pivot com TablePivotConfig. Quando
pivot está presente, as columns são ignoradas — os cabeçalhos são gerados dinamicamente a partir dos valores distintos de
columnField.
{
"type": "table",
"id": "pivot_icms",
"x": 0,
"y": 10,
"width": 782,
"height": 0,
"dataSourceId": "arrecadacao",
"showHeader": true,
"headerFill": "2e7d32",
"headerTextColor": "ffffff",
"headerBold": true,
"headerFontSize": 8,
"headerHeight": 20,
"rowHeight": 18,
"columnFontSize": 8,
"rowTextColor": "1b5e20",
"evenRowFill": "e8f5e9",
"oddRowFill": "ffffff",
"alternateRowColors": true,
"borderColor": "c8e6c9",
"borderWidth": 0.5,
"showRowBorders": true,
"showColumnBorders": true,
"columns": [],
"pivot": {
"rowFields": ["estado"],
"columnField": "mes",
"valueField": "icms",
"verb": "SUM",
"showRowTotals": true,
"showColumnTotals": true,
"totalLabel": "Total"
}
}
Campos de pivot#
Obrigatórios
| Campo | Descrição |
|---|---|
rowFields |
Lista de campos que formam os rótulos de linha. Suporta múltiplos para agrupamento hierárquico (ex:
["regiao", "estado"]
)
|
columnField |
Campo cujos valores distintos viram cabeçalhos de coluna (ex: "mes") |
valueField |
Campo numérico a agregar em cada célula (ex: "icms") |
Agregação
| Campo | Padrão | Descrição |
|---|---|---|
verb |
"SUM" |
Função de agregação:
"SUM"
,
"AVG"
,
"COUNT"
,
"MIN"
,
"MAX"
|
O total de linha e o total de coluna respeitam o
verbescolhido. ParaAVG, o total é a média real de todos os valores — não a média das médias por célula.
Totais
| Campo | Padrão | Descrição |
|---|---|---|
showRowTotals |
true |
Adiciona coluna de total ao final de cada linha |
showColumnTotals |
true |
Adiciona linha de totais no rodapé da tabela |
totalLabel |
"Total" |
Rótulo da coluna/linha de totais. String vazia usa "Total" em tempo de renderização |
totalsFill |
herda headerFill |
Cor de fundo da linha de totais (hex sem #) |
totalsTextColor |
herda headerTextColor |
Cor do texto da linha de totais |
totalsBold |
true |
Texto em negrito na linha de totais |
totalsFontSize |
herda columnFontSize |
Tamanho de fonte da linha de totais |
Ordenação de colunas
| Campo | Padrão | Descrição |
|---|---|---|
columnOrder |
[] |
Lista de valores fixados no início, nessa ordem (ex:
["Jan","Fev",...]
). Valores ausentes seguem
columnSort
|
columnSort |
"alpha" |
Estratégia para colunas não fixadas:
"alpha"
A→Z,
"alpha_desc"
Z→A,
"value_asc"
menor total primeiro,
"value_desc"
maior total primeiro,
"natural"
ordem de aparição nos dados
|
Estilo avançado
| Campo | Padrão | Descrição |
|---|---|---|
columnOverrides |
{} |
Mapa
{ "colValue": TableColumnOverride }
com overrides de largura, formato, alinhamento, negrito, cor de cabeçalho e
conditionalStyles
por coluna
|
cellConditionalStyles |
[] |
Regras globais de estilo condicional aplicadas a todas as células de dados.
columnOverrides[col].conditionalStyles
tem prioridade. Primeira regra satisfeita vence
|
Passo 3 — Usar SummaryBand com altura dinâmica#
O número de linhas pivot varia conforme os dados. Use height: 0 na SummaryBand
para que o PDF calcule a altura automaticamente:
{
"type": "summary",
"id": "summary_pivot",
"height": 0,
"elements": [
{ "type": "table", "id": "pivot_icms", ... }
]
}
height: 0em um band com um únicoTableElementativa o modo de altura dinâmica no PDF renderer. Os outros formatos (HTML, CSV, Excel) ignoram essa configuração.
Passo 4 — Dimensionar a tabela#
Com rowFields: ["estado"] (1 campo), 12 meses e 1 coluna de total, a tabela tem 14 colunas. O renderer distribui
width igualmente entre elas:
largura por coluna = width / total_colunas = 782 / 14 ≈ 55.9 pt
Para A4 landscape com margens de 30pt:
largura disponível = 842 − 30 − 30 = 782 pt
Ajuste width conforme a orientação e as margens do seu relatório. Com muitas colunas, prefira
A4 landscape ou reduza columnFontSize e headerFontSize para 7–8pt.
Passo 5 — Estrutura completa do relatório#
{
"reportId": "icms_pivot_001",
"reportName": "Arrecadação de ICMS por Estado — 2025",
"pageSettings": {
"format": "A4",
"orientation": "landscape",
"margins": { "left": 30, "right": 30, "top": 30, "bottom": 30 }
},
"dataSources": [
{
"id": "arrecadacao",
"type": "list",
"schema": { "estado": "string", "mes": "string", "icms": "number" }
}
],
"bands": [
{
"type": "header",
"id": "header_main",
"height": 72,
"elements": [
{
"type": "rect",
"id": "header_bg",
"x": 0, "y": 0, "width": 782, "height": 72,
"fill": "1b5e20", "hasBorder": false
},
{
"type": "text",
"id": "title",
"x": 20, "y": 10, "width": 600, "height": 26,
"content": "ARRECADAÇÃO DE ICMS POR ESTADO",
"fontSize": 20, "bold": true, "color": "ffffff"
},
{
"type": "text",
"id": "subtitle",
"x": 20, "y": 38, "width": 580, "height": 14,
"content": "Demonstrativo mensal — Exercício 2025 · Valores em R$ milhões",
"fontSize": 10, "color": "a5d6a7"
}
]
},
{
"type": "summary",
"id": "summary_pivot",
"height": 0,
"elements": [
{
"type": "table",
"id": "pivot_icms",
"x": 0, "y": 10, "width": 782, "height": 0,
"dataSourceId": "arrecadacao",
"showHeader": true,
"headerFill": "2e7d32",
"headerTextColor": "ffffff",
"headerBold": true,
"headerFontSize": 8,
"headerHeight": 20,
"rowHeight": 18,
"columnFontSize": 8,
"rowTextColor": "1b5e20",
"evenRowFill": "e8f5e9",
"oddRowFill": "ffffff",
"alternateRowColors": true,
"borderColor": "c8e6c9",
"borderWidth": 0.5,
"showRowBorders": true,
"showColumnBorders": true,
"columns": [],
"pivot": {
"rowFields": ["estado"],
"columnField": "mes",
"valueField": "icms",
"verb": "SUM",
"showRowTotals": true,
"showColumnTotals": true,
"totalLabel": "Total"
}
}
]
},
{
"type": "footer",
"id": "footer_main",
"height": 24,
"elements": [
{
"type": "text",
"id": "footer_page",
"x": 580, "y": 6, "width": 202, "height": 11,
"content": "Página {pageNumber} de {totalPages}",
"fontSize": 7, "italic": true, "color": "bdbdbd", "align": "right"
}
]
}
]
}
Passo 6 — Executar no exemplo#
O exemplo já está registrado na demo app. Para rodá-lo:
cd sulfite/example
fvm flutter run
Selecione "📊 ICMS por Estado (Pivot)" na lista de demos. O relatório gera em PDF e HTML com a mesma matrix pivotada.
Variações comuns#
Pivot hierárquico (dois rowFields)#
Agrupamento por região e estado — cada combinação vira uma linha:
"pivot": {
"rowFields": ["regiao", "estado"],
"columnField": "mes",
"valueField": "icms",
"verb": "SUM",
"showRowTotals": true,
"showColumnTotals": true,
"totalLabel": "Total"
}
Contagem em vez de soma#
Para contar quantas transações ocorreram por estado/mês:
"pivot": {
"rowFields": ["estado"],
"columnField": "mes",
"valueField": "quantidade",
"verb": "COUNT",
"showRowTotals": true,
"showColumnTotals": false
}
Sem totais, label personalizado#
"pivot": {
"rowFields": ["categoria"],
"columnField": "trimestre",
"valueField": "receita",
"verb": "AVG",
"showRowTotals": false,
"showColumnTotals": false,
"totalLabel": "Média Geral"
}
Ordenar colunas por valor (maior total primeiro)#
Use columnSort: "value_desc" para listar os meses com maior arrecadação à esquerda:
"pivot": {
"rowFields": ["estado"],
"columnField": "mes",
"valueField": "icms",
"verb": "SUM",
"columnSort": "value_desc",
"showRowTotals": true,
"showColumnTotals": true
}
columnSort | Comportamento |
|---|---|
"alpha" | Alfabético A→Z (padrão) |
"alpha_desc" | Alfabético Z→A |
"value_asc" | Crescente pelo total agregado da coluna |
"value_desc" |
Decrescente pelo total agregado da coluna (maior primeiro) |
"natural" | Ordem de aparição nos dados |
Dica: Para meses em português na ordem correta, use columnOrder para fixar a sequência e
columnSort: "natural" para os demais:
"pivot": {
"rowFields": ["estado"],
"columnField": "mes",
"valueField": "icms",
"verb": "SUM",
"columnOrder": ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun",
"Jul", "Ago", "Set", "Out", "Nov", "Dez"],
"columnSort": "natural"
}
Overrides de estilo por coluna#
Use columnOverrides para configurar largura, formato, alinhamento e cor de cabeçalho de colunas específicas:
"pivot": {
"rowFields": ["estado"],
"columnField": "mes",
"valueField": "icms",
"verb": "SUM",
"showRowTotals": true,
"columnOverrides": {
"Total": {
"bold": true,
"headerColor": "1a237e",
"align": "right",
"format": "#,##0.00"
},
"Dez": {
"headerColor": "b71c1c"
}
}
}
Estilos condicionais nas células#
Use cellConditionalStyles para colorir células com base nos dados. As regras são avaliadas em ordem e a
primeira que satisfaz a condição é aplicada:
"pivot": {
"rowFields": ["estado"],
"columnField": "mes",
"valueField": "icms",
"verb": "SUM",
"cellConditionalStyles": [
{ "when": "value > 200", "fill": "e8f5e9", "bold": true },
{ "when": "value < 50", "textColor": "e53935" }
]
}
Para aplicar estilos a uma coluna específica (com prioridade sobre cellConditionalStyles), use
columnOverrides[col].conditionalStyles:
"columnOverrides": {
"Total": {
"conditionalStyles": [
{ "when": "value > 1000", "fill": "1b5e20", "textColor": "ffffff", "bold": true }
]
}
}
O contexto de avaliação de cada regra contém todos os campos da linha mais value (valor bruto antes da formatação).
Configurar via Studio#
No editor de tabela (clique duplo na tabela ou ícone de lápis), role até o card Modo Pivot:
- Ative o toggle Ativar Pivot
-
Preencha Campos de Linha — nomes dos campos separados por vírgula (ex:
estado) - Preencha Campo de Coluna (ex:
mes) - Preencha Campo de Valor (ex:
icms) - Escolha a Agregação no dropdown (SUM / COUNT / AVG / MIN / MAX)
- Ative/desative Totais por Linha e Totais por Coluna
- Ajuste o Rótulo do Total se necessário
- Salve — o preview atualiza imediatamente
Desativar o toggle preserva a configuração anterior. Reativar restaura os campos já preenchidos.
Limitações conhecidas#
| Limitação | Impacto |
|---|---|
| CSV/Excel | Exporta os dados planos não pivotados — o pivot ocorre apenas no PDF e HTML |
| Múltiplos valueFields |
Um único
valueField
por configuração pivot. Para exibir várias métricas, use tabelas separadas
|