Developing Web Applications with the Web ADF - Web ADF JavaScript Library  

Graphics and map tips


The Web ADF JavaScript library contains the components necessary to create, manage and render graphics on the client.   Client-tier graphics are termed "graphic features" and consist of geometry, attributes, and symbology.   Graphic features are designed to be displayed within an ADF Map control, thus a Map control must be present in the page to view them.  Since graphic features persist as elements within a browser, they can be interacted with using standard client actions, such as when the mouse cursor hovers over or clicks on an element.     The ADF MapTips client control is designed to interactively display attributes of a graphic features be handling mouse actions on the feature.    The following diagram illustrates the relationships between graphic features and their component relationships. 
 
The GraphicFeatureBase component provides the properties and event handlers that can be applied to individual graphic features and groups of graphic features.   The properties enable you to set the default, selected, and highlight symbol.   The highlight symbol is frequently used to identify the graphic feature over which the mouse cursor is hovering.   MapTips can be applied to one or more graphic features using the GraphicFeatureBase mapTips property.   In addition, a set of mouse events are available to handle click, mouse over, mouse out and mouse move events.

The GraphicFeature component extends GraphicFeatureBase to represent one graphic feature using geometry and attributes.  You can consider a GraphicFeature to be a spatially enabled row of data.    It can be explicitly highlighted and selected using the highlight and selected symbol define in the base component (GraphicFeatureBase).   

The GraphicFeatureGroup component extends GraphicFeatureBase to represent a group of graphic features.   You can consider a GraphicFeatureGroup a spatially enabled table (feature class) with one or more graphic features.  GraphicFeatureGroup enables you to apply common properties and behaviors across all graphic features it contains.   As a result, you can define one symbol for a GraphicFeatureGroup and have it apply to all graphic features it contains.   Likewise you can define the opacity and visibility of all graphic features in the group. 

Working with client-side graphics (ESRI.ADF.Graphics)

There are two techniques for working with client-side graphics in the ADF using JavaScript: 1) create and manage graphics in the Web-tier and render on the client or 2) Create, manage and render graphics all on the client.  Option 1 involves using Web ADF .NET graphics resources and layers to store and manage graphics content but renders graphics on the client using ADF JavaScript components.  Graphics are available via .NET in the Web-tier and JavaScript on the client.    Option 2 consists of creating, managing and rendering graphics on the client using ADF JavaScript components.  Graphics are only available on the client (in browser memory).   Option 1 is discussed in another topic, although some of the client-side logic may overlap with option 2.   The remainder of this document will cover option 2.   Subcomponents of GraphicFeatures and GraphicFeatureGroups will be discussed, such as geometry and symbols, and optional components such as MapTips will be presented.  This document will conclude with a section on the creating and rendering GraphicsFeatures in a map.     

Geometry (ESRI.ADF.Geometries)

All graphic features use geometry to define their spatial component and a symbol to define how the geometry is displayed in the map.  The ADF JavaScript library includes a set of simple geometry types to store and work with spatial entities on the client.  Geometry can be created explicitly or via interaction with the Map client control.   For example, to create a new Point:

<script type="text/javascript">
	var newGeometry = new ESRI.ADF.Geometries.Point(-120,45);
</script>
					
Both Polylines and Polygons consist of parts (paths and rings, respectively).  Each part is created and\or accessed as a CoordinateCollection component.  For example, to create a Polygon with a single ring, review the following JavaScript code:
<script type="text/javascript">
	var ringString = "-120,45 -110,34 -115,42";		
	var pointArray = ringString.split(' ');
	
	var newRing = new ESRI.ADF.Geometries.CoordinateCollection();
	
	for(var i=0;i<pointArray.length;i++) {
		newRing.add(ESRI.ADF.Geometries.Point.fromString(pointArray[i]));
	}
  
	var map = $find('Map1');
	var newPolygon = new ESRI.ADF.Geometries.Polygon(newRing, map.get_spatialReference());
</script>
					
The CoordinateCollection component stores an array of Points.   Each Point is created using the convenience function fromString which assume a comma-delimited coordinate value.  The Polygon constructor optionally accepts a single Ring (CoordinateCollection) and a spatial reference. 

In many cases, geometry will be retrieved via interaction with the map.  The Map component maintains a function getGeometry() which configures the Map to capture user input.   The getGeometry() function has the following input parameter:
    
getGeometry Parameter Description 
type The shape type to capture via interaction with the map.  Valid types are defined in ESRI.ADF.Graphics.ShapeType and include:

Point, Line, Path, Envelope, Circle, Oval, Ring
onComplete

