terrestris GmbH & Co. KG

GeoExt 2.0

Inhalt

Vorheriges Thema

1.1. Erstellen eines Kartenfensters

Nächstes Thema

1.3. GeoExt Resources

1.2. Analyse der Karten Anwendung

Wie im vorherigen Abschnitt deomstriert, wird eine Karte die den ganzen Browser-Viewport ausfüllt generiert, indem man ein minimales HTML-Dokument, die Applikationsinitialisierung, und Interface Objekte kombiniert. Wir werden uns die einzelnen Teile nun noch einmal detailierter angucken.

1.2.1. Minimales HTML-Dokument

Weil die Mutter jedes Browserinhalts immernoch HTML ist, braucht jede Web-Appliaktion zumindest ein Basis-HTML-Dokumnt als container für den Inhalt

Wir empfehlen das Dokument als HTML5-Dokument zu deklarieren indem wir die folgende Zeile hinzufügen.

<!DOCTYPE html>

Die HTML-Seite hat keinen menschenlesbaren Inhalt, also bleibt der <body> leer. Es garantiert jedoch, dass alle Style- und Script-Resourcen geladen werden. Das passiert für gewöhnlich im <head>:

<link rel="stylesheet"
href="http://workshops.terrestris.de/libs/ext-4.2.1.883/resources/css/ext-all.css" />
<link rel="stylesheet"
href="http://workshops.terrestris.de/libs/OpenLayers-2.13.1/theme/default/style.css" />

<script src="http://workshops.terrestris.de/libs/ext-4.2.1.883/ext-dev.js"></script>

Es wird die development Version von Ext JS geladen, da diese einen autoload-Mechanismus inklusive Abhängikeits-Managment besitzt. Sollte also eine Klasse nicht definiert sein, so lädt Ext JS das entsprechende Script automatisch nach. Im Ext JS 4-Jargon wird diese Eigenschaft auch “synchronous loading” genannt. Die Klasse wird also zu dem Zeitpunkt geladen, wenn sie effektiv gebraucht wird.

GeoExt baut jedoch nicht nur auf Ext JS auf, sonder auch auf OpenLayers. Also müssen wir die OpenLayers-Bibliothek ebenfalls laden:

<!-- You should definitely consider using a custom single-file version of OpenLayers -->
<script src="http://workshops.terrestris.de/libs/OpenLayers-2.13.1/OpenLayers.js"></script>

Diese Zeilen laden die riesige Entwicklungsversion von OpenLayers. Diese Datei sollte nur ein Option für die Entwicklung sein, da die Datei selber dutzende anderer JavaScript-Dateien nachlädt.

1.2.2. OpenLayers.ProxyHost

Um auf Dateien von entfernten Severn zugreifen zu können, wie zum Beispiel beim WMS GetFeatureInfo, müssen wir einen Proxy einsetzen. Dieser umgeht die Same-Origin-Policy.

OpenLayers.ProxyHost = "/cgi-bin/proxy.cgi?url=";

1.2.3. Abhängigkeits-Management

Ext JS 4 bietet ein Abhängigkeits-Managment, das die benötigten Dateien in das DOM (Document Object Model) lädt. Das Einzige was man tun muss, ist den Root-Ordner anzugeben und die benötigten Klassen in eine “required”-Liste von Ext JS einzutragen. Dieser Mechanismus wird ebenfalls von GeoExt unterstützt.

Zuerst geben wir die Namespaces für Ext und GeoExt an und übergeben die Root-Ordner, in denen die Quellen liegen.

Ext.Loader.setConfig({
    enabled: true,
    disableCaching: false,
    paths: {
        GeoExt: "http://workshops.terrestris.de/libs/geoext2-2.0.0/src/GeoExt",
        Ext: "http://workshops.terrestris.de/libs/ext-4.2.1.883/src"
    }
});

Der autoloader unterstützt ebenfalls “asynchronous loading”. In diesem Fall werden Skripte früher geladen, im Prinzip sobald Ext.require aufgerufen wird oder wenn Klassen mit bestimmten Anforderungen (definiert mit “requires” in der Klasse) definiert werden. “Synchronous loading” funktioniert über XHR (XMLHttpRequest), während “asynchronous loading” funktioniert indem der Seite Script-tags hinzugefügt werden.

