Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8c32968
Add ReadME.
CalebRas Jun 5, 2023
49c6d1a
Add swift source file.
CalebRas Jun 5, 2023
7f8ad0d
Add metadata.
CalebRas Jun 5, 2023
30eb6b3
Add source to Build Phases.
CalebRas Jun 5, 2023
28e63cc
Add screenshot.
CalebRas Jun 5, 2023
8ba09cd
Remove ProgressView.
CalebRas Jun 8, 2023
d1089ed
Update with review suggestions.
CalebRas Jun 9, 2023
4a41863
Merge branch 'v.next' into Caleb/New-IdentifyLayerFeatures
CalebRas Jun 9, 2023
273d9f5
Merge branch 'v.next' into Caleb/New-IdentifyLayerFeatures
CalebRas Jun 12, 2023
b97ff83
Merge branch 'v.next' into Caleb/New-IdentifyLayerFeatures
CalebRas Jun 12, 2023
f57816b
Merge branch 'v.next' into Caleb/New-IdentifyLayerFeatures
CalebRas Jun 13, 2023
f31b7a4
Sort after conflict merge.
CalebRas Jun 13, 2023
05da329
Merge branch 'v.next' into Caleb/New-IdentifyLayerFeatures
CalebRas Jun 14, 2023
71c08b9
Update Shared/Samples/Identify layer features/README.md
CalebRas Jun 14, 2023
f3599a1
Update Shared/Samples/Identify layer features/README.md
CalebRas Jun 14, 2023
2aae258
Update Shared/Samples/Identify layer features/README.md
CalebRas Jun 14, 2023
222cc5d
Update Shared/Samples/Identify layer features/README.md
CalebRas Jun 14, 2023
83c6fd2
Update Shared/Samples/Identify layer features/IdentifyLayerFeaturesVi…
CalebRas Jun 14, 2023
24398c0
Update Shared/Samples/Identify layer features/README.md
CalebRas Jun 14, 2023
4cf087d
Update Shared/Samples/Identify layer features/IdentifyLayerFeaturesVi…
CalebRas Jun 14, 2023
c7d418e
Update Shared/Samples/Identify layer features/IdentifyLayerFeaturesVi…
CalebRas Jun 14, 2023
0d6dcc9
Update Shared/Samples/Identify layer features/IdentifyLayerFeaturesVi…
CalebRas Jun 14, 2023
69d1fae
Update Shared/Samples/Identify layer features/IdentifyLayerFeaturesVi…
CalebRas Jun 14, 2023
7dcd929
Update Shared/Samples/Identify layer features/README.md
CalebRas Jun 14, 2023
0af85bf
Update Shared/Samples/Identify layer features/README.md
CalebRas Jun 14, 2023
3be73dc
Update Shared/Samples/Identify layer features/IdentifyLayerFeaturesVi…
CalebRas Jun 14, 2023
ed90f3d
Update metadata.
CalebRas Jun 14, 2023
189315f
Update screenshot.
CalebRas Jun 14, 2023
3deb9b1
Merge branch 'v.next' into Caleb/New-IdentifyLayerFeatures
CalebRas Jun 14, 2023
f66c414
Update with review suggestions.
CalebRas Jun 15, 2023
fe5f044
Update naming.
CalebRas Jun 15, 2023
955b113
Merge branch 'v.next' into Caleb/New-IdentifyLayerFeatures
CalebRas Jun 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Samples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
D744FD182A2113C70084A66C /* CreateConvexHullAroundPointsView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = D744FD162A2112D90084A66C /* CreateConvexHullAroundPointsView.swift */; };
D75101812A2E493600B8FA48 /* ShowLabelsOnLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75101802A2E493600B8FA48 /* ShowLabelsOnLayerView.swift */; };
D75101822A2E497F00B8FA48 /* ShowLabelsOnLayerView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = D75101802A2E493600B8FA48 /* ShowLabelsOnLayerView.swift */; };
D751018E2A2E962D00B8FA48 /* IdentifyLayerFeaturesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D751018D2A2E962D00B8FA48 /* IdentifyLayerFeaturesView.swift */; };
D751018F2A2E966C00B8FA48 /* IdentifyLayerFeaturesView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = D751018D2A2E962D00B8FA48 /* IdentifyLayerFeaturesView.swift */; };
D752D9462A3A6F80003EB25E /* MonitorChangesToMapLoadStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D752D9452A3A6F7F003EB25E /* MonitorChangesToMapLoadStatusView.swift */; };
D752D9472A3A6FC0003EB25E /* MonitorChangesToMapLoadStatusView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = D752D9452A3A6F7F003EB25E /* MonitorChangesToMapLoadStatusView.swift */; };
D75362D22A1E886700D83028 /* ApplyUniqueValueRendererView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D75362D12A1E886700D83028 /* ApplyUniqueValueRendererView.swift */; };
Expand Down Expand Up @@ -226,6 +228,7 @@
dstPath = "";
dstSubfolderSpec = 7;
files = (
D751018F2A2E966C00B8FA48 /* IdentifyLayerFeaturesView.swift in Copy Source Code Files */,
D752D9472A3A6FC0003EB25E /* MonitorChangesToMapLoadStatusView.swift in Copy Source Code Files */,
D7CC34002A3147FF00198EDF /* ShowLineOfSightBetweenPointsView.swift in Copy Source Code Files */,
D71099712A280D830065A1C1 /* DensifyAndGeneralizeGeometryView.SettingsView.swift in Copy Source Code Files */,
Expand Down Expand Up @@ -363,6 +366,7 @@
D734FA092A183A5B00246D7E /* SetMaxExtentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetMaxExtentView.swift; sourceTree = "<group>"; };
D744FD162A2112D90084A66C /* CreateConvexHullAroundPointsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateConvexHullAroundPointsView.swift; sourceTree = "<group>"; };
D75101802A2E493600B8FA48 /* ShowLabelsOnLayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShowLabelsOnLayerView.swift; sourceTree = "<group>"; };
D751018D2A2E962D00B8FA48 /* IdentifyLayerFeaturesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifyLayerFeaturesView.swift; sourceTree = "<group>"; };
D752D9452A3A6F7F003EB25E /* MonitorChangesToMapLoadStatusView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MonitorChangesToMapLoadStatusView.swift; sourceTree = "<group>"; };
D75362D12A1E886700D83028 /* ApplyUniqueValueRendererView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplyUniqueValueRendererView.swift; sourceTree = "<group>"; };
D754E3222A1D66820006C5F1 /* StylePointWithPictureMarkerSymbolsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StylePointWithPictureMarkerSymbolsView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -516,6 +520,7 @@
E066DD33285CF3A0004D3D5B /* Find route */,
E088E1722863B5E600413100 /* Generate offline map */,
0044288C29C90BD500160767 /* Get elevation at point on surface */,
D751018A2A2E960300B8FA48 /* Identify layer features */,
D752D9422A3A6EB8003EB25E /* Monitor changes to map load status */,
75DD739029D38B1B0010229D /* Navigate route */,
E0EA0B75286638FD00C9621D /* Project geometry */,
Expand Down Expand Up @@ -847,6 +852,14 @@
path = "Show labels on layer";
sourceTree = "<group>";
};
D751018A2A2E960300B8FA48 /* Identify layer features */ = {
isa = PBXGroup;
children = (
D751018D2A2E962D00B8FA48 /* IdentifyLayerFeaturesView.swift */,
);
path = "Identify layer features";
sourceTree = "<group>";
};
D752D9422A3A6EB8003EB25E /* Monitor changes to map load status */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1323,6 +1336,7 @@
4D2ADC6229C5071C003B367F /* ChangeMapViewBackgroundView.Model.swift in Sources */,
0074ABCD2817BCC30037244A /* SamplesApp+Samples.swift.tache in Sources */,
E004A6F3284E4FEB002A1FE6 /* ShowResultOfSpatialOperationsView.swift in Sources */,
D751018E2A2E962D00B8FA48 /* IdentifyLayerFeaturesView.swift in Sources */,
F1E71BF1289473760064C33F /* AddRasterFromFileView.swift in Sources */,
00B04273282EC59E0072E1B4 /* AboutView.swift in Sources */,
7573E81F29D6134C00BEED9C /* TraceUtilityNetworkView.swift in Sources */,
Expand Down
141 changes: 141 additions & 0 deletions Shared/Samples/Identify layer features/IdentifyLayerFeaturesView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright 2023 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 IdentifyLayerFeaturesView: View {
/// A map with a topographic basemap centered on the United States.
@State var map: Map = {
let map = Map(basemapStyle: .arcGISTopographic)
map.initialViewpoint = Viewpoint(
center: Point(x: -10977012.785807, y: 4514257.550369, spatialReference: .webMercator),
scale: 68015210
)
return map
}()

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

/// The string text for the identify layer results overlay.
@State var overlayText = "Tap on the map to identify feature layers."

/// A Boolean value indicating whether to show an error alert.
@State var isShowingAlert = false

/// The error shown in the error alert.
@State var error: Error? {
didSet { isShowingAlert = error != nil }
}

var body: some View {
ZStack {
MapViewReader { proxy in
MapView(map: map)
.onSingleTapGesture { screenPoint, _ in
tapScreenPoint = screenPoint
}
.task {
do {
// Add map image layer to the map.
let mapImageLayer = ArcGISMapImageLayer(url: .worldCities)
try await mapImageLayer.load()

// Hide continent and world layers.
mapImageLayer.subLayerContents[1].isVisible = false
mapImageLayer.subLayerContents[2].isVisible = false
map.addOperationalLayer(mapImageLayer)

// Add feature layer to the map.
let featureTable = ServiceFeatureTable(url: .damageAssessment)
try await featureTable.load()
let featureLayer = FeatureLayer(featureTable: featureTable)
map.addOperationalLayer(featureLayer)
} catch {
// Present error load the layers if any.
self.error = error
}
}
.task(id: tapScreenPoint) {
// Identify layers using the screen point.
if let screenPoint = tapScreenPoint,
let results = try? await proxy.identifyLayers(
screenPoint: screenPoint,
tolerance: 12,
returnPopupsOnly: false,
maximumResultsPerLayer: 10
) {
handleIdentifyResults(results)
}
}
.overlay(alignment: .top) {
Text(overlayText)
.frame(maxWidth: .infinity, alignment: .center)
.padding(8)
.background(.thinMaterial, ignoresSafeAreaEdges: .horizontal)
}
.alert(isPresented: $isShowingAlert, presentingError: error)
}
}
}
}

