Find the service areas of several facilities from a feature service.
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
Click 'Find service areas' to calculate and display the service area of each facility (hospital) on the map. The polygons displayed around each facility represent 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
- Create a new
ServiceAreaTask
from a network service. - Create default
ServiceAreaParameters
from the service area task. - Set the parameters
ServiceAreaParameters.returnPolygons = true
to return polygons of all service areas. - Define
QueryParameters
that retrieve allFacility
items from aServiceFeatureTable
. Add the facilities to the service area parameters using the query parameters,serviceAreaParameters.SetFacilitiesWithFeatureTable(facilitiesTable, queryParameters).
- Get the
ServiceAreaResult
by solving the service area task using the parameters. - For each facility, get any
ServiceAreaPolygons
that were returned,serviceAreaResult.resultPolygons(facilityIndex)
. - Display the service area polygons as
Graphics
in aGraphicsOverlay
on theMapView
.
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
// [WriteFile Name=FindServiceAreasForMultipleFacilities, Category=Routing]
// [Legal]
// Copyright 2020 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.
// [Legal]
import QtQuick 2.6
import Esri.ArcGISRuntime 100.15
import QtQuick.Layouts 1.11
import QtQuick.Controls 2.2
Rectangle {
id: rootRectangle
clip: true
width: 800
height: 600
property url featureTableUrl: "https://services2.arcgis.com/ZQgQTuoyBrtmoGdP/ArcGIS/rest/services/San_Diego_Facilities/FeatureServer/0"
property url imageUrl: "https://static.arcgis.com/images/Symbols/SafetyHealth/Hospital.png"
property url serviceTaskAreaUrl: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/ServiceArea"
property list<SimpleFillSymbol> fillSymbols: [
SimpleFillSymbol {
style: Enums.SimpleFillSymbolStyleSolid
color: "#66FFA500"
outline: null
},
SimpleFillSymbol {
style: Enums.SimpleFillSymbolStyleSolid
color: "#66FF0000"
}
]
MapView {
id: mapView
anchors.fill: parent
Component.onCompleted: {
// Set the focus on MapView to initially enable keyboard navigation
forceActiveFocus();
}
GraphicsOverlay {
id: serviceAreasOverlay
}
Map {
Basemap {
initStyle: Enums.BasemapStyleArcGISLightGray
}
// create query parameters used to select all facilities from the feature table
QueryParameters {
id: queryParameters
whereClause: "1=1"
}
FeatureLayer {
featureTable: ServiceFeatureTable {
id: featureTable
url: featureTableUrl
}
onLoadStatusChanged: {
if(loadStatus === Enums.LoadStatusLoaded) {
mapView.setViewpointGeometryAndPadding(fullExtent, 100);
}
}
onErrorChanged: {
console.warn(error.message);
}
renderer: SimpleRenderer {
PictureMarkerSymbol {
url: imageUrl
height: 25
width: 25
}
}
}
ServiceAreaTask {
id: serviceAreaTask
url: serviceTaskAreaUrl
Component.onCompleted: {
load();
}
onErrorChanged: {
console.warn(error.message);
}
onLoadStatusChanged: {
if (loadStatus === Enums.LoadStatusLoaded) {
createDefaultParameters();
}
}
onCreateDefaultParametersStatusChanged: {
if (createDefaultParametersStatus === Enums.TaskStatusCompleted) {
createDefaultParametersResult.polygonDetail = Enums.ServiceAreaPolygonDetailHigh;
createDefaultParametersResult.returnPolygons = true;
// add service areas of 1 minute and 3 minutes travel time by car
createDefaultParametersResult.defaultImpedanceCutoffs = [1.0, 3.0];
createDefaultParametersResult.setFacilitiesWithFeatureTable(featureTable, queryParameters);
}
}
onSolveServiceAreaStatusChanged: {
if (solveServiceAreaStatus === Enums.TaskStatusCompleted) {
// iterate through the facilities to get the service area polygons
for (let i = 0; i < solveServiceAreaResult.facilities.length; i++) {
const serviceAreaPolygonList = solveServiceAreaResult.resultPolygons(i);
//create a graphic for each available polygon
for (let j = 0; j < serviceAreaPolygonList.length; j++) {
serviceAreasOverlay.graphics.append(ArcGISRuntimeEnvironment.createObject("Graphic", {geometry: serviceAreaPolygonList[j].geometry, symbol: fillSymbols[j]}));
}
}
}
}
}
}
RowLayout {
anchors {
left: parent.left
top: parent.top
}
Button {
Layout.fillWidth: true
Layout.fillHeight: true
text: "Find service areas"
onClicked: {
enabled = false;
serviceAreaTask.solveServiceArea(serviceAreaTask.createDefaultParametersResult)
}
}
}
}
BusyIndicator {
anchors.centerIn: parent
visible: true
running: serviceAreaTask.solveServiceAreaStatus === Enums.TaskStatusInProgress
}
}