Working with Symbols and Renderers

Symbols define all the non-geographic aspects of a Graphic's appearance. This includes a Graphic's color, border width, transparency, and more. The ArcGIS Runtime SDK for iOS includes many symbol classes, each of which allows you to specify symbology in a unique way. Each symbol type is also specific to one geometry type (i.e. point, line, or polygon).

Renderers define sets of Symbols to apply to a Graphics layer. The Symbol applied to each Graphic depends on the Graphic's attributes. The Renderer specifies which attribute values correspond to which Symbol.

Symbol Types

The available Symbols and the geometries to which they apply are summarized in the table below:

Symbol

Geometry

Description

Symbol Class

Simple Marker Symbol

Point

Symbolizes points with simple shapes

AGSSimpleMarkerSymbol

Picture Marker Symbol

Point

Symbolizes points with images

AGSPictureMarkerSymbol

Simple Line Symbol

Polyline

Symbolizes lines with pre-defined styles

AGSSimpleLineSymbol

Composite Symbol

Point, Polyline, or Polygon

Symbolizes geometries with an array of symbols

AGSCompositeSymbol

Simple Fill Symbol

Polygon

Fills polygons with a variety of patterns

AGSSimpleFillSymbol

Text Symbol

Point, Polyine, or Polygon

Displays text labels for geometries

AGSTextSymbol

All the symbol classes mentioned above inherit from AGSSymbol.

Creating Symbols

In many applications, the same Symbol will be used many times. Consider, for instance, an application that uses the Find task to allow users to search for counties. In this situation, it makes sense to apply the same symbology to the task's results every time the task is executed. In such cases, you should store a reference to the object in an instance variable/property in your class.

The following code creates an AGSSimpleMarkerSymbol drawn as a blue diamond with a white, three pixel-wide white outline.

//Create the AGSSimpleMarker Symbol and set some properties
AGSSimpleMarkerSymbol* myMarkerSymbol = [AGSSimpleMarkerSymbol simpleMarkerSymbol];
myMarkerSymbol.color = [UIColor blueColor];
myMarkerSymbol.style = AGSSimpleMarkerSymbolStyleDiamond;
myMarkerSymbol.outline.color = [UIColor whiteColor];
myMarkerSymbol.outline.width = 3;

The code below creates an AGSSimpleFillSymbol with a semi-transparent red fill and a red outline that is two pixels wide. Note that the outline for a simple fill symbol is itself an AGSSimpleLineSymbol.

//Create the AGSSimpleFillSymbol and set it’s color
AGSSimpleFillSymbol* myFillSymbol = [AGSSimpleFillSymbol simpleFillSymbol];
myFillSymbol.color = [UIColor colorWithRed:0.7 green:0.1 blue:0.1 alpha:0.5];

//Create the AGSSimpleLineSymbol used for the outline
AGSSimpleLineSymbol* myOutlineSymbol = [AGSSimpleLineSymbol simpleLineSymbol];
myOutlineSymbol.color = [UIColor redColor];
myOutlineSymbol.width = 2;

//set the outline property to myOutlineSymbol
myFillSymbol.outline = myOutlineSymbol;

Now that the symbol is declared, you can attach it to a graphic or use it in a renderer.

Renderers

A renderer defines a set of symbols that will be used for graphics in a Graphics Layer. You can use renderers to symbolize features with different colors or sizes based on a the graphic's attribute values. To use a renderer, you create it, define the symbology you want, then set the renderer property of a Graphics Layer.

myGraphicsLayer.renderer = myRenderer;

Creating a Simple Renderer

A simple renderer uses the same symbol for every graphic. All you have to do is create the renderer with the desired symbol, then Graphics Layer’s renderer property.

AGSSimpleRenderer* mySimpleRenderer = [AGSSimpleRenderer
simpleRendererWithSymbol:myMarkerSymbol];
myGraphicsLayer.renderer = mySimpleRenderer;

Note that the symbol property on AGSSimpleRenderer is read-only. To use a Symbol with a simple renderer you must create a Renderer with the desired symbol. Also, the Symbol type needs to match the feature type (marker symbols for point features, line symbols for polyline features, fill symbols for polygon features).

Creating a Class Breaks Renderer

A class breaks renderer symbolizes each Graphic based on the value of some numeric attribute. Graphics with similar values for the attribute get the same Symbol. The "breaks" define the values at which the symbology changes.

The mapping between symbols and values is defined in an array of AGSClassBreak objects. The AGSClassBreaksRenderer stores this in its classBreaks property as an array of AGSClassBreak objects. The AGSClassBreak object contains the Symbol used to draw the graphic, a minimum value, and a maximum value. Any value greater than or equal to the minimum value and less than the maximum value will get drawn using the class break symbol.

