saschabrunnerch/arcgis-maps-sdk-js-ai-context

arcgis-spatial-analysis

Perform spatial analysis using analysis objects, REST services for routing/geocoding/geoprocessing, and feature reduction with clustering/binning.

Voir la source

Mode d’emploi

  1. Copiez la commande et examinez le paquet avant de l’installer dans votre environnement agent.
  2. Consultez le document original pour les outils, identifiants et environnements requis.
  3. Décrivez les entrées et le livrable souhaité ; comparez la sortie aux sources.
npx skills add https://github.com/saschabrunnerch/arcgis-maps-sdk-js-ai-context --skill arcgis-spatial-analysis

Avant de commencer

  • L’installation n’inclut ni abonnement au modèle, ni quota API, ni accès aux fichiers.
  • Étoiles et installations reflètent l’activité, pas un test indépendant de qualité ou de sécurité.
Document Skill original

Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.

ArcGIS Spatial Analysis

Use this skill for spatial analysis objects (3D analyses), feature queries with statistics, and feature reduction (clustering/binning).

For geometry operators (buffer, union, intersect, clip, offset, etc.), see arcgis-geometry-operations. For routing, geocoding, and geoprocessing REST services, see arcgis-rest-services.

Import Patterns

Direct ESM Imports

javascript
import ViewshedAnalysis from "@arcgis/core/analysis/ViewshedAnalysis.js";
import Viewshed from "@arcgis/core/analysis/Viewshed.js";
import LineOfSightAnalysis from "@arcgis/core/analysis/LineOfSightAnalysis.js";
import ElevationProfileAnalysis from "@arcgis/core/analysis/ElevationProfileAnalysis.js";
import SliceAnalysis from "@arcgis/core/analysis/SliceAnalysis.js";
import ShadowCastAnalysis from "@arcgis/core/analysis/ShadowCastAnalysis.js";

Dynamic Imports (CDN)

javascript
const [ViewshedAnalysis, Viewshed] = await $arcgis.import([
  "@arcgis/core/analysis/ViewshedAnalysis.js",
  "@arcgis/core/analysis/Viewshed.js",
]);

Analysis Objects (3D)

Analysis objects are added to a SceneView's analyses collection. All analysis types require SceneView (not MapView).

ElevationProfileAnalysis

javascript
import ElevationProfileAnalysis from "@arcgis/core/analysis/ElevationProfileAnalysis.js";
import * as reactiveUtils from "@arcgis/core/core/reactiveUtils.js";

const analysis = new ElevationProfileAnalysis({
  profiles: [
    { type: "ground", color: "brown" },
    { type: "input", color: "blue" },
  ],
  displayUnits: {
    distance: "meters",
    elevation: "meters",
  },
});

view.analyses.add(analysis);
analysis.geometry = polyline;

// Get analysis view for results
const analysisView = await view.whenAnalysisView(analysis);

reactiveUtils.watch(
  () => analysisView.progress,
  (progress) => {
    if (progress === 1) {
      console.log("Results:", analysisView.results);
    }
  },
);

Interactive Analysis Placement

Analysis views support interactive placement via the place() method:

javascript
import * as promiseUtils from "@arcgis/core/core/promiseUtils.js";

const analysisView = await view.whenAnalysisView(analysis);
const abortController = new AbortController();

try {
  await analysisView.place({ signal: abortController.signal });
} catch (error) {
  if (!promiseUtils.isAbortError(error)) throw error;
}

// To cancel placement
abortController.abort();

ViewshedAnalysis

Uses a viewsheds collection of Viewshed objects (not direct observer property).

javascript
import ViewshedAnalysis from "@arcgis/core/analysis/ViewshedAnalysis.js";
import Viewshed from "@arcgis/core/analysis/Viewshed.js";

const viewshed = new Viewshed({
  observer: {
    type: "point",
    x: -122.4,
    y: 37.8,
    z: 100,
    spatialReference: { wkid: 4326 },
  },
  farDistance: 1000,
  heading: 45,
  tilt: 90,
  horizontalFieldOfView: 120,
  verticalFieldOfView: 90,
});

const analysis = new ViewshedAnalysis({
  viewsheds: [viewshed],
});

view.analyses.add(analysis);

