mcpField
A
arcgis-map-tools

arcgis-map-tools

github.com/saschabrunnerch开发2365 次安装29 周前更新
代码仓库

关于 arcgis-map-tools

arcgis-map-tools 是面向 ArcGIS Maps SDK for JavaScript 的开发技能,提供地图界面实现指引与代码模式,涵盖常见交互、测量、路线和导出功能。

主要功能

  1. 01图层滑动对比
  2. 022D 和 3D 距离与面积测量
  3. 03坐标转换与书签
  4. 04路线指引和编程式路线计算
  5. 05地图打印与截图导出
  6. 06高程剖面与要素识别

适用场景

  1. 01交互式比较两个地图图层
  2. 02为地图添加测量和坐标工具
  3. 03提供路线指引并检查地图要素
  4. 04导出地图用于报告或分享

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/saschabrunnerch/arcgis-maps-sdk-js-ai-context --skill arcgis-map-tools

安装后在 Claude Code 中输入/arcgis-map-tools确认已加载。

详细介绍

ArcGIS 地图工具

使用此技能进行卷帘对比、测量、坐标转换、书签、打印、路径规划和识别操作。

导入模式

直接 ESM 导入
import Measurement from "@arcgis/core/widgets/Measurement.js";
import DistanceMeasurement2D from "@arcgis/core/widgets/DistanceMeasurement2D.js";
import AreaMeasurement2D from "@arcgis/core/widgets/AreaMeasurement2D.js";
import Print from "@arcgis/core/widgets/Print.js";
import Directions from "@arcgis/core/widgets/Directions.js";
import * as route from "@arcgis/core/rest/route.js";
import * as identify from "@arcgis/core/rest/identify.js";
import * as print from "@arcgis/core/rest/print.js";
动态导入(CDN)
const Measurement = await $arcgis.import("@arcgis/core/widgets/Measurement.js");
const Print = await $arcgis.import("@arcgis/core/widgets/Print.js");
const [route, RouteParameters] = await $arcgis.import([
  "@arcgis/core/rest/route.js",
  "@arcgis/core/rest/support/RouteParameters.js",
]);

卷帘组件

通过在图层之间滑动进行对比。

卷帘组件
<arcgis-map zoom="15" center="-154.88, 19.46">
  <arcgis-zoom slot="top-left"></arcgis-zoom>
  <arcgis-swipe swipe-position="32"></arcgis-swipe>
</arcgis-map>

<script type="module">
  import Map from "@arcgis/core/Map.js";
  import TileLayer from "@arcgis/core/layers/TileLayer.js";

  const viewElement = document.querySelector("arcgis-map");
  const arcgisSwipe = document.querySelector("arcgis-swipe");

  const layer1 = new TileLayer({ url: "..." });
  const layer2 = new TileLayer({ url: "..." });

  viewElement.map = new Map({
    basemap: "satellite",
    layers: [layer1, layer2],
  });

  // Configure swipe when ready
  arcgisSwipe.addEventListener("arcgisPropertyChange", (e) => {
    if (e.detail.name === "state" && arcgisSwipe.state === "ready") {
      arcgisSwipe.leadingLayers.add(layer1);
      arcgisSwipe.trailingLayers.add(layer2);
    }
  });
</script>
卷帘组件(核心 API)
import Swipe from "@arcgis/core/widgets/Swipe.js";

const swipe = new Swipe({
  view: view,
  leadingLayers: [layer1],
  trailingLayers: [layer2],
  position: 50,
  direction: "horizontal", // or "vertical"
});

view.ui.add(swipe);

测量

测量组件

<arcgis-map>
  <arcgis-distance-measurement-2d
    slot="top-right"
  ></arcgis-distance-measurement-2d>
  <arcgis-area-measurement-2d slot="top-right"></arcgis-area-measurement-2d>
</arcgis-map>


<arcgis-scene>
  <arcgis-direct-line-measurement-3d
    slot="top-right"
  ></arcgis-direct-line-measurement-3d>
  <arcgis-area-measurement-3d slot="top-right"></arcgis-area-measurement-3d>
</arcgis-scene>
测量组件(核心 API)
import Measurement from "@arcgis/core/widgets/Measurement.js";

const measurement = new Measurement({ view: view });
view.ui.add(measurement, "bottom-right");

// Activate distance measurement
measurement.activeTool = view.type === "2d" ? "distance" : "direct-line";

// Activate area measurement
measurement.activeTool = "area";

// Clear measurements
measurement.clear();
2D 测量组件(核心 API)
import DistanceMeasurement2D from "@arcgis/core/widgets/DistanceMeasurement2D.js";
import AreaMeasurement2D from "@arcgis/core/widgets/AreaMeasurement2D.js";

const distanceWidget = new DistanceMeasurement2D({
  view: view,
  unit: "kilometers",
});
view.ui.add(distanceWidget, "top-right");