The JavaScript function to call when drawing geometry is complete.  The geometry entered is passed as an argument.  

If type = Ring, argument is of type Polygon.

If type = Line or Path, argument is of type Polyline.

If type = Envelope, argument is of type Envelope.

If type = Circle or Oval, argument is of type Oval.  

onCancel The JavaScript function to call if drawing geometry was cancelled.  Optional parameter.   
fillColor HTML color code for fill color used when drawing. The fill color will apply to surface types and have an opacity value of 0.2.  Opacity values range from 0 (transparent) to 1 (opaque). Default is none.  Optional parameter. 
lineColor HTML color code for line color used when drawing. The line color will be used as outline color for surface types.  Line size is 2 pixels.  The default color is black.  Optional parameter.
cursor

The style cursor to use when entering geometry.  Cursor types include 'hand', 'crosshair', and 'pointer'.  Default is crosshair.  Optional parameter.  

continuous If true, keeps collecting geometries until cancelGetGeometry() is called or the Map's  mouse mode changes.  Default is false.  Optional parameter.


Call the getGeometry() function to put the Map in a state to accept user input geometry.   By default, the Map's mouse mode is set to ESRI.ADF.UI.MouseMode.Custom, which means you are responsible for processing user input.  In this case, the JavaScript function specified when drawing geometry is completed will contain the logic to process the input.   Only one function can be called when drawing geometry has completed - you cannot call getGeometry() on the map multiple times and capture input geometry in multiple functions at the same time.  

The following code illustrates the basic use of the getGeometry() function - to get geometry input by the user when interacting with the map.  In this example, a key action (pressing the "a" key) will change the mouse mode of the map to accept a user provided envelope.     

					
<script type="text/javascript">

	var map;

	Sys.Application.add_init(initialize);

	function initialize() {
		map = $find('Map1');	

		var keyDownGetGeometry = function() 
		{     	    	        
			map.getGeometry(ESRI.ADF.Graphics.ShapeType.Envelope, useGeometry, null, 'red', '#0000FF', 'pointer', true);
		};
	    
		var keyUpCancelGeometry = function()
		{
			map.cancelGetGeometry();
		};        
	    
		// Key action when the "a" key is pressed
		map.setKeyAction(65,keyDownGetGeometry, keyUpCancelGeometry, null, false);  
	}

	function useGeometry(inputGeometry)
	{
		map.zoomToBox(inputGeometry, true);
	}		
	
</script>								

The call to getGeometry specifies the shape type of Envelope, the function useGeometry to process the user provided envelope, and a null reference because a function will not be called if getGeometry is cancelled.   Additional parameters specify the color red for the envelope outline, the HTML code for the color blue to define the partially transparent fill of the envelope, a pointer as the mouse cursor while the envelope is entered, and a final boolean value of 'true' to indicate that as long as cancelGetGeometry has not been called, getGeometry is in effect.  In this case, the key up event calls cancelGetGeometry() so as long as the "a" key is pressed the user can digitize an envelope.   At runtime, the user provided envelope may appear as follows:




The useGeometry function illustrates how the input geometry may be used.  In this case a call to the zoomToBox function on the map client control changes the extent of the map to coincide with the user provided envelope.   Note, to cancel getGeometry() call cancelGetGeometry() or change the Map's mouse mode (set_mouseMode). 

Creating GraphicFeatures

The colors specified in the getGeometry function are merely designed to provide visible graphics while a user is interacting with the map.  Once the geometry is created or captured, it must be packaged as a GraphicFeature and associated with a symbol to persist as graphics in the map.   A GraphicFeature is uniquely designed to store geometry and attributes as a client-tier feature.   When creating a GraphicFeature, you can give each one a unique id and use the set_geometry and set_attributes properties to add geometry and attributes, respectively.   Alternatively, use the Microsoft AJAX JavaScript library shortcut function $create to create a GraphicFeature in one line of code.   The following code block build on the map key action handler discussed earlier to digitize a user defined ring and create a GraphicFeature:

	function initialize() {
		map = $find('Map1');	

		// Function that will be called when the "a" key is pressed
		var keyDownGetGeometry = function() 
		{     	    	        
			map.getGeometry(ESRI.ADF.Graphics.ShapeType.Ring, drawGeometry, null, 'red', '#0000FF', 'pointer', true);
		};

		var keyUpCancelGeometry = function()
		{
			map.cancelGetGeometry();
		};        

		map.setKeyAction(65,keyDownGetGeometry, keyUpCancelGeometry, null, false);  
	}

	var graphicCount = 0;

	function drawGeometry(inputGeometry)
	{ 
		var coords = inputGeometry.getRing(0).toString("<br>", ",");	                
		var attributes = {"graphicID": graphicCount ,"featureCoordinates" : coords};
		var graphicFeature = $create(ESRI.ADF.Graphics.GraphicFeature,{"id":graphicCount.toString(),"geometry":inputGeometry,
			"attributes":attributes});
		graphicCount++;
	}

