Dynamic Layer Unique Value Renderer

Download Sample Application

This sample demonstrates that the client can override the unique value 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 unique value renderer definition
AGSUniqueValueDefinition *uniqueValueDefinition = [AGSUniqueValueDefinition uniqueValueDefinitionWithUniqueValueFields:@[@"state_name"]];

//Specify the color ramps...
AGSAlgorithmicColorRamp *alogrithmicColorRamp1 =
[AGSAlgorithmicColorRamp algorithmicColorRampWithFromColor:[AGSColor yellowColor]
toColor:[AGSColor blueColor]
algorithm:AGSColorRampAlgorithmCIELab];

...

//Create the mulitpart color ramps
AGSMultipartColorRamp *mpColorRamp = [[AGSMultipartColorRamp alloc] initWithColorRamps:@[alogrithmicColorRamp1, ..., ]];

//Assign the ramp to the definition
uniqueValueDefinition.colorRamp = mpColorRamp;

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

//Create a generate renderer task
_genRenTask = [AGSGenerateRendererTask generateRendererTaskWithURL:sublayerURL credential:credentials];

//Execute the task with the parameters and 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

let kUVRBaseMapURL = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"
let kUVRDynamicMapServiceURL = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer"

class DynamicLayerUVRSwiftSample: 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: kUVRBaseMapURL))
        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: kUVRDynamicMapServiceURL))
        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)
        
        let uniqueValueDefinition = AGSUniqueValueDefinition(uniqueValueFields:["state_name"])
        
        let alogrithmicColorRamp1 = AGSAlgorithmicColorRamp(fromColor: NSColor.yellowColor(), toColor: NSColor.blueColor(), algorithm: .CIELab)
        let alogrithmicColorRamp2 = AGSAlgorithmicColorRamp(fromColor: NSColor.redColor(), toColor: NSColor.greenColor(), algorithm: .CIELab)
        let alogrithmicColorRamp3 = AGSAlgorithmicColorRamp(fromColor: NSColor.brownColor(), toColor: NSColor.orangeColor(), algorithm: .CIELab)
        
        let mpColorRamp = AGSMultipartColorRamp(colorRamps: [alogrithmicColorRamp1, alogrithmicColorRamp2, alogrithmicColorRamp3])
        
        uniqueValueDefinition.colorRamp = mpColorRamp
        
        //Specify the parameters for the AGSGenerateRendererTask
        let genRenParams = AGSGenerateRendererParameters(classificationDefinition: uniqueValueDefinition, 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.5)
                            
                            //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 "DynamicLayerUVRSample.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 DynamicLayerUVRSample

#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];
    
    
    AGSUniqueValueDefinition *uniqueValueDefinition = [AGSUniqueValueDefinition uniqueValueDefinitionWithUniqueValueFields:@[@"state_name"]];
    
    AGSAlgorithmicColorRamp *alogrithmicColorRamp1 =
    [AGSAlgorithmicColorRamp algorithmicColorRampWithFromColor:[AGSColor yellowColor]
                                                       toColor:[AGSColor blueColor]
                                                     algorithm:AGSColorRampAlgorithmCIELab];
    
    AGSAlgorithmicColorRamp *alogrithmicColorRamp2 =
    [AGSAlgorithmicColorRamp algorithmicColorRampWithFromColor:[AGSColor redColor]
                                                       toColor:[AGSColor greenColor]
                                                     algorithm:AGSColorRampAlgorithmCIELab];
    
    AGSAlgorithmicColorRamp *alogrithmicColorRamp3 =
    [AGSAlgorithmicColorRamp algorithmicColorRampWithFromColor:[AGSColor brownColor]
                                                       toColor:[AGSColor orangeColor]
                                                     algorithm:AGSColorRampAlgorithmCIELab];
    
    AGSMultipartColorRamp *mpColorRamp = [[AGSMultipartColorRamp alloc] initWithColorRamps:@[alogrithmicColorRamp1, alogrithmicColorRamp2, alogrithmicColorRamp3]];
    
    uniqueValueDefinition.colorRamp = mpColorRamp;
    
    //Specify the parameters for the AGSGenerateRendererTask
    AGSGenerateRendererParameters *genRenParams = [AGSGenerateRendererParameters generateRendererParametersWithClassificationDefinition:uniqueValueDefinition whereClause:nil];
    
    //Execute the task with the parameters and 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.5];
                    
                    //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;
            
                [newLayerInfoArray addObject:newLayerInfo];
                
                
            }
            
            //set the Dynamic Map Service Layer dynamicLayerInfos property to be a 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 DynamicLayerUVRSample : 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?