Logosulfite.app
rafagazani/sulfite 999999

Bands

As quatro faixas horizontais que compõem o layout do relatório

Bands#

Um relatório é dividido em faixas horizontais chamadas bands. Cada band tem uma altura fixa e contém elementos posicionados por coordenadas x e y.

┌──────────────────────────────────────┐
│  Header Band (repete em toda página) │
├──────────────────────────────────────┤
│  Detail Band (uma por registro)      │
│  Detail Band (uma por registro)      │
│  Detail Band (uma por registro)      │
│  ...                                 │
├──────────────────────────────────────┤
│  Summary Band (uma vez, após dados)  │
├──────────────────────────────────────┤
│  Footer Band (repete em toda página) │
└──────────────────────────────────────┘

Tipos#

Aparece no topo de cada página do PDF. Usado para títulos, logos e informações fixas.

{
  "type": "header",
  "id": "header_main",
  "height": 100,
  "elements": [ ... ]
}

Detail#

Repete uma vez para cada registro do data source vinculado. É aqui que os dados tabulares são renderizados.

{
  "type": "detail",
  "id": "detail_items",
  "dataSourceId": "items",
  "height": 30,
  "elements": [ ... ]
}

O dataSourceId indica qual data source alimenta esta band. Cada registro gera uma instância da band no documento final.

Summary#

Aparece uma vez após todos os registros de detalhe. Usado para totais e agregados.

{
  "type": "summary",
  "id": "summary_totals",
  "height": 50,
  "elements": [ ... ]
}

Aparece no rodapé de cada página. Usado para paginação e informações legais.

{
  "type": "footer",
  "id": "footer_page",
  "height": 30,
  "elements": [ ... ]
}

Propriedades comuns#

PropriedadeTipoObrigatórioDescrição
type string Sim "header" , "detail" , "summary" , "footer" , "groupHeader" ou "groupFooter"
id string Sim Identificador único
height double Sim Altura em pontos
elements array Sim Lista de elementos posicionados
dataSourceId string detail, groupHeader Data source que alimenta a band
groupBy string groupHeader, groupFooter Campo do data source usado para agrupar registros
forcePageBreakBefore bool Não Se true, insere quebra de página antes desta band
visibility string Não Controla em quais páginas a band é renderizada (header/footer)
showOnPage int Não Renderiza somente na página informada (1-based). Sobrepõe visibility
printWhen string Não Expressão booleana — band é ocultada quando avalia false ou 0

As bands header e footer aceitam o campo visibility para controlar em quais páginas são renderizadas. Isso é útil para criar cabeçalhos de capa, rodapés de assinatura ou layouts que diferem por página.

ValorComportamento
"allPages" (padrão)Renderizada em todas as páginas
"firstPageOnly"Somente na primeira página
"lastPageOnly"Somente na última página
"allButFirst"Em todas exceto a primeira
"allButLast"Em todas exceto a última
"oddPagesOnly"Somente páginas ímpares (1, 3, 5…)
"evenPagesOnly"Somente páginas pares (2, 4, 6…)
"none"Nunca renderizada (band oculta)
{
  "type": "header",
  "id": "header_capa",
  "height": 120,
  "visibility": "firstPageOnly",
  "elements": [ ... ]
}
{
  "type": "footer",
  "id": "footer_assinatura",
  "height": 60,
  "visibility": "lastPageOnly",
  "elements": [ ... ]
}

showOnPage#

Renderiza a band somente em uma página específica (1-based). Quando definido, sobrepõe visibility:

{
  "type": "header",
  "id": "header_pagina3",
  "height": 40,
  "showOnPage": 3,
  "elements": [ ... ]
}

Renderização condicional (printWhen)#

A propriedade printWhen aceita uma expressão booleana avaliada em tempo de renderização. A band é ocultada quando a expressão avalia false ou 0. Usa o mesmo ExpressionEvaluator dos field bindings.

{
  "type": "summary",
  "id": "summary_totais",
  "height": 50,
  "printWhen": "total > 0",
  "elements": [ ... ]
}

Outros exemplos:

"printWhen": "pageNumber == 1"
"printWhen": "itemCount > 10"
"printWhen": "status == 'ativo'"
Em exportações CSV/Excel (sem conceito de página), qualquer valor de `visibility` diferente de `"none"` inclui a band. `printWhen` é avaliado normalmente.

Posicionamento#

Elementos dentro de uma band usam coordenadas relativas ao canto superior esquerdo da band:

Band (height: 40)
┌───────────────────────────────┐
│  ┌─────┐                     │  Elemento em x:10, y:5
│  │ Txt │                     │
│  └─────┘                     │
│                    ┌────┐    │  Elemento em x:300, y:15
│                    │ Fld│    │
│                    └────┘    │
└───────────────────────────────┘

