Simple Bar Chart Graph on Canvas Gadget
Posted: Tue Jun 26, 2012 12:40 pm
Crude, small and simple example, easy to butcher for your own use, or at least learn how not to do it
The chart grid does change to suit the data, up to a point, plus the Canvas size is related to the Window (fixed) Size. If the range of data you wish to cater for is large, plonk the canvas on a ScrollGadget and have your code dynamically change the size of both gadgets as required.
Sample data file HighestScores.txt:

The chart grid does change to suit the data, up to a point, plus the Canvas size is related to the Window (fixed) Size. If the range of data you wish to cater for is large, plonk the canvas on a ScrollGadget and have your code dynamically change the size of both gadgets as required.
Code: Select all
;Simple Bar Chart Graph. IdeasVacuum. Free to use, no restrictions.
Enumeration
#WinGraph
#CvsGraph
#FileIO
EndEnumeration
Structure Player
sPlayerName.s
iScore.i
iNameWidth.i
EndStructure
NewList Scores.Player()
Global igHighestScore.i = 0
Global igLongestName.i = 0
Global igWindowW.i = 700
Global igWindowH.i = 500
Global igCanvasW.i = (igWindowW - 20)
Global igCanvasH.i = (igWindowH - 20)
Global igWinBackColour.i = RGB(224,223,227) ;Classic Windows back colour
Global igFontID01.i = LoadFont(1, "Arial", 8, #PB_Font_Bold | #PB_Font_HighQuality + 2)
Global igFontID02.i = LoadFont(2, "Arial", 10, #PB_Font_Bold | #PB_Font_HighQuality + 2)
Macro RoundTo(i, s)
;-----------------
((s) * Round((i) / (s) + 0.5, #PB_Round_Down))
EndMacro
Procedure.i LoadInfo()
;--------------------
Shared Scores.Player()
Protected sVal.s = ""
Protected sScoresFile.s = "C:\MyGame\HighestScores.txt" ;<<-- Insert your own folder/file here
;Load the Player Data
;At the same time, get the Name length for right-alignment on graph later
If ReadFile(#FileIO,sScoresFile)
StartDrawing(CanvasOutput(#CvsGraph)) ;Needed for TextWidth function (nothing is drawn yet)
DrawingFont(igFontID02)
While Not Eof(#FileIO)
sVal = ReadString(#FileIO)
AddElement(Scores.Player())
Scores.Player()\sPlayerName = StringField(sVal, 1, Chr(44)) ;delimiter is a comma
Scores.Player()\iScore = ValD(StringField(sVal, 2, Chr(44)))
Scores.Player()\iNameWidth = TextWidth(Scores.Player()\sPlayerName)
If(Scores.Player()\iScore > igHighestScore) : igHighestScore = Scores.Player()\iScore : EndIf
If(Scores.Player()\iNameWidth > igLongestName) : igLongestName = Scores.Player()\iNameWidth : EndIf
Wend
StopDrawing()
CloseFile(#FileIO)
ProcedureReturn(#True)
Else
MessageRequester("Problem","Could not open HighestScores.txt file",#PB_MessageRequester_Ok | #MB_ICONERROR)
ProcedureReturn(#False)
EndIf
EndProcedure
Procedure DrawBarChart()
;-----------------------
;Draw a Chart on a Canvas, as though the Canvas is a sheet of paper
Shared Scores.Player()
Protected iTotalPlayers.i = 0
Protected iChartW.i = 0
Protected iChartH.i = 0
Protected iChartX0.i = 0
Protected iChartY0.i = 0
Protected iGridPitchX.i = 0
Protected iX.i = 0
Protected iTextCtrX.i = 0
Protected iLabelX.i = 0
Protected iLblX.i = 0
Protected iColour.i = 0
Protected iPreviousColour.i = 0
Protected dRatio.d = 0.00
Protected iGridPitchY.i = 0
Protected iY.i = 0
Protected iW.i = 0
Protected iTextX.i = 0
Protected iTextY.i = 0
Protected iTextCtrY.i = 0
Protected iHighestScore.i = 0
Protected iMulti.i = 100
If(igLongestName > 1) ;If it isn't, there was an issue with HighestScores.txt
StartDrawing(CanvasOutput(#CvsGraph))
DrawingFont(igFontID02)
BackColor(RGB(255,255,255))
DrawingMode(#PB_2DDrawing_Default)
;Draw shadow
Box(0,0,igCanvasW,igCanvasH,RGB(136,136,136)) ;Dark Grey
Box(-2,-2,igCanvasW + 4,10,igWinBackColour) ;(across top)
Box(-2,-2,10,igCanvasH + 4,igWinBackColour) ;(vertical left)
Box(0,0,igCanvasW -8,igCanvasH - 8,RGB(255,255,255)) ;White (Chart Region)
;Draw Canvas (paper) boundary
DrawingMode(#PB_2DDrawing_Outlined)
Box(0,0,igCanvasW -8,igCanvasH - 8,RGB(0,0,0)) ;Black
;Draw chart
;Chart has approx 15pix margin inside Canvas, all-round
iChartW = (igCanvasW - 40) - (igLongestName + 10)
iChartH = (igCanvasH - 65)
;Tweak Chart Height so that bars fit exact integer value (using double val = ugly bars)
iTotalPlayers = ListSize(Scores.Player())
iGridPitchY = (iChartH/iTotalPlayers)
iChartH = (iGridPitchY * iTotalPlayers)
iChartX0 = (igLongestName + 25)
iChartY0 = 15
;Tweak Chart Width so that grid lines fit exact integer value (using double val = ugly grid)
iGridPitchX = (iChartW/10)
iChartW = (iGridPitchX * 10)
DrawingMode(#PB_2DDrawing_Default)
Box(iChartX0,iChartY0,iChartW,iChartH,RGB(230,230,250)) ;Graph Background Lavenda
;Chart Grid Vertical Lines
DrawingMode(#PB_2DDrawing_Default)
iX = iChartX0
For i = 0 To 10
;X Y X2 Y2 Colour
If(iX < iChartW + iChartX0) : LineXY(iX,iChartY0,iX,(iChartH + 20),RGB(127,127,127)) : EndIf ;Grey Grid
;X Y X2 Y2 Colour
LineXY(iX,(iChartY0 + iChartH),iX,(iChartY0 + iChartH + 5),RGB(0,0,0)) ;Black 'comb'
iX + iGridPitchX
Next i
;Chart Labels along X
If(igHighestScore > 999) : iMulti = 1000 : EndIf
;Determine nearest 100 or 1000
iHighestScore = RoundTo(igHighestScore, iMulti)
If(igHighestScore > iHighestScore)
iHighestScore = ((igHighestScore - iHighestScore) + (iHighestScore + 20))
EndIf
iLabelX = (iHighestScore/10)
iLabelX = RoundTo(iLabelX, 5)
iLblX = 0
iX = iChartX0
For i = 0 To 11
iTextCtrX = (TextWidth(Str(iLblX)) / 2)
DrawText(iX - iTextCtrX,iChartH + 25,Str(iLblX),RGB(0,0,0))
iX + iGridPitchX
iLblX + iLabelX
Next i
;Chart Labels along Y + bars
iTextCtrY = (TextHeight("M") /2)
iTextY = (iChartY0 + (iGridPitchY/2)) - iTextCtrY
iY = iChartY0
dRatio = (iChartW/iHighestScore)
FirstElement(Scores.Player())
For i = 1 To iTotalPlayers
iTextX = ((iChartX0 - 5) - Scores.Player()\iNameWidth)
BackColor(RGB(255,255,255))
DrawingFont(igFontID02)
DrawText(iTextX,iTextY,Scores.Player()\sPlayerName,RGB(0,0,0))
iW = (dRatio * Scores.Player()\iScore)
iScoreX = ((iChartX0 + iW) - (TextWidth(StrD(Scores.Player()\iScore,0)) + 5))
iColour = RGB(Random(255),Random(255),Random(255))
If(iColour = iPreviousColour) : iColour = RGB(Random(255),Random(255),Random(255)) : EndIf
BackColor(iColour)
DrawingFont(igFontID01)
Box(iChartX0,iY,iW,iGridPitchY,iColour)
DrawText(iScoreX,iTextY,StrD(Scores.Player()\iScore,0),RGB(0,0,0))
NextElement(Scores.Player())
iPreviousColour = iColour
iY + iGridPitchY
iTextY + iGridPitchY
Next i
;Chart Grid Outline
DrawingMode(#PB_2DDrawing_Outlined)
Box(iChartX0,iChartY0,iChartW,iChartH,RGB(0,0,0)) ;Black
StopDrawing()
EndIf
EndProcedure
Procedure ShowWin()
;------------------
If OpenWindow(#WinGraph, 0, 0, igWindowW, igWindowH, "Highest Scores", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered)
SetWindowColor(#WinGraph,igWinBackColour)
CanvasGadget(#CvsGraph,10,10,igCanvasW,igCanvasH)
SetGadgetAttribute(#CvsGraph,#PB_Canvas_Cursor,#PB_Cursor_Hand)
Else
MessageRequester("Problem","Failed to open Window",#PB_MessageRequester_Ok | #MB_ICONERROR)
EndIf
EndProcedure
Procedure WaitForUser()
;----------------------
Protected iEvent.i = 0
Repeat
iEvent = WaitWindowEvent(1)
Until iEvent = #PB_Event_CloseWindow
EndProcedure
;## MAIN #############
ShowWin()
LoadInfo()
DrawBarChart()
WaitForUser()
;#####################
End
Cheryl,180
An Onymous,122
Beyonce,185
An Other,211
Joe Blogs,132
Will I Am,199
Rihanna,223
Ying Qin,285
Britney,180
John Smith,177
Lady Penelope, 252
Batman,99