Add a handles operator

Summary

In this chapter, we will walk through adding the HandleOperator. This will be a custom operator that inherits the built in handle operator and extends its functionality.

Concepts

  • Adding a handle operator to a selected node


A common use case for a 3D printing application is to offer the ability to position and transform parts around the printing plane. We have already demonstrated (in Section 4) how we can move any node in the scene by providing a transformation matrix to setNodeMatrix, but HOOPS Communicator offers much more for transforms through its built-in HandleOperator. Handles are added scene elements that can update the position of your parts through user interaction, rather than needing to call setNodeMatrix programmatically. The following video demonstrates what we will be building in this section.

The starter code provides the skeleton code for setting event listeners to several UI elements in our application. In the file app.js review the main class method setEventListeners(). You’ll notice the first event listener is for the “Show Handles” button with id="handles-button.

Our goal is to determine which nodes are selected, show the handles, and push the HandleOperator onto the OperatorManager stack. Add the following to the onclick event for the “Show Handles” button:

document.getElementById("handles-button").onclick = () => {
        // Need to gather the selected node IDs to know which nodes
        // will be affected by the transformation
        let nodeIds = [];
        const selectionItems = mainViewer.selectionManager.getResults();
        selectionItems.map((selectionItem) => {
                nodeIds.push(selectionItem.getNodeId());
        });

        // Ensure the user has made a selection before trying to add handles
        if (selectionItems.length !== 0) {
                let handlesOp = mainViewer.operatorManager.getOperator(Communicator.OperatorId.Handle);
                handlesOp.addHandles(nodeIds);
                handlesOp.showHandles();
                mainViewer.operatorManager.push(handlesOp);
        }
        else {
                alert("Try Again. Please first select nodes from the model to transform!");
        }
};

Select a part in the Main Viewer and click “Show Handles” at the bottom of the Inspector window. Handles should appear on your selected node. Click and drag one of the handles to transform your part.

You’ll notice the Node Net Matrix information is not updating. Add the following event listener to mainViewer.setCallback(...):

handleEvent: (eventType, nodeIds, initialMatrices, newMatrices) => {
        this.setMatrixText(mainViewer.model.getNodeNetMatrix(nodeIds[0]));
    }

The handleEvent callback is triggered when a geometry handle is moved, which is a great time to update the node net matrix in our application.

We do not want to interact with the Overhead View directly, but we do want both viewers to stay in synchronized with each other. We will cover this topic in the next section.