ArcGIS Analysis & Services
Use this skill for spatial analysis, geometry operations, REST services, and feature reduction (clustering/binning).
Geometry Operators
ArcGIS Maps SDK provides geometry operators for client-side spatial operations.
Loading Operators
import bufferOperator from "@arcgis/core/geometry/operators/bufferOperator.js"; import intersectOperator from "@arcgis/core/geometry/operators/intersectOperator.js"; import centroidOperator from "@arcgis/core/geometry/operators/centroidOperator.js";
// Load before use (most operators require this) await bufferOperator.load();
Buffer
import bufferOperator from "@arcgis/core/geometry/operators/bufferOperator.js"; await bufferOperator.load();
const buffered = bufferOperator.execute(point, 1000); // 1000 meters
Geodesic Buffer (accurate over large distances)
import geodesicBufferOperator from "@arcgis/core/geometry/operators/geodesicBufferOperator.js"; await geodesicBufferOperator.load();
const buffered = geodesicBufferOperator.execute(point, { distances: [100], unit: "kilometers" });
Intersect
import intersectOperator from "@arcgis/core/geometry/operators/intersectOperator.js"; await intersectOperator.load();
const intersection = intersectOperator.execute(geometry1, geometry2);
Union
import unionOperator from "@arcgis/core/geometry/operators/unionOperator.js"; await unionOperator.load();
const unioned = unionOperator.execute([polygon1, polygon2, polygon3]);
Centroid
import centroidOperator from "@arcgis/core/geometry/operators/centroidOperator.js"; await centroidOperator.load();
const centroid = centroidOperator.execute(polygon);
Contains / Within
import containsOperator from "@arcgis/core/geometry/operators/containsOperator.js"; await containsOperator.load();
const isContained = containsOperator.execute(polygon, point); // true/false
Distance
import geodeticLengthOperator from "@arcgis/core/geometry/operators/geodeticLengthOperator.js"; await geodeticLengthOperator.load();
const length = geodeticLengthOperator.execute(polyline, { unit: "miles" });
Area
import geodeticAreaOperator from "@arcgis/core/geometry/operators/geodeticAreaOperator.js"; await geodeticAreaOperator.load();
const area = geodeticAreaOperator.execute(polygon, { unit: "square-kilometers" });
Available Operators
Operator Purpose
bufferOperator
Create buffer around geometry
geodesicBufferOperator
Geodetic buffer (accurate)
intersectOperator
Find intersection
unionOperator
Combine geometries
differenceOperator
Subtract geometries
clipOperator
Clip geometry by envelope
convexHullOperator
Create convex hull
centroidOperator
Get centroid point
containsOperator
Test if contains
withinOperator
Test if within
intersectsOperator
Test if intersects
distanceOperator
Calculate planar distance
geodeticLengthOperator
Calculate geodetic length
geodeticAreaOperator
Calculate geodetic area
simplifyOperator
Simplify geometry
densifyOperator
Add vertices to geometry
projectOperator
Project to spatial reference
Analysis Objects
ElevationProfileAnalysis
import ElevationProfileAnalysis from "@arcgis/core/analysis/ElevationProfileAnalysis.js";
const analysis = new ElevationProfileAnalysis({ profiles: [ { type: "ground", color: "brown" }, { type: "input", color: "blue" } ], displayUnits: { distance: "meters", elevation: "meters" } });
// Add to SceneView view.analyses.add(analysis);
// Set line geometry analysis.geometry = polyline;
// Get analysis view for results const analysisView = await view.whenAnalysisView(analysis);
// Watch progress and results reactiveUtils.watch( () => analysisView.progress, (progress) => { if (progress === 1) { console.log("Results:", analysisView.results); } } );
LineOfSightAnalysis
import LineOfSightAnalysis from "@arcgis/core/analysis/LineOfSightAnalysis.js";
const analysis = new LineOfSightAnalysis({ observer: { type: "point", x: -122.4, y: 37.8, z: 100, spatialReference: { wkid: 4326 } }, targets: [ { type: "point", x: -122.41, y: 37.81, z: 50 }, { type: "point", x: -122.42, y: 37.79, z: 75 } ] });
view.analyses.add(analysis);
ViewshedAnalysis
import ViewshedAnalysis from "@arcgis/core/analysis/ViewshedAnalysis.js";
const analysis = new ViewshedAnalysis({ observer: { type: "point", x: -122.4, y: 37.8, z: 100, spatialReference: { wkid: 4326 } }, farDistance: 1000, heading: 45, tilt: 90, horizontalFieldOfView: 120, verticalFieldOfView: 90 });
view.analyses.add(analysis);
ShadowCastAnalysis
import ShadowCastAnalysis from "@arcgis/core/analysis/ShadowCastAnalysis.js";
const analysis = new ShadowCastAnalysis(); view.analyses.add(analysis);
// Configure date/time for shadow calculation view.environment.lighting.date = new Date("2024-06-21T12:00:00");
SliceAnalysis
import SliceAnalysis from "@arcgis/core/analysis/SliceAnalysis.js";
const analysis = new SliceAnalysis({ plane: { position: { type: "point", x: -122.4, y: 37.8, z: 50 }, heading: 0, tilt: 0 } });
view.analyses.add(analysis);
REST Services
Routing
import route from "@arcgis/core/rest/route.js";
const routeParams = { stops: [ { geometry: { x: -122.4, y: 37.8 } }, { geometry: { x: -122.5, y: 37.7 } } ], outSpatialReference: { wkid: 4326 }, returnDirections: true, returnRoutes: true };
const result = await route.solve( "https://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World", routeParams );
const routeGeometry = result.routeResults[0].route.geometry; const directions = result.routeResults[0].directions;
Geocoding (Address to Location)
import locator from "@arcgis/core/rest/locator.js";
const results = await locator.addressToLocations( "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer", { address: { SingleLine: "380 New York St, Redlands, CA" }, outFields: ["*"], maxLocations: 5 } );
results.forEach(result => { console.log(result.address, result.location); });
Reverse Geocoding (Location to Address)
import locator from "@arcgis/core/rest/locator.js";
const result = await locator.locationToAddress( "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer", { location: { x: -117.195, y: 34.057 } } );
console.log(result.address);
Geoprocessing
import geoprocessor from "@arcgis/core/rest/geoprocessor.js";
const params = { inputLayer: featureSet, distance: 1000, distanceUnits: "Meters" };
const result = await geoprocessor.execute( "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Buffer/GPServer/Buffer", params );
const outputFeatures = result.results[0].value;
import print from "@arcgis/core/rest/print.js";
const params = { view: view, template: { format: "pdf", layout: "letter-ansi-a-landscape", layoutOptions: { titleText: "My Map" } } };
const result = await print.execute( "https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task", params );
// Download the PDF window.open(result.url);
Places Service
import places from "@arcgis/core/rest/places.js"; import PlacesQueryParameters from "@arcgis/core/rest/support/PlacesQueryParameters.js"; import FetchPlaceParameters from "@arcgis/core/rest/support/FetchPlaceParameters.js";
// Query places near a point const queryParams = new PlacesQueryParameters({ categoryIds: ["4d4b7104d754a06370d81259"], // Arts and Entertainment radius: 500, // meters point: { type: "point", longitude: -87.626, latitude: 41.882 }, icon: "png" });
const results = await places.queryPlacesNearPoint(queryParams);
// Process results results.results.forEach(place => { console.log(place.name, place.location, place.categories[0].label); console.log("Distance:", place.distance / 1000, "km"); });
// Fetch detailed information about a place const fetchParams = new FetchPlaceParameters({ placeId: results.results[0].placeId, requestedFields: ["all"] });
const details = await places.fetchPlace(fetchParams); const placeDetails = details.placeDetails;
console.log("Address:", placeDetails.address.streetAddress); console.log("Phone:", placeDetails.contactInfo.telephone); console.log("Website:", placeDetails.contactInfo.website);
Places Category IDs
Category ID
Arts and Entertainment 4d4b7104d754a06370d81259
Business Services 4d4b7105d754a06375d81259
Community and Government 63be6904847c3692a84b9b9a
Dining and Drinking 63be6904847c3692a84b9bb5
Health and Medicine 63be6904847c3692a84b9bb9
Landmarks and Outdoors 4d4b7105d754a06377d81259
Retail 4d4b7105d754a06378d81259
Sports and Recreation 4f4528bc4b90abdf24c9de85
Travel and Transportation 4d4b7105d754a06379d81259
Feature Queries with Statistics
Basic Statistics
const query = featureLayer.createQuery(); query.outStatistics = [ { statisticType: "sum", onStatisticField: "population", outStatisticFieldName: "totalPop" }, { statisticType: "avg", onStatisticField: "population", outStatisticFieldName: "avgPop" }, { statisticType: "max", onStatisticField: "population", outStatisticFieldName: "maxPop" }, { statisticType: "min", onStatisticField: "population", outStatisticFieldName: "minPop" }, { statisticType: "count", onStatisticField: "population", outStatisticFieldName: "count" }, { statisticType: "stddev", onStatisticField: "population", outStatisticFieldName: "stdDev" } ];
const result = await featureLayer.queryFeatures(query); console.log(result.features[0].attributes);
Group By Statistics
const query = featureLayer.createQuery(); query.groupByFieldsForStatistics = ["state"]; query.outStatistics = [{ statisticType: "sum", onStatisticField: "population", outStatisticFieldName: "totalPop" }]; query.orderByFields = ["totalPop DESC"];
const result = await featureLayer.queryFeatures(query); // Returns one feature per state with total population
Spatial Statistics Query
const query = featureLayer.createQuery(); query.geometry = view.extent; query.spatialRelationship = "intersects"; query.outStatistics = [{ statisticType: "count", onStatisticField: "ObjectID", outStatisticFieldName: "featureCount" }];
const result = await featureLayer.queryFeatures(query); console.log("Features in view:", result.features[0].attributes.featureCount);
Feature Reduction
Clustering
const clusterConfig = { type: "cluster", clusterRadius: "100px", clusterMinSize: "24px", clusterMaxSize: "60px", popupTemplate: { title: "Cluster summary", content: "This cluster represents {cluster_count} features.", fieldInfos: [{ fieldName: "cluster_count", format: { digitSeparator: true, places: 0 } }] }, labelingInfo: [{ deconflictionStrategy: "none", labelExpressionInfo: { expression: "Text($feature.cluster_count, '#,###')" }, symbol: { type: "text", color: "white", font: { size: "12px", weight: "bold" } }, labelPlacement: "center-center" }] };
featureLayer.featureReduction = clusterConfig;
// Toggle clustering featureLayer.featureReduction = null; // Disable featureLayer.featureReduction = clusterConfig; // Enable
Cluster with Aggregated Fields
const clusterConfig = { type: "cluster", clusterRadius: "100px", fields: [{ name: "avg_magnitude", statisticType: "avg", onStatisticField: "magnitude" }, { name: "total_count", statisticType: "count", onStatisticField: "ObjectID" }], renderer: { type: "simple", symbol: { type: "simple-marker", style: "circle", color: "#69dcff" }, visualVariables: [{ type: "size", field: "total_count", stops: [ { value: 1, size: 8 }, { value: 100, size: 40 } ] }] } };
Binning
const binConfig = { type: "binning", fixedBinLevel: 4, // Level of detail renderer: { type: "simple", symbol: { type: "simple-fill", outline: { color: "white", width: 0.5 } }, visualVariables: [{ type: "color", field: "aggregateCount", stops: [ { value: 1, color: "#feebe2" }, { value: 50, color: "#fbb4b9" }, { value: 100, color: "#f768a1" }, { value: 500, color: "#c51b8a" }, { value: 1000, color: "#7a0177" } ] }] }, popupTemplate: { title: "Bin", content: "{aggregateCount} features in this bin" } };
featureLayer.featureReduction = binConfig;
Projection
import projectOperator from "@arcgis/core/geometry/operators/projectOperator.js"; await projectOperator.load();
// Project to Web Mercator const projected = projectOperator.execute(geometry, { wkid: 3857 });
// Project to WGS 84 const wgs84 = projectOperator.execute(geometry, { wkid: 4326 });
TypeScript Usage
Feature reduction configurations use autocasting with type properties. For TypeScript safety, use as const :
// Use 'as const' for type safety const clusterConfig = { type: "cluster", clusterRadius: "100px", renderer: { type: "simple", symbol: { type: "simple-marker", color: "#69dcff" } } as const, labelingInfo: [{ labelExpressionInfo: { expression: "Text($feature.cluster_count, '#,###')" }, symbol: { type: "text", color: "white" } as const }] } as const;
featureLayer.featureReduction = clusterConfig;
Tip: See arcgis-core-maps skill for detailed guidance on autocasting vs explicit classes.
Common Pitfalls
Operator not loaded: Most operators require await operator.load() before use
API key required: Some REST services (routing, geocoding) require an API key
Analysis only in SceneView: Some analyses (viewshed, line of sight) only work in 3D
Cluster fields: Use cluster_count to access feature count in clusters
Statistics query returns features: Statistics queries return features with calculated attributes, not raw numbers