Skip to content

Show service areas for multiple facilities

View on GitHub

Find the service areas of several facilities from a feature service.

Image of show service areas for multiple facilities sample

Use case

A city taxi company may calculate service areas around their vehicle lots to identify gaps in coverage. Alternatively, they may want to ensure overlaps where a high volume of passengers requires redundant facilities, such as near an airport.

How to use the sample

Upon running, the sample will calculate and display the service area of each facility (hospital) on the map. The polygons displayed around each facility represents the facility's service area: the red area is within 1 minute travel time from the hospital by car, whilst orange is within 3 minutes by car. All service areas are semi-transparent to show where they overlap.

How it works

  1. Create a new ServiceAreaTask from a network service.
  2. Create default ServiceAreaParameters from the service area task.
  3. Set the parameters returnsPolygons property to true to return polygons of all service areas.
  4. Define QueryParameters that retrieve all features from the facilities FeatureTable. Add the facilities to the service area parameters using the query parameters, serviceAreaParameters.setFacilities(fromFeaturesIn:queryParameters:)
  5. Get the ServiceAreaResult by solving the service area task using the parameters.
  6. For each facility, get any ServiceAreaPolygons that were returned, ServiceAreaResult.resultPolygons(forFacilityAtIndex:).
  7. Display each service area polygon as a Graphic in a GraphicsOverlay on the MapView.

Relevant API

  • ServiceAreaParameters
  • ServiceAreaPolygon
  • ServiceAreaResult
  • ServiceAreaTask

About the data

This sample uses a street map of San Diego, in combination with a feature service with facilities (used here to represent hospitals). Additionally a street network is used on the server for calculating the service area.

Tags

facilities, feature service, impedance, network analysis, service area, travel time

Sample Code

ShowServiceAreasForMultipleFacilitiesView.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
115
116
117
118
119
120
121
122
123
// Copyright 2025 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 ShowServiceAreasForMultipleFacilitiesView: View {
    /// A map with a light gray basemap style.
    @State private var map = Map(basemapStyle: .arcGISLightGray)

    /// The service area task used to calculate the service area.
    @State private var serviceAreaTask = ServiceAreaTask(url: URL(string: "https://sampleserver7.arcgisonline.com/server/rest/services/NetworkAnalysis/SanDiego/NAServer/ServiceArea")!)

    /// The feature table that contains the facilities.
    @State private var facilitiesFeatureTable = ServiceFeatureTable(url: URL(string: "https://services2.arcgis.com/ZQgQTuoyBrtmoGdP/ArcGIS/rest/services/San_Diego_Facilities/FeatureServer/0")!)

    /// A graphics overlay which will hold the results of the service area
    /// calculation.
    @State private var graphicsOverlay = GraphicsOverlay()

    /// The error that occurred during calculating the service area.
    @State private var error: Error?

    /// A Boolean value indicating if the service area is being calculated.
    @State private var isCalculatingServiceArea = false

    /// The service area fill symbols.
    let fillSymbols = [
        SimpleFillSymbol(color: .orange.withAlphaComponent(0.5)),
        SimpleFillSymbol(color: .red.withAlphaComponent(0.5))
    ]

    var body: some View {
        MapViewReader { mapViewProxy in
            MapView(map: map, graphicsOverlays: [graphicsOverlay])
                .overlay {
                    if isCalculatingServiceArea {
                        ProgressView("Calculating service area...")
                            .padding()
                            .background(.ultraThickMaterial)
                            .clipShape(.rect(cornerRadius: 10))
                            .shadow(radius: 15)
                    }
                }
                .task {
                    isCalculatingServiceArea = true
                    defer { isCalculatingServiceArea = false }

                    do {
                        // Create a feature layer to display the facilities.
                        // Then add the facilities feature layer to the map.
                        let featureLayer = FeatureLayer(featureTable: facilitiesFeatureTable)
                        map.addOperationalLayer(featureLayer)

                        // Load the facilities feature layer so that we can zoom
                        // to the full extent of the features.
                        try await featureLayer.load()
                        if let fullExtent = featureLayer.fullExtent {
                            await mapViewProxy.setViewpointGeometry(fullExtent, padding: 50)
                        }

                        // Create default parameters for the service area task.
                        let serviceAreaParameters = try await serviceAreaTask.makeDefaultParameters()
                        // Set the facilities for which to calculate service area for.
                        serviceAreaParameters.setFacilities(fromFeaturesIn: facilitiesFeatureTable, queryParameters: .all())
                        // Specify that we want polygons returned, with a high
                        // level of detail.
                        serviceAreaParameters.returnsPolygons = true
                        serviceAreaParameters.polygonDetail = .high
                        // Set our impedance cutoffs to 1 minute and 3 minutes
                        // accordingly.
                        serviceAreaParameters.removeAllDefaultImpedanceCutoffs()
                        serviceAreaParameters.addDefaultImpedanceCutoffs([1, 3])

                        // Solve the service area.
                        let serviceAreaResult = try await serviceAreaTask.solveServiceArea(
                            using: serviceAreaParameters
                        )

                        // Loop through the service area facilities and add the
                        // results to the graphics overlay.
                        for index in serviceAreaResult.facilities.indices {
                            let resultPolygons = serviceAreaResult.resultPolygons(forFacilityAtIndex: index)
                            // There can be multiple polygons for each facility.
                            for (index, polygon) in resultPolygons.enumerated() {
                                graphicsOverlay
                                    .addGraphic(
                                        Graphic(geometry: polygon.geometry, symbol: fillSymbols[index])
                                    )
                            }
                        }
                    } catch {
                        self.error = error
                    }
                }
        }
    }
}

private extension QueryParameters {
    /// Returns a query parameters with the where clause set to "1=1" so
    /// that all features will be returned.
    static func all() -> QueryParameters {
        let queryParameters = QueryParameters()
        queryParameters.whereClause = "1=1"
        return queryParameters
    }
}

#Preview {
    ShowServiceAreasForMultipleFacilitiesView()
}

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