Jetzt definieren wir die Anforderungen für unsere Basis-Beispiel:

Ext.require([
    'Ext.container.Viewport',
    'Ext.layout.container.Border',
    'GeoExt.panel.Map'
]);

Weitere Abhängigkeiten der aufgeführten Dateiten werden automatisch aufgelöst.

Um herauszufinden, welche Dateien ihre Applikation wirklich benötigt, schauen Sie einfach in die JavaScript-Konsole ihres Browsers. Wenn Sie die ext-dev.js verwenden wird ihnen die Konsole jede Menge hilfreiche Informationen geben. Unter Anderem solche, die ihnen die richtigen Abhängigkeiten anzeigen. Die folgende Meldung würde (so oder ähnlich) erscheinen wenn wir keinerlei Abhängigkeiten angeben würden:

[Ext.Loader] Synchronously loading 'GeoExt.panel.Map';
consider adding Ext.require('GeoExt.panel.Map') above Ext.onReady
            ext-dev.js:7981
[Ext.Loader] Synchronously loading 'Ext.container.Viewport';
consider adding Ext.require('Ext.container.Viewport') above Ext.onReady
            ext-dev.js:7981
[Ext.Loader] Synchronously loading 'Ext.layout.container.Border';
consider adding Ext.require('Ext.layout.container.Border') above Ext.onReady
            ext-dev.js:7981

Bemerkung

Wenn Sie GeoExt verwenden profitieren Sie von allen Vorteilen, die Ext JS und OpenLayers bieten. Sie können GeoExt zu ihren bestehenden Ext JS oder OpenLayers-Applikationen hinzufügen ohne die bestehende Funktionalität zu gefährden.

1.2.4. Applikationsinitialisierung

Applikationsinitialisierung bedeutet im gegeben Zusammenhang Code, der so früh wie möglich ausgeführt wird. Dabei sorgt Ext.onReady() dafür, dass das DOM geladen ist, dass wir nicht zu früh ins DOM schreiben und, dass alle Scripte geladen wurden.

var items = [];

Ext.onReady(function() {

    var mapPanel = Ext.create('GeoExt.panel.Map', {
        border: false,
        region: 'center',
        map: {
            numZoomLevels: 19,
            projection: new OpenLayers.Projection('EPSG:900913'),
            controls: [
                new OpenLayers.Control.Navigation(),
                new OpenLayers.Control.Attribution(),
                new OpenLayers.Control.PanPanel(),
                new OpenLayers.Control.ZoomPanel()
            ]
        },
        layers: [
            new OpenLayers.Layer.WMS(
                "OWS-WMS",
                "http://ows.terrestris.de/osm/service?",
                {layers: "OSM-WMS"},
                {isBaseLayer: false}
            )
        ],
        extent: [
            1476801.5360728,6887465.251975,
            1509344.6008606,6901262.1355786
        ]
    });
    items.push(mapPanel);

    // Create a viewport including the map panel
    Ext.create('Ext.container.Viewport', {
        layout: 'border',
        items: items
    });
});

Wir erstellen ein Array items, dass die UI-Elemente unserer Applikation beinhaltet.

Der wirklich interessante Teil dieses Snippets ist der Teil, in dem wir die items dem Viewport hinzufügen. In Ext JS werden für die grundlegenden Aufgaben in den meisten Fällen konfigurierbare Objekte erstellt, anstatt richtigen Code zu schreiben. Das macht die Entwicklung schneller und einfacher. Die Items interagieren dabei mit events und event listenern, der “Kleber” über den wir später noch sprechen.

Bevor wir uns die Items genauer anschauen werfen wir einen Blick darauf, wie wir den Viewport mit Inhalt füllen.

1.2.5. JavaScript Code der das User-Interface aufbaut

Wir haben bereits gesehen, dass der <body> des HTML-Dokuments leer ist. Alles was wir sehen wird von Ext JS hinzugefügt. Damit das funktioniert, muss das DOM der Seite bereit sein, um ihm Dinge anzuhängen. Um sicherzustellen, dass wir nicht zu früh in das DOM schreiben, bietet Ext JS den Ext.onReady() -Hook.

