0010. Gráficos em SVG próprio, com módulos pequenos do d3¶
- Status: aceita (M4)
- Data: 2026-09-26
- Marco: M4
Contexto¶
O M4 traz as primeiras vistas com gráficos: o fluxo dos tópicos no tempo (com três modos e transição entre eles), as sparklines da lista "em alta / em queda", os pequenos múltiplos por revista, o coroplético por UF, o mapa-múndi e o ranking de instituições. O plano geral previa o @observablehq/plot para facetas e heatmaps, e o d3 para o resto.
Requisitos da interface que pesam na escolha:
- tema por variáveis CSS (Observatório e Prancha), trocado sem redesenhar;
- acessibilidade por teclado: faixas, UFs e barras clicáveis precisam de
role,tabindexe teclas; osvelte-checkdo projeto falha com qualquer aviso de acessibilidade; - transição entre modos do fluxo (fluxo, absoluto, proporção) respeitando
prefers-reduced-motion; - testabilidade: a lógica em TypeScript puro, testada no Vitest (sem navegador), e os gráficos com
data-testide valores para o Playwright; - peso: o painel carrega por rota, e o site publicado deve abrir rápido em conexões modestas.
Decisão¶
Gráficos em SVG escrito em Svelte, com módulos pequenos do d3 para a matemática:
| Pacote | Versão | Para quê |
|---|---|---|
d3-shape |
3.2.0 | empilhamento (stack, stackOffsetWiggle/None/Expand, stackOrderInsideOut), áreas e curvas (curveMonotoneX) |
d3-array |
3.2.4 | marcas dos eixos (ticks) |
d3-geo |
3.1.1 | projeções equivalentes (cônica para o Brasil, Equal Earth para o mundo) e caminhos SVG |
topojson-client |
3.1.0 | TopoJSON → GeoJSON |
world-atlas |
2.0.2 | só no desenvolvimento: fonte da malha do mundo |
Sem @observablehq/plot e sem d3-scale: o Plot traz o d3 inteiro (70 a 120 KB comprimidos a mais) e redesenha o SVG a cada mudança, o que impede a transição entre modos e complica a acessibilidade; o d3-scale traz interpolação, cores e formatação de datas que não usamos (a formatação é Intl em português, em lib/formato.ts).
A lógica fica em módulos puros (lib/graficos/fluxo.ts, faixas.ts), e os componentes (Figura, Eixo, Sparkline, Dica) só desenham. Todo gráfico vem numa Figura, com uma frase-resumo e "Ver como tabela".
Malhas¶
As malhas ficam versionadas em frontend/src/lib/geografia/malhas/, geradas por scripts/baixar-malhas.ts, e são carregadas sob demanda pela vista Geografia:
| Malha | Fonte | Tamanho | Licença |
|---|---|---|---|
br-uf.json (27 UFs) |
API de malhas do IBGE, qualidade mínima | 31 KB | dados públicos do IBGE; citar a fonte |
mundo.json (177 países) |
Natural Earth 1:110m, via world-atlas |
104 KB | domínio público (world-atlas: ISC) |
O world-atlas identifica os países pelo código numérico da ONU; o gerador converte para o ISO 3166-1 alfa-2 do contrato com o CLDR do Node (Intl.getCanonicalLocales("und-076") dá und-BR). Kosovo, sem código numérico, vira XK; Chipre do Norte e Somalilândia ficam sem código. As duas projeções preservam áreas, como pede um mapa de cores por região: a cônica equivalente com paralelos em −2° e −22° para o Brasil e a Equal Earth para o mundo. A vista cita as fontes.
Consequências¶
- Os gráficos seguem o tema e o movimento reduzido sem código especial, e cada peça é testada isoladamente.
- Algumas coisas que o Plot faria de graça (facetas, legendas) são escritas à mão; a lista de componentes é curta e reaproveitada no M5 (classificação).
- Novas dependências de gráficos entram com versão fixa e com esta tabela atualizada.