mapbuilder-lib Software Design Description

Cameron Shorter

Mike Adair


Table of Contents

1. Scope
1.1. Identification
1.2. System Overview
1.3. Document Overview
2. Reference Documents
3. Design Decisions
3.1. Design Drivers
4. Architectural Design
4.1. Design Patterns
4.1.1. Model View Controller
4.1.1.1. MVC Overview
4.1.1.2. MVC benefits
4.1.2. Inheritance
4.1.2.1. Design Notes
4.1.3. Events
4.2. Technologies used
4.2.1. Javascript
4.2.2. AJAX
4.2.3. XSL
4.2.4. CSS
4.2.5. Sarissa
4.2.6. Javascript graphics
4.2.7.
4.3. Interface Design
4.3.1. MainPage
4.3.1.1. Design Notes
4.3.2. Web Map Context
4.3.3. Config
4.3.3.1. Config Document Schema
4.4. Components
4.4.1. Model
4.4.2. Widget
4.4.3. Tool
4.4.3.1. ButtonBase
4.4.4. Util
4.4.4.1. Listener
4.4.5. Mapbuilder
4.4.6. Inheritance
4.4.7. File and object name convention
5. Notes
5.1. Extending the code base
A. Glossary
B. UML Legend

Abstract

This document describes the design of mapbuilder-lib, a module within the Community Map Builder framework.

1. Scope

1.1. Identification

This document is referred to as mapbuilder-lib Software Design Description, associated with release $Name: mapbuilder-lib-1_0-rc1 $.

The source document is stored in Docbook XML format and is stored in the Community Mapbuilder CVS repository in mapbuilder/design/mapbuilder-lib.xml.

1.2. System Overview

mapbuilder-lib provides components that can be used to build geographic client applications within a web browser. It uses Open GIS Standards (OGC) to communication with external Map Servers.

It uses Javascript and XSL which can be rendered by Internet Explorer 6+, Mozilla 1.3+ and Netscape 6+.

mapbuilder-lib uses an object oriented design which makes it easy to extend.

1.3. Document Overview

This document describes the design of mapbuilder-lib, a module within the Community Map Builder framework. See the layout guide for instructions on customizing the configuration elements.

The structure of this document is loosely based on the SDD template provided by MIL-STD 498.

2. Reference Documents

3. Design Decisions

3.1. Design Drivers

The goals of the libraries are to provide the following:

Client is a Web Browser

Mapbuilder Clients should be easy for users to run. Users should not have to download and install new software. Instead all Mapbuilder clients should run inside the commonly used web browsers. In particular, Internet Explorer 6+ and Mozilla browsers based on Mozilla 1.3+.

Minimal Server Side Functionality

Mapbuilder should keep deployment requirements to a minimum in order to maximise the user base. Hence:

  1. Where possible, clients should not require server side scripts.

  2. If server side scripts are required, the server environments currently supported include: Perl, PHP, JSP. Contributions for equivalent functionality in other server environments is encouraged. Please see server dependencies

    (TBD link a section for server requirements).

Easy to incorporate libraries into a web page

Mapbuilder widgets are to be incorporated into HTML web pages. Incorporating widgets should be kept simple so that someone with basic HTML and Javascript knowledge can build a Mapbuilder Web Page.

Keep bandwidth to a minimum

All client functionality needs to be downloaded, so it is important to keep it to a minimum. Files that are downloaded should also be static which means that browsers will cache them locally. (CGI scripts generally do not provide images that are cached).

Use Javascript/XML/XSL

Mapbuilder stores state data internally in XML files. Converting XML to HTML is done using XSL. XSL has the advantage that it can be used both in the client and server.

Modular Design

A modular design has many benefits.

  1. A client need only include the module it requires, hence reducing the size of the client.

  2. A modular design is easier to understand, maintain and extend.

  3. Extra functionality can be easily added and removed.

  4. It is easier to break development up between multiple developers.

Open Source

Mapbuilder software is open source. Open source was chosen because:

  1. Part of our target audience are community groups who often cannot justify buying software.

  2. Developers are more likely to extend open source software.

  3. It's fun developing open source software.

Any libraries that Mapbuilder uses or extends should not introduce an incompatible or closed license.

Attract Developers

Hopefully potential developers will extend this project in preference to creating their own. Things that should help attract developers include:

  • Keep the design simple, modular and easy to understand.

  • Provide design and user documentation.

  • Provide discussion forums.

  • Provide stable releases which are easy to install and evaluate.

  • Provide demos that potential users and developers can try.