In unserem Beispiel, ist das User-Interface simpel. Wir erstellen nur einen neuen Ext.Viewport mit einem “border” layout. Das erlaubt es uns, den ganzen Browser mit unserer Applikation zu füllen, ohne der Seite HTML hinzuzufügen.

// Create a viewport including the map panel
Ext.create('Ext.container.Viewport', {
    layout: 'border',
    items: items
});

Dieser Ext.Viewport benutzt ein “border” layout. Dieses Layout kann items in den “regions” center, north, east, south und west haben. Verpflichtend ist dabei nur center. Die center-region nimmt dabei allen Platz ein, der von den anderen regions nicht verwandt wird. Deren Größe mit width und height angegeben werden.

1.2.6. GeoExt.panel.Map

In Ext JS 3 haben alle Konstruktoren von UI-Komponenten ein einzelnes Argument, was meistens ein Konfigurations Objekt ist. Wie alle JavaScript-Objekte, ist auch dieses Konfigurationsobjekt von geschwungenen Klammern umgeben und besteht aus key: value-Paaren.

Jetzt, mit Ext JS 4, verwendet man generell die Ext.create()-Methode, die normalerweise zwei Argumente hat: Der Klassenname der zu erstellenden Komponente als string und optional, ein vordefiniertes Konfigurationsobjekt.

So erstellt man zum Beispiel ein Map-Panel:

Ext.create('GeoExt.panel.Map', {
    // the configuration object
});

Werfen wir einen Blick auf unser Konfigurationsobjekt für die Karte:

{
    border: false,
    region: 'center',
    map: {
        numZoomLevels: 19,
        projection: new OpenLayers.Projection('EPSG:900913'),
        controls: [
            new OpenLayers.Control.Navigation(),
            new OpenLayers.Control.Attribution(),
            new OpenLayers.Control.PanPanel(),
            new OpenLayers.Control.ZoomPanel()
        ]
    },
    layers: [
        new OpenLayers.Layer.WMS(
            "OWS-WMS",
            "http://ows.terrestris.de/osm/service?",
            {layers: "OSM-WMS"},
            {isBaseLayer: false}
        )
    ],
    extent: [
        1476801.5360728,6887465.251975,
        1509344.6008606,6901262.1355786
    ]
}

Die ersten zwei Eigenschaften sind nicht GeoExt-spezifisch. region gibt die Region des Viewports an, in dem wir unsere Karte anzeigen wollen. border lässt uns kontrollieren, ob ein Außenrahmen für das UI angezeigt wird.

Bemerkung

Die folgenden Zeilen führen beide zum gleichen Ergebniss:

  • Ext.create('GeoExt.panel.Map({region: center, extent: /* ... */});
  • {xtype: "gx_mappanel", region: center, extent: /* ... */});

Alle Komponenten in Ext JS besitzen einen symbolischen Namen, der “xtype”-genannt wird. GeoExt vergibt seinen Komponenten ebenfalls einen “xtype”. Um sie von den anderen Komponenten zu unterscheiden, beginnen sie mit dem Prefix "gx_". In diesem Zusammenhang:

Die Verwendung von xtypes ist nützlich um Konfigurationen dynamisch per AJAX zu laden. In diesem Fall muss die Konfiguration JSON-kompatibel sein und darf ggf. nur simple types (number, string, boolean) beinhalten.

Die anderen Angaben sind speziell für das GeoExt.panel.Map: Anstatt eine OpenLayers.Map-Instanz zu erstellen, konfigurieren wir unter map nur einige Optionen für die Karte. extent definiert den initialen Kartenausschnitt und layers die initialen Layer. In unserer Basis-Karte wollen wir nur einen einzelnen Layer zeigen. Wie im reinen OpenLayers, tun wir dies mit einem OpenLayers.Layer.WMS-Objekt. Der einzige Unterschied ist, dass wir den Layer mit der Option {isBaseLayer: false} konfigurieren. Dies ist nicht zwingend notwendig, wir wollen später jedoch, dass der Layer im Layertree mit einer Checkbox statt einem Radiobutton angezeigt wird.

Sie haben ihre erste Applikation erfolgreich analysiert. Als nächstes wollen Wir mehr über das Entwickeln mit GeoExt lernen.