28 Feb 2018

Extension Skeleton: Toolbar & Docking Panel

Creating an extension is the recomended approach to add custom code to Viewer. And in most cases we want some UI for it: buttons & panels. This skeleton code shows how to create an extension with that. 

Docking Panel

First let's create a Docking Panel using the Autodesk.Viewing.UI.DockingPanel UI. Note the main container hosts the panel and the child div is where we should place the content. The CSS class used here allow themes on Viewer 4+.

// *******************************************
// My Awesome (Docking) Panel
// *******************************************
function MyAwesomePanel(viewer, container, id, title, options) {
    this.viewer = viewer;
    Autodesk.Viewing.UI.DockingPanel.call(this, container, id, title, options);

    // the style of the docking panel
    // use this built-in style to support Themes on Viewer 4+
    this.container.classList.add('docking-panel-container-solid-color-a');
    this.container.style.top = "10px";
    this.container.style.left = "10px";
    this.container.style.width = "auto";
    this.container.style.height = "auto";
    this.container.style.resize = "auto";

    // this is where we should place the content of our panel
    var div = document.createElement('div');
    div.style.margin = '20px';
    div.innerText = "My content here";
    this.container.appendChild(div);
    // and may also append child elements...

}
MyAwesomePanel.prototype = Object.create(Autodesk.Viewing.UI.DockingPanel.prototype);
MyAwesomePanel.prototype.constructor = MyAwesomePanel;

Extension

We actually have many samples with Extensions, here the main difference is to merge a Toolbar button with it. There are 2 tutorials on this subject: extensions and toolbar. The following code is just putting them togheter, and using the docking panel defined above. The button CSS should be defined on your .css file.

// *******************************************
// My Awesome Extension
// *******************************************
function MyAwesomeExtension(viewer, options) {
    Autodesk.Viewing.Extension.call(this, viewer, options);
    this.panel = null;
}

MyAwesomeExtension.prototype = Object.create(Autodesk.Viewing.Extension.prototype);
MyAwesomeExtension.prototype.constructor = MyAwesomeExtension;

MyAwesomeExtension.prototype.load = function () {
    if (this.viewer.toolbar) {
        // Toolbar is already available, create the UI
        this.createUI();
    } else {
        // Toolbar hasn't been created yet, wait until we get notification of its creation
        this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this);
        this.viewer.addEventListener(av.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);
    }
    return true;
};

MyAwesomeExtension.prototype.onToolbarCreated = function () {
    this.viewer.removeEventListener(av.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);
    this.onToolbarCreatedBinded = null;
    this.createUI();
};

MyAwesomeExtension.prototype.createUI = function () {
    var viewer = this.viewer;
    var panel = this.panel;

    // button to show the docking panel
    var toolbarButtonShowDockingPanel = new Autodesk.Viewing.UI.Button('showMyAwesomePanel');
    toolbarButtonShowDockingPanel.onClick = function (e) {
        // if null, create it
        if (panel == null) {
            panel = new MyAwesomePanel(viewer, viewer.container, 
                'awesomeExtensionPanel', 'My Awesome Extension');
        }
        // show/hide docking panel
        panel.setVisible(!panel.isVisible());
    };
    // myAwesomeToolbarButton CSS class should be defined on your .css file
    // you may include icons, below is a sample class:
    /* 
    .myAwesomeToolbarButton {
        background-image: url(/img/myAwesomeIcon.png);
        background-size: 24px;
        background-repeat: no-repeat;
        background-position: center;
    }*/
    toolbarButtonShowDockingPanel.addClass('myAwesomeToolbarButton');
    toolbarButtonShowDockingPanel.setToolTip('My Awesome extension');

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

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

MyAwesomeExtension.prototype.unload = function () {
    this.viewer.toolbar.removeControl(this.subToolbar);
    return true;
};

Autodesk.Viewing.theExtensionManager.registerExtension('MyAwesomeExtension', MyAwesomeExtension);

Loading the extension

To use the extension you need to include the JavaScript file:

<script src="your_folder/MyExtensionFileName.js"></script>

Then there are different ways to load an extension, here are the 2 most used. The following assumes you are using a code based on Basic Application tutorial.

1. On Viewer initialize

That's the most used, during registerViewer call, add a list of extensions you want to load.

viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D, { extensions: ['MyAwesomeExtension'] });

2. On Document Load event

In this case you need to pass options (or custom parameters to the extension), which is not possible during registerViewer call. Or just need to wait until the document is loaded as your extension needs to access the document data.

function onItemLoadSuccess(viewer, item) {
  viewer.loadExtension('MyAwesomeExtension', { param1: 'value1' });
}

As a reference, here is an example of on viewer initialize and an example of on document load.

Related Article