Feature Layer

Download Sample Application

Feature layers display individual features from an ArcGIS Server Feature Service or an ArcGIS Server Map Service. This sample demonstrates initializing a feature layer and setting it’s operation mode to on-demand. On-demand means that only features within the map's extent are returned from the service layer. Click on a feature to see the callout displayed. Note: With Feature Layers you can perform queries and selections on features, and work with feature attachments. When using an editable ArcGIS Server Feature Service you can also edit features and their attachments. The feature layer honors definition queries, scale dependencies, and other properties configured on the service layer.

//add feature layer to map and set delegate to know when layer loads or fails to load
//set outFields to return all fields
//set calloutDelegate so when you tap on the feature, it'll show callout

AGSFeatureLayer *featureLayerAmbulances = 
  [AGSFeatureLayer featureServiceLayerWithURL:[NSURL URLWithString:@"http://sampleserver6.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/0"] 
  mode:AGSFeatureLayerModeOnDemand];
featureLayerAmbulances.delegate = self;
featureLayerAmbulances.outFields = @[@"*"];
featureLayerAmbulances.calloutDelegate = self;
[self.mapView addMapLayer:featureLayerAmbulances withName:@"Ambulances"];

Sample Code

//SWIFT SAMPLE CODE
/*
Copyright 2014 Esri

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import Cocoa
import ArcGIS

//layer urls
let kFLBaseMapURL = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
let kFeatureLayerURL_Ambulances = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/0"
let kFeatureLayerURL_Police = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/1"
let kFeatureLayerURL_Fire = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/2"

class FeatureLayerSwiftSample: NSViewController, AGSLayerDelegate, AGSLayerCalloutDelegate {

    @IBOutlet weak var mapView:AGSMapView!
    
    //MARK: - awakeFromNib
    
    // -------------------------------------------------------------------------------
    //  awakeFromNib
    // -------------------------------------------------------------------------------
    override func awakeFromNib() {
    
        //add base layer to map and set delegate to know when layer loads or fails to load
        let baseMapLayer = AGSTiledMapServiceLayer(URL: NSURL(string: kFLBaseMapURL))
        baseMapLayer.delegate = self
        self.mapView.addMapLayer(baseMapLayer, withName:"Base Layer")
        
        //add feature layer to map and set delegate to know when layer loads or fails to load
        //set outFields to return all fields
        //set infoTemplateDelegate so when you tap on the feature, it'll show callout
        let featureLayerAmbulances = AGSFeatureLayer(URL: NSURL(string: kFeatureLayerURL_Ambulances), mode: .OnDemand)
        featureLayerAmbulances.delegate = self
        featureLayerAmbulances.outFields = ["*"]
        featureLayerAmbulances.calloutDelegate = self
        self.mapView.addMapLayer(featureLayerAmbulances, withName:"Ambulances")
        
        //add feature layer to map and set delegate to know when layer loads or fails to load
        //set outFields to return all fields
        //set infoTemplateDelegate so when you tap on the feature, it'll show callout
        let featureLayerPolice = AGSFeatureLayer(URL: NSURL(string: kFeatureLayerURL_Police), mode: .OnDemand)
        featureLayerPolice.delegate = self
        featureLayerPolice.outFields = ["*"]
        featureLayerPolice.calloutDelegate = self
        self.mapView.addMapLayer(featureLayerPolice, withName:"Police")
        
        //add feature layer to map and set delegate to know when layer loads or fails to load
        //set outFields to return all fields
        //set infoTemplateDelegate so when you tap on the feature, it'll show callout
        let featureLayerFire = AGSFeatureLayer(URL: NSURL(string: kFeatureLayerURL_Fire), mode: .OnDemand)
        featureLayerFire.delegate = self
        featureLayerFire.outFields = ["*"];
        featureLayerFire.calloutDelegate = self
        self.mapView.addMapLayer(featureLayerFire, withName:"Fire")
        
        //zoom to predefined extend with known spatial reference of the map
        let envelope = AGSEnvelope(xmin: -13052184.708694, ymin:4033059.017144, xmax:-13041500.789775, ymax:4040439.805481, spatialReference:AGSSpatialReference.webMercatorSpatialReference())
        self.mapView.zoomToEnvelope(envelope, animated:true)
    }
    
    //MARK: - Layer Delegate
    
    // -------------------------------------------------------------------------------
    //  layerDidLoad:layer
    // -------------------------------------------------------------------------------
    func layerDidLoad(layer: AGSLayer!) {
        println("Layer \(layer.name) loaded..")
    }
    
    
    // -------------------------------------------------------------------------------
    //  layer:didFailToLoadWithError:error
    // -------------------------------------------------------------------------------
    func layer(layer: AGSLayer!, didFailToLoadWithError error: NSError!) {
        if let viewWindow = self.view.window {
            let alert = NSAlert()
            alert.messageText = "Layer '\(layer.name)' failed to load"
            alert.informativeText = error.localizedDescription
            alert.beginSheetModalForWindow(viewWindow, modalDelegate: self, didEndSelector: nil, contextInfo: nil)
        }
    }
    
    func callout(callout: AGSCallout!, willShowForFeature feature: AGSFeature!, layer: AGSLayer!, mapPoint: AGSPoint!) -> Bool {
        if layer.name == "Ambulances" || layer.name == "Police" || layer.name == "Fire" {
            callout.title =  (feature.allAttributes() as NSDictionary).ags_stringByApplyingTemplate("${unitname}")
            callout.detail = self.detailForFeature(feature)
        }
        return true
    }
    
    //
    //// -------------------------------------------------------------------------------
    ////  detailForGraphic:screenPoint:mapPoint
    //// -------------------------------------------------------------------------------
    func detailForFeature(feature:AGSFeature) -> String {
    
        //display value of 'type' field from graphic's attribute as detail string
        //by retrieving the codedValue of the 'type' field
        var detail:String!
        
        let graphic = feature as AGSGraphic
        
        //loop through all fields of feature layer
        for field in (graphic.layer as AGSFeatureLayer).fields as [AGSField] {
        
            //if field name is type then go it to find
            if field.name == "type" {
            
                //type field is coded value domain so get domain from field
                let codedValueDomain = field.domain as AGSCodedValueDomain
                
                //loop through all coded values
                for codedValue in codedValueDomain.codedValues as [AGSCodedValue] {
                
                    //find coded value from graphic's type attribute
                    //set detail string as coded value's name
                    if codedValue.code.integerValue == graphic.attributeAsIntegerForKey("type", exists: nil) {
                        detail = codedValue.name
                    }
                }
            }
        }
        
        return detail;
    }
    
}
//OBJECTIVE C SAMPLE CODE
/*
 Copyright 2013 Esri
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#import "FeatureLayerSample.h"

//layer urls
#define kBaseMapURL @"http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
#define kFeatureLayerURL_Ambulances @"http://sampleserver6.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/0"
#define kFeatureLayerURL_Police @"http://sampleserver6.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/1"
#define kFeatureLayerURL_Fire @"http://sampleserver6.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/2"

@interface FeatureLayerSample ()

@end

@implementation FeatureLayerSample

#pragma mark - awakeFromNib

// -------------------------------------------------------------------------------
//  awakeFromNib
// -------------------------------------------------------------------------------
- (void)awakeFromNib {
            
    //add base layer to map and set delegate to know when layer loads or fails to load
	AGSTiledMapServiceLayer *baseMapLayer = [[AGSTiledMapServiceLayer alloc] initWithURL:[NSURL URLWithString:kBaseMapURL]];
    baseMapLayer.delegate = self;
    [self.mapView addMapLayer:baseMapLayer withName:@"Base Layer"];
    
    //add feature layer to map and set delegate to know when layer loads or fails to load
    //set outFields to return all fields
    //set infoTemplateDelegate so when you tap on the feature, it'll show callout
    AGSFeatureLayer *featureLayerAmbulances = [AGSFeatureLayer featureServiceLayerWithURL:[NSURL URLWithString:kFeatureLayerURL_Ambulances] mode:AGSFeatureLayerModeOnDemand];
    featureLayerAmbulances.delegate = self;
    featureLayerAmbulances.outFields = @[@"*"];
    featureLayerAmbulances.calloutDelegate = self;
    [self.mapView addMapLayer:featureLayerAmbulances withName:@"Ambulances"];
    
    //add feature layer to map and set delegate to know when layer loads or fails to load
    //set outFields to return all fields
    //set infoTemplateDelegate so when you tap on the feature, it'll show callout
    AGSFeatureLayer *featureLayerPolice = [AGSFeatureLayer featureServiceLayerWithURL:[NSURL URLWithString:kFeatureLayerURL_Police] mode:AGSFeatureLayerModeOnDemand];
    featureLayerPolice.delegate = self;
    featureLayerPolice.outFields = @[@"*"];
    featureLayerPolice.calloutDelegate = self;
    [self.mapView addMapLayer:featureLayerPolice withName:@"Police"];
    
    //add feature layer to map and set delegate to know when layer loads or fails to load
    //set outFields to return all fields
    //set infoTemplateDelegate so when you tap on the feature, it'll show callout
    AGSFeatureLayer *featureLayerFire = [AGSFeatureLayer featureServiceLayerWithURL:[NSURL URLWithString:kFeatureLayerURL_Fire] mode:AGSFeatureLayerModeOnDemand];
    featureLayerFire.delegate = self;
    featureLayerFire.outFields = @[@"*"];
    featureLayerFire.calloutDelegate = self;
    [self.mapView addMapLayer:featureLayerFire withName:@"Fire"];
    
    //zoom to predefined extend with known spatial reference of the map
    AGSEnvelope *envelope = [AGSEnvelope envelopeWithXmin: -13052184.708694 ymin:4033059.017144 xmax:-13041500.789775 ymax:4040439.805481 spatialReference:[AGSSpatialReference webMercatorSpatialReference]];
    [self.mapView zoomToEnvelope:envelope animated:YES];
}

#pragma mark - Layer Delegate

// -------------------------------------------------------------------------------
//  layerDidLoad:layer
// -------------------------------------------------------------------------------
- (void)layerDidLoad:(AGSLayer *)layer {
    NSLog(@"Layer %@ loaded..",layer.name);
}


// -------------------------------------------------------------------------------
//  layer:didFailToLoadWithError:error
// -------------------------------------------------------------------------------
- (void)layer:(AGSLayer *)layer didFailToLoadWithError:(NSError *)error {
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setMessageText:[NSString stringWithFormat:@"Layer '%@' failed to load",layer.name]];
    [alert setInformativeText:[NSString stringWithFormat:@"%@",error]];
    [alert beginSheetModalForWindow:self.view.window modalDelegate:self didEndSelector:nil contextInfo:nil];
}


-(BOOL)callout:(AGSCallout *)callout willShowForFeature:(id<AGSFeature>)feature layer:(AGSLayer *)layer mapPoint:(AGSPoint *)mapPoint {
    
    if ([layer.name isEqualToString:@"Ambulances"] ||
        [layer.name isEqualToString:@"Police"] ||
        [layer.name isEqualToString:@"Fire"]) {
        callout.title =  [[feature allAttributes] ags_stringByApplyingTemplate:@"${unitname}"];
        callout.detail = [self detailForFeature:feature];
    }
    
    return YES;
}

//
//// -------------------------------------------------------------------------------
////  detailForGraphic:screenPoint:mapPoint
//// -------------------------------------------------------------------------------
- (NSString*)detailForFeature:(id<AGSFeature>)feature {
    
    //display value of 'type' field from graphic's attribute as detail string
    //by retrieving the codedValue of the 'type' field
    NSString *detail = nil;
    
    AGSGraphic *graphic = (AGSGraphic*)feature;
    
    //loop through all fields of feature layer
    for (AGSField *field in ((AGSFeatureLayer*)graphic.layer).fields) {
        
        //if field name is type then go it to find 
        if ([field.name isEqualToString:@"type"]) {
            
            //type field is coded value domain so get domain from field
            AGSCodedValueDomain *codedValueDomain = (AGSCodedValueDomain*)field.domain;
            
            //loop through all coded values
            for (AGSCodedValue *codedValue in codedValueDomain.codedValues) {
                
                //find coded value from graphic's type attribute
                //set detail string as coded value's name
                BOOL exists;
                if ([codedValue.code intValue] == [graphic attributeAsIntegerForKey:@"type" exists:&exists]){
                    detail = codedValue.name;
                }
            }
        }
    }

    return detail;
}


@end
//OBJECTIVE C SAMPLE CODE
/*
 Copyright 2013 Esri
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#import <Cocoa/Cocoa.h>

@interface FeatureLayerSample : NSViewController <AGSLayerDelegate, AGSLayerCalloutDelegate>

@property (strong) IBOutlet AGSMapView *mapView;

@end
Feedback on this topic?