21 Jun 2017

Navigating between 2D views

Default blog image

All elements of the model have the __viewable_in__ property, have you used it before? It can be used to determine where a specific element is also viewable, which is handy to navigate between sheets (e.g. for Revit files). The following video show how it could work:

The following code shows the extension, note it's not performing error check for simplicity. The main idea is to keep a record of all 2D viewables, then on each element selected, list the sheets based on the __viewables_in__ property, allowing to change between these views.

AutodeskNamespace('Autodesk.Sample.Navigator');

Autodesk.Sample.Navigator = function (viewer, options) {
  Autodesk.Viewing.Extension.call(this, viewer, options);

  var _self = this;

  ///////////////////////////////////////////////////////////////////////////
  // load callback
  ///////////////////////////////////////////////////////////////////////////
  _self.load = function () {
    var _panel = null;
    var _panelGuid = newGUID();
    var viewables;

    viewables = viewerApp.bubble.search({'type': 'geometry', 'role': '2d'});

    createUI = function () {
      // Button 1
      var button1 = new Autodesk.Viewing.UI.Button('toolbarNavigator');
      button1.onClick = function (e) {
        if (_panel == null) {
          _panel = new Autodesk.Viewing.UI.DockingPanel(viewer.container, 'NavigatorPanel', 'Navigator');
          _panel.container.style.top = "10px";
          _panel.container.style.left = "10px";
          _panel.container.style.width = "auto";
          _panel.container.style.height = "auto";
          _panel.container.style.resize = "auto";

          var div = document.createElement('div');
          div.style.margin = '5px';
          div.id = _panelGuid;
          _panel.container.appendChild(div);


          var selectViewable = document.createElement('select');
          selectViewable.id = 'viewables2dList';

          viewables.forEach(function (view2d, index) {
            var option = document.createElement("option");
            option.value = index;
            option.text = view2d.data.name;
            selectViewable.appendChild(option);
          });
          div.appendChild(selectViewable);
          $('#viewables2dList').change(function () {
            viewerApp.selectItem(viewables[this.value], onItemLoadSuccess, onItemLoadFail);
          });
        }

        // show docking panel
        _panel.setVisible(true);

        viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, function (selected) {
          var ul = $('#' + _panelGuid + 'ul');
          if (ul) ul.remove();
          if (selected.dbIdArray.length == 0) return;

          ul = document.createElement('ul');
          ul.id = _panelGuid + 'ul'
          ul.className = 'list-group';
          div.appendChild(ul);
          viewer.model.getProperties(selected.dbIdArray[0], function (props) {
            var liTop = document.createElement('li');
            liTop.className = 'list-group-item';
            liTop.innerText = 'Also viewable on the following sheets:';
            ul.append(liTop);

            props.properties.forEach(function (prop) {
              if (prop.displayCategory === '__viewable_in__')
                viewables.forEach(function (view2d) {
                  var li = document.createElement('li');
                  if (view2d.data.guid === prop.displayValue) {
                    li.className = 'list-group-item PCitem';
                    li.id = view2d.data.guid;
                    li.onclick = onSelectView;
                    li.innerText = view2d.data.name;
                    ul.append(li);
                  }
                });
            })
          });
        });
      };
      button1.addClass('toolbarNavigatorButton');
      button1.setToolTip('Check extended data');

      // SubToolbar
      this.subToolbar = new Autodesk.Viewing.UI.ControlGroup('myAppGroup1');
      this.subToolbar.addControl(button1);

      viewer.toolbar.addControl(this.subToolbar);
    };

    createUI();

    console.log('MyExtension loaded');

    var elementToSelect;

    onSelectView = function (e) {
      var id = e.srcElement.id;
      viewables.forEach(function (view2d, index) {
        if (view2d.data.guid === id) {
          var selectedIds = viewer.getSelection();
          viewerApp.selectItem(view2d.data, function () {
            elementToSelect = selectedIds;
          }, onItemLoadFail);
        }
      });
    };

    viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, function () {
      if (elementToSelect) {
        viewer.select(elementToSelect);
        //viewer.fitToView(elementToSelect);
      }
      elementToSelect = null;
      createUI();
    });
    return true;
  };


  ///////////////////////////////////////////////////////////////////////////
  // unload callback
  ///////////////////////////////////////////////////////////////////////////
  _self.unload = function () {
    // ToDo: prepare to unload the extension

    console.log('MyExtension unloaded');
    return true;
  };
};

Autodesk.Sample.Navigator.prototype = Object.create(Autodesk.Viewing.Extension.prototype);

Autodesk.Sample.Navigator.prototype.constructor = Autodesk.Sample.Navigator;

Autodesk.Viewing.theExtensionManager.registerExtension('Autodesk.Sample.Navigator', Autodesk.Sample.Navigator);

function newGUID() {
  var d = new Date().getTime();
  var guid = 'xxxx-xxxx-xxxx-xxxx-xxxx'.replace(
    /[xy]/g,
    function (c) {
      var r = (d + Math.random() * 16) % 16 | 0;
      d = Math.floor(d / 16);
      return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
    });

  return guid;
};

The extension is self-contained, so just load the new button should appear. You'll need to define the class for it, something like:

.toolbarNavigatorButton {
    background-image: url(/img/Navigator.png);
    background-size: 20px;
    background-repeat: no-repeat;
    background-position: center;
}

.PCitem{
    cursor: pointer;
    background: none;
    color: #FFFFFF;
}

 

Related Article