9 Nov 2017

Switching Viewables in the Forge Viewer

Default blog image

    Here is a quick post to document a feature I just added to my main Forge web site: https://forge-rcdb.autodesk.io. It's about providing a UI to let the user switch between multiple views (or viewable items) contained in a single document. The A360 viewer offers this possibility but it is not part of the viewer API. Look no further I'm bringing that to you at no cost ;)

    Listing and switching between viewable items in a Forge document is actually pretty straightforward, you will mainly have to deal with wrapping a nice UI around it to let the user select which item has to be displayed. To see how to include or exclude views from a document before uploading to Forge, take a look at this article: How to Export Multiple 3D Views.

    Let's dive into the code (all my examples below are using ES6 and async/await + React for the UI part):

I - Load a document from a translated URN

/////////////////////////////////////////////////////////
// Load a document from URN
//
/////////////////////////////////////////////////////////
static loadDocument (urn) {

  return new Promise((resolve, reject) => {

    const paramUrn = !urn.startsWith('urn:')
      ? 'urn:' + urn
      : urn

    Autodesk.Viewing.Document.load(paramUrn, (doc) => {

      resolve (doc)

    }, (error) => {

      reject (error)
    })
  })
}

II - Get the list of all viewable items in the loaded document

/////////////////////////////////////////////////////////
// Return viewables
//
/////////////////////////////////////////////////////////
static getViewableItems (doc, roles = ['3d', '2d']) {

  const rootItem = doc.getRootItem()

  let items = []

  const roleArray = roles
    ? (Array.isArray(roles) ? roles : [roles])
    : []

  roleArray.forEach((role) => {

    items = [ ...items,
      ...Autodesk.Viewing.Document.getSubItemsWithProperties(
        rootItem, { type: 'geometry', role }, true) ]
  })

  return items
}

III - Load the selected viewable

    First we unload the current model, this code assumes we have a model loaded at the time user selects a different item, and simply loads a new one by obtaining its path. I am using viewer.tearDown which ensure memory of the current model is being released. This also supports switching from a 3D model to a 2D one and reciprocally. You can abstract away the React code which is specific to my app here.

/////////////////////////////////////////////////////////
// Load the selected viewable
//
/////////////////////////////////////////////////////////
onItemSelected (item) {

  const {activeItem} = this.react.getState()

  if (item.guid !== activeItem.guid) {

    this.viewer.tearDown()

    this.viewer.start()

    const path =
      this.viewerDocument.getViewablePath(item)

    this.viewer.loadModel(path)

    this.react.setState({
      activeItem: item
    })
  }
}

    That's pretty much all you need to know, the rest of the implementation was purely React and css work to create a nice UI around it. That feature is now available by default for any model with more than one view that you upload to the gallery section of my app: https://forge-rcdb.autodesk.io/gallery

    See the code in action below, or refer to the implementation: Viewing.Extension.ViewableSelector.js

Related Article