MODULE PieChart PIEC [ALL OS!]

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

MODULE PieChart PIEC [ALL OS!]

Beitrag von Mijikai »

PieChart module/gadget :)

Bild

Update v.1.00:
- Code ist nun OS Independent!

Update v.1.01
- Kleinere Bugs gefixt
- Code teilweise kommentiert

Module:

Code: Alles auswählen


;By Mijikai
;PIEC (PieChart) module [ALL OS!]
;Version: v.1.01
;Tested on Win10 x64
;PB v.5.60

DeclareModule PIEC
  Declare.i Create(X.i,Y.i,Name.s,Radius.d,Flag.b)
  Declare.i Add(*PieChart,Name.s,Value.d,Color.l)
  Declare.i Remove(*PieChart,Name.s)
  Declare.i Update(*PieChart,Name.s,Value.d)
  Declare.i Free(*PieChart)
EndDeclareModule

Module PIEC
  
  Structure PIEC_ENTRY_STRUCT
    Name.s{32}
    Image.i
    Color.l
    Value.d
    Percent.d
    Deg.d
    *NextEntry.PIEC_ENTRY_STRUCT
  EndStructure
  
  Structure PIEC_STRUCT
    Gadget.i
    GadgetList.i
    Image.i
    X.i
    Y.i
    Radius.d
    Flag.b
    Summ.d
    *FirstEntry.PIEC_ENTRY_STRUCT
  EndStructure 
  
  #PIEC_MIN_RADIUS            = 80
  #PIEC_FACTOR                = 20
  #PIEC_COLUMN_VALUE          = "Value"
  #PIEC_COLUMN_PERCENT        = "%"
  #PIEC_LIST_WIDTH            = 370
  #PIEC_COLUMN_NAME_WIDTH     = 205
  #PIEC_COLUMN_VALUE_WIDTH    = 55
  #PIEC_COLUMN_PERCENT_WIDTH  = 55
  
  Procedure.i DrawPie(*PieChart.PIEC_STRUCT,AngleStart.d,AngleEnd.d,Color.l)
    AngleStart - 90: AngleEnd - 90                                                                    ;Startposition für das Kuchenstück (oben)
    StrokePath(1):MovePathCursor(*PieChart\X,*PieChart\Y)                                             ;Strichdicke & Startposition der Zeichenoperationen festlegen
    VectorSourceColor(Color)                                                                          ;Zeichenfarbe
    VectorSourceCircularGradient(*PieChart\X,*PieChart\Y,*PieChart\Radius * 4.5)                      ;Zirkularen Gradient erstellen
    VectorSourceGradientColor(Color,0)                                                                ;Gradient Farbe 1
    VectorSourceGradientColor(-938208236,1)                                                           ;Gradient Farbe 2
    AddPathCircle(*PieChart\X,*PieChart\Y,*PieChart\Radius,AngleStart,AngleEnd, #PB_Path_Connected)   ;Kuchenstück zeichnen
    ClosePath():FillPath()                                                                            ;Zeichenoperation abschließen & Kuchenstück füllen
  EndProcedure
  
  Procedure.i DrawIco(*PieChartEntry.PIEC_ENTRY_STRUCT)
    If StartVectorDrawing(ImageVectorOutput(*PieChartEntry\Image))                                    ;Zeichne auf Bild X
      VectorSourceColor(-1):FillVectorOutput():StrokePath(1)                                          ;Hintergrund Zeichnen & Strichdicke einstellen
      VectorSourceColor(*PieChartEntry\Color):MovePathCursor(8,8)                                     ;Zeichenfarbe & Startposition für die Zeichnung festlegen
      VectorSourceCircularGradient(8,8,40)                                                            ;Zirkularen Gradient erstellen
      VectorSourceGradientColor(*PieChartEntry\Color,0)                                               ;Gradient Farbe 1
      VectorSourceGradientColor(-938208236,1)                                                         ;Gradient Farbe 2
      AddPathCircle(8,8,6):ClosePath():FillPath()                                                     ;Kreis zeichnen & Zeichenoperation abschließen & Kreis füllen
      StopVectorDrawing()                                                                             ;Zeichenoperation beenden            
      ProcedureReturn #True                                                                         ;Ergebnis (TRUE = alles in Ordnung)
    EndIf
  EndProcedure
  
  Procedure.i Draw(*PieChart.PIEC_STRUCT) 
    Protected *PieChartEntry.PIEC_ENTRY_STRUCT
    Protected Angle.d, Offset.d
    If *PieChart
      If *PieChart\FirstEntry
        *PieChartEntry = *PieChart\FirstEntry
        If StartVectorDrawing(ImageVectorOutput(*PieChart\Image))                                    ;Zeichenoperation beginnen 
          ClearGadgetItems(*PieChart\GadgetList)                                                     ;Liste leeren
          VectorSourceColor(-1)                                                                      ;Zeichenfarbe
          FillVectorOutput()                                                                         ;Hintergrund Zeichnen
          While *PieChartEntry
            If *PieChartEntry\Value > 0                                                              ;Nur etwas Zeichnen wenn der Wert > 0 ist!
              *PieChartEntry\Percent = (*PieChartEntry\Value / *PieChart\Summ) * 100                 ;Prozent berechnen
              *PieChartEntry\Deg = (*PieChartEntry\Value / *PieChart\Summ) * 360                     ;Grad berechnen
              If *PieChartEntry\Percent > 100
                *PieChartEntry\Percent = 100
              EndIf
              Offset = Angle + *PieChartEntry\Deg                                                    ;Offset berechnen
              DrawPie(*PieChart,Angle,Offset,*PieChartEntry\Color)                                   ;Kuchenstück zeichnen 
              Angle = Offset                                                                         ;Neuen Winkel setzen
            EndIf
            AddGadgetItem(*PieChart\GadgetList,-1,                                                   ;Eintrag zur Liste hinzufügen
                          Chr(10) + *PieChartEntry\Name  + 
                          Chr(10) + StrF(*PieChartEntry\Value,2) + 
                          Chr(10) + StrF(*PieChartEntry\Percent,2),
                          ImageID(*PieChartEntry\Image))
            *PieChartEntry = *PieChartEntry\NextEntry  
          Wend
          If *PieChart\Flag
            VectorSourceColor(-1)                                                                    ;Donut Variante zeichnen
            AddPathCircle(*PieChart\X,*PieChart\Y,*PieChart\Radius/3)                                
            ClosePath():FillPath()                                                    
          EndIf
          MovePathCursor(0,0)
          VectorSourceColor(-15461356)
          AddPathBox(0,0,ImageWidth(*PieChart\Image) + 1,ImageHeight(*PieChart\Image))               ;Rahmen zeichnen
          StrokePath(1)
          ClosePath()
          StopVectorDrawing()
          SetGadgetState(*PieChart\Gadget,ImageID(*PieChart\Image))
          ResizeGadget(*PieChart\Gadget,#PB_Ignore,#PB_Ignore,#PB_Ignore,#PB_Ignore)
          ProcedureReturn #True
        EndIf
      Else
        If StartVectorDrawing(ImageVectorOutput(*PieChart\Image))                                       ;Zeichenoperation beginnen (Bild Kuchenstück)
          VectorSourceColor(-1)                                                                         ;Zeichenfarbe
          FillVectorOutput()                                                                            ;Hintergrund zeichnen
          DrawPie(*PieChart,0,360,-1)                                                                   ;Kuchenstück (leer) zeichnen
          MovePathCursor(0,0)                                                                           ;Startposition für Zeichenoperation verschieben
          VectorSourceColor(-15461356)                                                                  ;Zeichenfarbe
          AddPathBox(0,0,ImageWidth(*PieChart\Image) + 1,ImageHeight(*PieChart\Image))                  ;Rahmen um das Kuchenstück zeichnen
          StrokePath(1)                                                                                 ;Strichdicke  
          ClosePath()                                                                                   ;Zeicheoperation abschließen
          If *PieChart\Flag
            VectorSourceColor(-1)                                                                    ;Donut Variante zeichnen
            AddPathCircle(*PieChart\X,*PieChart\Y,*PieChart\Radius/3)                                
            ClosePath():FillPath()                                                    
          EndIf  
          StopVectorDrawing()
          SetGadgetState(*PieChart\Gadget,ImageID(*PieChart\Image))
          ResizeGadget(*PieChart\Gadget,#PB_Ignore,#PB_Ignore,#PB_Ignore,#PB_Ignore)
          ProcedureReturn #True  
        EndIf
      EndIf 
    EndIf
  EndProcedure
  
  Procedure.i Create(X.i,Y.i,Name.s,Radius.d,Flag.b)
    Protected *PieChart.PIEC_STRUCT
    Radius - #PIEC_FACTOR                                                                                   ;Zeichengröße errechnen (Radius - Platzfaktor zum Rand)
    Radius * 2                                                                                              ;Radius = Durchmesser
    If Radius < #PIEC_MIN_RADIUS                                                                            ;Ist der Radius (Durchmesser) groß genug?
      Radius = #PIEC_MIN_RADIUS                                                                             ;Mimimalgröße setzen
    EndIf 
    Width = Radius + #PIEC_FACTOR                                                                           ;Bildgröße festlegen
    Height = Width                                                                                          ;Höhe = Breite (nur da um eventuelle Änderungen zu vereinfachen) 
    *PieChart = AllocateMemory(SizeOf(PIEC_STRUCT))                                                         ;Speicher reservieren
    If *PieChart
      *PieChart\Flag = Flag                                                                                 ;Parameter in den Speicher übertragen
      *PieChart\Radius = Radius / 2
      *PieChart\X = *PieChart\Radius + #PIEC_FACTOR / 2
      *PieChart\Y = *PieChart\X
      *PieChart\Image = CreateImage(#PB_Any,Width,Height)                                                   ;Bild erstellen
      If *PieChart\Image    
        *PieChart\Gadget = ImageGadget(#PB_Any,X,Y,Width,Height,0)                                          ;Bild Container erstellen
        If *PieChart\Gadget
          *PieChart\GadgetList = ListIconGadget(#PB_Any,X + Width,Y,#PIEC_LIST_WIDTH,Height,#Null$,25)      ;Liste erstellen
          If *PieChart\GadgetList
            AddGadgetColumn(*PieChart\GadgetList,1,Name,#PIEC_COLUMN_NAME_WIDTH)
            AddGadgetColumn(*PieChart\GadgetList,2,#PIEC_COLUMN_VALUE,#PIEC_COLUMN_VALUE_WIDTH)
            AddGadgetColumn(*PieChart\GadgetList,3,#PIEC_COLUMN_PERCENT,#PIEC_COLUMN_PERCENT_WIDTH)
            If Draw(*PieChart)
              ProcedureReturn *PieChart                                                                   ;Erstellte Struktur zurückgeben
            EndIf
          EndIf
          FreeGadget(*PieChart\Gadget)                                                                      ;Alle Resourcen freigeben
        EndIf 
        FreeImage(*PieChart\Image)
      EndIf 
      FreeMemory(*PieChart)
    EndIf 
  EndProcedure
  
  Procedure.i Add(*PieChart.PIEC_STRUCT,Name.s,Value.d,Color.l)
    Protected *PieChartEntryOld.PIEC_ENTRY_STRUCT
    Protected *PieChartEntry.PIEC_ENTRY_STRUCT
    If *PieChart And Not Value < 0                                                                         ;Wert darf nicht kleiner sein als 0!
      If *PieChart\FirstEntry                                                                              ;Ist schon ein Eintrag vorhanden?     
        *PieChartEntry = *PieChart\FirstEntry
        While *PieChartEntry                                                                               ;Durch die (verknüpfte) Liste gehen um einen freien Platz zu finden
          If Not *PieChartEntry\NextEntry
            *PieChartEntryOld = *PieChartEntry
            *PieChartEntry\NextEntry = AllocateMemory(SizeOf(PIEC_ENTRY_STRUCT))                            ;Speicher für einen neuen Eintrag reservieren
            If *PieChartEntry\NextEntry
              *PieChartEntry = *PieChartEntry\NextEntry                                                     ;Parameter in den Speicher übertragen                           
              *PieChartEntry\Name = Name
              *PieChartEntry\Value = Value
              *PieChartEntry\Color = Color
              *PieChartEntry\Image = CreateImage(#PB_Any,16,16,24)                                        ;Bild (Icon) erstellen
              If *PieChartEntry\Image
                If DrawIco(*PieChartEntry)                                                                ;Icon Zeichnen
                  *PieChart\Summ + *PieChartEntry\Value
                  If Draw(*PieChart) = #True
                    ProcedureReturn #True
                  Else
                    *PieChart\Summ - *PieChartEntry\Value
                  EndIf
                EndIf
                FreeImage(*PieChartEntry\Image)
              EndIf
              FreeMemory(*PieChartEntry)
              *PieChartEntryOld\NextEntry = #Null
              ProcedureReturn #False
            EndIf
          EndIf
          *PieChartEntry = *PieChartEntry\NextEntry
        Wend  
      Else
        *PieChart\FirstEntry = AllocateMemory(SizeOf(PIEC_ENTRY_STRUCT))          ;Ersten Eintrag erstellen
        If *PieChart\FirstEntry
          *PieChart\FirstEntry\Name = Name                                        ;Parameter in den Speicher übertragen
          *PieChart\FirstEntry\Value = Value
          *PieChart\FirstEntry\Color = Color
          *PieChart\FirstEntry\Image = CreateImage(#PB_Any,16,16)
          If *PieChart\FirstEntry\Image
            If DrawIco(*PieChart\FirstEntry)  
              If Draw(*PieChart)
                *PieChart\Summ = Value
                ProcedureReturn #True
              Else
                *PieChart\Summ = #Null
              EndIf
            EndIf
            FreeImage(*PieChart\FirstEntry\Image)
          EndIf 
          FreeMemory(*PieChart\FirstEntry)
          *PieChart\FirstEntry = #Null
          ProcedureReturn #False
        EndIf 
      EndIf
    EndIf 
  EndProcedure
  
  Procedure.i Remove(*PieChart.PIEC_STRUCT,Name.s)
    Protected *PieChartEntryOld.PIEC_ENTRY_STRUCT
    Protected *PieChartEntry.PIEC_ENTRY_STRUCT
    If *PieChart
      If *PieChart\FirstEntry
        *PieChartEntry = *PieChart\FirstEntry
        While *PieChartEntry                                            ;Durch die (verknüpfte) Liste gehen um den Eintrag zu finden
          If *PieChartEntry\Name = Name                           
            If *PieChartEntry = *PieChart\FirstEntry
              *PieChart\FirstEntry = *PieChartEntry\NextEntry
            Else
              *PieChartEntryOld\NextEntry = *PieChartEntry\NextEntry    ;Eintrag aus der Liste entfernen
            EndIf
            *PieChart\Summ - *PieChartEntry\Value                       ;Summe korrigieren
            If *PieChartEntry\Image
              FreeImage(*PieChartEntry\Image)                           ;Resourcen freigeben
            EndIf 
            FreeMemory(*PieChartEntry)
            Draw(*PieChart)
            ProcedureReturn #True
          EndIf
          *PieChartEntryOld = *PieChartEntry
          *PieChartEntry = *PieChartEntry\NextEntry  
        Wend
      EndIf
    EndIf 
  EndProcedure
  
  Procedure.i Update(*PieChart.PIEC_STRUCT,Name.s,Value.d)              ;Eintrag ändern
    Protected *PieChartEntry.PIEC_ENTRY_STRUCT
    Protected Buffer.i
    If *PieChart And Not Value < 0
      If *PieChart\FirstEntry
        *PieChartEntry = *PieChart\FirstEntry
        While *PieChartEntry 
          If *PieChartEntry\Name = Name
            *PieChart\Summ - *PieChartEntry\Value
            *PieChartEntry\Value = Value
            *PieChart\Summ + Value
            Draw(*PieChart)
            ProcedureReturn #True
          EndIf 
          *PieChartEntry = *PieChartEntry\NextEntry
        Wend
      EndIf
    EndIf
  EndProcedure
  
  Procedure.i Free(*PieChart.PIEC_STRUCT)                             ;Alle Resourcen freigeben
    Protected *PieChartEntry.PIEC_ENTRY_STRUCT
    Protected Buffer.i
    If *PieChart
      If *PieChart\FirstEntry
        *PieChartEntry = *PieChart\FirstEntry
        While *PieChartEntry 
          If *PieChartEntry\Image
            FreeImage(*PieChartEntry\Image)
          EndIf
          Buffer = *PieChartEntry
          *PieChartEntry = *PieChartEntry\NextEntry
          FreeMemory(Buffer)
        Wend
        If IsGadget(*PieChart\Gadget)
          FreeGadget(*PieChart\Gadget)
        EndIf 
        If IsGadget(*PieChart\GadgetList)
          FreeGadget(*PieChart\GadgetList)
        EndIf 
        If *PieChart\Image
          FreeImage(*PieChart\Image)
        EndIf 
        FreeMemory(*PieChart)
      EndIf
    EndIf 
  EndProcedure

EndModule
Beispiel:

Code: Alles auswählen

If OpenWindow(0,0,0,510,180,"MODULE PieChart PIEC",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  ButtonGadget(1,400,140,100,25,"Change Entry 3")
  PieChart = PIEC::Create(10,10,"Test PieChart!",70,#True)
  PIEC::Add(PieChart,"1 Sample Entry",60,RGBA(255,0,0,170))
  PIEC::Add(PieChart,"2 Sample Entry",30,RGBA(255,255,0,170))
  PIEC::Add(PieChart,"3 Sample Entry",50,RGBA(0,50,255,170))
  PIEC::Add(PieChart,"4 Sample Entry",0,RGBA(0,444,5,170))
  PIEC::Add(PieChart,"5 Sample Entry",20,RGBA(0,12,5,170))
  PIEC::Remove(PieChart,"5 Sample Entry")
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_CloseWindow
        Break
      Case #PB_Event_Gadget
      PIEC::Update(PieChart,"3 Sample Entry",Random(50,10))
    EndSelect
  ForEver
  PIEC::Free(PieChart)
EndIf
Zuletzt geändert von Mijikai am 18.08.2017 17:26, insgesamt 12-mal geändert.
Benutzeravatar
Kukulkan
Beiträge: 1066
Registriert: 09.09.2004 07:07
Wohnort: Süddeutschland
Kontaktdaten:

Re: MODULE PieChart PIEC

Beitrag von Kukulkan »

Hallo Mijikai,

guter Code, danke!

Ich hab so was ähnliches vor einiger Zeit auch gemacht. Allerdings Cross-Platform:
http://www.purebasic.fr/english/viewtop ... 12&t=65572

Es bietet Anti-Alias, Transparenz zum Hintergrund und einen optionalen inneren Radius (Ring-Style). Evtl. magst Du mal reingucken? Du könntest den Anti-Alias übernehmen (groß malen und dann klein skalieren).
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: MODULE PieChart PIEC

Beitrag von Mijikai »

Update:
Hab die Zeichenfunktionen neu geschrieben und den Code weiter verbessert.

@Kukulkan die Donut-Variante ist jetzt mit an Bord.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: MODULE PieChart PIEC [ALL OS!]

Beitrag von Mijikai »

Update v.1.00 :)
Hab den Code weiter verbessert, es werden nun alle OS unterstützt.
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: MODULE PieChart PIEC [ALL OS!]

Beitrag von RSBasic »

:allright:
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Re: MODULE PieChart PIEC [ALL OS!]

Beitrag von hjbremer »

:allright: sieht sehr gut aus und vor allem nicht allzu schwierig. Vielleicht noch mit ein paar Erklärungen,
damit man es auch noch Jahre später versteht. Den Fehler mit mangelnder Info mache ich auch viel zu oft.

Vielleicht als nächstes Projekt ein Balkendiagramm, auch schön mit Vectordrawing, damit ich was zum Lernen habe.

hatte vor vielen Jahren mal eins gepostet und es sah schrecklich aus, da gab es noch kein Vectordrawing.
und mein jetziges ist zwar schön, aber so kompliziert, weil ohne Vectordrawing, das ich den Code selbst nicht mehr verstehe.
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
Andre
PureBasic Team
Beiträge: 1754
Registriert: 11.09.2004 16:35
Computerausstattung: MacBook Core2Duo mit MacOS 10.6.8
Lenovo Y50 i7 mit Windows 10
Wohnort: Saxony / Deutscheinsiedel
Kontaktdaten:

Re: MODULE PieChart PIEC [ALL OS!]

Beitrag von Andre »

Sehr schön :allright:

@hjbremer: Für weitere Diagramme, u.a. Balken-Diagramme, mittels VectorDrawing siehe auch hier: http://www.purebasic.fr/english/viewtop ... tor+rashad
Bye,
...André
(PureBasicTeam::Docs - PureArea.net | Bestellen:: PureBasic | PureVisionXP)
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: MODULE PieChart PIEC [ALL OS!]

Beitrag von Mijikai »

Danke für das positive Feedback :)
Hab den Code nun teilweise kommentiert.
Antworten