const areaWidget = new AreaMeasurement2D({
  view: view,
  unit: "square-kilometers",
});
view.ui.add(areaWidget, "top-right");
3D 测量组件(核心 API)
import DirectLineMeasurement3D from "@arcgis/core/widgets/DirectLineMeasurement3D.js";
import AreaMeasurement3D from "@arcgis/core/widgets/AreaMeasurement3D.js";

const lineWidget = new DirectLineMeasurement3D({
  view: sceneView,
  unit: "meters",
});

const areaWidget = new AreaMeasurement3D({
  view: sceneView,
  unit: "square-meters",
});

坐标转换

坐标转换组件
<arcgis-map basemap="satellite" center="-117.195, 34.057" zoom="13">
  <arcgis-coordinate-conversion
    slot="bottom-left"
  ></arcgis-coordinate-conversion>
</arcgis-map>
坐标转换组件(核心 API)
import CoordinateConversion from "@arcgis/core/widgets/CoordinateConversion.js";

const ccWidget = new CoordinateConversion({ view: view });
view.ui.add(ccWidget, "bottom-left");

书签

书签组件
<arcgis-map item-id="YOUR_WEBMAP_ID">
  <arcgis-expand slot="top-right" expand-tooltip="Bookmarks">
    <arcgis-bookmarks></arcgis-bookmarks>
  </arcgis-expand>
</arcgis-map>
书签组件(核心 API)
import Bookmarks from "@arcgis/core/widgets/Bookmarks.js";

const bookmarks = new Bookmarks({
  view: view,
  editingEnabled: true,
  visibleElements: {
    addBookmarkButton: true,
    editBookmarkButton: true,
  },
});

view.ui.add(bookmarks, "top-right");

路线指引组件

路线指引组件
<arcgis-map>
  <arcgis-directions slot="top-right"></arcgis-directions>
</arcgis-map>
路线指引组件(核心 API)
import Directions from "@arcgis/core/widgets/Directions.js";

const directions = new Directions({
  view: view,
});

view.ui.add(directions, "top-right");

路径规划(编程方式)

基本路线
import * as route from "@arcgis/core/rest/route.js";
import RouteParameters from "@arcgis/core/rest/support/RouteParameters.js";
import FeatureSet from "@arcgis/core/rest/support/FeatureSet.js";
import Graphic from "@arcgis/core/Graphic.js";
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer.js";

const routeUrl =
  "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World";

const routeLayer = new GraphicsLayer();
map.add(routeLayer);

const routeParams = new RouteParameters({
  apiKey: "YOUR_API_KEY",
  stops: new FeatureSet(),
  outSpatialReference: { wkid: 3857 },
});

// Add stop on click
view.on("click", async (event) => {
  const stop = new Graphic({
    geometry: event.mapPoint,
    symbol: {
      type: "simple-marker",
      style: "cross",
      size: 15,
    },
  });
  routeLayer.add(stop);
  routeParams.stops.features.push(stop);

  if (routeParams.stops.features.length >= 2) {
    const result = await route.solve(routeUrl, routeParams);
    const routeResult = result.routeResults[0].route;
    routeResult.symbol = {
      type: "simple-line",
      color: [0, 0, 255, 0.5],
      width: 5,
    };
    routeLayer.add(routeResult);
  }
});
带路线指引的路线
const routeParams = new RouteParameters({
  apiKey: "YOUR_API_KEY",
  stops: new FeatureSet({ features: stopGraphics }),
  returnDirections: true,
  directionsLanguage: "en",
  returnRoutes: true,
  returnStops: true,
  impedanceAttribute: "TravelTime",
  outSpatialReference: { wkid: 4326 },
});

const result = await route.solve(routeUrl, routeParams);

const directions = result.routeResults[0].directions;
directions.features.forEach((feature) => {
  console.log(feature.attributes.text);
});

打印

打印组件
<arcgis-map item-id="YOUR_WEBMAP_ID">
  <arcgis-expand slot="top-right" expand-tooltip="Print">
    <arcgis-print></arcgis-print>
  </arcgis-expand>
</arcgis-map>
打印组件(核心 API)
import Print from "@arcgis/core/widgets/Print.js";

const print = new Print({
  view: view,
  printServiceUrl:
    "https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task",
  allowedFormats: ["pdf", "png32", "jpg"],
  allowedLayouts: ["a4-landscape", "a4-portrait", "letter-ansi-a-landscape"],
  templateOptions: {
    title: "Default Map Title",
    author: "Default Author",
  },
});

view.ui.add(print, "top-right");
打印服务(编程方式)
import * as print from "@arcgis/core/rest/print.js";
import PrintTemplate from "@arcgis/core/rest/support/PrintTemplate.js";
import PrintParameters from "@arcgis/core/rest/support/PrintParameters.js";

const printUrl =
  "https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task";

