SAPUI5 Controls mit D3.js erweitern – Teil 1

Mit D3.js steht der Web-Entwicklung eine mächtige JavaScript Bibliothek zu Verfügung um dynamische, interaktive Datenvisualisierung im Browser zu ermöglichen. Hierbei werden die Web-Standards SVG, HTML5 und CSS genutzt.

Die D3 Visualisierungsfähigkeiten legen nahe, SAPUI5 Modelle zu nutzen um Grafiken in SAPUI5 Custom Controls zu integrieren.

Es soll hier eine Füllstandanzeige implementiert werden, die in einem SAPUI5 XML View eingebunden werden kann und deren Werte über den entsprechenden Controller geändert werden können.

50percentDie Komponente soll über Eigenschaften steuerbar sein. Die Welle des Füllstandanzeigers ist dynamisch und der dargestellte Wert wird zum Anzeigebeginn hochgezählt.

Die D3 Bibliothek wird im Ordner „lib“ der SAPUI5 Applikation abgespeichert und in der „index.html“ referenziert:

// libs
jQuery.sap.require(„bixs.lib.d3“);

Ein SAPUI5 Custom Control ist eine JavaScript Klasse die von der Core Komponente „sap.ui.core.Control“ erbt.

In der Applikation wird ein Ordner „controls“ erstellt und darin eine Datei „D3FillingLevel.js“ mit der Rumpfimplementierung:

