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:

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:
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.

Hi,
ich habe dein Beispiel nachprogrammiert. Aber irgendwie scheint es bei mir Probleme mit dem Placeholder(was ich annehme, erste App) zu geben.
Denn ich bekomme immer eine weiße App, entweder spricht er auf das Flot-Plugin nicht an oder die Zeichnung ist nicht visible. Hab den Code auch mehrmals kontrolliert, scheint soweit alles mit deinem übereinzustimmen.
Ich entwickle auf Mac OS Snow Leopard 10.6.8, Xcode 3.2.3, iOS SDK 4.0.2, Titanium Developer 1.2.2 und dem Mobile SDK 1.6.2.
Vielen Dank schon mal
Michael
Hallo Michael,
wurde das “web”-Verzeichnis auch auf deinem iPhone/Simulator kopiert? Ein einfacher Test wäre es in der
chart.htmleinen Text auszugeben und zu sehen, ob WebKit die HTML Datei lädt und findet.Gruß
Sergej
Ja das habe ich gemacht, das funktioniert auch. Ich nehme an es liegt am webkit.addEventListener ich hab diesen in der app.js zwischen dem anlegen der WebView und window.add(webkit)eingefügt(für mich machte es nur dort Sinn). Meine Css datei ist relativ leer. Der nimmt doch standardmäßig die Farbe schwarz oder?
Ach ich bin so blöd, die Lösung war so einfach ich muss dem Placeholder eine Größe(width, height) in der css datei mitgeben. Trotzdem vielen Dank. Dein Tutorial bringt mich einen Schritt weiter in meinem Projekt.
Hallo Michael,
super, dass du den Fehler finden konntest! Darf ich wissen, an was du gerade baust?
Gruß
Sergej
Hast du ICQ oder Skype?
War etwas kurz heute Morgen, also erst mal Hallo. Ich schreibe eine App zum erfassen von EKG Daten. Deswegen würde ich mich gern mit der Austauschen was mit Titanium machbar ist und was nicht. Geht auch um Schnittstellen etc. Darüber hab ich auch jetzt noch nichts gefunden. Ob es möglich ist den Dock Anschluss mit Titanium anzusprechen.