Moderne Diagramme für VB6: Mit WebView2 und Chart.js statt altem MSChart

Ein altes VB6-Programm muss nicht nach den frühen 2000ern aussehen. Für meine Diagramme läuft deshalb Chart.js in einer eingebetteten WebView2-Ansicht, während VB6 die Daten über eine schlanke API liefert. Das Ergebnis: Zoom, Tooltips und Live-Updates, ohne die bewährte Anwendung neu schreiben zu müssen.

Hinweis: Microsoft und MSChart sind Marken der Microsoft Corporation. Dieser Beitrag ist unabhängig und nicht von Microsoft autorisiert oder gesponsert.

Warum MSChart nicht mehr ausreichte

Bei dem VB6-Programm, für das ich die Diagramme gebaut habe, war MSChart der Engpass. Die Anwendung lief zuverlässig, aber Zoom, flexible Tooltips und mehrere sauber getrennte Y-Achsen ließen sich damit nur umständlich umsetzen.

Für eine Windows-Anwendung, die täglich in der Produktion läuft und Live-Messwerte aus der Fertigung visualisiert, reichte das nicht mehr aus. Die Wunschliste war lang: mehrere unabhängige Diagramme gleichzeitig, mehrere Y-Achsen pro Diagramm für unterschiedliche physikalische Größen, Zoom zum Untersuchen einzelner Zeitfenster, Referenzlinien für Grenzwerte, moderne Tooltips — und das alles möglichst ohne Wartungsalbtraum.

Die Idee: moderne Diagramme in WebView2

Ich wollte die bestehende Anwendung behalten und nur die Diagrammanzeige modernisieren. Dafür läuft Chart.js in einem WebView2-Steuerelement; VB6 liefert die Daten über eine kleine API.

Für den VB6-Entwickler bleibt davon nichts sichtbar außer einer ganz normalen Property/Methoden-API — kein JavaScript nötig, kein Griff unter die Motorhaube. Für den Anwender wird aus einem müden 90er-Jahre-Chart ein Diagramm, das sich anfühlt wie eine moderne Web-App — inklusive Zoom, Live-Updates und Tooltips, wie man sie sonst nur aus Grafana- oder Power-BI-Dashboards kennt.

Was das Diagramm kann

Zehn Diagrammtypen, ein API-Aufruf

Linie, Balken, Fläche, gestapelte Fläche, gestapelte Balken, Bereichsfläche und Bereichsbalken für Min/Max-Bänder, Treppenstufenlinie, weiche Spline-Kurve und Punktediagramm — beim Anlegen der Messreihe einfach den gewünschten Typ mitgeben, fertig. Jede Messreihe kann jederzeit den Typ wechseln, ganz ohne das Diagramm neu aufzubauen.

Bis zu 6 unabhängige Y-Achsen pro Diagramm

Drei links, drei rechts, jede mit eigenem Label, eigenem Zahlenformat (z. B. "#,#0.00 °C") und wahlweise fester oder automatisch aus den Daten berechneter Skalierung. Damit lassen sich Temperatur, Luftfeuchtigkeit, Druck und ein Statuswert im selben Diagramm sauber getrennt darstellen, ohne dass sich die Skalen gegenseitig ins Gehege kommen.

Noch praktischer: Neue Messreihen können sich per AutoAssignDataset selbst anhand ihres Formats der passenden Achse zuordnen. Zwei Messreihen mit demselben Format landen automatisch auf derselben Achse — man muss beim Hinzufügen einer neuen Messgröße nicht jedes Mal von Hand konfigurieren, wohin sie gehört.

Mehrere Diagramme, eine Fläche

Beliebig viele unabhängige Diagramme lassen sich untereinander anordnen — mit synchronisierter Plot-Breite, damit ein gemeinsamer Zeitstrahl über alle Diagramme hinweg optisch exakt fluchtet. Eine automatische Farbvergabe sorgt dafür, dass benachbarte Diagramme nicht zufällig mit denselben Farben starten: Jedes weitere Diagramm beginnt seine Farbpalette an einer versetzten Stelle.

Zoom mit Historie

Ein Rechteck mit der Maus aufziehen, schon ist gezoomt — mit mehrstufiger Zoom-Historie und einem eigenen Zurück-Button direkt im Diagrammtitel, sodass man sich schrittweise wieder herauszoomen kann. Fest konfigurierte Achsengrenzen bleiben beim Zoomen unangetastet, nur der sichtbare Zeitausschnitt ändert sich.

Fadenkreuz & intelligenter Tooltip

Ein Fadenkreuz-Cursor (standardmäßig aktiv) und ein Mouse-Over-Tooltip, der wahlweise nur die Messreihen des aktuellen Diagramms zeigt — oder, mit einem einzigen Property-Umschalter (TooltipAlleDiagramme = True), gleich die Istwerte aller Diagramme an derselben X-Position. Ideal, wenn man mehrere Messgrößen aus verschiedenen Diagrammen zum exakt selben Zeitpunkt vergleichen will, ohne den Kopf zwischen mehreren Fenstern hin- und herzubewegen.

Referenzlinien & Flächenmarkierungen

Horizontale und vertikale Linien mit eigenem Label, eigener Farbe und eigenem Linienstil (durchgezogen, gestrichelt, gepunktet, Strich-Punkt) — zum Beispiel eine rote gestrichelte „Alarm 85 °C“-Linie. Dazu rechteckige Flächenmarkierungen zwischen zwei X- und zwei Y-Werten, etwa um ein Wartungsfenster oder einen Warnbereich optisch hervorzuheben. Beides läuft über dieselbe API wie normale Daten und lässt sich jederzeit per zurückgegebener ID wieder gezielt entfernen.

