Warning: include_once(/var/www/html/pmwiki-2.2.86/cookbook/soap4pmwiki/soap4pmwiki.php): failed to open stream: No such file or directory in /var/www/html/fields/dbp13/local/config.php on line 4

Warning: include_once(): Failed opening '/var/www/html/pmwiki-2.2.86/cookbook/soap4pmwiki/soap4pmwiki.php' for inclusion (include_path='.:/opt/php/lib/php') in /var/www/html/fields/dbp13/local/config.php on line 4

Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/fields/dbp13/local/config.php:4) in /var/www/html/pmwiki-2.2.86/pmwiki.php on line 1250
Datenbankpraktikum SS 2013 - Datenvisualisierung - Javascript

Javascript

Dominik Lips

Um die Benutzeroberfläche dynamisch zu gestalten, wurde Javascript eingesetzt. Dies bietet sich an weil schon seit vielen Jahren Javascript-Interpreter standartmässig in Webbrowser enthalten sind und inzwischen ein beachtliches Performanceniveau erreicht haben. Um von unterschiedlichen Implementierungen in verschiedenen Browsern zu abstrahieren wurden mehrere Bibliotheken eingesetzt welche über alle Browser hinweg eine einheitliche API bereitstellen.

Verwendete Bibliotheken
  • jQuery v1.10.2 - Für DOM-Manipulation, AJAX-Request, DOM-Event-Binding
  • highcharts - Für Balken- und Tortendiagramme
  • Twitter Bootstrap Plug-Ins - Javascript für die GUI-Komponenten des Twitter Bootstrap Frameworks
  • radio.js - Implementierung des Publish/Subscribe-Patterns für applikationsinternes Event-Handling
  • spin.js - Für Anzeige der Lade-Animation
  • Three.js - Für die 3D-Darstellung des Google Globes

Außerdem wurden noch weitere Plug-Ins für diese Basisblibiotheken genutzt, um diese mit bestimmten Funktionalitäten zu erweitern:

  • Twitter Bootstrap Slider - Erweitert Bootstrap um einen Slider für die Zeitleiste.
  • Twitter Bootstrap Multiselect - Stellt ein komfortables Dropdown-Menü für eine Mehrfachauswahl bereit.
  • jqTimeline - Stellt eine Skala für die Zeitleiste bereit. Wurde überarbeitet um Semester anzuzeigen.
  • jQuery Formstate Plugin - Überträgt eine Formular in ein Javascript Objekt und umgekehrt. Wurde ebenfalls an unsere Bedürfnisse angepasst.
Strukturierung des Quellcodes

Um unseren eigenen Javascript-Quellcode zu strukturieren haben wir uns für Namespacing mittels Objekt-Literalen entschieden. Dies bietet sich für kleinere Projekte an, da es schnell umzusetzen ist, aber dennoch eine klare Struktur erzwingt. So entsteht eine Baumstruktur von Objekten, die wiederum andere enthalten.

  • App - Enthält alle Funktionen die für die ganze Applikation gebraucht werden
    • App.filter - ViewModel für das Filterformular
      • App.filter.listener - Callback-Funktionen des Filter-Objekts
    • App.model - Speichert die anzuzeigenden Daten zwischen und regel die Kommunikation mit dem Backend
    • App.slider - ViewModel für die Zeitleiste
      • App.slider.playButton - ViewModel für den "Abspielen"-Button
    • App.chart - ViewModel für die Diagramme allgemein
      • App.chart.columnchart - Enthält alles was für die Anzeige des Balkendiagramm notwendig ist
      • App.chart.piechart - Enthält alles was für die Anzeige des Tortendiagramm notwendig ist
      • App.chart.googlemaps - Enthält alles was für die Anzeige von GoogleMaps notwendig ist
      • App.chart.googleglobe - Enthält alles was für die Anzeige des GoogleGlobe notwendig ist
      • App.chart.listener - Enthält die Callback-Funktion des Chart-Objekts
    • App.searches - Regelt das Speichern und Laden des Formularzustandes im localStorage des Browsers

Ein Beispiel für ein solches Code-Konstrukt sieht wie folgt aus:

