Author : uwekel
Current version : 21-04-2014
Date of creation : 2014-04-21 20:12:40
Date of last version : 2014-04-21 20:12:40
Compatible with : Linux, Mac, Windows
Compile on : PureBasic only
Basic version used : PureBasic 5.21 LTS
Category : Custom gadgets,
Description : A little ChartGadget for drawing bar and line charts.
  1. EnableExplicit
  2.  
  3. Macro Iter(Object, ListOrMap)
  4.   ListOrMap
  5.   Object=ListOrMap
  6. EndMacro
  7. Macro Max(a, b)
  8.   ((a) * Bool((a) >=(b)) + (b) * Bool((b) > (a)))
  9. EndMacro
  10. Macro Min(a, b)
  11.   ((a) * Bool((a) <=(b)) + (b) * Bool((b) < (a)))
  12. EndMacro
  13.  
  14. Enumeration ;flags
  15.   #ChartFlagBorder = 1
  16.   #ChartFlagLegendRight = 2
  17.   #ChartFlagLegendBottom = 4
  18.   #ChartFlagXAxis = 8
  19.   #ChartFlagYAxis = 16
  20.   #ChartFlagHGrid = 32
  21.   #ChartFlagVGrid = 64
  22.   #ChartFlagStapled = 128
  23.   #ChartFlagBarsBorderless = 256
  24.   #ChartFlagXAxisVAlign = 512
  25.   #ChartFlagSortColumns = 1024
  26.   #ChartFlagSortRows = 2048
  27. EndEnumeration
  28. Enumeration ;attributes
  29.   #ChartSetFlags
  30.   #ChartSetFont
  31.   #ChartSetBackColor
  32.   #ChartSetFrontColor
  33.   #ChartSetAreaColor
  34.   #ChartSetGridColor
  35.   #ChartSetValueColor
  36.   #ChartSetAxisColor
  37.   #ChartSetLineWidth
  38.   #ChartSetPointSize
  39.   #ChartSetPadding
  40.   #ChartSetDecimalPlaces
  41. EndEnumeration
  42. Enumeration ;text types
  43.   #ChartTextTitle
  44.   #ChartTextYAxis
  45.   #ChartTextXAxis
  46.   #ChartTextUnit
  47. EndEnumeration
  48. Enumeration ;row types
  49.   #ChartRowTypeBar
  50.   #ChartRowTypeLine
  51. EndEnumeration
  52. Enumeration ;row flags
  53.   #ChartRowFlagValues = 1
  54.   #ChartRowFlagPoints = 2
  55. EndEnumeration
  56. Enumeration ;chart clear flags
  57.   #ChartClearKeepRows = 1
  58.   #ChartClearKeepColumns = 2
  59. EndEnumeration
  60.  
  61. Structure _ChartRow
  62.   Name.s
  63.   Type.b
  64.   Color.l
  65.   Flags.i
  66.   LastY.i
  67. EndStructure
  68. Structure _ChartColumn
  69.   Name.s
  70.   Minimum.f
  71.   Maximum.f
  72. EndStructure
  73. Structure _ChartValue
  74.   Row.s
  75.   Column.s
  76.   Value.f
  77. EndStructure
  78. Structure _Chart
  79.   Title.s
  80.   YTitle.s
  81.   XTitle.s
  82.   Unit.s
  83.   BackColor.l
  84.   FrontColor.l
  85.   AreaColor.l
  86.   GridColor.l
  87.   ValueColor.l
  88.   AxisColor.l
  89.   LineWidth.i
  90.   PointSize.i
  91.   Padding.i
  92.   DecimalPlaces.i
  93.   Minimum.f
  94.   Maximum.f
  95.   Flags.i
  96.   Font.i
  97.   TextHeight.i
  98.   StepValue.f
  99.   BarRowCount.i
  100.   List Rows._ChartRow()
  101.   List Columns._ChartColumn()
  102.   List Values._ChartValue()
  103. EndStructure
  104.  
  105. Procedure.f _ChartRoundUp(Value.f, StepValue.f)
  106.   ;rounds a value to the next higher step
  107.   Protected negative, v.f
  108.   ;convert negative to positive
  109.   If Value < 0
  110.     negative = #True
  111.     Value * -1
  112.   EndIf
  113.   ;round value
  114.   v = Int(Value / StepValue) * StepValue
  115.   If v < Value
  116.     v + StepValue
  117.   EndIf
  118.   ;restore negative value
  119.   If negative
  120.     v * -1
  121.   EndIf
  122.   ;return result
  123.   ProcedureReturn v
  124. EndProcedure
  125. Procedure.f _ChartRoundStepValue(Value.f)
  126.   ;returns a good step range value for a data point value
  127.   Protected n
  128.   ;avoid errors if value is zero
  129.   If Not Value
  130.     ProcedureReturn 1
  131.   EndIf
  132.   ;move value between 1 and 10
  133.   While Value > 10
  134.     Value / 10
  135.     n - 1
  136.   Wend
  137.   While Value < 1
  138.     Value * 10
  139.     n + 1
  140.   Wend
  141.   ;round
  142.   Select Value
  143.   Case 1 To 2.5
  144.     Value = 2.5
  145.   Case 2.5 To 5
  146.     Value = 5
  147.   Default
  148.     Value = 10
  149.   EndSelect
  150.   ;move value to original position
  151.   While n > 0
  152.     Value / 10
  153.     n - 1
  154.   Wend
  155.   While n < 0
  156.     Value * 10
  157.     n + 1
  158.   Wend
  159.   ;return rounded result
  160.   ProcedureReturn Value
  161. EndProcedure
  162. Procedure _ChartPoint(X, Y, Radius)
  163.   Protected xl, xr, yt, yb, i, yo
  164.   ;get corner positions
  165.   xl = x - Radius
  166.   xr = x + Radius
  167.   yt = y - Radius
  168.   yb = y + Radius
  169.   ;filling
  170.   For i = Radius To 0 Step -1
  171.     yo = Radius - i
  172.     LineXY(x - i, y - yo, x + i, y - yo)
  173.     LineXY(x - i, y + yo, x + i, y + yo)
  174.   Next
  175.   ;border
  176.   LineXY(xl, y, x, yt, $000000)
  177.   LineXY(x, yt, xr, y, $000000)
  178.   LineXY(xl, y, x, yb, $000000)
  179.   LineXY(x, yb, xr, y, $000000)
  180. EndProcedure
  181. Procedure _ChartLine(X, Y, x3, y3, Color, Thickness)
  182.   ;paints a chart line with anti-aliasing
  183.   Protected.f thick, x2, y2, app, hypo, cosphi, sinphi
  184.   Protected.l color1, color2, r, g, b, r1, g1, b1
  185.   Protected signx, signy, n, nn, w, h, xp, yp
  186.  
  187.   w = x3 - X
  188.   h = y3 - Y
  189.  
  190.   If w >= 0
  191.     signx = 1
  192.   Else
  193.     signx = -1
  194.     w = -w
  195.   EndIf
  196.   If h >= 0
  197.     signy = 1
  198.   Else
  199.     signy = -1
  200.     h = -h
  201.   EndIf
  202.  
  203.   thick.f = Thickness / 2
  204.   hypo.f = Sqr(w * w + h * h)
  205.   cosphi.f = w / hypo
  206.   sinphi.f = -Sin(ACos(cosphi))
  207.  
  208.   For n = -Thickness To w + Thickness
  209.     For nn = -Thickness To h + Thickness
  210.      
  211.       x2 = n * cosphi - nn * sinphi
  212.       y2 = Abs(n * sinphi + nn * cosphi)
  213.      
  214.       If y2 <= thick + 0.5
  215.         app = 0.5 + thick - y2
  216.         If app > 1
  217.           app = 1
  218.         EndIf
  219.         If x2 > -1 And x2 < hypo + 1
  220.           If x2 < 0
  221.             app * (1 + x2)
  222.           ElseIf x2 > hypo
  223.             app * (1 - x2 + hypo)
  224.           EndIf
  225.         Else
  226.           app = 0
  227.         EndIf
  228.         If app > 0
  229.           xp = X + n * signx
  230.           If xp >= 0 And xp < OutputWidth()
  231.             yp = Y + nn * signy
  232.             If yp >= 0 And yp < OutputHeight()
  233.               If app >= 1
  234.                 Plot(xp, yp, Color)
  235.               Else
  236.                 color1 = Point(xp, yp)
  237.                 r = Color & $FF
  238.                 g = Color >> 8 & $FF
  239.                 b = Color >> 16
  240.                 r1 = color1 & $FF
  241.                 g1 = color1 >> 8 & $FF
  242.                 b1 = color1 >> 16
  243.                 r = r * app + r1 * (1 - app)
  244.                 g = g * app + g1 * (1 - app)
  245.                 b = b * app + b1 * (1 - app)
  246.                 color2 = RGB(r, g, b)
  247.                 Plot(xp, yp, color2)
  248.               EndIf
  249.             EndIf
  250.           EndIf
  251.         EndIf
  252.       EndIf
  253.     Next
  254.   Next
  255.  
  256. EndProcedure
  257. Procedure _ChartPaintValue(*c._Chart, X, Y, Value.f)
  258.   ;paint value
  259.   Protected w, h, s.s
  260.   ;get value string
  261.   s = StrF(Value, *c\DecimalPlaces)
  262.   ;coordinates
  263.   w = TextWidth(s)
  264.   h = *c\TextHeight
  265.   X - w / 2
  266.   Y - *c\TextHeight / 2
  267.   ;draw
  268.   DrawText(X, Y, s, *c\FrontColor, *c\ValueColor)
  269.   DrawingMode(#PB_2DDrawing_Outlined)
  270.   X - 1: Y - 1: w + 2: h + 2
  271.   Box(X, Y, w, h, *c\ValueColor)
  272.   X - 1: Y - 1: w + 2: h + 2
  273.   Box(X, Y, w, h, 0)
  274.   DrawingMode(#PB_2DDrawing_Default)
  275. EndProcedure
  276. Procedure _ChartPaintBar(*c._Chart, *r._ChartRow, x, y, w, h)
  277.   ;paint bar
  278.   Box(x, y, w, h, *r\Color)
  279.   ;paint bar borders
  280.   If Not *c\Flags & #ChartFlagBarsBorderless
  281.     Line(x, y, 1, h, 0)
  282.     Line(x, y, w, 1, 0)
  283.     Line(x + w, y, 1, h, 0)
  284.     Line(x, y + h, w + 1, 1, 0)
  285.   EndIf
  286. EndProcedure
  287. Procedure _ChartPaintLegend(*c._Chart, *r._ChartRow, x, y)
  288.   ;paint legend item
  289.   Protected i, cx, cy, ps
  290.   Select *r\Type
  291.   Case #ChartRowTypeBar
  292.     _ChartPaintBar(*c, *r, x + 1, y + 1, *c\TextHeight - 3, *c\TextHeight - 2)
  293.   Case #ChartRowTypeLine
  294.     cy = y + *c\TextHeight / 2
  295.     _ChartLine(x + 1, cy, x + *c\TextHeight - 2, cy, *r\Color, *c\LineWidth)
  296.     ;limit pointsize to textsize
  297.     cx = x + *c\TextHeight / 2 - 1
  298.     ps = Min(*c\PointSize, *c\TextHeight / 2 - 2)
  299.     _ChartPoint(cx, cy, ps)
  300.   EndSelect
  301.   ;row name
  302.   DrawText(x + *c\TextHeight + 1, y, *r\Name, *c\FrontColor, *c\BackColor)
  303. EndProcedure
  304.  
  305. Procedure ChartPaint(Gadget)
  306.   ;paint the whole chart
  307.   Protected *g._Chart, *c._ChartColumn, *r._ChartRow, *v._ChartValue
  308.   Protected x, y, w, h, font, xah, yaw, areah, splits, v.f, x1, y1, cw.f, i, xr, s.s, tw, cx, bw, zypos, zyneg, zy, bx, vh, px, py, lx, ly, lw, pass
  309.   #_ChartAxisLimiterLength = 8
  310.   #_ChartLegendPad = 8
  311.   #_ChartXAxisPad = 4
  312.   *g = GetGadgetData(Gadget)
  313.   With *g
  314.     StartDrawing(CanvasOutput(Gadget))
  315.     ;preparation
  316.    
  317.     ;drawing area size
  318.     w = OutputWidth()
  319.     h = OutputHeight()
  320.     ;create and measure font
  321.     DrawingFont(\Font)
  322.     \TextHeight = TextHeight("Xg")
  323.     ;paint background
  324.     Box(x, y, w, h, \BackColor)
  325.     ;add padding
  326.     If \Padding
  327.       x + \Padding
  328.       y + \Padding
  329.       w - \Padding * 2
  330.       h - \Padding * 2
  331.     EndIf
  332.    
  333.     ;paint top title
  334.    
  335.     If \Title
  336.       tw = TextWidth(\Title)
  337.       DrawText((w - tw) / 2, y, \Title, \FrontColor, \BackColor)
  338.       y + \TextHeight + \Padding
  339.       h - \TextHeight - \Padding
  340.     ElseIf \Flags & #ChartFlagYAxis
  341.       ;at least use half height of text as spacing for y-axis values
  342.       y + \TextHeight / 2
  343.       h - \TextHeight / 2
  344.     EndIf
  345.    
  346.     ;paint legend
  347.    
  348.     If \Flags & #ChartFlagLegendRight
  349.       ;maximum row name width
  350.       ly = y + h / 2
  351.       ForEach Iter(*r, \Rows())
  352.         tw = TextWidth(*r\Name)
  353.         If tw > lw
  354.           lw = tw
  355.         EndIf
  356.         ly - (\TextHeight + #_ChartLegendPad) / 2
  357.       Next
  358.       tw + \TextHeight
  359.       lx = x + w - tw
  360.       ForEach Iter(*r, \Rows())
  361.         _ChartPaintLegend(*g, *r, lx, ly)
  362.         ly + \TextHeight + #_ChartLegendPad
  363.       Next
  364.       w - tw - \Padding
  365.     ElseIf \Flags & #ChartFlagLegendBottom
  366.       ;get total width
  367.       ly = y + h - \TextHeight - \Padding
  368.       lx = x + w / 2
  369.       ForEach Iter(*r, \Rows())
  370.         ;#_ChartLegendPad = 8
  371.         lx - (TextWidth(*r\Name) + \TextHeight - #_ChartLegendPad) / 2
  372.       Next
  373.       ForEach Iter(*r, \Rows())
  374.         tw = TextWidth(*r\Name)
  375.         _ChartPaintLegend(*g, *r, lx, ly + \Padding)
  376.         lx + tw + \TextHeight + #_ChartLegendPad
  377.       Next
  378.       h - \TextHeight - \Padding
  379.     EndIf
  380.    
  381.     ;left title of y-axis
  382.    
  383.     If \YTitle
  384.       tw = TextWidth(\YTitle)
  385.       DrawRotatedText(x, y + (h + tw) / 2, \YTitle, 90, \FrontColor)
  386.       x + \TextHeight + \Padding
  387.       w - \TextHeight - \Padding
  388.     EndIf
  389.    
  390.     ;bottom title of x-axis
  391.    
  392.     If \XTitle
  393.       tw = TextWidth(\XTitle)
  394.       DrawText(x + (w - tw) / 2, y + h - \TextHeight, \XTitle, \FrontColor, \BackColor)
  395.       h - \TextHeight - \Padding
  396.     EndIf
  397.    
  398.     ;x-axis height
  399.    
  400.     If \Flags & #ChartFlagXAxis
  401.       xah = #_ChartAxisLimiterLength
  402.       If \Flags & #ChartFlagXAxisVAlign
  403.         ForEach \Columns()
  404.           xah = Max(xah, TextWidth(\Columns()\Name))
  405.         Next
  406.       Else
  407.         xah = Max(xah, \TextHeight)
  408.       EndIf
  409.       ;add small gap between
  410.       xah + #_ChartXAxisPad * 2
  411.       ;reduce remain space for area
  412.       h - xah
  413.     EndIf
  414.    
  415.     ;value range
  416.    
  417.     If h > 0
  418.       ;get value range for each column
  419.       ForEach Iter(*c, \Columns())
  420.         *c\Minimum = 0
  421.         *c\Maximum = 0
  422.         ForEach Iter(*v, \Values())
  423.           If *v\Column = *c\Name
  424.             If \Flags & #ChartFlagStapled ;sum stapled bars
  425.               ForEach Iter(*r, \Rows())
  426.                 If *r\Name = *v\Row
  427.                   If *r\Type = #ChartRowTypeBar
  428.                     If *v\Value > 0
  429.                       *c\Maximum + *v\Value
  430.                     Else
  431.                       *c\Minimum + *v\Value
  432.                     EndIf
  433.                   EndIf
  434.                   Break
  435.                 EndIf
  436.               Next
  437.             ElseIf *v\Value < *c\Minimum
  438.               *c\Minimum = *v\Value
  439.             ElseIf *v\Value > *c\Maximum
  440.               *c\Maximum = *v\Value
  441.             EndIf
  442.           EndIf
  443.         Next
  444.       Next
  445.       ;calculate min/max for chart (over all columns)
  446.       \Minimum = 0
  447.       \Maximum = 0
  448.       ForEach Iter(*c, \Columns())
  449.         If *c\Minimum < \Minimum
  450.           \Minimum = *c\Minimum
  451.         EndIf
  452.         If *c\Maximum > \Maximum
  453.           \Maximum = *c\Maximum
  454.         EndIf
  455.       Next
  456.       ;widen range to avoid later errors (division by 0)
  457.       If \Maximum = \Minimum
  458.         \Maximum + 1
  459.       EndIf
  460.       ;number of splits
  461.       Select h
  462.       Case 0 To 50
  463.         splits = 1
  464.       Case 0 To 100
  465.         splits = 2
  466.       Case 100 To 500
  467.         splits = 5
  468.       Default
  469.         splits = 10
  470.       EndSelect
  471.       ;calculate and round step value
  472.       \StepValue = (\Maximum - \Minimum) / splits
  473.       \StepValue = _ChartRoundStepValue(\StepValue)
  474.       ;round min/max
  475.       \Minimum = _ChartRoundUp(\Minimum, \StepValue)
  476.       \Maximum = _ChartRoundUp(\Maximum, \StepValue)
  477.     EndIf
  478.    
  479.     ;y-axis width
  480.    
  481.     If \Flags & #ChartFlagYAxis
  482.       yaw = TextWidth(StrF(\Maximum, \DecimalPlaces) + \Unit)
  483.       tw = TextWidth(StrF(\Minimum, \DecimalPlaces) + \Unit)
  484.       If tw > yaw
  485.         yaw = tw
  486.       EndIf
  487.       yaw + #_ChartAxisLimiterLength
  488.       x + yaw
  489.       w - yaw
  490.     EndIf
  491.    
  492.     ;paint area
  493.    
  494.     If h > 0
  495.       ;background
  496.       Box(x, y, w, h, \AreaColor)
  497.       ;paint horizontal grid of x-axis
  498.       If \Flags & #ChartFlagHGrid
  499.         v = \Minimum
  500.         While v <= \Maximum
  501.           y1 = y + h - h * (v - \Minimum) / (\Maximum - \Minimum)
  502.           Line(x, y1, w, 1, \GridColor)
  503.           v + \StepValue
  504.         Wend
  505.       EndIf
  506.       ;paint vertical grid of y-axis
  507.       If \Flags & #ChartFlagVGrid
  508.         cw = w / ListSize(\Columns())
  509.         Line(x, y, 1, h, \GridColor)
  510.         ForEach \Columns()
  511.           i + 1
  512.           x1 = x + cw * i
  513.           Line(x1, y, 1, h, \GridColor)
  514.         Next
  515.       EndIf
  516.       ;black line at zero position
  517.       y1 = y + h - h * -\Minimum / (\Maximum - \Minimum)
  518.       If y1 >= y And y1 <= y + h
  519.         Line(x, y1, w + 1, 1, \AxisColor)
  520.       EndIf
  521.     EndIf
  522.    
  523.     ;paint values
  524.    
  525.     If FirstElement(\Values())
  526.       ;reset last y-positions per row (for line chart)
  527.       ForEach \Rows()
  528.         \Rows()\LastY = 0
  529.       Next
  530.       ;single column width
  531.       #Gap = 0.125
  532.       cw = w / ListSize(\Columns())
  533.       ;single bar width
  534.       bw = cw * (1 - #Gap - #Gap)
  535.       ;share width of bars if not stapled
  536.       If Not \Flags & #ChartFlagStapled And \BarRowCount > 1
  537.         bw / \BarRowCount
  538.       EndIf
  539.       ;paint bars then lines
  540.       For pass = 1 To 3
  541.         ForEach Iter(*c, \Columns())
  542.           ;column x-position
  543.           cx = x + ListIndex(\Columns()) * cw
  544.           ;zero line y-position
  545.           zypos = y + h - h * -\Minimum / (\Maximum - \Minimum)
  546.           zyneg = zypos
  547.           bx = cx + cw * #Gap
  548.           ForEach Iter(*r, \Rows())
  549.             ForEach Iter(*v, \Values())
  550.               If *v\Row = *r\Name And *v\Column = *c\Name
  551.                 vh = h * *v\Value / (\Maximum - \Minimum)
  552.                 If pass = 1 And *r\Type = #ChartRowTypeBar
  553.                   ;paint bars in first pass
  554.                   ;positive values above zero line, negatives below
  555.                   If *v\Value > 0 Or Not \Flags & #ChartFlagStapled
  556.                     zy = zypos
  557.                   Else
  558.                     zy = zyneg
  559.                   EndIf
  560.                   ;paint bar
  561.                   _ChartPaintBar(*g, *r, bx, zy - vh, bw, vh)
  562.                   ;paint value
  563.                   If *r\Flags & #ChartRowFlagValues
  564.                     _ChartPaintValue(*g, bx + bw / 2, zy - vh / 2, *v\Value)
  565.                   EndIf
  566.                   ;shift to next bar position
  567.                   If Not \Flags & #ChartFlagStapled
  568.                     bx + bw ;next is right
  569.                   ElseIf *v\Value > 0
  570.                     zypos - vh ;next positve value is above
  571.                   Else
  572.                     zyneg - vh ;next negative value is below
  573.                   EndIf
  574.                  
  575.                 ElseIf *r\Type = #ChartRowTypeLine
  576.                   ;value point position
  577.                   px = cx + cw / 2
  578.                   py = zy - vh
  579.                   If pass = 2
  580.                     ;paint lines in second pass
  581.                     ;line is possible from the second value
  582.                     If \Rows()\LastY
  583.                       _ChartLine(px - cw, *r\LastY, px, py, *r\Color, \LineWidth)
  584.                     EndIf
  585.                     ;remember this y-position so a line can be drawn next
  586.                     *r\LastY = py
  587.                    
  588.                   ElseIf pass = 3
  589.                     ;paint data points and values in third pass
  590.                     _ChartPoint(px, py, \PointSize)
  591.                     ;paint value
  592.                     If *r\Flags & #ChartRowFlagValues
  593.                       If *v\Value >= 0
  594.                         ;positiv above line
  595.                         py - \PointSize - \TextHeight + 4
  596.                       Else
  597.                         ;negative below line
  598.                         py + \PointSize + \TextHeight - 4
  599.                       EndIf
  600.                       _ChartPaintValue(*g, px, py, *v\Value)
  601.                     EndIf
  602.                    
  603.                   EndIf
  604.                 EndIf
  605.               EndIf
  606.             Next
  607.           Next
  608.         Next
  609.       Next
  610.     EndIf
  611.    
  612.     ;paint y-axis
  613.    
  614.     If \Flags & #ChartFlagYAxis
  615.       ;vertical line
  616.       Line(x, y, 1, h, \AxisColor)
  617.       ;delimiters and values
  618.       v = \Minimum
  619.       While v <= \Maximum
  620.         y1 = y + h - h * (v - \Minimum) / (\Maximum - \Minimum)
  621.         Line(x - #_ChartAxisLimiterLength + 1, y1, #_ChartAxisLimiterLength, 1, \AxisColor)
  622.         s = StrF(v, \DecimalPlaces) + \Unit
  623.         DrawText(x - #_ChartAxisLimiterLength - TextWidth(s), y1 - \TextHeight / 2, s, \FrontColor, \BackColor)
  624.         v + \StepValue
  625.       Wend
  626.     EndIf
  627.    
  628.     ;paint x-axis
  629.    
  630.     If \Flags & #ChartFlagXAxis
  631.       y + h
  632.       cw = w / ListSize(\Columns())
  633.       Line(x, y, w + 1, 1, \AxisColor)
  634.       Line(x, y, 1, #_ChartAxisLimiterLength, \AxisColor)
  635.       i = 0
  636.       ForEach Iter(*c, \Columns())
  637.         i + 1
  638.         xr = x + cw * i
  639.         Line(xr, y, 1, #_ChartAxisLimiterLength, \AxisColor)
  640.         If \Flags & #ChartFlagXAxisVAlign
  641.           DrawRotatedText(xr - (cw + \TextHeight) / 2, y + xah - #_ChartXAxisPad, *c\Name, 90, \FrontColor)
  642.         Else
  643.           tw = TextWidth(*c\Name)
  644.           DrawRotatedText(xr - cw / 2 - tw / 2, y + #_ChartXAxisPad, *c\Name, 0, \FrontColor)
  645.         EndIf
  646.       Next
  647.     EndIf
  648.    
  649.     StopDrawing()
  650.   EndWith
  651. EndProcedure
  652. Procedure ChartSet(Gadget, Setting, Value)
  653.   ;setup chart attributes
  654.   Protected *g._Chart = GetGadgetData(Gadget)
  655.   Select Setting
  656.   Case #ChartSetFlags
  657.     *g\Flags = Value
  658.   Case #ChartSetFont
  659.     *g\Font = Value
  660.   Case #ChartSetBackColor
  661.     *g\BackColor = Value
  662.   Case #ChartSetFrontColor
  663.     *g\FrontColor = Value
  664.   Case #ChartSetAreaColor
  665.     *g\AreaColor = Value
  666.   Case #ChartSetGridColor
  667.     *g\GridColor = Value
  668.   Case #ChartSetValueColor
  669.     *g\ValueColor = Value
  670.   Case #ChartSetLineWidth
  671.     *g\LineWidth = Value
  672.   Case #ChartSetPointSize
  673.     *g\PointSize = Value
  674.   Case #ChartSetPadding
  675.     *g\Padding = Value
  676.   Case #ChartSetDecimalPlaces
  677.     *g\DecimalPlaces = Value
  678.   EndSelect
  679. EndProcedure
  680. Procedure ChartRow(Gadget, Name.s, Type.b, Color.l, Flags=0)
  681.   ;add a row to the chart
  682.   Protected *g._Chart, *r._ChartRow
  683.   *g = GetGadgetData(Gadget)
  684.   ;insert sorted by name
  685.   If *g\Flags & #ChartFlagSortRows
  686.     ForEach *g\Rows()
  687.       If *g\Rows()\Name > Name
  688.         *r = InsertElement(*g\Rows())
  689.         Goto Set:
  690.       EndIf
  691.     Next
  692.   EndIf
  693.   *r = AddElement(*g\Rows())
  694.   Set:
  695.   *r\Name = Name
  696.   *r\Type = Type
  697.   *r\Color = Color
  698.   *r\Flags = Flags
  699.   ;count number of rows with bars
  700.   If Type = #ChartRowTypeBar
  701.     *g\BarRowCount + 1
  702.   EndIf
  703. EndProcedure
  704. Procedure ChartColumn(Gadget, Name.s)
  705.   ;add a column to the chart
  706.   Protected *g._Chart, *c._ChartColumn
  707.   *g = GetGadgetData(Gadget)
  708.   ;insert sorted by name
  709.   If *g\Flags & #ChartFlagSortColumns
  710.     ForEach *g\Columns()
  711.       If *g\Columns()\Name > Name
  712.         *c = InsertElement(*g\Columns())
  713.         Goto Set
  714.       EndIf
  715.     Next
  716.   EndIf
  717.   ;append new column
  718.   *c = AddElement(*g\Columns())
  719.   Set:
  720.   *c\Name = Name
  721. EndProcedure
  722. Procedure ChartValue(Gadget, Row.s, Column.s, Value.f)
  723.   ;add or update chart value
  724.   Protected *g._Chart, *v._ChartValue
  725.   *g = GetGadgetData(Gadget)
  726.   ;update existing value
  727.   ForEach Iter(*v, *g\Values())
  728.     If *v\Row = Row And *v\Column = Column
  729.       *v\Value = Value
  730.       ProcedureReturn
  731.     EndIf
  732.   Next
  733.   ;add new value
  734.   *v = AddElement(*g\Values())
  735.   *v\Row = Row
  736.   *v\Column = Column
  737.   *v\Value = Value
  738. EndProcedure
  739. Procedure ChartText(Gadget, Type, Text.s)
  740.   Protected *c._Chart = GetGadgetData(Gadget)
  741.   Select Type
  742.   Case #ChartTextTitle
  743.     *c\Title = Text
  744.   Case #ChartTextYAxis
  745.     *c\YTitle = Text
  746.   Case #ChartTextXAxis
  747.     *c\XTitle = Text
  748.   Case #ChartTextUnit
  749.     *c\Unit = Text
  750.   EndSelect
  751. EndProcedure
  752. Procedure ChartClear(Gadget, Flags=0)
  753.   ;remove all data from the chart
  754.   Protected *g._Chart = GetGadgetData(Gadget)
  755.   *g\BarRowCount = 0
  756.   ClearList(*g\Values())
  757.   If Not Flags & #ChartClearKeepColumns
  758.     ClearList(*g\Columns())
  759.   EndIf
  760.   If Not Flags & #ChartClearKeepRows
  761.     ClearList(*g\Rows())
  762.   EndIf
  763. EndProcedure
  764. Procedure ChartGadget(Gadget, x, y, w, h, Flags=0)
  765.   ;create new chart gadget (from CanvasGadget)
  766.   Protected *c._Chart, canvasflag, id
  767.   If Flags & #ChartFlagBorder
  768.     canvasflag = #PB_Canvas_Border
  769.   EndIf
  770.   id = CanvasGadget(Gadget, x, y, w, h, canvasflag)
  771.   ;support #PB_Any
  772.   If Gadget = #PB_Any
  773.     Gadget = id
  774.   EndIf
  775.   ;create and store additional object data
  776.   *c = AllocateMemory(SizeOf(_Chart))
  777.   SetGadgetData(Gadget, *c)
  778.   NewList *c\Columns()
  779.   NewList *c\Rows()
  780.   NewList *c\Values()
  781.   ;default settings
  782.   *c\Font = GetGadgetFont(#PB_Default)
  783.   *c\BackColor = $FFFFFF
  784.   *c\FrontColor = $000000
  785.   *c\AreaColor = $CDEBFF
  786.   *c\GridColor = $87B8DE
  787.   *c\ValueColor = $FFFFFF
  788.   *c\AxisColor = $000000
  789.   *c\LineWidth = 3
  790.   *c\PointSize = 5
  791.   *c\Padding = 8
  792.   *c\Flags = Flags
  793.   ;initial paint
  794.   ChartPaint(Gadget)
  795.   ;return result
  796.   ProcedureReturn id
  797. EndProcedure
  798.  
  799. DisableExplicit
  800.  
  801. CompilerIf #PB_Compiler_IsMainFile
  802.  
  803.   If OpenWindow(0, 0, 0, 800, 500, "Chart-Test", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
  804.    
  805.     ;setup chart (comment lines out to see the result)
  806.     flags = #ChartFlagBorder
  807.     flags | #ChartFlagLegendBottom
  808.     flags | #ChartFlagYAxis
  809.     flags | #ChartFlagXAxis
  810.     ;flags | #ChartFlagXAxisVAlign
  811.     flags | #ChartFlagHGrid
  812.     flags | #ChartFlagVGrid
  813.     flags | #ChartFlagStapled
  814.    
  815.     ChartGadget(0, 10, 10, 780, 480, flags)
  816.     ChartText(0, #ChartTextTitle, "Cost per Month")
  817.     ChartText(0, #ChartTextYAxis, "Euro")
  818.     ChartText(0, #ChartTextXAxis, "Month")
  819.     ChartText(0, #ChartTextUnit, " EUR")
  820.     ;ChartSet(0, #ChartSetPadding, 32)
  821.     ;ChartSet(0, #ChartSetPointSize, 15)
  822.     ;ChartSet(0, #ChartSetFont, FontID(LoadFont(#PB_Any, "Lucida Sans", 12)))
  823.     ChartSet(0, #ChartSetLineWidth, 6)
  824.    
  825.     ;add some data rows
  826.     ChartRow(0, "Positive", #ChartRowTypeBar, $009060)
  827.     ChartRow(0, "Negative", #ChartRowTypeBar, $2020E0)
  828.     ChartRow(0, "Average", #ChartRowTypeLine, $00D7FF, #ChartRowFlagValues)
  829.    
  830.     ;add some data columns
  831.     For i = 1 To 12
  832.       month.s = StringField("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec", i, "|")
  833.       ChartColumn(0, month)
  834.      
  835.       ;add a value for each row and column
  836.       positive = Random(9, 1) * 10
  837.       negative = Random(9, 1) * -10
  838.       ChartValue(0, "Positive", month, positive)
  839.       ChartValue(0, "Negative", month, negative)
  840.       ChartValue(0, "Average", month, (positive + negative) / 2)
  841.      
  842.     Next
  843.    
  844.     ;refresh the chart
  845.     ChartPaint(0)
  846.    
  847.     ;run event loop
  848.     Repeat
  849.       Select WaitWindowEvent()
  850.       Case #PB_Event_SizeWindow
  851.         ;resize the chart and redraw it
  852.         ResizeGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20)
  853.         ChartPaint(0)
  854.       Case #PB_Event_CloseWindow
  855.         Break
  856.       EndSelect
  857.     ForEver
  858.    
  859.   EndIf
  860. CompilerEndIf
2014-02-22 11:54:46 by Thorsten1867
Please translate to English!
[german]Bitte ├╝bersetzen![/german]