vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
sevAniGif - als kostenlose Vollversion auf unserer vb@rchiv CD Vol.5  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück
Rubrik: Controls   |   VB-Versionen: VB2008, VB201028.02.13
MSChart-WinForms Animation

Dieser Tipp zeigt einen ersten Ansatz für die Animation von Charts in WindowsForms.

Autor:   Dietrich HerrmannBewertung:     [ Jetzt bewerten ]Views:  8.516 
ohne HomepageSystem:  WinXP, Win7, Win8, Win10, Win11kein Beispielprojekt 

Am Markt gibt es einige Pakete für die Datenvisualisierung mittels Diagrammen, die auch gewisse Animationen gestatten. Uns ist das Paket Microsoft Charts für WindowsForms und Web kostenlos gegeben. Und für WindowsForms-Lösungen habe ich die im folgenden beschriebenen Funktionen zur Animation von Datapoints mit "Bordmitteln" entwickelt.

Es ist als ein erster Ansatz zu sehen, der mit etwas Fantasie eingesetzt und möglicherweise noch weiter entwickelt werden kann.
Die Lösung geht prinzipiell davon aus, dass ein bis mehrere Datenserien gezeigt werden sollen, die allerdings alle von nur einer XValues-Menge ausgehen. Dann werden die YValues individuell in Schrittweiten eingeteilt, die auf dem Maximalwert der Serie beruhen.

Die gezeigte Prozedur benötigt folgende Prämissen:
XValues und YValues müssen jeweils in einem Array zur Verfügung gestellt werden. Stellt man die Werte mittels Datenbank eventuell über Dataview bereit, zeige ich im Beispiel, wie man die Werte einfach in Arrays kopiert.

Für die YValues benötigt man zwei Arrays, eines mit den Endwerten und eines mit der gleichen Anzahl Null-Werten. Die Animation ist dann so gelöst, dass im Null-Werte-Array für jeden XPoint die Schrittweite addiert wird, bis der zugehörige Endwert erreicht wird. Aus dem XValue-Array und dem berechneten YValue-Array wird die neue Serie mitteles DataBindXY gebundenund die Chart upgedatet. Nach dem Update wird eine Minimalpause eingelegt. Dieser Prozess wird so lange ausgeführt, bis alle DataPoints die YValue-Endwerte erreicht haben.

Die Prozedur stellt verschiedene Möglichkeiten der Animation zur Verfügung, was aus den Parameterangaben ersichtlich ist.

Hier erst mal die Prozedur:

''' <summary>
'''   Animation von Charts
''' </summary>
''' <param name="theChart">die Chart</param>
''' <param name="theSerie">die zu animierende Serie</param>
''' <param name="anzXValues">die Anzahl der XValues</param>
''' <param name="theSteps">die Schrittweite der YValues bei der Animation</param>
''' <param name="xvField">das Feld mit den XValues</param>
''' <param name="yvField">das Feld mit den YValues</param>
''' <param name="pSec">die Zeitspanne für die Pause während der Animation</param>
''' <param name="animArt">die Animationsart (0..einzelnes oder 1..gleichzeitiges Wachsen</param>
''' <param name="direction">die Richtung der Animation (0..von links, 1..von rechts</param>
''' <param name="clearing">sollen die Serienpunkte gelöscht werden, ja|nein</param>
Public Sub AnimateCharts(theChart As Chart, theSerie As Object, anzXValues As Short, theSteps As Object, _
  xvField As Object, yvField As Object, _
  pSec As Single, Optional animArt As Short = 0, _
  Optional direction As Short = 0, _
  Optional clearing As Boolean = False)
 
  Dim w As Boolean
  Dim anfang, ende, schritt As Short
  anfang = 0 : schritt = 1 : ende = anzXValues - 1
  If direction = 1 Then  ' Animation von rechts
   anfang = anzXValues - 1 : ende = 0 : schritt = -1
  End If
 
  ' ein Feld für alle Datapoint-Values = 0
  Dim iniField(anzXValues - 1) As Object
  iniField.Initialize()
 
  ' ein Feld für die XValues, ein Feld für die YValues
  Dim xField(anzXValues - 1), yField(anzXValues - 1) As Object
 
  ' die Felder mit Daten aus Dataview füllen
  For j As Short = 0 To anzXValues - 1
    xField(j) = xvField(j)
    yField(j) = yvField(j)
  Next 
 
  With theChart
    If clearing Then
      ' Series.Points löschen
      .Series(theSerie).Points.Clear()
 
      ' Series.Points mit den aktuellen Xvalues und den YValues=0 verbinden
      .Series(theSerie).Points.DataBindXY(xField, iniField)
 
      ' Chart updaten
      .Update()
    End If
 
    ' Animation gemäß gewünschter Art
    Select Case animArt
      Case 0
        ' die Animation ausführen für alle XValues
        ' Art: einen Datapoint nach dem anderen gemäß der XValues-Reihenfolge animieren
        ' (einzelnes Wachsen)
        For i As Short = anfang To ende Step schritt
          Do
            iniField(i) += theSteps  ' Wert aus dem Null-YValues-Feld um Schrittweite erhöhen
            If theSteps < 0 Then
              w = (iniField(i) + theSteps <= yField(i))
            Else
              w = (iniField(i) + theSteps >= yField(i))
            End If
 
            ' Abfrage, ob aktueller YValue den endgültigen YValue erreicht hat
            If w Then iniField(i) = yField(i) ' den Null-YValue auf den endgültigen Wert setzen
 
            ' Series.Points nun mit Null-YValue-Feld verbinden
            .Series(theSerie).Points.DataBindXY(xField, iniField)
 
            ' Chart updaten
            .Update()
 
            ' Pause einlegen bis zur nächsten Wertberechnung
            Delay(pSec)
            If w Then Exit Do ' Schleife verlassen
          Loop
        Next
 
      Case 1
        ' die Animation ausführen für alle XValues
        ' Art: alle Datapoints gleichzeitig animieren, bei 0 beginnend bis zum jeweiligen Endpunkt
        ' (gleichzeitiges Wachsen)
        Dim dmax(yField.Length - 1) As Short  ' Feld für Registrieren, ob Endpunkte erreicht
        dmax.Initialize()
        ' Schleife für die Animation
        Do
          For i As Short = anfang To ende Step schritt
            If dmax(i) = 0 Then iniField(i) += theSteps
            If theSteps < 0 Then
              w = (iniField(i) <= yField(i))
            Else
              w = (iniField(i) >= yField(i))
            End If
            If w Then
              dmax(i) += 1
            Else
              dmax(i) = 0
            End If
          Next 
          .Series(theSerie).Points.DataBindXY(xField, iniField)
          .Update()
          Delay(pSec)
 
          ' sind alle Endpunkte erreicht?
          Dim x As Boolean = Array.TrueForAll(dmax, AddressOf NoZeroValues)
          If x Then Exit Do ' alle Endpunkte erreicht
        Loop
    End Select
  End With
End Sub

Und gleich noch die benötigten Hilfsfunktionen:

1. Delay für das Erzeugen einer "Pseudo-Pause"

' eine Pause erzeugen
Public Function Delay(ByVal seconds As Single) As Single
  Dim StartTime As DateTime = DateTime.Now
  Do
    ' Nichts tun.
  Loop While DateTime.Now.Subtract(StartTime).TotalSeconds < seconds
  Return seconds
End Function

2. NoZeroValues als Predicate(Of T) für die Array-Funktion Array.TrueForAll

Private Function NoZeroValues(v As Short) As Boolean
  Return (v > 0)
End Function

3. MaxMinOfArray zum Ermitten des Maximums|Minimums der Werte eines Array

''' <summary>
''' Ermitteln von Maximum/Minimum der Werte eines Feldes
''' </summary>
''' <param name="theArray">das zu durchsuchende Feld</param>
''' <param name="flag">True für Maximum, False für Minimum</param>
''' <returns>den Wert (max oder min)</returns>
Public Function MaxMinOfArray(ByVal theArray As Array, _
  Optional ByVal flag As Boolean = True) As Object
 
  Dim max = theArray(0)
  For i As Integer = 0 To theArray.Length - 1
    If flag Then
      If theArray(i) > max Then
        max = theArray(i)  ' Maximum
      End If
    Else
      If theArray(i) < max Then
        max = theArray(i)  ' Minimum
      End If
    End If
  Next i
  Return max
End Function

Anwendung der Prozedur:
Die Chart sollte schon "fertig definiert" sein, entweder im Designer oder programmatisch. Also Erscheinungsbild, Achsen, Serien usw.
Dann ruft man die Animationsprozedur folgendermaßen auf: man definiert zunächst die Zeit für die Animationspause, im Beispiel delSec. Durch Ausprobieren kann man den Wert austesten, aber ich verwende jetzt 0.02, was noch eine einigermaßen "flüssige" Animation erlaubt.

Dim delSec As Single = 0.02

Mein Beispiel hier geht von zwei Serien aus, die dargestellt werden sollen und zeige gleichzeitig, wie man die benötigten Felder aus DataViews erstellt.

Dim xdv1(dv1.Count - 1), ydv1(dv1.Count - 1), ydv2(dv2.Count - 1) As Object
For j As Short = 0 To dv1.Count - 1
  xdv1(j) = dv1.Item(j)("Jahr")
  ydv1(j) = dv1.Item(j)("Betrag")
  ydv2(j) = dv2.Item(j)("Stunden")
Next 

Dabei sind

  • dv1: die XValues aus dem Dataview dv1 (bspw. enthält dv1 die Zeilen mit den Inhalten Jahr und Betrag)
  • dv2: die YValues aus dem Dataview dv2 (bspw. enthält dv2 die Zeilen mit den Inhalten Jahr und Stunden)

und es werden die Felder erstellt

  • xdv1 enthält die XValues für die Serien
  • ydv1... enthält die YValues für die Serie "Umsatz"
  • ydv2... enthält die YValues für die Serie "Stunden"

Für jede Serie ermittle ich eine passende Schrittweite.
In meinem Falle:

Dim stp1 As Single = MaxMinOfArray(ydv1) * delSec
Dim stp2 As Single = MaxMinOfArray(ydv2) * delSec

Und definiere zwei Felder für die anfänglichen Null-YValues je Serie:

Dim in1(dv1.Count - 1) As Single
Dim in2(dv2.Count - 1) As Short

Jetzt erfolgt der Aufruf der Prozedur:

AnimateCharts(Chart1, "Umsatz", dv1.Count, MaxMinOfArray(ydv1) * delSec, _
  xdv1, ydv1, delSec, , CShort(Rnd()))
AnimateCharts(Chart1, "Stunden", dv2.Count, CShort(MaxMinOfArray(ydv2) * delSec), _
  xdv1, ydv2, delSec, , CShort(Rnd()))

CShort(Rnd()) setze ich hier ein für eine zufällige Animationsart ein...

Wie löst man die Animation aus?
Ein richtiges Chart-Ereignis habe ich dafür nicht gefunden. Man muss eventuell den Trick anwenden:
Einen Button definieren, diesen außer Sicht lokalisieren, den Animationsstart ins Click-Ereignis dieses Buttons legen und dann mit Performclick auslösen.
Ich habe beispielsweise Charts auf Seiten eines TabControls und löse die Animation bei Wechsel der Seite (TabControl.SelectedIndexChanged) aus.

Nun wünsche ich Spaß beim Experimentieren und Ausprobieren!

Dieser Tipp wurde bereits 8.516 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel