Change sublayer renderer

View on GitHub
Sample viewer app

Apply a renderer to a sublayer.

Change sublayer renderer sample

Use case

A layer showing animal populations contains sublayers for different species. A renderer could be applied which gives each sublayer a different color, so that populations of each species can be compared visually.

How to use the sample

Tap on the "Apply renderer" button to apply a class breaks renderer based on population for each county. Tap on the "Reset" button to reset to original renderer.

How it works

  1. Create an AGSArcGISMapImageLayer from its URL.
  2. After it is done loading, get the counties sublayer from the map image layer's mapImageSublayers array.
  3. After the sublayer loads, get its original AGSRenderer.
  4. Create an AGSClassBreaksRenderer with a collection of AGSClassBreaks for different population ranges.
  5. Set the results as the sublayer's new AGSRenderer.

Relevant API

  • AGSArcGISMapImageLayer
  • AGSArcGISMapImageSubLayer
  • AGSClassBreak
  • AGSClassBreaksRenderer

About the data

This application displays census data from an ArcGIS Server map service. It contains various population statistics, including total population for each county in 2007.

Additional information

The service hosting the layer must support dynamic layers to be able to change the rendering of sublayers.

Tags

class breaks, dynamic layer, dynamic rendering, renderer, sublayer, symbology, visualization

Sample Code

ChangeSublayerRendererViewController.swift
                                                                                                                             
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2017 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 UIKit
import ArcGIS

class ChangeSublayerRendererViewController: UIViewController {
    @IBOutlet private var mapView: AGSMapView!
    @IBOutlet private var resetBarButtonItem: UIBarButtonItem!
    @IBOutlet private var applyRendererBarButtonItem: UIBarButtonItem!

    /// Map image layer.
    private let mapImageLayer = AGSArcGISMapImageLayer(url: URL(string: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer")!)
    /// The counties sublayer of the map image layer.
    private var countiesSublayer: AGSArcGISMapImageSublayer?
    private var originalRenderer: AGSRenderer?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Add the source code button item to the right of navigation bar.
        (self.navigationItem.rightBarButtonItem as! SourceCodeBarButtonItem).filenames = ["ChangeSublayerRendererViewController"]

        // Initialize map with basemap.
        let map = AGSMap(basemapStyle: .arcGISStreets)

        // Add map image layer to the map.
        map.operationalLayers.add(mapImageLayer)

        // Set map on the map view.
        mapView.map = map

        // Set viewpoint.
        let envelope = AGSEnvelope(xMin: -13834661.666904, yMin: 331181.323482, xMax: -8255704.998713, yMax: 9118038.075882, spatialReference: .webMercator())
        mapView.setViewpoint(AGSViewpoint(targetExtent: envelope))

        // Load map image layer to access sublayers.
        self.mapImageLayer.load { [weak self] (error: Error?) in
            guard let self = self else { return }
            if let error = error {
                print("Error loading map image layer: \(error)")
            } else {
                self.mapImageLayerDidLoad()
            }
        }
    }

    /// Called in response to the map image layer loading successfully.
    func mapImageLayerDidLoad() {
        // Get the counties sublayer.
        let mapImageSublayers = mapImageLayer.mapImageSublayers
        guard mapImageSublayers.count >= 3,
            let sublayer = mapImageSublayers[2] as? AGSArcGISMapImageSublayer else {
                return
        }
        countiesSublayer = sublayer
        // Load the sublayer to get the original renderer.
        sublayer.load { [weak self] (error) in
            guard let self = self else { return }
            if let error = error {
                print("Error loading map image sublayer: \(error)")
            } else {
                self.countiesSublayerDidLoad()
            }
        }
    }

    /// Called in response to the counties sublayer loading successfully.
    func countiesSublayerDidLoad() {
        originalRenderer = countiesSublayer?.renderer

        // Enable bar button items.
        applyRendererBarButtonItem.isEnabled = true
        resetBarButtonItem.isEnabled = true
    }

    /// Creates a class breaks renderer for counties in the US based on their
    /// population in 2007.
    ///
    /// - Returns: An `AGSClassBreaksRenderer` object.
    private func makeClassBreakRenderer() -> AGSClassBreaksRenderer {
        // Outline symbol.
        let lineSymbol = AGSSimpleLineSymbol(style: .solid, color: UIColor(white: 0.6, alpha: 1), width: 0.5)

        // Symbols for each class break.
        let symbol1 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.89, green: 0.92, blue: 0.81, alpha: 1), outline: lineSymbol)
        let symbol2 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.59, green: 0.76, blue: 0.75, alpha: 1), outline: lineSymbol)
        let symbol3 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.38, green: 0.65, blue: 0.71, alpha: 1), outline: lineSymbol)
        let symbol4 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.27, green: 0.49, blue: 0.59, alpha: 1), outline: lineSymbol)
        let symbol5 = AGSSimpleFillSymbol(style: .solid, color: UIColor(red: 0.16, green: 0.33, blue: 0.47, alpha: 1), outline: lineSymbol)

        // Class breaks.
        let classBreak1 = AGSClassBreak(description: "-99 to 8560", label: "-99 to 8560", minValue: -99, maxValue: 8560, symbol: symbol1)
        let classBreak2 = AGSClassBreak(description: "> 8,560 to 18,109", label: "> 8,560 to 18,109", minValue: 8561, maxValue: 18109, symbol: symbol2)
        let classBreak3 = AGSClassBreak(description: "> 18,109 to 35,501", label: "> 18,109 to 35,501", minValue: 18110, maxValue: 35501, symbol: symbol3)
        let classBreak4 = AGSClassBreak(description: "> 35,501 to 86,100", label: "> 35,501 to 86,100", minValue: 35502, maxValue: 86100, symbol: symbol4)
        let classBreak5 = AGSClassBreak(description: "> 86,100 to 10,110,975", label: "> 86,100 to 10,110,975", minValue: 86101, maxValue: 10110975, symbol: symbol5)

        // Create a class break renderer using the class breaks above.
        let classBreakRenderer = AGSClassBreaksRenderer(fieldName: "POP2007", classBreaks: [ classBreak1, classBreak2, classBreak3, classBreak4, classBreak5])

        return classBreakRenderer
    }

    // MARK: - Actions

    @IBAction private func applyRenderer() {
        countiesSublayer?.renderer = makeClassBreakRenderer()
    }

    @IBAction private func reset() {
        countiesSublayer?.renderer = originalRenderer
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.