From arcgis-maps-sdk-js-ai-context
Work with advanced layer types including WMS, WFS, WMTS, OGCFeatureLayer, MapImageLayer, MediaLayer, and dynamic data layers. Use for OGC services, server-side rendering, and georeferenced media content.
How this skill is triggered — by the user, by Claude, or both
Slash command
/arcgis-maps-sdk-js-ai-context:arcgis-advanced-layersThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill for working with OGC services, MapImageLayer, MediaLayer, and dynamic data layers.
Use this skill for working with OGC services, MapImageLayer, MediaLayer, and dynamic data layers.
import WMSLayer from "@arcgis/core/layers/WMSLayer.js";
const layer = new WMSLayer({
url: "https://ows.terrestris.de/osm/service"
});
await layer.load();
// Find and use a specific sublayer
const sublayer = layer.findSublayerByName("OSM-WMS");
if (sublayer) {
layer.sublayers = [sublayer];
}
map.add(layer);
import Map from "@arcgis/core/Map.js";
import SceneView from "@arcgis/core/views/SceneView.js";
import Basemap from "@arcgis/core/Basemap.js";
import WMSLayer from "@arcgis/core/layers/WMSLayer.js";
const wmsLayer = new WMSLayer({
url: "https://ows.terrestris.de/osm/service"
});
await wmsLayer.load();
const sublayer = wmsLayer.findSublayerByName("OSM-WMS");
if (sublayer) {
wmsLayer.sublayers = [sublayer];
}
const map = new Map({
basemap: new Basemap({
baseLayers: [wmsLayer],
title: "WMS Basemap"
})
});
const view = new SceneView({
container: "viewDiv",
map: map
});
import WFSLayer from "@arcgis/core/layers/WFSLayer.js";
const layer = new WFSLayer({
url: "https://geobretagne.fr/geoserver/ows",
name: "fma:bvme_zhp_vs_culture",
copyright: "GéoBretagne"
});
map.add(layer);
import WFSLayer from "@arcgis/core/layers/WFSLayer.js";
import wfsUtils from "@arcgis/core/layers/ogc/wfsUtils.js";
// Get capabilities from WFS endpoint
const capabilities = await wfsUtils.getCapabilities("https://geobretagne.fr/geoserver/ows");
// List available feature types
capabilities.featureTypes.forEach(featureType => {
console.log(featureType.title, featureType.name);
});
// Create layer from specific feature type
const layerInfo = await wfsUtils.getWFSLayerInfo(capabilities, "featureTypeName");
const layer = WFSLayer.fromWFSLayerInfo(layerInfo);
map.add(layer);
import WMTSLayer from "@arcgis/core/layers/WMTSLayer.js";
const layer = new WMTSLayer({
url: "https://www.ign.es/wmts/ign-base",
activeLayer: {
id: "IGNBase-gris",
tileMatrixSetId: "GoogleMapsCompatible"
},
serviceMode: "KVP",
copyright: "Instituto Geográfico Nacional"
});
map.add(layer);
import Basemap from "@arcgis/core/Basemap.js";
import WMTSLayer from "@arcgis/core/layers/WMTSLayer.js";
const wmtsBasemap = new Basemap({
baseLayers: [
new WMTSLayer({
url: "https://www.ign.es/wmts/ign-base",
activeLayer: { id: "IGNBase-gris", tileMatrixSetId: "GoogleMapsCompatible" },
serviceMode: "KVP"
})
],
thumbnailUrl: "https://example.com/thumbnail.jpg"
});
const map = new Map({
basemap: wmtsBasemap
});
import OGCFeatureLayer from "@arcgis/core/layers/OGCFeatureLayer.js";
const layer = new OGCFeatureLayer({
url: "https://demo.ldproxy.net/vineyards", // OGC API landing page
collectionId: "vineyards", // Collection ID
minScale: 5000000,
renderer: {
type: "simple",
symbol: {
type: "simple-fill",
color: [76, 129, 64, 0.6]
}
},
popupTemplate: {
title: "{name}",
content: "Area: {area_ha} hectares"
}
});
map.add(layer);
const layer = new OGCFeatureLayer({
url: "https://demo.ldproxy.net/vineyards",
collectionId: "vineyards",
labelingInfo: [{
labelExpressionInfo: {
expression: "$feature.NAME"
},
symbol: {
type: "text",
color: "#4a6741",
haloSize: 1,
haloColor: "white",
font: {
family: "Arial",
style: "italic"
}
},
minScale: 100000
}]
});
import MapImageLayer from "@arcgis/core/layers/MapImageLayer.js";
// From portal item
const layer = new MapImageLayer({
portalItem: {
id: "d7892b3c13b44391992ecd42bfa92d01"
}
});
// From URL
const layer2 = new MapImageLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer"
});
map.add(layer);
const layer = new MapImageLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
sublayers: [
{ id: 2, visible: true }, // States
{ id: 1, visible: true }, // Highways
{ id: 0, visible: true } // Cities
]
});
// Toggle sublayer visibility
layer.when(() => {
const sublayer = layer.findSublayerById(1);
sublayer.visible = !sublayer.visible;
});
const layer = new MapImageLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
sublayers: [{
id: 0,
definitionExpression: "pop2000 > 100000"
}]
});
const layer = new MapImageLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
sublayers: [{
id: 2,
renderer: {
type: "simple",
symbol: {
type: "simple-fill",
color: [0, 100, 200, 0.5],
outline: { color: "white", width: 1 }
}
}
}]
});
const layer = new MapImageLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
sublayers: [{
id: 4,
title: "Railroads",
renderer: {
type: "simple",
symbol: {
type: "simple-line",
color: [255, 255, 255, 0.5],
width: 0.75,
style: "long-dash-dot-dot"
}
},
source: {
type: "data-layer",
dataSource: {
type: "table",
workspaceId: "MyDatabaseWorkspaceIDSSR2",
dataSourceName: "ss6.gdb.Railroads"
}
}
}]
});
const layer = new MapImageLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer",
sublayers: [{
id: 0,
opacity: 0.75,
source: {
type: "data-layer",
dataSource: {
type: "join-table",
// Left table: map layer with geometries
leftTableSource: {
type: "map-layer",
mapLayerId: 3
},
// Right table: data table in workspace
rightTableSource: {
type: "data-layer",
dataSource: {
type: "table",
workspaceId: "CensusFileGDBWorkspaceID",
dataSourceName: "ancestry"
}
},
leftTableKey: "STATE_NAME",
rightTableKey: "State",
joinType: "left-outer-join"
}
},
renderer: {
type: "class-breaks",
field: "ancestry.Norwegian",
normalizationField: "states.POP2007",
classBreakInfos: [
{ minValue: 0, maxValue: 0.01, symbol: createSymbol("#f8e3c2") },
{ minValue: 0.01, maxValue: 0.05, symbol: createSymbol("#d86868") }
]
}
}]
});
import MediaLayer from "@arcgis/core/layers/MediaLayer.js";
import ImageElement from "@arcgis/core/layers/support/ImageElement.js";
import ExtentAndRotationGeoreference from "@arcgis/core/layers/support/ExtentAndRotationGeoreference.js";
import Extent from "@arcgis/core/geometry/Extent.js";
const imageElement = new ImageElement({
image: "https://example.com/historical-map.png",
georeference: new ExtentAndRotationGeoreference({
extent: new Extent({
xmin: -10047456,
ymin: 3486722,
xmax: -10006982,
ymax: 3514468,
spatialReference: { wkid: 102100 }
})
})
});
const mediaLayer = new MediaLayer({
source: [imageElement],
title: "Historical Map"
});
map.add(mediaLayer);
const imageInfos = [
{
url: "image1.png",
extent: { xmin: -100, ymin: 30, xmax: -90, ymax: 40 }
},
{
url: "image2.png",
extent: { xmin: -95, ymin: 35, xmax: -85, ymax: 45 }
}
];
const imageElements = imageInfos.map(info => new ImageElement({
image: info.url,
georeference: new ExtentAndRotationGeoreference({
extent: new Extent({
...info.extent,
spatialReference: { wkid: 4326 }
})
})
}));
const mediaLayer = new MediaLayer({
source: imageElements
});
const georeference = new ExtentAndRotationGeoreference({
extent: new Extent({
xmin: -122.5,
ymin: 37.5,
xmax: -122.0,
ymax: 38.0,
spatialReference: { wkid: 4326 }
}),
rotation: 15 // Degrees clockwise
});
import ControlPointsGeoreference from "@arcgis/core/layers/support/ControlPointsGeoreference.js";
const georeference = new ControlPointsGeoreference({
controlPoints: [
{
sourcePoint: { x: 0, y: 0 }, // Top-left of image (pixels)
mapPoint: { x: -122.5, y: 38.0 } // Map coordinates
},
{
sourcePoint: { x: 1000, y: 0 }, // Top-right
mapPoint: { x: -122.0, y: 38.0 }
},
{
sourcePoint: { x: 1000, y: 800 }, // Bottom-right
mapPoint: { x: -122.0, y: 37.5 }
},
{
sourcePoint: { x: 0, y: 800 }, // Bottom-left
mapPoint: { x: -122.5, y: 37.5 }
}
],
width: 1000, // Image width in pixels
height: 800 // Image height in pixels
});
import VideoElement from "@arcgis/core/layers/support/VideoElement.js";
const videoElement = new VideoElement({
video: "https://example.com/timelapse.mp4",
georeference: new ExtentAndRotationGeoreference({
extent: new Extent({
xmin: -122.5,
ymin: 37.5,
xmax: -122.0,
ymax: 38.0,
spatialReference: { wkid: 4326 }
})
})
});
const mediaLayer = new MediaLayer({
source: [videoElement]
});
// Control video playback
videoElement.content.play();
videoElement.content.pause();
videoElement.content.currentTime = 30; // Seek to 30 seconds
// Animated GIFs work like regular images
const gifElement = new ImageElement({
image: "https://example.com/weather-animation.gif",
georeference: new ExtentAndRotationGeoreference({
extent: new Extent({
xmin: -130,
ymin: 25,
xmax: -65,
ymax: 50,
spatialReference: { wkid: 4326 }
})
})
});
const mediaLayer = new MediaLayer({
source: [gifElement]
});
const mediaLayer = new MediaLayer({
source: [imageElement],
opacity: 0.7,
blendMode: "multiply" // normal, multiply, luminosity, etc.
});
// Change opacity dynamically
mediaLayer.opacity = 0.5;
// Change blend mode
mediaLayer.blendMode = "luminosity";
// Individual element opacity
imageElement.opacity = 0.8;
// Update dynamically
document.getElementById("opacitySlider").addEventListener("input", (e) => {
imageElement.opacity = e.target.value / 100;
});
// Access source
const source = mediaLayer.source;
// Add elements
source.elements.push(newImageElement);
source.elements.push(element1, element2);
// Remove elements
source.elements.splice(source.elements.indexOf(imageElement), 1);
source.elements.length = 0; // Remove all
// Iterate elements
source.elements.forEach(element => {
console.log(element.image || element.video);
});
// Enable interactive editing of georeference control points
const mediaLayerView = await view.whenLayerView(mediaLayer);
// Enable interactive mode to allow control point editing
mediaLayerView.interactive = true;
// Disable interactive mode
mediaLayerView.interactive = false;
<div id="viewDiv" style="height: 600px; width: 100%;"></div>
<script type="module">
import Map from "@arcgis/core/Map.js";
import MapView from "@arcgis/core/views/MapView.js";
import MediaLayer from "@arcgis/core/layers/MediaLayer.js";
import ImageElement from "@arcgis/core/layers/support/ImageElement.js";
import ExtentAndRotationGeoreference from "@arcgis/core/layers/support/ExtentAndRotationGeoreference.js";
import Extent from "@arcgis/core/geometry/Extent.js";
// Create image elements for historical maps
const imageElements = [
{
name: "1891 Map",
url: "https://example.com/map-1891.png",
extent: { xmin: -10047456, ymin: 3486722, xmax: -10006982, ymax: 3514468 }
},
{
name: "1920 Map",
url: "https://example.com/map-1920.png",
extent: { xmin: -10045000, ymin: 3488000, xmax: -10008000, ymax: 3516000 }
}
].map(info => new ImageElement({
image: info.url,
georeference: new ExtentAndRotationGeoreference({
extent: new Extent({
...info.extent,
spatialReference: { wkid: 102100 }
})
})
}));
const mediaLayer = new MediaLayer({
source: imageElements,
title: "Historical Maps",
blendMode: "normal"
});
const map = new Map({
basemap: "topo-vector",
layers: [mediaLayer]
});
const view = new MapView({
container: "viewDiv",
map: map,
center: [-89.93, 29.97],
zoom: 10
});
</script>
| Layer Type | Use Case | Data Source |
|---|---|---|
| WMSLayer | Raster imagery from OGC WMS | WMS 1.1.1/1.3.0 |
| WFSLayer | Vector features from OGC WFS | WFS 2.0.0 |
| WMTSLayer | Cached tiles from OGC WMTS | WMTS 1.0.0 |
| OGCFeatureLayer | Vector from OGC API - Features | OGC API |
| MapImageLayer | Server-rendered imagery | ArcGIS Map Service |
| MediaLayer | Georeferenced images, video, GIFs | Local/remote media |
layers-wms - Adding and configuring WMS layerslayers-wfs - Working with WFS layerslayers-ogcfeaturelayer - OGC Features API layer usagelayers-mapimagelayer - Dynamic MapImageLayer configurationlayers-medialayer-images - Displaying images with MediaLayerlayers-medialayer-video - Video playback in MediaLayerlayers-medialayer-control-points - Control point placement for medialayers-medialayer-interactive - Interactive media layer manipulationWFS version: WFSLayer requires WFS 2.0.0 with GeoJSON output format
CORS: OGC services need CORS headers or proxy configuration
Sublayer IDs: MapImageLayer sublayer IDs must match service layer IDs
Dynamic data sources: Require registered workspaces on the server
Field prefixes: In joined tables, prefix field names with table name (e.g., ancestry.Norwegian)
Media CORS: Images and videos from external servers need CORS headers
Video autoplay: Browsers may block autoplay - require user interaction first
npx claudepluginhub elowen53/arcgis-maps-sdk-js-ai-context-4.0 --plugin arcgis-maps-sdk-js-ai-contextCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.