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.

소스 보기

사용 방법

  1. 설치 명령을 복사하고 자신의 에이전트 환경에 설치하기 전에 소스 패키지를 확인하세요.
  2. 필요한 도구, 인증 정보, 지원 환경은 원본 문서에서 확인하세요.
  3. 입력과 원하는 산출물을 설명하고 출처와 결과를 대조하세요.
npx skills add https://github.com/saschabrunnerch/arcgis-maps-sdk-js-ai-context --skill arcgis-spatial-analysis

시작 전 확인

  • 설치에는 모델 구독, API 한도, 파일 접근 권한이 포함되지 않습니다.
  • 별점 수와 설치 수는 활동 지표이며 독립적인 품질·보안 검증이 아닙니다.
원본 Skill 문서

원본 저장소의 제목, 예시, 코드, 표, 링크, 이미지를 유지해 표시합니다.

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.

관련 작업

같은 저장소의 Skills

더 많은 Skills

모든 Skills