Table of Contents

Download Sample Application

The Table of Contents view controller is used to display a list of the layers that appear in the map. You can toggle the layer visibility and can explore the sub-layers and symbology using the hierarchical tree view. If you wish to add the Table of Contents view controller to your application we have provided you with the source code so that you can have full control over it’s look, feel and functionality. You can find the source code for the EAFTOCViewController Table of Contents class by downloading the Esri Application Framework project from GitHub at this location: https://github.com/Esri/preview-app-osx.

//header file
@property (strong) IBOutlet AGSMapView *mapView;
@property (strong) IBOutlet NSView *tocView;
@property (strong) AGSMapContentsTree* contentsTree;
@property (strong) EAFTOCViewController *tocViewController;

//implementation file
- (void)mapViewDidLoad:(AGSMapView *)mapView {

    //create the Map Content Tree using the contents of the MapView 
    self.contentsTree = [[AGSMapContentsTree alloc] initWithMapView:self.mapView];
    
    //create the TOC view controller using the Map Contents Tree
    self.tocViewController = [[EAFTOCViewController alloc] initWithContentsTree:self.contentsTree];
    
    //set the TOC view controllers frame and sizing parameters
    [[self.tocViewController view] setFrame:CGRectInset([self.tocView bounds],10,10)];
    [[self.tocViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
    
    //add the TOC view controller to the TOC NSView
    [self.tocView addSubview:[self.tocViewController view]];
}

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 kTOCBaseMapURL = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"
let kDynamicMapServiceURL = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer"
let kTiledMapServiceURL = "http://services.arcgisonline.com/ArcGIS/rest/services/Specialty/Soil_Survey_Map/MapServer"
let kFeatureLayerURL = "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0"

class TableOfContentsSwiftSample: NSViewController, AGSMapViewLayerDelegate, AGSLayerDelegate, NSSplitViewDelegate {

    @IBOutlet weak var mapView:AGSMapView!
    @IBOutlet weak var tocView:NSView!
    var contentsTree:AGSMapContentsTree!
    var tocViewController:EAFTOCViewController!
    
    //MARK: - awakeFromNib
    
    // -------------------------------------------------------------------------------
    //  awakeFromNib
    // -------------------------------------------------------------------------------
    override func awakeFromNib() {
    
        //enable wrap around
        self.mapView.enableWrapAround()
        
        //set layer delegate to know when mapView loads
        self.mapView.layerDelegate = self
        
        //add base layer to map and set delegate to know when layer loads or fails to load
        let baseMapLayer = AGSTiledMapServiceLayer(URL: NSURL(string: kTOCBaseMapURL))
        baseMapLayer.delegate = self
        self.mapView.addMapLayer(baseMapLayer, withName:"Base Map")
        
        //add dynamic layer to map and set delegate to know when layer loads or fails to load
        let dynamicLayer = AGSDynamicMapServiceLayer(URL: NSURL(string: kDynamicMapServiceURL))
        dynamicLayer.delegate = self
        self.mapView.addMapLayer(dynamicLayer, withName:"Census")
        
        //add tiled layer to map and set delegate to know when layer loads or fails to load
        let tiledLayer = AGSTiledMapServiceLayer(URL: NSURL(string: kTiledMapServiceURL))
        tiledLayer.delegate = self
        self.mapView.addMapLayer(tiledLayer, withName:"Soil Survey")
        
        //add feature layer to map and set delegate to know when layer loads or fails to load
        let featureLayer = AGSFeatureLayer(URL: NSURL(string: kFeatureLayerURL), mode: .OnDemand)
        featureLayer.delegate = self
        self.mapView.addMapLayer(featureLayer, withName:"Incidents")
        
        //zoom to predefined extend with known spatial reference of the map
        let sr = AGSSpatialReference.webMercatorSpatialReference()
        let env = AGSEnvelope(xmin: -13639984, ymin:4537387, xmax:-13606734, ymax:4558866, spatialReference:sr)
        self.mapView.zoomToEnvelope(env, animated:true)
    }
    
    //MARK: - MapView Layer Delegate
    
    // -------------------------------------------------------------------------------
    //  mapViewDidLoad:mapView
    //
    //  this will be called when mapView loads successfully, let's set table of contents
    // -------------------------------------------------------------------------------
    func mapViewDidLoad(mapView: AGSMapView!) {
    
        self.contentsTree = AGSMapContentsTree(mapView: self.mapView)
        self.tocViewController = EAFTOCViewController(contentsTree: self.contentsTree)
        self.tocViewController.view.frame = CGRectInset(self.tocView.bounds, 10, 10)
        self.tocViewController.view.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable
        self.tocView.addSubview(self.tocViewController.view)
    }
    
    //MARK: - Layer Delegate
    
    // -------------------------------------------------------------------------------
    //  layerDidLoad:layer
    //
    //  this will be called when layer loads successfully, let's print name of loaded layer
    // -------------------------------------------------------------------------------
    func layerDidLoad(layer: AGSLayer!) {
        println("Layer \(layer.name) loaded..")
    }
    
    // -------------------------------------------------------------------------------
    //  layer:didFailToLoadWithError:error
    //
    //  this will be called when layer fails load, let's show error message
    // -------------------------------------------------------------------------------
    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)
        }
    }
    
    //MARK: - NSSplitView delegate
    
    // -------------------------------------------------------------------------------
    //  splitView:constrainMaxCoordinate
    //
    //  this will restrict resize of splitView at specified max value
    // -------------------------------------------------------------------------------
    func splitView(splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
        return 260
    }
    
    // -------------------------------------------------------------------------------
    //  splitView:constrainMinCoordinate
    //
    //  this will restrict resize of splitView at specified min value
    // -------------------------------------------------------------------------------
    func splitView(splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat {
        return 200
    }
    
}
//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 "TableOfContentsSample.h"
#import "EAFTOCViewController.h"

