ESRI ArcGIS iPhone API – Class Breaks Renderer Sample

by James Richards June 04, 2010

Introduction

Here is a quick sample demonstrating the use of a Class Breaks Renderer in the ESRI ArcGIS iPhone API. The sample queries an ArcGIS Server Map Service for cities in California and renders them as graphics based on the population. Here’s a screenshot of the app running in the simulator.

ClassBreaks

Click here to download the source code from this article.

[more]

Discussion

If you’ve been programming with any of the ESRI Client APIs, then you’ll recognize the Class Breaks Renderer concept. For those who aren’t familiar, here’s a snippet from the Working with Symbols and Renderers section of the ArcGIS iPhone SDK Concepts documentation:

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.

Code Listings

ClassBreaksViewController.h

#import <UIKit/UIKit.h>
#import "AGSiPhone.h"

#define kTiledMapServiceURL @"http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer"
#define kDynamicMapServiceURL @"http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/0"

@interface ClassBreaksViewController : UIViewController<AGSMapViewDelegate, AGSQueryTaskDelegate> {
    AGSMapView *mapView;
    AGSGraphicsLayer *cityGraphicsLayer;
    AGSQueryTask *cityQueryTask;
    
}

@property (nonatomic, retain) IBOutlet AGSMapView *mapView;
@property (nonatomic, retain) AGSGraphicsLayer *cityGraphicsLayer;
@property (nonatomic, retain) AGSQueryTask *cityQueryTask;

@end

ClassBreaksViewController.m

#import "ClassBreaksViewController.h"

@implementation ClassBreaksViewController

@synthesize mapView;
@synthesize cityGraphicsLayer;
@synthesize cityQueryTask;

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Set map view delegate
    self.mapView.mapViewDelegate = self;
    
    // Create tile base map layer
    AGSTiledMapServiceLayer *tiledLayer = [[AGSTiledMapServiceLayer alloc] initWithURL:[NSURL URLWithString:kTiledMapServiceURL]];
    [self.mapView addMapLayer:tiledLayer withName:@"BaseLayer"];
    [tiledLayer release];
    
    // Create grpahics layer
    self.cityGraphicsLayer = [AGSGraphicsLayer graphicsLayer];
    
    // Create symbols for the three class breaks
    AGSSimpleMarkerSymbol *lowSymbol = [AGSSimpleMarkerSymbol simpleMarkerSymbol];
    lowSymbol.color = [UIColor colorWithRed:151.0/255.0 green:216.0/255.0 blue:255.0/255.0 alpha:0.8];
    lowSymbol.outline.width = 0;
    lowSymbol.size = 15;
    
    AGSSimpleMarkerSymbol *mediumSymbol = [AGSSimpleMarkerSymbol simpleMarkerSymbol];
    mediumSymbol.color = [UIColor colorWithRed:255.0/255.0 green:165.0/255.0 blue:83.0/255.0 alpha:0.8];
    mediumSymbol.outline.width = 0;
    mediumSymbol.size = 20;
    
    AGSSimpleMarkerSymbol *highSymbol = [AGSSimpleMarkerSymbol simpleMarkerSymbol];
    highSymbol.color = [UIColor colorWithRed:222.0/255.0 green:0.0 blue:0.0 alpha:0.8];
    highSymbol.outline.width = 0;
    highSymbol.size = 25;
    
    // Create a class breaks renderer with a default simple marker symbol and an attribute field
    AGSClassBreaksRenderer *cityRenderer = [AGSClassBreaksRenderer
                                            classBreaksRendererWithDefaultSymbol:lowSymbol 
                                                               forAttributeField:@"POP1990"];
    
    // Create three AGSClassBreak objects, one each for low, medium and high populations
    AGSClassBreak* lowClassBreak = [AGSClassBreak
                                    classBreakInfoWithSymbol:lowSymbol forMinValue:DBL_MIN
                                    maxValue:50000.0];
    
    AGSClassBreak* mediumClassBreak = [AGSClassBreak
                                       classBreakInfoWithSymbol:mediumSymbol forMinValue:50000.0
                                       maxValue:250000];
    
    AGSClassBreak* highClassBreak = [AGSClassBreak
                                     classBreakInfoWithSymbol:highSymbol forMinValue:250000.0
                                     maxValue:DBL_MAX];
    
    // Create an NSMutableArray, fill it with the class break objects,
    // and set it to the renderer’s classBreaks property
    cityRenderer.classBreaks = [NSMutableArray arrayWithObjects:
                                lowClassBreak, mediumClassBreak, highClassBreak, nil];
    
    // Add the renderer to the graphics layer
    self.cityGraphicsLayer.renderer = cityRenderer;
    
    // Add the graphics layer to the map view
    [self.mapView addMapLayer:self.cityGraphicsLayer withName:@"CityGraphicsLayer"];
}

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return YES;
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    
    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.cityGraphicsLayer = nil;
    self.mapView = nil;
    [super viewDidUnload];
}

