Con questo breve tutorial, illustro come creare dei semplici Grafici a Torta usando le istruzioni grafiche del GDI+.
Avviamo un nuovo progetto Windows Application e inseriamo il seguente codice:
Public Class Form1 'definizione dei controlli Private WithEvents PictureBox1 As New PictureBox Private WithEvents GroupBox1 As New GroupBox Private WithEvents rbVisioneCompatta As New RadioButton Private WithEvents rbVisioneEsplosa As New RadioButton 'dati da elaborare e rappresentare nel grafico a torta Dim datiGrafico() As Single = {12000, 6000, 6900, 7800} 'dati elaborati per essere e trasformati in percentuali e rappresentati nel grafico a torta Dim datiPercentuali(0 To 3) As Single 'colore di primo piano del grafico Dim colori() As System.Drawing.Color = {Color.Blue, Color.Red, Color.Green, Color.Yellow} 'colore del bordo del grafico Dim coloriScuri() As System.Drawing.Color = {Color.DarkBlue, Color.DarkRed, Color.DarkGreen, Color.YellowGreen} 'etichette dei vari spicchi del grafico a torta Dim nomiBarre() As String = {"Proteine", "Lipidi", "Carboidrati", "Alcol"} Private Sub Grafico_a_Torte_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 'si aggiungono i controlli alla Form Me.Size = New Size(500, 500) Me.Text = "Grafico a Torta" PictureBox1.Size = New Size(450, 275) PictureBox1.BackColor = Color.Black PictureBox1.Location = New Point(21, 19) GroupBox1.Text = "Visualizzazione" GroupBox1.Size = New Size(200, 110) GroupBox1.Location = New Point(146, 320) rbVisioneCompatta.Text = "Compatta" rbVisioneCompatta.Checked = True rbVisioneCompatta.Location = New Point(20, 28) rbVisioneEsplosa.Text = "Esplosa" rbVisioneEsplosa.Checked = False rbVisioneEsplosa.Location = New Point(20, 66) Me.Controls.Add(PictureBox1) Me.Controls.Add(GroupBox1) Me.GroupBox1.Controls.Add(rbVisioneCompatta) Me.GroupBox1.Controls.Add(rbVisioneEsplosa) CreazioniSpicchi(datiGrafico) End Sub Private Sub CreazioniSpicchi(ByRef dati() As Single) 'conversioni dei dati in valori percentuali rappresentabili sul grafico: 'si recupera il totale... Dim somma As Single = 0 For Each d As Single In dati somma += d Next '...e lo si usa per determinare le varie percentuali For i As Integer = 0 To 3 datiPercentuali(i) = 360 * datiGrafico(i) / somma Next End Sub Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles PictureBox1.Paint 'ogni spicchio per essere disegnato ha bisogno di un angolo iniziale e dell'ampiezza dell'angolo 'definizione dell'angolo iniziale Dim angoloIniziale As Single 'definizione della bisettrice di ogni spicchio Dim angoloBisettrice As Single 'coordinate del centro dello spicchio Dim punto As New PointF 'per realizzare l'effetto 3D si disegnano 31 grafici a torta uno sopra all'altro e traslati fra di loro di un pixel. 'l'ultimo grafico viene disegnato con un colore più chiaro per dare l'illusione della vista prospettica For z As Integer = 130 To 100 Step -1 angoloIniziale = 0 angoloBisettrice = 0 For i As Integer = 0 To 3 angoloBisettrice += datiPercentuali(i) / 2 'nella visione esplosa gli spicchi non formano un ellisse compatto ma sono separati gli uni dagli altri 'ogni vertice giace su un ellisse più piccola concentrica a quella che rappresenta il grafico stesso 'con il blocco seguente viene calcolato il punto in cui giace il vertice dello spicchio Select Case angoloBisettrice Case 0 To 90 punto.X = Math.Cos(DecToRad(angoloBisettrice)) * 25 punto.Y = Math.Sin(DecToRad(angoloBisettrice)) * 10 Case 90 To 180 punto.X = -Math.Cos(DecToRad(180 - angoloBisettrice)) * 25 punto.Y = Math.Sin(DecToRad(180 - angoloBisettrice)) * 10 Case 180 To 270 punto.X = -Math.Cos(DecToRad(angoloBisettrice - 180)) * 25 punto.Y = -Math.Sin(DecToRad(angoloBisettrice - 180)) * 10 Case Is > 270 punto.X = Math.Cos(DecToRad(360 - angoloBisettrice)) * 25 punto.Y = -Math.Sin(DecToRad(360 - angoloBisettrice)) * 10 End Select 'se è selezionata l'opzione Visualizzazione Compatta... If rbVisioneCompatta.Checked Then 'se il grafico da disegnare è quello più in alto (=ultimo)... If z = 100 Then 'si disegna il grafico con colori chiari... e.Graphics.FillPie(New SolidBrush(colori(i)), 100, z, 250, 100, angoloIniziale, datiPercentuali(i)) Else 'altrimenti si disegna il grafico con colori scuri realizzando il bordo della "Torta" e.Graphics.FillPie(New SolidBrush(coloriScuri(i)), 100, z, 250, 100, angoloIniziale, datiPercentuali(i)) End If 'altrimenti se è selezionata l'opzione Visualizzazione Esplosa... Else 'se il grafico da disegnare è quello più in alto (=ultimo)... If z = 100 Then 'si disegna il grafico con colori chiari...e si traslano gli spicchi portando i loro vertici nel Punto calcolato 'dal blocco Select Case e.Graphics.FillPie(New SolidBrush(colori(i)), 100 + punto.X, z + punto.Y, 250, 100, angoloIniziale, _ datiPercentuali(i)) Else 'come sopra ma con i colori scuri e.Graphics.FillPie(New SolidBrush(coloriScuri(i)), 100 + punto.X, z + punto.Y, 250, 100, angoloIniziale, _ datiPercentuali(i)) End If End If 'si aggiornano i valori dei due angoli angoloIniziale += datiPercentuali(i) angoloBisettrice += datiPercentuali(i) / 2 Next Next 'dimensione in pixel delle stringhe che rappresentano i valori numerici da disegnare in prossimità degli spicchi Dim dimensioneStringa As New SizeF 'distanza del vertice del rettangolo che contiene la scritta, dal centro dell'ellisse quando il grafico è compatto Dim distanza As New PointF angoloBisettrice = 0 For i As Integer = 0 To 3 'si recuperano le dimensioni della stringa che sarà disegnata in modo da poterla rappresentare esternamente 'al grafico ma con uno spigolo sempre vicino al bordo del grafico stesso dimensioneStringa = e.Graphics.MeasureString(datiGrafico(i).ToString, New Font("Arial", 8, FontStyle.Regular)) angoloBisettrice += datiPercentuali(i) / 2 'se è selezionata l'opzione Visualizzazione Compatta... If rbVisioneCompatta.Checked Then 'Si imposta la distanza del testo dal centro dell'ellisse distanza.X = 125 distanza.Y = 50 Else 'altrimenti si aumenta tale distanza per compensare l'"Eslposione" del grafico distanza.X = 150 distanza.Y = 60 End If 'gli spicchi "Esplodono" muovendosi sulla bisettrice dell'angolo che coprono, e spostandosi in modo 'che il loro vertice si posizioni sul nuovo "Punto" Select Case angoloBisettrice Case 0 To 90 punto.X = Math.Cos(DecToRad(angoloBisettrice)) * distanza.X + 225 punto.Y = Math.Sin(DecToRad(angoloBisettrice)) * distanza.Y + 150 Case 90 To 180 punto.X = -Math.Cos(DecToRad(180 - angoloBisettrice)) * distanza.X + 225 - dimensioneStringa.Width punto.Y = Math.Sin(DecToRad(180 - angoloBisettrice)) * distanza.Y + 150 Case 180 To 270 punto.X = -Math.Cos(DecToRad(angoloBisettrice - 180)) * distanza.X + 225 - dimensioneStringa.Width punto.Y = -Math.Sin(DecToRad(angoloBisettrice - 180)) * distanza.Y + 150 - dimensioneStringa.Height Case Is > 270 punto.X = Math.Cos(DecToRad(360 - angoloBisettrice)) * distanza.X + 225 punto.Y = -Math.Sin(DecToRad(360 - angoloBisettrice)) * distanza.Y + 150 - dimensioneStringa.Height End Select 'si disegna il testo e.Graphics.DrawString(datiGrafico(i).ToString, New Font("Arial", 8, FontStyle.Regular), Brushes.WhiteSmoke, _ punto.X, punto.Y) angoloBisettrice += datiPercentuali(i) / 2 Next 'si disegna la legenda For i As Integer = 0 To 3 e.Graphics.FillRectangle(New SolidBrush(colori(i)), 360, (i + 1) * 15 + 10, 10, 10) e.Graphics.DrawString(nomiBarre(i), New Font("Arial", 8, FontStyle.Regular), Brushes.White, 380, (i + 1) * 15 + 10) Next End Sub 'conversione fra angoli sessagesimali e radianti Private Function DecToRad(ByVal angolo As Single) As Double Return (angolo * Math.PI / 180) End Function 'si ridisegna l'area se cambia lo stato di un'opzione Private Sub CambioOpzione(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles rbVisioneCompatta.CheckedChanged, rbVisioneEsplosa.CheckedChanged PictureBox1.Invalidate() End Sub End Class
Ecco il risultato: