Category: javascript

Dragonfly: Opera’s Antwort auf Firebug

authorOmar | 7. Mai 2008

Opera hat die erste Alpha der Debug-Werkstatt Dragonfly herausgebracht. Obwohl der Browser Opera noch immer ein closed-source Projekt ist, wird Dragonfly unter der BSD-Lizenz veröffentlicht.

Opera pitches Dragonfly as a tool for debugging web pages and web applications. Its feature set includes a JavaScript error console and command line, a debugger, and CSS and DOM inspectors. The current release (out today, and requiring Opera 9.5 beta 2) is an alpha, but they’ve announced planned improvements for the future. Notably, write access to CSS and DOM properties is still to come, as well as support for non-desktop versions of Opera.

Noch reicht die Funktionalität nicht an die von Firebug, aber das soll noch kommen..

The initial alpha release is just the beginning. Opera Dragonfly has a fully featured road map, including support for editing of CSS, JavaScript and the DOM, a single window mode, improved JavaScript thread handling, XHR and HTTP monitoring, improved keyboard navigation, and translation into a number of languages.

Dynamic Sorting of HTML-tables via XSLT

authorOmar | 27. August 2006

[lplang lang="english"]

More than eight months ago - actually on newyear’s eve - i was sitting at my PC trying to find a solution to a question Ursula asked in wer-weiss-was1 about sorting data in HTML-tables without having to reconnect to the server. At the end of the night, i was able to make a suggestion in form of a XSL Transformation that was changed dynamically with a javascript function whenever the user selected a table header.

Looking back..

The suggested solution does work fine, but it has some flaws that make it rather hard to implement in a normal webdesign-case.

The most fatal problem about the solution was, that the data that had to be sorted would be loaded after the document was loaded. That way, someone running without javascript enabled, wouldn’t be able to see the document correctly. Also, search engines such as googlebot won’t be able to see any of the data presented.

Of course one could attach the table and delete it via javascript. This would mean that javascript-disabled clients would still be able to see the data and javascript-enabled clients would be able to dynamically sort the table. But this way one would load the data in the table twice. This could be a problem when one has to display a big table or if creating the table costs too much CPU-time on the server.

Another problem of the implementation is the inflexibility of the script. It is made exactly for the specific data and has to be changed for any other data resulting in a huge amount of coding required.

Alternative suggestion

In the latest iX-magazine there is an article about sorting HTML-tables via Javascript (Sept. 2006 | “Auf der Stelle: HTML-Tabellen mit Javascript sortieren”, p. 142). The author Christian Kirsch suggests saving all the data of a given table into an array and sorting it via array.sort(col) using the standard sorting algorithms of javascript.

In fact, he solves every problem i had with my implementation, but i still think, that it is more elegant to use XSL-Transformations, since they can be expanded to include filtering-capabilities which still can be implemented using normal javascript, but at the cost of huge code. Plus if one wants to sort by more than one column, the pure javascript-solution would be even bigger whereas the XSL-solution will only expand by one statement per sortcolumn or filter-criteria!

New Suggestion

Here’s my new suggestion: XSL-Sort for HTML-Tables

The basis of the implementation was a normal HTML-table. It has to be XHTML-compatible, as shown in the example below:

<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>4</td>
<td>Hans Jürgen</td>
</tr>
<tr>
<td>1</td>
<td>Otto Quatsch</td>
</tr>
</tbody>
</table>

Note that i’m using thead and tbody - elements! They are important or else i’d have to rewrite the table header every time i resort the table. Now to sort this markup-fragment i will use this xslt-file:

<xsl:stylesheet
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0″>
<xsl:template match=”tbody”>
<html>
<body>
<table>
<tbody>
<xsl:for-each select=”tr”>
<xsl:sort select=”td[1]“ />
<tr>
<xsl:for-each select=”td”>
<td class=”{@class}”><xsl:value-of select=”current()” /></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

The select-statement in the sort-element is the one that has to be changed programatically depending on which column-header the user selects. For more explanation on the select-statement refer to this wonderful reference.

Coding

The code is pretty much straight forward, though it could be irritating because it’s not very well structured. To begin with, the engine searches for any table inside the document and then installs eventlisteners in every column head and marks the column heads with a non-standard attribute colnumber. This is the easiest way i found to know which column to sort on. This is done in install_sorters() and install_sorter(mytable) respectively.

The onclick-Event of every column header calls the function sortfor(). Here, the colnumber-attribute of the event target (some column header) is read and used to change the xsl-DOM. It needs to only change the element xsl:sort:

// sort for column #
var mysort = xslt.getElementsByTagNameNS(XSLNS, “sort”).item(0);
mysort.setAttributeNS(null,”select”,”td["+colnumber+"]“);
// Perhaps sort as number??
colclass=col.getAttributeNS(null,”class”);
if (colclass.lastIndexOf(’sorttypenumber’)>-1)
mysort.setAttributeNS(null,”data-type”,”number”);
else mysort.removeAttributeNS(null,”data-type”);
// Alternating Sort order
sortorder=”ascending”;
if (table.getAttributeNS(null,”sortedfor”)==colnumber) {
if (table.getAttributeNS(null,”sortorder”)==”ascending”)
sortorder=”descending”;
}
mysort.setAttributeNS(null,”order”,sortorder);
// Now save the sort-parameters as attributes of table
table.setAttributeNS(null,”sortedfor”,colnumber);
table.setAttributeNS(null,”sortorder”,sortorder);

As can be seen in the last two lines, the script saves the sort-information as attributes in the table-element. This information is then used to determine which way to sort the next time the user selects a column header. Furthermore, it has to be able to differentiate between numeric and string columns, since sorting numbers as though they were strings would result in a weird row order. To determine the data-type of a specific column, the script reads the class-attribute of the column header. It expects that numeric columns are marked with the class “sorttypenumber”.

After that, there isn’t much to do: running the xsl-processor and replacing the old tbody-element with the sorted data.

// run the xslt-processor
processor.importStylesheet(xslt);
result = processor.transformToDocument(data.getElementsByTagName(”tbody”).item(0));
result=result.getElementsByTagName(”tbody”).item(0);
// and replace old data with sorted data.
var temp=table.getElementsByTagName(”tbody”).item(0);
table.replaceChild(result,temp);

Problems with Internet Explorer

As usual Microsoft has it’s own implementing theory that says:

Thou shall not be compatible!

I don’t want to get into details concerning the changes i had to make for the sake of Internet Explorer, but two points i’d like to mention:

  1. The eventlistener of the object window wasn’t willing to work. I tried the method attachEvent as well as simply assigning the event-function to the attribute onload. Both didn’t get me, where i wanted to be. But the attachEvent method can be set at the end of the main HTML-document. Strangely, not at the end of the javascript-file, which - logic would suggest - would be parsed after the main file..
  2. Replacing existing nodes with a string of xml-elements did seem to be rather easy, but it wasn’t, especially since i only need a fragment of the markup the xsl-processor outputs! I ended up running a regular expression search for the tbody-fragment inside the outerHTML-attribute of the online-table and replacing it with the xml-fragment from the processor. Just have a look at the code (around line 80) and you’ll see how much trouble i had inserting that small portion of markup.. If anyone has a better solution, please don’t hesitate to post a comment!

Conclusion

It is possible to have data, that is already loaded and parsed into the HTML-document resorted and - hopefully in the near future - filtered or otherwise manipulated without having to put too much into coding special-case functions. The script can easily be implemented into any existing page and make every table on that page sortable. At this time it requires the table to be xhtml-compatible and to have column headers. If some columns have to be sorted numerically, the script requires a special class to be given to the column header.

Of course, this script isn’t meant for badly designed sites where the element-placement is done via fake tables. It’s also not meant for tables with spanning cells (colspan or rowspan), since they will throw the xsl-transformation off-balance. Either way, it shouldn’t destroy any of the two cases, as long as they don’t employ table headers (and most don’t)..

Have fun and please do comment!

[/lplang]
[lplang lang="deutsch" default="default"]

Schon vor mehr als 8 Monaten habe ich mich mit der dynamischen Sortierung von HTML-Tabellen beschäftigt und einen Lösungsvorschlag gemacht, mit dem sich erreichen lässt, dass in einer Tabelle nach einem beliebigen Feld sortiert werden kann.

Die Grundidee besteht darin, die Tabellendaten als XML-Daten nachzuladen und durch eine XSL-Transformation laufen zu lassen, die letztere sortiert. Bei Anwahl einer Spaltenüberschrift wird ein Script ausgeführt, das die XSL-Anweisungen verändert und die Transformation erneut laufen lässt und die “alten” Daten mit den sortierten ersetzt.

Nachteile

Der grösste Nachteil der bisherigen Lösung ist die Abhängigkeit des Nutzers von Javascript. Bei abgeschaltetem Javascript ist die Tabelle - und damit die Daten - nicht zu sehen. Während das für den normalen Benutzer relativ erträglich ist, da die meisten Nutzer Javascript eingeschaltet haben, ist das für eine Suchmaschinenoptimierung kontraproduktiv, da Such-Bots wie googlebot keine Scripte ausführen und somit nicht die Daten in der Tabelle indexieren können.

Natürlich kann man die Daten als statische Tabelle im HTML einfügen und bei eingeschaltetem Javascript die xml-Daten nachladen, allerdings bedeutet das die doppelte Übertragungsmenge und kann bei grösseren Tabellen eine starke Verlangsamung der Seite zur Folge haben.

Weiterhin ist das Script nicht sehr flexibel, da es für eine spezielle Tabelle geschrieben ist und für andere neu geschrieben werden müsste. Das bedeutet widerum viel mehr code als vertretbar wäre..

Array-Alternative

In der neusten iX findet sich ein Artikel mit dem Titel “Auf der Stelle - HTML-Tabellen mit Javascript sortieren”, der dasselbe Problem bespricht und einen Vorschlag zur Lösung macht (Sept. 2006, S. 142). Der Author Christian Kirsch schlägt vor, die Daten einer beliebigen Tabelle komplett in ein Array einzulesen, darin mittels der Methode .sort(col) zu sortieren und danach wieder in die Tabelle zu schreiben.

Während dieser Vorschlag alle von mir angesprochenen Nachteile meines scripts löst - es ist nicht auf eine Tabelle bezogen und die Daten sind bei abgeschaltetem Javascript sichtbar - glaube ich, dass die Lösung im Vergleich nicht sehr elegant ist und möglicherweise langsamer als die xsl-gestützte Sortierung. Weiterhin ist es mittels xsl möglich das Script weiter aufzuwerten, um etwa nach bestimmten Suchkriterien zu filtern oder nach mehr als einer Spalte zu sortieren, während das mittels javascript zwar auch möglich, aber mit sehr komplexem code verbunden ist.

Neuer Ansatz

Hier ist mein neuer Vorschlag: XSL-Sort for HTML-Tables

Die Grundlage für die Umsetzung bildet eine standardmässige HTML-Tabelle, die über Spaltenüberschriften und xhtml-kompatibles tbody-Element verfügt.

<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>4</td>
<td>Hans Jürgen</td>
</tr>
<tr>
<td>1</td>
<td>Otto Quatsch</td>
</tr>
</tbody>
</table>

Es bietet sich an, auch das thead-Element zu benutzen, um den Überschriften-Teil der Tabelle vom Datenteil syntaktisch zu trennen.

Um diesen Teil der Seite zu sortieren, kann man sich eines xsl-Fragments bedienen, wie er weiter unten aufgelistet ist:

<xsl:stylesheet
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0″>
<xsl:template match=”tbody”>
<html>
<body>
<table>
<tbody>
<xsl:for-each select=”tr”>
<xsl:sort select=”td[1]“ />
<tr>
<xsl:for-each select=”td”>
<td class=”{@class}”><xsl:value-of select=”current()” /></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Interessant ist hier die Benutzung der select-Anweisung im sort-Element. Das sort-Element bezweckt, dass die Daten nach dem Inhalt der ersten Spalte sortiert werden. Die Zahl in den eckigen Klammern gibt somit direkt die zu sortierende Spalte an. Für mehr Informationen zur sort-Anweisung, empfehle ich die folgende Seite: XPath Expression Syntax.

Javascript

Zu allererst muss dafür gesorgt werden, dass alle Spaltenüberschriften einen Eventlistener verpasst bekommt, der erst bei Selektierung dieser Überschrift die Sortierung einleitet. In den Funktionen install_sorters() und install_sorter() werden in allen Spaltenüberschriften in allen Tabellen diese Eventlisteners installiert und weiterhin über ein nicht-standard-Attribut colnumber die Spaltennummer übergeben, die für die Sortierung gebraucht wird.

Die onclick-Events der Spaltenüberschriften rufen die Funktion sortfor() auf. Darin wird das Attribut colnumber ermittelt und für die Manipulation der xsl-Transformation xsl:sort verwendet.

// Nach Spalte # sortieren
var mysort = xslt.getElementsByTagNameNS(XSLNS, “sort”).item(0);
mysort.setAttributeNS(null,”select”,”td["+colnumber+"]“);
// Als Zeichenfolge oder als Zahl sortieren?
colclass=col.getAttributeNS(null,”class”);
if (colclass.lastIndexOf(’sorttypenumber’)>-1)
mysort.setAttributeNS(null,”data-type”,”number”);
else mysort.removeAttributeNS(null,”data-type”);
// Aufsteigend oder absteigend sortieren?
sortorder=”ascending”;
if (table.getAttributeNS(null,”sortedfor”)==colnumber) {
if (table.getAttributeNS(null,”sortorder”)==”ascending”)
sortorder=”descending”;
}
mysort.setAttributeNS(null,”order”,sortorder);
// Nun noch einige Sortier-Parameter in die zugehörige Tabelle speichern..
table.setAttributeNS(null,”sortedfor”,colnumber);
table.setAttributeNS(null,”sortorder”,sortorder);

Wie man den letzten zwei Zeilen ansehen kann, werden weitere zwei weitere Parameter in die DOM gespeichert. Beide dienen der Ermittlung bei der nächsten Selektion einer Spaltenüberschrift, in welche Richtung sortiert werden soll (absteigend oder ansteigend). Die Speicherung in Element-Attribut sichert eine gänzliche Abkoppelung des Scripts vom tatsächlichen HTML.

Weiterhin verwendet das Script das Klasse-Attribut der Spaltenüberschriften für die Ermittlung des Datentyps der Spalte. Wenn sich ein Eintrag “sorttypenumber” in der Klassenangabe wiederfindet, dann ist die Spalte numerisch zu sortieren!

Der Schluss bildet die Verarbeitung der xsl-Anweisungen und das Austauschen der “alten” Daten gegen die neu sortierten Daten. Beides findet sich ähnlich schon im letzten Vorschlag wieder.

// run the xslt-processor
processor.importStylesheet(xslt);
result = processor.transformToDocument(data.getElementsByTagName(”tbody”).item(0));
result=result.getElementsByTagName(”tbody”).item(0);
// and replace old data with sorted data.
var temp=table.getElementsByTagName(”tbody”).item(0);
table.replaceChild(result,temp);

Probleme mit dem Internet Explorer

Wie sooft braut sich Microsoft mit ihrer Nicht-Umsetzung von w3c-Vorgaben ihre eigene Suppe. Ich möchte nicht in die Details einsteigen, sondern nur zwei Punkte ansprechen:

  1. Der Eventlistener des Objekts window wollte partout sich nicht ordentlich setzen lassen. Ich habe es über attachEvent, sowie über die statische Vergabe des Attributs onload versucht - ohne Erfolg. Die attachEvent-Methode hat aber funktioniert, als ich sie ans Ende der HTML-Datei brachte. Der gesunde Menschenverstand sagt doch aber, dass die Javascript-Datei (die ja erst noch eingebunden werden müsste) später ausgeführt wird als Skripte in der HTML-Datei..
  2. Die Ersetzung der alten Nodes mit den sortierten Daten war im IE nicht so einfach wie ich annahm, besonders da ich nur einen Teil der von der xsl-Engine zurückgegebenen Zeichenfolge einbinden möchte. Für Lacher wird also meine eher eigenartige Lösung sorgen. Einfach mal um Zeile 80 herum schauen..

Schlussfolgerung

Es lassen sich bereits geladene und eingebundene Tabellen im nachinein ohne weitere Verbindung zum Server und ohne besonders angefertigte Funktionen neu sortieren und - hoffentlich in naher Zukunft- filtern oder anderweitig manipulieren. Das Skript lässt sich relativ leicht für andere Seiten verwenden und kann idealerweise durch einfache Einbindung und Beachten der Grundstrukturen dafür sorgen, dass alle Tabellen auf einer beliebigen Seite sortierbar werden.

Natürlich wird das Skript versagen, wenn es auf Seiten angewandt wird, die aus weit verschachtelten Tabellen als Designersatz bestehen. Auch wird die Sortierung von Tabellen mit zusammengefassten Zellen (über die Attribute colspan oder rowspan) nicht ohne weiteres funktionieren. Auf der anderen Seite sollten beide Sorten von Tabellen nicht weiter vom Skript zerstört werden, solange sie nicht über Spaltenüberschriften verfügen.

Viel Spass und bitte kommentieren..

[/lplang]


  1. roughly who-knows-what, a very nicely structured german internet forum []

Dynamic visualization of network-graphs II

authorOmar | 4. April 2006

In the first part i’ve introduced a way of aligning interconnected nodes in an optimal way. The methods used had some flaws that i discussed in the last article about dynamic network-graphs. In this article i would like to expand and improve the previous script.

What are you talking about??

First, here is the demo as it stands to date:
buildnetwork.svg

Usage

Starting off, you will be presented a cleared area of 500×500 px2 with only one main node in it. This one is created at initialization and is pretty heavy so that it works as anker for the network later on and is marked with a star (*). To draw a new node, just click anywhere in the bordered area. Since any two objects are driven away from each other (had to do that to preserve a minimum distance between two nodes), you will immediately see the two nodes getting into opposite corners (the initial one slower). You can go on and draw other nodes. Eventually you’ll need to connect two nodes. To do that, click on the first node, hold down the mousebutton and drag the cursor to any other node. On release a connection is created between the two nodes and they start to attract each other.

Repeat the steps as long as you like (and your memory holds!). The network connections are optimized the whole time and the effect of the algorithms can be viewed immediately. That also means, that some CPU-power is allways being used.

Deployment

Right now, the code is really not easy (or nice) to deploy. The objects are way too much interdependent with the outer scripts. Global variabels, object references, callback functions and eventhandlers aren’t in a way that would allow a smooth deployment. If anybody still wants to get started, three global references are of great importance: drawg is the global reference to the container element which will contain the node objects. conng is the one for the connections and bg is the bg-container, that will hold the interactive connection line. Also the general SVGDoc (ownerDocument) has to be referenced.

After that, simply creating a netfield-object (o = new netfield();) and adding some nodes (o.addnode("*",250,250,100);) does the trick. o.draw() gets the svg representation of the nodes and connections in the field o.getforces(); calculates the forces between them and o.domoves(); moves the nodes accordingly.

What’s this all for?

I’m planning on using netfield for two purposes (at least). First i’d like to test some navigation usage. If it is possible to cache nodes and show them only on mouseover of their parent node (or some connected node), then a dynamic tree navigation can be achieved. The main advantage of this sort of navigation is that it can adjust to any sort of space given to it.

The second usage case is the visualization of website statistics. Theoretically it is possible to track any user (or ip) from the beginning with the referrer through all the websites he visited including pages he went back to and visited other pages from (fork). The problem is that this information can’t be easily displayed. A list isn’t appropiate for two reasons: 1. You can’t display a fork-like route, 2. if you want to display more than one user’s way through a website, you’d really need that extra dimension. With this approach it would be a color for each user showing his trails. This way one can easily see which page is linking to which other page most frequently.. Mind you, i didn’t finish the digging-code to get those information (specially following the path of one user) out of the database, but i will worry about that, when the time comes..

What’s missing yet?

In the next version i’d like to be able to simply put a netfield-element inside the svg-document and let the code worry about the rest (creating the node, connection and temporary-layers and all the eventhandlers). Also, i’d need to create a namespace for the netfield-element. What would be really nice, is a structure that would allow the creation of nodes with svg-elements. It would look something like this:

<net:field x="0" y="0" height="500px" width="500px" connectivity="true">
<net:node id="someid" x="30" y="50" mass="2" />
<net:node id="someid2" x="50" y="74" mass="1" />
<net:connection id="somecon" node1="someid" node2="someid2" length="100"
minlength="5" />
</net:field>

Wouldn’t that be cool?? To get things really going, the netfield()-object would also create a buttons-layer containing some navigational and editorial buttons. For example one should be able to zoom in and out or delete nodes or connections or even change the size of the field interactively. Looking forward to that..

What is behind the curtains?

Three objects stand at the core of the script:

  1. node():

    The code representation of any given node. In the svg-code, the node-group has an attribute “nodeindex”, that references the actual node-object. Similarly, the node-object has a property called .svgObject that references the svg-code of a node.

    methods

    • .draw() - builds the svg-code and draws the actual node-representation. If you want to change the representation (e.g. box rather than circle), then this is the place. The method creates an g-element that contains the whole representation. The g-element is translated to the place, where the node has to be, so every element inside it has to be centered around 0,0. Also at the time being, the method draws the force-vector, which is stored inside the object .forcesvgObject. At the time being, this method needs a globally declared variable drawg which is a reference to a container-element in which the nodes are drawn.
    • .toString() - standard method to print object-type. Simply returns “[NetNode Object]“. This method is used, when doing something like this:
      mynode=new node();
      alert(mynode); //alerts [NetNode Object]
      

    properties

    • .id - some id for the node. This can be shown in .draw(). The initial id can be set with the first argument of node().
    • .parent - reference to parent element. Should be a netfield()-object, but this isn’t being checked right now.
    • .svgObject - contains reference to the actual svg-group representing the node.
    • .forcesvgObject - contains reference to the svg-group representing the force vector
    • .mass - Mass of the node. This influences the velocity of the node. Can be set with the fourth argument of node()

    objects

    • .pos - contains the position information. .pos.x and .pos.y are the actual coordinates at which the node is located. This information can be defined when creating the node-object by setting the second (x) and third (y) argument.
    • .force - The force-object contains the x- and y-components of the calculated force-vector.
  2. connection():

    The connections between nodes are modeled as an object each. This object is pretty straight forward:

    methods

    • .draw() - Draws the connection. Needs a globally declared reference to a container-element (conng). This container-element should be behind the drawg-element!
    • .toString() - again the standard method to print object-type. Simply returns “[NetConnection Object]”.

    properties

    • .parent - Reference to parent element.
    • .svgObject - Reference to svg object
    • .nodes - Array containing the references to the two nodes that are connected via this connection.
    • .weight - not used right now, but this should be similar to the force of the spring holding the two connected nodes together.
    • .clength - nominal length of the connection.
    • .minlength - minimal length of the connection. Not implemented yet!
  3. netfield():

    This is the actual field that contains all the calculations. In a more advanced version, this object will isa be able to create all the needed svg-objects to begin with. Right now it contains the following:

    methods

    • .toString() - yet again the standard method to print object-type. Simply returns “[Network Object]”.
    • .addnode - add a node-element to the field. This creates a node-element and places a reference in the object .nodes. (Propably better to place it under .nodes.add()..) It takes the same arguments as the node()-object and returns a reference.
    • .addconnection - creates a connection between two nodes with a specified weight and nominal length (arguments in that order). The method checks to see if the two nodes are connected first and returns a reference to the connection when created.
    • .draw() - calls all the draw-methods of every node()- and connection()-subelements.
    • .getforces - calculates the forces on all the nodes and stores it inside the node().force-objects.
    • .domoves - moves all the nodes according to the forces that are saved in the .force-objects. Returns a movement-value, to determine the amount of movement in the whole field.
    • .getforcedet - Returns the sum of all forces inside the field.
    • .getNodeById - As the name suggests, this method searches for the (first) node with the specified id. Returns false, if nothing found.
    • .setconnectivity - Little Tricky: The connectivity is the ability of the nodes inside a field to accept new and interactive connections (using the mouse as described above). If the supplied argument is true then on each node-object an eventhandler for mousedown is registered. At the time being, the eventhandler had to be an absolute reference (o.startconn), i’m trying to find out, how to get the name of the fieldobject-reference (wip)
    • .startconn, .drawnewconn, .stopconn and .clearnewconn - eventhandlers for the interactive connecting-process.

    properties

    • .mindistance - Minimal distance of any two nodes in the field. Not implemented yet.

    objects

    • .nodes - collection of node()-objects.
    • .connections - collection of connection()-objects.

Nachgelegt: Pulldown für Internet Explorer

authorOmar | 18. März 2006

Im vorigen Artikel habe ich eine Vorgehensweise beschrieben, wie Pull-Down-Menüs über einfache CSS-Anweisungen erreicht werden können und ganz ohne javascript. Leider funktioniert das im Internet Explorer nicht, vor allem da dieser bis auf das a-Element keinen hover-Effekt anwenden kann. Ich habe den Internet Explorer Nutzern geraten, sich einen ordentlichen Browser anzuschaffen, wozu ich immer noch stehe. Trotzdem konnte ich kaum schlafen vor Mitleid und in Gedanken an all die Nutzer, denen nun wichtige Informationen entgehen werden ( ;) ), nur weil sie nicht in der Lage sind, Firefox, Opera oder ähnliche Browser zu installieren.

Nun ist der Bau eines javascript-basierten Pull-downs nicht so schwer, findet er sich doch auf diversen Seiten. Ich wollte aber die CSS-Technik nicht vollkommen ausser Acht lassen (für die Browser, die das benutzen können), ausserdem könnte ich den Quelltext nicht leiden, wenn überall onmouseover und onmouseout steht.

Lösung

Es wird nun eine Script-Datei eingebunden, die zuallererst ein onload-Event einträgt, falls der Browser das all-Objekt kennt (das trifft meines Wissens nur auf den Internet Explorer zu..). In der aufgerufenen Funktion init() werden alle die Elemente gesucht, die der Klasse ‘menu’ angehören. Die Funktion getElementsByClassName habe ich mir bei TM abkopiert. Die Funktion geht alle Elemente im Dokument durch und listet alle die Elemente im Ausgabearray, die im Class-Attribut die gesuchte Klasse enthalten. Danach wird für jedes dieser Elemente ein onmousover-Event eingetragen. Da das Script nur für den Internet Explorer gedacht ist, brauche ich mich mit den verschiedenen Funktionen der verschiedenen Browser nicht rumzuschlagen. Ein .attachEvent('onmouseout',collapse); fügt die entsprechende Funktion ein. Wichtig anzumerken wäre, dass mit attachEvent der aufzurufenden Funktion (collapse) keine Argumente übergeben werden können!

In expand() wird das ul-Element gesucht und dessen display-Attribut auf ‘block’ gesetzt, andersherum in collapse() wird das display-Attribut wieder auf ‘hidden’ gesetzt.

Einige Anmerkungen

Um das Ausfahren aus dem Menüelement ein wenig sauberer hinzubekommen, musste ich einen padding-Abstand einfügen (1px). Ausserdem hat der Internet Explorer Probleme mit dem herunterreichen von Ereignissen zu haben, denn bei einem Link-Element innerhalb eines h2-Elements wird das onmouseover-Script des Letzteren scheinbar nicht ausgeführt. Das Script schaut also, ob das h2-Element (das für das Ausfahren des Menüs zuständig ist) ein a-Element enthält und falls ja, dann wird das onmouseover-Event auf das a-Element gesetzt. Dementsprechend muss die Funktion expand() weiter ‘oben’ im Elementenbaum suchen können:

if (evt.parentNode.getElementsByTagName("ul").length>0)
evt.parentNode.getElementsByTagName(”ul”).item(0).style.display=’block’;
else if (evt.parentNode.parentNode.getElementsByTagName(”ul”).length>0)
evt.parentNode.parentNode.getElementsByTagName(”ul”).item(0).style.display=’block’;

Tja, das wars auch schon fürs Erste. Wieder: Kommentare, Erfahrungsberichte u.ä. immer her damit!

Nächste Präsentation

authorOmar | 6. März 2006

Ich muss in nächster Zeit mindestens zwei Vorträge halten (Projektarbeiten) und muss dementsprechend die Präsentationen dazu vorbereiten. Natürlich habe ich keine Lust Microsoft Powerpoint zu verwenden. Allerdings ist die Alternative ‘OpenOffice Impress’ not very impressive.. Dafür habe ich aber eine Lösung gefunden, die mir gefällt: HTML-Präsentationen!

HTML Slidy ist ein Präsentationsscript, das aus einer speziell angefertigten HTML-Seite eine Präsentation macht. Zum Design wird CSS benutzt, javascript regelt die Navigation. Man kann sogar über Anchor-Marker (wie ‘#[3]‘) eine bestimmte Folie verlinken. Die Vorteile liegen auf der Hand:

  • kostengünstig
  • bekannte Technik, eben HTML und CSS zum Design
  • wenigster Aufwand (notfalls tut’s der vorinstallierte Internet Explorer)
  • kleine Dateigrösse (je nach dem wie gross die enthaltenen Bilder sind..)
  • Der Einbau von SVG-Grafiken mit zusätzlichen Animationsoptionen bietet sich gewissermassen an
  • jedes kleine Detail ist leicht änderbar
  • Die einzige mir bekannte Präsentationsalternative, in der der Author die Option besitzt, notfalls ein wenig scrollen in einer Folie einzubauen, wenn mal ein zusätzlicher Punkt benötigt wird
  • Die Präsentationen sind im Anschluss sehr leicht online zu stellen

Ausserdem gibt es die Weiterentwicklung S5, die ein paar mehr Optionen bietet. Was noch fehlt wäre das Einblenden von Video-Sequenzen, aber das sollte über ein Object-Element machbar sein. Die nächsten Präsentationen werden ein Spass..

BMW wird von Google gestraft

authorOmar | 5. Februar 2006

Wozu braucht sich gerade BMW auf solche Tricks zu stützen, um in Google weiter oben aufzutauchen? Naja, jedenfalls hat Google reagiert und die deutschen Seiten des Autobauers mit einem Pagerank 0 versehen.

Davon mal abgeshen, hat sich jemand mal den Quelltext der Seite angeschaut? Wie schlecht muss man programmieren, um einen solchen Salat auszuspucken? Nur als Schmankerl:

var x=21;
var z=Math.random();

if(z > 0.33 && z <=0.66){
x=4;
}
else if(z > 0.66) {
x=0;
}

/*if(z > 0.14 && z <=0.28){
x=1;
}else if(z > 0.28 && z <=0.43){
x=2;
}else if(z > 0.43 && z <=0.57){
x=3;
}else if(z > 0.57 && z <=0.71){
x=4;
}else if(z > 0.71 && z <=0.85){
x=5;
}else if(z > 0.85){
x=6;
}
if(z > 0.16 && z <=0.33){
x=2;
}else if(z > 0.33 && z <=0.5){
x=3;
}else if(z > 0.5 && z <=0.66){
x=4;
}else if(z > 0.66 && z <=0.83){
x=5;
}else if(z > 0.83){
x=6;
}
if(z > 0.33 && z <=0.66){
x=5;
}else if(z > 0.66){
x=8;
}*/

// x=0;no randomizing, homepage

Muss denn diese ganze “Wahrscheinlichkeitsrechnung” unbedingt ständig mitübertragen werden? Für Nicht-Prgrammierer: Ab /*if(z > 0.14 && z <=0.28){ ist alles bereits auskommentiert, d.h. ist ohne Belang. Aber das ist noch nicht einmal das einzige Problem. Der Webdesigner von BMW scheint die Idee einer HTML-Seite nicht begriffen zu haben. So funktioniert die Seite nur mit eingeschaltetem Javascript, was für einen kommerziellen Auftritt einer Katastrophe gleichkommt. Ausserdem werden Bots nach Inhalt suchen, bis sie kotzen müssen vor lauter Arrays, onmouseovers, DOM-Zugriffen und Tabellen wo das Auge reicht, durch die sich ein Durchhangeln erst gar nicht lohnt, da sie eh’ keinen Inhalt enthalten. Kein Wunder, dass die Seite zu Tricks greifen muss, um überhaupt auf dem allgemeinen Radar sichtbar zu werden…

Deshalb mein Tip an BMW: Feuert den Webdesigner, schafft euch einen fünfjährigen an, der die Grundelemente von HTML kennt und lasst ihn euren Auftritt planen.

z4 Coupe

Wen BMW keinesfalls feuern sollte ist der Designer des neuen z4-Coupé. Erinnert mich zwar im Heck (zumindest in der Seitenansicht) sehr an Porsche, aber was soll’s, sieht gut aus! Wer nicht überzeugt ist, sollte sich das Video auf Autoblog.com anschauen. Achja, und zum Vergleich kann man sich natürlich jederzeit meinen Roadster anschauen ;).

Dynamic visualization of network-graphs

authorOmar | 11. Januar 2006

For the past couple of weeks i’ve been trying to find out how to visualize my referrer statistics visually. It would be a network nodes, each connected to some of the other nodes, via edges. The requirement of the visualization-engine would be the following:

  • nodes must hold a specified distance to other nodes.
  • interconnected nodes should try to get as close together as possible (they should still abide by the first rule)
  • connections can be weighted, so that those with a higher weight would be preferred to be shorter
  • each node has a mass - A higher mass results in slower motion and more stability.
  • nodes can be fixed (not moving)
  • the space used by the entire network should be minimized

To see an Example of my own implementation so far:

node1.svg
To view the example either Firefox >1.5 or Internet Explorer + ASV is requiered. To run the demo, just press the button “Press me”. Pressing it again will refine the result.

I have been reading many articles, technical websites and documentations trying to find a “simple” algorithm that could meet the requirements. To begin with i didn’t want to be able to drag the nodes around. It would be sufficient to just have them aligned according to the requirements at startup.

Yet the easiest way i found is to model the nodes as physical masses and the edges as springs. Then one would have to run a couple of iterations, until the system proves to be stable. During each iteration for every node the resulting force would be calculated and it would be decided by how much and in what direction the node would travel.

What’s still missing?

much!!

  • not-connected nodes could overlap (i’m still thinking about which way to go to detect collision, because i don’t want the whole network to wedge on one node not “getting through”.
  • though edge-weighting is already implemented, it’s not easy to alter it after creating the edge.
  • edge-length should be the length outside the node, so that one can have bigger and smaller nodes, without having to redefine the edge-length every time.
  • some optimization required, so that the code would run smoothly with any given number of nodes/connections. Of course that is limited to memory and cpu-power, but at this time there is still much, one can get out of the system(s)
  • i wasn’t able to set a timeout, so that the system would update itself automatically. have to look into it again..

For Coders: this is my first test of object-oriented programming via JavaScript, so don’t be too harsh with me please. But Please do comment on the code, so that hopefully it gets better with the time. And of course i’d like to hear what anyone else does with the code..

Elf der Woche

authorOmar | 7. Januar 2006

In ihrer Neujahrsansprache hat Bundeskanzlerin Merkel die Weltmeisterschaft und ihre Auswirkung auf Deutschland hervorgehoben. Sabbeljahn hat den Vorschlag gemacht, im WM-Jahr wöchentlich die “Elf der Woche” mit einem geeigneten Platz auf dem Spielfeld auszuzeichnen.

meine ‘elf der woche’ nominiert personen des oeffentlichen lebens, die sich durch ausserordentliche handlungen, aeusserungen, gesten oder aehnliches hervorgetan haben. es steht zwar zu fuerchten, dass sich vor allem unsere politisch handelnden zur nominierung draengeln werden. dennoch ist das rennen auch fuer schauspieler, saenger, sportler, promis (oder solche, die es sein wollen), wissenschaftler, ganze institutionen - ja vielleicht sogar auch andere blogger - offen.

Ich hatte in den Kommentaren vorgeschlagen, das ganze grafisch zu machen und hab mich auch schon aufgemacht, dieses Ziel zu erreichen. Rausgekommen ist eine svg-Engine, die (mittels AJAX) eine XML-Datei (gefüllt mit den Wochenelf) auswertet, und die Spieleraufstellung zeigt.

Wochenelf der KW1 2006

Bereits jetzt lassen sich die komischsten Spieleraufstellungen einstellen und Auswechselspieler eintragen. Später sollen die Erklärungen zu den “Leistungen” der einzelnen “Spieler” bei mouseover erscheinen, mitsamt Links zu Artikeln, die darüber berichten. Viel Spass. Zur interaktiven Spieleraufstellung der aktuellen Woche kommt man hierüber:

Elf der Woche

XML, XSLT und Tabellen sortieren

authorOmar | 1. Januar 2006

Im wer-weiss-was-Forum wurde die Frage gestellt, wie man am einfachsten eine längere Liste automatisch sortieren lassen könnte. Die einfachste Möglichkeit (ganz ohne Programmierung gehts nicht) wäre natürlich, die Daten in eine Datenbank zu speichern und mittels SQL-Befehl orderby auszulesen. Dazu muss allerdings eine Datenbank auf dem Server installiert sein und eine serverseitige Sprache (CGI, ASP oder PHP) verfügbar sein. Wenn eines hiervon nicht vorhanden ist oder wenn der Aufwand für eine Tabelle zu groß ist, empfiehlt sich die Speicherung der Daten in XML-Format und der Abfrage und Darstellung mittels XSLT und XPath.

Vorab einmal mein Lösungsvorschlag:

XSLT dynamic order list

XML

XML steht für “Extensible Markup Language” und ist ein Standard zur Speicherung von Daten jeglicher Art in Form einer Baumstruktur. Ein Beispiel:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<catalog>
	<cd>
		<title>Empire Burlesque</title>
		<artist>Bob Dylan</artist>
		<country>USA</country>
		<company>Columbia</company>
		<price>10.90</price>
		<year>1985</year>
	</cd>
</catalog>

Beispiel sehen

XSLT

Mit XSLT lassen sich XML-Dokumente auf relativ einfache Art und Weise formatieren. Wer sich mit XSLT vertraut machen will, kann sich das Tutorial auf w3schools.com antun. Für mein Beispiel reicht eine kleine Auswahl der Daten und eine Sortierung

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
	<h2>My CD Collection</h2>
	<table border="1">
	<tr bgcolor="#9acd32">
		<th align="left">Title</th>
		<th align="left">Artist</th>
		<th align="left">Country</th>
		<th align="left">Company</th>
		<th align="left">Price</th>
		<th align="left">Year</th>
	</tr>
	<xsl:for-each select="catalog/cd">
	<xsl:sort select="artist" order="ascending" />
	<tr>
		<td><xsl:value-of select="title"/></td>
		<td><xsl:value-of select="artist"/></td>
		<td><xsl:value-of select="country"/></td>
		<td><xsl:value-of select="company"/></td>
		<td><xsl:value-of select="price"/></td>
		<td><xsl:value-of select="year"/></td>
	</tr>
	</xsl:for-each>
	</table>
</xsl:template>
</xsl:stylesheet>

Um eine XSL Transformation auf eine XML-Datei anzuwenden, gibt es die Möglichkeit, einen entsprechenden Eintrag in die XML-Datei vorzunehmen:

<?xml-stylesheet type="text/xsl" href="struct.xsl"?>

Beispiel ansehen (Firefox macht das scheinbar nicht ohne weiteres mit…)

XSL Transformation in Laufzeit

Es gibt ausserdem die Möglichkeit, XSL Transformationen in Laufzeit einer Internetseite auf eine beliebige XML-Struktur anzuwenden. Dazu bietet der Internet Explorer die Methode transformNode() an. Im Beispielcode werden sowohl die XML-Daten als auch die XSLT-Struktur nach Laden der Seite nachgeladen.

	if (isIE) {
		// Load XML
		xml = new ActiveXObject("Microsoft.XMLDOM");
		xml.async = false;
		xml.load("data.xml");

		// Load XSL
		xsl = new ActiveXObject("Microsoft.XMLDOM");
		xsl.async = false;
		xsl.load("struct.xsl");

		// Transform
		output = xml.transformNode(xsl);
	}

Firefox unterstützt weder das ActiveXObject noch die Methode transformNode(). Dafür hat Firefox (und Mozilla natürlich) das Objekt XSLTProcessor:

	if (isNav) {
		//for mozilla/netscape
		processor = new XSLTProcessor();
		xslt = document.implementation.createDocument("", "", null);
		xslt.async = false;
		xslt.load("struct.xsl");
		processor.importStylesheet(xslt);

		src_doc = document.implementation.createDocument("","", null);
		src_doc.async = false;
		src_doc.load("data.xml");

		result = processor.transformToDocument(src_doc);
		xmls = new XMLSerializer();
		output = xmls.serializeToString(result);
	}

Dynamische Sortierung mittels XML und XSLT

Was noch fehlt ist eine Methode, die die XSLT-Struktur in Laufzeit zu verändern, so dass nach einem anderen Parameter sortiert wird. Dazu soll die Funktion changeorder() da sein. Da die XSLT-Struktur genauso wie XML durchsuchbar ist, können hier die Funktionen getElementsByTagName() von Nutzen sein. Eine Besonderheit: Da xsl in einem anderen Namespace abgelegt ist, muss eigentlich die Funktion getElementsByTagNameNS() verwendet werden. Firefox unterstützt sie (GetElementsByTagNameNS(XMLNS, "sort");), Internet Explorer natürlich nicht! Im Internet Explorer übergibt man einfach die Namespace mit dem Tagname: GetElementsByTagName("xsl:sort"); Wenn man nun das sort-Element referenziert hat, muss nur noch das Attribut select auf den neuen Wert geändert werden und die Transformation erneut auf die noch gespeicherten Daten angewandt werden. Um abwechselnd aufwärts und abwärts zu sortieren, entscheidet die Funktion decide anhand der vorherigen Sortierung.

Conclusion

Das wars dann auch schon. Die einmal geladenen Daten können im Browser sooft wie nötig umsortiert werden, ohne dass eine Verbindung zum Server vonnöten wäre. Das ganze kann noch erheblich komplexer werden, indem nach bestimmten Feldern gesuch oder gar gruppiert wird. Ich hoffe Ursula vom wer-weiss-was-Forum kann hiermit was anfangen..

Was lernen wir: Statt Geister zu verjagen, kann man seine Zeit recht gut nutzen, indem man sich neue Techniken anschaut. Mit XSLT werd ich mich noch ein Weilchen beschäftigen, mal sehen, was man noch alles damit machen kann…

Nachbarschaftskarte

authorOmar | 5. Dezember 2005

Angeregt durch Schwerdtfegers Kommentar zu GeoURL und durch den Eintrag zum RSS-Feed von Geo-Url, habe ich mich heute daran gesetzt, eine Karte meiner “Umgebung” - zumindest der registrierten - zu zeichnen. Das Resultat von drei Stunden harte Arbeit, 2 Liter Saft und sämtlichen zerrissenen Haaren lässt sich auf der Nachbarschaftsseite begutachten.

Zur Vorgehensweise:

Auf der Seite direkt ist ein iframe, der die eigentliche svg-Datei enthält. In der svg-Datei sind sowohl statische Elemente (das Bullauge), wie auch dynamische. Zu den statischen kann später auch eine Hannoverkarte im Hintergrund gehören..

Die Daten der Nachbarschaftsseiten sollten idealerweise direkt von GeoUrl geladen werden. Diese bieten einen anpassbaren RSS-Feed für die eigene Seite:

http://geourl.org/near/?p=http://www.toomuchcookies.net/;format=rss10

Da aber firefox sicherheitshalber keine Verbindung mit einem anderen als den aufgerufenen Server aufnimmt und mein Webhoster offensichtlich die Durchschleife von Daten durch meine Domain ausgeschaltet hat (fopen(url)), muss ich zur Zeit mit einer statischen Version des Feeds vorliebnehmen, die ich heruntergeladen hatte. Das ist vor allem für diejenigen Hannoveraner wichtig, die sich bei GeoUrl anmelden, sich aber auf meiner Karte nicht wiederfinden..

AJAX zum Abrufen der Daten:

AJAX steht für Asynchronous JavaScript and XML. Die Grundidee besteht darin, nicht bei jeder Aktion des Nutzers die komplette Internetseite neuzuladen, sondern nur die Daten nachzuladen, die man zur Aktualisierung der Ansicht braucht.

Im Vorliegenden Fall will ich die Ansicht zwar nur einmal ändern, aber dadurch, dass ich die Daten erst lade, nachdem die restliche Seite vollständig geladen ist, muss der Nutzer nicht so lange warten, bis er irgendwas sehen kann.

Um die Daten nachzuladen benötigt man das Objekt XMLHTTPRequest. In Firefox ist das Objekt eingebaut und kann über new XMLHttpRequest(); aufgerufen werden. Im Internet Explorer ist das Objekt nur über das ActiveX-Objekt aufrufbar: new ActiveXObject("Microsoft.XMLHTTP");. Erstaunlicherweise ist das der einzige Unterschied. Die Methoden und Eigenschaften der beiden Objekte sind identisch! Um Asynchron arbeiten zu können, benötigt XMLHTTPRequest eine callback-Funktion, die aufgerufen wird, wenn sich der Status der Übertragung ändert. Über die Eigenschaft onreadystatechange kann diese Funktion übergeben werden.

requestobj.open('GET', url, true);
requestobj.onreadystatechange=XMLHTTPResult;
requestobj.send(null);

Das Event onreadystatechange wird bei jeder Änderung aufgerufen, nicht nur, wenn die Daten vollständig geladen sind. Deshalb wird der aktuelle Status am Anfang der Callback-Funktion XMLHTTPResul abgefragt. Eine “4″ bedeutet, dass alle Daten verfügbar sind.

function XMLHTTPResult() {
if (requestobj.readyState==4) {
extractitems(requestobj.responseXML);
}
}

Nun wird der Funktion extractitems die geparsten und somit leicht durchsuchbaren XML-Daten übergeben. extractitems geht alle “item”-Tags durch und extrahiert die wichtigen Daten (”title”,”link”,”longitude”,”latitude”). Hierbei muss man sich auf DOM-low-level-Methoden beschränken, damit das Script sowohl unter IE als auch unter Firefox läuft.

Z.B. kann man unter Firefox ein DOM-Objekt folgendermassen ansprechen:
var items = node.getElementsByTagName("item")[0];
Damit wird das erste Objekt unter node mit dem TagName “item” referenziert. Dies ist aber leider unter IE nicht machbar. Deshalb muss man die etwas umständlichere Schreibweise
var items = node.getElementsByTagName("item").item(0);
verwenden. Eine weitere Besonderheit stellen Namespace-Tags dar. Im GeoUrl-Feed werden folgende Elemente verwendet:
<geourl:longitude>9.75700000000002</geourl:longitude>
<geourl:latitude>52.395</geourl:latitude>

In einem Browser werden diese Elemente über node.getElementsByTagName("geourl:longitude")... im anderen über node.getElementsByTagName("longitude")... angesprochen.

AJAX mit SVG:

Ich bin mir bisher nicht im Klaren darüber, “wer” beim Zusammenspiel zwischen IE und ASV die Scripte ausführt. Ich habe es nämlich nicht hinbekommen aus einem SVG-Objekt heraus das ActiveX-Objekt anzusprechen! Kein ActiveX-Objekt, kein XMLHTTPRequest!

Es gibt - wie so meist - auch hier ein workaround: ASV unterstützt die Funktion getURL, die zwar SVG-Standard sein soll, aber nicht von Firefox unterstützt wird… D.h. das Script muss erkennen, ob das XMLHTTPRequest-Objekt vorhanden und ansprechbar ist, wenn nicht, dann müssen die Daten über einen Callback der Funktion getURL in geparste XML-Daten umgewandelt werden:

if (requestobj) {
requestobj.open(’GET’, url, true);
requestobj.onreadystatechange=XMLHTTPResult;
requestobj.send(null);
} else if (window.getURL){
getURL(url,getURLCallback);
}

Glücklicherweise gibt es die Funktion parseXML, die diese Aufgabe ohne zu murren erlädigen kann:


function getURLCallback(data) {
if (data.success) {
var node = parseXML(data.content, document);
extractitems(node.firstChild);
}
}

Auch hieraus werden die Daten an die Funktion extractitems weitergegeben.

Ausblick:

Das Entwickelt sich ja fast zu einer Doktorarbeit…

  • Einige SVG-Funktionen sind noch nicht implementiert. Vor allem Firefox hinkt noch stark hinterher. Zu diesen Funktionen gehört etwa getSubStringLength, womit sich die tatsächliche Länge des Textes feststellen lässt. Zur Zeit muss man damit leben, dass die Hintergrund-Box, die mit dem Titel der Seite erscheint immer gleichlang ist.
  • Zur Positionierung der Punkte benutze ich den Abstand zu meinem Standort mit einer Konstante multipliziert. Diese Konstante müsste irgendwann einen klaren Bezug zur Vergrösserung haben.
  • Der GeoUrl-RSS-Feed sollte zwar gecacht werden (um die Seite nicht unnötig zu belasten und gleichzeitig um den Seitenaufbau zügig zu halten), allerdings sollte eine direkte Live-Anbindung möglich sein, damit die Daten nicht ständig manuell auf dem Laufenden gehalten werden müssen.
  • Ausserdem liesse sich über ein Parameter die maximale Entfernung einstellen. Dieser Parameter fliesst in die URL zum GeoUrl-Feed, wie auch in die Vergrösserungskonstante.
  • Eine tatsächliche Karte im Hintergrund ist wünschenswert…

An dieser Stelle noch einmal einen herzlichen Dank an Bernd Ott von der php-Usergroup Hannover, der erst kürzlich einen informativen Vortrag über AJAX gehalten hat und mein Interesse geweckt hat.