Tags:, Posted in Titanium:-)7 Kommentare

In meiner App möchte ich ein Diagramm darstellen und benötige dafür eine Möglichkeit 2D Grafiken zu erzeugen. Die API von Titanium bietet derzeit keine Möglichkeit dies zu tun, weshalb ich mir überlegt habe WebKit zu nutzen und dann auf einem Canvas zu zeichnen. Die ersten Versuche im iPhone Simulator waren sehr vielversprechend, aber leider wird der Code auch mit der Geschwindigkeit meines MacBooks ausgeführt. Die Performanz, mit der die Diagramme auf dem Gerät erzeugt werden, ist eher ernüchternd.

Bevor ich auf die einzelnen Werte eingehe, erkläre ich erstmal einen möglichen Weg Diagramme mit Titanium darzustellen. Meine Ordnerstruktur sieht wie im folgenden Bild aus:
bildschirmfoto-2010-04-15-um-084628

Die Titanium Skripte liegen bei mir alle in der Wurzel. In diesem Fall ist es nur die app.js. Sie ist einfach aufgebaut und erzeugt nur eine WebView, in der eine URL geladen wird.

1
2
3
4
5
6
7
8
9
10
var window = Ti.UI.createWindow({
  orientationModes: [Ti.UI.LANDSCAPE_RIGHT]
});
 
var webkit = Ti.UI.createWebView({
  url: 'web/chart.html'
});
 
window.add(webkit);
window.open();

Die WebView Komponente lädt eine lokale HTML Seite. Die HTML Seiten befinden sich in dem Ordner web und relativ dazu liegen die Skripte und die Stylesheets. Ein wesentlicher Unterschied zu einer normalen Webanwendung ist die Benennung der JavaScript Dateien. Sie enden bei mir mit *.javascript. Titanium liest in seinem Build-Vorgang rekursiv alle Dateien mit der Endung *.js ein und nimmt an, dass dies Titanium Skripte sein müssen. Der Parser geht strikt vor und erlaubt keine Fehler. In Bibliotheken wie jQuery oder Prototype fehlt aber ab und an ein Semikolon. Damit kommt Titanium nicht klar. Eine Möglichkeit das Problem zu umgehen ist die Umbenennung der Endung. Auf diese Weise müssen externe Bibliotheken nicht in die HTML Seiten eingebettet werden.

Wie zu sehen ist, nutze ich für dieses Beispiel Flot. Ein jQuery Plugin zur Erzeugung von Diagrammen. Dafür muss zuerst jQuery, dann Flot, dann mein Code geladen werden. Die HTML Datei, die die WebView Komponente also lädt, sieht wie folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
<html>
  <head>
    <link rel="stylesheet" type="text/css" href="css/style.css" />
    <script type="text/javascript" src="scripts/jquery.min.javascript"></script>
    <script type="text/javascript" src="scripts/jquery.flot.min.javascript"></script>
    <script type="text/javascript" src="scripts/chart.javascript"></script>
  </head>
  <body>
    <!-- Render the chart in this container -->
    <div id="placeholder"></div>
  </body>
</html>

Was nun fehlt ist die Brücke zwischen Flot in der WebView und Titanium. Das Schöne ist, dass die WebView eine Methode bereitstellt, mit der sich JavaScript Code evaluieren lässt: evalJS. Ich bevorzuge den JavaScript Code, der für die WebView gedacht ist, an einer Stelle zu halten und habe daher mir die chart.javascript angelegt:

1
2
3
4
5
6
7
8
9
10
function runChartDemo() {
  var d1 = [];
  for (var i = 0; i < 14; i += 0.5) {
    d1.push([i, Math.sin(i)]);
  }
  var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]];
  var d3 = [ [0, 12], [7, 12], null, [7, 2.5], [12, 2.5]];
 
  $.plot($("#placeholder"), [ d1, d2, d3 ]);
}

Die runChartDemo() Funktion steht mir spätestens dann zu Verfügung, wenn die WebView geladen und Einsatzbereit ist. Und das bekomme ich in Titanium durch einen EventListener mitgeteilt. Nebenbei: In den Docs steht geschrieben, dass entweder nur die Titanium Events oder die Events in dem JavaScript Universum der WebView genutzt werden sollen. Nach Möglichkeit nicht gemischt. Auf jeden Fall kann ich nun in der app.js das load-Event der WebView abgreifen und meine Funktionen ausführen:

1
2
3
webkit.addEventListener('load', function() {
  webkit.evalJS('runChartDemo()');
});

Starte ich Titanium, sehe ich das folgende Ergebnis:bildschirmfoto-2010-04-15-um-1004111

Nun zu den Nachteilen. Es ist langsam. Zumindest so langsam, dass es mir als Anwender keinen Spass machen wird, auf die Grafik zu warten. Alleine die nackte WebView wird auf meinem iPhone 3G in ca. 1000ms erzeugt. Dann wird jQuery und Flot geladen. Wie lange das dauert, hängt davon ab, ob es zum ersten mal in der App passiert oder zum x-ten mal (das iPhone scheint das zu cachen). Ich habe Werte zwischen 2000ms und 8000ms gehabt. Dann wird das Diagramm erzeugt. Ist es ein einfaches, dauert die Erzeugung 800ms, bei einem komplexeren mit vielen Daten auch schonmal 2000ms. Soll in der Summe heissen, dass diese Lösung im besten Fall nach 3500ms und im schlimmsten Fall nach 11000ms ein Diagramm zeigt.

Ich habe einige Diagramm-Bibliotheken gefunden, aber die meisten, die von der Optik in Betracht kommen, basieren auf einer anderen Bibliothek wie jQuery, MochiKit oder MooTools. Für mich persönlich sind 3500ms akzeptabel, aber 11000ms nicht. Deshalb denke ich, dass noch einiges an Forschungsbedarf auf mich zukommt.

April 14, 2010