arcgis-core-maps

Use this skill when creating 2D maps (MapView) or 3D scenes (SceneView) with the ArcGIS Maps SDK for JavaScript.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "arcgis-core-maps" with this command: npx skills add saschabrunnerch/arcgis-maps-sdk-js-ai-context/saschabrunnerch-arcgis-maps-sdk-js-ai-context-arcgis-core-maps

ArcGIS Core Maps

Use this skill when creating 2D maps (MapView) or 3D scenes (SceneView) with the ArcGIS Maps SDK for JavaScript.

Import Patterns

Direct ESM Imports (Recommended for Build Tools)

Use with Vite, webpack, Rollup, or other build tools:

import Map from "@arcgis/core/Map.js"; import MapView from "@arcgis/core/views/MapView.js"; import FeatureLayer from "@arcgis/core/layers/FeatureLayer.js";

  • Tree-shakeable

  • Standard JavaScript modules

  • Best for production applications

Dynamic Imports (CDN / No Build Tools)

Use with CDN script tags when no build step is available:

const Map = await $arcgis.import("@arcgis/core/Map.js"); const MapView = await $arcgis.import("@arcgis/core/views/MapView.js");

// Multiple imports const [FeatureLayer, Graphic] = await $arcgis.import([ "@arcgis/core/layers/FeatureLayer.js", "@arcgis/core/Graphic.js" ]);

Note: The examples in this skill use Direct ESM imports. For CDN usage, replace import X from "path" with const X = await $arcgis.import("path") .

Autocasting vs Explicit Classes (TypeScript)

The ArcGIS SDK supports autocasting - passing plain objects instead of class instances. Understanding when to use each approach is important for TypeScript projects.

When to Use Explicit Classes (Non-Autocast)

Use new SimpleRenderer() , new Point() , etc. when:

  • You need instance methods or instanceof checks

  • Building shared internal libraries - constructor APIs surface breaking changes at compile time

  • You want strong editor discoverability - new SimpleRenderer({ ... }) exposes properties clearly

  • You mutate objects incrementally - long-lived instances are clearer as real classes

import SimpleRenderer from "@arcgis/core/renderers/SimpleRenderer.js"; import SimpleMarkerSymbol from "@arcgis/core/symbols/SimpleMarkerSymbol.js";

const renderer = new SimpleRenderer({ symbol: new SimpleMarkerSymbol({ color: [226, 119, 40], size: 8 }) });

When to Use Autocasting

Use plain objects with type property when:

  • Configuration-heavy code - renderers, symbols, popups are usually data, not behavior

  • UI-driven configuration - React state → plain objects → SDK properties is simpler

  • Serialization and reuse matter - configs can be stored, diffed, tested, reused

  • Property updates after creation - layer.renderer = { ... } works cleanly in React useEffect

// Use 'as const' or 'satisfies' to keep discriminated unions narrow const renderer = { type: "simple", symbol: { type: "simple-marker", color: [226, 119, 40], size: 8 } } as const;

// Or with satisfies for better type inference import type { SimpleRenderer } from "@arcgis/core/renderers/SimpleRenderer.js";

const renderer = { type: "simple", symbol: { type: "simple-marker", color: [226, 119, 40], size: 8 } } satisfies __esri.SimpleRendererProperties;

TypeScript Best Practices

The real TypeScript concern is keeping discriminated unions narrow:

// ❌ BAD - type widens to string const symbol = { type: "simple-marker", color: "red" };

// ✅ GOOD - type stays literal const symbol = { type: "simple-marker", color: "red" } as const;

// ✅ GOOD - explicit type annotation const symbol: __esri.SimpleMarkerSymbolProperties = { type: "simple-marker", color: "red" };

Recommended Default

  • Autocast for configuration (renderers, symbols, popups, labels)

  • Explicit classes for behavior (when you need methods or instanceof)

  • Use as const or satisfies to maintain type safety with autocasting

Two Approaches

  1. Map Components (Modern - Recommended)

