autodesk-forgeautodesk-viewer

Move Model-Browser/Layer-Manager content into sidebar


I would like to move the Model-Browser and Layer-Manager tools into a fixed sidebar. I already moved the content of the properties tool in its dedicated tab in the sidebar. Now I am struggling to move the other two tools into their intended tabs. In particular i don't know how to access the data/functionality of those tools so I can display them in my Sidebar instead of their own existing panels.

Moving the properties into its own tab worked just fine, so I can always view them without interacting with the toolbar at the bottom.

Now I am stuck regarding the functionality of the 'DisplayModelBrowser()' and 'DisplayLayerManager()' functions.

This is my Code so far:

<head>
  <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
  <meta charset="utf-8">

  <link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css" type="text/css">
  <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>

  <style>
    body, html {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      display: flex;
      overflow: hidden;
    }
    #container {
      display: flex;
      width: 100%;
      height: 100%;
    }
    #forgeViewer {
      flex: 1;
      width: 75% ;
      height: 100%;
      background: #f0f0f0;
      flex-shrink: 0;
      z-index: 1;
      position:relative;
    }
    #propertyPanel {
      width: 25%;
      height: 100%;
      overflow-y: auto;
      border-left: 1px solid #ccc;
      padding: 10px;
      box-sizing: border-box;
      background: #fff;
      z-index: 2;
      position: relative;
    }
    #tabMenu {
      display: flex;
      border-bottom: 1px solid #ccc;
    }
    .tab {
      flex: 1;
      padding: 10px;
      cursor: pointer;
      text-align: center;
      background: #f0f0f0;
      border-right: 1px solid #ccc;
    }
    .tab:last-child {
      border-right: none;
    }
    .tab.active {
      background: #fff;
      font-weight: bold;
    }
    .tabContent {
      display: none;
    }
    .tabContent.active {
      display: block;
    }

    .adsk-viewing-viewer #toolbar-orbitTools{display:none!important}
    .adsk-viewing-viewer #toolbar-panTool{display:none!important}
    .adsk-viewing-viewer #toolbar-zoomTool{display:none!important}
    .adsk-viewing-viewer #toolbar-cameraSubmenuTool{display:none!important}
    .adsk-viewing-viewer #toolbar-settingsTool{display:none!important}
    .adsk-viewing-viewer #toolbar-fullscreenTool{display:none!important}
    .adsk-viewing-viewer #toolbar-propertiesTool{display:none!important}
    .adsk-viewing-viewer #toolbar-cameraSubmenuTool{display:none!important}

  </style>
</head>
<body>

<div id="container">
  <div id="forgeViewer"></div>
  <div id="propertyPanel">
    <div id="tabMenu">
      <div class="tab active" data-tab="properties">Properties</div>
      <div class="tab" data-tab="modelBrowser">Model Browser</div>
      <div class="tab" data-tab="layerManager">Layer Manager</div>
    </div>
    <div id="properties" class="tabContent active">
      <h2>Properties</h2>
      <div id="propertyContent"></div>
    </div>
    <div id="modelBrowser" class="tabContent">
      <h2>Model Browser</h2>
            <div id="modelBrowserContent">
        <div id="tree"></div>
      </div>
    </div>
    <div id="layerManager" class="tabContent">
      <h2>Layer Manager</h2>
      <div id="layerManagerContent"></div>
    </div>
  </div>
</div>

<script>
  var viewer;
  var options = {
    env: 'AutodeskProduction2',
    api: 'streamingV2',  // for models uploaded to EMEA change this option to 'streamingV2_EU'
    getAccessToken: function(onTokenReady) {
      var token = <MyToken>;
      var timeInSeconds = 3600; // Use value provided by APS Authentication (OAuth) API
      onTokenReady(token, timeInSeconds);
    }
  };

  Autodesk.Viewing.Initializer(options, function() {
    var htmlDiv = document.getElementById('forgeViewer');
    viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
    var startedCode = viewer.start();
    if (startedCode > 0) {
      console.error('Failed to create a Viewer: WebGL not supported.');
      return;
    }

    console.log('Initialization complete, loading a model next...');

    var documentId = <MyDocumentID>;
    Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);

    viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, function(event) {
      const dbIds = event.dbIdArray;
      if (dbIds.length > 0) {
        viewer.getProperties(dbIds[0], function(props) {
          displayProperties(props);
        });
      } else {
        clearProperties();
      }
    });
    setupTabSwitching()
  });

  function onDocumentLoadSuccess(viewerDocument) {
    var defaultModel = viewerDocument.getRoot().getDefaultGeometry();
    viewer.loadDocumentNode(viewerDocument, defaultModel);
    displayModelBrowser();
    displayLayerManager();
  }

  function onDocumentLoadFailure() {
    console.error('Failed fetching Forge manifest');
  }

  function displayProperties(props) {
    const propertyContent = document.getElementById('propertyContent');
    propertyContent.innerHTML = '';
    for (const prop of props.properties) {
      const propDiv = document.createElement('div');
      propDiv.innerHTML = `<strong>${prop.displayName}</strong>: ${prop.displayValue}`;
      propertyContent.appendChild(propDiv);
    }
  }

  function clearProperties() {
    const propertyContent = document.getElementById('propertyContent');
    propertyContent.innerHTML = '<p>No properties available</p>';
  }

 function displayModelBrowser() {
    const modelBrowserContent = document.getElementById('modelBrowserContent');
    modelBrowserContent.innerHTML = '';
    const modelTree = document.createElement('div');

    modelTree.innerHTML = new Autodesk.Viewing.UI.ModelStructurePanel(modelBrowserContent,"tree", "testTitle1");
    modelBrowserContent.appendChild(modelTree);
}

  function displayLayerManager() {
    const layerManagerContent = document.getElementById('modelBrowserContent');
    layerManagerContent.innerHTML = '';
    const layerList = document.createElement('div');
    // don't know  how to add the LayerManager functionality to the layerList div...
    layerManagerContent.appendChild(layerList);
  }

  function setupTabSwitching() {
    const tabs = document.querySelectorAll('.tab');
    const tabContents = document.querySelectorAll('.tabContent');

    tabs.forEach(tab => {
      tab.addEventListener('click', () => {
        tabs.forEach(t => t.classList.remove('active'));
        tabContents.forEach(tc => tc.classList.remove('active'));

        tab.classList.add('active');
        document.getElementById(tab.dataset.tab).classList.add('active');
      });
    });
  }

</script>
</body>


Solution

  • Displaying the model browser hierarchy and the layers in your own UI should be possible.

    The model browser hierarchy can be obtained in couple of ways. One option would be to use the Model Derivative service's GET Fetch Object Tree endpoint. Another option would be using the instance tree object provided by the Viewer SDK:

    const tree = viewer.model.getInstanceTree();
    const root = tree.getRootId();
    tree.enumNodeChildren(root, function (dbid) {
        const name = tree.getNodeName(dbid);
        const parent = tree.getNodeParentId(dbid);
        console.log(`I'm ${name} and my parent node is ${parent}`);
    }, true);
    

    Getting the layers is also possible using the Viewer SDK:

    const modelData = viewer.model.getData();
    console.log(modelData.layersRoot);