[Commits] r2247 - in sandbox/foss4g2010/src/doc: . basics layout wfs
commits at geoext.org
commits at geoext.org
Fri Jul 30 14:32:45 CEST 2010
Author: pgiraud
Date: 2010-07-30 14:32:45 +0200 (Fri, 30 Jul 2010)
New Revision: 2247
Added:
sandbox/foss4g2010/src/doc/wfs/
sandbox/foss4g2010/src/doc/wfs/editing.png
sandbox/foss4g2010/src/doc/wfs/editing.rst
sandbox/foss4g2010/src/doc/wfs/grid.png
sandbox/foss4g2010/src/doc/wfs/grid.rst
sandbox/foss4g2010/src/doc/wfs/index.rst
sandbox/foss4g2010/src/doc/wfs/layer.png
sandbox/foss4g2010/src/doc/wfs/layer.rst
sandbox/foss4g2010/src/doc/wfs/wfst.png
sandbox/foss4g2010/src/doc/wfs/wfst.rst
Removed:
sandbox/foss4g2010/src/doc/layout/toolbar.rst
Modified:
sandbox/foss4g2010/src/doc/basics/dissect.rst
sandbox/foss4g2010/src/doc/basics/map.rst
sandbox/foss4g2010/src/doc/basics/map1.png
sandbox/foss4g2010/src/doc/index.rst
sandbox/foss4g2010/src/doc/layout/index.rst
sandbox/foss4g2010/src/doc/layout/layout.rst
sandbox/foss4g2010/src/doc/layout/legend.rst
sandbox/foss4g2010/src/doc/layout/tree.rst
sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst
Log:
OpenGeo workshop update, more work to come
Modified: sandbox/foss4g2010/src/doc/basics/dissect.rst
===================================================================
--- sandbox/foss4g2010/src/doc/basics/dissect.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/basics/dissect.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -113,11 +113,18 @@
layout: "fit",
items: [{
xtype: "gx_mappanel",
- layers: [new OpenLayers.Layer.WMS(
- "Imagery",
- "/geoserver/ows?",
- {layers: "bluemarble"}
- )]
+ layers: [new OpenLayers.Layer.WMS("Global Imagery",
+ "http://maps.opengeo.org/geowebcache/service/wms", {
+ layers: "bluemarble"
+ }, {
+ buffer: 0,
+ visibility: false
+ }
+ )],
+ extent: new OpenLayers.Bounds(
+ 143.83482400000003, -43.648056,
+ 148.47914100000003, -39.573891
+ )
}
}
@@ -140,6 +147,9 @@
If we want our MapPanel to zoom to the first layer's maximum extent, there is
nothing else we need to configure.
+The last property ``extent`` is here to tell the OpenLayers map to zoom to the
+given extent when initialized.
+
.. note::
The following two notations are equivalent:
Modified: sandbox/foss4g2010/src/doc/basics/map.rst
===================================================================
--- sandbox/foss4g2010/src/doc/basics/map.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/basics/map.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -32,17 +32,17 @@
<html>
<head>
<title>GeoExt Map Window</title>
-
+
<script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext/ext-all.js"></script>
<link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css" />
<script src="openlayers/lib/OpenLayers.js"></script>
-
+
<script type="text/javascript" src="geoext/lib/GeoExt.js"></script>
-
+
<script type="text/javascript">
Ext.BLANK_IMAGE_URL = "ext/resources/images/default/s.gif";
-
+
Ext.onReady(function() {
new Ext.Window({
title: "My Map Window",
@@ -52,10 +52,14 @@
items: [{
xtype: "gx_mappanel",
layers: [new OpenLayers.Layer.WMS(
- "Imagery",
- "/geoserver/ows?",
- {layers: "bluemarble"}
- )]
+ "Tasmania",
+ "/geoserver/wms?",
+ {layers: "tasmania"}
+ )],
+ extent: new OpenLayers.Bounds(
+ 143.83482400000003, -43.648056,
+ 148.47914100000003, -39.573891
+ )
}]
}).show();
});
Modified: sandbox/foss4g2010/src/doc/basics/map1.png
===================================================================
(Binary files differ)
Modified: sandbox/foss4g2010/src/doc/index.rst
===================================================================
--- sandbox/foss4g2010/src/doc/index.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/index.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -21,11 +21,10 @@
Add some standard GeoExt widgets such as Layer Tree, LegendPanel, as well
as User Extension such as WMSBrowser.
Put them all in a well organized interface using a ViewPort.
+
+:ref:`geoext.wfs`
+ Create a WFS-T editor with a synchronized map and table view.
-:ref:`geoext.features`
- Learn how to load features from a WFS service, display them in a grid and
- in the map, then synchronize feature selection between grid and map.
-
:ref:`geoext.editing`
Enable feature editing.
@@ -34,5 +33,5 @@
basics/index
layout/index
- features/index
+ wfs/index
editing/index
Modified: sandbox/foss4g2010/src/doc/layout/index.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/index.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/index.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -18,6 +18,5 @@
Add a Tree to Manage the Map Layers <tree>
Create a LegendPanel <legend>
- Plug a WMSBrowser <wmsbrowser>
Organize the Application Interface Using a ViewPort <layout>
- Add a Toolbar to the MapPanel <toolbar>
+ Plug a WMSBrowser <wmsbrowser>
Modified: sandbox/foss4g2010/src/doc/layout/layout.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/layout.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/layout.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -3,3 +3,113 @@
Organize the Application Interface Using a ViewPort
===================================================
+.. code-block:: javascript
+
+ Ext.onReady(function() {
+ var layers = [
+ new OpenLayers.Layer.WMS("Global Imagery",
+ "http://maps.opengeo.org/geowebcache/service/wms", {
+ layers: "bluemarble"
+ }, {
+ buffer: 0,
+ visibility: false
+ }
+ ),
+ new OpenLayers.Layer.WMS("Tasmania State Boundaries",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_state_boundaries"
+ }, {
+ buffer: 0
+ }
+ ),
+ new OpenLayers.Layer.WMS("Water",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_water_bodies",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }
+ ),
+ new OpenLayers.Layer.WMS("Cities",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_cities",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }
+ ),
+ new OpenLayers.Layer.WMS("Tasmania Roads",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_roads",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }
+ ),
+ // create a group layer (with several layers in the "layers" param)
+ // to show how the LayerParamLoader works
+ new OpenLayers.Layer.WMS("Tasmania (Group Layer)",
+ "/geoserver/wms", {
+ layers: [
+ "topp:tasmania_state_boundaries",
+ "topp:tasmania_water_bodies",
+ "topp:tasmania_cities",
+ "topp:tasmania_roads"
+ ],
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0,
+ // exclude this layer from layer container nodes
+ displayInLayerSwitcher: false,
+ visibility: false
+ }
+ )
+ ];
+
+ var mappanel = new GeoExt.MapPanel({
+ extent: new OpenLayers.Bounds(
+ 143.83482400000003, -43.648056,
+ 148.47914100000003, -39.573891
+ ),
+ map: new OpenLayers.Map({allOverlays: false}),
+ layers: layers,
+ region: 'center'
+ });
+
+ new Ext.Viewport({
+ layout: 'border',
+ items: [mappanel]
+ });
+ });
+
+.. code-block:: javascript
+
+ {
+ xtype: 'tabpanel',
+ region: 'west',
+ width: 250
+ }
+
+
+.. code-block:: javascript
+
+ activeTab: 0,
+ items: [tree]
+
+.. note::
+
+ Don't forget to add a title to the tree panel.
+ Also no need to render the panel, the rendering will be done by Ext while doing the layout.
+
+Repeat the same operation for legendPanel. You should now have a column on the left with two tabs.
+
+.. code-block:: javascript
+
Modified: sandbox/foss4g2010/src/doc/layout/legend.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/legend.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/legend.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -2,3 +2,14 @@
Create a LegendPanel
====================
+
+.. code-block:: javascript
+
+ var legendPanel = new GeoExt.LegendPanel({
+ defaults: {
+ labelCls: 'mylabel',
+ style: 'padding:5px'
+ },
+ bodyStyle: 'padding:5px'
+ });
+ legendPanel.render(document.body);
Deleted: sandbox/foss4g2010/src/doc/layout/toolbar.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/toolbar.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/toolbar.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -1,5 +0,0 @@
-.. _geoext.layout.toolbar:
-
-Add a Toolbar to the MapPanel
-=============================
-
Modified: sandbox/foss4g2010/src/doc/layout/tree.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/tree.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/tree.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -2,3 +2,120 @@
Add a Tree to Manage the Map Layers
===================================
+
+We want several layers: base and overlay layers.
+Modify the ``layers`` array to match the following.
+
+.. code-block:: javascript
+
+ var layers = [
+ new OpenLayers.Layer.WMS("Global Imagery",
+ "http://maps.opengeo.org/geowebcache/service/wms", {
+ layers: "bluemarble"
+ }, {
+ buffer: 0,
+ visibility: false
+ }
+ ),
+ new OpenLayers.Layer.WMS("Tasmania State Boundaries",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_state_boundaries"
+ }, {
+ buffer: 0
+ }
+ ),
+ new OpenLayers.Layer.WMS("Water",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_water_bodies",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }
+ ),
+ new OpenLayers.Layer.WMS("Cities",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_cities",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }
+ ),
+ new OpenLayers.Layer.WMS("Tasmania Roads",
+ "/geoserver/wms", {
+ layers: "topp:tasmania_roads",
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0
+ }
+ ),
+ // create a group layer (with several layers in the "layers" param)
+ // to show how the LayerParamLoader works
+ new OpenLayers.Layer.WMS("Tasmania (Group Layer)",
+ "/geoserver/wms", {
+ layers: [
+ "topp:tasmania_state_boundaries",
+ "topp:tasmania_water_bodies",
+ "topp:tasmania_cities",
+ "topp:tasmania_roads"
+ ],
+ transparent: true,
+ format: "image/gif"
+ }, {
+ isBaseLayer: false,
+ buffer: 0,
+ // exclude this layer from layer container nodes
+ displayInLayerSwitcher: false,
+ visibility: false
+ }
+ )
+ ];
+
+Also, since we don't want all layers to be considered as overlays we need to set
+options for our map.
+Add the following to your `GeoExt.MapPanel` configuration object:
+
+.. code-block:: javascript
+
+ map: new OpenLayers.Map({allOverlays: false})
+
+.. code-block:: javascript
+
+ var treeConfig = [{
+ nodeType: "gx_baselayercontainer"
+ }, {
+ nodeType: "gx_overlaylayercontainer",
+ expanded: true
+ }, {
+ nodeType: "gx_layer",
+ layer: "Tasmania (Group Layer)",
+ isLeaf: false,
+ // create subnodes for the layers in the LAYERS param. If we assign
+ // a loader to a LayerNode and do not provide a loader class, a
+ // LayerParamLoader will be assumed.
+ loader: {
+ param: "LAYERS"
+ }
+ }];
+ var tree = new Ext.tree.TreePanel({
+ border: false,
+ loader: new Ext.tree.TreeLoader({
+ applyLoader: false
+ }),
+ root: {
+ nodeType: "async",
+ children: treeConfig
+ },
+ rootVisible: false
+ });
+ tree.render(document.body);
+
+Don't forget to add a title to the tree panel
+
+
+
Modified: sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst 2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -3,3 +3,9 @@
Plug a WMSBrowser
=================
+
+
+.. code-block:: javascript
+
+
+
Added: sandbox/foss4g2010/src/doc/wfs/editing.png
===================================================================
(Binary files differ)
Property changes on: sandbox/foss4g2010/src/doc/wfs/editing.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/foss4g2010/src/doc/wfs/editing.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/editing.rst (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/editing.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,186 @@
+.. _geoext.wfs.editing:
+
+Editing Featuers and Their Attributes
+=====================================
+
+We will now enhance our application by making the layer and its attributes
+editable, and using WFS-T to commit changes.
+
+Making Layer and Grid Editable
+------------------------------
+
+Let's modify our application to allow for editing feature geometries and
+attributes. On the layer side this requires replacing the SelectFeature
+control that the FeatureSelectionModel automatically creates with a
+ModifyFeature control. On the grid side, we have to replace the GridPanel with
+an EditorGridPanel, provide editors for the columns, and reconfigure the
+FeatureSelectionModel a bit.
+
+.. rubric:: Tasks
+
+#. Open :file:`wfs-editor.html` in your text editor. Add a ModifyFeature
+ control to the map and activate it. To do so, find the mapPanel
+ definition, and add the following code just below:
+
+ .. code-block:: javascript
+
+ var modifyControl = new OpenLayers.Control.ModifyFeature(layer);
+ mapPanel.map.addControl(modifyControl);
+ modifyControl.activate();
+
+#. Reconfigure the FeatureSelectionModel to use the internal SelectFeature
+ control of the modifyControl, and enable ``singleSelect`` (meaning that
+ only one feature can be selected at a time, which makes sense for
+ editing). The FeatureSelectionModel instantiation should now look like
+ this:
+
+ .. code-block:: javascript
+
+ sm: new GeoExt.grid.FeatureSelectionModel({
+ selectControl: modifyControl.selectControl,
+ singleSelect: true
+ }),
+
+#. Replace the GridPanel with an EditorGridPanel and configure editors for
+ the columns: TextField by default, and NumberField for the
+ "# of Facilities" column. This is how the whole gridPanel definition
+ should look now:
+
+ .. code-block:: javascript
+
+ var gridPanel = new Ext.grid.EditorGridPanel({
+ title: "Feature Table - Manhattan (NY) landmarks",
+ region: "center",
+ viewConfig: {forceFit: true},
+ store: store,
+ sm: new GeoExt.grid.FeatureSelectionModel({
+ selectControl: modifyControl.selectControl,
+ singleSelect: true
+ }),
+ cm: new Ext.grid.ColumnModel({
+ defaults: {
+ sortable: true,
+ editor: {xtype: "textfield"}
+ },
+ columns: [
+ {header: "Name", dataIndex: "LANAME"},
+ {header: "CFCC", dataIndex: "CFCC"},
+ {header: "Land", dataIndex: "LAND"}
+ ]
+ })
+ });
+
+Adding "Create" and "Delete" Buttons
+------------------------------------
+
+We are already able to modify existing features, but we also want to be able
+to add and remove features. To add features, we will use an
+`OpenLayers.Control.DrawFeature
+<http://dev.openlayers.org/releases/OpenLayers-2.9/doc/apidocs/files/OpenLayers/Control/DrawFeature-js.html>`_.
+Thanks to our FeatureStore, a feature added to the layer will automatically
+also show up in the grid. For deleting features, we add a button with a custom
+handler.
+
+.. rubric:: Tasks
+
+#. Create a DrawFeature control. To do so, add the following right above the
+ mapPanel definition:
+
+ .. code-block:: javascript
+
+ var drawControl = new OpenLayers.Control.DrawFeature(
+ layer,
+ OpenLayers.Handler.Polygon,
+ {handlerOptions: {multi: true}}
+ );
+
+ Add the following below the mapPanel definition:
+
+ .. code-block:: javascript
+
+ mapPanel.map.addControl(drawControl);
+
+#. Add a bottom toolbar (``bbar``) property to the mapPanel definition. Now
+ the mapPanel definition should look like this:
+
+ .. code-block:: javascript
+
+ var mapPanel = new GeoExt.MapPanel({
+ title: "Map",
+ region: "west",
+ width: 400,
+ layers: [layer],
+ extent: new OpenLayers.Bounds(-74.047, 40.68, -73.908, 40.882),
+ bbar: [
+ new GeoExt.Action({
+ control: drawControl,
+ text: "Create",
+ enableToggle: true
+ }), {
+ text: "Delete",
+ handler: function() {
+ gridPanel.getSelectionModel().each(function(rec) {
+ var feature = rec.get("feature");
+ modifyControl.unselectFeature(feature);
+ store.remove(rec);
+ })
+ }
+ }
+ ]
+ });
+
+#. Save your file. Open or refresh @workshop_url@/wfs-editor.html in your
+ browser. Double-click in a grid cell to modify it. Click on a feature in
+ the map and modify it by playing with the vertices. Remove a feature by
+ hitting "Delete". Hit "Create" and draw a new feature. Scroll down to the
+ bottom of the Feature Table and edit its attributes. Hit the "Create"
+ button again to turn back to selection mode.
+
+.. figure:: editing.png
+
+ Modified layer after heavy feature editing.
+
+A Closer Look
+`````````````
+The "Create" button uses a `GeoExt.Action
+<http://geoext.org/lib/GeoExt/widgets/Action.html>`_ to turn an OpenLayers
+control into a button. It is important to understand that any OpenLayers
+control can be added to a toolbar or menu by wrapping it into such an Action.
+
+.. code-block:: javascript
+
+ new GeoExt.Action({
+ control: drawControl,
+ text: "Create",
+ enableToggle: true
+ }),
+
+The "Delete" button is just a plain Ext.Button. When clicked, it performs the
+action defined in its handler.
+
+.. code-block:: javascript
+
+ {
+ text: "Delete",
+ handler: function() {
+ gridPanel.getSelectionModel().each(function(rec) {
+ var feature = rec.get("feature");
+ modifyControl.unselectFeature(feature);
+ store.remove(rec);
+ })
+ }
+ }
+
+The handler function uses the selection model's ``each`` method to walk
+through the selected records (which will either be none ore one in our case,
+with ``singleSelect`` set to true). Before removing the record, we use the
+modifyControl's ``unselectFeature`` method to remove the feature's editing
+vertices and unselect the feature, bringing the layer in a clean state.
+
+Next Steps
+----------
+
+It is nice to be able to create, modify and delete features, but finally we
+will need to save our changes. The :ref:`final section <geoext.wfs.wfst>` of
+this module will teach you how to use the WFS-T functionality of OpenLayers
+to commit changes to the server.
Added: sandbox/foss4g2010/src/doc/wfs/grid.png
===================================================================
(Binary files differ)
Property changes on: sandbox/foss4g2010/src/doc/wfs/grid.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/foss4g2010/src/doc/wfs/grid.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/grid.rst (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/grid.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,190 @@
+.. _geoext.wfs.grid:
+
+Creating a Grid View of WFS Features
+====================================
+
+GeoExt borrows most of its WFS support from OpenLayers. What it does provide
+though is the `GeoExt.data.FeatureStore
+<http://geoext.org/lib/GeoExt/data/FeatureStore.html>`_, so showing feature
+attributes in a grid is a very easy task. If we just want to display features
+in a grid, we can use a `GeoExt.data.ProtocolProxy
+<http://geoext.org/lib/GeoExt/data/ProtocolProxy.html>`_, so we don't even
+need an OpenLayers layer.
+
+Vector Features in a Table
+--------------------------
+
+Let's start with some code that reads a WFS layer and displays the feature
+attributes in a table:
+
+.. _geoext.wfs.grid.grid:
+
+.. code-block:: html
+
+ <html>
+ <head>
+ <title>GeoExt WFS Editor</title>
+
+ <script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
+ <script type="text/javascript" src="ext/ext-all.js"></script>
+ <link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css" />
+ <script src="openlayers/lib/OpenLayers.js"></script>
+
+ <script type="text/javascript" src="geoext/lib/GeoExt.js"></script>
+
+ <script type="text/javascript">
+ Ext.BLANK_IMAGE_URL = "ext/resources/images/default/s.gif";
+
+ Ext.onReady(function() {
+ var store = new GeoExt.data.FeatureStore({
+ fields: [
+ {name: "LANAME", type: "string"},
+ {name: "CFCC", type: "string"},
+ {name: "LAND", type: "float"}
+ ],
+ proxy: new GeoExt.data.ProtocolProxy({
+ protocol: new OpenLayers.Protocol.WFS({
+ url: "/geoserver/ows",
+ version: "1.1.0",
+ featureType: "poly_landmarks",
+ featureNS: "http://www.census.gov",
+ srsName: "EPSG:4326"
+ })
+ }),
+ autoLoad: true
+ });
+
+ var gridPanel = new Ext.grid.GridPanel({
+ title: "Feature Table - Manhattan (NY) landmarks",
+ region: "center",
+ viewConfig: {forceFit: true},
+ store: store,
+ cm: new Ext.grid.ColumnModel({
+ defaults: {
+ sortable: true
+ },
+ columns: [
+ {header: "Name", dataIndex: "LANAME"},
+ {header: "CFCC", dataIndex: "CFCC"},
+ {header: "Land", dataIndex: "LAND"}
+ ]
+ })
+ });
+
+ var mainPanel = new Ext.Panel({
+ renderTo: document.body,
+ layout: "border",
+ height: 450,
+ width: 800,
+ items: [gridPanel]
+ });
+ });
+ </script>
+ </head>
+ <body>
+ </body>
+ </html>
+
+.. rubric:: Tasks
+
+#. Open a text editor, paste the code from above into a new file and save it
+ as :file:`wfs-editor.html` in the root of your workshop directory.
+
+#. After saving your changes, point your browser to
+ @workshop_url@/wfs-editor.html. You should see a grid, populated with
+ data.
+
+.. figure:: grid.png
+
+ A table view of WFS features.
+
+Understanding the FeatureStore
+``````````````````````````````
+Let's have a look at the FeatureStore definition:
+
+.. _geoext.wfs.grid.store:
+
+.. code-block:: javascript
+
+ var store = new GeoExt.data.FeatureStore({
+ fields: [
+ {name: "name", type: "string"},
+ {name: "owner", type: "string"},
+ {name: "usage", type: "string"},
+ {name: "number_fac", type: "int", defaultValue: 0}
+ ],
+ proxy: new GeoExt.data.ProtocolProxy({
+ protocol: new OpenLayers.Protocol.WFS({
+ url: "/geoserver/ows",
+ version: "1.1.0",
+ featureType: "parks",
+ featureNS: "http://medford.opengeo.org",
+ srsName: "EPSG:4326"
+ })
+ }),
+ autoLoad: true
+ });
+
+Two things are important: the field definition, and some way to tell the store
+where to get its data from.
+
+The field definition is straight forward -- we just need to make sure that we
+use the corect name of the attributes, and assign an appropriate type. Not all
+fields of the layer need to be mapped here -- only those we want to use. For
+the "number_fac" field we also set a default value, to make sure that we
+always display a number.
+
+There are many ways to tell a feature store where to find its data. When
+working with a map and a vector layer, it is enough to point it to that layer
+and it will synchronize itself with the layer. We will see how that works in
+the :ref:`next section <geoext.wfs.layer>`. For now, since we don't use a
+layer here, we use a ProtocolProxy. This is a wrapper for an
+`OpenLayers.Protocol
+<http://dev.openlayers.org/releases/OpenLayers-2.9/doc/apidocs/files/OpenLayers/Protocol-js.html>`_
+instance.
+
+A Closer Look at the Grid
+`````````````````````````
+A grid needs at least a store and a column definition to work properly. Let's
+see how we have done this for our feature grid:
+
+.. code-block:: javascript
+
+ var gridPanel = new Ext.grid.GridPanel({
+ title: "Feature Table - Medford Parks",
+ region: "center"
+ viewConfig: {forceFit: true},
+ store: store,
+ cm: new Ext.grid.ColumnModel({
+ defaults: {
+ sortable: true
+ },
+ columns: [
+ {header: "Name", dataIndex: "name"},
+ {header: "Owner", dataIndex: "owner"},
+ {header: "Usage", dataIndex: "usage", width: 35},
+ {
+ xtype: "numbercolumn",
+ header: "# of Facilities",
+ dataIndex: "number_fac",
+ format: "1,000",
+ align: "right",
+ width: 55
+ }
+ ]
+ })
+ });
+
+We have discussed the :ref:`store <geoext.wfs.grid.store>` already, so let's
+have a look at the definition of the ColumnModel: the columns are connected to
+fields of FeatureRecords using the ``dataIndex`` property. The numeric
+column ("# of Facilities") needs some extra attention: we want to ``align`` it
+to the right, and we can provide a number ``format`` property. This works
+exactly as the number formats in your favorite spreadsheet application.
+
+Next Steps
+----------
+
+Features in a grid are somewhat boring. We want to add a geospatial component
+to our application and give it a map. The :ref:`next section
+<geoext.wfs.layer>` explains how to do that.
Added: sandbox/foss4g2010/src/doc/wfs/index.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/index.rst (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/index.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,37 @@
+.. module:: geoext.wfs
+ :synopsis: Learn how to use WFS with GeoExt.
+
+.. _geoext.wfs:
+
+WFS Made Easy with GeoExt
+=========================
+
+GeoExt provides access to remote WFS data vie Stores and Readers, using the
+same mechanisms that Ext JS provides for any remote data access. Because the
+`GeoExt.data.FeatureStore
+<http://geoext.org/lib/GeoExt/data/FeatureStore.html>`_ can synchronize its
+records with an OpenLayers vector layer, working with vector features from
+WFS is extremely effortless.
+
+Users familiar with desktop based GIS
+applications expect to have a combined map and table (grid) view of geospatial
+data. GeoExt brings this feature to the web. At the end of this module, you
+will have built a simple WFS feature editor. The grid view comes for free
+because Ext JS can display data from any store in a grid, and the synchronized
+selection between map and table is also handled by GeoExt. Rendering
+the data on the map, editing and committing changes over WFS-T is provided by
+OpenLayers.
+
+GeoExt's FeatureReader is not limited to WFS protocol and GML -- other
+protocols (e.g. plain HTTP) with formats like KML, GeoRSS or GeoJSON work as
+well.
+
+In this module, you will:
+
+.. toctree::
+ :maxdepth: 1
+
+ Create a grid view of WFS features, <grid>
+ Add a map view of the same features with synchronized highlighting, <layer>
+ Make features editable, <editing>
+ Save modifications over WFS-T. <wfst>
Added: sandbox/foss4g2010/src/doc/wfs/layer.png
===================================================================
(Binary files differ)
Property changes on: sandbox/foss4g2010/src/doc/wfs/layer.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/foss4g2010/src/doc/wfs/layer.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/layer.rst (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/layer.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,133 @@
+.. _geoext.wfs.layer:
+
+A Synchronized Map and Table View of Vector Features
+====================================================
+
+In Ext JS, grids can not only have a store and a column model, but also a
+selection model. The FeatureStore provides everything to synchronize itself
+with the features of an OpenLayers vector layer, and the
+`GeoExt.grid.FeatureSelectionModel
+<http://geoext.org/lib/GeoExt/widgets/grid/FeatureSelectionModel.html>`_ can
+be used to synchronize highlighting (feature selection) between layer and
+grid.
+
+Let the Layer Fetch the Features, not the Store
+-----------------------------------------------
+
+We will now configure a vector layer with the WFS protocol and get rid of the
+ProtocolProxy.
+
+.. rubric:: Tasks
+
+#. Open :file:`wfs-editor.html` again in your text editor. Find the store
+ definition, and add the following code above it to create a layer:
+
+ .. code-block:: javascript
+
+ var layer = new OpenLayers.Layer.Vector("vector", {
+ strategies: [new OpenLayers.Strategy.Fixed()],
+ protocol: new OpenLayers.Protocol.WFS({
+ url: "/geoserver/wms",
+ version: "1.1.0",
+ featureType: "poly_landmarks",
+ featureNS: "http://www.census.gov",
+ srsName: "EPSG:4326"
+ })
+ });
+
+#. Now remove the ``proxy`` and ``autoLoad`` properties from the store
+ definition, and add a ``layer`` property pointing to the layer that we
+ created above.
+
+ .. code-block:: javascript
+
+ var store = new GeoExt.data.FeatureStore({
+ fields: [
+ {name: "LANAME", type: "string"},
+ {name: "CFCC", type: "string"},
+ {name: "LAND", type: "float"}
+ ],
+ layer: layer
+ });
+
+The ``protocol`` property we added to the layer definition is exactly the same
+that we had in the ProtocolProxy configuration in the :ref:`previous version
+<geoext.wfs.grid.grid>`.
+
+Adding a MapPanel to Display The Layer
+--------------------------------------
+
+Configured like above, our application does the same as before. The only
+difference is that OpenLayers takes care of loading features now. This means
+that unless we add the layer to a map, features won't be loaded, and we won't
+see anything in the grid. So let's add a map to our application.
+
+.. rubric:: Tasks
+
+#. Create a map panel. To do so, add the following code above the gridPanel
+ definition:
+
+ .. code-block:: javascript
+
+ var mapPanel = new GeoExt.MapPanel({
+ title: "Map",
+ region: "west",
+ width: 400,
+ layers: [layer],
+ extent: new OpenLayers.Bounds(-74.047, 40.68, -73.908, 40.882)
+ });
+
+#. Add the mapPanel to the application's main panel, by modifying the main
+ panel definition to look like this:
+
+ .. code-block:: javascript
+
+ var mainPanel = new Ext.Panel({
+ renderTo: document.body,
+ layout: "border",
+ height: 450,
+ width: 800,
+ items: [gridPanel, mapPanel]
+ });
+
+Now the application has a map window with a vector layer sharing its content
+with the grid.
+
+Synchronizing Feature Selection between Map and Grid
+----------------------------------------------------
+
+We are almost there. We just have to add some code to enable feature
+selection on the layer and synchronize it with the grid. Surprisingly, this
+requires just one line of code.
+
+.. rubric:: Tasks
+
+#. Configure the grid with a FeatureSelectionModel to get feature selection
+ (highlighting) synchronized between map and grid. Your gridPanel
+ definition should now start like this:
+
+ .. code-block:: javascript
+
+ var gridPanel = new Ext.grid.GridPanel({
+ title: "Feature Table - Manhattan (NY) landmarks",
+ region: "center",
+ viewConfig: {forceFit: true},
+ store: store,
+ sm: new GeoExt.grid.FeatureSelectionModel(),
+ cm: new Ext.grid.ColumnModel({
+
+#. Save your changes. Open or reload @workshop_url@/wfs-editor.html in your
+ browser. Select some features in the map and/or in the feature table and
+ see how they synchronize.
+
+.. figure:: layer.png
+
+ Map and table view of vector features with synchronized highlighting.
+
+What's Next?
+------------
+
+Having a map viewer like this is really close to a Desktop GIS. But for the
+ultimate user experience, we have to add editing capabilities. This is
+explained in the :ref:`next section <geoext.wfs.editing>`.
+
Added: sandbox/foss4g2010/src/doc/wfs/wfst.png
===================================================================
(Binary files differ)
Property changes on: sandbox/foss4g2010/src/doc/wfs/wfst.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: sandbox/foss4g2010/src/doc/wfs/wfst.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/wfst.rst (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/wfst.rst 2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,216 @@
+.. _geoext.wfs.wfst:
+
+Committing Feature Modifications Over WFS-T
+===========================================
+
+Until GeoExt also provides writers, we have to rely on OpenLayers for writing
+modifications back to the WFS. This is not a big problem though, because WFS-T
+support in OpenLayers is solid. But it requires us to take some extra care of
+feature states.
+
+Managing Feature States
+-----------------------
+
+For keeping track of "create", "update" and "delete" operations, OpenLayers
+vector features have a ``state`` property. The WFS protocol relies on this
+property to determine which features to commit using an "Insert", "Update" or
+"Delete" transaction. So we need to make sure that the ``state`` property gets
+set properly:
+
+* ``OpenLayers.State.INSERT`` for features that were just created. We do not
+ need to do anything here, because the DrawFeature control handles this for
+ us.
+* ``OpenLayers.State.UPDATE`` for features with modified attributes, except
+ for features that have ``OpenLayers.State.INSERT`` set already. For modified
+ geometries, the ModifyFeature control handles this.
+* ``OpenLayers.State.DELETE`` for features that the user wants to delete,
+ except for features that have ``OpenLayers.State.INSERT`` set, which can be
+ removed.
+
+.. rubric:: Tasks
+
+#. Open :file:`wfs-editor.html`` in your text editor. Add an "afteredit"
+ listener to the gridPanel definition, setting the state to
+ ``OpenLayers.State.UPDATE``, unless it is ``OpenLayers.State.INSERT``.
+ The first few lines of yourgridPanel definition should now look like this:
+
+ .. code-block:: javascript
+
+ var gridPanel = new Ext.grid.EditorGridPanel({
+ title: "Feature Table - Manhattan (NY) landmarks",
+ region: "center",
+ viewConfig: {forceFit: true},
+ store: store,
+ listeners: {
+ afteredit: function(e) {
+ var feature = e.record.get("feature");
+ if(feature.state !== OpenLayers.State.INSERT) {
+ feature.state = OpenLayers.State.UPDATE;
+ }
+ }
+ },
+ sm: new GeoExt.grid.FeatureSelectionModel({
+ selectControl: modifyControl.selectControl,
+ singleSelect: true
+ }),
+
+#. Modify the handler for the "Delete" button so it re-adds deleted features
+ with a state other than ``OpenLayers.State.INSERT``, after setting
+ their state to ``OpenLayers.State.DELETE`` (which also makes them
+ invisible on the layer:
+
+ .. code-block:: javascript
+
+ {
+ text: "Delete",
+ handler: function() {
+ gridPanel.getSelectionModel().each(function(rec) {
+ var feature = rec.get("feature");
+ modifyControl.unselectFeature(feature);
+ store.remove(rec);
+ if(feature.state !== OpenLayers.State.INSERT) {
+ feature.state = OpenLayers.State.DELETE;
+ layer.addFeatures([feature]);
+ }
+ });
+ }
+ }
+
+ To avoid that features marked ``OpenLayers.State.DELETE`` show up in the
+ grid, we have to configure a filter for the store, using its
+ ``addFeatureFilter`` config property. Make the store definition look like
+ this:
+
+ .. code-block:: javascript
+
+ var store = new GeoExt.data.FeatureStore({
+ fields: [
+ {name: "name", type: "string"},
+ {name: "owner", type: "string"},
+ {name: "usage", type: "string"},
+ {name: "number_fac", type: "int", defaultValue: 0}
+ ],
+ layer: layer,
+ addFeatureFilter: function(feature) {
+ return feature.state !== OpenLayers.State.DELETE;
+ }
+ });
+
+Adding a Save Strategy and a Save Button
+----------------------------------------
+
+Saving feature modifications the OpenLayers way requires the vector layer to
+be configured with an `OpenLayers.Strategy.Save
+<http://dev.openlayers.org/releases/OpenLayers-2.9/doc/apidocs/files/OpenLayers/Strategy/Save-js.html>`_.
+We will now add such a strategy, along with a "Save" button.
+
+.. rubric:: Tasks
+
+#. Find the layer definition in your :file:`wfs-browser.html` file.
+ Instantiate a Save strategy above, and make the layer uses it by adding it
+ to the layer's ``strategies`` array. The whole code block should now look
+ like this:
+
+ .. code-block:: javascript
+
+ var saveStrategy = new OpenLayers.Strategy.Save();
+ var layer = new OpenLayers.Layer.Vector("vector", {
+ strategies: [new OpenLayers.Strategy.Fixed(), saveStrategy],
+ protocol: new OpenLayers.Protocol.WFS({
+ url: "/geoserver/ows",
+ version: "1.1.0",
+ featureType: "parks",
+ featureNS: "http://medford.opengeo.org",
+ srsName: "EPSG:4326"
+ })
+ });
+
+ .. warning:: If you are modifying this example to work with a layer that
+ is stored in a shapefile or a MySQL database, modify your saveStrategy
+ to look like this:
+
+ .. code-block:: javascript
+
+ var saveStrategy = new OpenLayers.Strategy.Save({
+ onCommit: function() {
+ saveStrategy.layer.refresh();
+ }
+ });
+
+ This is required because the mentioned data backends do not report
+ back the ids of inserted features. What it does is that it refreshes
+ the whole layer rather than just assigning the appropriate feature
+ ids to the features that are already on the layer.
+
+#. Add a button on the right side of the map panel's bottom toolbar, with a
+ handler that calls the ``save`` method of the saveStrategy. The mapPanel's
+ bbar definition has to look like this now:
+
+ .. code-block:: javascript
+
+ bbar: [
+ new GeoExt.Action({
+ control: drawControl,
+ text: "Create",
+ enableToggle: true
+ }), {
+ text: "Delete",
+ handler: function() {
+ gridPanel.getSelectionModel().each(function(rec) {
+ var feature = rec.get("feature");
+ modifyControl.unselectFeature(feature);
+ gridPanel.store.remove(rec);
+ if(feature.state !== OpenLayers.State.INSERT) {
+ feature.state = OpenLayers.State.DELETE;
+ layer.addFeatures([feature]);
+ }
+ })
+ }
+ }, "->", {
+ text: "Save",
+ handler: function() {
+ store.commitChanges();
+ saveStrategy.save();
+ }
+ }
+ ]
+
+#. Save your file and reload @workshop_url@/wfs-editor.html. Make some
+ changes and hit "Save". Reload the page to see that your changes were
+ persisted.
+
+.. figure:: wfst.png
+
+ Application with "Save" button and a persisted feature after reloading.
+
+One More Look at the "Save" Button
+``````````````````````````````````
+For the "Save" button, we have added a line of code reading
+``store.commitChanges()``.
+
+.. code-block:: javascript
+
+ {
+ text: "Save",
+ handler: function() {
+ store.commitChanges();
+ saveStrategy.save();
+ }
+ }
+
+In Ext JS, the ``commitChanges`` method of a store is used to save changes.
+We use OpenLayers to perform the WFS transaction, so we would not necessarily
+have to call ``commitChanges``. But doing so will make sure that the records are no
+longer marked "dirty", which resets the store into the same clean state that the
+layer will be in when the commit operation is finished. The pleasant side effect
+of calling ``commitChanges`` is that the tiny read triangles in the top left
+corner of edited grid cells disappear.
+
+Conclusion
+----------
+
+You have successfully created a WFS based feature editor. GeoExt makes working
+with features easy, thanks to its FeatureStore. Although there is no write
+support yet for the FeatureStore in GeoExt, saving changes via WFS-T is easy
+because of the solid WFS-T support in OpenLayers and the interoperability of
+GeoExt and OpenLayers.
More information about the Commits
mailing list