1.2. Dissecting Your Map Application

As demonstrated in the previous section, a map that fills the whole browser viewport is generated by bringing together a minimal html document, application initialization code, and user interface configuration objects. We’ll look at each of these parts in a bit more detail.

1.2.1. Minimal HTML Document

Since the mother of all web browser content is still HTML, every web application needs at least a basic HTML document as container. It does not contain human readable markup, so it has an empty body. But it makes sure that all required style and script resources are loaded. These usually go in the document’s head:

<link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css">
<script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext/ext-all.js"></script>

Ext JS can be used standalone, or together with JavaScript frameworks like JQuery. Depending on this environment, an appropriate adapter has to be loaded first. We use Ext JS standalone, so we need the ext-base.js adapter. In the second line, we load the main library.

GeoExt not only relies on Ext JS, but also on OpenLayers. So we also have to load OpenLayers. And finally, we can load GeoExt:

<script src="openlayers/lib/OpenLayers.js"></script>
<script type="text/javascript" src="geoext/lib/GeoExt.js"></script>

Note

When using GeoExt, you also benefit from all the functionality that plain Ext JS and OpenLayers provide. You can add GeoExt to your existing Ext JS and OpenLayers applications without breaking anything.

1.2.2. Application Initialization Code

Application initialization in this context means code that is executed as early as possible.

Ext.BLANK_IMAGE_URL = "ext/resources/images/default/s.gif";
var app, items = [], controls = [];

items.push({
    xtype: "gx_mappanel",
    ref: "mapPanel",
    region: "center",
    map: {
        numZoomLevels: 19,
        controls: controls
    },
    extent: OpenLayers.Bounds.fromArray([
        -122.911, 42.291,
        -122.787,42.398
    ]),
    layers: [new OpenLayers.Layer.WMS(
        "Medford",
        "/geoserver/wms?SERVICE=WMS",
        {layers: "medford"},
        {isBaseLayer: false}
    )]
});
controls.push(
    new OpenLayers.Control.Navigation(),
    new OpenLayers.Control.Attribution(),
    new OpenLayers.Control.PanPanel(),
    new OpenLayers.Control.ZoomPanel()
);

We start with setting a local URL for the blank image that Ext JS uses frequently, and define some variables. We populate two arrays. items is the user interface items of our application, and controls is our OpenLayers map controls.

The really interesting part in the snippet above is the one with the items that we will add as configuration objects to the viewport. In Ext JS, we find ourselves creating configuration objects instead of writing code for most basic tasks, which usually makes application development easier and faster. The items interact through events and events listeners, the “glue” which we will talk about later.

Before we look at the items in more detail, let’s find out how to add content to our viewport.

1.2.3. Building the User Interface

We already saw that the body of our HTML document is empty. Everything that we see on the web page is added by Ext JS, but for this to work we need to have the DOM of the page ready, so we can append to it. To ensure that we don’t write to the DOM too early, Ext provides the Ext.onReady() hook.

In our example, the user interface is simple. We just create a new Ext.Viewport with a border layout. This allows us to fill the whole browser viewport with our application, and we don’t need to add any markup to our page.

Ext.onReady(function() {
    app = new Ext.Viewport({
        layout: "border",
        items: items
    });
});

The Ext.Viewport here uses a “border” layout. It can have items for its center, north, east, south and west regions, but only the center region is mandatory. It takes up all the space that is not used by the other regions, which need to be configured with a width or height.

Note

To make our workshop application modular, we will be calling Ext.onReady() several times as we add functionality. There is no need to do this in a real life application, where all DOM dependent code usually goes into a single Ext.onReady() block.

1.2.4. The GeoExt.MapPanel Component

In Ext JS, all constructors of UI components take a single argument, which we will be referring to as “configuration object”. Like all JavaScript objects, this configuration object is wrapped in curly braces, and contains key: value pairs. Let’s have a look at the configuration object for our map:

{
    xtype: "gx_mappanel",
    ref: "mapPanel",
    region: "center",
    map: {
        numZoomLevels: 19,
        controls: controls
    },
    extent: OpenLayers.Bounds.fromArray([
        -122.911, 42.291,
        -122.787,42.398
    ]),
    layers: [new OpenLayers.Layer.WMS(
        "Medford",
        "/geoserver/wms?SERVICE=WMS",
        {layers: "medford"},
        {isBaseLayer: false}
    )]
}

The first three properties are not specific to GeoExt. The xtype tells Ext JS which constructor to send the configuration object to. ref defines a reference relative to the container (in this case the Ext.Viewport we add this item to). The region is the region of the viewport we want to place our map in.

Note

The following two notations are equivalent:

  • new GeoExt.MapPanel({region: center, extent: /* ... */});
  • {xtype: "gx_mappanel", region: center, extent: /* ... */});

Ext JS keeps a registry of available components, called “xtypes”. GeoExt adds its components to this registry. To make them distinguishable from others, their names start with the “gx_” prefix. In this context, the ref property is also important: it is used to create a reference so we can access the component later more easily.

Using xtypes is useful when loading configurations dynamically with AJAX. In that case, the configuration has to be JSON compliant, and may only contain simple types (numbers, strings and boolean values).

The other properties are specific to the GeoExt.MapPanel: Instead of creating an OpenLayers.Map instance, we just configure some configuration options for the map in the map option. extent sets the initial extent of the map, and layers the initial set of layers. For our simple map, we just want to show a single WMS layer. As in plain OpenLayers, we do this by instantiating an OpenLayers.Layer.WMS object. The only difference here is that we configure the WMS layer with the {isBaseLayer: false} option. This is not strictly necessary now, but when we add a layer tree later, we want to see the tree node for this layer rendered with a checkbox, not with a radio button.

You’ve successfully dissected your first application! Next let’s learn more about developing with GeoExt.