The following code creates an AGSClassBreaksRenderer in order to symbolize cities according to size. There are three class breaks, the first is from DBL_MIN to 50,000; the second is from 50,000 to 250,000; the last is from 250,000 to DBL_MAX:

//create the renderer with a default simple marker symbol  
//and an attribute field.  
AGSClassBreaksRenderer *cityRenderer = [[[AGSClassBreaksRenderer alloc] init] autorelease];  
cityRenderer.field = @"POP1990";  
cityRenderer.minValue = DBL_MIN;      

//create three AGSClassBreak objects, one each for  
//low, medium and high populations and the appropriate  
//symbol (for clarity, the symbol creation has been omitted)  
AGSClassBreak* lowClassBreak = [AGSClassBreak classBreakInfoWithLabel:@"Low" description:@"" maxValue:50000 symbol:lowMarkerSymbol];    
AGSClassBreak* mediumClassBreak =[AGSClassBreak classBreakInfoWithLabel:@"Medium" description:@"" maxValue:250000 symbol:mediumMarkerSymbol];    
AGSClassBreak* highClassBreak = [AGSClassBreak classBreakInfoWithLabel:@"High" description:@"" maxValue:DBL_MAX symbol:highMarkerSymbol];    

//add the AGSClassBreak objects to the renderer   
NSMutableArray* classBreaks = [NSMutableArray array];
[classBreaks addObject:lowClassBreak];   
[classBreaks addObject:mediumClassBreak];
[classBreaks addObject:highClassBreak];        
cityRenderer.classBreaks = classBreaks;


//add the renderer to the graphics layer  
citiesGraphicsLayer.renderer = cityRenderer;

Creating a Unique Value Renderer

A unique value renderer symbolizes groups of Graphics that have matching attributes. This is most common with nominal, or string data. For example, you could use a unique value renderer to symbolize zoning designations: yellow for "Residential", purple for "Industrial", red for "Commercial", and so on. You can also use unique value renderers on numeric fields that are coded values, or on ordinal attributes such as "First", "Second", "Third", and so on.

The following code creates an AGSUniqueValueRenderer for symbolizing cities with three values: “VILLAGE”, “CITY”, and “TOWN”, each with a unique Symbol to represent the “TYPE” attribute field (the creation of the Symbols has been omitted for clarity):

//create the renderer  
//specify the attribute field whose values will decide the symbol 
//we need to provide a default symbol for unmatched values
AGSUniqueValueRenderer *cityRenderer = [[[AGSUniqueValueRenderer alloc] init] autorelease];  
cityRenderer.defaultSymbol = defaultMakerSymbol;  
cityRenderer.field1 = @"TYPE";      

//create three AGSUniqueValue objects, one each for  
//CITY, TOWN, and VILLAGE 
AGSUniqueValue* village = [[AGSUniqueValue alloc] initWithValue:@"VILLAGE" label:@"village" description:nil symbol:villageSymbol];  
AGSUniqueValue* city = [[AGSUniqueValue alloc] initWithValue:@"CITY" label:@"city" description:nil symbol:citySymbol];  
AGSUniqueValue* town = [[AGSUniqueValue alloc] initWithValue:@"TOWN" label:@"town" description:nil symbol:townSymbol];    

//add the AGSUniqueValue objects to the renderer
[cityRenderer.uniqueValues addObject:village];  
[cityRenderer.uniqueValues addObject:city];  
[cityRenderer.uniqueValues addObject:town];    

//add the renderer to the graphics layer  
citiesGraphicsLayer.renderer = cityRenderer;

Note that the object in the setObject method above is the Symbol and the key is the attribute that Symbol will represent. The attributes are members of the attribute field specified in the AGSUniqueValueRenderer uniqueValueRendererWithDefaultSymbol method.

Remember, for all Renderer variations, the Symbol type needs to match the feature type: marker symbols for point features, line symbols for polyline features, and fill symbols for polygon features.

Creating a Temporal Renderer

A temporal renderer can only be used with a feature layer that is time aware. It symbolizes features based on the time information contained in the features. Time information can either be an instant of time, or a period of time. Information representing an instant of time is stored in a single attribute of the feature. Information representing a period of time is stored in two attributes representing the start time and the end time. The temporal renderer is useful in visualizing changes to features over time.

A temporal renderer consists of two elements - An observation renderer, and an interpolator.

