ArcGIS Advanced Widgets
Use this skill for specialized and advanced widgets including building exploration, indoor mapping, device GPS tracking, navigation aids, histograms, and media viewing.
Related skills: See arcgis-widgets-ui for basic widgets (Legend, LayerList, Search, Popup, etc.) and arcgis-map-tools for measurement, print, directions, and swipe tools.
Component Overview
Component Widget Class Purpose
arcgis-building-explorer
BuildingExplorer Explore building scene layers
arcgis-floor-filter
FloorFilter Filter indoor maps by floor
arcgis-oriented-imagery-viewer
OrientedImageryViewer View oriented imagery
arcgis-video-player
VideoPlayer Play video service feeds
arcgis-track
Track Track device GPS location
arcgis-locate
Locate Zoom to user location
arcgis-scale-bar
ScaleBar Display map scale bar
arcgis-compass
Compass Show north orientation
arcgis-navigation-toggle
NavigationToggle Switch between pan and rotate
arcgis-histogram-range-slider
HistogramRangeSlider Histogram with range selection
BuildingExplorer
Explore and filter BuildingSceneLayer data by disciplines and categories. Works only in 3D SceneView with BuildingSceneLayer.
BuildingExplorer Component
<arcgis-scene> <arcgis-building-explorer slot="top-right"></arcgis-building-explorer> </arcgis-scene>
<script type="module"> import BuildingSceneLayer from "@arcgis/core/layers/BuildingSceneLayer.js";
const sceneElement = document.querySelector("arcgis-scene"); const buildingExplorer = document.querySelector("arcgis-building-explorer");
await sceneElement.viewOnReady();
const buildingLayer = new BuildingSceneLayer({ url: "https://tiles.arcgis.com/tiles/V6ZHFr6zdgNZuVG0/arcgis/rest/services/BSL__4326__United_States__NewYork__702702_702_Main/SceneServer" });
sceneElement.map.add(buildingLayer); </script>
BuildingExplorer Widget (Core API)
import BuildingExplorer from "@arcgis/core/widgets/BuildingExplorer.js"; import BuildingSceneLayer from "@arcgis/core/layers/BuildingSceneLayer.js";
const buildingLayer = new BuildingSceneLayer({ url: "https://tiles.arcgis.com/tiles/V6ZHFr6zdgNZuVG0/arcgis/rest/services/BSL__4326__United_States__NewYork__702702_702_Main/SceneServer" });
map.add(buildingLayer);
const buildingExplorer = new BuildingExplorer({ view: view, layers: [buildingLayer] });
view.ui.add(buildingExplorer, "top-right");
BuildingExplorer with External Reference
<calcite-shell> <calcite-shell-panel slot="panel-start"> <calcite-panel heading="Building Explorer"> <arcgis-building-explorer reference-element="sceneView"></arcgis-building-explorer> </calcite-panel> </calcite-shell-panel>
<arcgis-scene id="sceneView"></arcgis-scene> </calcite-shell>
FloorFilter
Filter floor-aware web maps by facility and floor level. Requires a floor-aware web map that contains floor plan data with facility and level information.
FloorFilter Component
<arcgis-map item-id="YOUR_FLOOR_AWARE_WEBMAP_ID"> <arcgis-floor-filter slot="top-left"></arcgis-floor-filter> </arcgis-map>
FloorFilter Widget (Core API)
import FloorFilter from "@arcgis/core/widgets/FloorFilter.js"; import WebMap from "@arcgis/core/WebMap.js";
const webMap = new WebMap({ portalItem: { id: "YOUR_FLOOR_AWARE_WEBMAP_ID" } });
const view = new MapView({ container: "viewDiv", map: webMap });
await view.when();
const floorFilter = new FloorFilter({ view: view });
view.ui.add(floorFilter, "top-left");
FloorFilter with External Reference
<calcite-shell> <calcite-shell-panel slot="panel-start"> <calcite-panel heading="Floor Filter"> <arcgis-floor-filter reference-element="mapView"></arcgis-floor-filter> </calcite-panel> </calcite-shell-panel>
<arcgis-map id="mapView" item-id="YOUR_FLOOR_AWARE_WEBMAP_ID"> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-map> </calcite-shell>
FloorFilter Events
// Watch for floor level changes floorFilter.watch("level", (level) => { console.log("Selected level:", level); });
// Watch for facility changes floorFilter.watch("facility", (facility) => { console.log("Selected facility:", facility); });
// Watch for site changes floorFilter.watch("site", (site) => { console.log("Selected site:", site); });
OrientedImageryViewer
View and navigate oriented imagery captured in the field. Requires an OrientedImageryLayer.
OrientedImageryViewer Component
<arcgis-map> <arcgis-oriented-imagery-viewer slot="top-right"></arcgis-oriented-imagery-viewer> </arcgis-map>
<script type="module"> import OrientedImageryLayer from "@arcgis/core/layers/OrientedImageryLayer.js";
const viewElement = document.querySelector("arcgis-map"); const viewer = document.querySelector("arcgis-oriented-imagery-viewer");
await viewElement.viewOnReady();
const oiLayer = new OrientedImageryLayer({ url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/OrientedImagery/MapServer/0" });
viewElement.map.add(oiLayer); viewer.layer = oiLayer; </script>
OrientedImageryViewer Widget (Core API)
import OrientedImageryViewer from "@arcgis/core/widgets/OrientedImageryViewer.js"; import OrientedImageryLayer from "@arcgis/core/layers/OrientedImageryLayer.js";
const oiLayer = new OrientedImageryLayer({ url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/OrientedImagery/MapServer/0" });
map.add(oiLayer);
const viewer = new OrientedImageryViewer({ view: view, layer: oiLayer });
view.ui.add(viewer, "top-right");
OrientedImageryViewer with External Panel
<calcite-shell> <calcite-shell-panel slot="panel-end" width-scale="l"> <calcite-panel heading="Oriented Imagery"> <arcgis-oriented-imagery-viewer reference-element="mapView"></arcgis-oriented-imagery-viewer> </calcite-panel> </calcite-shell-panel>
<arcgis-map id="mapView" basemap="satellite"> <arcgis-zoom slot="top-left"></arcgis-zoom> </arcgis-map> </calcite-shell>
VideoPlayer
Play video feeds from a VideoLayer service. Requires a VideoLayer with an associated video service.
VideoPlayer Component
<arcgis-map> <arcgis-video-player slot="top-right"></arcgis-video-player> </arcgis-map>
<script type="module"> import VideoLayer from "@arcgis/core/layers/VideoLayer.js";
const viewElement = document.querySelector("arcgis-map"); const videoPlayer = document.querySelector("arcgis-video-player");
await viewElement.viewOnReady();
const videoLayer = new VideoLayer({ url: "https://your-server.com/arcgis/rest/services/VideoService/MapServer/0" });
viewElement.map.add(videoLayer); videoPlayer.layer = videoLayer; </script>
VideoPlayer Widget (Core API)
import VideoPlayer from "@arcgis/core/widgets/VideoPlayer.js"; import VideoLayer from "@arcgis/core/layers/VideoLayer.js";
const videoLayer = new VideoLayer({ url: "https://your-server.com/arcgis/rest/services/VideoService/MapServer/0" });
map.add(videoLayer);
const videoPlayer = new VideoPlayer({ view: view, layer: videoLayer });
view.ui.add(videoPlayer, "top-right");
Track
Track the user's device GPS location in real time. Requires HTTPS and user permission to access device location.
Track Component
<arcgis-map basemap="streets-navigation-vector" center="-118.24, 34.05" zoom="12"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-track slot="top-left"></arcgis-track> </arcgis-map>
Track Widget (Core API)
import Track from "@arcgis/core/widgets/Track.js"; import Graphic from "@arcgis/core/Graphic.js";
const track = new Track({ view: view, useHeadingEnabled: true, goToOverride: (view, options) => { options.target.scale = 1500; return view.goTo(options.target); } });
view.ui.add(track, "top-left");
// Start tracking programmatically track.start();
Track Events
// Track position updates track.on("track", (event) => { const { position } = event; console.log("Latitude:", position.coords.latitude); console.log("Longitude:", position.coords.longitude); console.log("Accuracy:", position.coords.accuracy); console.log("Heading:", position.coords.heading); console.log("Speed:", position.coords.speed); });
// Track errors track.on("track-error", (event) => { console.error("Tracking error:", event.error); });
Track with Custom Symbol
const track = new Track({ view: view, graphic: new Graphic({ symbol: { type: "simple-marker", size: 12, color: "blue", outline: { color: "white", width: 2 } } }) });
view.ui.add(track, "top-left");
Locate
Zoom to the user's current location. A single-action widget that finds the device location and pans the map to it.
Locate Component
<arcgis-map basemap="streets-navigation-vector" center="-118.24, 34.05" zoom="12"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-locate slot="top-left"></arcgis-locate> </arcgis-map>
Locate Widget (Core API)
import Locate from "@arcgis/core/widgets/Locate.js";
const locate = new Locate({ view: view, useHeadingEnabled: false, goToOverride: (view, options) => { options.target.scale = 1500; return view.goTo(options.target); } });
view.ui.add(locate, "top-left");
Locate Events
// Listen for locate event locate.on("locate", (event) => { console.log("Located at:", event.position.coords.latitude, event.position.coords.longitude); });
// Listen for errors locate.on("locate-error", (event) => { console.error("Location error:", event.error); });
Locate with Custom Symbol
const locate = new Locate({ view: view, graphic: new Graphic({ symbol: { type: "simple-marker", size: 14, color: "#00bfff", outline: { color: "white", width: 2 } } }) });
view.ui.add(locate, "top-left");
ScaleBar
Display a scale bar indicator showing map scale in metric or imperial units.
ScaleBar Component
<arcgis-map basemap="streets-navigation-vector" center="-118.24, 34.05" zoom="12"> <arcgis-scale-bar slot="bottom-left"></arcgis-scale-bar> </arcgis-map>
ScaleBar Widget (Core API)
import ScaleBar from "@arcgis/core/widgets/ScaleBar.js";
const scaleBar = new ScaleBar({ view: view, unit: "dual" // "metric", "imperial", "dual", "non-metric" });
view.ui.add(scaleBar, "bottom-left");
ScaleBar Styles
// Line style (default) const scaleBar = new ScaleBar({ view: view, unit: "dual", style: "line" // "line" or "ruler" });
// Ruler style const scaleBarRuler = new ScaleBar({ view: view, unit: "metric", style: "ruler" });
Compass
Display a compass indicator showing the current orientation of the map. Automatically appears when the map is rotated and hides when north is up.
Compass Component
<arcgis-map basemap="streets-navigation-vector" center="-118.24, 34.05" zoom="12"> <arcgis-compass slot="top-left"></arcgis-compass> </arcgis-map>
<!-- Also works with 3D scenes --> <arcgis-scene> <arcgis-compass slot="top-left"></arcgis-compass> </arcgis-scene>
Compass Widget (Core API)
import Compass from "@arcgis/core/widgets/Compass.js";
const compass = new Compass({ view: view });
view.ui.add(compass, "top-left");
Compass Behavior
// Clicking the compass resets the view rotation to north (0 degrees) // In 3D, it also resets the camera heading
// Programmatically reset rotation view.rotation = 0; // 2D // or view.goTo({ heading: 0 }); // 3D
NavigationToggle
Switch between pan and rotate navigation modes. Primarily useful in 3D SceneView.
NavigationToggle Component
<arcgis-scene> <arcgis-navigation-toggle slot="top-left"></arcgis-navigation-toggle> </arcgis-scene>
NavigationToggle Widget (Core API)
import NavigationToggle from "@arcgis/core/widgets/NavigationToggle.js";
const navigationToggle = new NavigationToggle({ view: view });
view.ui.add(navigationToggle, "top-left");
NavigationToggle Layout
// Horizontal layout (default) const navigationToggle = new NavigationToggle({ view: view, layout: "horizontal" // "horizontal" or "vertical" });
// Vertical layout const navigationToggleVertical = new NavigationToggle({ view: view, layout: "vertical" });
HistogramRangeSlider
Display a histogram chart with adjustable range slider handles for filtering data. Commonly used with smart mapping to visualize data distribution and filter by value ranges.
HistogramRangeSlider (Core API)
import HistogramRangeSlider from "@arcgis/core/widgets/HistogramRangeSlider.js"; import * as histogram from "@arcgis/core/smartMapping/statistics/histogram.js";
// Generate histogram bins from a layer field const histogramResult = await histogram.histogram({ layer: featureLayer, field: "population", numBins: 30 });
const slider = new HistogramRangeSlider({ bins: histogramResult.bins, min: histogramResult.minValue, max: histogramResult.maxValue, values: [histogramResult.minValue, histogramResult.maxValue], excludedBarColor: "#d7d7d7", rangeType: "between", container: "sliderDiv" });
HistogramRangeSlider with Layer Filtering
import HistogramRangeSlider from "@arcgis/core/widgets/HistogramRangeSlider.js"; import * as histogram from "@arcgis/core/smartMapping/statistics/histogram.js";
const fieldName = "median_income";
const histogramResult = await histogram.histogram({ layer: featureLayer, field: fieldName, numBins: 50 });
const slider = new HistogramRangeSlider({ bins: histogramResult.bins, min: histogramResult.minValue, max: histogramResult.maxValue, values: [histogramResult.minValue, histogramResult.maxValue], excludedBarColor: "#d7d7d7", rangeType: "between", labelFormatFunction: (value) => { return "$" + Math.round(value).toLocaleString(); }, container: "sliderDiv" });
// Filter layer when slider values change
slider.on(["thumb-change", "thumb-drag", "segment-drag"], () => {
const [min, max] = slider.values;
featureLayer.definitionExpression =
${fieldName} >= ${min} AND ${fieldName} <= ${max};
});
HistogramRangeSlider with Smart Mapping
import HistogramRangeSlider from "@arcgis/core/widgets/HistogramRangeSlider.js"; import * as histogram from "@arcgis/core/smartMapping/statistics/histogram.js"; import * as colorRendererCreator from "@arcgis/core/smartMapping/renderers/color.js";
// Create color renderer and histogram together const colorParams = { layer: featureLayer, field: "population", view: view };
const [rendererResponse, histogramResult] = await Promise.all([ colorRendererCreator.createContinuousRenderer(colorParams), histogram.histogram({ layer: featureLayer, field: "population", numBins: 30 }) ]);
featureLayer.renderer = rendererResponse.renderer;
const slider = new HistogramRangeSlider({ bins: histogramResult.bins, min: histogramResult.minValue, max: histogramResult.maxValue, values: [histogramResult.minValue, histogramResult.maxValue], excludedBarColor: "#d7d7d7", rangeType: "between", container: "sliderDiv" });
// Update renderer stops when slider changes slider.on(["thumb-change", "thumb-drag", "segment-drag"], () => { const renderer = featureLayer.renderer.clone(); const colorVariable = renderer.visualVariables[0]; colorVariable.stops = [ { value: slider.values[0], color: colorVariable.stops[0].color }, { value: slider.values[1], color: colorVariable.stops[colorVariable.stops.length - 1].color } ]; featureLayer.renderer = renderer; });
HistogramRangeSlider Configuration
const slider = new HistogramRangeSlider({ bins: histogramResult.bins, min: 0, max: 100, values: [20, 80],
// Range type: "between", "not-between", "at-least", "at-most", "equal", "not-equal" rangeType: "between",
// Visual options barCreatedFunction: (index, element) => { // Customize individual bars element.setAttribute("fill", index % 2 === 0 ? "#007ac2" : "#005a8e"); }, excludedBarColor: "#d7d7d7", includedBarColor: "#007ac2",
// Data line overlays dataLines: [ { value: 50, label: "Average" } ], dataLineCreatedFunction: (element, label, index) => { element.setAttribute("stroke", "red"); },
// Precision for displayed values precision: 2,
container: "sliderDiv" });
Combining Multiple Advanced Widgets
Complete 3D Building Explorer App
<!DOCTYPE html> <html> <head> <script type="module" src="https://js.arcgis.com/calcite-components/3.3.3/calcite.esm.js"></script> <script src="https://js.arcgis.com/4.34/"></script> <script type="module" src="https://js.arcgis.com/4.34/map-components/"></script> <style> html, body { height: 100%; margin: 0; } </style> </head> <body> <calcite-shell> <calcite-navigation slot="header"> <calcite-navigation-logo slot="logo" heading="Building Explorer"></calcite-navigation-logo> </calcite-navigation>
<calcite-shell-panel slot="panel-start">
<calcite-panel heading="Building">
<arcgis-building-explorer reference-element="sceneView"></arcgis-building-explorer>
</calcite-panel>
</calcite-shell-panel>
<arcgis-scene id="sceneView">
<arcgis-zoom slot="top-left"></arcgis-zoom>
<arcgis-compass slot="top-left"></arcgis-compass>
<arcgis-navigation-toggle slot="top-left"></arcgis-navigation-toggle>
<arcgis-scale-bar slot="bottom-left"></arcgis-scale-bar>
</arcgis-scene>
</calcite-shell>
<script type="module"> import BuildingSceneLayer from "@arcgis/core/layers/BuildingSceneLayer.js"; import Map from "@arcgis/core/Map.js";
const sceneElement = document.querySelector("arcgis-scene");
await sceneElement.viewOnReady();
const buildingLayer = new BuildingSceneLayer({
url: "https://tiles.arcgis.com/tiles/V6ZHFr6zdgNZuVG0/arcgis/rest/services/BSL__4326__United_States__NewYork__702702_702_Main/SceneServer"
});
sceneElement.map.add(buildingLayer);
</script> </body> </html>
Indoor Mapping with Floor Filter and Track
<arcgis-map item-id="YOUR_FLOOR_AWARE_WEBMAP_ID"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-floor-filter slot="top-left"></arcgis-floor-filter> <arcgis-locate slot="top-left"></arcgis-locate> <arcgis-track slot="top-left"></arcgis-track> <arcgis-scale-bar slot="bottom-left"></arcgis-scale-bar> </arcgis-map>
Navigation Widgets in 3D Scene
<arcgis-scene basemap="satellite"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-compass slot="top-left"></arcgis-compass> <arcgis-navigation-toggle slot="top-left"></arcgis-navigation-toggle> <arcgis-locate slot="top-left"></arcgis-locate> <arcgis-scale-bar slot="bottom-left"></arcgis-scale-bar> </arcgis-scene>
Reference Samples
-
building-explorer
-
Exploring building scene layers
-
floor-filter
-
Indoor floor filtering
-
oriented-imagery
-
Oriented imagery viewer
-
track
-
GPS tracking widget
-
widgets-compass
-
Compass widget usage
-
widgets-scalebar
-
ScaleBar widget configuration
-
histogram-range-slider
-
Histogram range slider for filtering
Common Pitfalls
Track widget requires HTTPS: The Track and Locate widgets use the Geolocation API, which only works on HTTPS origins (or localhost). They will fail silently on HTTP.
FloorFilter needs floor-aware web map: The FloorFilter widget requires a web map configured with floor-aware data including facility and level information. A standard web map without floor plan data will not display anything.
BuildingExplorer only works with BuildingSceneLayer in SceneView: BuildingExplorer requires both a 3D SceneView (not MapView) and at least one BuildingSceneLayer in the map. It will not work with other layer types or in 2D.
HistogramRangeSlider needs properly configured bins array: The bins property must be an array of objects with minValue , maxValue , and count properties. Use the smartMapping/statistics/histogram module to generate valid bins from layer data.
Missing reference-element attribute on components: When placing advanced widget components outside their parent map or scene element (e.g., in a Calcite side panel), you must set the reference-element attribute to the ID of the map/scene element. Without it, the widget cannot connect to the view.