private extension IdentifyLayerFeaturesView {
/// Updates the overlay text based on the identify layer results.
/// - Parameter results: An `IdentifyLayerResult` array to handle.
func handleIdentifyResults(_ results: [IdentifyLayerResult]) {
// Get layer names and geoelement counts from the results.
let identifyLayerResultInfo: [(layerName: String, geoElementsCount: Int)] = results.map { identifyLayerResult in
let layerName = identifyLayerResult.layerContent.name
let geoElementsCount = geoElementsCountFromResult(identifyLayerResult)
return (layerName, geoElementsCount)
}

let message = identifyLayerResultInfo
.map { "\($0.layerName): \($0.geoElementsCount)" }
.joined(separator: "\n")

let totalGeoElementsCount = identifyLayerResultInfo.map(\.geoElementsCount).reduce(0, +)

// Update overlay text with the geo-elements found if any.
overlayText = totalGeoElementsCount > 0 ? message : "No element found."
}

/// Counts the geo-elements from an identify layer result using recursion.
/// - Parameter result: The `IdentifyLayerResult` to count.
/// - Returns: The count of the geo-elements.
private func geoElementsCountFromResult(_ identifyResult: IdentifyLayerResult) -> Int {
// Get geoElements count from the result.
var count = identifyResult.geoElements.count

// Get the count using recursion from the result's sublayer results if any.
for result in identifyResult.sublayerResults {
count += geoElementsCountFromResult(result)
}
return count
}
}

