Slide 45 de 53

Desenhando em um canvas

Um gráfico, nas unidades do próprio programa
import hive.ui

// 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++ {
		if harvest bounds i {
			tall := hive.conv.itf(harvest[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])))
}
Uma linha, um anel e uma palavra
import hive.ui

proc main(): void {
	// Uma linha através de cinco lugares — x, y, x, y — e um anel sobre o
	// último deles, que é um dot e por isso não precisou de nome próprio.
	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, não existe frame para agendar e não há nada para limpar: um gráfico é reconstruído a partir do estado exatamente como o resto da página é, e a mesma árvore que uma window troca é a que page escreve — então um gráfico desenhado para um programa é um gráfico servido por um servidor web sem mudar nada.Existem cinco marks, e cada um está aqui pelo mesmo motivo que uma forma está: não dá para fazê-lo a partir dos outros. dot é um círculo preenchido, bar é um retângulo, path é uma linha através de uma sequência de pontos, patch são esses mesmos números preenchidos, e words é texto posicionado no plano. Um anel é um dot sem preenchimento, uma grade é um vetor de paths, uma seta é um path — e nenhum deles precisou de um nome próprio.Tudo em um canvas é dito nas unidades do próprio programa. region(x, y, largura, altura) diz qual parte do plano a caixa mostra, e um mapa de um circuito escrito em metros desenha um carro de nove metros com nove de comprimento. paint(Tone) é a cor de um mark e thick(Float) é a espessura com que um path é desenhado, também nas unidades da região — então um mapa com zoom tem estradas mais grossas, que é o que dar zoom significa. A caixa pode ter qualquer formato; o que é desenhado mantém o seu e fica centralizado nela.Duas colocações valem ser ditas explicitamente, porque as duas são o tipo de coisa que um programa descobre estando meia largura fora do lugar. Um bar é posicionado pelo seu meio, como tudo mais em um canvas — um mark posicionado pelo canto seria o único sempre errado. E words fica centralizado no lugar que recebe, com a sua altura nas unidades da região e não em pontos, porque um rótulo em uma planta é do tamanho da coisa que ele rotula.