Windowing für sehr große Datenmengen

Ein integriertes Windowing (MaxDatapoints) zeigt bei Bedarf nur die letzten N Datenpunkte an und blendet einen horizontalen Scrollbalken für die Vergangenheit ein — auch bei sehr langen Live-Aufzeichnungen über viele Stunden bleibt das Diagramm dadurch flüssig. Per ScrollToX lässt sich außerdem gezielt zu einem bestimmten Zeitpunkt springen, ohne manuell zu scrollen.

Live-Datenanbindung direkt aus der Datenbank

Einzelne Werte lassen sich per AddData nachtragen, für den Massenimport gibt es aber AddDataFromRecordset — ein komplettes ADODB.Recordset wird in einem Rutsch übernommen, inklusive optionaler zweiter Y-Spalte für Bereichstypen und optionaler Text-Spalte für individuelle Tooltip-Beschriftungen (z. B. „Schicht A / 14 Artikel“ statt eines nackten Zahlenwerts):

Dim rs As ADODB.Recordset
Set rs = GetRecordset("SELECT Zeit, Temp FROM Messwerte ORDER BY Zeit")
Diagramm.AddDataFromRecordset "Temperatur", rs, "Zeit", "Temp"
Diagramm.Refresh

Events zurück nach VB6

Klick auf einen Datenpunkt, Zoom geändert, neuer Datenpunkt hinzugefügt, Diagramm bereit — das Steuerelement feuert ganz normale VB6-Events, sodass sich Interaktionen im Diagramm direkt mit der restlichen Anwendung verdrahten lassen, etwa um beim Klick auf einen Messwert den zugehörigen Datensatz in einer Liste zu markieren.

Screenshot-Export auf Knopfdruck

Ein Aufruf, und der sichtbare Diagrammausschnitt landet als Bild in einem neuen Tab — praktisch für Berichte oder die schnelle Dokumentation eines auffälligen Verlaufs, ganz ohne externe Screenshot-Software.

Unter der Haube

Technisch ist das Ganze bewusst schlank gehalten: ein VB6-UserControl (Diagramm.ctl) als dünner Wrapper um WebView2, eine lokale — komplett offline-fähige — HTML/JS-Anwendung mit Chart.js v4, chartjs-plugin-zoom für die Zoom-Funktion und html2canvas für den Screenshot-Export. Der JavaScript-Code ist in über 20 fokussierte Module aufgeteilt und in einer festen Reihenfolge geladen: zuerst das Event-System, dann die API-Module (Daten-, Diagramm-, Dataset-, Anzeige-, Zoom-Verwaltung, Annotationen), danach CSS, globaler Zustand und schließlich die eigentliche Rendering-Logik — erst wenn alles geladen ist, meldet die Seite sich per DiagramReady-Event bei VB6.

Für die WebView2-Einbindung selbst kommt nicht Microsofts rohe API zum Einsatz, sondern ein schlanker, sehr flotter Wrapper namens cWebView2 — Teil von RC6.dll, dem Herzstück von VB-RichClient6 (kurz „RC6“). Das ist eine kostenlose, erstaunlich umfangreiche Klassenbibliothek für klassisches VB6 von Olaf Schmidt (offizielle Seite: vbrichclient.com), die der Sprache Fähigkeiten nachrüstet, die sie nie eingebaut hatte — von SQLite über 2D-Grafik (Cairo) bis eben WebView2 —, alle über eine einheitliche New_c-Fabrik ansprechbar (Set WV = New_c.WebView2, analog New_c.BigInt, New_c.UTC, …). Downloads (Basis-Paket RC6BaseDlls.zip), eine ausführliche Versionshistorie sowie Demos/Tutorials gibt es direkt auf der offiziellen Website; die Lizenz erlaubt kommerzielle Nutzung, ohne den eigenen Quellcode offenlegen zu müssen. Downloads, Versionshistorie und Demos findest du auf der offiziellen RC6-Website.

Die Kommunikation läuft in beide Richtungen: VB6 ruft JavaScript-Funktionen über ExecuteScript auf, JavaScript meldet Ereignisse (Klick auf einen Datenpunkt, Zoom geändert, …) über ein leichtes Event-Polling zurück — ein 100-ms-Timer statt teurer synchroner Callbacks, das reicht für ein flüssiges Nutzererlebnis völlig aus, ohne die VB6-Anwendung mit synchronen JS-Aufrufen zu blockieren.

Ein Refresh()-Aufruf durchläuft dabei intern eine ganze Kette an Schritten — Datasets auf alle passenden Diagramme replizieren, Daten gruppieren, Y-Achsen-Bereiche einfrieren, fehlende Standardwerte auffüllen, Farben automatisch zuweisen, Legende und Titel neu aufbauen, Chart.js-Instanzen (neu) initialisieren und schließlich rendern — alles innerhalb eines einzigen API-Aufrufs, sodass für den VB6-Entwickler nach jeder Datenänderung nur ein Diagramm.Refresh übrig bleibt.

Fazit

Für mein Projekt war WebView2 der passende Weg: Die VB6-Anwendung bleibt bestehen, während die Diagramme Zoom, Live-Updates und flexible Achsen bekommen. Die wichtigste Erkenntnis für mich: Eine moderne Oberfläche muss nicht bedeuten, ein funktionierendes VB6-System neu zu schreiben.

Wenn du weitere VB6-Projekte sehen möchtest, findest du hier auch meinen Profiler, das MenuEx-Kontextmenü und den ZeitPicker.