##########
Operators 
##########


Overview
========
In order for a user to interact with the |ProductName| Viewer, your application will need to respond to various input events from devices 
such as the mouse, the keyboard, or a touch screen. While it is possible to handle user input yourself using DOM event listeners directly, 
|ProductName| provides the concept of “Operators” in order to simplify and enhance this process. Operators hook into the browser 
event loop and fire predefined actions in response to user inputs - it is essentially a class of bundled functionality that will be triggered 
by captured input events. Operators are a way to handle user input in a more structured way - they encapsulate the logic of handling user input 
in a single place, and to make it easier to switch between different modes of interaction.

.. image:: images/operatorsOverview.gif
    :alt: Operators Overview
    :align: center

|

The OperatorStack Class
=======================
Each Viewer in a |ProductName| CloudSession will typically contain one or more Views for rendering. When a View is created, it composes an 
OperatorStack object that is owned and associated only with that View. Therefore, any Operators on that particular OperatorStack are only active for that View. 

This OperatorStack is responsible for adding, removing, reordering, and referencing any Operators on the View. To achieve this, the
OperatorStack contains standard stack behavioral functions, such as push, pop, set, etc. As its name implies, the OperatorStack will call any Operator logic
in a 'last in, first called' order. In other words, the Operator at the top of the stack will be the first to receive and respond to the input event.
Depending on how the Operator is implemented or defined, the event may or may not propagate down the stack to other Operators.

The OperatorStack will function on any object that is derived from the abstract Operator base class. Once an operator is pushed to the stack, it will
be registered and can be retrieved using the unique name identifier of the Operator, regardless of whether the operator is active on the stack or not. 


The Operator Class
==================
The Operator class is an abstract class that contains optional functions with names that correspond to DOM event listeners. These functions can be 
implemented to perform desired actions when the corresponding event is triggered in the View. 

The functions for events that can currently be implemented by an Operator derived class are:

* onMouseDown
* onMouseUp
* onClick
* onDblClick
* onMouseMove
* onWheel
* onKeyDown
* onKeyUp
* onTouchStart
* onTouchEnd
* onTouchMove
* onPointerDown
* onPointerUp
* onPointerMove


When an Operator is instantiated, it needs a unique name identifier. A unique name ensures that the operator can be easily identified and managed 
within the OperatorStack. For standard built-in operators in Envision, you can reference this unique name using the StandardOperator enum.

The optional operator event handler methods are required to return an OperatorEventStatus indicating whether the particular event should propagate 
down the stack, or not. If the event is designated to propagate, the OperatorStack will call the next operator in the stack using the same event.
If the event is not designated to propagate, the OperatorStack will not call any other operators in the stack for that event.

An instance of a given Operator can only be attached to one or zero Views. You can reference an Operators owning View with the ownerView property. 


Basic Examples
==============
Here is the simpliest class implementation of an Operator in Envision. This Operator simply takes the mouse coordinates of the Viewer element and logs
the values to the console on each new onmousemove event. 

.. code-block:: typescript

    export class EventLogOperator extends cee.Operator {

        constructor(name: string) {
            super(name);
        }

        onMouseMove(event: MouseEvent) {
            console.log(`  offsetX: ${event.offsetX},   offsetY: ${event.offsetY}`);
            return cee.OperatorEventStatus.PROPAGATE;
        }
    }

.. image:: images/SimpleEventLog.gif
    :alt: Simple Event Log Operator
    :align: center

|

Of course, we suspect your Operators will be a bit more complex and useful than this, but this simple example demonstrates the basic principle and simplicity
of creating an Operator. 

Once we have our operator class created, we can instantiate it, and push it to the desired views operator stack.

.. code-block:: typescript

    const opStack = myView.operators;
    const operator = new EventLogOperator("LogOperator");
    opStack.push(operator);


Any event detected by this View will now pass that event along to the implemented operator functions. 

Notice we have chosen to let the onmousemove event propagate in this simple operator. This allows the same event to be used by another operator further down the stack
that may have an onMouseMove function implemented. If we had chosen to not allow the event to propagate, no other onMouseMove functions implemented in other operators
on the OperatorStack would be called. 

Let's build another simple operator, but now one that uses some other |FamilyName| APIs in order to control our scene and interrogate the model. In this operator, we will 
show the specified scalar result on a RemoteModel when holding the left mouse button down. 

.. code-block:: typescript

    export class ScalarPeekOperator extends cee.Operator {

        private m_scalarId: number = -1;
        private m_hitRemoteModel: cee.ug.RemoteModel = null;

        constructor(name: string) {
            super(name);
        }

        get scalarId(): number {
            return this.m_scalarId;
        }
        set scalarId(id: number) {
            this.m_scalarId = id;
        }

        onMouseDown(event: MouseEvent) {
            const ray = this.ownerView.ownerViewer.rayFromCssCoordinate(this.ownerView, event.offsetX, event.offsetY);
            for (let model of this.ownerView.getModelArray()) {
                if (model instanceof cee.ug.RemoteModel) {
                    this.m_hitRemoteModel = model;
                    break;
                }
            }
            if (this.m_hitRemoteModel) {
                this.m_hitRemoteModel.rayIntersect(this.m_hitRemoteModel.currentFrameIndex, ray, (intersectResult) => {
                    if (intersectResult.hitItem.anythingHit) {
                        intersectResult.model.modelSpec.fringesResultId = this.m_scalarId;
                    }
                })
            }
            return cee.OperatorEventStatus.PROPAGATE;
        };

        onMouseUp() {
            if (this.m_hitRemoteModel) {
                    this.m_hitRemoteModel.modelSpec.fringesResultId = -1;
                    this.m_hitRemoteModel = null;
            }
            return cee.OperatorEventStatus.PROPAGATE;
        }
    }

