Erster Preview des GpsGallery fertig

Die Probleme mit dem Firefox erwiesen sich als systematisch. Aus irgendeinem Grund parsen Opera und IE folgenden Code anders als der Firefox:

<html>
<div id="someName" />
<script type="text/javascript">
alert(someName);
</script>
</html>

Unter IE/Opera erscheint (wenn auch wenig sinnvoller) Text, da sie automatisch die den Div-Container mit der ID someName in die Variable someName umsetzten. Der FireFox macht das nicht, dort schreit einen einfach nur das „undefined“ an.

Nachdem ich schnell meine Scripte entsprechend angepasst habe, gebe ich das erste mal meinen Code raus, diesmal noch unversioniert. Da ich noch im „ich such mir mein optimales Versionierungstool“-Prozess bin…
Sourcecodes

Erste Bugfixes beim GalleryTest

Nach dem „Release“ meines GalleryTest erschlugen mich gleich zwei Fehler von denen ich dachte, dass ich sie „nicht hätte“.

Während unter die Seite unter Localhost einwandfrei läuft, gab es Probleme wenn sie auf meinem WebServer lief.

Das erste Problem war einfach zu lösen. Unter  Opera scheint das AutoSuggest unter localhost abgeschaltet zu sein. Sobald die Seite „real“ gehostet zu werden, fuscht dieses AutoSuggest einem dazwischen. Denn es fängt die KeyUp-Events ab.  Einfach das entsprechende Attribut setzten und das Problem ist gelöst.

 <input type="text" autocomplete="off" />

Das interessantere Problem brachte mir jedoch (wär hätte es anders erwartet) der IE (v8) ein. Ich hab schon damit gerechnet das der IE und der Rest der Browser-Welt Unterschiede herausstellen. Das der IE aber CSS unterschiedlich parsed in Abhängigkeit wo die Seite aufgerufen wird, dass war mir neu.

Stein des Anstoßes war die SuggestBox. Dieser „ausgeblendete“ Div-Container sollte sich mittels z-Index über alle anderen Container legen. Das funktionierte auch so weit ganz gut, bis ich die Webseite im IE öffnete und auch nur wenn sie nicht unter localhost lief.

Das Problem scheint zu sein, dass der GoogleMaps-Container in der Hauptebene liegt, und die SuggestBox in einen anderen Container geschachtelt ist. Diesem Container ist jedoch keine „Tiefe“ zugewiesen. Nachdem ich das geändert hatte, lief die Seite auch unter dem IE einwandfrei.

Interessanter ist, dass der Firefox meine inline-Scriptes komplett ignoriert. Da werd ich nochmal hirnschmalz reinstecken…

Erster Testlauf meiner „Spielwiese“

Wie angekündigt sind meine Arbeiten an einer Galerie mit GPS-Daten so weit fortgeschritten, dass man was zeigen. Das ganze ist noch nicht perfekt. Es gibt noch einige Fehler und Performance-Lecks aber im Großen und Ganzen tut es was es soll.

Bekannte Fehler:

  • Die Suggest-Funktion scheint noch nicht unter allen Browsern so zu laufen wie sie soll…
  • Die Map-Box (GoogleMaps) beim anklicken eines Markers sieht scheiße aus, das wird noch überarbeitet
  • Das Design ansich wird noch überarbeitet.
  • Noch keine Interaktion zwischen Karte und Slider am unteren Bildrand

zu finden ist das Ganze unter:  http://raptor2101.dyndns.org/GalleryTest

Brainfuck Reloaded: OOP in JS

Objektorientiertes Programmieren ist in JS für gestandene OOPler etwas „komplizierter“. Das Member-Methoden ihren Bezug zum Objekt verlieren können ist etwas gewöhnungsbedürftig. Auch sonst ist das Thema der Sichtbarkeiten unter JS etwas gewöhnungsbedürftig. Man hat nun zwei Möglichkeiten:

  • Lernen durch Schmerzen – Trial and Error: das kann für eingefleischte OOP-ler sehr schmerzvoll werden
  • Sich über die Doku einarbeiten

Leider wird letzteres sehr schwer. Die mir bekannten Dokumentation schwanken stark zwischen „völlig belanglos“, „für Anfänger“ bis „am Thema vorbei“. Es gibt nur wenige Dokumente die das Konzept hinter JS klar darlegen. Manch ein Kritiker unterstellt das es so was bei JS nicht gibt 😉

Am besten stellt sich das OOP-Konzept von JS bei einem Vergleich dar. HIer eine Klasse im klassischen OOP alla Java, C++ oder C-Sharp

public class MyClass
{
  private string someVariable;
  
  public class MyClass(string someVariable)
  {
    this.someVariable=someVariable;
  }

  public string GetVariable()
  {
    return someVariable;
  }
}

Nun die Klasse in JS

function MyClass(someVariable){
  this.someVariable=someVariable;
}
MyClass.prototype.AlertVariable=function(){
  alert(this.someVariable);
}

Das erste was auffällt ist, dass es kein Klassen-Konstrukt wie unter Java oder CSharp gibt. Eine Klasse wird über ihren Konstruktor repräsentiert. Will man Methoden hinzufügen, so geschieht dies über den prototype. Soweit so normal und verständlich. Kommen wir nun zu den interessanten Sachen.

var myInstanz=new MyClass("SomeValue");
myInstanz.AlertVariable();
$(document).ready(myInstanz.AlertVariable);

Wer den Term „$(document)“ irritierend findet, sollte sich vorher noch mal die jQuery-Tutorials anschauen. Der normale OOP-ler würde (so er denn die Syntax versteht) erwarten, dass nun zwei mal „SomeValue“ ausgegeben wird. Führt man den JavaScript aus, kommt es nur zu einer Meldung und einem Fehlersymbol (je nach Browser). Führt man den Code im Debugger aus stellt sich schnell die Zeile „return this.someVariable;“als Fehlerquelle raus. Beim „zweiten“ Aufruf innerhalb des Events „zeigt“ der this-Operator nicht mehr auf die Instanz der Klasse sondern auf den Event-Auslöser.

Nun kann man sich einen Knoten ins Hirn machen und alles gelernte über Bord werfen und wieder „schön“ Prozedural programmieren. Damit umgeht man einen Großteil der Probleme. Es wird aber sehr schnell sehr unübersichtlich. Eine weitere Möglichkeit ist, zu tricksen. Das grundlegende Problem mit dem this-Operator lässt sich nicht lösen oder umgehen. Der man kann es nur mit anderen Strukturen „umschiffen“. Das Beispiel von Oben ein wenig umgestellt.

var myInstanz=new MyClass("SomeValue");
myInstanz.AlertVariable();
$(document).ready(function (){
  myInstanz.AlertVariable();
});

Da jetzt die Instanz der Klasse direkt angesprochen wird, funktioniert intern wieder der this-Operator wie gewohnt. Was dem verwirrten OOP-ler jetzt vollends aus der Bahn werfen dürfte, Warum zum Geier kann man aus der Subfunktion auf die Variable myInstanz zugreifen. Aber diesen Umstand verbucht man unter „nicht Fragen nur Wundern“. Leider lässt sich nicht jedes Problem so übersichtlich lösen, aber das Prinzip bleibt immer das gleiche: Der Event-Handler, der den this-Operator verbiegt wird in einem Kontext erstellt, wo die Referenz auf die Zielinstanz noch vorhanden ist (oder man stellt die Referenz her) und greift dann über die Sichtbarkeit auf diese Referenz zu. Mal ein komplexeres Problem.

function MyClass(someDomObject,displayText){
  this.alertVariable=function(){
    alert(displayText);
  };

  var alertVariable=this.alertVariable;

  $("a",someDomObject).each(function(){
    $(this).click(function(){
      alertVariable();
    });
  });
}

MyClass.prototype.AlertVariable=function(){
  this.alertVariable();
}

