Save a web scene

Explore in the sandboxView live

This sample demonstrates how to save a WebScene to a Portal for ArcGIS item by either creating a new item or overwriting an existing item that has been loaded from a Portal for ArcGIS item.

Saving a web scene is easy. All that's required is a WebScene and a valid Portal to save the scene to.

Saving to a new item

Create a new empty WebScene instance and a Portal instance where the WebScene should be saved to. Loading the Portal will trigger user authentication, and if successful the item will be saved to the given Portal.

Load a basic webscene
                                                                                                                                                                       
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>Save a web scene | Sample | ArcGIS API for JavaScript 4.19</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.19/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.19/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }

      #sidebarDiv {
        width: 240px;
        padding: 10px;
        height: 200px;
      }

      #overlayDiv {
        z-index: 1;
        position: absolute;
        margin: auto auto;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        width: 280px;
        height: 180px;
        padding: 10px;
        background-color: white;
        border: 1px solid grey;
        visibility: hidden;
      }

      input[type="text"] {
        width: 100%;
      }
    </style>

    <script>
      require([
        "esri/views/SceneView",
        "esri/WebScene",
        "esri/widgets/BasemapGallery",
        "esri/widgets/Expand"
      ], (SceneView, WebScene, BasemapGallery, Expand) => {


        /************************************************************
         * Creates a new WebScene instance. A WebScene can reference
         * a PortalItem ID that represents a WebScene saved to
         * arcgis.com or an on-premise portal.
         *
         * To load a WebScene from an on-premise portal, set the portal
         * url with esriConfig.portalUrl (see above).
         ************************************************************/
        const scene = new WebScene({
          portalItem: {
            // autocasts as new PortalItem()
            id: "90e3c30bdbbe4886a94f75c2cdd7edce"
          }
        });

        /************************************************************
         * Set the WebScene instance to the map property in a
         * SceneView.
         ************************************************************/
        const view = new SceneView({
          map: scene,
          container: "viewDiv"
        });


        // add basemapGallery widgets
        view.ui.add(
          [
            new Expand({
              content: new BasemapGallery({
                view: view
              }),
              view: view
            })
          ],
          "top-left"
        );

        view.when(() => {
          // When the webscene and view resolve, display the webscene's
          // new title in the Div
          const title = document.getElementById("webSceneTitle");
          const save = document.getElementById("saveWebScene");
          save.disabled = false;
          save.addEventListener("click", () => {
            document.getElementById("saveWebScene").disabled = true;
            document.getElementById("saveWebScene").classList.add("esri-button--secondary");

            // item automatically casts to a PortalItem instance by saveAs
            const item = {
              title: title.value
            };


            // Update properties of the WebScene related to the view.
            // This should be called just before saving a webscene.
            scene.updateFrom(view).then(() => {
              scene
                .saveAs(item)
                // Saved successfully
                .then((item) => {
                  // link to the newly-created web scene item
                  const itemPageUrl = item.portal.url + "/home/item.html?id=" + item.id;
                  const link = '<a target="_blank" href="' + itemPageUrl + '">' + title.value + "</a>";

                  statusMessage("Save WebScene", "<br> Successfully saved as <i>" + link + "</i>");
                })
                // Save didn't work correctly
                .catch((error) => {
                  statusMessage("Save WebScene", "<br> Error " + error);
                });
            });

          });

          const overlay = document.getElementById("overlayDiv");
          const ok = overlay.getElementsByTagName("input")[0];

          function statusMessage(head, info) {
            document.getElementById("saveWebScene").classList.remove("esri-button--secondary");
            document.getElementById("saveWebScene").disabled = false;
            document.getElementById("head").innerHTML = head;
            document.getElementById("info").innerHTML = info;
            overlay.style.visibility = "visible";
          }

          ok.addEventListener("click", () => {
            overlay.style.visibility = "hidden";
          });

          view.ui.add("sidebarDiv", "top-right");
        });
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div id="sidebarDiv" class="esri-widget">
      <h4 class="esri-heading">Save WebScene</h4>
      <label class="esri-feature-form__label">Title</label>
      <input id="webSceneTitle" type="text" class="esri-input" value="WebScene Saving Sample" /><br /><br />
      <input id="saveWebScene" type="button" value="Save" disabled class="esri-button" />
    </div>
    <div id="overlayDiv" class="esri-widget">
      <h4 class="esri-heading" id="head"></h4>
      <label id="info"></label><br /><br />
      <input type="button" value="OK" class="esri-button" />
    </div>
  </body>
</html>

In case the scene is added to a view, the scene can only be saved once the view properties are updated on the scene:

Save a webscene
                                                                                                                                                                       
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>Save a web scene | Sample | ArcGIS API for JavaScript 4.19</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.19/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.19/"></script>

    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }

      #sidebarDiv {
        width: 240px;
        padding: 10px;
        height: 200px;
      }

      #overlayDiv {
        z-index: 1;
        position: absolute;
        margin: auto auto;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        width: 280px;
        height: 180px;
        padding: 10px;
        background-color: white;
        border: 1px solid grey;
        visibility: hidden;
      }

      input[type="text"] {
        width: 100%;
      }
    </style>

    <script>
      require([
        "esri/views/SceneView",
        "esri/WebScene",
        "esri/widgets/BasemapGallery",
        "esri/widgets/Expand"
      ], (SceneView, WebScene, BasemapGallery, Expand) => {


        /************************************************************
         * Creates a new WebScene instance. A WebScene can reference
         * a PortalItem ID that represents a WebScene saved to
         * arcgis.com or an on-premise portal.
         *
         * To load a WebScene from an on-premise portal, set the portal
         * url with esriConfig.portalUrl (see above).
         ************************************************************/
        const scene = new WebScene({
          portalItem: {
            // autocasts as new PortalItem()
            id: "90e3c30bdbbe4886a94f75c2cdd7edce"
          }
        });

        /************************************************************
         * Set the WebScene instance to the map property in a
         * SceneView.
         ************************************************************/
        const view = new SceneView({
          map: scene,
          container: "viewDiv"
        });


        // add basemapGallery widgets
        view.ui.add(
          [
            new Expand({
              content: new BasemapGallery({
                view: view
              }),
              view: view
            })
          ],
          "top-left"
        );

        view.when(() => {
          // When the webscene and view resolve, display the webscene's
          // new title in the Div
          const title = document.getElementById("webSceneTitle");
          const save = document.getElementById("saveWebScene");
          save.disabled = false;
          save.addEventListener("click", () => {
            document.getElementById("saveWebScene").disabled = true;
            document.getElementById("saveWebScene").classList.add("esri-button--secondary");

            // item automatically casts to a PortalItem instance by saveAs
            const item = {
              title: title.value
            };


            // Update properties of the WebScene related to the view.
            // This should be called just before saving a webscene.
            scene.updateFrom(view).then(() => {
              scene
                .saveAs(item)
                // Saved successfully
                .then((item) => {
                  // link to the newly-created web scene item
                  const itemPageUrl = item.portal.url + "/home/item.html?id=" + item.id;
                  const link = '<a target="_blank" href="' + itemPageUrl + '">' + title.value + "</a>";

                  statusMessage("Save WebScene", "<br> Successfully saved as <i>" + link + "</i>");
                })
                // Save didn't work correctly
                .catch((error) => {
                  statusMessage("Save WebScene", "<br> Error " + error);
                });
            });

          });

          const overlay = document.getElementById("overlayDiv");
          const ok = overlay.getElementsByTagName("input")[0];

          function statusMessage(head, info) {
            document.getElementById("saveWebScene").classList.remove("esri-button--secondary");
            document.getElementById("saveWebScene").disabled = false;
            document.getElementById("head").innerHTML = head;
            document.getElementById("info").innerHTML = info;
            overlay.style.visibility = "visible";
          }

          ok.addEventListener("click", () => {
            overlay.style.visibility = "hidden";
          });

          view.ui.add("sidebarDiv", "top-right");
        });
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div id="sidebarDiv" class="esri-widget">
      <h4 class="esri-heading">Save WebScene</h4>
      <label class="esri-feature-form__label">Title</label>
      <input id="webSceneTitle" type="text" class="esri-input" value="WebScene Saving Sample" /><br /><br />
      <input id="saveWebScene" type="button" value="Save" disabled class="esri-button" />
    </div>
    <div id="overlayDiv" class="esri-widget">
      <h4 class="esri-heading" id="head"></h4>
      <label id="info"></label><br /><br />
      <input type="button" value="OK" class="esri-button" />
    </div>
  </body>
</html>

Overwriting an existing item

Create a new WebScene instance and set the portal item ID inside the portalItem property of the WebScene. Loading the Portal will trigger user authentication, and if successful the item will be saved to the given Portal.

                                
/************************************************************
 * Creates a new WebScene instance. A WebScene can reference
 * a PortalItem ID that represents a WebScene saved to
 * arcgis.com or an on-premise portal.
 ************************************************************/
const scene = new WebScene({
  portalItem: {
    id: "3a9976baef9240ab8645ee25c7e9c096"
  }
});

/************************************************************
 * Create a new Portal instance and request immediate user
 * authentication.
 ************************************************************/
const portal = new Portal({
  authMode: "immediate"
});

/************************************************************
 * Loading of either the scene or the portal will trigger
 * authentication and once both Promises are resolved, the
 * Webscene will be saved thereby overwriting the previously
 * loaded PortalItem with any changes that have occurred.
 ************************************************************/
scene.load().then(() => {
  portal.load().then(() => {
    scene.portalItem.title = "Modified WebScene";
    scene.portalItem.portal = portal;
    scene.save();
  });
});

To use load or save items from an on-premise portal, set the URL of the portal in esriConfig.portalUrl.

Please refer to the ArcGIS Organization portals for information on how the ArcGIS API for JavaScript makes use of working with portal items.