The feature type for the getGeometry function call is set to Ring and the function to process the input geometry points to drawGeometry.  In the drawGeometry function the inputGeometry (a Polygon with one Ring) is interrogated to return its coordinates.   The toString() function, valid for all geometry types at some level, can be used to  convert geometry into a string.  In most cases you can define how the points and coordinates are separated.  In this example, the points in a Ring (a CoordinateCollection) are separated by an HTML page break (<BR>) and the individual coordinates are separated by a comma.    The string returned is stored as an attribute with the GraphicFeature.  Attributes are defined using an array of string:object pairs.    Consider the string to be a field name and the object to be a field value.  The pairs are wrapped in curly brackets and separated by a comma. 

The $create shortcut function requires the type definition and an optional set of properties, event handlers, etc.  In this example the type is ESRI.ADF.Graphics.GraphicFeature and the properties are id, geometry, and attributes.   A unique id is recommended to qualify the GraphicFeature; in this case an iterator stores an integer value.  The geometry property is set to the user defined polygon and the attributes property is set to the variable referencing the array of field:value pairs.  At this stage the GraphicFeature has been created but need to be associated with a symbol to be rendered in the map.   

Symbols (ESRI.ADF.Graphics)

A GraphicFeature must be associated with a symbol to be rendered in a map. A set of simple symbol components are provided by the ADF JavaScript library.  The geometry type and symbol types that can be used to render it are listed in the table below:

Geometry type Supported Symbol types
Point MarkerSymbol
Polyline LineSymbol 
Surfaces:
Polygon
Envelope
Oval
LineSymbol (boundary)
FillSymbol (fill)
         
For all symbol types you can define the opacity (0-1) and cursor when the mouse hovers over the GraphicFeature using the symbol.  GraphicFeatureBase defines three properties you can use to associate symbology with a GraphicFeature or a group of GraphicFeatures (GraphicFeatureGroup): symbol, highlightSymbol and selectedSymbol.   The following table defines when a GraphicFeature uses which symbol:

GraphicFeatureBase symbol property Description
symbol Default symbol used if a GraphicFeature's highlight and isSelected properties are false.
highlightSymbol The highlightSymbol is used if a GraphicFeature's highlight property is true.  In many cases the highlight property is set to true on a mouse over event of the GraphicFeature - and false on mouse out.   
selectedSymbol
The selectedSymbol is used if a GraphicFeature's isSelected property is true.  The property may be used to define a subset of GraphicFeatures within a group.

The ADF JavaScript library does not provide a renderer, instead the symbol properties on GraphicFeatureGroup operate as a "simple renderer" for all GraphicFeatures.  To simulate a unique value or range renderer, each classification would require a separate GraphicFeatureGroup.   Since symbols are often applied to GraphicFeatureGroups, the next section will discuss GraphicFeatureGroup creation and apply symbology where appropriate. 

Creating GraphicFeatureGroups

GraphicFeatureGroups contain and manage a collection of GraphicFeatures.  In essence, they emulate a simple feature class in the ADF JavaScript library.  Symbols associated with a GraphicFeatureGroup are applied to all GraphicFeatures it contains.  A set of collection management functions, such as add(), remove(), and get(), enable the manipulation and interaction with the group contents.  The visible and opacity properties provide a means for adjusting the visible properties of all features.    
While symbols can be applied to individual GraphicFeatures, they are often applied to GraphicFeatureGroups for ease of use.   Building on the example discussed earlier, the following code defines a default and highlight symbol for a Polygon, creates a GraphicFeatureGroup and applies the symbols, then adds a GraphicFeature.  Recall that the GraphicFeature was created using geometry entered by the user:

	
	var graphicCount = 0;

	function drawGeometry(inputGeometry)
	{ 
		var coords = inputGeometry.getRing(0).toString("<br>", ",");	                
		var attributes = {"graphicID": graphicCount ,"featureCoordinates" : coords};
		var graphicFeature = $create(ESRI.ADF.Graphics.GraphicFeature,{"id":graphicCount.toString(),"geometry":inputGeometry,
			"attributes":attributes});
		graphicCount++;

		var graphicFeatureGroupID = "polygonGraphics";            
		var graphicFeatureGroup = $find(graphicFeatureGroupID);

		if(!graphicFeatureGroup) 
		{                        
			var defaultSymbol = new ESRI.ADF.Graphics.FillSymbol('white','blue',2,'default');
			defaultSymbol.set_opacity(0.5);

			var highlightSymbol = new ESRI.ADF.Graphics.FillSymbol('yellow','green',4,'pointer');
			highlightSymbol.set_opacity(0.5);

			var graphicFeatureGroup = $create(ESRI.ADF.Graphics.GraphicFeatureGroup,
				{"id":graphicFeatureGroupID,"symbol":defaultSymbol,"highlightSymbol":highlightSymbol});

			map.addGraphic(graphicFeatureGroup); 
		}     
		graphicFeatureGroup.add(graphicFeature); 
	 }

