HOOPS Web Viewer general concepts

Loading data at startup

Data can be loaded into the viewer at startup in a number of ways depending on whether client or server based rendering is being used.

  • Streaming from the server: This is the default mode of loading data. The name of the model to stream is specified upon viewer creation. The model is loaded on the server and data is streamed to the client. This mode is supported for both client and server based rendering. Using this method, the endpointURI property specifies the location of the server process while the model property specifies the name of the model to load.


    const hwv = new Communicator.WebViewer({
        containerId: "viewerContainer",
        endpointUri: "ws://localhost:55555",
        model: "micro",
  • Loading via AJAX: This option is available for Client rendering only. Using this loading method, no server process is required for viewing. The method works only with SCS files. SCS files are optionally generated with HOOPS Converter. When loading files using this method, the endpointURI property specifies a valid HTTP URL for the desired SCS File. In this case the model property is omitted.


    const hwv = new Communicator.WebViewer({
        containerId: "viewerContainer",
        endpointUri: "http://www.example.com/micro.scs",
  • Loading via typed array: This option is available for Client rendering only. Using this loading method, no server process is required for viewing. The method works only with Uint8Array objects. The system assumes that the data contained in the array is a binary representation of a SCS file. When loading files using this method, the model and endpointUri properties are omitted from the viewer’s constructor.


    const myBinaryData = new Uint8Array(0);

    const hwv = new Communicator.WebViewer({
        containerId: "viewerContainer",
        buffer: myBinaryData,

Loading HWF data

HWF files created with HOOPS Communicator 2015+ may be loaded into the system. When using this mode, a server connection is not required. The HWF file is retrieved via AJAX request, parsed, then loaded into the scene. Passing the empty: true option into the viewer signals no server backend is present for this session. When using this mode, no stream cache data may be loaded.

The code listing below illustrates creating a viewer without a server back end and using the Communicator.HWF.Importer class to load a model named part.hwf. Include the hwf_import.js file in your page to enable this functionality.

    const hwv = new Communicator.WebViewer({
        containerId: "viewerContainer",
        empty: true,

        sceneReady: () => {
            const importer = new Communicator.HWF.Importer(hwv);
            importer.import({ url: "part.hwf" });



All Interaction with the Web Viewer that occurs as a result of user input happens through operators. Operators are objects which listen for particular input events (such as a mouse up or down) and perform actions when they occur. The Web Viewer ships with a number of useful attributes out of the box for navigating the scene, selecting objects, and creating markup.

Multiple operators may be active at the same time. Operators become active when they are added to the operator stack. When an event occurs, the operator stack is traversed starting with the most recently added operator. Each operator has the ability when notified to mark an event as ‘handled’, which prevents the event from propagating to the next operators on the stack. An event will propagate through the stack until it is marked as ‘handled’, or all operators on the stack have been notified.

Custom operators

Often times there are cases when the functionality provided by the built-in operators are not sufficient for your needs. The Web Viewer allows you to create your own operators which provide a totally customized user interaction experience. Custom Operators are useful for performing specialized tasks or bringing specific functionality from an existing application into the Web Viewer.

Custom operators are objects that implement some or all of the <a href=”api_ref/typedoc/interfaces/communicator.operator.operator.html”>Operator Interface</a>. Once registered with the Web Viewer, they behave like any built-in operator.

Runtime modification

The Web Viewer allows for the modification of various attributes of parts at run time. These include a part’s color, transparency, and visibility. By modifying these attributes for groups of objects, you can change the display of the model based on your own data. For example, recently modified parts could be highlighted with a certain color, parts that are out of stock could be made transparent, or parts that a user does not have access to could be hidden all together. This behavior is accomplished by linking the data in your own system with the identifiers generated as part of the XML output from HOOPS Converter.


Markup is data created by the viewer separately from the model. The web viewer supports a number of different markup types out of the box including Views. The <a href=”api_ref/typedoc/classes/communicator.markupmanager.html”>MarkupManager</a> class is the main interface to working with Markup in the Web Viewer. Methods to load and export markup are available.

Custom markup

Custom markup objects may be created by the user to fulfill a variety of needs. These objects should define a draw method which handles rendering the object on the canvas. Custom Markup objects are registered with the <a href=”api_ref/typedoc/classes/communicator.markupmanager.html”>MarkupManager</a> class which takes over control of them.

This listing shows a simple markup object which draws a 2d pox whose position in 2d window space aligns with a point in world space:

class CustomBoxMarkup extends Communicator.Markup.MarkupItem {
    private _viewer: Communicator.WebViewer;
    private _box = new Communicator.Markup.Shape.Rectangle();
    private _worldPoint: Communicator.Point3;

    constructor(viewer: Communicator.WebViewer, worldPoint: Communicator.Point3) {
        this._viewer = viewer;
        this._box.setSize(new Communicator.Point2(50, 50));
        this._worldPoint = worldPoint.copy();

    public draw(): void {
        const screenPosition = this._viewer.view.projectPoint(this._worldPoint);


The markup object is then created and registered with the system:

    const customBoxMarkup = new CustomBoxMarkup(viewer, Communicator.Point3.zero());


Redline is a specialized type of markup that is associated with a particular camera view. It is only rendered when a particular MarkupView is activated. A number of redline shapes are provided along with the viewer, however, it is possible to add extra redline items. Please refer to the custom_redline example for detailed code samples.

Suppressing incremental updates

Operations in Communicator that change what is displayed may cause the image to be completely redrawn or simply reprocessed, depending on the nature of the operation. Highlighting, for example, is a post-process effect that leaves the original image intact, whereas changing the color or material of an object requires the image to be completely redrawn for correctness.

Communicator draws images incrementally in order to maintain interactivity across models of varying complexity and across hardware of varying power. Because of this, most operations that require a complete redraw are not suitable for response to continuous user interaction like mouse dragging (one notable exception is camera movement–this and certain other operations use an ‘interactive’ draw type that includes a delay after the first frame to prevent flicker).

Sometimes, however, it is necessary to tie operations that require a complete redraw to continuous user interaction. In this case, it may be desirable to avoid the appearance of incremental drawing while still maintaining interactivity. Calling View.setDisplayIncompleteFrames(false) for the duration of the interaction will cause only the final, complete frame of an incremental draw (and the first frame of an ‘interactive’ draw) to be displayed.

An important drawback of this mode is that triggering a redraw while another is still in progress will terminate that draw, and therefore repeatedly triggering redraws at high frequency will likely result in no frames being displayed. This can be alleviated by batching operations that will trigger a redraw and executing them in the handler for the frameDrawn event (or after the event has fired).