Mit Hilfe von jqPlot, einer auf jQuery aufbauenden Bibliothek lassen sich auf einfache Art und Weise Diagramme zeichnen. In zahlreichen Tutorials auf der Homepage beschreibt Chris Leonello die umfangreichen Features seines Tools.
Auf eine Möglichkeit geht er jedoch nicht ein: Es lassen sich dynamische Diagramme aufbauen, die erst nach und nach die Werte anzeigen. Wie man das macht, wollen wir in diesem Eintrag beschrieben.
Ziel ist es, ein Diagramm zu erstellen, welches die Daten eines ABS-Bremsversuchs parallel zu einem Video anzeigt.
Wir nehmen mit Kameras die Fahrt unseres Modellautos auf und zeichnen parallel dazu verschiedene Sensorparameter auf, später wollen wir diese natürlich auch gleichzeitig anzeigen. Dazu soll die Y-Achse eines entsprechenden Diagramms die jeweiligen Werte und die X-Achse die Zeit anzeigen.
Also auf zum Programmierteil: Als erstes müssen die erzeugten Daten für jQuery zugreifbar gemacht werden (wir nutzen an dieser Stelle ein Objekt, welches wir als „assioziatives Array“ benutzen):
var speed = new Array(); speed[0] = 0.0; speed[5] = 0.0; … speed[5076] = 5.1; … speed[8747] = 0.0; var slip_front_left = new Array(); slip_front_left[0] = 0.0; …
Das Zeichnen des Diagramms lagern wir in eine Funktion aus:
function drawCompleteDiagrams() { $('#diagramContainer').empty(); targetPlot = $.jqplot('diagramContainer', [speed, slip_front_left], diagramOptions); }
Im HTML Quellcode existiert ein <div>;-Element mit der id diagramContainer, welches als Behälter für das Diagram dient. Dort kann man auch die entsprechende Größe und so weiter einstellen, wie bei allen anderen Diagrammen auch (das würde an dieser Stelle zu weit führen, die Hilfe von der jqPlot-Seite ist aber auch sehr ausführlich).
Zu beachten ist hier, dass wir den Container vorsichtshalber leeren, falls schon etwas darin gezeichnet wurde, da sonst die Diagramme übereinander gezeichnet werden. Dies ist wichtig für die dynamischen Diagramme des nächsten Schrittes:
function updateData() { if (!running) return; setTimeout(updateData, 500); var currentTime = video.getTime() * 1000; if (currentTime > 9000) { running = false; drawCompleteDiagrams(); return; } var speed_temp = new Array(); var slip_front_left_temp = new Array(); for(var i=0, length = speed.length; i < length; i++) { if (length > currentTime) {break;} speed_temp[i] = speed[i]; slip_front_left_temp[i] = slip_front_left[i]; } $('#diagramContainer').empty(); targetPlot = $.jqplot('diagramContainer', [speed_temp, slip_front_left_temp], diagramOptions); }
Die Inhalte des Quellcodes noch einmal kurz zusammengefasst: Falls die Funktion aufgerufen wird, obwohl nichts läuft, brechen wir ab (somit müsst ihr irgendwo running auf false setzen, und schon wird nichts gezeichnet).
Danach wird sofort das nächste Aufrufen der Funktion angestoßen, damit die Zeit möglichst genau stimmt. Wir lassen hier alle 500 Millisekunden zeichnen, damit auch schwächere Rechner nicht ins Stocken geraten.
Als nächstes lassen wir uns die aktuelle Zeit geben. Diese holen wir aus einen Video, zu dem die Daten parallel angezeigt werden. Ohne Video könnte man es beispielsweise aus den Zeitunterschieden der aktuellen Zeit (var now = new Date().getTime()) und einem zu Beginn gemerkten Zeitstempel berechnen.
Es folgt eine weitere Abbruchbedingung: Wenn wir über 9 Sekunden sind (ja, unser Video ist kurz) zeichnen wir das vollständige Diagramm und beenden das dynamische Zeichnen.
Als nächstes kopieren wir alle benötigten Werte (also bei uns bis zum Zeitstempel) in temporäre Arrays und übergeben diese an die Zeichenfunktion. Hier ist das Leeren des Containers besonders wichtig, damit die Diagramme nicht übereinander gemalt werden.
Noch ein Hinweis: Da jqPlot automatisch auf die vorhanden Werte skaliert, ist es sinnvoll mit den Optionen die Grenzen der Achsenbeschriftung anzugeben, damit das Diagramm auch gleichmäßig wächst und sich die Werte nicht mehr verschieben. Dazu hier ein Ausschnitt aus den Optionen (weitere Werte findet ihr in der ausführlichen Dokumentation von jqPlot):
var diagramOptions = { xaxis: { ... labelRenderer: $.jqplot.CanvasAxisLabelRenderer, tickOptions:{formatString:"%d"}, min: 0, max: 8747 }, ... };
Und so sieht dann das Ergebnis aus:
Das Bild zeigt oberen Diagramm den Zustand mitten im Versuch (Bremsen hat gerade begonnen und die Räder blockieren das erste mal), und im unteren Diagramm sieht man das Ende des Versuchs.