Each GraphicFeatureGroup should have a unique id; in this case it is "polygonGraphics".   The code checks for the existence of the GraphicFeatureGroup using the Microsoft AJAX shortcut function $find().  If it exists, merely add the GraphicFeature.  If not, such as when the first GraphicFeature is created, define a default and highlight symbols assign to a new GraphicFeatureGroup created using the $create() shortcut function.   The FillSymbol constructor defines the fill and outline colors, the outline width, and the cursor when the mouse hovers of the symbol.   To view the GraphicFeatureGroup content in the map, call the addGraphic function on the map component.   This will be discussed in greater detail in the next section.  The screenshot below illustrates how this code may function at runtime, enabling the user to add multiple GraphicFeatures to the same GraphicFeatureGroup, rendered using the default symbol. 


The highlight symbol was defined but not used.  How can we utilize it?  In many cases the highlight symbol is used to indicate that a mouse cursor has moved over a GraphicFeature.   GraphicFeatureBase defines a set of event handlers to track mouse actions on GraphicFeatures and groups.  In this case, we should define a set of functions to handle the mouseOver and mouseOut events when the GraphicFeatureGroup is created.   The code block below shows the creation of a GraphicFeatureGroup with the mouse out and over functions defined.  Both event handlers receive the GraphicFeatureGroup (sender) and mouse event which contains a reference to the GraphicFeature element. 

	var graphicFeatureGroup = $create(ESRI.ADF.Graphics.GraphicFeatureGroup,
		{"id":graphicFeatureGroupID,"symbol":defaultSymbol,"highlightSymbol":highlightSymbol},
		{"mouseOver":onMouseOverGraphics,"mouseOut":onMouseOutGraphics});
. . .
	
	function onMouseOverGraphics(sender, eventArgs) 
	{	
		eventArgs.element.set_highlight(true);
	}

	function onMouseOutGraphics(sender, eventArgs) 
	{
		eventArgs.element.set_highlight(false);
	}				
					
When mousing over a GraphicFeature the highlight property for the feature is set to true and it is rendered using the highlight symbol defined for the GraphicFeatureGroup.  On mouse out, the GraphicFeature highlight property for the feature is set to false and it is rendered using the default symbol.  The following screenshot show how this may look at runtime.




Adding graphics to a map
 

The Map client control maintains three methods for managing the display of graphics in the map.  All three methods and descriptions are listed below:

Map method Description
addGraphic(GraphicFeatureBase) Add the GraphicFeature or group to the map.  If symbology is associated with the graphic features, they will display immediately. 
removeGraphic(GraphicFeatureBase) Remove the specified GraphicFeature or group from the map. 
  
refreshGraphics(force)
Re-renders all graphics associated with a map.  If force is true, this method will redraw all graphic features and hook up any events. 

Note, this method is called internally when the map initializes and when calling map.addGraphic().   It will not re-retrieve ADF .NET graphic layer content rendered on the client.

You can add individual GraphicFeatures or groups of GraphicFeatures.   If working with a group, you only need to add the group once - thereafter merely add GraphicFeatures to the group.   Once added, you can use the Microsoft AJAX library $find shortcut function and specify the id of the GraphicFeature or GraphicFeatureGroup to locate client graphic content. 

Technically there is no limit to the number of GraphicFeatures and groups that can be added to a map component.   Keep in mind that graphics rendered on the client reside in browser memory and thus require sufficient client-side resources to handle the volume.   As a result, manage client graphics wisely to balance performance and functionality. 

Defining Map Tips  