4. Architectural Design

4.1. Design Patterns

4.1.1. Model View Controller

Mapbuilder uses the Model View Controller (MVC) design pattern for rendering widgets. Unlike many Content Management Systems, mapbuilder stores it's all it's model data in the web browser, which speeds up user interactions because communication with the server is reduced.

4.1.1.1. MVC Overview

Figure 1. Model View Controller

Model View Controller

The MVC pattern forces one to think of an application in terms of three modules:

Model

This maintains the state and data that the application represents. When changes occur in the model, it sends update events to all of its views. Context is the Model in the Mapbuilder application and stores Layers, Bounding Box etc.

View

The user interface which displays information about the model to the user. Views displaying dynamic data need to register for StateChange events from the Model. Legend, MapPane, etc are all Mapbuilder Views that get update events when Context changes.

Controller

The user interface presented to the user to manipulate the application (ie keyboard and mouse input). ZoomTool, PanTool, SelectFeature are all Mapbuilder Controllers which update Context.

Some components can act as both a View and Controller. For example, a LocatorMap may allow users to draw a select box to change the BoundingBox. Also, when the BoundingBox in Context changes, the LocatorMap will draw a new Box over it's basemap.

There is a lot of literature describing the MVC Design Pattern. Here is one.

The components are explained in more detail in Section 4.4, “Components”.

4.1.1.2. MVC benefits

The benefits of using the MVC design pattern include:

Modularity

Views and Tools can be added or removed without effecting the rest of the application. Tools do not have any dependencies on Views and visa-versa which makes Tools and Views simpler.

Multiple Views

Views can display the same data in different ways. For example, a Locater Map and Main Map both display the BoundingBox in different ways.

Parallel Development

Once the interfaces have been defined, components can be developed in parallel.

4.1.2. Inheritance

Javascript doesn't provide inheritance, however there are a number of sub-optimal hacks available and we have used a couple of them in mapbuilder. Most are similar to this example where Legend extends WidgetBase.

Legend.js
var base = new WidgetBase(this, widgetNode, model);
WidgetBase.js
  ...
  // If this object is being created because a child is extending this object,
  // then child.properties = this.properties
  for (sProperty in this) {
    widget[sProperty] = this[sProperty];
  }

It is important to note that our implementation of inheritance requires each function call to be passed it's object instance (usually called objRef). Eg:

  /**
   * Remove widget from display.
   * @param objRef Pointer to this object.
   */ 
  this.clearWidget = function(objRef) {
    ..
  }
4.1.2.1. Design Notes

We should use the Javascript .apply() method for inheritance as used by the kamap project as it provides a cleaner implimentation.

4.1.3. Events

TBD

4.2. Technologies used

4.2.1. Javascript

4.2.2. AJAX

4.2.3. XSL

4.2.4. CSS

4.2.5. Sarissa

4.2.6. Javascript graphics

4.2.7. 

4.3. Interface Design

Figure 2. Components required to use mapbuilder-lib

Components required to use mapbuilder-lib

4.3.1. MainPage

The Main Web Page uses include and initialise mapbuilder-lib and to layout the page.

Example 1. Including and initialising mapbuilder-lib

<html>
  <head>
    <title>Mapbuilder Demo</title>
    <link rel="stylesheet" href="../lib/skin/default/html.css" type="text/css">
    <script>
      // URL of Mapbuilder configuration file.
      var mbConfigUrl='config/CompleteConfig.xml';
    </script>
    <script type="text/javascript" src="../lib/Mapbuilder.js"></script>
  </head>

  <body onload="mbDoLoad()">
    <Insert more html here/>
  </body>
</html>

mapbuilder-lib widgets are inserted using HTML tags with unique identifies. When mapbuilder-lib renders widgets, HTML is inserted into the widget tags.

Example 2. HTML with widget tags

<table>
  <tr>
    <td id="mainMapPaneId"/>
  </tr>
  <tr>
    <td>
      <div id="buttonBarId"/>
    </td>
  </tr>
</table>

For further details on how to use mapbuilder-lib, refer to the Users Guide.

4.3.1.1. Design Notes

Layout of widgets should be done using CSS instead of tables. Most Content Management Systems (CMS) use CSS for layout. The CSS can be maintained as a "skin" and a different skin can be selected easilly by users.

A minor change needs to be made to the paint() methods so that painting to an undefined HTML id will work.

4.3.2. Web Map Context