// Add more viewsheds dynamically
analysis.viewsheds.add(
  new Viewshed({
    observer: {
      type: "point",
      x: -122.41,
      y: 37.79,
      z: 80,
      spatialReference: { wkid: 4326 },
    },
    farDistance: 500,
    heading: 0,
    tilt: 90,
    horizontalFieldOfView: 360,
    verticalFieldOfView: 90,
  }),
);

// Clear all viewsheds
analysis.clear();

LineOfSightAnalysis

Uses LineOfSightAnalysisObserver and LineOfSightAnalysisTarget wrapper objects.

javascript
import LineOfSightAnalysis from "@arcgis/core/analysis/LineOfSightAnalysis.js";
import LineOfSightAnalysisObserver from "@arcgis/core/analysis/LineOfSightAnalysisObserver.js";
import LineOfSightAnalysisTarget from "@arcgis/core/analysis/LineOfSightAnalysisTarget.js";

const analysis = new LineOfSightAnalysis({
  observer: new LineOfSightAnalysisObserver({
    position: {
      type: "point",
      x: -122.4,
      y: 37.8,
      z: 100,
      spatialReference: { wkid: 4326 },
    },
  }),
  targets: [
    new LineOfSightAnalysisTarget({
      position: {
        type: "point",
        x: -122.41,
        y: 37.81,
        z: 50,
        spatialReference: { wkid: 4326 },
      },
    }),
    new LineOfSightAnalysisTarget({
      position: {
        type: "point",
        x: -122.42,
        y: 37.79,
        z: 75,
        spatialReference: { wkid: 4326 },
      },
    }),
  ],
});

view.analyses.add(analysis);

ShadowCastAnalysis

Uses date, startTimeOfDay, endTimeOfDay, and mode properties.

javascript
import ShadowCastAnalysis from "@arcgis/core/analysis/ShadowCastAnalysis.js";

const analysis = new ShadowCastAnalysis({
  date: new Date("2025-06-21"),
  startTimeOfDay: 21600000, // 6:00 AM (milliseconds from midnight)
  endTimeOfDay: 57600000, // 4:00 PM
  mode: "total-duration", // "total-duration", "discrete", "min-duration"
  utcOffset: -7, // UTC offset in hours
});

view.analyses.add(analysis);

SliceAnalysis

Uses a shape property of type SlicePlane (not plane).

javascript
import SliceAnalysis from "@arcgis/core/analysis/SliceAnalysis.js";
import SlicePlane from "@arcgis/core/analysis/SlicePlane.js";

const analysis = new SliceAnalysis({
  shape: new SlicePlane({
    position: {
      type: "point",
      x: -122.4,
      y: 37.8,
      z: 50,
      spatialReference: { wkid: 4326 },
    },
    heading: 0,
    tilt: 0,
    width: 200,
    height: 200,
  }),
  tiltEnabled: false,
  excludeGroundSurface: false,
});

view.analyses.add(analysis);

AreaMeasurementAnalysis

javascript
import AreaMeasurementAnalysis from "@arcgis/core/analysis/AreaMeasurementAnalysis.js";

const analysis = new AreaMeasurementAnalysis();
view.analyses.add(analysis);

// Set geometry after user draws or programmatically
analysis.geometry = polygon;

// Watch for results
const analysisView = await view.whenAnalysisView(analysis);
reactiveUtils.watch(
  () => analysisView.result,
  (result) => {
    if (result) {
      console.log("Area:", result.area?.value, result.area?.unit);
      console.log(
        "Perimeter:",
        result.perimeterLength?.value,
        result.perimeterLength?.unit,
      );
    }
  },
  { initial: true },
);

DistanceMeasurementAnalysis

Uses a geometry property (Polyline), not startPoint/endPoint.

javascript
import DistanceMeasurementAnalysis from "@arcgis/core/analysis/DistanceMeasurementAnalysis.js";

const analysis = new DistanceMeasurementAnalysis({
  geometry: {
    type: "polyline",
    paths: [
      [
        [-122.4, 37.8, 0],
        [-122.41, 37.81, 0],
      ],
    ],
    spatialReference: { wkid: 4326 },
  },
});

view.analyses.add(analysis);

VolumeMeasurementAnalysis

javascript
import VolumeMeasurementAnalysis from "@arcgis/core/analysis/VolumeMeasurementAnalysis.js";

const analysis = new VolumeMeasurementAnalysis();
view.analyses.add(analysis);

analysis.geometry = polygon;

