ArcGIS Advanced Layers
Use this skill for working with OGC services, MapImageLayer, CatalogLayer, MediaLayer, and dynamic data layers.
WMSLayer (Web Map Service)
Basic WMSLayer
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);
WMSLayer as Basemap (Map Component)
<arcgis-scene> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-scene>
<script type="module"> import WMSLayer from "@arcgis/core/layers/WMSLayer.js"; const viewElement = document.querySelector("arcgis-scene");
const layer = new WMSLayer({ url: "https://ows.terrestris.de/osm/service" });
await layer.load(); const sublayer = layer.findSublayerByName("OSM-WMS"); if (sublayer) { layer.sublayers = [sublayer]; }
viewElement.map = { basemap: { baseLayers: [layer], title: "WMS Layer" } }; </script>
WFSLayer (Web Feature Service)
Basic WFSLayer
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);
WFS Capabilities
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);
WMTSLayer (Web Map Tile Service)
Basic WMTSLayer
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);
WMTSLayer as Basemap
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 });
OGCFeatureLayer
Basic OGCFeatureLayer
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);
OGCFeatureLayer with Labeling
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 }] });
MapImageLayer
Basic MapImageLayer
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);
MapImageLayer with Sublayers
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; });
MapImageLayer with Definition Expression
const layer = new MapImageLayer({ url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer", sublayers: [{ id: 0, definitionExpression: "pop2000 > 100000" }] });
MapImageLayer with Custom Renderer
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 } } } }] });
Dynamic Data Layers
Data Layer from Table
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" } } }] });
Data Layer with Table Join
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") } ] } }] });
CatalogLayer
Basic CatalogLayer
import CatalogLayer from "@arcgis/core/layers/CatalogLayer.js";
const layer = new CatalogLayer({ portalItem: { id: "487cc66d305145d3b67fed383456af48", portal: { url: "https://jsapi.maps.arcgis.com/" } } });
map.add(layer);
Working with CatalogLayer Footprints
import CatalogLayer from "@arcgis/core/layers/CatalogLayer.js"; import catalogUtils from "@arcgis/core/layers/catalog/catalogUtils.js";
const layer = new CatalogLayer({ portalItem: { id: "YOUR_CATALOG_ITEM_ID" } });
map.add(layer);
const layerView = await view.whenLayerView(layer);
// Query all footprints const result = await layer.queryFeatures({ where: "1=1", returnGeometry: true, outFields: ["*"], orderByFields: [layer.itemNameField] });
// Add labels to footprint layer layer.footprintLayer.labelingInfo = [{ labelExpressionInfo: { expression: "$feature." + layer.itemNameField }, symbol: { type: "label-3d", symbolLayers: [{ type: "text", material: { color: "white" }, size: 10 }] } }];
// Highlight a footprint const highlight = layerView.footprintLayerView.highlight(feature);
// Create layer from footprint const footprint = layer.createFootprintFromLayer(selectedLayer); const newLayer = await layer.createLayerFromFootprint(footprint); map.add(newLayer);
CatalogLayer with LayerList
const layerList = document.querySelector("arcgis-layer-list");
layerList.catalogOptions = { selectionMode: "single" };
layerList.listItemCreatedFunction = (event) => { if (catalogUtils.isLayerFromCatalog(event.item.layer)) { event.item.actionsSections = [[{ title: "Add layer to map", icon: "add-layer", id: "add-layer" }]]; } };
MediaLayer
MediaLayer Basics
Create MediaLayer with Images
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);
Multiple Images
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 });
Georeferencing Methods
Extent and Rotation
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 });
Control Points (Corners)
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 });
Video Elements
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 GIF
// 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] });
Layer Configuration
Opacity and Blend Mode
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";
Element Opacity
// Individual element opacity imageElement.opacity = 0.8;
// Update dynamically document.getElementById("opacitySlider").addEventListener("input", (e) => { imageElement.opacity = e.target.value / 100; });
Managing Source Elements
// 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); });
Interactive Control Points
// 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;
Complete Example
<arcgis-map center="-89.93, 29.97" zoom="10"> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-map>
<script type="module"> 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"; import Map from "@arcgis/core/Map.js";
const viewElement = document.querySelector("arcgis-map");
// 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" });
viewElement.map = new Map({ basemap: "topo-vector", layers: [mediaLayer] }); </script>
Layer Comparison
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
CatalogLayer Collection of layers ArcGIS Catalog Service
MediaLayer Georeferenced images, video, GIFs Local/remote media
Reference Samples
-
layers-wms
-
Adding and configuring WMS layers
-
layers-wfs
-
Working with WFS layers
-
layers-ogcfeaturelayer
-
OGC Features API layer usage
-
layers-mapimagelayer
-
Dynamic MapImageLayer configuration
-
layers-cataloglayer
-
Using CatalogLayer to browse portal content
-
layers-medialayer-images
-
Displaying images with MediaLayer
-
layers-medialayer-video
-
Video playback in MediaLayer
-
layers-medialayer-control-points
-
Control point placement for media
-
layers-medialayer-interactive
-
Interactive media layer manipulation
Common Pitfalls
WFS 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
CatalogLayer portal: Must specify portal URL for non-ArcGIS Online items
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