Skip To Content ArcGIS for Developers Sign In Dashboard

Dynamic Layer Class Breaks Renderer

Download Sample Application

This sample demonstrates that the client can override the class breaks renderers specified by a dynamic map service layer. The dynamic layer needs to be enabled for dynamic rendering by calling setEnableDynamicLayers(true) on the layer before it is added to the map. The new renderers are created client-side but the information is applied at the server level when rendering the map image.

//Create the class breaks definition for the renderer using the 5 quantile method on the pop2000 field
AGSClassBreaksDefinition *classBreaksDef = [AGSClassBreaksDefinition classBreaksDefinitionWithClassificationField:@"pop2000" classificationMethod:AGSClassBreaksDefinitionClassificationMethodQuantile breakCount:5];

//Generate the renderer for that definition
AGSAlgorithmicColorRamp *alogrithmicColorRamp = [AGSAlgorithmicColorRamp algorithmicColorRampWithFromColor [AGSColor whiteColor] toColor:[AGSColor brownColor] algorithm:AGSColorRampAlgorithmCIELab];

//Apply the renderer to the definition
classBreaksDef.colorRamp = alogrithmicColorRamp;

//Specify the parameters for the AGSGenerateRendererTask
AGSGenerateRendererParameters *genRenParams = [AGSGenerateRendererParameters generateRendererParametersWithClassificationDefinition:classBreaksDef whereClause:nil];

//Execute the task with the parameters and process the completion block
_genRenOp = [_genRenTask generateRendererWithParameters:genRenParams completion:^(AGSRenderer *renderer, NSError *error) {.......}

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 kCBRBaseMapURL = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"
let kCBRDynamicMapServiceURL = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer"

class DynamicLayerCBRSwiftSample: NSViewController, AGSLayerDelegate {

    @IBOutlet weak var mapView:AGSMapView!
    
    var dynamicMSLayer:AGSDynamicMapServiceLayer!
    var genRenParams:AGSGenerateRendererParameters!
    var genRenTask:AGSGenerateRendererTask!
    var genRenOp:AGSCancellable!
    
    //MARK: - awakeFromNib
    
    // -------------------------------------------------------------------------------
    //  awakeFromNib
    // -------------------------------------------------------------------------------
    override func awakeFromNib() {
        
        //enable wrap around
        self.mapView.enableWrapAround()
        
        //add base layer to map and set delegate to know when layer loads or fails to load
        let baseMapLayer = AGSTiledMapServiceLayer(URL: NSURL(string: kCBRBaseMapURL))
        baseMapLayer.delegate = self
        self.mapView.addMapLayer(baseMapLayer, withName:"Base Layer")
        
        //add dynamic layer to map and set delegate to know when layer loads or fails to load
        self.dynamicMSLayer = AGSDynamicMapServiceLayer(URL: NSURL(string: kCBRDynamicMapServiceURL))
        self.dynamicMSLayer.delegate = self
        self.mapView.addMapLayer(self.dynamicMSLayer, withName:"USA")
        
        //zoom to predefined extend with known spatial reference of the map
        let envelope = AGSEnvelope(xmin: -19839095.588617, ymin:2145730.010627, xmax:-7454984.983701, ymax:11542629.109590, spatialReference:AGSSpatialReference.webMercatorSpatialReference())
        self.mapView.zoomToEnvelope(envelope, animated:true)
    }
    
    
    func layerDidLoad(layer: AGSLayer!) {
        
        if (!(layer is AGSDynamicMapServiceLayer) || (layer as AGSDynamicMapServiceLayer).URL.absoluteString != kUVRDynamicMapServiceURL) {
            return
        }
        
        let string = "\(kUVRDynamicMapServiceURL)/2"
        let sublayerURL = NSURL(string: string)
        
        //Create the AGSGenerateRendererTask providing the URL to the sublayer to be rendered
        //In this case it is the 2nd layer (States)
        
        self.genRenTask = AGSGenerateRendererTask(URL: sublayerURL)
        
        //Create the class breaks definition for the renderer using the 5 quantile method on the pop2000 field
        let classBreaksDef =
            AGSClassBreaksDefinition(classificationField: "pop2000", classificationMethod: .Quantile, breakCount:5)
        
        //Generate the renderer for that definition
        let alogrithmicColorRamp = AGSAlgorithmicColorRamp(fromColor: NSColor.whiteColor(), toColor: NSColor.brownColor(), algorithm: .CIELab)
        
        //Apply the renderer to the definition
        classBreaksDef.colorRamp = alogrithmicColorRamp
        
        //Specify the parameters for the AGSGenerateRendererTask
        let genRenParams = AGSGenerateRendererParameters(classificationDefinition: classBreaksDef, whereClause: nil)
        
        //Execute the task with the parameters and completion block
        self.genRenOp = self.genRenTask.generateRendererWithParameters(genRenParams, completion: { [weak self] (renderer, error) -> Void in
            if let weakSelf = self {
                if error != nil {
                    weakSelf.showErrorWithTitle("Error generating renderer", message:error.localizedDescription)
                }
                else {
                    
                    //If the renderer was created then override the renderer by setting the Dynamic Map Service layer infos (dynamicLayerInfos) to a array of AGSDynamicLayerInfos (containing the new renderer).
                    
                    //Create an array to contain the layer information for all layers in the dynamic map service
                    var newLayerInfoArray = Array<AGSDynamicLayerInfo>()
                    
                    //Get the map service information from the Dynamic Map Service Layer
                    let mapServiceInfo = weakSelf.dynamicMSLayer.mapServiceInfo
                    
                    
                    //For each layer in the map service information
                    for layerInfo in mapServiceInfo.layerInfos as [AGSLayerInfo] {
                        
                        //Get the layer map source from the Layer's ID
                        let layerMapSource = AGSLayerMapSource(mapLayerID: Int(layerInfo.layerId), geodatabaseVersion: nil)
                        
                        //create the new layer info and add it to the array of dynamic
                        var newLayerInfo:AGSDynamicLayerInfo!
                        
                        //For the 2nd layer (States)
                        if (layerInfo.layerId  == 2) {
                            
                            //create drawing info using the renderer and set opacity to be transparent (0.5)
                            let drawingInfo = AGSDrawingInfo(renderer: renderer, opacity: 0.8)
                            
                            //create the layer info using the drawing info
                            newLayerInfo = AGSDynamicLayerInfo(layerID: layerInfo.layerId, drawingInfo: drawingInfo, layerSource:layerMapSource)
                        }
                        else {
                            //create the layer info and don't override the drawing info
                            newLayerInfo = AGSDynamicLayerInfo(layerID: layerInfo.layerId, drawingInfo: nil, layerSource: layerMapSource)
                        }
                        
                        newLayerInfo.name = layerInfo.name
                        newLayerInfoArray.append(newLayerInfo)
                    }
                    
                    //set the Dynamic Map Service Layer dynamicLayerInfos property to be a new array of AGSDynamicLayerInfo.
                    weakSelf.dynamicMSLayer.dynamicLayerInfos = newLayerInfoArray
                    
                    //refresh the layer
                    weakSelf.dynamicMSLayer.refresh()
                    
                }
            }
        })
        
    }
    
    // -------------------------------------------------------------------------------
    //  layer:didFailToLoadWithError:error
    // -------------------------------------------------------------------------------
    
    func layer(layer: AGSLayer!, didFailToLoadWithError error: NSError!) {
        self.showErrorWithTitle("Layer \(layer.name) failed to load", message: error.localizedDescription)
    }
    
    func showErrorWithTitle(title:String, message:String) {
        if let viewWindow = self.view.window {
            let alert = NSAlert()
            alert.messageText = title
            alert.informativeText = message
            alert.beginSheetModalForWindow(viewWindow, modalDelegate: self, didEndSelector: nil, contextInfo: nil)
        }
    }
    
}
//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 "DynamicLayerCBRSample.h"

//layer urls
#define kBaseMapURL @"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"
#define kDynamicMapServiceURL @"http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer"

@implementation DynamicLayerCBRSample

#pragma mark - awakeFromNib

// -------------------------------------------------------------------------------
//  awakeFromNib
// -------------------------------------------------------------------------------
- (void)awakeFromNib {
    
    //enable wrap around
    [self.mapView enableWrapAround];
            
    //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 dynamic layer to map and set delegate to know when layer loads or fails to load
    self.dynamicMSLayer = [AGSDynamicMapServiceLayer dynamicMapServiceLayerWithURL:[NSURL URLWithString:kDynamicMapServiceURL]];
    self.dynamicMSLayer.delegate = self;
    [self.mapView addMapLayer:self.dynamicMSLayer withName:@"USA"];
    
    //zoom to predefined extend with known spatial reference of the map
    AGSEnvelope *envelope = [AGSEnvelope envelopeWithXmin:-19839095.588617 ymin:2145730.010627 xmax:-7454984.983701 ymax:11542629.109590 spatialReference:[AGSSpatialReference webMercatorSpatialReference]];
    [self.mapView zoomToEnvelope:envelope animated:YES];
}

#pragma mark - Layer Delegate

// -------------------------------------------------------------------------------
//  layerDidLoad:layer
// -------------------------------------------------------------------------------
- (void)layerDidLoad:(AGSLayer *)layer {
    
    if (![layer isKindOfClass:[AGSDynamicMapServiceLayer class]] && ![[((AGSDynamicMapServiceLayer*)layer).URL absoluteString] isEqualToString:kDynamicMapServiceURL]) {
        return;
    }
    
    NSMutableString *string = [NSMutableString string];
    [string appendString:kDynamicMapServiceURL];
    [string appendString:@"/2"];
    NSURL *sublayerURL = [NSURL URLWithString:string];

    //Create the AGSGenerateRendererTask providing the URL to the sublayer to be rendered
    //In this case it is the 2nd layer (States)
    
    _genRenTask = [AGSGenerateRendererTask generateRendererTaskWithURL:sublayerURL credential:nil];
    
    //Create the class breaks definition for the renderer using the 5 quantile method on the pop2000 field
    AGSClassBreaksDefinition *classBreaksDef =
    [AGSClassBreaksDefinition classBreaksDefinitionWithClassificationField:@"pop2000"
                                                      classificationMethod:AGSClassBreaksDefinitionClassificationMethodQuantile
                                                                breakCount:5];
    
    //Generate the renderer for that definition
    AGSAlgorithmicColorRamp *alogrithmicColorRamp =
    [AGSAlgorithmicColorRamp algorithmicColorRampWithFromColor:[AGSColor whiteColor]
                                                       toColor:[AGSColor brownColor]
                                                     algorithm:AGSColorRampAlgorithmCIELab];
    
    //Apply the renderer to the definition
    classBreaksDef.colorRamp = alogrithmicColorRamp;

    
    //Specify the parameters for the AGSGenerateRendererTask
    AGSGenerateRendererParameters *genRenParams = [AGSGenerateRendererParameters generateRendererParametersWithClassificationDefinition:classBreaksDef whereClause:nil];
    
    //Execute the task with the parameters and process the completion block
    _genRenOp = [_genRenTask generateRendererWithParameters:genRenParams completion:^(AGSRenderer *renderer, NSError *error) {
        
        if (error) {
                [self showErrorWithTitle:@"Error generating renderer" message:[NSString stringWithFormat:@"%@",error]];
            
        }
        if (!error){
            
            //If the renderer was created then override the renderer by setting the Dynamic Map Service layer infos (dynamicLayerInfos) to a array of AGSDynamicLayerInfos (containing the new renderer).
            
            //Create an array to contain the layer information for all layers in the dynamic map service
            NSMutableArray *newLayerInfoArray = [[NSMutableArray alloc] init];
            
            //Get the map service information from the Dynamic Map Service Layer
            AGSMapServiceInfo *mapServiceInfo = _dynamicMSLayer.mapServiceInfo;
            
            //For each layer in the map service information
            for (int i=0;i<[mapServiceInfo.layerInfos count];i++) {
                
                //Get the layer information
                AGSMapServiceLayerInfo *layerInfo = (_dynamicMSLayer.mapServiceInfo.layerInfos)[i];
                //Get the layer map source from the Layer's ID
                AGSLayerMapSource *layerMapSource = [AGSLayerMapSource layerMapSourceWithMapLayerID:layerInfo.layerId geodatabaseVersion:nil];
                
                //create the new layer info and add it to the array of dynamic
                AGSDynamicLayerInfo *newLayerInfo;
                
                //For the 2nd layer (States)
                if (layerInfo.layerId  == 2) {
                    
                    //create drawing info using the renderer and set opacity to be transparent (0.5)
                    AGSDrawingInfo *drawingInfo = [[AGSDrawingInfo alloc] initWithRenderer:renderer opacity:0.8];
                    
                    //create the layer info using the drawing info
                    newLayerInfo = [[AGSDynamicLayerInfo alloc] initWithLayerID:layerInfo.layerId
                                                                    drawingInfo:drawingInfo
                                                                    layerSource:layerMapSource];
                    
                }else
                {
                    //create the layer info and don't override the drawing info
                    newLayerInfo = [[AGSDynamicLayerInfo alloc] initWithLayerID:layerInfo.layerId
                                                                    drawingInfo:nil
                                                                    layerSource:layerMapSource];
                }
                
                newLayerInfo.name = layerInfo.name;
                
                //Add the original layers and the new layer to the array
                [newLayerInfoArray addObject:newLayerInfo];
                
                
            }
            
            //set the Dynamic Map Service Layer dynamicLayerInfos property to be the new array of AGSDynamicLayerInfo.
            _dynamicMSLayer.dynamicLayerInfos = newLayerInfoArray;
            
            //refresh the layer
            [_dynamicMSLayer refresh];
            
        }
    } ];

}

// -------------------------------------------------------------------------------
//  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];
}

- (void)showErrorWithTitle:(NSString*)title message:(NSString*)message {
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setMessageText:title];
    [alert setInformativeText:message];
    [alert beginSheetModalForWindow:self.view.window modalDelegate:self didEndSelector:nil contextInfo:nil];
}

@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 DynamicLayerCBRSample : NSViewController <AGSLayerDelegate>

@property (strong) AGSDynamicMapServiceLayer *dynamicMSLayer;
@property (strong) AGSGenerateRendererParameters *genRenParams;
@property (strong) AGSGenerateRendererTask *genRenTask;
@property (strong) NSOperation *genRenOp;

@property (strong) IBOutlet AGSMapView *mapView;

@end
Feedback on this topic?