// Watch for results
const analysisView = await view.whenAnalysisView(analysis);
reactiveUtils.watch(
  () => analysisView.result,
  (result) => {
    if (result) {
      console.log(
        "Cut volume:",
        result.cutVolume?.value,
        result.cutVolume?.unit,
      );
      console.log(
        "Fill volume:",
        result.fillVolume?.value,
        result.fillVolume?.unit,
      );
    }
  },
  { initial: true },
);

DimensionAnalysis

javascript
import DimensionAnalysis from "@arcgis/core/analysis/DimensionAnalysis.js";
import LengthDimension from "@arcgis/core/analysis/LengthDimension.js";

const dimension = new LengthDimension({
  startPoint: {
    type: "point",
    x: -122.4,
    y: 37.8,
    z: 0,
    spatialReference: { wkid: 4326 },
  },
  endPoint: {
    type: "point",
    x: -122.41,
    y: 37.81,
    z: 0,
    spatialReference: { wkid: 4326 },
  },
});

const analysis = new DimensionAnalysis({
  dimensions: [dimension],
});

view.analyses.add(analysis);

Analysis Types Summary

AnalysisUse CaseConstructor Key
ViewshedAnalysisVisible area from observerviewsheds (Collection of Viewshed)
LineOfSightAnalysisVisibility between pointsobserver, targets (wrapper objects)
ShadowCastAnalysisShadow visualizationdate, startTimeOfDay, endTimeOfDay, mode
SliceAnalysisCross-section of 3D contentshape (SlicePlane)
ElevationProfileAnalysisTerrain profile along a lineprofiles, geometry (Polyline)
AreaMeasurementAnalysis3D area measurementgeometry (Polygon)
DistanceMeasurementAnalysis3D distance measurementgeometry (Polyline)
VolumeMeasurementAnalysisCut/fill volumegeometry (Polygon)
DimensionAnalysisLength dimensions in 3Ddimensions (LengthDimension[])

Feature Queries with Statistics

Basic Statistics

javascript
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

javascript
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

javascript
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

javascript
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

javascript
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

javascript
const binConfig = {
  type: "binning",
  fixedBinLevel: 4,
  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;

Common Pitfalls

  1. Analysis objects are SceneView-only: All analysis types (viewshed, line of sight, shadow cast, etc.) require 3D SceneView. They do not work in MapView.
  1. ViewshedAnalysis uses a viewsheds collection: Do not set observer directly on ViewshedAnalysis. Create Viewshed objects and add them to the viewsheds collection:
javascript
   // Anti-pattern
   new ViewshedAnalysis({ observer: point, farDistance: 1000 });

   // Correct
   new ViewshedAnalysis({
     viewsheds: [new Viewshed({ observer: point, farDistance: 1000 })],
   });
  1. Cluster field names: Use cluster_count (not clusterCount) to access the feature count in cluster popups and labels.
  1. Statistics queries return features: Statistics queries return features with calculated attributes, not raw numbers. Access results via result.features[0].attributes.
  1. Analysis progress: Check analysisView.progress === 1 or watch analysisView.result to know when analysis results are ready. Don't read results before they're computed.
  1. SliceAnalysis uses `shape` not `plane`: The property is shape of type SlicePlane, not plane:
javascript
   // Anti-pattern
   new SliceAnalysis({ plane: slicePlane });

   // Correct
   new SliceAnalysis({ shape: slicePlane });

Reference Samples

  • analysis-viewshed - Interactive viewshed analysis in 3D
  • analysis-objects - Multiple analysis types in a single scene
  • analysis-elevation-profile - Elevation profile along a line
  • analysis-shadow-cast - Shadow cast duration visualization
  • analysis-area-measurement - Area measurement on 3D surfaces
  • analysis-volume-measurement - Cut/fill volume measurement
  • line-of-sight - Line of sight visibility analysis
  • featurereduction-cluster - Feature clustering
  • featurereduction-binning - Feature binning for aggregation
  • featurereduction-cluster-aggregate-fields - Clusters with aggregated statistics

Related Skills

  • See arcgis-geometry-operations for client-side geometry operations (buffer, union, intersect, etc.).
  • See arcgis-rest-services for server-side REST services (routing, geocoding, geoprocessing).
  • See arcgis-coordinates-projection for coordinate projection and formatting.
  • See arcgis-layers for FeatureLayer queries and layer configuration.

Tâches connexes

du même dépôt

Autres Skills

Tous les Skills