Artikelformat

Dartiagram: Meine erste Dart Library

1 Kommentar

Nach den ersten Schritten mit Dart gestern, möchte ich mich heute an einem ersten kleinen eigenen Projekt versuchen. Eine einfache Library, die es erleichtert einfache Diagramme zu erstellen. Es gibt schon großartige Librarys wie etwa chart.js, welche auch in Dart portiert wurde, aber mir geht es noch nicht um den Produktiveinsatz, sondern um das Experimentieren mit Dart.

Planung

Als erstes habe ich ein Skizze gemacht, um im Blick zu haben, wo ich hin möchte. Ein einfaches Säulendiagramm. In der Minimalversion sollte es ausreichen, wenn man die Werte der Balken übergibt. Für das Beispiel könnte das so aussehen: ‚dartiagram (35 20 28);‘. Oder mit Beschriftung: ‚dartiagram (35 20 28, ‚Kategorie 1‘ ‚Kategorie 2‘ ‚Kategorie 3‘, ‚x-Beschriftung‘, ‚y-Beschriftung‘, ‚Titel‘). Ich sehe schon jetzt viele mögliche Probleme und werde mich daher heute auf die erstem Möglichkeit, allerdings mit Beistrichen, damit da nicht eine zusätzliche Fehlerquelle reinkommt. Also: dartiagram (num a, num b, num c). Wobei mir da dann unklar ist, wie ich erweiterbar machen kann. Während ich bei der Möglichkeit ohne Beistrichen nur dartiagram (string a) habe und den dann bei den Leerzeichen splitten und in Numbers parsen könnte. Fühlt sich komisch, aber sinnvoller an. Und irgendwann kann man das dann über if Abfragen erweitern, damit man entweder Werte direkt oder etwa als json übergeben kann.

Nächstes Problem: Wie fange ich an? Erst dachte ich, dass ich direkt ein Pub Package erstelle, aber nachdem ich mich etwas herumgeklickt habe, scheint es mir sinnvoller, wenn ich erst eine Demo-Webapp erstelle und aus dieser dann den Code für ein Package abstrahiere.

Ein paar Stufen tiefer. Wie soll das ganze funktionieren?

  • Einbindung im code durch ‚dartiagram (string chart_data)‘.
  • Variable chart_data wird in Einzeldatenpunkte zerteilt. -> bars_data = Liste mit den einzelnen Datenpunkten als Numbers
  • Säulendiagramm berechnen und ausgeben
    • Canvasgröße per Default 500x500px
    • 100% Höhe des Säulendiagramms = höchster Wert + 10%
    • Breite eines Balken = 80% von (Canvasgröße-100px für Beschriftung / Anzahl der Datenpunkte)
    • Höhe der Balken = höchster Wert 100%, Rest prozentuell Wert/(Höhe/100)
    • Wert des Balken über dem Balken anzeigen

Ich merke, dass ich mein Mathematikwissen wieder einmal auffrischen sollte. Aber der grundsätzliche Plan steht.

Coding

Neues Projekt, sample web application. Dann hübsch das pubspec.yaml ausfüllen.
Dart Editor 2014-07-24 14.30.56

Beim Editieren des Beispiel-HTMLs fällt mir auf, dass Dart ja gar nicht direkt im HTML aufgerufen werden kann. Kurz recherchieren. Maximal eine Dart-Datei und keine Inline-Aufrufe. Ich bin kurz überfragt. Wie übergebe ich dann Werte über das HTML? Erst verrückte Idee: <canvas class="dartiagram" id="35_20_28"></canvas>. Eigentlich kann ich mich darum später kümmern. Also erstmal schauen, dass ich es schaffe, dass die main() Funktion irgendwas ins Canvas malt. Übergabe der Werte kann ich später implementieren, erstmal hardcoden.

Während dem coden habe ich immer wieder in Chapter 2 der Dart Tour und den dart:html API Docs nachgelesen sowie ein paar Zeilen aus dem sunflower Beispiel übernommen.

Statt Schritt für Schritt vorzugehen und dazwischen immer wieder zu testen, ob es so funktioniert, wie ich mir das vorstelle, habe ich den Grundcode in einem Durchgang geschrieben. Für einen Anfänger wie mich, wahrscheinlich nicht ideal. So sieht es aus:
dartiagram_v0

Super finde ich die kleinen Symbole auf der linken Seite, die erscheinen, wenn man in einem Kommentar ‚TODO‘ schreibt. Vermutlich Standard in vielen Editoren, aber ich habe es bisher noch nicht gesehen.

