<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Length dimensioning | Sample | ArcGIS Maps SDK for JavaScript</title>
<!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
<script type="module" src="https://js.arcgis.com/5.0/"></script>
font-family: var(--calcite-font-family);
<arcgis-scene id="viewElement" item-id="313c4a9ea86546b3a445a3d159e90350">
<arcgis-zoom slot="top-left"> </arcgis-zoom>
<arcgis-navigation-toggle slot="top-left"> </arcgis-navigation-toggle>
<arcgis-compass slot="top-left"> </arcgis-compass>
<calcite-card id="dimensioningDiv" slot="top-right">
<calcite-label layout="inline-space-between"> Floor </calcite-label>
value-labels-display="always"></arcgis-slider>
<calcite-button id="dimensioningToggleButton" class="button">Add your own</calcite-button>
<arcgis-expand expand-icon="layers" slot="bottom-right">
<arcgis-layer-list></arcgis-layer-list>
const [DimensionAnalysis, DimensionLayer, GroupLayer, LengthDimension, Point, promiseUtils] =
"@arcgis/core/analysis/DimensionAnalysis.js",
"@arcgis/core/layers/DimensionLayer.js",
"@arcgis/core/layers/GroupLayer.js",
"@arcgis/core/analysis/LengthDimension.js",
"@arcgis/core/geometry/Point.js",
"@arcgis/core/core/promiseUtils.js",
/**********************************************
* Component and view setup
*********************************************/
const viewElement = document.getElementById("viewElement");
await viewElement.viewOnReady();
/**********************************************
*********************************************/
const programmaticDimensionLayer = new DimensionLayer({
title: "Programmatic dimensions",
source: new DimensionAnalysis({
textBackgroundColor: [0, 0, 0, 0.6],
const interactiveDimensionAnalysis = new DimensionAnalysis({
textBackgroundColor: [19, 70, 148, 0.8],
const interactiveDimensionLayer = new DimensionLayer({
title: "Interactive dimensions",
source: interactiveDimensionAnalysis,
viewElement.map.addMany([programmaticDimensionLayer, interactiveDimensionLayer]);
const interactiveDimensionLayerView =
await viewElement.whenLayerView(interactiveDimensionLayer);
const apartmentsLayer = viewElement.map.layers.find(
(layer) => layer.title === "Stadskantoor",
apartmentsLayer.outFields = ["*"];
/**********************************************
*********************************************/
// add the building and dimensioning into a grouplayer
const groupLayer = new GroupLayer({
layers: [apartmentsLayer, programmaticDimensionLayer],
title: "Building with dimensions",
viewElement.map.add(groupLayer);
const apartmentsLayerView = await viewElement.whenLayerView(apartmentsLayer);
/**********************************************
*********************************************/
function filterByFloorNumber(selectedFloor) {
apartmentsLayerView.filter = {
where: `Level_ <= '${selectedFloor}'`,
/**********************************************
* Dimension creation functions
*********************************************/
// Get all the aparments polygon features to use for dimensioning
const apartmentFeatures = (await apartmentsLayer.queryFeatures()).features;
// Function to show the dimensions on a specific floor
function showDimensionsFloor(selectedFloor) {
programmaticDimensionLayer.source.dimensions.removeAll();
const polygonsForDimensioning = apartmentFeatures.filter((item) => {
return item.attributes.Level_ === selectedFloor;
showElevationDimensions(polygonsForDimensioning[0]);
polygonsForDimensioning.forEach(showEdgeDimensions);
spatialReference: viewElement.spatialReference,
// Function to show the dimensioning on the elevation
function showElevationDimensions(feature) {
programmaticDimensionLayer.source.dimensions.push(
spatialReference: groundPoint.spatialReference,
z: feature.attributes["Elevation"] + feature.attributes["FloorHeight"],
// Function to show the dimensioning of the polygon edges
function showEdgeDimensions(feature) {
const firstRing = feature.geometry.rings[0];
for (let i = 0; i < firstRing.length - 1; i++) {
// only show the dimensions on 2 sides of the polygon
if (feature.attributes["Level_"] > 14) {
} else if (feature.attributes["Level_"] > 8) {
const vertex = firstRing[i];
const nextVertex = firstRing[i + 1];
programmaticDimensionLayer.source.dimensions.push(
spatialReference: viewElement.spatialReference,
z: feature.attributes["Elevation"] + feature.attributes["FloorHeight"],
spatialReference: viewElement.spatialReference,
z: feature.attributes["Elevation"] + feature.attributes["FloorHeight"],
/**********************************************
* Interactive dimensioning
*********************************************/
const dimensioningToggleButton = document.getElementById("dimensioningToggleButton");
let abortController = null;
async function startInteractivePlacement() {
abortController?.abort();
abortController = new AbortController();
const { signal } = abortController;
// While the signal is not aborted, keep placing dimensions interactively
while (!signal.aborted) {
await interactiveDimensionLayerView.place({ signal });
// This is used to handle the case when the dimension placement is aborted.
if (!promiseUtils.isAbortError(error)) {
// Operation was aborted. Note that we only clear the abortController
// if this operation is the latest one. If another operation was started
// in the meantime, there will be a different abort controller and signal.
if (abortController && abortController.signal === signal) {
interactiveDimensionLayerView.interactive = false;
dimensioningToggleButton.addEventListener("click", () => {
// If there is an ongoing interactive placement (abortController exists), abort it.
// Otherwise, start a new interactive placement.
startInteractivePlacement();
/**********************************************
* Initial dimension display
*********************************************/
// Show the dimensioning on floor 24
document.getElementById("floorSlider").addEventListener("arcgisChange", async (event) => {
const selectedFloor = event.target.values[0];
showDimensionsFloor(selectedFloor);
filterByFloorNumber(selectedFloor);
/**********************************************
*********************************************/
// Update the UI component according to whether there is a pending operation.
const placing = abortController != null;
dimensioningToggleButton.appearance = placing ? "outline" : "solid";
dimensioningToggleButton.textContent = placing ? "Cancel" : "Add your own";