private extension URL {
/// A world cities image layer URL.
static var worldCities: URL {
URL(string: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer")!
}

/// A damage assessment feature layer URL.
static var damageAssessment: URL {
URL(string: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/DamageAssessment/FeatureServer/0")!
}
}
32 changes: 32 additions & 0 deletions Shared/Samples/Identify layer features/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Identify layer features

Identify features in all layers in a map.

![Image of Identify layer features sample](identify-layer-features.png)

## Use case

"Identify layers" operation allows users to tap on a map, returning features at that location across multiple layers. Because some layer types have sublayers, the sample recursively counts results for sublayers within each layer.

## How to use the sample

Tap to identify features. The text overlay will update to show all layers with features under the tapped location, as well as a layer count.

## How it works

1. The tapped position is passed to `MapViewProxy.identifyLayers(screenPoint:tolerance:returnPopupsOnly:maximumResultsPerLayer:)` method.
2. For each `IdentifyLayerResult` in the results, features are counted.
* Note: there is one identify result per layer with matching features; if the feature count is 0, that means a sublayer contains the matching features.

## Relevant API

* IdentifyLayerResult
* LayerContent

## Additional information

The GeoView supports two methods of identify: `identifyLayer`, which identifies features within a specific layer and `identifyLayers`, which identifies features for all layers in the current view.

## Tags

identify, recursion, recursive, sublayers
25 changes: 25 additions & 0 deletions Shared/Samples/Identify layer features/README.metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"category": "Maps",
"description": "Identify features in all layers in a map.",
"ignore": false,
"images": [
"identify-layer-features.png"
],
"keywords": [
"identify",
"recursion",
"recursive",
"sublayers",
"IdentifyLayerResult",
"LayerContent"
],
"redirect_from": [],
"relevant_apis": [
"IdentifyLayerResult",
"LayerContent"
],
"snippets": [
"IdentifyLayerFeaturesView.swift"
],
"title": "Identify layer features"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.