sap.ui.define([
„sap/ui/core/Control“
],
function (Control) {
„use strict“;
return Control.extend(„bixs.controls.D3FillingLevel“, {}
});

Als nächstes werden die Meta-Daten der Komponente beschrieben. Die Metadaten definieren die Struktur der Komponente. Sie bestehen aus den Eigenschaften (Properties), den Ereignissen (Events), den Aggregationen und Assoziationen. Auf Basis der Metadaten erstellt SAPUI5 automatisch Setter- und Getter-Methoden.

Eigenschaften werden durch ihren Namen und den Typ charakterisiert. Optional kann ein Default-Wert mitgegeben werden. Als Typ zählen einfache Datentypen wie string, int und float, aber auch Arrays und Objekte.

Für den Füllstandanzeiger werden unter anderem folgende Eigenschaften verwendet:

metadata : {
properties: {
„title“: {type : „string“, group : „Misc“, defaultValue : „FillingLevel“},
„width“: {type : „int“, group : „Misc“, defaultValue : 100},
„height“: {type : „int“, group : „Misc“, defaultValue : 100},

„mtop“: {type : „int“, group : „Misc“, defaultValue : 10},
„mbottom“: {type : „int“, group : „Misc“, defaultValue : 10},
„mleft“: {type : „int“, group : „Misc“, defaultValue : 10},
„mright“: {type : „int“, group : „Misc“, defaultValue : 10},

„minValue“: {type : „int“, group : „Misc“, defaultValue : 0},
„maxValue“: {type : „int“, group : „Misc“, defaultValue : 100},

„circleThickness“: {type : „float“, group : „Cycle“, defaultValue : 0.05},
„circleFillGap“: {type : „float“, group : „Cycle“, defaultValue : 0.05},
„circleColor“: {type : „string“, group : „Cycle“, defaultValue : „#178BCA“},

(…)

In dem Bereich der Aggregationen werden interne SAPUI5 Controls deklariert, die von der Komponente genutzt werden können.

Für die Füllstandanzeige benötigen wir eine (multiple : false) interne VBox.

aggregations : {
_vbox : {type : „sap.m.VBox“, multiple: false, visibility : „hidden“}
},

Als nächstes wird der Konstruktor der Komponente implementiert.

init : function () {

(…)

var oVBox = new sap.m.VBox( {id : (…) } )
this.setAggregation(„_vbox“, oVBox);
},

Die Init-Methode wird von SAPUI5 automatisch ausgeführt, wenn eine neue Instanz der Komponente erzeugt wird. Hier werden interne Komponenten erstellt und in der Aggregation gespeichert.

Jetzt wird die HTML-Ausgabe der Komponente gerendert. Dazu wird die geerbte Methode „renderer“ redefiniert:

renderer : function (oRM, oControl) {
oRM.write(„<div“);
oRM.writeControlData(oControl);
oRM.writeClasses();
oRM.write(„>“);
oRM.renderControl(oControl.getAggregation(„_vbox“));

oRM.write(„</div“);
},

Diese Methode ermöglicht uns den Einsatz der D3 Bibliothek, da automatisch eine weitere Methode (onAfterRendering) durch „renderControl“ aufgerufen wird:

onAfterRendering : function() {
var that = this;

// config lesen

// get configuration
var config = this.getConfig();
// liefert alle Eigenschaften im Objekt config („config.title“ …)

// Wert aus Komponente lesen

var value = this.getValue();
// Aufruf der automatisch generieren Getter-Methode

var fillingLevel = d3.select(//(…))
.append(„svg“)
.attr(„width“, config.width + config.mleft + config.mright)
.attr(„height“, config.height + config.mtop + config.mbottom)
.style(„background-color“,“white“);

Mit dem D3 Selektor wird ein Element des Document Object Models (DOM) zuerst ausgewählt und mit Operatoren manipuliert. Konkret wird hier ein „svg“ Knoten dem DOM hinzugefügt und mit Attributen versehen.

Ein D3 Beispiel für das Zeichnen eines Kreises:

var radius = Math.min(config.width, config.height)/2;
var locationX = config.width/2 – radius;
var locationY = config.height/2 – radius;

this.circle = this.svg.append(„circle“)
.attr(„r“, radius)
.attr(„cx“, locationX)
.attr(„cy“, locationY)

Einen Text in der Mitte des Kreises zeichnet man mit:

this.circleText = this.svg.append(„text“)
.attr(„x“, locationX)
.attr(„y“, locationY)
.style(„opacity“,0.5)
.attr(„text-anchor“, „middle“)
.attr(„font-size“, 15)
.style(„fill“, „white“)
.attr(„cursor“,„pointer“)
.attr(„dominant-baseline“, „middle“)
.attr(„alignment-baseline“, „middle“)

Es soll möglich sein den Wert des Füllstandanzeigers zu verändern. Hierzu dienen die öffentliche Methode „updateValue“ und die private Methode „_changeObject“:

updateValue: function (iValue) {
this.setProperty(„value“, +iValue, true);
this._changeObject();
},

Der neue Wert wird in die Eigenschaft „value“ der Instanz geschrieben. An dieser Stelle könnte auch die automatisch erstellte Methode „setValue()“ benutzt werden.

_changeObject : function() {
d3.select(…)
.select(„svg“).remove();
this.onAfterRendering();
}

Das ursprüngliche „svg“ Element wird aus dem DOM entfernt und es wird ein neues mit dem geänderten Wert erstellt.

Die Komponente kann nun im SAPUI5 View (XML) genutzt werden:
(…)

xmlns:bixs=“bixs.controls“

(…)

<l:HorizontalLayout>

<Input id=„newValue“ value=„“ />

<Button text=„set new Value“ press=„onPress“ />

<bixs:D3FillingLevel id=„d3FillingLevel1“  />

<bixs:D3FillingLevel id=„d3FillingLeve2“

value=„60“
displayPercent = „false“
textColor = „red“
waveTextColor = „white“
circleColor=„red“
waveColor=„red“ />

</l:HorizontalLayout>

Der erste Füllstandanzeiger wird mit den Default-Werten der Komponente erzeugt. Der zweite „überschreibt“ einige der Eigenschaften.
fillinglevel
Um Werte des Füllstandanzeigers zu verändern wird der SAPUI5 Controller des Views um eine Methode „onPress“ erweitert.

onPress : function(oEvent) {
var oView = this.getView();

var oD3FillingLevel1 = oView.byId(„d3FillingLevel1“);
var oD3FillingLevel2 = oView.byId(„d3FillingLevel2“);

var oInput = oView.byId(„newValue“);
var sInput = oInput.getValue();
oInput.setValue(„“);

oD3FillingLevel1.updateValue(+sInput);
}

Nun kann per Eingabe und betätigen der Schaltfläche der Wert des ersten Füllstandanzeigers geändert werden.

Im nächsten Teil des Blogs wird das „Eventing“, also die Nachrichtenübermittlung von der Komponente nach außen mittels Ereignissen dargestellt.

Des Weiteren werden Daten eines SAPUI5 Modells in einer D3 Komponente verwendet sowie die Möglichkeiten des Aggregation-Binding des Custom Controls aufgezeigt.

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

Marcel
Marcel Metzen

Senior Consultant

Getagged mit: , , , , , , , , , , , ,