Skip to content

Tutorial: Dashboard com gráficos

Neste tutorial você vai construir um dashboard executivo em paisagem com 3 tipos de gráfico, texto rico, tabela de dados e múltiplos data sources. O resultado exporta para PDF, HTML (com Chart.js interativo), CSV e Excel.

Exemplo completo: examples/07-dashboard

O que você vai aprender

  • Definir múltiplos data sources em um relatório
  • Usar chart com tipos bar, line e pie
  • Combinar gráficos, richText e table no mesmo relatório
  • Configurar orientação landscape
  • Diferenças de renderização entre PDF e HTML

1. Configurar a página em paisagem

Para dashboards, a orientação paisagem dá mais espaço horizontal:

json
{
  "pageSettings": {
    "format": "A4",
    "orientation": "landscape",
    "margins": { "left": 30, "right": 30, "top": 30, "bottom": 30 }
  }
}

2. Definir múltiplos data sources

Um dashboard normalmente combina dados de fontes diferentes. Declare quantos precisar:

json
{
  "dataSources": [
    {
      "id": "monthly",
      "type": "list",
      "schema": {
        "month": "string",
        "revenue": "number",
        "expenses": "number",
        "profit": "number",
        "orders": "integer"
      }
    },
    {
      "id": "categories",
      "type": "list",
      "schema": {
        "category": "string",
        "total": "number",
        "percentage": "number"
      }
    }
  ]
}

Os dados correspondentes no data.json:

json
{
  "monthly": [
    { "month": "Jan", "revenue": 185000, "expenses": 142000, "profit": 43000, "orders": 234 },
    { "month": "Fev", "revenue": 198000, "expenses": 148000, "profit": 50000, "orders": 256 }
  ],
  "categories": [
    { "category": "Eletrônicos", "total": 1250000, "percentage": 43.9 },
    { "category": "Vestuário", "total": 680000, "percentage": 23.9 }
  ]
}

3. Criar gráfico de barras

O gráfico de barras é ideal para comparar valores entre categorias. Cada series gera um grupo de barras:

json
{
  "type": "chart",
  "id": "bar_revenue",
  "x": 30,
  "y": 10,
  "width": 350,
  "height": 180,
  "chartType": "bar",
  "dataSourceId": "monthly",
  "categoryField": "month",
  "series": [
    { "name": "Receita", "valueField": "revenue", "color": "2196f3" },
    { "name": "Despesas", "valueField": "expenses", "color": "ff5722" }
  ],
  "options": {
    "showLegend": true,
    "legendPosition": "bottom",
    "showGridLines": true
  }
}

4. Criar gráfico de linhas

Linhas funcionam bem para tendências ao longo do tempo:

json
{
  "type": "chart",
  "id": "line_profit",
  "x": 410,
  "y": 10,
  "width": 350,
  "height": 180,
  "chartType": "line",
  "dataSourceId": "monthly",
  "categoryField": "month",
  "series": [
    { "name": "Lucro", "valueField": "profit", "color": "4caf50" },
    { "name": "Pedidos (x100)", "valueField": "orders", "color": "ff9800" }
  ]
}

5. Criar gráfico de pizza

Pizza é perfeita para proporções. Usa sempre a primeira série, e cada categoria vira uma fatia:

json
{
  "type": "chart",
  "id": "pie_categories",
  "x": 30,
  "y": 200,
  "width": 280,
  "height": 190,
  "chartType": "pie",
  "dataSourceId": "categories",
  "categoryField": "category",
  "series": [
    { "name": "Vendas", "valueField": "total", "color": "2196f3" }
  ],
  "options": {
    "showLegend": true,
    "legendPosition": "right"
  }
}

6. Adicionar tabela de dados

O table renderiza dados em formato tabular com header e zebra-striping:

json
{
  "type": "table",
  "id": "monthly_table",
  "x": 340,
  "y": 200,
  "width": 420,
  "dataSourceId": "monthly",
  "showHeader": true,
  "alternateRowColors": true,
  "headerFill": "1565c0",
  "columns": [
    { "id": "col_month", "header": "Mês", "binding": "month", "width": 80 },
    { "id": "col_revenue", "header": "Receita", "binding": "revenue", "width": 90, "format": "currency:BRL", "align": "right" },
    { "id": "col_profit", "header": "Lucro", "binding": "profit", "width": 80, "format": "currency:BRL", "align": "right" },
    { "id": "col_orders", "header": "Pedidos", "binding": "orders", "width": 60, "format": "integer", "align": "center" }
  ]
}