Ok was wird hier getrieben. Der Klasse MyClass wird ein DOM-Object übergeben. Dieses Objekt kann alles sein, auch eine XML-Node, Hauptsache es ist von jQuery verarbeitbar. Der Ausdruck $(„a“,someDomObject) selektiert jedes a-Element (<a href=““ />) und mittels der each-Funktion wird für jedes selektierte Objekt die übergebene Funktion (die inplace gebaut wird) ausgeführt. Für die ich jetzt abgehängt hab, das ganze in C-Sharp. Das würde dann so aussehen (mit LINQ).

public class MyClass
{
  private string someVariable;

  public class MyClass(XmlNode someDomObject, string displayText)
  {
    var selectedNodes = someDomObject.SelectNodes("a");

    //LINQ & Delegate
    selectedNodes.ForEach(DoSomething)

    //klassisch
    foreach(XmlNode node in selectedNodes)
    {
      DoSomething(node);
    }
  }
  
  private void DoSomething(XmlNode node)
  {
    //Die XmlNode-Klasse hat in .NET kein Click(ed)-Event ich spar mir das mal
  }
  
  public void AlertVariable()
  {
    MessageBox.Show(someVariable);
  }
}

Wirklich „brainfucked“ ist dann die „Zeile“: $(this).click(function() {}); Der this-Operator zeigt dabei nicht mehr auf die Klasse, wie man beim ersten lesen vielleicht vermuten würde, sondern „konsequenterweise“ auf das abzuarbeitende Element. In CSharp entspricht das dem Übergabewert der Funktion DoSomething. Wem sich das Konzept mal eröffnet hat, wird schnell feststellen, dass die Sichtbarkeiten wie in C/C++ gelöst wurden (einschließlich globaler Objekte). Nur dieser this-Operator ist halt ein wenig frickelig. Deswegen sieht dieser Block so „scheiße“ aus:

this.alertVariable=function(){
  alert(displayText);
};
var alertVariable=this.alertVariable;

Erst wird eine Funktion/Delegetate auf eine Funktion angelegt. Diese wird in der der Member-Variable „alertVariable“ referenziert. Auf diese kann aber innerhalb der Each->Click funktion nicht zugegriffen werden. Da der this-Operator ja umgebogen wird. Daher kopiert man die Referenz in eine lokale Variable, die wiederum ist überall verfügbar…

Wenn man diesen Spaß auf die Spitze treiben will, schreibt mal einfach sechs bis sieben Ebenen wo jeder this-Operator auf ein anderes Ziel zeigt (z.B. ein XmlDokument mit n-Ebenen die alle einzeln abgearbeitet werden müssen;)). Dass ist dann Brainfuck-delux.

Die Entwicklung geht weiter…

Ich hab lange nichts von mir hören lassen. Ich hab die Zeit effektiv genutzt um mich der Galerie zu widmen. Eigentlich wollte ich letztes Wochenende eine Vorabversion ins Netz stellen, hab mich dann aber doch dagegen entschieden. Die Performance war mies und entscheidende Features haben gefehlt.

Heute hab ich fast alle meine Wunschfeatures zusammengeschaltet, so dass ich im Laufe der nächsten Tage mal eine Testversion zeigen kann. Was habe ich bis jetzt umgesetzt:

  • Eine Simple Goole-Map auf der ein Pfad angezeigt wird (nicht weiter wild)
  • Auf der Map werden Markierungen angezeigt, wo welche Bilder geschossen worden ist. Da meine Galerien jedoch meist viele Bilder beinhalten (>200 Bilder) musste ich hierbei etwas geschickter vorgehen:
    • nur Bilder die sich in dem sichtbaren Kartenbereich befinden werden überhaupt dargestellt (bzw an den Client übertragen)
    • Bilder die zu nah bei einander sind, so dass sie sich, aufgrund der Kartenauflösung/Zoomstufe, überlappen würden, werden zusammengefasst.
  • Es gibt eine Schnellauswahl der Bilder über eine Eingabe von Tags. Diese Tags werden dabei aus den Bildern extrahiert. Für die Eingabe steht die von Google bekannte „Suggest“-Funktion zur Verfügung (mit allen Annehmlichkeiten der Maus und Tastatursteuerung)
  • Zusätzlich gibt es einen Slider am unteren Rand, wie ihn Lightroom zur Verfügung stellt
  • Das ganze ist mittels C#/ASP.NET entwickelt und voll Mono tauglich