- (void)dealloc {
    [cityGraphicsLayer release];
    [mapView release];
    [super dealloc];
}

#pragma mark AGSMapViewDelegate

// Called when the map view is loaded (after the view is loaded) 
- (void)mapViewDidLoad:(AGSMapView *)mapView {
        
    // Set up query task for cities and perform query returning all attributes
    self.cityQueryTask = [AGSQueryTask queryTaskWithURL:[NSURL URLWithString:kDynamicMapServiceURL]];
    self.cityQueryTask.delegate = self;
    
    AGSQuery *cityQuery = [AGSQuery query];
    cityQuery.where = @"STATE_NAME = 'California'";
    cityQuery.outFields = [NSArray arrayWithObject:@"*"];
        
    [self.cityQueryTask executeWithQuery:cityQuery];
    
    // Create extent to be used as default
    AGSEnvelope *envelope = [AGSEnvelope envelopeWithXmin:-118.6
                                                     ymin:33.6
                                                     xmax:-118.1
                                                     ymax:34.2
                                         spatialReference:self.mapView.spatialReference];
    
    // Call method to set extent, pass in envelope
    [self.mapView performSelector:@selector(zoomToEnvelope:animated:) 
                       withObject:envelope
                       afterDelay:0.5];    
}    

#pragma mark AGSQueryTaskDelegate

// When query is executed ....
- (void)queryTask:(AGSQueryTask *)queryTask didExecuteWithFeatureSetResult:(AGSFeatureSet *)featureSet {
    // Iterate the returned features (graphics) and add them to the graphics layer
    for (AGSGraphic *graphic in featureSet.features) {
        [self.cityGraphicsLayer addGraphic:graphic];
    }
    [self.cityGraphicsLayer dataChanged];
    
    // Clean up query task memory
    self.cityQueryTask = nil;
}

// If there's an error with the query task give info to user
- (void)queryTask:(AGSQueryTask *)queryTask didFailWithError:(NSError *)error {
    // Clean up query task memory
    self.cityQueryTask = nil;

    // Display error message
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                    message:[error localizedDescription]
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];
}

@end

Summary

In this post you learned how to use a Class Breaks Renderer in the ESRI ArcGIS iPhone API to display cities of varying population with different symbols.

Click here to download the source code from this article.

I hope you are finding these posts on the ESRI iPhone API to be helpful. If you have any suggestions, ideas or feedback, please leave them in the comments below.

Additional Resources

Tags: , , ,

ArcGIS Server | ESRI | iPhone | Mobile

Comments are closed

Powered by BlogEngine.NET 1.6.0.0
Theme by Mads Kristensen | Modified by Mooglegiant
Creative Commons License This work is licensed under a Creative Commons Attribution 3.0 United States License.

Welcome

James Richards

Hi, I'm James Richards the CTO and co-founder of Artisan Global LLC. We make location-aware mobile apps with maps. I'm the author of QuakeFeed and I helped launch Zaarly at LASW Feb 2011. I also enjoy surfing, snowboarding, golfing, yoga, and music. I love my family: Linda, Sequoya and our cats Remy and Twiggy. Thanks for stopping by, I hope you find something helpful here.

Subscribe by RSS   Follow me on Twitter   Connect on Facebook   View my profile on LinkedIn


Amazon Associates

Some of my posts may contain Amazon Associates links. I only include these links when it makes sense within the context of the article. If you are in the market for one of these items, please consider clicking on an affiliate link to make your purchase. You still get the same great deal from Amazon and it will help me pay for hosting and bandwidth. Thanks!