Zeitleiste Grafisch darstellen Vb.net

werner_sg

Erfahrenes Mitglied
Hallo habe mal etwas wo ich nicht mal Ansatzweise was zu gefunden habe.

ich habe in meiner Access Tabelle jeweils einen Anfangs und einen Endzeitpunkt das ganze würde ich gerne grafisch darstellen also in einer art Linien Diagramm

Jede Zeile verfügt wie gesagt über Start und Endzeitpunkt sowie das Fahrzeug

für jedes Fahrzeug sollte eine Zeitreihe mit den Daten entstehen, ich hänge mal ein Bild drann zum besseren Verständnis.

für jeden Wink mit dem Zaunpfahl wäre ich dankbar
 

Anhänge

  • beispiel.jpg
    beispiel.jpg
    15,4 KB · Aufrufe: 5
PicureBox und Paint Ereignis abonnieren und dort mit dem Graphics Objekt aus dem EventArgs zeichnen.
Die Breite deiner PictureBox wären 100% anhand derer du die zeiteinteilung des Fahrzeugs berechnen/zeichnen könntest
 
Ich hatte auch eventuell überlegt eine reihe von buttons oder ähnliches anzulegen und diese dann je nach ergebnis der sql abfrage umzufärben.

ich bräuchte dann aber x Reihen die sich erst aus der Abfrage ergeben

Das ganze dann in einem Panel mit Scrollbalken

Zu deiner Variante bin ich aber auch gerade am Infos sammeln ;-)
 
Das mit PictureBox/Paint-Ereignis ist eigentlich der einfachere Teil.
Das schwierige wird dann eher die Mathematik dahinter sein.
Die PictureBox dürfte eine fixe Breite haben,
linker Rand = "Von"-Datum
rechter Rand = "Bis"-Datum
Falls der Zeitraum variabel ist (Falls das mit deinem Datenbank-Thread zu tun hat), musst du dann erst Tage auf Twips/Pixel/WasAuchImmer umrechnen, und dann mit diesen Einheiten weiterrechnen.

Ich hatte mal in FreePascal/Lazarus so was ähnliches gemacht, aber da gings um die Zeitleiste eines Videos, in welcher man einen Cut-In und einen Cut-Out definieren konnte.
Das grafische Zeug war einfach, aber das Umrechnen der Position(en) war ein Alptraum
 
Was mir am meisten Gedanken macht ist die horizontale Anordnung.

Die Daten filtern und zuordnen wird der einfachste Punkt.

Einfach eine Liste pro Fahrzeugnummer mit allen start und endpunkten, ein Fahrzeug Kann ja im Monat oder Jahr mehrere haben.

Das dann aber horizontal grafisch darstellen
 
Das ist ja das was ich meine.

Stell dir vor, die PictureBox is 10.000 breit (in welcher Einheit auch immer)
und der Zeitraum den du auswertest ist 100 Tage (beginnend am 01.07.2021)
Ergo entsprechen 100 PictureBox-Einheiten (PB-Einheiten) einem Tag deines Zeitraums
Bedeutet, wenn für Fahrzeug BMW320 du eine Reservierung am 03.07.2021 für einen Tag hast, wäre
die linke Position des Farbbalkens 200 PB-Einheiten, die rechte Position bei 300 PB-Einheiten
usw.
 
Aufjedenfall keine Buttons oder anderweitige Controls zu hauf auf ein Formular packen.
Dies wird die Performance deines Fenster runterziehen und das Problem mit dem ausrechnen der Zeitlinie würde dir so und so nicht erspart bleiben.

Sie die Zeiten einfach als fixe Punkte.
z.B. deine PictureBox ist 200 Pixel breit das wären unser 100% horizontaler Zeichnugnsbereich

Auto A fährt von 08 bis 12 Uhr und wieder von 17 bis 18 Uhr.
Wenn wir von ausgehen das ein Tag nur 24 Stunden hat wären dies unsere 100% eines Tages welches wir nur in die einzelnen abschnitte aufteilen müssen.

Ganz einfach könntest du dir es hier mit TimeSpan machen wenn wir einfach die Eigenschaft Ticks zur Hilfe nehmen.
C#:
            TimeSpan tagGesamt = new TimeSpan(23, 59, 59); //usnere 24 Stunden, die 100%

            TimeSpan fahrt1Beginn = new TimeSpan(8, 0, 0);
            TimeSpan fahrt1Ende = new TimeSpan(12, 0, 0);

            decimal tag1BeginnProzent = (fahrt1Beginn.Ticks / (decimal)tagGesamt.Ticks); //wichtig ein Wert nach decimal casten sosnt bekommen wir keine nachkommastellen
            decimal tag1EndeProzent = (fahrt1Ende.Ticks / (decimal)tagGesamt.Ticks);

            TimeSpan fahrt2Beginn = new TimeSpan(17, 0, 0);
            TimeSpan fahrt2Ende = new TimeSpan(18, 0, 0);

            decimal tag2BeginnProzent = (fahrt2Beginn.Ticks / (decimal)tagGesamt.Ticks);
            decimal tag2EndeProzent = (fahrt2Ende.Ticks / (decimal)tagGesamt.Ticks);

            int bildBreite = 200;

            //die Prozente umrechnen auf unser Bild
            Rectangle recFahrt1 = new Rectangle((int)(tag1BeginnProzent * bildBreite), 0, (int)((tag1EndeProzent * bildBreite) - (tag1BeginnProzent * bildBreite)), 10);
            Rectangle recFahrt2 = new Rectangle((int)(tag2BeginnProzent * bildBreite), 0, (int)((tag2EndeProzent * bildBreite) - (tag2BeginnProzent * bildBreite)), 10);