const template = new PrintTemplate({
  format: "pdf", // pdf, png32, png8, jpg, gif, eps, svg, svgz
  layout: "a4-landscape", // Or custom layout name
  exportOptions: { dpi: 300 },
  layoutOptions: {
    titleText: "My Map",
    authorText: "Author Name",
    copyrightText: "Copyright 2025",
    scalebarUnit: "Kilometers",
  },
});

const params = new PrintParameters({
  view: view,
  template: template,
});

const result = await print.execute(printUrl, params);
console.log("PDF URL:", result.url);
打印格式
格式说明
pdfAdobe PDF
png32带透明度的 PNG(32 位)
png88 位 PNG
jpgJPEG
gifGIF
eps封装 PostScript
svg可缩放矢量图形
svgz压缩 SVG
仅导出地图(无布局)
const template = new PrintTemplate({
  format: "png32",
  layout: "map-only",
  exportOptions: {
    width: 1920,
    height: 1080,
    dpi: 96,
  },
});
截图作为替代方案

无需打印服务即可快速导出:

const screenshot = await view.takeScreenshot({
  format: "png",
  width: 1920,
  height: 1080,
  quality: 90,
});

// Download
const link = document.createElement("a");
link.download = "map-screenshot.png";
link.href = screenshot.dataUrl;
link.click();

高程剖面

高程剖面组件
<arcgis-scene>
  <arcgis-elevation-profile slot="top-right"></arcgis-elevation-profile>
</arcgis-scene>
高程剖面组件(核心 API)
import ElevationProfile from "@arcgis/core/widgets/ElevationProfile.js";

const elevationProfile = new ElevationProfile({
  view: view,
  profiles: [{ type: "ground" }, { type: "view" }],
});

view.ui.add(elevationProfile, "top-right");

识别

在 MapImageLayer 上进行识别
import * as identify from "@arcgis/core/rest/identify.js";
import IdentifyParameters from "@arcgis/core/rest/support/IdentifyParameters.js";

const identifyURL =
  "https://sampleserver6.arcgisonline.com/arcgis/rest/services/MtBaldy_BaseMap/MapServer";

const params = new IdentifyParameters({
  tolerance: 3,
  layerIds: [0, 1, 2, 3, 4],
  layerOption: "top", // "top", "visible", "all"
  width: view.width,
  height: view.height,
});

view.on("click", async (event) => {
  params.geometry = event.mapPoint;
  params.mapExtent = view.extent;

  const response = await identify.identify(identifyURL, params);

  const features = response.results.map((result) => {
    const feature = result.feature;
    feature.attributes.layerName = result.layerName;
    feature.popupTemplate = {
      title: result.layerName,
      content: "{*}",
    };
    return feature;
  });

  if (features.length > 0) {
    view.openPopup({
      features: features,
      location: event.mapPoint,
    });
  }
});

查找

查找服务
import * as find from "@arcgis/core/rest/find.js";
import FindParameters from "@arcgis/core/rest/support/FindParameters.js";

const findUrl =
  "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer";

const params = new FindParameters({
  searchText: "California",
  layerIds: [0, 1, 2],
  searchFields: ["STATE_NAME", "NAME"],
  returnGeometry: true,
});

const result = await find.find(findUrl, params);

result.results.forEach((r) => {
  console.log(r.feature.attributes);
});

参考示例

  • widgets-measurement - 距离和面积测量工具
  • widgets-measurement-3d - 3D 测量工具
  • widgets-print - 用于导出地图的打印组件
  • widgets-directions - 用于路径规划的路线指引组件
  • swipe - 用于对比图层的卷帘组件
  • coordinate-conversion - 坐标转换工具
  • bookmarks - 书签导航
  • elevation-profile - 高程剖面组件

常见问题

  1. 路径规划需要 API 密钥:路线服务需要有效的 API 密钥或经过身份验证的用户。

  2. 识别容差:根据缩放级别设置合适的容差。在高缩放级别下,容差过低可能会漏掉要素。

  3. 卷帘图层顺序:将前景和背景图层指定给卷帘组件之前,必须先将它们添加到地图的图层集合中。

  4. 测量单位:2D 和 3D 视图应使用不同的测量组件。统一的 Measurement 组件会根据 view.type 自动选择。

  5. 打印服务 URL:默认的 Esri 打印服务 URL 可能需要身份验证。自定义打印服务需要配置各自的 URL。

  6. 地图内的坐标转换:必须将其作为子级放在 <arcgis-map> 中并指定 slot;若放在外部,则使用 reference-element。

相关技能

  • 基础 UI 组件和 Calcite 布局请参阅 arcgis-widgets-ui
  • 专用组件请参阅 arcgis-widgets-advanced
  • REST API 查询和分析工具请参阅 arcgis-rest-services
  • 服务端分析操作请参阅 arcgis-spatial-analysis

评论

支持 Markdown