Identify features in WMS layer

View on GitHub

Identify features in a WMS layer and display the associated popup content.

Image of Identify features in WMS layer sample

Use case

Map symbols generally showcase only one or two data points via color or size, but the data can contain many more attributes than what is shown on the map. These additional attributes can be shown in an attribute table or popup for the map viewer to explore interactively. For example, the map might be symbolized to show population density with different shades of a color, but it might contain other interesting attributes to explore in a table, such as median income, educational attainment, and median age.

How to use the sample

Tap a feature to identify it. The HTML content associated with the feature will be displayed in a web view.

How it works

  1. A WMS layer is added via URL and a layer name.
  2. When the map is tapped, MapViewProxy.identify is used to find matching results within the WMS layer.
  3. If there is a matching feature, the HTML property is taken via a lookup in the feature's attribute dictionary.
  4. This particular server will produce an identify result with an empty table when there is no identified feature. In all other cases, a table with an OBJECTID column is added. This sample checks for the presence of OBJECTID in the HTML, and doesn't display the result if it is missing.
  5. The HTML is displayed in the web view.

Note: The service returns HTML regardless of whether there was an identify result. The sample uses a simple rule to hide empty results.

Relevant API

  • IdentifyLayerResult
  • IdentifyLayerResult.GeoElements
  • MapView.Identify
  • WMSFeature
  • WMSFeature.Attributes
  • WMSLayer

About the data

This sample shows a map of surface water sources in each U.S. state. States with more surface and ground water sources appear darker blue. The attribute table includes counts of surface and ground water sources. This map service is provided by the U.S. EPA.

Tags

OGC, web map service, WMS

Sample Code

IdentifyFeaturesInWMSLayerView.swift
Use dark colors for code blocksCopy
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
// Copyright 2024 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
//
//   https://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 ArcGIS
import SwiftUI

struct IdentifyFeaturesInWMSLayerView: View {
    /// A map with a dark gray base basemap centered on the USA.
    @State private var map: Map = {
        let map = Map(basemapStyle: .arcGISDarkGrayBase)
        let center = Point(x: -95.7129, y: 37.0902, spatialReference: .wgs84)
        map.initialViewpoint = Viewpoint(center: center, scale: 7e7)
        return map
    }()

    /// The WMS layer with EPA water info.
    @State private var waterInfoLayer = WMSLayer(url: .epaWaterInfo, layerNames: ["4"])

    /// The text of a WMS feature HTML attribute that is shown in the web view.
    @State private var webViewText = ""

    /// The tapped screen point.
    @State private var tapScreenPoint: CGPoint?

    /// The placement of the callout on the map.
    @State private var calloutPlacement: CalloutPlacement?

    /// The string text for the identify layer overlay.
    private let overlayText = "Tap on the map to identify features in the WMS layer."

    /// The error shown in the error alert.
    @State private var error: Error?

    init() {
        map.addOperationalLayer(waterInfoLayer)
    }

    var body: some View {
        MapViewReader { mapViewProxy in
            MapView(map: map)
                .callout(placement: $calloutPlacement.animation(.default.speed(2))) { _ in
                    ScrollView(.horizontal) {
                        WebView(htmlString: webViewText)
                            // Set the width so the html is readable.
                            .frame(width: 800, height: 95)
                            // Disable the WebView scrolling.
                            .disabled(true)
                    }
                    .frame(maxWidth: 300)
                    .padding(10)
                }
                .onSingleTapGesture { screenPoint, _ in
                    tapScreenPoint = screenPoint
                }
                .task(id: tapScreenPoint) {
                    do {
                        // Identify on WMS layer using the screen point.
                        guard let screenPoint = tapScreenPoint else {
                            return
                        }
                        calloutPlacement = nil

                        // Identify feature on water info layer.
                        let identifyResult = try await mapViewProxy.identify(
                            on: waterInfoLayer,
                            screenPoint: screenPoint,
                            tolerance: 2
                        )
                        // Convert the result to text.
                        if let feature = identifyResult.geoElements.first,
                           let htmlText = feature.attributes["HTML"] as? String,
                           // Display the HTML table if it has an OBJECTID column.
                           htmlText.contains("OBJECTID"),
                           let location = mapViewProxy.location(fromScreenPoint: screenPoint) {
                            webViewText = htmlText
                            calloutPlacement = .location(location)
                        }
                    } catch {
                        self.error = error
                    }
                }
                .overlay(alignment: .top) {
                    Text(overlayText)
                        .frame(maxWidth: .infinity, alignment: .center)
                        .padding(8)
                        .multilineTextAlignment(.center)
                        .background(.thinMaterial, ignoresSafeAreaEdges: .horizontal)
                }
        }
        .errorAlert(presentingError: $error)
    }
}

private extension URL {
    /// A URL to the WMS service showing EPA water info.
    static var epaWaterInfo: URL {
        URL(string: "https://watersgeo.epa.gov/arcgis/services/OWPROGRAM/SDWIS_WMERC/MapServer/WMSServer?request=GetCapabilities&service=WMS")!
    }
}

#Preview {
    IdentifyFeaturesInWMSLayerView()
}

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