Neste tutorial, mostrarei como usar JavaScript e a tela para exibir informações numéricas na forma de gráficos de pizza e gráficos de rosca.
O que é um gráfico de pizza?
Um gráfico é uma ferramenta estatística usada para representar graficamente dados numéricos. Um gráfico de pizza exibe esses dados numéricos como um círculo dividido em fatias. O tamanho de cada fatia é proporcional ao valor numérico que ela representa.
O que é um gráfico de rosca?
Para simplificar, um gráfico de rosca é uma variação do gráfico de pizza. A diferença é que as fatias são cortadas em direção ao centro da torta de forma que apenas a borda fique visível. Dessa forma, o gráfico parece um donut e, portanto, o nome.
Comece a desenhar com a tela
Antes de desenhar o gráfico de pizza, vamos dar uma olhada no desenho de suas partes. Veremos como podemos usar o componente canvas e JavaScript para desenhar:
- uma linha
- um arco (uma parte de um círculo)
- uma forma cheia de cor
Para começar a desenhar usando a tela HTML5, precisaremos criar algumas coisas:
- Uma pasta para guardar os arquivos do projeto; vamos chamar esta pasta tutorial de gráfico de pizza.
- Um arquivo HTML index.html dentro de tutorial de gráfico de pizza pasta. Este arquivo conterá o código HTML.
- Um arquivo JS script.js dentro de tutorial de gráfico de pizza pasta. Este arquivo conterá nosso código JavaScript.
Vamos manter as coisas muito simples e adicionar o seguinte código dentro index.html:
Nós temos o elemento com o ID
myCanvas
para que possamos referenciá-lo em nosso código JS. Em seguida, carregamos o código JS através do marcação.
Lado de dentro
script.js
, o código JS primeiro obterá uma referência à tela e, em seguida, definirá sua largura e altura. Para desenhar na tela, precisamos apenas de uma referência ao seu contexto 2D que contém todos os métodos de desenho.
var myCanvas = document.getElementById("myCanvas"); myCanvas.width = 300; myCanvas.height = 300; var ctx = myCanvas.getContext("2d");
Adicionando algumas funções auxiliares
Agora que temos a tela configurada e também uma referência à tela de desenho, vamos definir algumas funções JavaScript que poderemos reutilizar ao desenhar o gráfico de pizza. Adicionaremos as funções em nosso arquivo script.js.function drawLine(ctx, startX, startY, endX, endY, color){ ctx.save(); ctx.strokeStyle = color; ctx.beginPath(); ctx.moveTo(startX,startY); ctx.lineTo(endX,endY); ctx.stroke(); ctx.restore(); }o
drawLine
função recebe seis parâmetros:
-
ctx
: referência ao contexto do desenho -
startX
: a coordenada X do ponto inicial da linha -
startY
: a coordenada Y do ponto inicial da linha -
endX
: a coordenada X do ponto final da linha -
endY
: a coordenada Y do ponto final da linha -
color
: a cor da linha
beginPath()
. Isso informa ao contexto de desenho que estamos começando a desenhar algo novo na tela. Nós usamos moveTo()
para definir o ponto de partida, ligue lineTo()
para indicar o ponto final e, em seguida, faça o desenho real chamando stroke()
.
Vamos agora ver como podemos desenhar uma parte de um círculo, também chamado de arco.
function drawArc(ctx, centerX, centerY, radius, startAngle, endAngle, color){ ctx.save(); ctx.strokeStyle = color; ctx.beginPath(); ctx.arc(centerX, centerY, radius, startAngle, endAngle); ctx.stroke(); ctx.restore(); }o
drawArc
função recebe sete parâmetros:
-
ctx
: referência ao contexto do desenho -
centerX
: a coordenada X do centro do círculo -
centerY
: a coordenada Y do centro do círculo -
radius
: a coordenada X do ponto final da linha -
startAngle
: o ângulo inicial em radianos onde a parte do círculo começa -
endAngle
: o ângulo final em radianos onde a parte do círculo termina -
color
: a cor do arco
function drawPieSlice(ctx,centerX, centerY, radius, startAngle, endAngle, fillColor, strokeColor) { ctx.save(); ctx.fillStyle = fillColor; ctx.strokeStyle = strokeColor; ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.arc(centerX, centerY, radius, startAngle, endAngle, strokeColor); ctx.closePath(); ctx.fill(); ctx.restore(); }o
drawPieSlice
função recebe sete parâmetros:
-
ctx
: referência ao contexto do desenho -
centerX
: a coordenada X do centro do círculo -
centerY
: a coordenada Y do centro do círculo -
radius
: a coordenada X do ponto final da linha -
startAngle
: o ângulo inicial em radianos onde a parte do círculo começa -
endAngle
: o ângulo final em radianos onde a parte do círculo termina -
fillColor
: a cor usada para preencher a fatia -
strokeColor
: a cor usada para desenhar o perímetro da fatia
drawLine(ctx, 200, 200, 300, 300, "#000"); drawArc(ctx, 250, 250, 150, 0, Math.PI/3, "#000"); drawPieSlice(ctx, 250, 250, 150, Math.PI/2, Math.PI/2 + Math.PI/3, "#F00", "#000");Ele produzirá este resultado: Agora temos todas as ferramentas necessárias para desenhar um gráfico de pizza, então vamos ver como podemos usá-las juntas.
Desenhando o gráfico de pizza
Conceitualmente, qualquer gráfico tem duas partes principais:- O modelo de dados contém os dados numéricos a serem representados. Este é estruturado em um formato específico para o tipo de gráfico.
- A representação gráfica é como os dados numéricos no modelo de dados são representados por elementos visuais de acordo com algumas regras na forma de fórmulas matemáticas.
O modelo de dados do gráfico de pizza
A forma mais comum de estruturar o modelo de dados para gráficos de pizza é uma série de categorias e valores correspondentes, onde cada uma das categorias e valores são associados a uma fatia do bolo. Como exemplo, o modelo de dados de um gráfico de pizza exibindo o número de vinis que agrupei por gênero seria algo como:- Música clássica: 16
- Rock alternativo: 12
- Pop: 18
- Jazz: 32
PieChart
objeto mais tarde:
{ "Classical Music": 16, "Alternative Rock": 12, "Pop": 18, "Jazz": 32, }
A representação gráfica do gráfico de pizza
O gráfico de pizza usa um círculo para exibir as informações no modelo de dados, dividindo-as em fatias. Cada fatia corresponde a uma categoria do modelo de dados e o tamanho da fatia é proporcional ao valor da categoria. Minha pequena coleção de 88 vinis tem quatro categorias. Cada categoria receberá uma fatia do gráfico de pizza proporcional ao número de vinis nessa categoria. Mas como medimos o tamanho de uma fatia? Isso é fácil - fazemos isso pelo ângulo na ponta da fatia. Tudo o que precisamos saber é que o círculo completo corresponde a um ângulo de360 degrees
ou 2 * PI
. Então meio círculo seria 180 deg
ou PI
um quarto 90 deg
ou PI/2
e assim por diante.
Para determinar o ângulo para cada fatia de categoria, usamos a fórmula:
slice angle = 2 * PI * category value / total value
De acordo com esta fórmula, os 16 vinis de música clássica terão um ângulo de corte de aprox. 0,36 * PI ou 64,8 graus.
Vamos ao desenho. Para isso, usaremos uma classe JavaScript que nomearemos Piechart
. O construtor receberá um argumento de opções, um objeto contendo o seguinte:
-
canvas
: referência à tela onde queremos desenhar o gráfico de pizza -
data
: referência a um objeto que contém o modelo de dados -
colors
: um array contendo as cores que queremos usar para cada fatia -
seriesName
: uma string que contém o título do gráfico -
padding
: para nos dizer quanto preenchimento deve ser adicionado ao gráfico -
donutHoleSize
: especifica a fração que deve ser cortada do gráfico de pizza. -
titleOptions
: um objeto que contém informações sobre a fonte, tamanho, alinhamento e cor do título etc.
Piechart
classe também contém um método draw()
que faz o desenho real do gráfico.
var Piechart = function(options){ constructor(options) { this.options = options; this.canvas = options.canvas; this.ctx = this.canvas.getContext("2d"); this.colors = options.colors; this.titleOptions = options.titleOptions; this.totalValue = [...Object.values(this.options.data)].reduce((a, b) => a + b, 0); this.radius = Math.min(this.canvas.width / 2, this.canvas.height / 2) - options.padding; } drawSlices() { var colorIndex = 0; var startAngle = -Math.PI / 2; for (var categ in this.options.data) { var val = this.options.data[categ]; var sliceAngle = (2 * Math.PI * val) / this.totalValue; drawPieSlice( this.ctx, this.canvas.width / 2, this.canvas.height / 2, this.radius, startAngle, startAngle + sliceAngle, this.colors[colorIndex % this.colors.length] ); startAngle += sliceAngle; colorIndex++; } } }A classe começa armazenando o passado
options
em diferentes propriedades dentro do constructor()
método. Ele armazena o canvas
referência e cria um contexto de desenho também armazenado como membro de classe. Em seguida, ele armazena o colors
array passado como opções.
Convertemos nossos valores de objeto em um array dentro do construtor e usamos o método reduce() para obter o total de todos os pontos de dados. Este valor é usado posteriormente no cálculo do ângulo de diferentes fatias. Também calculamos o raio do nosso gráfico de pizza dentro do método construtor, tomando o valor mínimo entre metade da largura da tela e metade da altura da tela e, em seguida, subtraindo o preenchimento. Subtrair o preenchimento para calcular o raio ajuda a introduzir algum espaço entre os diferentes elementos do gráfico.
o drawSlices()
método faz todo o desenho real do gráfico de pizza. Para cada categoria no modelo de dados, aplicamos a fórmula mencionada acima para calcular o ângulo da fatia de pizza. Por fim, utilizamos o drawPieSlice()
função usando o centro da tela como o centro da fatia. Também compensamos o ângulo inicial e final das fatias cada vez que desenhamos uma categoria, caso contrário as fatias se sobrepõem.
Para usar a classe, temos que criar uma instância e então chamar o drawSlices()
método no objeto criado.
var myPiechart = new Piechart( { canvas: myCanvas, data: { "Classical Music": 16, "Alternative Rock": 12, "Pop": 18, "Jazz": 32 }, colors: ["#80DEEA", "#FFE082", "#FFAB91", "#CE93D8"] } ); myPiechart.drawSlices();E o resultado fica assim:
Desenhando o gráfico de rosca
Vimos como desenhar o gráfico de pizza. Também sabemos que um gráfico de rosca difere apenas por ter um buraco no meio do gráfico. Como desenhamos o buraco? Podemos desenhar um círculo branco sobre o gráfico de pizza. Vamos modificar odrawSlices()
método do Piechart
aula para fazer isso.
drawSlices() { var colorIndex = 0; var startAngle = -Math.PI / 2; for (var categ in this.options.data) { var val = this.options.data[categ]; var sliceAngle = (2 * Math.PI * val) / this.totalValue; drawPieSlice( this.ctx, this.canvas.width / 2, this.canvas.height / 2, this.radius, startAngle, startAngle + sliceAngle, this.colors[colorIndex % this.colors.length] ); startAngle += sliceAngle; colorIndex++; } if (this.options.doughnutHoleSize) { drawPieSlice( this.ctx, this.canvas.width / 2, this.canvas.height / 2, this.options.doughnutHoleSize * this.radius, 0, 2 * Math.PI, "#FFF", "#FFF" ); drawArc( this.ctx, this.canvas.width / 2, this.canvas.height / 2, this.options.doughnutHoleSize * this.radius, 0, 2 * Math.PI, "#000" ); } }O código adicionado parece no
options
parâmetro para uma variável de membro doughnutHoleSize
. Se isso não existir nas opções, o código desenhará o gráfico de pizza como antes, mas se existir, um círculo branco será desenhado com o mesmo centro do gráfico de pizza.
O raio do círculo é determinado multiplicando o raio do gráfico de pizza e o valor de doughnutHoleSize
. Este deve ser um número entre 0 e 1, onde 0 resultará em um gráfico de pizza e quaisquer valores maiores que 0 resultarão em um donut com o furo cada vez maior, 1 tornando o gráfico invisível.
Para desenhar um gráfico de rosca com um buraco com metade do tamanho do gráfico, precisaríamos usar um doughnutHoleSize
de 0,5 e faça as seguintes chamadas:
var myDougnutChart = new Piechart( { canvas:myCanvas, data:myVinyls, colors:["#fde23e","#f16e23", "#57d9ff","#937e88"], doughnutHoleSize:0.5 } ); myDougnutChart.drawSlices();E aqui está o resultado:
Adicionando rótulos e uma legenda de gráfico
Nosso gráfico de pizza e o gráfico de rosca parecem muito bons, mas podemos torná-los ainda melhores adicionando duas coisas:- rótulos de valor: mostrando a porcentagem correspondente a cada fatia
- uma legenda do gráfico: mostrando as categorias e suas cores correspondentes no gráfico
100 * value associated to a slice / total value
com todo o círculo representando 100%
.
Por exemplo, no caso de nossos dados de amostra, os vinis com música clássica representariam aproximadamente 26%
. Seria bom poder escrever esse valor na fatia correspondente. Para isso, usaremos o fillText(text,x,y)
função do contexto do desenho. Esta função recebe três parâmetros: o texto e o x
e y
coordenadas.
Como calculamos o x
e y
coordenadas nas quais colocar o texto? Temos que fazer uso de algum conhecimento de geometria e algo chamado coordenadas polares. Basicamente, as coordenadas polares usam um raio e um ângulo para definir a posição de um ponto. As duas fórmulas que usaremos são:
x = R * cos(angle)
y = R * sin(angle)
Aplicaremos essas duas fórmulas para colocar o texto na metade do raio do gráfico de pizza e na metade do ângulo de cada fatia de pizza. Para fazer isso, precisamos adicionar outro método chamado drawLabels()
para nosso Piechart
classe:
drawLabels() { var colorIndex = 0; var startAngle = -Math.PI / 2; for (var categ in this.options.data) { var val = this.options.data[categ]; var sliceAngle = (2 * Math.PI * val) / this.totalValue; var labelX = this.canvas.width / 2 + (this.radius / 2) * Math.cos(startAngle + sliceAngle / 2); var labelY = this.canvas.height / 2 + (this.radius / 2) * Math.sin(startAngle + sliceAngle / 2); if (this.options.doughnutHoleSize) { var offset = (this.radius * this.options.doughnutHoleSize) / 2; labelX = this.canvas.width / 2 + (offset + this.radius / 2) * Math.cos(startAngle + sliceAngle / 2); labelY = this.canvas.height / 2 + (offset + this.radius / 2) * Math.sin(startAngle + sliceAngle / 2); } var labelText = Math.round((100 * val) / this.totalValue); this.ctx.fillStyle = "black"; this.ctx.font = "32px Khand"; this.ctx.fillText(labelText + "%", labelX, labelY); startAngle += sliceAngle; } }O código percorre cada fatia, calcula a porcentagem, calcula a posição e usa o
fillText()
método para desenhá-lo no gráfico. Temos usado o fillStyle
propriedade para definir a cor do texto para Preto e a font
propriedade para definir o tamanho e a família de fontes do rótulo. Também é importante observar que se o gráfico for um gráfico de rosca e o doughnutHoleSize
estiver definido, o rótulo será empurrado em direção à borda do gráfico para torná-lo centralizado na fatia de rosca.
E aqui está a aparência dos gráficos resultantes com os rótulos de valor:
Para completar nosso gráfico, a última coisa que adicionaremos é a legenda do gráfico. A legenda do nosso gráfico exibirá as categorias do nosso modelo de dados e a cor usada para a fatia correspondente. Primeiro temos que fazer algumas modificações no nosso index.html
arquivo adicionando um
tag que irá armazenar nosso elemento legend.
Então em script.js
adicionamos o código que cria o conteúdo do elemento legend. Fazemos isso dentro do drawLegend()
método do Piechart
classe:
drawLegend() {
let pIndex = 0;
let legend = document.querySelector("div[for="myCanvas"]");
let ul = document.createElement("ul");
legend.append(ul);
for (let ctg of Object.keys(this.options.data)) {
let li = document.createElement("li");
li.style.listStyle = "none";
li.style.borderLeft =
"20px solid " + this.colors[pIndex % this.colors.length];
li.style.padding = "5px";
li.textContent = ctg;
ul.append(li);
pIndex++;
}
}
O código procura um legend
elemento passado pelo options
parâmetro. Se for fornecido, este elemento é preenchido com o código HTML contendo uma caixa colorida e o nome da categoria do modelo de dados.
Nossos gráficos também terão um título que descreverá o que o gráfico deve nos mostrar. Podemos fazer isso adicionando outro método chamado drawTitle()
para nosso PieChart
classe. As opções de configuração para o título do gráfico serão retiradas do titleOptions
objeto passado para o PieChart
classe.
drawTitle() {
this.ctx.save();
this.ctx.textBaseline = "bottom";
this.ctx.textAlign = this.titleOptions.align;
this.ctx.fillStyle = this.titleOptions.fill;
this.ctx.font = `${this.titleOptions.font.weight} ${this.titleOptions.font.size} ${this.titleOptions.font.family}`;
let xPos = this.canvas.width / 2;
if (this.titleOptions.align == "left") {
xPos = 10;
}
if (this.titleOptions.align == "right") {
xPos = this.canvas.width - 10;
}
this.ctx.fillText(this.options.seriesName, xPos, this.canvas.height);
this.ctx.restore();
}
Mais uma coisa que podemos fazer para nossa própria conveniência é definir um draw()
método que chama todos os outros métodos da classe para desenhar o gráfico inteiro.
draw() {
this.drawSlices();
this.drawLabels();
this.drawTitle();
this.drawLegend();
}
Também precisamos fazer uma alteração na maneira como chamamos o desenho do nosso gráfico de pizza assim:
var myPiechart = new PieChart({
canvas: myCanvas,
seriesName: "Vinyl records",
padding: 40,
doughnutHoleSize: 0.4,
data: {
"Classical Music": 16,
"Alternative Rock": 12,
"Pop": 18,
"Jazz": 32
},
colors: ["#80DEEA", "#FFE082", "#FFAB91", "#CE93D8"],
titleOptions: {
align: "center",
fill: "black",
font: {
weight: "bold",
size: "18px",
family: "Lato"
}
}
});
myPiechart.draw();
E aqui está o gráfico resultante e a legenda do gráfico:
Parabéns
Vimos que desenhar gráficos usando a tela HTML5 não é tão difícil. Requer apenas um pouco de matemática e um pouco de conhecimento de JavaScript. Agora você tem tudo o que precisa para desenhar seus próprios gráficos de pizza e de rosca.
Se você deseja uma solução rápida e fácil para criar não apenas gráficos de pizza e donuts, mas muitos outros tipos de gráficos, você pode baixar o Infographic Charts and Graphics HTML Tags Library ou seu plugin WordPress Gráficos e Gráficos WordPress Visual Designer.