Escolha o caminho
Todo gráfico do Nonius desenha a mesma coisa — uma série de pontos em ordem de tempo —, mas os pontos podem chegar até ele de quatro jeitos. Qual serve depende de duas perguntas: onde estão os pontos agora, e eles param de chegar? (Uma palavra nova — um tile, um resumo — está no glossário.)
| Seus pontos | Caminho | O que o gráfico guarda |
|---|---|---|
| Já estão na página, gerados ou buscados pelo seu próprio código | Entregue-os | Todos |
| Um histórico fechado, pequeno o bastante para mandar inteiro | Um arquivo | Todos, buscados uma vez |
| Um histórico longo demais para mandar, ou que muita gente lê | Tiles de um servidor | Só o que a vista na tela precisa |
| Chegando agora, conforme acontecem | Um feed ao vivo | Os mais novos, conforme chegam |
E quando não há navegador nenhum — um relatório mandado por e-mail, um programa de desktop, um servidor que responde com uma figura —, o gráfico é desenhado como imagem.
“Pequeno o bastante para mandar inteiro” é questão de conta. Um ponto tem 24 bytes (um tempo, um valor e um peso, 8 bytes cada), então dez milhões de pontos são um arquivo de 240 MB, baixado antes do primeiro quadro e guardado na memória do navegador. Um dia de leituras uma por segundo são 86.400 pontos, 2 MB: o arquivo é a escolha simples. Anos de leituras uma por milissegundo são centenas de gigabytes: só tiles chegam lá.
Entregue-os
Sua página já tem os pontos — calculados, lidos da sua própria API, decodificados do seu próprio formato. Entregue-os ao gráfico em ordem de tempo, quantos quiser de cada vez. O exemplo do pacote do navegador:
const chart = await createChart(canvas);
chart.setScale(2);
chart.push(t, v, w);
t, v e w são colunas de inteiros; Seus dados diz
como uma leitura vira esses inteiros, e por que setScale(2).
Um arquivo
Um arquivo de série guarda um histórico fechado no formato do próprio
Nonius, o NSB1. O gráfico busca o arquivo inteiro e lê seus bytes onde
eles chegam, sem etapa de decodificação, então um arquivo de milhões de
pontos é desenhado assim que termina de chegar.
const chart = await createChart(canvas);
await loadNsb(chart, await fetch(url));
O arquivo é escrito uma vez, de onde os dados estiverem: um CSV, um programa em Rust ou .NET, o Node. Seus dados mostra cada um.
Tiles de um servidor
Quando o histórico é longo demais para mandar, um servidor o guarda e manda tiles: pedaços pequenos cortados para a vista na tela, cada um com mais ou menos os bytes dos seus pixels, seja qual for o tamanho do histórico. Com o zoom aberto em dez anos, o gráfico lê resumos; com o zoom num segundo, os pontos daquele segundo. O gráfico busca tiles conforme a pessoa arrasta e dá zoom.
import { attachTiles, createChart, fetchSeries, interact } from "nonius";
// A series on a Nonius server, drawn from its tiles: the chart holds only
// what its views need and fetches the rest as a person moves, however long
// the history. `url` is the series' address, `…/v1/series/{id}`.
export async function fromServer(canvas, url) {
// Asked for first, so the answer comes while the WebAssembly downloads.
const meta = fetchSeries(url);
const chart = await createChart(canvas);
// Opens the chart on the whole series.
const tiles = await attachTiles(chart, url, { meta });
const interaction = interact(chart, canvas, { tiles });
return { chart, tiles, interaction };
}
Esse é um módulo inteiro. O fetchSeries fica sem await de
propósito: o gráfico recebe a promise, e a resposta chega enquanto o
WebAssembly baixa. O interact recebe os tiles, para que cada vista
para onde a pessoa se move busque os tiles de que precisa. url é o
endereço da série no servidor, http://host:porta/v1/series/{id}. O servidor pode ser o
nonius-server, a partir de um arquivo de série, ou o seu, falando o
protocolo do Nonius.
Servir mostra como rodar um.
Um feed ao vivo
Pontos que estão acontecendo agora chegam por um WebSocket, como
quadros numerados enviados pelo crate Rust
nonius-live. O gráfico
acompanha os pontos mais novos; um quadro que a rede perde é notado
pelo número e pedido de novo.
const chart = await createChart(canvas);
// A feed's values are integers and carry no scale: say how many decimal
// places they have (2 here: 10_050 is 100.50).
chart.setScale(2);
const stream = streamInto(chart, url);
Uma imagem
O mesmo gráfico, desenhado como PNG na CPU: sem navegador, sem GPU. Um
servidor responde a GET /v1/series/{id}/png?from=…&to=…&width=…&height=…;
no .NET, a série se desenha:
// Light, for a box of 1200 × 400 CSS pixels at a pixel ratio of 2:
// the size is in device pixels, the ratio in thousandths.
byte[] image = series.StillPng(new Still(first, last + 1, 2400, 800, Theme.Light, RatioPermille: 2000));
File.WriteAllBytes(png, image);
e no Rust, o nonius-render faz isso. A imagem é o quadro que o
navegador desenha, pixel por pixel no canvas 2D, então um relatório e
uma página concordam. Desenhar mostra cada um.
Na dúvida?
Comece por um arquivo. É uma busca e uma chamada, e o arquivo que ele pede é o que um servidor serve depois: passar para tiles muda como o gráfico é alimentado, não os dados.