SAPUI5 Controls mit D3.js erweitern – Teil 3

Nachdem wir in den vorangegangenen Teilen des Blogs erfahren haben wie die D3 Bibliothek in SAPUI5 Custom Controls verwendet wird, werden wir uns nun einem etwas komplexeren Thema widmen:
der Übergabe von Modeldaten an eine Komponente und die Visualisierung dieser Daten.
Ziel wird sein, aus einem JSON Modell ein Balkendiagramm zu erstellen, das in etwa folgendermaßen aussehen könnte:

Unsere Datenquelle soll zu einem Kunden dessen Umsatz liefern.

Die Daten werden in unserem Beispiel aus einer Datei geladen, können aber natürlich auch durch einen Web Service zur Verfügung gestellt werden. Für die weitere Verarbeitung in der „Custom Component“ spielt dies an dieser Stelle keine Rolle.
Als erstes erzeugen wir einen neuen XML View und dessen Controller. In der „Init()“ Methode des Controllers wird das Modell aus der Datei geladen.

Im XML View soll unsere neue Komponente ähnlich benutzt werden können, wie bekannte Komponenten, z.B sap.m.List(). Wir werden ein Item Template anlegen und dieses in der Aggregation der Komponente an die Daten binden. Im View sieht das dann so aus:

Wie man sieht benötigen wir zwei Komponenten. Die Komponente für die Chart Erstellung „bixs:D3BarChart“ und als Schnittstelle zu den Daten eine Item Komponente „bixs:D3BarChartItem“.
Beginnen wir mit den Items:

Wir benötigen hier nur einige Eigenschaften, die im „metadata“ Teil der Item Komponente angelegt werden. Man kann hier recht allgemein bleiben, so dass unser Item auch in anderen Controls genutzt werden kann (dim1, dim2, dim3, value).  Zur Laufzeit generiert uns SAPUI5 Getter und Setter Methoden, die den Zugriff auf die Daten erlauben.
In den Aggregationen der Chart Komponente werden die Items angelegt:

Hier ist zu beachten, dass, da eine Menge von Sätzen übergeben werden, auch eine Menge von Instanzen von D3BarChartItem erzeugt werden muss. Daher ist der Parameter „multiple“ „true“.
Wie in den beiden vorangegangenen Blogs gesehen enthalten die Aggregationen weiterhin eine VBox, der Parameter „multiple“ ist dann natürlich „false“.
Die Properties werden noch angereichert mit Schnittstellen für Höhe und Breite, sowie Top-, Bottom-, Left- und Right- Margins.

init“ und die „render“ Methode können aus den vorhergehenden Blogs übernommen werden. Neu hinzu kommt eine Methode „getConfig“, die uns alle Properties in einem Objekt übergibt.

Wie wir schon gesehen haben, wird die Methode „onAfterRendering“ nach dem Rendern der „VBox“ aufgerufen, in der der Zugriff auf die Daten und die SVG Visualisierung erfolgt.
Nach dem Erzeugen einer Selbst-Referenz und dem Aufruf der „getConfig“ Methode sammeln wir uns die Modeldaten aus den gebundenen Items zusammen.
Die Items werden in der generierten Getter Methode „this.getItems()“ zur Verfügung gestellt.

Wie im Debugger zu sehen ist, erhalten wir ein Array von Item-Objekten, in denen die gebundenen Werte in den „mProperties“ zu finden sind.
Eine Schleife über dieses Array sammelt die Daten in ein neues Array „data“.

Im Debugger sieht man:

Um die Höhe der Balken später an die Höhe des SVG Elements anzupassen wird der Maximalwert der Daten benötigt. Diesen liefert die „d3.max“ Methode, der wir mitgeben können wo die Werte „value“ im „data“ Array zu finden sind. Das „+“ vor „d.value“ wandelt den String in numerische Werte um.

Mit „d3.map“ erstellen wir noch ein Array über die erste Dimension „dim1“ die an „customer“ gebunden ist.

Um Daten an die Proportionen der Zeichenfläche anzupassen bietet die D3 Bibliothek ein mächtiges Werkzeug, das „Scaling“. Wir benötigen hier zwei Skalierungen. Eine für die x-Achse, die Werte, und eine für die y-Achse, die einzelnen Kunden aus den übergebenen Daten.
Numerische Skalierung erhält man durch „scaleLienar()“, textalische Skalierung liefert „scaleBand()“. Dieses Beispiel nutzt die Version 4 der D3 Bibliothek. Version 3 enthält noch eine andere Syntax, z.B. „d3.scale.linear()“ für die numerische Skalierung.

Eine detailliertere Beschreibung dieser Methoden würde an dieser Stelle zu weit führen. Näheres kann z.B. im D3 Wiki (https://github.com/d3/d3/wiki) nachgelesen werden.
Die einzelnen Balken des Diagramms werden mittels eines „Translators“ an die korrekte Position verschoben. Auch das Konzept des „Transform/Translate“ kann im Wiki vertieft werden.

Jetzt wird gezeichnet. Zuerst ein äußerer Rahmen, abhängig von den Parametern Höhe und Breite, darin ein Group Element, verschoben um die Seitenränder.

Das Group Element „mainGroup“ wird mittels einer „Translator“ Funktion an die korrekte Position verschoben.
Für die einzelnen Balken des Diagramms erstellen wir wiederum eine Gruppe. Hier wird die „.data(data).enter()“ Methode benutzt, die als Loop über die Daten (das „data“ Array) verstanden werden kann. In den weiteren Attributen kann auf die einzelnen Datensätze zugegriffen werden.

Jeder Balken soll mittels „mouseover“ und „mouseout“ in einer Textbox Details zum Datensatz zeigen. Der Satz selbst wird hier in der Variablen „d“ übergeben. „i“ übergibt den Index des Satzes. Die Funktion „showData()“ blendet die Textbox ein und wieder aus.

In „barGroup“ wird nun ein Rechteck gezeichnet. Durch „.data()“ enthält „barGroup“ ein Array von Group Elementen. Wird nun ein weiteres Element diesem Array hinzugefügt, geschieht das für jedes Objekt des Arrays. Der folgende Code fügt also Rechtecke in der Anzahl der „Group“ Elemente ein.


Breite und Höhe beziehen wir aus den Skalierungen, die zu Beginn eingeführt wurden.
Zum Schluss fügen wir noch Achsenbeschriftungen ein. Die Werte auf er x-Achse:

Das Zeichnen selbst geschieht in der Methode „.call()“, die als Rückgabe die Knoten der Achse liefert.
Die Kundenbezeichnungen auf der y-Achse:

Die Texte liefert die „xScale“ Skalierung. Die Ausrichtung der Textknoten wird hier noch im Winkel 45 Grad gedreht.
Damit kommen wir zum Ende der kleinen Reihe über SAPUI5 und das Zusammenspiel mit der JavaScript Bibliothek D3. Der komplette Sourcecode dieses letzten Beispiels kann nachgefragt werden.

Sie haben Fragen zu SAP UI5? Dann sprechen Sie uns gerne an.

Marcel
Marcel Metzen

Architect biX Solutions

 

 

Getagged mit: , , , ,