Setting up the main viewer

Summary

In this chapter, we will walk through setting the main focus of our application: the viewer.

Concepts

  • Instantiating and starting the WebViewer

  • Setting callbacks

  • Configuring additional WebViewer options


Create the main entry and structure for the application

To get started, we will create a new JS file titled app.js and place it in the src/js folder. The app.js file will contain our main application logic, as well as manage the setup and handling of our <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.webviewer.html”>WebViewer</a></span> object.

To better organize our code, we will be breaking up our code and using the external module approach for this development. We will be using the ES6 class syntax to encapsulate functionality. Let us start by making the main class in our app.js file. This is where we will instantiate our viewer and build our application through composition from other objects we will create later. Right now, we will just leave the class and constructor blank and return to it.

class main {
        constructor() {

        }
} // End main class

Setup, instantiate, and start the WebViewer

As discussed in the Building A Basic App tutorial, HOOPS Communicator requires that the DOM content and structure be loaded before trying to instantiate any <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.webviewer.html”>WebViewer</a></span> objects, since they will look for a <div> id to populate. Because of this, we will instantiate our main class within the onload browser event callback, once all the DOM content has been loaded.

Lastly, since we have provided the CSS file for you, you can import the CSS at the top of the app.js file. Your app.js file should now look something like this:

import '../css/tutorial-userData.css';

// Application logic will begin once DOM content is loaded
window.onload = () => {
        const app = new main();
};

class main {
        constructor() {

        }
} // End main class

At this point, you are welcome to run npm run build in the command line to start our webpack server and serve the frontend framework that we have provided. You can leave the development server running, and it will update your frontend as we write more code. You should see something like this before writing any additional Javascript:

../../_images/inventory-mgmt-empty-app.png

Because we have provided the HTML and styling, we should see the <span class=’code’>&lt;div&gt;</span> element present that we can instantiate our <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.webviewer.html”>WebViewer</a></span> into. We will use this div ID when setting up our viewer.

<!-- Main Viewer Component w/ Interaction -->
<div id="canvas" class="comp-container">
        <div id="viewer"></div>
        <div id="viewer-label" class="comp-label">Hoops WebViewer</div>
</div>

We can see that the div ID we are interested in is called “viewer”. We will do the same procedure documented in the Building A Basic Application tutorial to instantiate an empty viewer. Go ahead and write the following code in the constructor of your main class, using the “viewer” div ID.

class main {

        constructor() {

                // Instantiate the viewer
                this._viewer = new Communicator.WebViewer({
                        containerId: "viewer",
                        empty: true
                });

        } // End main constructor

} // End main class

If you look back at your web application, you will see nothing has changed. This is because we have not yet started the viewer, just instantiated it.

this._viewer.start();

Again, you may be wondering why nothing has changed – don’t worry, we haven’t loaded a model yet - you can specify a model when instantiating the viewer, but we elected not to.

Create the WebViewer callback skeletons

The next step is to setup the callbacks on the <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.webviewer.html”>WebViewer</a></span>. If you are unfamiliar with basic callback usage in HOOPS Communicator, or need a refresher, please review the <a href=”../basic-app/hello-web-viewer.html#registering_callbacks”>callbacks section</a> of the Building A Basic Application tutorial. For our application, we are interested in two main callbacks – <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#modelstructureready”>modelStructureReady</a></span> and <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#selectionarray”>selectionArray</a></span>.

Because we want to load a model to the scene after we have instantiated and started the viewers, we need to wait for the <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#modelstructureready”>modelStructureReady</a></span> callback to fire, or else we will get an error to trying to access the <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.model.html”>Communicator.Model</a></span> class too quickly. The <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#selectionarray”>selectionArray</a></span> callback will be used to gather user selection events, and query model/node information.

this._viewer.setCallbacks({
        modelStructureReady: () => {
                // Set Background color for viewers
                // Enable nav cube and axis triad
                // Enable load model button
        },
        selectionArray: (selectionEvents) => {
                // Reset info fields if no selection item was chosen
                // Otherwise, display node information for the first node in the selection array
                // If the selection nodeId is found in the application data, populate the inspector fields with application data
                }
        }
}); // End Callbacks

From the comments, you can see we will be performing several steps in each callback. Let’s start with the <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#modelstructureready”>modelStructureReady</a></span> callback first, as it is rather straightforward.

When the <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#modelstructureready”>modelStructureReady</a></span> callback is fired, we should be able to add some additional elements to our scene, like a navigation cube and axis triad. By default, you can access the navigation cube and axis triad via the <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.view.html”>Communicator.View</a></span> object in the <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.webviewer.html”>WebViewer</a></span>. We will retrieve these objects, enable them, and move the navigation cube from its default position to the lower right corner of the scene.

// Additional viewer options
this._viewer.view.getAxisTriad().enable();
this._viewer.view.getNavCube().enable();
this._viewer.view.getNavCube().setAnchor(Communicator.OverlayAnchor.LowerRightCorner);

In addition, we will spice up our viewers by adding a colored background consistent with our UI theme. This is as simple as calling <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.view.html#setbackgroundcolor”>setBackgroundColor</a></span> on the <span class=’code’><a href=”../../api_ref/typedoc/classes/communicator.view.html”>Communicator.View</a></span> object. You can specify a single background color, or make a gradient from top to bottom by providing two colors. We will choose to make the gradient.

// Background color for viewers
viewer.view.setBackgroundColor(new Communicator.Color(0, 153, 220), new Communicator.Color(218, 220, 222));

Lastly, but most importantly, we will enable the input button to load a model to the scene. We will write this functionality later, but by waiting for <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#modelstructureready”>modelStructureReady</a></span> to fire before enabling the button will ensure we get no loading errors by trying to load a model prematurely. Our final <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#modelstructureready”>modelStructureReady</a></span> callback will look like this:

modelStructureReady: () => {
        // Background color for viewers
        this._viewer.view.setBackgroundColor(new Communicator.Color(100, 150, 200), new Communicator.Color(222, 222, 222));

        // Additional viewer options
        this._viewer.view.getAxisTriad().enable();
        this._viewer.view.getNavCube().enable();
        this._viewer.view.getNavCube().setAnchor(Communicator.OverlayAnchor.LowerRightCorner);
        let loadButton = document.getElementById("open-model-button");
        loadButton.disabled = false;
},

The <span class=’code’><a href=”../../api_ref/typedoc/interfaces/communicator.callbackmap.html#selectionarray”>selectionArray</a></span> callback is more involved, and will rely on some other aspects of our application, so for now we will keep it empty and revisit the callback as we develop the pieces we need for its functionality.