################
Custom Operators
################

Custom operators are JavaScript objects that implement the :doc:`Communicator.Operator </api_ref/viewing/modules/Communicator.Operator>` interface. To write an operator you derive from the ``Operator`` base class and implement some of the methods related to the various events coming from the browser.

In the example below we define a simple operator that only responds to the :ref:`onMouseDown() <api_ref/viewing/interfaces/Communicator.Operator.Operator:onmousedown>` and :ref:`onMouseUp() <api_ref/viewing/interfaces/Communicator.Operator.Operator:onmouseup>` events: 

.. literalinclude:: /../../applications/client/docs/PG_Viewing_Operators.ts
   :start-after: //! [webviewer_sampleoperator]
   :end-before: //! [webviewer_sampleoperator]
   
Every event handler receives an event object related to its type of event. For mouse events, an example would be the type of :doc:`MouseInputEvent </api_ref/viewing/classes/Communicator.Event.MouseInputEvent>`, for touch events, the type is :doc:`TouchInputEvent </api_ref/viewing/classes/Communicator.Event.TouchInputEvent>`. The event object has various member functions to retrieve the mouse location, button status, and other relevant information. 

Operators can be as simple as the one above that turn an object transparent while the mouse is pressed, or they can be much more complex and have multiple stages like an operator that performs a measurement operation and then positions the resulting markup based on user input. It is up to you to decide how complex you want to make the interaction that is encapsulated by a single operator.

When using custom operators, you should await the call to the parent class' function before returning from your implementation. This can be achieved either by adding await to the parent's function call:

.. code-block:: js

	async onMouseMove(event) {
		  await super.onMouseMove(event);
	}

Or by returning the result of the parent's function call:

.. code-block:: js

	async onMouseDown(event) {
		 return super.onMouseDown(event);
	}

For a list of all Event objects please see the :doc:`API Reference Manual </api_ref/viewing/modules/Communicator.Event>`.


Registering an operator
=======================

Custom operators must be registered with the :doc:`OperatorManager </api_ref/viewing/classes/Communicator.OperatorManager>`. Registering the operator makes it available but does not activate it.

.. literalinclude:: /../../applications/client/docs/PG_Viewing_Operators.ts
   :start-after: //! [webviewer_registeroperator]
   :end-before: //! [webviewer_registeroperator]
   
Registering an operator returns an identifier which you can then use to activate the operator later. Each custom operator has a unique handle.


Activating an operator
======================

There are two ways to activate a registered operator. The first one is to simply :ref:`push <api_ref/viewing/classes/Communicator.OperatorManager:push>` it on the operator "stack".

.. literalinclude:: /../../applications/client/docs/PG_Viewing_Operators.ts
   :start-after: //! [webviewer_pushoperator]
   :end-before: //! [webviewer_pushoperator]


HOOPS Web Viewer has a stack of standard operators active by default, as described in the :ref:`standard operators page <prog_guide/viewing/operators/standard-operators:built-in-operators>`.

When using the :ref:`push function <api_ref/viewing/classes/Communicator.OperatorManager:push>`, your custom operator will be added to the end of the stack and be first in line to receive events. You can then "pop" it from the stack at any time with the :ref:`OperatorManager.pop() <api_ref/viewing/classes/Communicator.OperatorManager:pop>` function.

You can also "replace" an existing operator on the stack at a specific position with :ref:`OperatorManager.set() <api_ref/viewing/classes/Communicator.OperatorManager:set>`:

.. literalinclude:: /../../applications/client/docs/PG_Viewing_Operators.ts
   :start-after: //! [webviewer_setoperator1]
   :end-before: //! [webviewer_setoperator1]

In this case, the default select operator is replaced by your custom operator at position 1 in the stack. If you want to remove an operator from the stack without replacing it, you can call the :ref:`OperatorManager.remove() <api_ref/viewing/classes/Communicator.OperatorManager:remove>` function. Be aware that this function will modify the position of all operators above it in the stack.

If you prefer to start over and define your operator stack from scratch, you can use the :ref:`OperatorManager.clear() <api_ref/viewing/classes/Communicator.OperatorManager:clear>` function which completely empties the operator stack.

To retrieve a particular ``Operator`` object (to call functions on it, change settings, etc.) you can use the :ref:`OperatorManager.getOperator() <api_ref/viewing/classes/Communicator.OperatorManager:getoperator>` function. There can only be one object of a given type on the operator stack at a time, so you only need to pass the relevant operator ID to this function.


Event propagation
=================

All operator events, such as ``OnMouseUp()`` and ``OnMouseDown()`` are sequentially propagated to all operators on the stack starting with the operator highest on the stack. This is so that multiple operators can be active at the same time and effectively run in parallel. Because of this, an operator must be carefully designed to not interfere with the behavior of other operators or the application must ensure that the operator is the only one active.

If an operator handles an event of a given type it often needs to "consume" the event meaning it needs to stop it from propagating down to the operators lower in the stack. In the case of the :doc:`NavCubeOperator </api_ref/viewing/classes/Communicator.Operator.NavCubeOperator>`, for example, this is because the operator might have determined that the NavCube element has been clicked on. In that case, it makes no sense to send the mouse messages also to the Orbit operator which would result in an unexpected camera movement. Another example might be an operator only "interested" mouse events but letting all other event types (e.g. keyboard events) pass through.

To consume an event, simply call :ref:`setHandled(true) <api_ref/viewing/classes/Communicator.Operator.HandleOperator:sethandled>` on the event object in the function that processes the event. If this function is called all the operators lower in the stack will not see the event but instead, receive a :ref:`stopInteraction() <api_ref/viewing/interfaces/Communicator.Operator.Operator:stopinteraction>` event indicating that their current action (e.g. orbiting the camera, moving the cutting plane, etc) should be canceled. You should make sure that your custom operator also handles the :ref:`stopInteraction() <api_ref/viewing/interfaces/Communicator.Operator.Operator:stopinteraction>` event.

For a more advanced Operator Example please consult the :doc:`Advanced operator concepts </tutorials/basic-app/advanced-operator>` section in the *Building a basic application* tutorial.

Please see the :doc:`reference manual </api_ref/viewing/modules/Communicator.Operator>` for more information on each operator category. Some of them will also be discussed throughout this Programming Guide.