Natürlich bekam ich beim ersten Laufen lassen eine Fehlermeldung. Erst nach etwas Suchen fand ich einen Hinweis, mit dem ich etwas anfangen konnte.
dartiagram_error

Anscheinend bekommt die Funktion das Canvas Element mit der ID dartiagram nicht zum greifen. Nachdem ich erst glaubte, dass Dart ausgeführt wird bevor die Seite ausreichend geladen ist, was Unsinn ist, weil Dart aktuell immer erst nach dem vollständigen Laden ausgeführt wird. Tatsächlich habe ich versehentlich einmal #dartiagram und einmal #dartiagramm geschrieben.

Nächster Versuch. Neuer Fehler: „Breaking on exception: type ‚List‘ is not a subtype of type ’num‘ of ‚other‘.“. Schon etwas vertrauter mit dem Debugger habe ich mir angeschaut, was die letzte funktionierende Ausführung war und konnte schnell sehen, dass ich vergessen habe statt der Liste selbst die Länge der Liste abzufragen. Korrekt: „i < bars_data.length" dartiagram error list

Nächster Fehler: „NoSuchMethodError: method not found: ‚lenght'“. Habe ich mich verschrieben? Nein. Oh. Weiter unten, bei dem Ausrechnen der Säulenbreite habe ich mich verschrieben.

Nächster Fehler: „type ‚double‘ is not a subtype of type ‚int‘ of ‚bar_start‘.“. Ich habe versucht einen Integer mit einem Double zu addieren. Gefällt Dart wohl nicht. Also ‚int bar_start‘ in ’num bar_start‘ geändert.

Keine Fehler mehr. Juhu. Und wie sieht es aus?

Dartiagramtmp - Chromium 2014-07-24 18.59.45

Säulen sind da. Aber statt, dass sie unterschiedlich hoch sind, unterscheiden sie sich in der Breite. Mal bar_width und bar_height vertauschen: „..rect(bar_start, 0, bar_height, bar_width)“.

Dartiagramtmp - Chromium 2014-07-24 19.03.35

Sieht schon besser aus. Aber eigentlich wollte ich sie von unten nach oben. Dass 0,0 links oben ist, hätte ich mir denken können. Weiter geht es etwas mit Versuchen das ganze zum funktionieren zu bekommen. Höhe und Breite negativ und den Starpunkt nicht auf 0 sondern eben über die Breite des ersten Balkens. Sonst würde es negativ nicht funktionieren. Ganz durchschaue ich den Code im Moment nicht mehr, aber er funktioniert.

Dartiagram

Und jetzt noch der Test, ob es auch mit mehreren Datenpunkten funktioniert: „var bars_data = [35, 20, 28, 20, 11, 45, 4, 12];“
Dartiagramtmp - Chromium 2014-07-24 19.21.51

Funktioniert. Natürlich fallen gleich zwei Probleme auf. Ich berechne die Breite zwar über die Anzahl der Säulen, aber füge immer 10px Abstand hinzu. Wenn man das auch prozentual über die Anzahl macht, dann würde der Platz nicht irgendwann aus sein. Ebenfalls ist aktuell die Höhe noch absolut festgelegt anstatt über die höchste Säule. Und man könnte auch in Frage stellen, ob Canvas das ideale Mittel für sowas ist. Einerseits kann das Diagramm somit einfach als .png gespeichert werden, aber es dürfte schwierig werden es interaktiv zumachen.

Und hier noch der Code.

Ich bin zufrieden. Es ist nicht alles implementiert, was ich vor hatte und es gibt vieles, das optimiert werden kann. Aber es ist mein erstes eigene DArt Programm. Und weil jedes Dart Programm zugleich eine Library ist, könnte es auch in anderen integriert werden. Da habe ich es mir etwas einfach gemacht, aber es ist Abend und ich sollte eigentlich Lernen und ein paar Artikel für AmbassadorBase schreiben.

Veröffentlicht von

Ich studiere Medienwissenschaften an der Uni Paderborn, arbeite freiberuflich als Social Media Analyst und veröffentliche jährlich einen Blogbeitrag. | | | Newsletter

1 Kommentar An der Unterhaltung teilnehmen

  1. Thanks for letting us look over your shoulder while coding! When I remember how, back in the sebenties not only would that not have worked as there were non interactive graphics, the whole process would have taken days if not weeks, because to correct „lenght“ one would have first delivered a set of punched cards, run them through a reader, get the program compiled. If lucky, next morning a printout (!) would show the mistake. Back to the card puncher, rerun the set and so on. IF you got computer time at all, that was. ;-)

    Antworten

Schreibe eine Antwort

Pflichtfelder sind mit * markiert.