The observation renderer specifies the symbols to be used when features don't contain any time information, or when the map does not have a time extent. The observation renderer can be a simple, class breaks, or unique value renderer.

The interpolator adjusts the size and color of symbols specified by the observation renderer for features that have time information. Two types of interpolators are supported : ramp interpolator and time class breaks ager.

Ramp Interpolator

A ramp interpolator finds a suitable size and color for a feature from a range of sizes and colors. The range of sizes and colors is specified using starting and ending values. The interpolator determines the exact size and color for a feature by comparing the feature's time information with the map's time extent. For example, if a feature's time information falls in the center of the map's time extent, a size and color from the middle of the specified range is used for the symbol. When a feature's time information contains both a start time and an end time, the start time is compared with the map's time extent to determine size and color to use.

The following example shows how a ramp interpolator symbolizes features with a range of colors and sizes.

//A time-aware feature layer
AGSFeatureLayer* featLayer = ...;

//Observation renderer
AGSSimpleMarkerSymbol* pointSymbol = [[[AGSSimpleMarkerSymbol alloc] init] autorelease];
pointSymbol.style = AGSSimpleMarkerSymbolStyleSquare;
pointSymbol.size = 6; 
pointSymbol.color = [UIColor blackColor];
AGSSimpleRenderer* obsRenderer = [AGSSimpleRenderer simpleRendererWithSymbol:pointSymbol];

//Color range
UIColor* startCol = [UIColor redColor];
UIColor* endCol = [UIColor yellowColor];

//Size range
int startSize = 10;
int endSize = 2;

//A ramp interpolator using the color and size range
AGSRampInterpolator* ramp = [[AGSRampInterpolator alloc] initWithStartColor:startCol endColor:endCol startSize:startSize endSize:endSize];

//A temporal renderer
AGSTemporalRenderer* temporalRenderer = [[AGSTemporalRenderer alloc] initWithObservationRenderer:obsRenderer observationAger:ager featureLayer:featLayer];
featLayer.renderer = temporalRenderer;

Time Class Breaks Ager

A time class breaks ager uses a collection of time class breaks to find a suitable size and color for a feature. Each class break is associated with a maximum relative age, a symbol size, and color. The age specifies how old a feature could be to be applicable for the class break. Thus, you can specify different symbol sizes and colors for features of different ages. The interpolator determines the actual size and color for a feature by computing the feature's age and finding a class break appropriate for that age. Age is computed by comparing the feature's time information with the ending point of the map's time extent. When a feature's time information contains both a start time and an end time, the start time is used is used for computing the age.

The following example shows how a time class breaks ager symbolizes features along a timeline using time class breaks.

//A time-aware feature layer
AGSFeatureLayer* featLayer = ...;

//An array to hold the class breaks
NSMutableArray* classBreaks = [[[NSMutableArray alloc] init] autorelease];

//Class break for features upto 2 days old
AGSTimeClassBreak* tcb = [[[AGSTimeClassBreak alloc] init] autorelease];
tcb.maxRelativeAge = 2;
tcb.size = 8;
tcb.color = [UIColor whiteColor];
[classBreaks  addObject:tcb];

//Class break for features upto 5 days old
tcb = [[[AGSTimeClassBreak alloc] init] autorelease];
tcb.maxRelativeAge = 5;
tcb.size = 5;
tcb.color = [UIColor blueColor];
[classBreaks  addObject:tcb];

//Class break for features upto 12 days old
tcb = [[[AGSTimeClassBreak alloc] init] autorelease];
tcb.maxRelativeAge = 12;
tcb.size = 3;
tcb.color = [UIColor redColor];
[classBreaks  addObject:tcb];

//A class breaks ager based on the class breaks defined above
AGSTimeClassBreaksAger *classbreaksAger = [[AGSTimeClassBreaksAger alloc] initWithTimeClassBreaks:classBreaks units:AGSTimeIntervalUnitsDays];

//Observation renderer
AGSSimpleMarkerSymbol* pointSymbol = [[[AGSSimpleMarkerSymbol alloc] init] autorelease];
pointSymbol.style = AGSSimpleMarkerSymbolStyleCircle;
pointSymbol.size = 2; 
pointSymbol.color = [UIColor blackColor];
AGSSimpleRenderer* obsRenderer = [AGSSimpleRenderer simpleRendererWithSymbol:pointSymbol];

//Temporal renderer
AGSTemporalRenderer* temporalRenderer = [[AGSTemporalRenderer alloc] initWithObservationRenderer:obsRenderer observationAger:classbreaksAger featureLayer:featLayer];
featLayer.renderer = temporalRenderer;

5/9/2012