The Web Map Context stores geographic state, like Map Layers, Bounding Box, etc. The format is defined by the OGC's Web Map Context (WMC) specification.

At least one context.xml file is required for each Mapbuilder application and is referenced from the config.xml file.

4.3.3. Config

The Config file is an XML document which describes which mapbuilder-lib components should be included in an application. The schema for the config file is stored at mapbuilder/lib/schema/config.xsd and can be viewed more easilly using the Mapbuilder Components Register.

4.3.3.1. Config Document Schema

The mapbuilder-lib configuration XML document is based on RDF principles. Future plans include defining a mapbuilder config document schema by extending the RDF schema.

The config doc follows Object-Property-Value rule of GML3 and RDF. As a rule of thumb, this means that parent and child elements alternate between UpperCamelCase and lowerCamelCase, Upper is for objects and lower is for properties. An object can only contain another object through a property value.

Example 3. Example use of Object-Property-Value

    <ContextCollection id="collectionGroup">
      <defaultModelUrl>context/demoCollection.ccml</defaultModelUrl>
      <widgets>
        <CollectionList id="collectionListId">
          <scriptFile>widget/collectionList/CollectionList.js</scriptFile>
          <stylesheet>widget/collectionList/Collection2List.xsl</stylesheet>
          <targetWidgetGroup>mainMapGroup</targetWidgetGroup>
        </CollectionList>
      </widgets>
    </ContextCollection>

A more complete description of the object-property-value rule can be found in section 2.1 of the document: Developing and Managing GML Application Schemas.

4.4. Components

Figure 3. mapbuilder-lib components

mapbuilder-lib components

4.4.1. Model

Figure 4. Model Components

Model Components

Model components store mapbuilder state and notify widgets when state changes. State is often read from and stored in XML files.

TBD: Explain how state is stored in Listener objects.

4.4.2. Widget

Figure 5. Widget Components

Widget Components

Widgets are responsible for rendering map components into the MainPage whenever state changes. Usually, the widget uses XSL to convert an XML document to an HTML snippet. The HTML snippet is inserted into the widget's HTML tag in the MainPage.

4.4.3. Tool

Figure 6. Tool Components

Tool Components

Tool Components process mouse and key actions on behalf of a widget and update Model Components with new state information.

4.4.3.1. ButtonBase

Tools which extend ButtonBase have a Button image associated with the Tool which allows a user to select the Tool using the Button.

4.4.4. Util

4.4.4.1. Listener

The Listener object provides setParam() and getParam() methods, and notifies Listeners when the parameter changes. Objects requiring this functionality extend the Listener object.

The Listener object was introduced to overcome Javascript's poor support for events.

Example 4. Simple use of Listener

SomeModel contains a parameter someParam and SomeWidget needs to repaint itself whenever someParam changes.

