Skip to content

Commit

Permalink
Service area (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinr authored Oct 5, 2020
1 parent 8f52dfb commit 50c602a
Show file tree
Hide file tree
Showing 5 changed files with 9,632 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/arcgis-rest-routing/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export const ARCGIS_ONLINE_ROUTING_URL =
"https://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World";
export const ARCGIS_ONLINE_CLOSEST_FACILITY_URL =
"https://route.arcgis.com/arcgis/rest/services/World/ClosestFacility/NAServer/ClosestFacility_World/";
export const ARCGIS_ONLINE_SERVICE_AREA_URL =
"https://route.arcgis.com/arcgis/rest/services/World/ServiceAreas/NAServer/ServiceArea_World";

// nice to have: verify custom endpoints contain 'NAServer' and end in a '/'
export interface IEndpointOptions extends IRequestOptions {
Expand Down
1 change: 1 addition & 0 deletions packages/arcgis-rest-routing/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

export * from "./solveRoute";
export * from "./closestFacility";
export * from "./serviceArea";
export * from "./helpers";
export {
ILocation,
Expand Down
163 changes: 163 additions & 0 deletions packages/arcgis-rest-routing/src/serviceArea.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* Copyright (c) 2018 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import {
request,
cleanUrl,
appendCustomParams,
} from "@esri/arcgis-rest-request";

import {
ILocation,
IPoint,
IFeature,
IFeatureSet,
} from "@esri/arcgis-rest-types";

import {
ARCGIS_ONLINE_SERVICE_AREA_URL,
IEndpointOptions,
normalizeLocationsList,
} from "./helpers";

import { arcgisToGeoJSON } from "@terraformer/arcgis";

export interface IServiceAreaOptions extends IEndpointOptions {
/**
* Specify one or more locations around which service areas are generated.
*/
facilities: Array<IPoint | ILocation | [number, number]>;
/**
* Specify if the service should return routes.
*/
travelDirection?: "incidentsToFacilities" | "facilitiesToIncidents";
barriers?: Array<IPoint | ILocation | [number, number]>;
polylineBarriers?: IFeatureSet;
polygonBarriers?: IFeatureSet;
outputLines?: boolean;
returnFacilities?: boolean;
returnBarriers?: boolean;
returnPolylineBarriers?: boolean;
returnPolygonBarriers?: boolean;
preserveObjectID?: boolean;
}

interface IFeatureSetWithGeoJson extends IFeatureSet {
geoJson?: any;
}

export interface IServiceAreaResponse {
messages: string[];
saPolygons?: IFeatureSetWithGeoJson;
incidents?: IFeatureSet;
facilities?: IFeatureSet;
barriers?: IFeatureSet;
polygonBarriers?: IFeatureSet;
polylineBarriers?: IFeatureSet;
}

function getTravelDirection(
key: "incidentsToFacilities" | "facilitiesToIncidents"
): "esriNATravelDirectionFromFacility" | "esriNATravelDirectionToFacility" {
if (key === "incidentsToFacilities") {
return "esriNATravelDirectionFromFacility";
} else {
return "esriNATravelDirectionToFacility";
}
}

/**
* ```js
* import { serviceArea } from '@esri/arcgis-rest-routing';
* //
* serviceArea({
* facilities: [
* [-90.444716, 38.635501],
* [-90.311919, 38.633523],
* [-90.451147, 38.581107]
* ],
* authentication
* })
* .then(response) // => {routes: {features: [{attributes: { ... }, geometry:{ ... }}]}
* ```
* Used to find the area that can be reached from the input location within a given travel time or travel distance. See the [REST Documentation](https://developers.arcgis.com/rest/network/api-reference/service-area-synchronous-service.htm) for more information.
*
* @param requestOptions Options to pass through to the routing service.
* @returns A Promise that will resolve with service area polygons for the request.
* @restlink https://developers.arcgis.com/rest/network/api-reference/service-area-synchronous-service.htm
*/
export function serviceArea(
requestOptions: IServiceAreaOptions
): Promise<IServiceAreaResponse> {
const endpoint =
requestOptions.endpoint || ARCGIS_ONLINE_SERVICE_AREA_URL;
const options = appendCustomParams<IServiceAreaOptions>(
requestOptions,
[
"barriers",
"polylineBarriers",
"polygonBarriers",
"outputLines",
"returnFacilities",
"returnBarriers",
"returnPolylineBarriers",
"returnPolygonBarriers",
"preserveObjectID",
],
{
params: {
returnFacilities: true,
returnBarriers: true,
returnPolylineBarriers: true,
returnPolygonBarriers: true,
preserveObjectID: true,
...requestOptions.params,
},
}
);

// Set travelDirection
if (requestOptions.travelDirection) {
options.params.travelDirection = getTravelDirection(
requestOptions.travelDirection
);
}

// the SAAS service does not support anonymous requests
if (
!requestOptions.authentication &&
endpoint === ARCGIS_ONLINE_SERVICE_AREA_URL
) {
return Promise.reject(
"Finding service areas using the ArcGIS service requires authentication"
);
}
options.params.facilities = normalizeLocationsList(
requestOptions.facilities
).join(";");

if (requestOptions.barriers) {
options.params.barriers = normalizeLocationsList(
requestOptions.barriers
).join(";");
}

return request(`${cleanUrl(endpoint)}/solveServiceArea`, options).then(
cleanResponse
);
}

function cleanResponse(res: any): IServiceAreaResponse {
// remove "fieldAliases" because it does not do anything.
delete res.saPolygons.fieldAliases;

// add "geoJson" property to "saPolygons"
if (res.saPolygons.spatialReference.wkid === 4326) {
res.saPolygons.geoJson = arcgisToGeoJSON(res.saPolygons);
}
return res;
}

export default {
serviceArea,
};
Loading

0 comments on commit 50c602a

Please sign in to comment.