@@ -29,6 +29,7 @@ class FindClosestFacilityFromPointSample extends StatefulWidget {
2929
3030class _FindClosestFacilityFromPointSampleState
3131 extends State <FindClosestFacilityFromPointSample > with SampleStateSupport {
32+ // Create the URIs for the fire station and fire images, as well as the URIs for the facilities and incidents layers.
3233 static final _fireStationImageUri = Uri .parse (
3334 'https://static.arcgis.com/images/Symbols/SafetyHealth/FireStation.png' );
3435 static final _fireImageUri = Uri .parse (
@@ -37,46 +38,63 @@ class _FindClosestFacilityFromPointSampleState
3738 'https://services2.arcgis.com/ZQgQTuoyBrtmoGdP/ArcGIS/rest/services/San_Diego_Facilities/FeatureServer/0' );
3839 static final _incidentsLayerUri = Uri .parse (
3940 'https://services2.arcgis.com/ZQgQTuoyBrtmoGdP/ArcGIS/rest/services/San_Diego_Incidents/FeatureServer/0' );
41+ // Create a task for the closest facility service.
4042 final _closestFacilityTask = ClosestFacilityTask .withUrl (Uri .parse (
4143 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/NetworkAnalysis/SanDiego/NAServer/ClosestFacility' ));
42-
44+ // Create a controller for the map view.
4345 final _mapViewController = ArcGISMapView .createController ();
46+ // Create a graphics overlay for the route.
4447 final _routeGraphicsOverlay = GraphicsOverlay ();
45- bool _isRouteSolved = false ;
46- bool _isInitialized = false ;
48+ // Create a flag to track whether the route has been solved.
49+ var _routeSolved = false ;
50+ // A flag for when the map view is ready and controls can be used.
51+ var _ready = false ;
52+ // Create parameters for the closest facility task.
4753 late final ClosestFacilityParameters _closestFacilityParameters;
54+ // Create a symbol for the route line.
4855 final _routeLineSymbol = SimpleLineSymbol (
4956 style: SimpleLineSymbolStyle .solid, color: Colors .blue, width: 5.0 );
5057
5158 @override
5259 Widget build (BuildContext context) {
5360 return Scaffold (
5461 body: SafeArea (
55- child: Column (
62+ top: false ,
63+ child: Stack (
5664 children: [
57- Expanded (
58- child: ArcGISMapView (
59- controllerProvider: () => _mapViewController,
60- onMapViewReady: onMapViewReady,
61- ),
62- ),
63- SizedBox (
64- height: 60 ,
65- child: Row (
66- crossAxisAlignment: CrossAxisAlignment .center,
67- mainAxisAlignment: MainAxisAlignment .spaceEvenly,
68- children: [
69- ElevatedButton (
70- onPressed: ! _isRouteSolved && _isInitialized
71- ? () => solveRoutes ()
72- : null ,
73- child: const Text ('Solve Routes' ),
65+ Column (
66+ children: [
67+ Expanded (
68+ // Add a map view to the widget tree and set a controller.
69+ child: ArcGISMapView (
70+ controllerProvider: () => _mapViewController,
71+ onMapViewReady: onMapViewReady,
7472 ),
75- ElevatedButton (
76- onPressed: _isRouteSolved ? () => resetRoutes () : null ,
77- child: const Text ('Reset' ),
78- ),
79- ],
73+ ),
74+ Row (
75+ mainAxisAlignment: MainAxisAlignment .spaceEvenly,
76+ children: [
77+ // Create buttons to solve the routes and reset the graphics.
78+ ElevatedButton (
79+ onPressed: ! _routeSolved ? solveRoutes : null ,
80+ child: const Text ('Solve Routes' ),
81+ ),
82+ ElevatedButton (
83+ onPressed: _routeSolved ? resetRoutes : null ,
84+ child: const Text ('Reset' ),
85+ ),
86+ ],
87+ ),
88+ ],
89+ ),
90+ // Display a progress indicator and prevent interaction until state is ready.
91+ Visibility (
92+ visible: ! _ready,
93+ child: SizedBox .expand (
94+ child: Container (
95+ color: Colors .white30,
96+ child: const Center (child: CircularProgressIndicator ()),
97+ ),
8098 ),
8199 ),
82100 ],
@@ -85,16 +103,41 @@ class _FindClosestFacilityFromPointSampleState
85103 );
86104 }
87105
88- Future <void > onMapViewReady () async {
106+ void onMapViewReady () async {
107+ // Create a map with the ArcGIS Streets basemap style.
89108 final map = ArcGISMap .withBasemapStyle (BasemapStyle .arcGISStreets);
90109
110+ // Create feature table for the facilities layer.
111+ final facilitiesFeatureTable =
112+ ServiceFeatureTable .withUri (_facilitiesLayerUri);
113+ // Create a marker symbol for the facilities.
114+ final facilitiesMarkerSymbol =
115+ PictureMarkerSymbol .withUrl (_fireStationImageUri)
116+ ..width = 30
117+ ..height = 30 ;
118+ // Create a feature layer for the facilities.
91119 final facilitiesLayer =
92- buildFeatureLayer (_facilitiesLayerUri, _fireStationImageUri);
93- final incidentsLayer = buildFeatureLayer (_incidentsLayerUri, _fireImageUri);
120+ FeatureLayer .withFeatureTable (facilitiesFeatureTable)
121+ ..renderer = SimpleRenderer (symbol: facilitiesMarkerSymbol);
122+
123+ // Create feature table for the incidents layer.
124+ final incidentsFeatureTable =
125+ ServiceFeatureTable .withUri (_incidentsLayerUri);
126+ // Create a marker symbol for the incidents.
127+ final incidentsMarkerSymbol = PictureMarkerSymbol .withUrl (_fireImageUri)
128+ ..width = 30
129+ ..height = 30 ;
130+ // Create a feature layer for the incidents.
131+ final incidentsLayer = FeatureLayer .withFeatureTable (incidentsFeatureTable)
132+ ..renderer = SimpleRenderer (symbol: incidentsMarkerSymbol);
133+
134+ // Add the layers to the map.
94135 map.operationalLayers.addAll ([facilitiesLayer, incidentsLayer]);
95136
137+ // Set the map on the map view controller.
96138 _mapViewController.arcGISMap = map;
97139
140+ // Add the route graphics overlay to the map view controller.
98141 _routeGraphicsOverlay.opacity = 0.75 ;
99142 _mapViewController.graphicsOverlays.add (_routeGraphicsOverlay);
100143
@@ -104,80 +147,92 @@ class _FindClosestFacilityFromPointSampleState
104147 incidentsLayer.load (),
105148 ]);
106149
107- // Get the extent from the layers and use the combination as the viewpoint geometry
150+ // Get the extent from the layers and use the combination as the viewpoint geometry.
108151 final mapExtent = GeometryEngine .combineExtents (
109152 geometry1: facilitiesLayer.fullExtent! ,
110153 geometry2: incidentsLayer.fullExtent! ,
111154 );
112155
156+ // Set the viewpoint geometry on the map view controller.
113157 _mapViewController.setViewpointGeometry (mapExtent, paddingInDiPs: 30 );
114158
159+ // Generate the closest facility parameters.
115160 _closestFacilityParameters = await generateClosestFacilityParameters (
116- facilitiesLayer, incidentsLayer );
161+ facilitiesFeatureTable, incidentsFeatureTable );
117162
118- setState (() => _isInitialized = true );
163+ // Set the initialized flag to true.
164+ setState (() => _ready = true );
119165 }
120166
121167 FeatureLayer buildFeatureLayer (Uri tableUri, Uri imageUri) {
168+ // Create a feature table and feature layer for the facilities or incidents.
122169 final featureTable = ServiceFeatureTable .withUri (tableUri);
123- final featureLayer = FeatureLayer . withFeatureTable (featureTable);
124- final markerSymbol = PictureMarkerSymbol . withUrl (imageUri);
125- markerSymbol.width = 30 ;
126- markerSymbol.height = 30 ;
127- featureLayer .renderer = SimpleRenderer (symbol: markerSymbol);
170+ final markerSymbol = PictureMarkerSymbol . withUrl (imageUri)
171+ ..width = 30
172+ ..height = 30 ;
173+ final featureLayer = FeatureLayer . withFeatureTable (featureTable)
174+ . .renderer = SimpleRenderer (symbol: markerSymbol);
128175
129176 return featureLayer;
130177 }
131178
132179 Future <ClosestFacilityParameters > generateClosestFacilityParameters (
133- FeatureLayer facilitiesLayer, FeatureLayer incidentsLayer) async {
180+ FeatureTable facilitiesFeatureTable,
181+ FeatureTable incidentsFeatureTable) async {
182+ // Create query parameters to get all features.
134183 final featureQueryParams = QueryParameters ()..whereClause = '1=1' ;
135-
136- final parameters = await _closestFacilityTask.createDefaultParameters ();
137- parameters .setFacilitiesWithFeatureTable (
138- featureTable: facilitiesLayer.featureTable ! as ArcGISFeatureTable ,
139- queryParameters: featureQueryParams,
140- );
141- parameters .setIncidentsWithFeatureTable (
142- featureTable: incidentsLayer.featureTable ! as ArcGISFeatureTable ,
143- queryParameters: featureQueryParams,
144- );
184+ // Create default parameters for the closest facility task.
185+ final parameters = await _closestFacilityTask.createDefaultParameters ()
186+ . .setFacilitiesWithFeatureTable (
187+ featureTable: facilitiesFeatureTable as ArcGISFeatureTable ,
188+ queryParameters: featureQueryParams,
189+ )
190+ . .setIncidentsWithFeatureTable (
191+ featureTable: incidentsFeatureTable as ArcGISFeatureTable ,
192+ queryParameters: featureQueryParams,
193+ );
145194
146195 return parameters;
147196 }
148197
149- Future < void > solveRoutes () async {
150- final results = await _closestFacilityTask. solveClosestFacility (
151- closestFacilityParameters : _closestFacilityParameters,
152- );
153-
198+ void solveRoutes () async {
199+ setState (() => _ready = false );
200+ // Solve the closest facility task with the parameters.
201+ final result = await _closestFacilityTask. solveClosestFacility (
202+ closestFacilityParameters : _closestFacilityParameters);
154203 for (var incidentIdx = 0 ;
155- incidentIdx < results .incidents.length;
204+ incidentIdx < result .incidents.length;
156205 ++ incidentIdx) {
157206 final rankedFacilities =
158- results .getRankedFacilityIndexes (incidentIndex: incidentIdx);
207+ result .getRankedFacilityIndexes (incidentIndex: incidentIdx);
159208 if (rankedFacilities.isEmpty) {
160209 continue ;
161210 }
162211
212+ // Get the route to the closest facility.
163213 final closestFacilityIdx = rankedFacilities.first;
164- final routeToFacility = results .getRoute (
214+ final routeToFacility = result .getRoute (
165215 facilityIndex: closestFacilityIdx,
166216 incidentIndex: incidentIdx,
167217 );
218+ // Add the route to the graphics overlay.
168219 if (routeToFacility != null ) {
169220 final routeGraphic = Graphic (
170- geometry: routeToFacility.routeGeometry,
171- symbol: _routeLineSymbol,
172- );
221+ geometry: routeToFacility.routeGeometry, symbol: _routeLineSymbol);
173222 _routeGraphicsOverlay.graphics.add (routeGraphic);
174223 }
175224 }
176- setState (() => _isRouteSolved = true );
225+
226+ // Set the route solved flag to true.
227+ setState (() {
228+ _ready = true ;
229+ _routeSolved = true ;
230+ });
177231 }
178232
179233 void resetRoutes () {
234+ // Clear the graphics overlay and set the route solved flag to false.
180235 _routeGraphicsOverlay.graphics.clear ();
181- setState (() => _isRouteSolved = false );
236+ setState (() => _routeSolved = false );
182237 }
183238}
0 commit comments