SomeModel extends Listener()
function SomeModel() {
  // Inherit the Listener functions and parameters
  var listener = new Listener();
  for (sProperty in listener) { 
    this[sProperty] = listener[sProperty]; 
  }
  ...
SomeWidget registers to receive update events when someParam changes
  /** Function called when someParam changes */
  this.someFunction=function(objRef){
    alert("someParam has changed");
  }
  someModel.addListener("someParam",this.someFunction,this);
SomeTool updates someParam and triggers a call to SomeWidget.someFunction
  SomeModel.setParam("someParam", "newValue");

4.4.5. Mapbuilder

The Mapbuilder object is responsible for loading and initialising required script files. The scripts required is determined from the Config file. The Mapbuilder object loads the scripts in order of dependency, periodically checking the load status. When all scripts have loaded, the javascript objects are initialised which triggers the rendering of widgets.

4.4.6. Inheritance

Javascript doesn't naturally provide inheritance. Instead there are a number of hack solutions that a programmer can choose from. In mapbuilder-lib, the following method is used:

Example 5. SomeObject inherits from the Listener Object

function SomeObject() {
  // Inherit the Listener functions and parameters
  var listener = new Listener();
  for (sProperty in listener) { 
    this[sProperty] = listener[sProperty]; 
  }
  ...

4.4.7. File and object name convention

Javascript object constructors must have the same name as the node of it's corresponding object in the configuration document. For example, a <Context> object from the config doc will be instantiated by the javascript call:

var model = new Context();

The Javascript code for each model, widget and tool object type should be created in the lib/model, lib/widget and lib/tool directories respectively. By default, the file containing javascript object code will have the same filename as the object type name, so for example, the javascript Context code will be loaded from the file lib/model/Context.js. This default filename of the javascript object code can be over-ridden by setting a <scriptfile> property on the object in the configuration document.

In addition, the stylehseet filename for widgets will also use the object type name with an extension of .xsl by default. For example, the <Legend> XSL file to style the Legend object is lib/widget/Legend.xsl by default. This default filename can be over-ridden by setting a <stylesheet> property on the widget object.

5. Notes

5.1. Extending the code base

When extending the mapbuilder code base, it's usually easiest to copy code from other models, widgets and tools.

Depending on what functionality you want to add, you will begin at one of the steps listed below. For example you could be just adding a tool to a widget (step 4 only) or you could be adding a whole new model type, along with a new ModelGroup in the config file and associated widgets and tools (steps 1 through 4).

  1. Add a new model type:

    If you are representing a new XML document type not already supported by mapbuilder, first code the javascript Model object. All model objects should inherit from ModelBase. Javascript source files are added to the lib/models directory. Add a new object to the <models> property of the config document which points to the javascript source file. The model constructor must be named the same as the <modelType> properties of a ModelGroup object.

  2. Add a new model:

    Only do this if the actual instance of the model you are working with is not already represented as a Model in config. Assign the Model an "id" attribute so that it can be referenced using that id as the property name of mbConfig (e.g. mbConfig['modelId']). Add defaultModelUrl properties to the Model which is the URL of the document that will be loaded by default.

  3. Add widgets to a model:

    For each view of the model to be displayed on the web page, add a widget object to the <widgets> property. All widget objects must inherit from the WidgetBase class. A widget constructor must have the same name as the widget object node name in the config document. Source code for widgets is added as a subdirectory of lib/widgets containing all files required to paint the widget. Add the <scriptfile> and <stylesheet> properties to the object in config to point to these source files. The widget will be painted to the HTML element with the same id as the "id" attribute of the widget. Customize the widget object as required.

  4. Add tools to widgets

    For each controller used to control the model objects, add a tool object to the widget <tools> property. A tool constructor must have the same name as the tool object node name in the config document. Source code for tools are added to the lib/tools directory (TBD: subject to change). Add the <scriptfile> property to the object in config to point to these source files. A tool contained by one model group can be used as a controller of another model group by adding a <targetModelGroup> property which has the value of a ModelGroup id. Customize the tool object as required.

A. Glossary

Table A.1. Glossary

TermExpanded AcronymDescription
AOIArea Of Interest 
CSSCoordinate System Specification 
CTSCoordinate Transform ServiceAs specified by the OGC.
IDEIntegrated Development Environment 
IRCInternet Relay ChatA way to communicate in real time with lots of other people around the world in a virtual meeting.
GCSGrid Coverage SpecificationAs specified by the OGC.
GISGeographic Information Systems 
GMLGeographic Markup LanguageXML format for describing geographic features.
LGPLGNU General Public LicenseOpen Source License.
MIL-STD 498Military Standard 498Set of processes for software development.
OGCOpen GIS ConsortiumGeographic Standards Body
RDFResource Description FrameworkFramework to describe any Internet resource such as a Web site and its content.
SDDSoftware Design DescriptionA design document as defined by MIL-STD 498.
SRSSpacial Reference SystemSpacial Reference System (as defined by the OGC). An alpha-numeric ID which specifies what coordinate system you are using. Eg: SRS="EPSG:4326".
SVGScalable Vector Graphics 
SLDStyled Layer DescriptorXML document which describes how to draw specific features. Eg, A road line may be drawn in red, 3 pixels wide.
UMLUnified Modeling LanguageA set of diagrams used to describe software pictorially.
WCSWeb Coverage Server 
WFSWeb Feature ServerReturn vector data about features.
WMSWeb Map ServerReturn raster map images and point queries.
XSLExtensible Stylesheet LanguageA language for expressing stylesheets.
XSLTXSL TransformA language for transforming XML documents into other XML documents.
XMLExtensible Markup Language 

B. UML Legend

Table B.1. Legend for UML class diagrams

Package
Dependencies between packages. This expresses that classes within a package use classes from the package it depends on.
Interfaces. An Interface is restricted to only contain operations but no attributes. Also, operations are abstract and have no implementation.
Classes. Classes hold operations and attributes and have relations to other classes via association or inheritance relations.
Inheritance relations. Between interfaces or between classes.
Implementation relations. Only between interfaces and classes.
Association relations. Associations are relations between classes. They often include navigation arrows, and multiplicity (eg 1..*).