关于 arcgis-spatial-analysis
面向 ArcGIS 开发者的空间分析技能,涵盖 3D 分析、要素统计查询与要素简化,并说明对象配置及常见 API 陷阱。
主要功能
- 01配置 3D 分析对象
- 02执行带统计的要素查询
- 03聚类要素并汇总字段
- 04配置要素分箱
- 05说明 API 陷阱及正确属性
适用场景
- 01构建可视域或高程分析
- 02测量 3D 面积、距离或体积
- 03按分组或空间范围汇总要素数据
- 04通过聚类或分箱简化密集要素
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ saschabrunnerch/ arcgis-maps-sdk-js-ai-context --skill arcgis-spatial-analysis安装后在 Claude Code 中输入/arcgis-spatial-analysis确认已加载。
详细介绍
ArcGIS 空间分析
将此技能用于空间分析对象(3D 分析)、带统计信息的要素查询,以及要素缩减(聚类/分箱)。
有关几何运算符(缓冲区、联合、相交、裁剪、偏移等),请参阅
arcgis-geometry-operations。 有关路由、地理编码和地理处理 REST 服务,请参阅arcgis-rest-services。
导入模式
直接 ESM 导入
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";
动态导入(CDN)
const [ViewshedAnalysis, Viewshed] = await $arcgis.import([
"@arcgis/core/analysis/ViewshedAnalysis.js",
"@arcgis/core/analysis/Viewshed.js",
]);
分析对象(3D)
分析对象会添加到 SceneView 的 analyses 集合中。所有分析类型都需要 SceneView(而不是 MapView)。
ElevationProfileAnalysis
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);
}
},
);
交互式放置分析
分析视图支持通过 place() 方法进行交互式放置:
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
使用由 Viewshed 对象组成的 viewsheds 集合(而不是直接设置观察者属性)。
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
使用 LineOfSightAnalysisObserver 和 LineOfSightAnalysisTarget 包装对象。
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
使用 date、startTimeOfDay、endTimeOfDay 和 mode 属性。
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
使用 SlicePlane 类型的 shape 属性(而不是 plane)。
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
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
使用 geometry 属性(Polyline),而不是 startPoint/endPoint。
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
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
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);
分析类型摘要
| 分析 | 用途 | 构造函数键 |
|---|---|---|
| ViewshedAnalysis | 观察者的可见区域 | viewsheds(Viewshed 集合) |
| LineOfSightAnalysis | 点之间的可见性 | observer、targets(包装对象) |
| ShadowCastAnalysis | 阴影可视化 | date、startTimeOfDay、endTimeOfDay、mode |
| SliceAnalysis | 3D 内容的横截面 | shape(SlicePlane) |
| ElevationProfileAnalysis | 沿线的地形剖面 | profiles、geometry(Polyline) |
| AreaMeasurementAnalysis | 3D 面积测量 | geometry(Polygon) |
| DistanceMeasurementAnalysis | 3D 距离测量 | geometry(Polyline) |
| VolumeMeasurementAnalysis | 挖填方体积 | geometry(Polygon) |
| DimensionAnalysis | 3D 长度尺寸 | dimensions(LengthDimension[]) |
带统计信息的要素查询
基本统计
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);
分组统计
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
空间统计
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);
要素缩减
聚类
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
带聚合字段的聚类
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 },
],
},
],
},
};
分箱
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;
常见问题
-
分析对象仅适用于 SceneView:所有分析类型(视域、视线、阴影投射等)都需要 3D SceneView,无法在 MapView 中使用。
-
ViewshedAnalysis 使用 viewsheds 集合:不要在 ViewshedAnalysis 上直接设置
observer。请创建Viewshed对象,并将其添加到viewsheds集合中:// Anti-pattern new ViewshedAnalysis({ observer: point, farDistance: 1000 }); // Correct new ViewshedAnalysis({ viewsheds: [new Viewshed({ observer: point, farDistance: 1000 })], }); -
聚类字段名称:在聚类弹出窗口和标注中,使用
cluster_count(而不是clusterCount)获取要素数量。 -
统计查询返回要素:统计查询返回带有计算所得属性的要素,而不是原始数值。通过
result.features[0].attributes访问结果。 -
分析进度:检查
analysisView.progress === 1或监视analysisView.result,以确定分析结果何时就绪。请勿在结果计算完成前读取结果。 -
SliceAnalysis 使用
shape,而不是plane:该属性是SlicePlane类型的shape,而不是plane:// Anti-pattern new SliceAnalysis({ plane: slicePlane }); // Correct new SliceAnalysis({ shape: slicePlane });
参考示例
analysis-viewshed- 3D 交互式视域分析analysis-objects- 在单个场景中使用多种分析类型analysis-elevation-profile- 沿线生成高程剖面analysis-shadow-cast- 阴影投射时长可视化analysis-area-measurement- 测量 3D 表面上的面积analysis-volume-measurement- 挖填方体积测量line-of-sight- 视线可见性分析featurereduction-cluster- 要素聚类featurereduction-binning- 对要素分箱以进行聚合featurereduction-cluster-aggregate-fields- 包含聚合统计信息的聚类
相关技能
- 有关客户端几何操作(缓冲区、合并、相交等),请参阅
arcgis-geometry-operations。 - 有关服务器端 REST 服务(路径规划、地理编码、地理处理),请参阅
arcgis-rest-services。 - 有关坐标投影和格式化,请参阅
arcgis-coordinates-projection。 - 有关 FeatureLayer 查询和图层配置,请参阅
arcgis-layers。