7. Usar RichText para destaques

O richText permite texto inline com estilos mistos — perfeito para KPIs:

json
{
  "type": "richText",
  "id": "kpi_highlight",
  "x": 500,
  "y": 18,
  "width": 280,
  "spans": [
    { "content": "Receita total: ", "fontSize": 11, "color": "90caf9" },
    { "content": "R$ 2.847.500", "fontSize": 14, "bold": true, "color": "ffffff" },
    { "content": "  |  Lucro: ", "fontSize": 11, "color": "90caf9" },
    { "content": "R$ 982.350", "fontSize": 14, "bold": true, "color": "69f0ae" }
  ]
}

Cada span é um trecho de texto com estilo independente. Propriedades disponíveis:

PropriedadeTipoDescrição
contentstringTexto do trecho
fontSizedoubleTamanho da fonte
boldboolNegrito
italicboolItálico
underlineboolSublinhado
colorstringCor hex (sem #)

8. Onde colocar cada elemento

Os gráficos e tabela ficam na banda summary (aparece uma vez), enquanto o header contém título e KPIs:

┌─────────────────────────────────────────────────────────────┐
│  Header: Título + KPIs em richText                         │
├─────────────────────────────────────────────────────────────┤
│  Summary:                                                   │
│  ┌────────────┐  ┌────────────┐                            │
│  │ Bar Chart  │  │ Line Chart │                            │
│  │ (receita)  │  │ (lucro)    │                            │
│  └────────────┘  └────────────┘                            │
│  ┌────────────┐  ┌──────────────────────┐                  │
│  │ Pie Chart  │  │ Tabela mensal        │                  │
│  │ (categ.)   │  │ Mês | Receita | ...  │                  │
│  └────────────┘  └──────────────────────┘                  │
│  Nota de análise (richText)                                │
├─────────────────────────────────────────────────────────────┤
│  Footer: Confidencial | Página                             │
└─────────────────────────────────────────────────────────────┘

Detail vazio

O detail band deve existir com height: 0 e elements: [] para o motor iterar os registros e alimentar os gráficos. Os gráficos referenciam o data source diretamente via dataSourceId.

9. Resultado por formato

FormatoComo renderiza
PDFGráficos nativos via package:pdf, tabela renderizada como grade
HTMLGráficos interativos via Chart.js 4 (CDN), tabela como <table>
CSVDados tabulares do detail (sem visual gráfico)
ExcelDados tabulares em planilha .xlsx

10. Gerar em Dart

dart
import 'dart:convert';
import 'dart:io';
import 'package:sulfite_core/sulfite_core.dart';

void main() async {
  final engine = SulfiteEngineImpl();
  final report = await engine.parseReport(
    File('examples/07-dashboard/report.json').readAsStringSync(),
  );
  final data = jsonDecode(
    File('examples/07-dashboard/data.json').readAsStringSync(),
  );
  final ctx = await engine.processData(report, data);

  // PDF
  File('dashboard.pdf').writeAsBytesSync(await engine.renderToPdf(ctx));

  // HTML (gráficos interativos)
  File('dashboard.html').writeAsStringSync(await engine.renderToHtml(ctx));

  print('Dashboard exportado!');
}

Dicas

  • No HTML, os gráficos são interativos (hover, tooltips). No PDF são imagens estáticas
  • Ajuste width e height dos gráficos para caber na página — se o conteúdo ultrapassar a altura disponível, o motor lança TooManyPagesException
  • Use cores do Material Design (hex sem #): 2196f3 (blue), 4caf50 (green), ff5722 (deep orange)
  • Múltiplos data sources não precisam ter o mesmo número de registros
  • Para barras empilhadas, adicione "stacked": true nas options — as séries são desenhadas camada sobre camada em vez de lado a lado
  • Se uma série tiver color: "000000" (padrão), o motor atribui automaticamente uma cor da paleta interna (kChartPalette)
  • Use as propriedades de borda (hasBorder, borderColor, borderWidth, borderDashed, borderDashGap) para destacar a área do gráfico

Próximos passos

Sulfite do 🇧🇷 para o mundo © 2026 Rafael S. Pinheiro