The ADF JavaScript MapTips component enables interaction with client graphics in a map by displaying graphic feature attribute content in an animated, HTML formatted dialog during a mouse over event on the respective graphic.   Associating map tips with a Graphic Feature or group is easily accomplished using the mapTips property.   Each MapTips component has a Callout component that represents the dialog that contains the GraphicFeature attributes.   A Callout represents the dialog and content associated with a map tip and maintains two states, open and closed.  When closed only information in the title of the Callout is visible.  When open both the title and body of the Callout is visible.  The MapTips component provides a few convenient properties to define the content of its callout.  In general, the content is represented by a template that can contain valid browser content, such as HTML, JavaScript, CSS, etc. for both the title and body of the callout.   The hoverTemplate defines content and formatting for the callout title while contentTemplate specifies the format of the callout body content.    The following code block builds on the drawGeometry() function presented in a previous example to add and enable map tips on the user provided geometry as a GraphicFeature:

	function drawGeometry(inputGeometry)
	{ 
		var ringCoords = inputGeometry.getRing(0).get_coordinates();
		for (var i=0;i<ringCoords.length;i++) 
		{
			ringCoords[i][0] = ringCoords[i][0].toFixed(2);
			ringCoords[i][1] = ringCoords[i][1].toFixed(2);
		}            
		var formattedCoords = new ESRI.ADF.Geometries.CoordinateCollection(ringCoords);	
		var coords = formattedCoords.toString("<br>", ",");                
		var attributes = {"graphicID": graphicCount ,"featureCoordinates" : coords};
		var graphicFeature = $create(ESRI.ADF.Graphics.GraphicFeature,{"id":graphicCount.toString(),"geometry":inputGeometry, 
			"attributes":attributes});
		graphicCount++;                   
		            
		var graphicFeatureGroupID = "polygonGraphics";            
		var graphicFeatureGroup = $find(graphicFeatureGroupID);

		if(!graphicFeatureGroup) 
		{                        
			var defaultSymbol = new ESRI.ADF.Graphics.FillSymbol('white','blue',2,'default');
			defaultSymbol.set_opacity(0.5);

			var highlightSymbol = new ESRI.ADF.Graphics.FillSymbol('yellow','green',4,'pointer');
			highlightSymbol.set_opacity(0.5);
					        
			var mapTips = $create(ESRI.ADF.UI.MapTips, { "id":"polygonGraphicsMapTips", "animate":false });
				
			mapTips.set_hoverTemplate("<b><nobr>Dynamic Map Tip {@graphicID}</nobr></b>");

			mapTips.set_contentTemplate('<span>Coordinates: <br><b>{@featureCoordinates}</b></span>')

			var graphicFeatureGroup = $create(ESRI.ADF.Graphics.GraphicFeatureGroup,{"id":graphicFeatureGroupID,
				"symbol":defaultSymbol,"highlightSymbol":highlightSymbol,"mapTips":mapTips},
				{"mouseOver":onMouseOverGraphics,"mouseOut":onMouseOutGraphics});

			map.addGraphic(graphicFeatureGroup); 
		}     
		graphicFeatureGroup.add(graphicFeature); 
	}				
					
					
      

There are four important items related to map tips in this code block:  

1) The attributes of a GraphicFeature are prepared for presentation in a callout.  The coordinate values of the input geometry are modified to provide a more presentable value.  This highlights the task of preparing attribute data associated with a GraphicFeature which will be presented in a map tip callout.     

2) The MapTips component is created using the $create shortcut function and associated with a GraphicFeatureGroup using the mapTips property.   Note that $create, rather than new, should always be used to create MapTips components, as the Web ADF expects MapTips to be registered as AJAX components, which is done automatically when using $create. 

3) There are two techniques for enabling map tips on graphics: create the graphics (GraphicFeature or group) and set the mapTips property -or- create the MapTips component and use the AddGraphics() function to associate with a GraphicFeature or group.   Both techniques produce the same results, thus the use of one or the other depends on developer preference.    

4) Set the content of the MapTips component by defining the hover (title) and content (body) portions of the map tips callout - use the hoverTemplate and contentTemplate properties, respectively.  Both templates are designed to contain browser supported content such as HTML, stylesheets, and JavaScript and display attribute values associated with a GraphicFeature.   In both templates a placeholder variable stores the location of a GraphicFeature attribute value using the format {@<attribute name> }.  The attribute value is populated when the map tip callout is displayed for a GraphicFeature, usually during a mouse over event on the feature.   The pertinent code and attributes are highlighted below:

      

A comprehensive sample of ADF JavaScript techniques and capabilities is available within this help system.   See the Common Custom JavaScript sample for instructions and code.