Nachtrag:
Alternativ vom DateTime die Ticks Eigenschaft verwenden wenn Zeitleiste in Verbindung auch mit Datumsangaben.
Dann sollteste aber ein Maximales Endedatum für die Zeitliste definieren, z.B. nur immer eine Woche im Voraus oder so.
 
Aufjedenfall keine Buttons oder anderweitige Controls zu hauf auf ein Formular packen.
Dies wird die Performance deines Fenster runterziehen und das Problem mit dem ausrechnen der Zeitlinie würde dir so und so nicht erspart bleiben.
So weiter im Text :giggle: hatte erst mal alles andere vorgezogen und fertiggestellt-

habe das soweit verstanden, und mir zusätzlich noch einigen Quellen dazu durchgeschaut.

Knackpunkt:

es bestehen eventuell mehrere Reihen in der Datenbank für ein Fahrzeug

z.B. Zeile 17 Fahrzeug 1 vom 12.8.2021 bis 23.8.2021 ebenso Zeile 43 vom 31.8.2021 bis 12.09.2021 und auch noch Zeile 51 vom 15.09.2021 bis 30.09.2021

hier gillt es in diesem Fall ja auch erst mal jede Zeile oder Row zu prüfen und dann in einer Datatable oder in einem Datagrid alles zusammen in einer Zeile darzustellen

Der TimeSpan Gesamt wäre in meinem Fall / TimeSpan MonatGesamt = new TimeSpan(31)

Den folgenden Block benötige ich sicherlich nicht oder?

Code:
    decimal tag1BeginnProzent = (fahrt1Beginn.Ticks / (decimal)tagGesamt.Ticks); //wichtig ein Wert nach decimal casten sosnt bekommen wir keine nachkommastellen
            decimal tag1EndeProzent = (fahrt1Ende.Ticks / (decimal)tagGesamt.Ticks);
weil ich ja keine Kommazahlen haben werde

int bildBreite = 200; würde ich auf 620 setzen dann habe ich für jeden tag dann 20

das eingemachte

Code:
Rectangle recFahrt1 = new Rectangle((int)(fahrt1Beginn * bildBreite), 0, (int)((fahrt1EndeProzent * bildBreite) - (fahrt1Beginn * bildBreite)), 10);

hier müsste ja eigentlich ein Grundgerüst hin, welches sich per Bedarf erweitert

Prüfe ob Farzeug 1 mehrfach vorhanden ist (wenn eine vorsortierung und abbildung nebeneinander im datagrid oder Datatable nicht so einfach möglich)
wenn ja dann für jede Zeile das Bild berechnen
wenn nein nur den einzelnen Antrag anzeigen

Dann zur nächsten vorhanden Fahrzeug Nummer springen und das ganze wiederholen

Die Möglichkeit vorher zu wissen oder festzulegen wieviele Reihen man braucht gibt es nicht es werden immer X Fahrzeuge und X einträge pro Fahrzeug im Monat sein

Werde heute mal dafür zum spielen und testen eine Extra Form dafür erstellen

in das Programm werde ich an diese Stelle solange mal die Excel Datei einbinden und darstellen lassen in der das bisher per Hand gepflegt wird.

Freue mich über hilfreiche und anregende Infos und Beiträge
 
Würde erst mal per SQL Min- und Max-Datum pro Fahrzeug ziehen, und aus diesem Ergebnis noch einmal Min- und Max-Datum ziehen (nicht pro Fahrzeug), Es sei dann du gibst die Grenzen "manuell" an

Fahrzeug 1: 01.08.2021 bis 31.08.2021
Fahrzeug 2: 15.08.2021 bis 10.09.2021
Fahrzeug 1: 15.09.2021 bis 30.09.2021
Fahrzeug 2: 20.09.2021 bis 16.10.2021

Erste Abfrage:
Fahrzeug 1: Min=01.08.2021 - Max=30.09.2021
Fahrzeug 2: Min=15.08.2021 - Max=16.10.2021

Zweite Abfrage
Min=01.08.2021 - Max=16.10.2021

Mit der zweiten Abfrage erhälst du dann den "notwendigen" Platz den du brauchst um ihn im Bild darzustellen. Der Rest ist dann nur Skalierung.

