Changes between Initial Version and Version 1 of MapGuideTutorial


Ignore:
Timestamp:
Mar 11, 2008, 5:30:54 AM (16 years ago)
Author:
pagameba
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • MapGuideTutorial

    v1 v1  
     1[[PageOutline]]
     2= Fusion MapGuide Tutorial =
     3
     4== Introduction ==
     5
     6This tutorial describes how to build a web-based mapping application using the Fusion application developer's toolkit and !MapGuide Open Source.  It assumes you are familiar with !MapGuide Open Source, it's PHP extensions, and that you have the Sheboygan sample data (available from [http://mapguide.osgeo.org]) installed.
     7
     8This tutorial provides a high level overview of the various APIs.
     9
     10== Essential Concepts ==
     11
     12It is very important that you understand how !MapGuide works.  !MapGuide comes with its own extensive documentation.  If you are not familiar with creating !MapDefinition resources, please review the !MapGuide documentation.
     13
     14Fusion is all about creating a web application.  You will need some familiarity with HTML, JavaScript, CSS.
     15
     16The primary development language for building Fusion applications is !JavaScript, but if you need to add server-side functionality using the !MapGuide API, then a knowledge of PHP is also required.
     17
     18Fusion makes extensive use of static and dynamically generated HTML.  You need to be familiar with the Document Object Model (DOM) implemented by various browsers, and the subtle differences between the browsers in how scripting with the DOM works.  Although it is possible to use Fusion without any DOM scripting, it is likely that most applications will need to use some scripting to achieve their desired functionality.
     19
     20Fusion makes extensive use of CSS to achieve its look and feel in a minimally intrusive way.  The design principle behind much of the structure of the user interface components of Fusion is to let the browser do as much of the work as possible with its native layout engine.  This is the most efficient and natural design for web pages, and reduces the amount of javascript code that needs to be executed by the client's browser.  You will need to thoroughly understand CSS design and implementation concepts in order to fully customize the Fusion interface, but to use the default look and feel of Fusion with moderate customization does not require advanced CSS knowledge.
     21
     22== Preparing for the Tutorial ==
     23
     24The examples in this tutorial rely on the Sheboygan sample data that is available with !MapGuide Open Source (as a separate download from [http://mapguide.osgeo.org]).  Please obtain and install the Sheboygan sample data if you have not already done so.
     25
     26== Hello Sheboygan ==
     27
     28Creating a new Fusion application is really quite straight-forward.  The simplest way to demonstrate the core concepts of Fusion is to build a small, working application.  The ''Hello Sheboygan'' application is going to have a map and three navigation tools (zoom in, zoom out, and pan).  It will be fully functional, albeit quite plain!
     29
     30<image of app here>
     31
     32First, create a directory on your server to hold all the files required by the application.  The directory needs to be in a web-accessible location.  You can always create a directory in your www folder of your !MapGuide Open Source installation if you don't know where else to put it.  Call this directory {{{hello}}}.
     33
     34The next step is to decide what functionality, or widgets, are needed by the application.  The list (from the description above) is:
     35
     36 * a Map widget
     37 * a Zoom In widget
     38 * a Zoom Out widget
     39 * a Pan widget
     40
     41These widgets need to be described in an ApplicationDefinition xml file.  Fusion allows you to store the ApplicationDefinition resource in the MapGuide repository or as a separate XML file.  For the purpose of this document, we will be assuming that you are storing the ApplicationDefinition resource as a separate XML file.  There are instructions at the end of this document for using an ApplicationDefinition resource stored in a !MapGuide repository.
     42
     43By convention, the name of the file is ApplicationDefinition.xml.  So, create a new file in the {{{hello}}} directory and name it ApplicationDefinition.xml.  For our very simple example, we need an ApplicationDefinition tag with a Title tag, a !MapGroup tag, and a !WidgetSet tag to hold our four widgets (see the ApplicationDefinition page for a more complete description).  Individual widgets are represented as Widget tags inside the WidgetSet tag where the actual widget is specified by the Type tag and the HTML element that the widget will be created in is specified by the Name tag.  Our four widgets each have a specific Widget tag with several options, most of which are not required for this example.  The resulting XML for Hello Sheboygan is:
     44{{{
     45<ApplicationDefinition
     46      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     47      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     48      xsi:noNamespaceSchemaLocation="ApplicationDefinition-1.0.0.xsd">
     49  <Title>Hello Sheboygan</Title>
     50  <MapGroup>
     51    <Map xsi:type="MapGuideLayerType">
     52      <Type>MapGuide</Type>
     53      <SingleTile>true</SingleTile>
     54      <Extension>
     55        <ResourceId>Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition</ResourceId>
     56      </Extension>
     57    </Map>
     58  </MapGroup>
     59  <WidgetSet>
     60    <MapWidget>
     61      <Name>Map</Name>
     62      <Type>Map</Action>
     63      <StatusText/>
     64      <MapId>HelloSheboygan</MapId>
     65    </Widget>
     66    <Widget>
     67      <Name>ZoomIn</Name>
     68      <Type>Zoom</Type>
     69      <StatusText/>
     70      <Extension>
     71        <Direction>in</Direction>
     72      </Extension>
     73      <ImageUrl>images/icons/zoom-in.png</ImageUrl>
     74      <ImageClass/>
     75      <Label/>
     76      <Tooltip>Click or click and drag on the map to zoom in</Tooltip>
     77      <Disabled/>
     78    </Widget>
     79    <Widget>
     80      <Name>ZoomOut</Name>
     81      <Type>Zoom</Type>
     82      <StatusText/>
     83      <Extension>
     84        <Direction>out</Direction>
     85      </Extension>
     86      <ImageUrl>images/icons/zoom-out.png</ImageUrl>
     87      <ImageClass/>
     88      <Label/>
     89      <Tooltip>Click on the map to zoom out</Tooltip>
     90      <Disabled/>
     91    </Widget>
     92    <Widget xsi:type="UiWidgetType">
     93      <Name>Pan</Name>
     94      <Type>Pan</Type>
     95      <StatusText/>
     96      <Extension/>
     97      <ImageUrl>images/icons/pan.png</ImageUrl>
     98      <ImageClass/>
     99      <Label/>
     100      <Tooltip>Click and drag the map to pan</Tooltip>
     101      <Disabled/>
     102    </Widget>   
     103  </WidgetSet>
     104  <Extension />
     105</ApplicationDefinition>
     106}}}
     107
     108The next thing that our ''Hello World'' application needs is a template, which is simply an html file.  Create a new file in the {{{hello}}} directory and name it {{{index.html}}}.  Here's the {{{index.html}}} file contents:
     109
     110{{{
     111<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
     112<html>
     113<head>
     114<title>Hello Sheboygan</title>
     115<!-- change the source of the following tag to point to your fusion installation -->
     116<script type="text/javascript" src="../fusion/lib/fusion.js"></script>
     117<script type="text/javascript">
     118window.onload = function() {
     119    Fusion.initialize();
     120}
     121</script>
     122</head>
     123<body>
     124<div id="Toolbar" style="position: relative; width: 400px; height: 24px">
     125    <div id="ZoomIn"></div>
     126    <div id="ZoomOut"></div>
     127    <div id="Pan"></div>
     128</div>
     129<div id="Map" style="position: relative; width: 400px; height: 400px"></div>
     130</body>
     131</html>
     132}}}
     133
     134It is highly recommended to use a valid doctype for your Fusion application template pages.  If you omit the doctype or use an invalid doctype, most browsers will revert to a mode called ''Quirks Mode''.  Fusion will mostly function correctly, but you may notice some minor issues and your application may appear differently depending on the browser.  By using a valid HTML or XHTML doctype, browsers will use a mode called ''Standards Compliant Mode'' and your application will work consistently between different browsers.
     135
     136You will need to make sure that the '''src''' of the script tag that points to {{{fusion.js}}} is a valid path, it can be relative (as in the example above) or absolute (starting with http://).  If it is absolute, then the url must be pointing to the same server as the url you use to load the application.
     137
     138That is all that is needed to build a fully functional Fusion application.  Save your files and then load the application by entering the URL to the {{{index.html}}} page in your web browser.  If everything is set up correctly, you should see three buttoms appear, followed shortly by a square map image below the buttons.  You can click any of the buttons to activate them, and use them on the map.
     139
     140== Under the Hood ==
     141
     142As you can see, quite a lot of things are going on without a lot of code.  Adding other widgets is as simple as adding an HTML container for them in the HTML page and adding a Widget in the WidgetSet.  So how exactly does Fusion turn this small amount of HTML and XML into a functional web mapping application?
     143
     144The first  important step is including fusion.js in your web page (the first script tag in the ''Hello Sheboygan'' example).  This makes Fusion available to your application.  The second important step is invoking the {{{Fusion.initialize()}}} method during (or after) the '''onload''' event of the web page (the contents of the second script tag).  {{{Fusion.initialize()}}} starts the process of getting the application running and the following steps happen:
     145
     146 * the Fusion configuration file (config.json) is loaded and parsed
     147 * the ApplicationDefinition configuration file is loaded and parsed
     148 * Widgets with associated HTML elements are identified
     149 * the !JavaScript file associated with each identified Widget is loaded
     150 * any dependencies of the Commands are loaded
     151 * when all Commands (and their dependencies) are loaded, a new instance of each Command is created for each HTML element.
     152 * when all Commands have been initialized, the FUSION_INITIALIZED event is emitted.
     153
     154An important step in this process is the loading of the Map widget(s).  After each Map widget has been created, it:
     155
     156attempts to create a session with the server for that Map instance.  All Map instances will share the session.
     157if an initial map is specified:
     158issue a MAP_LOADING event
     159attempt to load the Map (which will wait until the session has been created)
     160issue a MAP_LOADED event when the map has finished loading
     161 
     162All Commands (except Map Commands) are associated with a specific Map Command by name.  If a specific Map Command Name is not specified in the Command, then the Command will be associated with the first Map in the WebLayout.  As most applications have only one map instance, it is typical to leave out the explicit MapName when defining Commands.
     163
     164Most Commands require the Map to be loaded in order to be usable in the application.  As it is possible to define a Map Command without providing a default map for it to load, some widgets are designed to allow selecting a Map to load.  These widgets are typically enabled even when no map is loaded.
     165
     166For widgets that do require a Map to be loaded, they automatically register for the MAP_LOADED event and will enable themselves as soon as this event has been issued.
     167
     168Fusion Architecture
     169
     170Fusion Integration into MGOS
     171
     172MapGuide Open Source architecture is divided into three tiers:
     173
     174Server Tier.  This tier runs the MGOS server.  Fusion is not integrated into this tier.
     175Web Extensions Tier.  This tier runs with a Web Server.  Fusion is installed in this tier and makes use of the MGOS Web Extensions API to implement some functionality.
     176Client Tier.  This tier runs in the client's web browser.  Most of Fusion exists in this tier, and it completely replaces the existing MGOS client tier (known as the AJAX viewer).
     177
     178Diagram 1 shows how Fusion integrates into the MGOS Tiers.  The blue blocks are new Fusion components and the light grey blocks are existing MGOS components.
     179
     180The Fusion Server components work directly with the MGOS PHP API to implement specific functionality such as buffering features and working with selections.
     181
     182The Fusion JavaScript API and widgets are installed with the MGOS Web Tier, but they are actually loaded up to and executed in the Client Tier.
     183WebLayouts, HTML and Widgets
     184
     185The API and widgets are linked to specific HTML elements within an HTML page through the WebLayout XML document.  A widget is the executable code (javascript class) that is loaded when Fusion identifies an HTML element id and WebLayout command name that are the same.  The Action of the WebLayout Command identifies the exact javascript file to be loaded and the javascript object that needs to be instantiated to create a functional widget.  The runtime instance of the javascript object is the widget.
     186
     187When the runtime instance is created, it uses the HTML element id to determine where in the HTML page it should display its user interface.  Any custom configuration for the widget is placed in the WebLayout Command XML block as sub tags (each widget has its own list of what customization is possible, see the Command API Reference for details). 
     188
     189If you are customizing the look and feel of a single widget by overriding the CSS styling for the widget, this is normally done by using the #<id> syntax to limit your changes to that specific widget.
     190Understanding WebLayouts
     191
     192A Web Layout is an XML document that provides control over the appearance and behaviour of elements of a Fusion application.  It consists of blocks of XML that control various aspects of a Fusion application.  The root element of a Web Layout document is always <WebLayout>.
     193The following elements may exist within the WebLayout element:
     194Map
     195ToolBar
     196CommandSet
     197Map
     198
     199The Map block is optional and may occur 0 or more times.  It defines per-Map metadata that cannot be stored with the Map in any other way.  The Map block contains the following elements:
     200ResourceId.  The ResourceId tag identifies the Map to which this metadata is relevant.
     201Links.  Links are used to identify external URLs that contain information related to groups or layers.  Links are discussed in more detail below.
     202LayerEvents.  LayerEvents are used to make changes to the visibility of related groups and/or layers when a layer or group changes visibility.  LayerEvents are described in more detail below.
     203Links
     204
     205The Links block can contain any number of Group and Layer blocks.  Group and Layer blocks contain identical tags:
     206Name.  This tag is used to identify a Group or Layer by its name.
     207Url.  This tag is the href that is opened when the user wants to get information about the Group or Layer.  It may be absolute or relative, but if it is relative, it is relative to the application.
     208
     209Example Links block:
     210
     211<Links>
     212  <Group>
     213    <Name>Transportation</Name>
     214    <Url>http://localhost/transportation.html</Url>
     215  </Group>
     216  <Layer>
     217    <Name>Parcels</Name>
     218    <Url>http://localhost/parcels.html</Url>
     219  </Layer>
     220</Links>
     221LayerEvents
     222
     223The LayerEvents block can contain any number of Layer and/or Group blocks.  A Layer or Group block identifies the Layer or Group to which it applies in a Name tag.  There are two additional blocks that control what happens when the Layer or Group changes visibility.  The OnEnable block is used when the Layer or Group becomes visible, and the OnDisable block is used when the Layer or Group becomes hidden.  Both blocks have the same structure.  They contain any number of Layer or Group blocks that contain a Name tag (which identifies a Layer or Group) and an Enable tag (which determines if the Layer or Group should become visible or hidden).
     224
     225When any layer or group changes visibility via the legend control or programmatically via the API, if a LayerEvent exists for that Layer or Group, then the appropriate OnEnable or OnDisable block will be 'executed' as well.  This means any layers or groups in the appropriate block will change state as dictated by the Enable tag of that Layer or Group.
     226
     227Example LayerEvents block:
     228
     229<LayerEvents>
     230  <Layer>
     231    <Name>RoadBuffer</Name>
     232    <OnEnable>
     233      <Layer>
     234        <Name>RoadCenterline</Name>
     235        <Enable>true</Enable>
     236      </Layer>
     237    </OnEnable>
     238    <OnDisable>
     239      <Layer>
     240        <Name>RoadCenterline</Name>
     241        <Enable>false</Enable>
     242      </Layer>
     243    </OnDisable>
     244  </Layer>
     245</LayerEvents>
     246Example
     247
     248A complete Map block example:
     249
     250<Map>
     251  <ResourceId>Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition</ResourceId>
     252  <Links>
     253    <Group>
     254      <Name>Transportation</Name>
     255      <Url>http://localhost/transportation.html</Url>
     256    </Group>
     257    <Layer>
     258      <Name>Parcels</Name>
     259      <Url>http://localhost/parcels.html</Url>
     260    </Layer>
     261  </Links>
     262  <LayerEvents>
     263    <Layer>
     264    <Name>RoadBuffer</Name>
     265      <OnEnable>
     266        <Layer>
     267          <Name>RoadCenterline</Name>
     268          <Enable>true</Enable>
     269        </Layer>
     270      </OnEnable>
     271      <OnDisable>
     272        <Layer>
     273          <Name>RoadCenterline</Name>
     274          <Enable>false</Enable>
     275        </Layer>
     276      </OnDisable>
     277    </Layer>
     278  </LayerEvents>
     279</Map>
     280ToolBars
     281
     282ToolBars are provided as a convenience for creating user interface elements that are displayed as a horizontal toolbar of buttons, menus and separators.  A Web Layout may specify zero or more ToolBar tags.
     283A ToolBar contains the following sub-tags:
     284Name.  Required.  This is a unique name for the ToolBar.  The ToolBar element that is created has an HTML id with this value.
     285Container.  Required.  This is the HTML id of an element (typically a DIV) that the ToolBar is to be created within.  More than one ToolBar can be assigned to the same container.
     286Visible.  Optional.  This contains either true or false, indicating the initial visibility of the ToolBar.  The default value is true.  There is currently no way to change the visibility of a ToolBar so it is recommended to leave this tag out or set it to true.
     287Button.  Optional.  There can be zero or more Button blocks in a ToolBar, although a ToolBar with no buttons has no purpose.  Button blocks are described in more detail below.
     288Button blocks
     289
     290A Button block inside a ToolBar is used to make something appear in the user interface.  The order of Buttons in the ToolBar is used to determine the order of the elements in the user interface.  A Button block contains a mandatory Function tag which must contain one of the following values:
     291Command.
     292Flyout
     293Separator
     294
     295If the Function tag value is Command, the Button is a clickable button that activates a Command described in the WebLayout.  This Button block contains one more tag, Command, which contains the name of a Command to be found in the CommandSet (Commands and the CommandSet are described below.
     296
     297If the Function tag value is Flyout, the Button is specifying a drop-down menu that opens when the user clicks the Button in the ToolBar.  This Button block contains a Label tag, which contains the text displayed in the ToolBar, and some number of SubItem tags that specify the items in the menu.  The SubItem blocks are structured identically to a Button block, and contain a Function tag and variable other tags depending on the value of the Function tag.  Flyout menus can contain sub-menus by specifying a Function tag value of Flyout.
     298
     299If the Function tag value is Separator, the Button specifies a visual separator is to be placed in the ToolBar.  Separators have no other tags in their Button block.
     300
     301An example of a ToolBar block is:
     302
     303<ToolBar>
     304  <Name>MainToolbar</Name>
     305  <Container>ToolbarContainer</Container>
     306  <Visible>true</Visible>
     307  <Button>
     308    <Function>Command</Function>
     309    <Command>ZoomIn</Command>
     310  </Button>
     311  <Button>
     312    <Function>Command</Function>
     313    <Command>ZoomOut</Command>
     314  </Button>
     315  <Button>
     316    <Function>Flyout</Function>
     317    <Label>Extent History</Label>
     318    <SubItem>
     319      <Function>Command</Function>
     320      <Command>PreviousExtent</Command>
     321    </SubItem>
     322    <SubItem>
     323      <Function>Command</Function>
     324      <Command>NextExtent</Command>
     325    </SubItem>
     326  </Button>
     327</ToolBar>
     328
     329CommandSet
     330
     331The CommandSet block is mandatory and only one CommandSet block is allowed in the WebLayout.  The CommandSet block contains one or more Command blocks.  The Command blocks are used to configure widgets.
     332
     333Although the content of a Command block is dictated by the type of widget that the Command will create, some elements of Command blocks are common.  This document describes the common elements.  Additional configuration of Commands is described in the Command Reference document.
     334
     335All Command blocks contain the following tags:
     336
     337Name.  The Name of the Command is used by Fusion to determine where the Command is to be placed in the user interface.  The Command will be created inside an HTML element that has an id with the same value as the Command's Name.  In the case of a Command that is referenced by a ToolBar, the Command does not require an HTML element as the ToolBar will create one for the Command.  Each Command must have a unique Name.
     338Action.  The Action of the Command is the actual widget that will be created for the Command.  If a Command references a widget that does not exist, an error will occur that will prevent the application from loading.
     339Location.  This is an optional tag and is used to identify where custom widgets can be found.  If Location is not provided, the widget is assumed to be one of the stock widgets distributed with Fusion.  If the Location is provided, it must be a relative path to the directory containing the widget's javascript file.  Fusion has an ext directory and, by convention, custom widgets (and optional packages of widgets) are installed in sub-directories under this directory.  If you follow this convention, the Location tag would contain a value like 'ext/mywidgets'.
     340TargetViewer.  This tag is provided for backwards compatibility.  It is not used by Fusion and is ignored.  In future versions, this tag will be removed entirely.  It should contain a value of 'All'.
     341
     342Please use the Command Reference document to find out about the specific tags used by the various widgets.
     343Understanding Events
     344
     345The event code in Fusion is designed to provide an asynchronous notification mechanism that can be used to register for, and receive notification of, key events that happen asynchronously in Fusion.  The following terms are used with respect to events:
     346
     347event id: a unique identifier for an event, represented by a javascript variable that is all in upper case (e.g FUSION_INITIALIZED)
     348trigger: when an event occurs, it is 'triggered' and all the registered callback functions are notified
     349register: provide a callback function that is called when an event is triggered
     350deregister: remove a callback function that was previously registered
     351publish: anything that can trigger an event must publish all the valid event ids
     352
     353The event mechanism of Fusion is implemented by two functions: registerForEvent and deregisterForEvent.  Both functions have the same signature, taking an event ID as the first parameter and a callback function pointer as the second parameter.
     354
     355The Fusion application object provides two specific events that can be used by applications to get notification of when Fusion initialization has completed and when an error occurs anywhere in Fusion.  These events are:
     356
     357FUSION_INITIALIZED.  This is triggered when Fusion's initialization is complete and the application is running.  This signals that it is safe for the application to communicate with specific widgets.  Note that the Map widget, specifically, will be ready but may not have actually loaded the map.  There is a separate event for that (see the Map widget in the Command API reference).  Applications should register for this event before calling Fusion.initialize().
     358FUSION_ERROR.  This is triggered when an internal error happens.  Details on the error are passed to the callback function.  Applications should register for this event before calling Fusion.initialize() to ensure that they receive errors that happen during initialization.
     359
     360Widgets in Fusion also use and trigger events.  Widgets are designed to be completely independent of one another, allowing them to be added to, or removed from, applications with little or no impact on the other widgets in the application.  However, there are cases (especially with the Map widget) where it is important that widgets be able to communicate with other widgets or with the application as a whole.  For these situations, there is an event mechanism built into Fusion that allows widgets, and applications built on Fusion, to register for and trigger events.  The event mechanism allows widgets to be independent of each other, but still provide a high level of integration when required.
     361
     362To register a callback function for a widget event, the application must first obtain a reference to the widget through one of the methods of the Fusion object (getWidgetById typically) and then call registerForEvent passing one of the event IDs that is valid for that widget.
     363
     364Working with Maps
     365
     366In Fusion, the Map widget is central to everything that is going on.  It is not valid to design a Fusion application without a Map in it.  The Map widget is the primary interface between the application and the spatial data represented by the map.  Most widgets in Fusion either display information about the map or allow the user to interact with the map in some way.
     367
     368The Map widget API is probably the most used one in Fusion.  It is completely documented in the Command API reference, but the most used methods are described here.
     369
     370loadMap(mapDefinition).  This causes the Map widget to load the specified MapDefinition.
     371reloadMap().  This causes the Map widget to reload the current MapDefinition.  This is necessary when the map state has changed in certain ways (adding or removing layers in the map, for instance) and is primarily an internal function.
     372setExtents(minx, miny, maxx, maxy).  This is used to set the map extents to a particular bounding box programmatically.
     373drawMap().  This is used to render a map image and load it in the browser.  Normally, this is called automatically as required, but occasionally it may be required to be called programmatically when the state of the map has changed on the server without the knowledge of the Map widget.
     374query(options).  This is described more completely in the Command API Reference, but the query method is used to query the Map in some way and create (or modify) a selection.
     375getSessionId()
     376
     377When a Map is defined in the WebLayout file, it can have a default MapDefinition that is automatically loaded when the application is loaded.  But it is not mandatory to specify a default map.  When no default map is specified, the Map widget is still initialized.  Loading of a MapDefinition is then done in response to a widget (such as the MapMenu widget) or some application-specific code.  Regardless of how it happens, when a MapDefinition has been loaded, the Map widget will trigger a MAP_LOADED event.&nbsp; Most widgets are not useful if there is no map loaded, so they use the MAP_LOADED event to determine when they should be enabled.  This means that most widgets will appear initially disabled until the map has been loaded.  There are some notable exceptions, including the Map Menu widget which is used to provide a drop-down menu of MapDefinitions that the user can pick from.
     378
     379Once the Map is loaded, many events may be triggered, including:
     380
     381MAP_SESSION_CREATED.  The Map widget is responsible for creating and maintaining a session with the server.  When the session has been created, this event is triggered.  Nothing can happen until this event has been triggered.
     382MAP_LOADING.  The Map widget triggers this event when it is starting to load a new Map.  This is primarily used by widgets to prepare themselves for the new map by discarding their current state and temporarily disabling themselves.
     383MAP_LOADED.  The Map widget triggers this event when a map has been loaded and is ready.
     384MAP_EXTENTS_CHANGED.  The Map widget triggers this event for any navigation that changes the current extents.
     385MAP_BUSY_CHANGED.  The Map widget maintains a reference count of asynchronous events as they start and finish.  An application can use this event to display a processing image so that the user is aware that some asynchronous activitity is happening.
     386MAP_RESIZED.  The Map widget triggers this event when the size of the map is changed.
     387MAP_SELECTION_ON.  The Map widget triggers this event when a new selection has been created.
     388MAP_SELECTION_OFF.  The Map widget triggers this event when the current selection has been cleared.
     389MAP_ACTIVE_LAYER_CHANGED.  The Map widget allows for a single layer to be marked as active by the application.  This event is triggered when the active layer is changed.
     390MAP_GENERIC_EVENT.  Most widgets rely directly on their Map widget for everything.  In some cases, though, widgets need to be informed of changes in other widgets.  In these cases, the Map widget can act as a broker for events through the MAP_GENERIC_EVENT.  Widgets that employ the MAP_GENERIC_EVENT normally do so for a specific internal purpose, and the application should not normally register for this event.
     391
     392Working with Selections
     393
     394There are several widgets in Fusion that allow the user to interactively select features on the Map.  Fusion takes care of updating the Map image with the current selection, if necessary, but does not display attributes of the selected features to the user.  That is up to the application.
     395
     396Regardless of how the features are selected, the Map widget provides the API for an application to retrieve and work with the user's selection.  There are two events that can be used by an application to know when the user selection has changed:
     397
     398MAP_SELECTION_ON.  The Map widget triggers this event when a new selection has been created.
     399MAP_SELECTION_OFF.  The Map widget triggers this event when the current selection has been cleared.
     400
     401When the application receives a MAP_SELECTION_ON event from the Map widget, it can use the following functions to work with the selection:
     402
     403hasSelection().  This method returns a boolean value which indicates if there is currently a selection or not
     404getSelection(callback).  This method retrieves the current selection.  Retrieving the selection is potentially an asynchronous operation and so the callee provides a callback function that is called when the selection is ready.  The callback function is passed a single argument, a Selection object, described below.
     405clearSelection().  This method is used to clear the current selection.  This removes the selection from the map and invalidates the current selection object.
     406
     407An application will typically call getSelection() in response to the MAP_SELECTION_ON event.  Typical code for this might look like:
     408
     409window.onload=function() {
     410    Fusion.registerForEvent(FUSION_INITIALIZED, onInitialized);
     411    Fusion.initialize();
     412}
     413
     414var theMap;
     415function onInitialized() {
     416    theMap = Fusion.getWidgetById('Map');
     417    theMap.registerForEvent(MAP_SELECTION_ON, selectionOn);
     418    theMap.registerForEvent(MAP_SELECTION_OFF, selectionOff);
     419}
     420
     421function selectionOn() {
     422    //a new selection has been made, request it
     423    theMap.getSelection(displaySelection);
     424}
     425
     426function displaySelection(selection) {
     427    //display the selection to the user in some way ...
     428}
     429
     430function selectionOff() {
     431    //clear the selection results
     432}
     433
     434A Selection object is used to access the selection results.  It provides the following API:
     435
     436getNumLayers() returns the number of layers that have features selected
     437getNumElements() returns the total number of features that are selected
     438getLowerLeftCoord() returns the lower, left coordinate of the bounding box of all selected features
     439getUpperRightCoord() returns the upper, right coordinate of the bounding box of all selected features
     440getLayerByName(name) gets the layer selection object for a layer from the name of the layer.  This returns null if there is no layer with the requested name in the selection results
     441getLayer(index) gets the layer selection object for the requested layer where index is between 0 and one less that the value returned by getNumLayers().
     442
     443An application will typically loop over the layers in a selection and retrieve individual results using the Layer Selection object returned by getLayer() or getLayerByName().  Layer selection objects have the following API
     444
     445getName() returns the name of the layer that the selected features are in
     446getNumElements() returns the number of features selected in this layer
     447getNumProperties() returns the number of data properties, or attributes, of the features in this layer
     448getPropertyNames() returns an array of the names of each of the properties
     449getPropertyTypes() returns an array of the types of the properties
     450getElementValue(elementIndex, propertyIndex) returns the actual value of a given property for a given element
     451
     452       
     453The following code is an example of how to use the Selection and Layer Selection objects to create a tabular display of selected features.
     454
     455function displaySelection(selection) {
     456    //display the selection to the user in some way ...
     457    //make sure something got selected ...
     458    if (selection && selection.getNumElements() > 0) {
     459       //obtain a reference to the HTML Element that the results
     460       //will be placed in
     461       var resultElm = $('selectionResultDiv');
     462       for (var i=0; i<selection.getNumLayers(); i++) {
     463          var selectionLayer = selection.getLayer(i);
     464          var propNames = selectionLayer.getPropertyNames();
     465          var span = document.createElement('span');
     466          span.className = 'selectionResultsTitle';
     467          span.innerHTML = 'Layer ' + selectionLayer.getName();
     468          resultElm.appendChild(span);
     469          var table = document.createElement('table');
     470          table.className = 'selectionResultsTable';
     471          resultElm.appendChild(table);
     472          //set up the table header to be the property names         
     473          var thead = document.createElement('thead');
     474          table.appendChild(thead);
     475          var tr = document.createElement('tr');
     476          thead.appendChild(tr);
     477          for (var j=0; j<propNames.length; j++) {
     478             var td = document.createElement('td');
     479             td.innerHTML = propNames[j];
     480             tr.appendChild(td);
     481          }
     482          //output the selection values
     483          var tbody = document.createElement('tbody');
     484          table.appendChild(tbody);
     485          for (var j=0; j<selectionLayer.getNumElements(); j++) {
     486             var tr = document.createElement(tr);
     487             tbody.appendChild(tr);
     488             for (var k=0; k<propNames.length; k++) {
     489                var td = document.createElement('td');
     490                td.innerHTML = selectionLayer.getElementValue(j, k);
     491                tr.appendChild(td);
     492             }
     493          }
     494           }
     495    } else {
     496       //could display a message of some sort saying nothing was selected?
     497    }
     498}
     499