Web components approach using <arcgis-map> and <arcgis-scene> .

  1. Core API

Traditional JavaScript approach using Map , MapView , and SceneView classes.

CDN Setup

Map Components Approach

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>ArcGIS Map</title> <style> html, body { height: 100%; margin: 0; } </style> <!-- Load Calcite components --> <script type="module" src="https://js.arcgis.com/calcite-components/3.3.3/calcite.esm.js">&#x3C;/script> <!-- Load ArcGIS Maps SDK --> <script src="https://js.arcgis.com/4.34/">&#x3C;/script> <!-- Load Map components --> <script type="module" src="https://js.arcgis.com/4.34/map-components/">&#x3C;/script> </head> <body> <arcgis-map basemap="topo-vector" center="-118.24,34.05" zoom="12"> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-map> </body> </html>

Core API Approach

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>ArcGIS Map</title> <style> html, body, #viewDiv { height: 100%; margin: 0; } </style> <!-- REQUIRED: main.css for Core API --> <link rel="stylesheet" href="https://js.arcgis.com/4.34/esri/themes/light/main.css" /> <script src="https://js.arcgis.com/4.34/">&#x3C;/script> </head> <body> <div id="viewDiv"></div> <script type="module"> import Map from "@arcgis/core/Map.js"; import MapView from "@arcgis/core/views/MapView.js";

const map = new Map({ basemap: "topo-vector" });
const view = new MapView({
  container: "viewDiv",
  map: map,
  center: [-118.24, 34.05], // [longitude, latitude]
  zoom: 12
});

</script> </body> </html>

2D Maps

Map Components

<arcgis-map basemap="topo-vector" center="-118.24,34.05" zoom="12"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-compass slot="top-left"></arcgis-compass> <arcgis-home slot="top-left"></arcgis-home> <arcgis-locate slot="top-left"></arcgis-locate> </arcgis-map>

<script type="module"> const mapElement = document.querySelector("arcgis-map"); await mapElement.viewOnReady(); // Wait for view to be ready const view = mapElement.view; // Access the MapView const map = mapElement.map; // Access the Map </script>

Core API

import Map from "@arcgis/core/Map.js"; import MapView from "@arcgis/core/views/MapView.js";

const map = new Map({ basemap: "streets-vector" });