.. image:: images/ScalarPeek.gif
    :alt: Scalar Peek Operator
    :align: center

|

Here we create an accessor to get/set the scalarID we want to show, and then implement the onMouseDown and onMouseUp optional operator functions.
In onMouseDown, we determine if there is a RemoteModel in the view to operate on (this example simply takes the first one added to the scene and does 
not account for multiple RemoteModels in the scene). We then cast a ray into the scene to determine if that ray intersects the RemoteModel. If so, 
it colors the model as fringes with the specified scalarId (if the id is invalid, the viewer will log an exception - you can implement more robust
handling if desired). In onMouseUp, we remove the coloring of the fringes.


The "Hot Key" Operator
======================
The OperatorStack also has a special field, known as a 'hot key' operator. This is a special designation you can give to one (and only one) Operator
on the stack. It gives special priority to the Operator and allows for quick access to an Operator. If a hot key operator is assigned, it can be 
immediately accessed by holding the Alt/Opt key. 

This optional key mapping can directly access an operator on the stack without needing to worry about what other operators are currently on the stack. 
The hot key operator will take precedence over the stack, and fire its operator logic, and not propagate its events down the stack. 
This can be particularly useful if you wish to quickly maintain access to another global operator, such as navigation, but also allows for quick 
pairings of operators that may work frequently together.

In the example image below, you can see we use the Box Operator, which by default does not propagate its navigation events. However, we can quickly
still navigate the scene by holding the Alt/Opt key to access the Navigation Operator, effectively bypassing the local box navigation. 

.. image:: images/HotKeyExample.gif
    :alt: Hot Key Operator
    :align: center

|

Operators Examples and Example App 
==================================
We have developed several operators that can serve as the basis or inspiration for other operators you may want to use in your application. You can find
these operators in the Examples/Operators directory of your |ProductName| package. In here, you will see a SampleOperators folder containing
classes for the various operators we have developed. Some Operators are only designed to work with particular modules, such as RemoteModel or GeometryModel. 
Depending on your application, you can expand these operators to handle different model types, though this will require more handling and implementation for the 
various models in your scene. We have decided to keep them separate and focused to a particular module for simplicity. 

You will find Operator samples for:

* Geometry Previews (such as visualizing a plane or box)
* Picking Operations (for parts or nodes in a scene)
* Transforms (Translations/Rotations)

You may also notice that you can abstract common functionality into abstract classes, and inherit from those. For example, if you want to make separate RemoteModel
and ConstantRemoteModel picking operations, you can handle the common picking logic in the parent class, and then leave the module specific implementation to the 
child classes. 

Child classes can also extend the capability of a fully functional operator. In the case of the UgCutPlanePreviewOperator, we take the base functionality of the 
PlanePreviewOperator (which will simply visualize a plane), and then perform feature extractions using that PlanePreview to make a cutting plane. In this example, we can
now visualize the location of a cutting plane on the client side, before directing the server to perform the actual cutting plane and feature extraction.

We encourage you to use as much or as little of these samples in your application, as you see fit. We hope that these samples will serve as inspiration for your own 
operators and give insight on how to take advantage of the Operators feature. 


Disabling Operators in Favor of Legacy Viewer UI 
================================================

While we recommend the use of operators to handle your Viewer UI, if you are not ready to make the transition yet, you can disable the use of operators. 
If you wish to disable the Operators feature in favor of the legacy Viewer UI, you can do so by setting the 'useOperators' property of the ViewerOptions to false.
It should be noted that this legacy UI is deprecated and will be removed in future versions of |ProductName|, so we recommend exploring the use of Operators
as soon as possible.


Transitioning from the Legacy Viewer UI functions to Operators
==============================================================

*   **navigation**: Properties to control navigation behavior found in view.navigation are now managed with the built-in NavigationOperator. As opposed to the legacy Navigation class, 
    the NavigationOperator will not automatically be instanced and pushed to the OperatorStack when the Viewer is created, and it is the developers responsibility to do so. If you
    do not wish to extend the NavigationOperator for your own purposes, you can simply push the NavigationOperator to the OperatorStack to have the same navigation behavior as the
    legacy Navigation class:

    .. code-block:: typescript

        myView.operators.push(new cee.NavigationOperator());

        Once instanced and pushed to the stack, you can retrieve the NavigationOperator with the following code:

    .. code-block:: typescript

        const navigationOperator = myView.operators.get(cee.StandardOperator.NavigationOperator);

*   **picking**: The ug.PickHelper and Viewer.setPickHandler functionality has been deprecated, but can easily be used in the same way with Operators. In the 
    Examples/Common/Operators directory of the package, you can find the refactored operator variations of these functions. In order to make use of these operators,
    you can instantiate them and push them to the OperatorStack to have them respond to mouse picking events.