terrestris GmbH & Co. KG

GeoExt 2.0

Inhalt

Vorheriges Thema

3. WFS und GeoExt

3.1. Erstellen eines synchronisierten Grid- und Map-Views von WFS-Features

GeoExt bekommt die meisten seiner WFS-Funktionen von OpenLayers. Was GeoExt allerdings besonders macht, ist der GeoExt.data.FeatureStore. Dieser macht es uns sehr einfach, Features in einem Grid anzuzeigen. Wenn wir nur die Daten anzeigen wollen, können wir das GeoExt.data.proxy.Protocol verwenden und benötigen keinen OpenLayers.Layer.

Bemerkung

Vergessen Sie nicht die benötigten Klassen hinzuzuladen.

Ext.require([
    'GeoExt.selection.FeatureModel',
    'GeoExt.data.FeatureStore',
    'GeoExt.data.proxy.Protocol',
    'Ext.grid.column.Number'
]);

3.1.1. Vector Features in Karte und Tabelle

Wir verwenden einen OpenLayers.Layer.Vector für die Geometrien und ein Grid für die Attribute des WFS-Layers.

Fangen wir mit dem Code an, der einen WFS-Layer liest, die Attribute in einem Grid darstellt und die Selektion der Features zwischen Karte und Grid synchronisiert:

Tasks

  1. Öffnen Sie ihre map.html aus der letzten Übung in einem Editor, falls Sie dies nicht bereits getan haben. Kopieren Sie den folgenden Code und fügen ihn unmittelbar vor der Erstellung des Viewports ein.

    Ext.define('BogusModel', {
        extend: 'Ext.data.Model',
        fields: [
            // {name: 'name',  type: 'string'}
        ]
    });
    
    items.push({
        xtype: "grid",
        ref: "featureGrid",
        title: "Feature Table",
        region: "south",
        height: 150,
        sm: Ext.create('GeoExt.selection.FeatureModel'),
        store: Ext.create('Ext.data.Store', {
            model: 'BogusModel'
        }),
        columns: [],
        bbar: []
    });
    
  2. Der Code macht nicht wirklich viel. Er erstellt ein leeres Grid in der “south”-Region unserer Applikation und bereitet ein Selection-Model (sm) vor, dass wir später dazu verwenden, Karte und Grid zu synchronisieren. Fügen wir der Karte nun einen WFS-Layer hinzu und füttern das Grid mit diesen Daten. Um das zu tun, ändern wir den Store und die Spalten in der oberen Grid-Definition wie folgt:

    Ext.define('MyFeatureModel', {
        extend: 'Ext.data.Model',
        fields: [
            {name: "name", type: "string"},
            {name: "osm_id", type: "int"}
        ]
    });
    
    items.push({
        xtype: "grid",
        ref: "featureGrid",
        title: "Feature Table",
        region: "south",
        height: 250,
        selModel: Ext.create('GeoExt.selection.FeatureModel'),
        store: Ext.create('GeoExt.data.FeatureStore', {
            model: 'MyFeatureModel',
            proxy: Ext.create('GeoExt.data.proxy.Protocol', {
                model: 'MyFeatureModel',
                protocol: new OpenLayers.Protocol.WFS({
                    url: "http://ows.terrestris.de/geoserver/osm/wfs",
                    version: "1.1.0",
                    featureType: "osm-fuel",
                    maxFeatures: 20,
                    outputFormat: 'JSON',
                    featureNS: "http://terrestris.de",
                    srsName: "EPSG:900913"
                }),
                reader: Ext.create('GeoExt.data.reader.Feature', {
                    root: 'features'
                })
            }),
            autoLoad: true
        }),
        columns: [
            {header: "Name", dataIndex: "name", flex: 2},
            {header: "OSM-ID", dataIndex: "osm_id", flex: 1}
        ],
        bbar: []
    });
    
  3. Um das ganze zu vervollständingen, wollen wir nun die Geometrien der Karte hinzufügen. Kopieren Sie dazu das folgende Snippet hinter den Code, der den Viewport erstellt.

    var vectorLayer = new OpenLayers.Layer.Vector("Tankstellen WFS"),
        featureGrid = Ext.ComponentQuery.query('grid[ref="featureGrid"]')[0];
    
        mapPanel.map.addLayer(vectorLayer);
    
        featureGrid.store.bind(vectorLayer);
        featureGrid.getSelectionModel().bind(vectorLayer);
    
  4. Nach dem Sie ihre Änderungen gespeichert haben, rufen Sie die map wie gewohnt im Browser auf. Sie sollten nun die Applikation mit dem neu erstellten Grid, sowie die in orange gerenderten Geometrien sehen. Evtl. müssen sie weit herauszoomen, um die Objekte in der Karte zu sehen. Wenn Sie nun ein Feature in der Karte auswählen, wird die entsprechende Zeile im Grid markiert. Das funktioniert auch umgekehrt.

../_images/grid.png

Synchronisierte Karte und Tabelle.

3.1.1.1. Den Code verstehen

Wie wir bereits wissen, können wir ein Grid mit einem Store konfigurieren, um ihm mitzuteilen, woher er seine Daten bekommt. Dieses mal verwenden wir dazu, einen GeoExt.data.FeatureStore, den wir mit einem GeoExt.data.proxy.Protocol konfigurieren, um mit einem OpenLayers.Protocol.WFS zu kommunizieren.

Die Synchronisation der Auswahl im Grid und in der Karte, wird von einem GeoExt.selection.FeatureModel, geliefert, welches wir anstatt des Standard-Selection-Models verwenden:

selModel: Ext.create('GeoExt.selection.FeatureModel'),

Wenn wir den Vector-Layer der Karte hinzufügen, müssen wir das Selection-Model und den Store ebenfalls hinzufügen.

featureGrid.store.bind(vectorLayer);
featureGrid.getSelectionModel().bind(vectorLayer);

Beachten Sie, dass dies nicht notwendig ist, wenn der FeatureStore mit einem layer konfiguriert ist. Aber da wir den Store hier vor dem Layer erstellen, können wir dort noch nicht auf ihn zugreifen, also binden wir ihn erst später.

3.1.1.2. Bonus: Einen Filter einbauen

Leider zeigt die Anwendung derzeit nicht alle Haltestellen im Ausschnit an. Der WFS-Server stellt default-mäßig nur eine gewisse Anzahl an Features dar. Wir haben die Anzahl zudem mit “maxFeatures” auf 20 Stück limitiert. Ausserdem sind diese zur Zeit zufällig über Deutschland verteilt. Um eine für unseren Kartenausschnitt passende Auswahl an Features zu bekommen wenden wir nun einen OpenLayers.Filter.Spatial an.

Wir fügen dazu den folgenden Code oberhalb der Initalisierung des Feature-Grids ein...

var filter = new OpenLayers.Filter.Spatial({
    type: OpenLayers.Filter.Spatial.BBOX,
    value: new OpenLayers.Bounds(1476801.5360728,6887465.251975,
                                 1509344.6008606,6901262.1355786)
});

... und fügen diesen dem OpenLayers.Protocol.WFS hinzu:

protocol: new OpenLayers.Protocol.WFS({
    url: "http://ows.terrestris.de/geoserver/osm/wfs",
    version: "1.1.0",
    featureType: "osm-fuel",
    featureNS: "http://terrestris.de",
    srsName: "EPSG:900913",
    defaultFilter: filter
}),

Wenn Sie die Koordinaten im Filter, mit denen unseres Extent vergleichen, werden Sie feststellen, dass die Koordinaten identisch sind. Wir haben also nun eine, auf den Anfangsauschnitt bezogene, Auswahl an Features.