<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Integrated mesh modification | 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>
border-left: 5px solid rgb(252, 173, 88);
border-left: 5px solid rgb(157, 219, 129);
border-left: 5px solid rgb(133, 148, 209);
<arcgis-scene item-id="001bb7ee3ce44ae5a8a15bef72f4404a">
<arcgis-zoom slot="top-left"></arcgis-zoom>
<arcgis-navigation-toggle slot="top-left"></arcgis-navigation-toggle>
<arcgis-compass slot="top-left"> </arcgis-compass>
<calcite-panel heading="Integrated Mesh Modifications" slot="top-right">
<div slot="title">Mesh is being updated</div>
<calcite-block heading="Step 1: Create a modification polygon" expanded>
icon-start="edit-geometry"
label="Create modification polygon"
>Create polygon</calcite-button
<calcite-block heading="Step 2: Select modification type" expanded>
<calcite-segmented-control
<calcite-segmented-control-item class="clip" value="clip" checked>
<b>Clip </b> - removes selected area
</calcite-segmented-control-item>
<calcite-segmented-control-item class="mask" value="mask">
<b>Mask</b> - displays only selected area
</calcite-segmented-control-item>
<calcite-segmented-control-item class="replace" value="replace">
<b>Replace</b> - flattens selected area
</calcite-segmented-control-item>
</calcite-segmented-control>
const [GraphicsLayer, SketchViewModel, SceneModification, SceneModifications, reactiveUtils] =
"@arcgis/core/layers/GraphicsLayer.js",
"@arcgis/core/widgets/Sketch/SketchViewModel.js",
"@arcgis/core/layers/support/SceneModification.js",
"@arcgis/core/layers/support/SceneModifications.js",
"@arcgis/core/core/reactiveUtils.js",
// Query for the view HTML element and wait for it to be ready before accessing the map
const viewElement = document.querySelector("arcgis-scene");
await viewElement.viewOnReady();
// Create a graphics layer to store modification polygons and add them to the map
const graphicsLayer = new GraphicsLayer();
viewElement.map.add(graphicsLayer);
// Get the first IntegratedMeshLayer or IntegratedMesh3DTilesLayer found in the map
const imLayer = viewElement.map.layers.find((layer) => {
return layer.type === "integrated-mesh" || layer.type === "integrated-mesh-3dtiles";
* Update the UI based on the rendering status of the integrated mesh layer
* - wait for the integrated mesh layer view to be created before displaying the UI initially
* - use a loader UI to indicate when the integrated mesh layer is being updated after modification changes
const scrim = viewElement.querySelector("calcite-scrim");
viewElement.whenLayerView(imLayer).then((layerView) => {
document.querySelector("calcite-panel").style.display = "flex";
// hide loader overlay when layerView is done updating
() => !layerView.updating,
() => setLoaderVisibility(false),
// Polygon symbol used for sketching modifications
type: "polygon-3d", // autocasts as new PolygonSymbol3D()
type: "fill", // autocasts as new FillSymbol3DLayer()
color: [255, 255, 255, 0.8],
* Define the SketchViewModel
* - pass in the symbol for sketching polygons
* - set updateOnGraphicClick to false to handle the update process manually depending on the modification type
const sketchViewModel = new SketchViewModel({
polygonSymbol: sketchSymbol,
updateOnGraphicClick: false,
* Add a click event to the button to start sketching a polygon
* - disable the button while a sketch is in progress
const createModificationButton = document.getElementById("createModification");
createModificationButton.addEventListener("click", () => {
createModificationButton.setAttribute("disabled", "");
sketchViewModel.create("polygon");
* Listen to changes to the modification type in the UI
* - if a graphic is selected, update its modification type and the integrated mesh accordingly
const modificationControl = document.getElementById("modificationControl");
modificationControl.addEventListener("click", (event) => {
const graphic = sketchViewModel.updateGraphics.items[0];
updateModificationType(graphic, modificationControl.value);
* Listen to create events on the sketchViewModel
* - re-enable the create button if the create operation is canceled or completed
* - if the creation is completed, also set the graphic's modification type to update the integrated mesh
sketchViewModel.on("create", (event) => {
if (event.state === "cancel") {
createModificationButton.removeAttribute("disabled");
} else if (event.state === "complete") {
createModificationButton.removeAttribute("disabled");
updateModificationType(event.graphic, modificationControl.value);
* Listen on sketch-update
* - when the user selects or edits an existing modification polygon, update the integrated mesh accordingly
sketchViewModel.on("update", (event) => {
if (event.state === "active") {
// Listen to sketch-delete and update the integrated mesh modifications
sketchViewModel.on("delete", updateIntegratedMesh);
// Listen to click events in the view element to detect if the user would like to update an existing graphic in the scene
viewElement.addEventListener("arcgisViewClick", (event) => {
include: [graphicsLayer],
const result = response.results[0];
if (result?.type === "graphic") {
processSelectedGraphic(result.graphic);
* Enable the user to update a modification polygon after selecting a graphic in the scene
* - only if there is no polygon creation or update already in progress
* - update the modification control UI to the selected graphic's modification type
* - update the sketch symbol's "enableZ" value (z-value only used for "replace" modifications)
function processSelectedGraphic(graphic) {
if (sketchViewModel.state === "ready") {
const modificationType = graphic.attributes.modificationType;
modificationControl.querySelector(`[value=${modificationType}]`).checked = true;
sketchViewModel.update(graphic, {
enableZ: modificationType === "replace",
* Update/set a graphic's modification type
* - store it as an attribute on the graphic for future reference
* - update the graphic's symbolization and the integrated mesh accordingly
* - update the sketch symbol's "enableZ" value (z-value only used for "replace" modifications)
function updateModificationType(graphic, modificationType) {
graphic.attributes = { modificationType: modificationType };
replace: [133, 148, 209],
// Polygon symbol used to represent finalized modifications
type: "polygon-3d", // autocasts as new PolygonSymbol3D()
type: "fill", // autocasts as new FillSymbol3DLayer()
color: colors[modificationType],
sketchViewModel.update(graphic, {
enableZ: modificationType === "replace",
* Apply the modifications to the integrated mesh
* - create the modification collection using data from the graphics layer (geometry and modification type)
function updateIntegratedMesh() {
imLayer.modifications = new SceneModifications(
graphicsLayer.graphics.toArray().map((graphic) => {
return new SceneModification({
geometry: graphic.geometry,
type: graphic.attributes.modificationType,
// show loader overlay when modifications are changed
setLoaderVisibility(true);
// Show / hide loader overlay
function setLoaderVisibility(visible) {
scrim.style.display = visible ? "flex" : "none";