A coordenada y é relativa ao topo da band, não da página.

Múltiplas bands do mesmo tipo#

Um relatório pode ter mais de uma band de cada tipo. A ordem no array bands define a ordem de renderização:

{
  "bands": [
    { "type": "header", "id": "h1", "height": 80, "elements": [...] },
    { "type": "header", "id": "h2", "height": 40, "elements": [...] },
    { "type": "detail", "id": "d1", "dataSourceId": "items", "height": 30, "elements": [...] },
    { "type": "summary", "id": "s1", "height": 50, "elements": [...] },
    { "type": "footer", "id": "f1", "height": 25, "elements": [...] }
  ]
}

Quebra de página forçada#

{
  "type": "summary",
  "id": "sum",
  "height": 60,
  "forcePageBreakBefore": true,
  "elements": [ ... ]
}

O summary acima sempre começa em uma nova página.

Group Bands (quebra de grupo)#

Relatórios gerenciais frequentemente exigem agrupamento — por vendedor, por cliente, por período. O Sulfite suporta isso com dois tipos de band: groupHeader e groupFooter.

┌──────────────────────────────────────┐
│  Header Band                         │
├──────────────────────────────────────┤
│  ┌── GroupHeader (vendedor: "Ana") ──┐
│  │  Detail Band (venda 1)            │
│  │  Detail Band (venda 2)            │
│  └── GroupFooter (subtotal Ana) ─────┘
│  ┌── GroupHeader (vendedor: "Carlos")┐
│  │  Detail Band (venda 3)            │
│  └── GroupFooter (subtotal Carlos) ──┘
├──────────────────────────────────────┤
│  Summary Band (total geral)          │
├──────────────────────────────────────┤
│  Footer Band                         │
└──────────────────────────────────────┘

GroupHeader#

Renderiza uma vez no início de cada grupo. O campo groupBy indica qual campo do data source define a quebra.

{
  "type": "groupHeader",
  "id": "gh_vendedor",
  "dataSourceId": "vendas",
  "groupBy": "vendedor",
  "height": 35,
  "elements": [
    { "type": "field", "id": "f_vendedor", "x": 10, "y": 8, "width": 300, "binding": "vendedor", "bold": true, "fontSize": 14 }
  ]
}

GroupFooter#

Renderiza uma vez no final de cada grupo. Ideal para subtotais. O AggregateElement dentro de um groupFooter calcula o agregado apenas sobre os registros do grupo.

{
  "type": "groupFooter",
  "id": "gf_vendedor",
  "groupBy": "vendedor",
  "height": 30,
  "elements": [
    { "type": "aggregate", "id": "subtotal", "x": 300, "y": 5, "width": 100, "verb": "SUM", "dataSourceId": "vendas", "targetKey": "valor", "format": "currency:BRL", "bold": true }
  ]
}

Exemplo completo com agrupamento#

{
  "bands": [
    { "type": "header", "id": "hdr", "height": 60, "elements": [...] },
    { "type": "groupHeader", "id": "gh", "dataSourceId": "vendas", "groupBy": "vendedor", "height": 35, "elements": [...] },
    { "type": "detail", "id": "det", "dataSourceId": "vendas", "height": 25, "elements": [...] },
    { "type": "groupFooter", "id": "gf", "groupBy": "vendedor", "height": 30, "elements": [...] },
    { "type": "summary", "id": "sum", "height": 40, "elements": [...] },
    { "type": "footer", "id": "ftr", "height": 30, "elements": [...] }
  ]
}

O DataProcessor agrupa os registros automaticamente pela chave groupBy e renderiza a hierarquia: groupHeader → detail rows → groupFooter para cada grupo.

Se o `groupHeader` tem `printWhen` que avalia `false`, o grupo inteiro (header + details + footer) é suprimido.
GroupBands funcionam em todos os formatos: PDF, HTML, CSV e Excel. Cada renderer respeita a hierarquia de grupo e o `printWhen`.

Editando bands no Studio#

O Sulfite Studio oferece dois pontos de edição de bands sem precisar editar JSON manualmente:

  • Painel lateral — expanda uma band no painel esquerdo do designer para editar height, dataSourceId, forcePageBreakBefore, visibility, showOnPage e printWhen diretamente.
  • BandManagerDialog — aberto pela toolbar (botão Gerenciar Bands), exibe todas as bands em cards expansíveis com todos os campos editáveis, drag & drop para reordenar e botão de exclusão com confirmação.

Todas as edições feitas no Studio são refletidas imediatamente no editor JSON (modo Code) e vice-versa.

Próximo passo#

Data Sources →