//layer urls
#define kBaseMapURL @"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"
#define kDynamicMapServiceURL @"http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer"
#define kTiledMapServiceURL @"http://services.arcgisonline.com/ArcGIS/rest/services/Specialty/Soil_Survey_Map/MapServer"
#define kFeatureLayerURL @"http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0"

@interface TableOfContentsSample ()
@property (strong) EAFTOCViewController *tocViewController;
@end

@implementation TableOfContentsSample

#pragma mark - awakeFromNib

// -------------------------------------------------------------------------------
//  awakeFromNib
// -------------------------------------------------------------------------------
- (void)awakeFromNib {
    
    //enable wrap around
    [self.mapView enableWrapAround];
    
    //set layer delegate to know when mapView loads
    self.mapView.layerDelegate = self;
    
    //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 Map"];
    
    //add dynamic layer to map and set delegate to know when layer loads or fails to load
	AGSDynamicMapServiceLayer *dynamicLayer = [AGSDynamicMapServiceLayer dynamicMapServiceLayerWithURL:[NSURL URLWithString:kDynamicMapServiceURL]];
    dynamicLayer.delegate = self;
	[self.mapView addMapLayer:dynamicLayer withName:@"Census"];
    
    //add tiled layer to map and set delegate to know when layer loads or fails to load
	AGSTiledMapServiceLayer *tiledLayer = [AGSTiledMapServiceLayer tiledMapServiceLayerWithURL:[NSURL URLWithString:kTiledMapServiceURL]];
    tiledLayer.delegate = self;
	[self.mapView addMapLayer:tiledLayer withName:@"Soil Survey"];
    
    //add feature layer to map and set delegate to know when layer loads or fails to load
    AGSFeatureLayer *featureLayer = [AGSFeatureLayer featureServiceLayerWithURL:[NSURL URLWithString:kFeatureLayerURL] mode:AGSFeatureLayerModeOnDemand];
    featureLayer.delegate = self;
    [self.mapView addMapLayer:featureLayer withName:@"Incidents"];
    
    //zoom to predefined extend with known spatial reference of the map
	AGSSpatialReference *sr = [AGSSpatialReference webMercatorSpatialReference];
	AGSEnvelope *env = [AGSEnvelope envelopeWithXmin:-13639984 ymin:4537387 xmax:-13606734 ymax:4558866 spatialReference:sr];
	[self.mapView zoomToEnvelope:env animated:YES];
}

#pragma mark - MapView Layer Delegate

// -------------------------------------------------------------------------------
//  mapViewDidLoad:mapView
//
//  this will be called when mapView loads successfully, let's set table of contents 
// -------------------------------------------------------------------------------
- (void)mapViewDidLoad:(AGSMapView *)mapView {
        
    self.contentsTree = [[AGSMapContentsTree alloc] initWithMapView:self.mapView];
    self.tocViewController = [[EAFTOCViewController alloc] initWithContentsTree:self.contentsTree];
    [[self.tocViewController view] setFrame:CGRectInset([self.tocView bounds],10,10)];
    [[self.tocViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
    [self.tocView addSubview:[self.tocViewController view]];
}

#pragma mark - Layer Delegate

// -------------------------------------------------------------------------------
//  layerDidLoad:layer
//
//  this will be called when layer loads successfully, let's print name of loaded layer
// -------------------------------------------------------------------------------
- (void)layerDidLoad:(AGSLayer *)layer {
    NSLog(@"Layer %@ loaded..",layer.name);
}

// -------------------------------------------------------------------------------
//  layer:didFailToLoadWithError:error
//
//  this will be called when layer fails load, let's show error message
// -------------------------------------------------------------------------------
- (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];
}

#pragma mark - NSSplitView delegate

// -------------------------------------------------------------------------------
//  splitView:constrainMaxCoordinate
//
//  this will restrict resize of splitView at specified max value
// -------------------------------------------------------------------------------
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex {
    return 260;
}

// -------------------------------------------------------------------------------
//  splitView:constrainMinCoordinate
//
//  this will restrict resize of splitView at specified min value
// -------------------------------------------------------------------------------
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex {
    return 200;
}

@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 TableOfContentsSample : NSViewController <AGSMapViewLayerDelegate,AGSLayerDelegate>

@property (strong) IBOutlet AGSMapView *mapView;
@property (strong) IBOutlet NSView *tocView;
@property (strong) AGSMapContentsTree* contentsTree;

@end
Feedback on this topic?