// Doze de largura e cem de altura, então um mês de 68 quilos é desenhado
// com 68 de comprimento e nada precisa virar pixel primeiro.
func chart(harvest: Int[]): ui.View {
mut ui.Mark[dyn] marks = []
for i := 0; i < len(harvest); i++ {
tall := hive.conv.itf(harvest[i]) // a condição do laço prova i
// Um bar é posicionado pelo seu meio, e é por isso que o chão
// é 100 e o meio de um em pé sobre ele fica meia barra acima.
append(marks, ui.bar([ui.paint(ui.Tone.Good())],
hive.conv.itf(i) + 0.5, 100.0 - tall / 2.0, 0.7, tall))
}
append(marks, ui.words([ui.paint(ui.Tone.Muted())], 6.0, 8.0, 7.0, "kg por mês"))
return ui.canvas([
ui.width(480),
ui.height(200),
ui.region(0.0, 0.0, 12.0, 100.0),
], marks)
}
proc main(): void {
// A mesma árvore que uma window trocaria é a que uma página escreve.
echo len(ui.page("Colheita", chart([31, 44, 58, 72, 68, 51])))
}proc main(): void {
// Uma linha através de cinco lugares — x, y, x, y — e um ponto sobre o último.
trace := ui.path([ui.thick(0.15), ui.paint(ui.Tone.Good())],
[0.0, 2.0, 1.0, 5.0, 2.0, 4.0, 3.0, 8.0, 4.0, 7.0])
tip := ui.dot([ui.paint(ui.Tone.Good())], 4.0, 7.0, 0.2)
// words fica centralizado no lugar, e sua altura também está nas
// unidades da região — então esta tem um doze avos do plano em que está.
label := ui.words([ui.paint(ui.Tone.Muted())], 4.0, 8.4, 0.8, "agora")
view := ui.canvas([
ui.width(360),
ui.height(200),
ui.region(-0.5, 0.0, 5.5, 10.0),
], [trace, tip, label])
echo ui.html(view)
}canvas(attrs, marks) é um widget como qualquer outro e um Mark é um valor como qualquer outro, então o que um canvas guarda é o que está nele agora. Não existe contexto de desenho, nem quadro para agendar, nem nada para limpar: um gráfico é reconstruído a partir do estado exatamente como o resto da página, e uma página servida desenha um exatamente como uma janela desenha.
Existem cinco marcas, cada uma aqui porque não dá para fazê-la com as outras:
dot(attrs, x, y, radius), um círculo preenchido;bar(attrs, x, y, width, height), um retângulo;path(attrs, points), uma linha por uma sequência de pontos escrita x, y, x, y, e patch(attrs, points), os mesmos números preenchidos;words(attrs, x, y, height, text), texto posicionado no plano.Um anel é um path em volta de um círculo, uma grade é um vetor de paths e uma seta é um path; um dot é sempre preenchido.
Tudo é dito nas unidades do próprio programa. region(x, y, width, height) diz qual parte do plano a caixa mostra, então um circuito mapeado em metros desenha um carro de nove metros com nove de comprimento; paint(Tone) é a cor de uma marca e thick(Float) a largura de um path, também nas unidades da região — então dar zoom engrossa as estradas, que é o que dar zoom significa. A caixa pode ter qualquer formato, e o que é desenhado mantém o seu, centralizado. Toda marca é posicionada pelo meio — uma barra incluída — e as palavras ficam centralizadas no seu lugar com a altura nas unidades da região. O y cresce para baixo, como numa página, então o chão de um gráfico é o seu maior y.