Prinzipiell würde ich immer versuchen, so viel wie möglich direkt aus der Datenbank zu holen (im Beispiel die Gruppierung pro Fahrzeug), und so wenig wie möglich "Nachbereitung" im Frontend

EDIT: Je länger ich mir das anschaue, desto mehr denke ich dass du sowas wie ein Pivot brauchst, und da wirds dann 3-Dimensional
Auf Anhieb wüsste ich jetzt zwei Varianten:
Abfrage auf die Fahrzeug-Haupt-Tabelle (Wo ein Fahrzeug hoffentlich UNIQUE ist) mit nem LEFT JOIN auf die Reservierungs-Tabelle inkl. COUNT
Beispiel Fahrzeug 1 und Fahrzeug 3 haben Reservierungen für den betrachteten Zeitraum, Fahrzeug 2 hat keine.
Ergebnis
Fahrzeug 1 - 4
Fahrzeug 2 - 0
Fahrzeug 3 - 2
Somit wüsstest du schon mal wieviele grafische Balken du pro Fahrzeug brauchst.
In einem zweiten Durchlauf holst du pro Fahrzeug (WHERE Fahrzeug=BMW320) die Reservierungsdaten DatumVon, DatumBis (WHERE (DatumVon BETWEEN UntereGrenze AND ObereGrenze) OR (DatumBis BETWEEN UntereGrenze AND ObereGrenze), sortiert nach EINEM der beide Daten (Ein Overlap kann ja theoretisch nicht stattfinden für ein und dasselbe Fahrzeug)

Die zweite Variante wäre ähnlich, jedoch alles schon fix und fertig per SQL holen.
Setzt jedoch voraus, dass die Datenbank (Access?) so etwas wie eine String-Aggregate-Funktion anbietet (was ich im Falle von Access bezweifel). Hier würde man sich den zweiten SQL-Durchlauf sparen können, da die Termine in einem String zurückgegeben werden, welchen man nur splitten müsste, und daraus resultierenden die Farbbalken anordnen/zeichnen.

Ich hoffe ich war verständlich
 
Zuletzt bearbeitet:
Bei mir bräuchtest du die Nachkommastellen da ich dort Prozentual die Zeitleiste errechnet, wodurch dein Bild selbst eine X-beliebige Breite haben kann, die Aufteilung in der Zeitleiste erfolgt prozentual.

Da du mit Datumsangaben arbeitest und du glaube schonmal probleme mit TimeSpan hattest könnteste anstelle der TimeSpan Ticks auch einfach dein Datum als Zahl wandeln.
(Bei Datumsangaben passt TimeSpan eh auch nicht mehr)

z.B. der 10.09.2021 könntest du als Zahl 20210910 (JahrMonatTag) halten
errechnen könnte so aussehen
Code:
(((Year(meinDatum) * 10000) + Monath(meinDatum)) * 100) + Day(meinDatum)

Pseudocode mäßig könnte das ganze so aussehen
Code:
//minimum/kleinste Datum über alle Fahrzeuge, wandeln wir in eine Zahl
zeitleisteMin = (((Year(minimumDatum) * 10000) + Month(minimumDatum)) * 100) + Day(minimumDatum)

//maximum/höchste Datum über alle Fahrzeuge, wandeln wir in eine Zahl
zeitleisteMax = (((Year(maximumDatum) * 10000) + Month(maximumDatum)) * 100) + Day(maximumDatum)

//Minum abziehen damit wir unsere 100% zeitleiste haben (Achtung, unten wird auch Minimum immer abgezogen)
zeitleisteMaxBereich = zeitleisteMax - zeitleisteMin + 1

bildBreite = X

Liste FahrzeugeMitZeiten;
durchlaufe FahrzeugeMitZeiten (fahrzeug 1 bis N)
{
    fahrzeugNr = fahrzeug.Nummer
    fahrzeugBeginn = (((Year(fahrzeug.fahrt.beginn) * 10000) + Month(fahrzeug.fahrt.beginn)) * 100) + Day(fahrzeug.fahrt.beginn)
    fahrzeugEnde =(((Year(fahrzeug.fahrt.ende) * 10000) + Month(fahrzeug.fahrt.ende)) * 100) + Day(fahrzeug.fahrt.ende)
 
    prozentualBeginn = ((fahrzeugBeginn - zeitleisteMin) / zeitleisteMaxBereich);
    prozentualEnde = ((fahrzeugEnde - zeitleisteMin) / zeitleisteMaxBereich);
 
    Rechteck rec = neues Rechteck
    rec.Left = (prozentualBeginn * bildBreite)
    rec.Top = fahrzeugNr * 10
    rec.Width = ((prozentualEnde * bildBreite) - (prozentualBeginn * bildBreite))
    rec.Height = 10
 
    zeichnen.ZeichneRechteck(rec, Grün)
}
 
Zuletzt bearbeitet:
Zurück