const view = new MapView({ container: "viewDiv", map: map, center: [-118.24, 34.05], zoom: 12, // Optional constraints constraints: { minZoom: 5, maxZoom: 18, rotationEnabled: false } });

3D Scenes

Map Components

<arcgis-scene basemap="topo-3d" ground="world-elevation"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-navigation-toggle slot="top-left"></arcgis-navigation-toggle> </arcgis-scene>

<script type="module"> const sceneElement = document.querySelector("arcgis-scene"); await sceneElement.viewOnReady(); const view = sceneElement.view; // SceneView </script>

Core API

import Map from "@arcgis/core/Map.js"; import SceneView from "@arcgis/core/views/SceneView.js";

const map = new Map({ basemap: "topo-3d", ground: "world-elevation" });

const view = new SceneView({ container: "viewDiv", map: map, camera: { position: { longitude: -118.24, latitude: 34.05, z: 25000 // altitude in meters }, heading: 0, // compass direction tilt: 45 // 0 = straight down, 90 = horizon } });

Video View Container

The arcgis-video component is a third view container alongside arcgis-map and arcgis-scene , used for displaying video feeds from video services.

Map Component

<arcgis-video> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-video>

import "@arcgis/map-components/dist/components/arcgis-video";

const videoElement = document.querySelector("arcgis-video"); videoElement?.addEventListener("arcgisViewReadyChange", (event) => { const { view } = event.detail; console.log("Video view ready:", view); });

Note: arcgis-video supports the same position slots as arcgis-map and arcgis-scene : top-left , top-right , bottom-left , bottom-right , top-start , top-end , bottom-start , bottom-end .

Loading WebMaps and WebScenes

WebMap (2D)

<!-- Map Components --> <arcgis-map item-id="f2e9b762544945f390ca4ac3671cfa72"> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-map>

// Core API import MapView from "@arcgis/core/views/MapView.js"; import WebMap from "@arcgis/core/WebMap.js";

const webmap = new WebMap({ portalItem: { id: "f2e9b762544945f390ca4ac3671cfa72" } });

const view = new MapView({ map: webmap, container: "viewDiv" });

WebScene (3D)

<!-- Map Components --> <arcgis-scene item-id="YOUR_WEBSCENE_ID"> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-scene>

// Core API import SceneView from "@arcgis/core/views/SceneView.js"; import WebScene from "@arcgis/core/WebScene.js";

const webscene = new WebScene({ portalItem: { id: "YOUR_WEBSCENE_ID" } });

const view = new SceneView({ map: webscene, container: "viewDiv" });

Navigation Components

Component Purpose

arcgis-zoom

Zoom in/out buttons

arcgis-compass

Orientation indicator, click to reset north

arcgis-home

Return to initial extent

arcgis-locate

Find user's location

arcgis-navigation-toggle

Switch between pan/rotate modes (3D)

arcgis-fullscreen

Toggle fullscreen mode

arcgis-scale-bar

Display map scale

Slot Positions

<arcgis-map basemap="streets-vector"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-home slot="top-left"></arcgis-home> <arcgis-search slot="top-right"></arcgis-search> <arcgis-legend slot="bottom-left"></arcgis-legend> <arcgis-scale-bar slot="bottom-right"></arcgis-scale-bar> </arcgis-map>

Available slots: top-left , top-right , bottom-left , bottom-right , top-start , top-end , bottom-start , bottom-end

View Configuration

Setting Initial Extent

// By center and zoom const view = new MapView({ container: "viewDiv", map: map, center: [-118.24, 34.05], zoom: 12 });

// By scale const view = new MapView({ container: "viewDiv", map: map, center: [-118.24, 34.05], scale: 50000 // 1:50,000 });

// By extent const view = new MapView({ container: "viewDiv", map: map, extent: { xmin: -118.5, ymin: 33.8, xmax: -117.9, ymax: 34.3, spatialReference: { wkid: 4326 } } });

Programmatic Navigation

// Go to location await view.goTo({ center: [-118.24, 34.05], zoom: 15 });

// Animated navigation await view.goTo( { center: [-118.24, 34.05], zoom: 15 }, { duration: 2000, easing: "ease-in-out" } );

// Go to extent await view.goTo(layer.fullExtent);

// Go to features await view.goTo(featureSet.features);

View Constraints

// Constrain zoom levels view.constraints = { minZoom: 5, maxZoom: 18 };

// Constrain to area view.constraints = { geometry: layer.fullExtent, minScale: 500000 };

// Disable rotation view.constraints = { rotationEnabled: false };

Event Handling

// View ready view.when(() => { console.log("View is ready"); });

// Click event view.on("click", (event) => { console.log("Clicked at:", event.mapPoint); });

// Pointer move view.on("pointer-move", (event) => { const point = view.toMap(event); console.log("Mouse at:", point.longitude, point.latitude); });

// Extent change (using reactiveUtils) import * as reactiveUtils from "@arcgis/core/core/reactiveUtils.js";

reactiveUtils.watch( () => view.extent, (extent) => console.log("Extent changed:", extent) );

// Stationary (after pan/zoom completes) reactiveUtils.watch( () => view.stationary, (isStationary) => { if (isStationary) { console.log("Navigation complete"); } } );

Module Imports

// Single import import FeatureLayer from "@arcgis/core/layers/FeatureLayer.js";

// Multiple imports import Map from "@arcgis/core/Map.js"; import MapView from "@arcgis/core/views/MapView.js"; import Graphic from "@arcgis/core/Graphic.js";

Common Basemaps

Basemap ID Description

streets-vector

Street map

topo-vector

Topographic

satellite

Satellite imagery

hybrid

Satellite with labels

dark-gray-vector

Dark gray canvas

gray-vector

Light gray canvas

osm

OpenStreetMap

topo-3d

3D topographic (SceneView)

esriRequest (HTTP Requests)

Basic Request

import esriRequest from "@arcgis/core/request.js";

// GET request with JSON response const response = await esriRequest(url, { query: { f: "json" }, responseType: "json" });

console.log("Status:", response.httpStatus); console.log("Data:", response.data);

Request with Options

const response = await esriRequest(url, { query: { f: "json", param1: "value1" }, responseType: "json", // "json", "text", "array-buffer", "blob", "image" method: "post", // "auto", "head", "post" body: formData, // For POST requests timeout: 30000, // Timeout in ms headers: { "X-Custom-Header": "value" } });

Download Binary Data

// Image response const imageResponse = await esriRequest(imageUrl, { responseType: "image" }); const imageElement = imageResponse.data;

// Binary data const binaryResponse = await esriRequest(fileUrl, { responseType: "array-buffer" }); const arrayBuffer = binaryResponse.data;

Planetary Visualization (Mars)

Mars Scene

<arcgis-scene> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-navigation-toggle slot="top-left"></arcgis-navigation-toggle> </arcgis-scene>

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

const viewElement = document.querySelector("arcgis-scene");

// Set Mars spatial reference viewElement.spatialReference = { wkid: 104971 }; // Mars 2000

// Configure camera for Mars viewElement.camera = { position: { x: 27.63423, y: -6.34466, z: 1281525, spatialReference: { wkid: 104971 } }, heading: 332, tilt: 37 };

await viewElement.viewOnReady();

// Mars elevation const marsElevation = new ElevationLayer({ url: "https://astro.arcgis.com/arcgis/rest/services/OnMars/MDEM200M/ImageServer" }); viewElement.ground = { layers: [marsElevation] };

// Mars imagery const marsImagery = new TileLayer({ url: "https://astro.arcgis.com/arcgis/rest/services/OnMars/MDIM/MapServer", title: "Mars Imagery" }); viewElement.map.add(marsImagery); </script>

Overview Map (Synchronized Views)

Overview Map with Scene

<arcgis-scene basemap="hybrid" ground="world-elevation"> <arcgis-zoom slot="top-left"></arcgis-zoom> <!-- Embed overview map inside scene --> <arcgis-map basemap="topo-vector" id="overviewDiv" slot="top-right"></arcgis-map> </arcgis-scene>

<style> #overviewDiv { width: 300px; height: 200px; border: 1px solid black; } </style>

<script type="module"> import Graphic from "@arcgis/core/Graphic.js"; import reactiveUtils from "@arcgis/core/core/reactiveUtils.js";

const sceneElement = document.querySelector("arcgis-scene"); const overviewElement = document.querySelector("arcgis-map");

await sceneElement.viewOnReady(); await overviewElement.viewOnReady();

// Disable rotation on overview overviewElement.constraints.rotationEnabled = false; overviewElement.view.ui.components = [];

// Add visible area graphic const visibleAreaGraphic = new Graphic({ symbol: { type: "simple-fill", color: [0, 0, 0, 0.5], outline: null } }); overviewElement.graphics.add(visibleAreaGraphic);

// Sync overview with main scene reactiveUtils.watch( () => sceneElement.visibleArea, async (visibleArea) => { visibleAreaGraphic.geometry = visibleArea; await overviewElement.goTo(visibleArea); }, { initial: true } ); </script>

promiseUtils (Async Utilities)

Debounce

import promiseUtils from "@arcgis/core/core/promiseUtils.js";

// Create debounced function const debouncedUpdate = promiseUtils.debounce(async () => { // This only runs after 300ms of no calls await updateFeatures(); });

view.on("pointer-move", () => { debouncedUpdate(); });

Abort Error Handling

import promiseUtils from "@arcgis/core/core/promiseUtils.js";

const abortController = new AbortController();

try { await someAsyncOperation({ signal: abortController.signal }); } catch (error) { if (promiseUtils.isAbortError(error)) { // Operation was intentionally cancelled console.log("Operation cancelled"); } else { // Real error throw error; } }

// Cancel the operation abortController.abort();

reactiveUtils (Property Watching)

Watch Properties

import reactiveUtils from "@arcgis/core/core/reactiveUtils.js";

// Watch single property reactiveUtils.watch( () => view.scale, (scale) => console.log("Scale:", scale) );

// Watch with initial value reactiveUtils.watch( () => view.extent, (extent) => console.log("Extent:", extent), { initial: true } );

// Watch once reactiveUtils.once( () => view.stationary === true ).then(() => { console.log("View became stationary"); });

// When condition becomes true reactiveUtils.when( () => layer.loaded, () => console.log("Layer loaded") );

Reference Samples

  • intro-mapview

  • Basic MapView setup and configuration

  • intro-sceneview

  • Basic SceneView setup for 3D

  • webmap-basic

  • Loading a WebMap from portal

  • watch-for-changes-reactiveutils

  • Reactive property watching with reactiveUtils

  • overview-map

  • Creating an overview/inset map

Common Pitfalls

Missing CSS for Core API: The Core API requires main.css for widgets and popups to render correctly.

<!-- Anti-pattern: no CSS import --> <script type="module"> import MapView from "@arcgis/core/views/MapView"; import Map from "@arcgis/core/Map"; const view = new MapView({ container: "viewDiv", map: new Map({ basemap: "topo-vector" }) }); </script>

<!-- Correct: include the CSS --> <link rel="stylesheet" href="https://js.arcgis.com/4.34/esri/themes/light/main.css" /> <script type="module"> import MapView from "@arcgis/core/views/MapView"; import Map from "@arcgis/core/Map"; const view = new MapView({ container: "viewDiv", map: new Map({ basemap: "topo-vector" }) }); </script>

Impact: The map itself renders, but widgets (Zoom, Legend, Search) and popups appear unstyled or completely broken. Layouts collapse and controls become unusable.

Not awaiting viewOnReady(): View properties are not available until the view is ready.

// Anti-pattern: accessing view before it is ready const mapElement = document.querySelector("arcgis-map"); const view = mapElement.view; // undefined - view is not ready yet view.goTo({ center: [-118, 34] }); // TypeError: Cannot read properties of undefined

// Correct: wait for the view to be ready const mapElement = document.querySelector("arcgis-map"); await mapElement.viewOnReady(); const view = mapElement.view; // MapView instance, safe to use view.goTo({ center: [-118, 34] });

Impact: view is null or undefined before the component initializes, causing runtime errors on any property access or method call.

Coordinate order: ArcGIS uses [longitude, latitude] , not [latitude, longitude] .

// Anti-pattern: lat/lng order (Google Maps convention) const view = new MapView({ center: [34.05, -118.24], // lat first, lng second - WRONG zoom: 12 });

// Correct: lng/lat order (ArcGIS convention) const view = new MapView({ center: [-118.24, 34.05], // lng first, lat second zoom: 12 });

Impact: The map centers on the wrong location, often in the middle of the ocean or on a different continent, with no error message to indicate the mistake.

Missing viewDiv height: Ensure the container has height:

html, body, #viewDiv { height: 100%; margin: 0; }

Script type: Use type="module" for async/await support:

<script type="module"> // async/await works here </script>

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

arcgis-widgets-ui

No summary provided by upstream source.

Repository SourceNeeds Review
General

arcgis-popup-templates

No summary provided by upstream source.

Repository SourceNeeds Review
General

arcgis-geometry-operations

No summary provided by upstream source.

Repository SourceNeeds Review
General

arcgis-authentication

No summary provided by upstream source.

Repository SourceNeeds Review