Noch ein wenig Feintuning und ich kann am WE geht eine Testseite online.

Brainfuck die zweite

Nach zwei Wochen hab ich so langsam den Dreh raus. Wenn man sich mal auf die Widrigkeiten von JavaScript eingelassen hat und JQuery nutzt kommt man recht gut vorran. Ohne JQuery geht es zwar auch, aber dann hat man mehr schmerzen als ohne 😉

Was hab ich nun die letzten zwei Wochen so getrieben. Nun ja erstmal grundlegend JavaScript am Beispiel „Wie interagiere ich mit GoogleMaps“ gelernt/eingearbeitet. Das „Erfahrene“ dann so in ein ASP-Steuerelement umgesetzt, dass man so halbwegs aus dem Codebehind die Steuerung übernehmen kann.

Es stellte sich schnell herraus, dass der aktuelle „Arbeitsprozess“ des ASP AJAX-Frameworks (Atlas) nicht dafür gemacht ist eigene Steuerelemente zu unterstützen die mehr Interaktion benötigen, als „clicked“-Handler. Ein vollständiger PostBack (ob nun mittels JavaScript oder ohne) ist ein wenig zu viel, wenn man nur ein paar Bilder bewegen will.

Nach dieser Erkenntnis und dem Empfinden, dass mein bisheriger JS-Code scheiße aussieht, hab ich nochmal alles überarbeitet und JQuery eingesetzt. Der Code ist zwar immer noch kaum „wartbar“ aber immerhin schön schlank.

Die Servercontrols wurden mit einem eigenen ResponseHandler versehen. Sie agieren völlig losgelöst vom eigentlichen ASP-Seiten-Lebenzyklus. Mittels eines eigenen RequestHandlers werden sie parallel zum den normalen Requestes mit Daten versorgt. Dahinter stehen selbstgeschrieben Bibliotheken die eine die Verarbeitung von GPS-Daten und Exif-Infomrationen erleichtern. Und das alles läuft unter Mono 😉

In den folgenden Tagen werde ich mal eine Beispielseite online stellen.

GeoTagging, Bilder und Galerien

Nunja seit einer Woche hab ich schon nichts mehr von mir hören lassen. Das hat einen guten Grund. Ich hab mein Urlaub beendet und nunja meine geschossenen Bilder gesichtet und gleich die Kamera eingeschickt… blöde Geschichte… egal kommen wir zum interessanten.

Wenn man Bilder über den Zeitstempel mit einer GPS-Strecken-Datei korreliert bekommt man was … ja was eigendlich. In erster linie mal gar nichts. Es Bedarf erst irgendwelcher Tools, meistens online, um diese getaggten Informationen auszuwerten. Da ich jedoch keine Lust hab meine Bilder auf Flickr oder ähnlichem Online zu stellen hab ich mich mal auf die Suche nach brauchbarer Software gemacht.

Das einzig sinnvolle was ich fand war GeoTag. Dies Programm stellt mittels GoogleMaps schön anschaulich dar, wo die Photos geschossen wurden. Leider sind die sonstigen Funktionen was die Präsentation betrifft unterirdisch. UNd auch sonst findet sich wenig was zumindestens Tags verarbeitet und gleichzeitig Bilder auf ner Karte darstellt, ohne dass dabei die Bilder gleich auf irgendwelchen Fremdrechnern gehostet werden…

Nun gut, seit einer Woche schlage ich mich mit JavaScript, GoogleMaps und erweiterten EXIF-Infos rumm. Selbst ist der Programmierer. Den ersten Protypen einer ASP anwendung die Daten aus Bilder ausließt und samt GPX Datei auf einer GoogleMaps Karte darstellt hab ich schon. Ich werde näheres dazu in Kürze veröffentlichen.