Beispielcode für die Verwendung von Namespacing mittels Objekt-Literalen

Zeile 6 sorgt dafür, dass das "Wurzelobjekt" App definiert ist. Wenn es nicht bereits existiert wird ein leeres Objekt angelegt. Dies ist nötig weil nicht garantiert werden kann das der Javascript Interpreter im Browser die Datei in der das App Objekt definiert ist bereits verarbeitet hat. Falls dies nicht der Fall ist und Zeile 6 nicht vorhanden wäre, würde es zu einem Fehler kommen. In Zeile 8 wird dann der Eigenschaft chart ein neues Objekt zugewiesen welches das ViewModel für die Diagramm-Buttons/Fläche enthält.

Steuerung durch Events

Die Benutzeroberfläche wird größtenteils durch Events gesteuert. Als Beispiel sei hier der Ablauf beim Abrufen neuer Daten erklärt.

Ablauf der Events beim Aktualisieren der Daten

Wenn der Benutzer den "Aktualisieren"-Button betätigt wird das Event filter.submit ausgelöst. Daraufhin holt sich das Model die aktuellen Filtereinstellungen und bereitet sie für die Erstellung des Suchobjekts im Backend auf. Ist dies geschehen werden die Daten vom Server geladen. Zu Beginn dieses Prozesses wird das Event model.fetch ausgelöst, worauf die Oberfläche mit dem deaktivieren der Buttons zum Wechseln des Diagrammtyps reagiert. Außerdem wird der "Aktualisieren"-Button in einen Lademodus versetzt, in dem er deaktiviert wird und den Text Laden... anzeigt. Desweiteren wird über dem Diagrammbereich eine Ladeanimation angezeigt.

Sind nun bespielsweise die Daten für die Highchartsdarstellung geladen, wird das Event model.hc.fetched ausgelöst. Wenn der akutelle Diagrammtyp Balken- oder Tortendiagramm ist, werden diese Daten bereits angezeigt. Das gleiche gilt für GoogleMaps (Event: model.gmaps.fetched) und den GoogleGlobe (Event: model.globe.fetched). Sind nun alle Daten geladen wird das Event model.fetched ausgelöst und der "Aktualisieren"-Button wieder in den Ausgangszustand versetzt.

Zur Realisierung dieser Event-Steuerung wurde neben den DOM-Events die Blibiothek radio.js genutzt. Hiermit steht eine einfach aber effektive Implementierung des Publish/Subscribe-Patterns zur Verfügung. Dies ermöglicht ein applikationinternes Event-Management das nicht mit den DOM-Events korreliert.

Model-View-ViewModel Architektur

Das Design-Pattern Model-View-ViewModel ist eine Abwandelung des Model-View-Controller-Patterns. In unserem Kontext der Programmierung mit Javascript im Browser, ist das Model dafür zuständig die Daten für die Diagramme zu verwalten und die Kommunikation mit dem Server zu erledigen. Die View stellt lediglich das HTML dar, welches im Browser anzeigt wird. Das ViewModel entspricht einer Javascript-Representation des Zustands der View. So kann leichter auf bestimmte Eigenschaften zugegriffen, beziehungsweise Programmcode der lediglich für das verändern der View zuständig ist, vom Rest abgekapselt werden.

Als Beispiel für dieses Vorgehen sei hier das Objekt App.filter genannt, welches das ViewModel für die Filtereinstellungen auf der linken Seite ist. Die View ist ein einfaches HTML-Formular. Wird etwas in dem Formular durch den Benutzer verändert, wird der Formularzustand automatisch in ein Javascript Objekt umgewandelt welches über App.filter.getFilter() zugänglich ist. So muss der Rest der Applikation nicht direkt auf das DOM zugreifen um die Werte aus dem Formular auszulesen, sondern kann mit einer einfach zu handhabene Schnittstelle kommunizieren. Auf der anderen Seite, wird die View automatisch aktualisiert wenn die Filtereinstellungen über die Schnittstelle verändert werden. Dies war beispielsweise bei den Drilldown-Filter nützlich, da das DOM nicht direkt manipuliert werden musste.


Page last modified on August 23, 2013, at 07:01 PM